=begin
 ******************************************************************************
 * Copyright 1990-2007 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : Battery drivers and loggers
 * Filename : battery.rb
 * Author   : Henthorn
 * Project  : Benthic Rover
 * Version  :
 * Created  : Oct-07   Basic functions incl logging
 * Modified : 
 ******************************************************************************
=end

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

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

##########
# Battery level logging class that uses board-level A/D function
# to acquire battery voltage.
# Set-up to acquire data at a desired interval (e.g., 60 secs).
# The driver simply executes the system A/D voltage program, reads the response,
# and logs the data in log file.
#
class BatteryMon
  include SyslogWriter

  attr_accessor :rawdata, :volt, :name, :channel, :offset, :interval, :thread

  ##
  # Types:         string             int/string   int/string     int/string
  # Units:         none                scalar      scalar          seconds
  #
  def initialize(p_name='battery',p_channel=4,p_offset=39700,p_interval=300)
    @name = p_name
    @channel = p_channel.to_i
    @offset = p_offset.to_i
    @interval = p_interval.to_f
    
    # Initialize the object variables and constants
    @volt  = -1
    @thread = nil
    @RAWDATA_ELEMENTS = 1

    @datafile_name = nil
    @datafile = nil
  end

  ##
  # Re-initialize driver.
  # Stop the current driver if running, then
  # set-up to run again with a fresh log file.
  # This method can be used to begin logging in a different directory.
  #
  def reinit
    self.stop
    self.init
  end


  ##
  # Stop the read/log thread by killing it. Set self.thread to nil
  #
  def stop
    if (@thread && @thread.alive?)
      @thread.kill
      @thread.join
      @thread = nil
      syslog("_ Stopping #{@name} thread")
    end
  end

  ##
  # Close - synonym for stop
  #
  def close
    self.stop
  end

  ##
  # Read and log data in a separate thread.
  #
  def run(data_dir=DataLog.deployment_data_home)

    # Let's not run two threads at once
    #
    if (@thread and @thread.alive?)
      syslog("! BatteryMon driver already running")
      return
    end

    # May be a different deployment. Open log files just in case.
    #
    unless (data_dir && File.exist?(data_dir) && File.directory?(data_dir))
      data_dir = "."
    end

    @datafile_name = data_dir + File::SEPARATOR +  \
                     @name + "_raw.csv"
    @datafile = DataLog.new(@datafile_name)

    if (@datafile.need_heading)
      @datafile.file.write("Rover Timestamp (ISO601),Voltage (V)\n")
    end

    # Start the monitor thread and log data
    #
    syslog("_ Getting battery data every #{@interval} seconds")
    @thread = Thread.new do
      Thread.current["name"] = "battery log"
      while true
        log_data if (acquire_data)
        sleep(@interval)
      end
    end
  end

  ##
  # Callable test function.
  # Purpose is to test functionality and run every line of code in
  # the class.
  #
  def test_me
    # Typical usage
    self.run
    sleep(10)
    self.stop

    # Log in a different file at faster rate.
    self.name = "new_mon"
    self.interval = 1
    self.reinit
    self.run
    sleep(5)
    # Try to run two threads.
    self.run
    sleep(4)
    self.stop
  end

  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  #
  protected

  ##
  # Init
  # Prepare driver for execution.
  # In this case, we just need a log file.
  #
  def init
    # The datafile name is derived from the name
    # FIXME: Need to acquire the directory name from the Deployment
    #
    @datafile_name = DataLog.plan_data_home + File::SEPARATOR +  \
                     @name + "_raw.csv"
    @datafile = DataLog.new(@datafile_name)
    @datafile.file.write("Rover Timestamp (ISO601),Voltage (V)\n")

  end

  ##
  # Execute the adc program and read the resulting voltage 
  #
  def acquire_data
    # Process data
    #
    adc_com = "adc -ac #{@channel} -j #{@offset}"
    @rawdata = `#{adc_com}`
    @data = @rawdata.split
    
    if @data.length == @RAWDATA_ELEMENTS
      @volt  = 10 * (@data[0].to_f)
    else
      syslog("! adc execution error")
      return false
    end
        
    syslog("_ #{@name}: volt=#{@volt}")
    return true
  end

  ##
  # Write data to log file
  #
  def log_data
    @datafile.write(@volt)
  end



end

##
# Overrides data read function to provide simulation capability
#
class SimBatteryMon < BatteryMon 
  # The data reader must simulate the data interval provided
  #  
  def acquire_data
    @volt = 29.8
    return true
  end
  
end

##
# Standalone unit test (recommended)
#
if __FILE__ == $0
  # Test code here
  if (ARGV.length > 0)
    bm = SimBatteryMon.new("SimBatteryMon_test")
  else
    bm = BatteryMon.new("BatteryMon_test")
  end
  bm.interval = 3
  bm.test_me
  puts("Done")
end
