=begin
 ******************************************************************************
 * Copyright 1990-2011 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : What is contained within the file
 * Filename : relay8.rb
 * Author   : henthorn@mbari.org
 * Project  : Benthic Rover
 * Version  : 1
 * Created  : 07/21/11
 * Modified : 
 ******************************************************************************
=end

# Refer to Rover-code home directory as base
#
require "#{ENV['ROVER_HOME']}/utils/rover_environment"
#

require 'utils/misc'
require 'utils/datalog'

##########
# Interface to TS-RELAY8 relay board
#
class Relay8
  include SyslogWriter

  ##
  # Some constants to use with Relay8 objects
  # Updated for TS-7250-V2
  #
  # PEEK = "peekpoke 8 0x11e00142"   for 7200
  PEEK = "devmem 0x81008142 8"

  FIRST   = 0
  STEPPER = 0
  FLUOR   = 1
  CAMERA  = 2
  EXTLED  = 3
  RNGLED  = 4
  LAST    = 4

  @@dev_names = ["Stepper Motor", "Fluorometer" , "Camera", \
                 "External LED", "Ring LED"]

  #####
  # Initialize, get the current value of the RELAY8 register
  #
  def initialize()
    @state = current_state
    syslog("_ Relay8 object instantiated")
  end
  #####

  def stepperOn
    self.turn_on(STEPPER)
  end
  
  def stepperOff
    self.turn_off(STEPPER)
  end
  
  def fluoroOn
    self.turn_on(CAMERA)
  end
  
  def fluoroOff
    self.turn_off(CAMERA)
  end

  def fluorometerOn
    self.turn_on(FLUOR)
  end
  
  def fluorometerOff
    self.turn_off(FLUOR)
  end

  def extledOn
    self.turn_on(EXTLED)
  end
  
  def extledOff
    self.turn_off(EXTLED)
  end
7
  def rngledOn
    self.turn_on(RNGLED)
  end
  
  def rngledOff
    self.turn_off(RNGLED)
  end


  #####
  # Turn the given device on (close the relay).
  # Use on of the relay constants defined above as the argument.
  #
  def turn_on(relay_num)
    raise("Invalid relay: #{relay_num}") if(relay_num<FIRST || relay_num>LAST)

    mask = 1 << relay_num
    ns = self.current_state | mask

    syslog("_ Turning on relay #{@@dev_names[relay_num]} with #{ns}")
    @state = new_state(ns)
  end
  #####


  #####
  # Turn the given device off (open the relay).
  # Use one of the relay constants defined above as the argument.
  #
  def turn_off(relay_num)
    raise("Invalid relay: #{relay_num}") if(relay_num<FIRST || relay_num>LAST)

    mask = 1 << relay_num
    ns = self.current_state & ~mask

    syslog("_ Turning off relay #{@@dev_names[relay_num]} with #{ns}")
    @state = new_state(ns)
  end
  #####


  #####
  # Return true if the given device is on (relay is closed).
  # Use on of the relay constants defined above as the argument.
  #
  def on?(relay_num)
    raise("Invalid relay: #{relay_num}") if(relay_num<FIRST || relay_num>LAST)

    mask = 1 << relay_num
    return ((self.current_state & mask) == mask)
  end
  #####


  #####
  # Turn all the devices off (open all relays)
  #
  def all_off()
    syslog("_ all devices off")
    @state = new_state(0)
  end
  #####

  def allOff()
    return all_off()
  end

  protected
  
  #####
  # Set the state of the RELAY8 register to the hex Fixnum value argument
  # Returns the result of the command as a Fixnum (should be the same as
  # the argument).
  # Updated for 7250-V2
  #
  def new_state(ns)
    poke = format("%s %#x", PEEK, ns)
    puts("#{poke}")
    unless (system("#{poke}"))
      syslog("! relay request failed #{poke}")
    end
    current_state()
  end
  #####


  #####
  # Return the current value of the RELAY8 register as Fixnum
  #  
  def current_state()
    cs = `#{PEEK}`
    cs.hex
  end
  #####


  def Relay8.usage
    puts("  ruby relay8.rb [device  state]")
    puts("\tdevice = (fluoro | stepper | camera | extled | rngled)")
    puts("\tstate  = (1 | 0)")
  end

  def Relay8.test
    return Relay8.usage() if (ARGV.length == 1 || ARGV.length > 2)
    if (ARGV.length == 2)
      r = Relay8.new

      device = ARGV[0]
      state  = ARGV[1]

      case device.downcase
      when "stepper"
        dev = STEPPER
      when "camera"
        dev = CAMERA
      when "extled"
        dev = EXTLED
      when "rngled"
        dev = RNGLED
      when "fluoro"
        dev = FLUOR
      when "alloff"
        r.allOff
        return
      else
        puts("Unknown device!")
        return Relay8.usage()
      end

      case state
      when "1"
        r.turn_on(dev)
      when "0"
        r.turn_off(dev)
      else
        puts("Bad state argument!")
        return Relay8.usage()
      end
      return
    end

    r = Relay8.new

    for i in FIRST..LAST
      r.turn_on(i)
      raise "Relay #{i} failed to close!" unless (r.on?(i))
      sleep(0.5)
    end

    for i in FIRST..LAST
      r.turn_off(i)
      raise "Relay #{i} failed to open!" if (r.on?(i))
      sleep(0.5)
    end

  end

end


#####
# Standalone unit test (recommended)
# Include at the end of the file as a hook to run a unit test of
# the code from the command line including the command line options
# (e.g., "$ ruby my_class.rb --sim").
#
if __FILE__ == $0
  # Use a semaphore file to ensure serial access to the wakey port
  #
  File.new("/tmp/relay8.lock", File::CREAT || File::EXCL)
  
  # Get the command and execute if valid
  # Write the result to stdio
  #
  w = Relay8.new
  cmd = ARGV[0]

  # Is there a command in ARGV?
  #
  unless (cmd)
    puts("No command!\n")
    Relay8.instance_methods(false).each do |m|
      puts(m)
    end
    exit
  end
  
  # Is the command a valid Wakey method?
  #
  unless(w.respond_to?(cmd))
    puts "#{cmd}: unknown command!"
    exit
  end
  
  # Zero or one argument
  #
  if (ARGV[1])
    result = w.send(cmd, ARGV[1])
  else
    result = w.send(cmd)
  end
  puts(result)
end

