#--
#******************************************************************************
#* 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 : 
#******************************************************************************
#++

require 'rover_environment'
require 'rover_utils'
require 'rover_thread'
require 'configman.rb'
require 'posix/serialport'

# Implements a driver/logger function that uses A to D program to acquire
# battery voltage. Set-up to acquire data at a desired interval (e.g., 60 secs).
# The driver simply executes the A to D voltage program, reads the response, and
# logs the data in log file.
#

class BattMan 
  include LogHelper

  # The _name_ attribute is derived from the portname when the object is
  # created. A portname of '/dev/optode_port' renders a name of 'optode_port'.
  # Portnames must be unique.
  #
  attr_reader :rawdata, :volt, :name, :thread

  # Args: SerialPort config object, serial port name.
  # Typical usage: op = Aanderaa.new(nil, '/dev/this_optode')
  # Default serial port configuration: 9600,8,N,1
  #
  def initialize(name = 'battery', channel = 4, offset = 38800, interval = 300)
    @name = name
    @channel = channel
    @offset = offset
    @interval = interval.to_f
    
    # The logfile name is derived from the name
    @logfilename = @name + ".csv"

    # Initialize the object variables and constants
    @header_written = false
    @volt  = -1
    @thread = nil
    @RAWDATA_ELEMENTS = 1
    
  end

  def write_header
    # Write the header for the log file
    datawrite("Rover Timestamp (UTC) , Mission Time (sec), Voltage (V) \n, \n",
	      @logfilename)
    @header_written = true
  end

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

  # Close - synonym for stop
  #
  def close
    self.stop
  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("! Error parsing rawdata on #{@name}, data array length is: " +
             "#{@data.length} and should be #{@RAWDATA_ELEMENTS}")
      elements_string = "["
      @data.each {|el| elements_string += el + ", "}
      elements_string += "]"
      syslog("_ elements in @data array: #{elements_string}")
      return false
    end
        
    syslog("_ Obtained voltage data #{@name}: volt=#{@volt}")
    return true
  end

  # Write data to log file
  #
  def log_data
    datalog("#{@volt}", @logfilename)
  end

  # Read and log data in a separate thread
  #
  def run
    syslog("_ Getting battery data every #{@interval} seconds")
    write_header unless @header_written
    @thread = RoverThread.new do
      Thread.current["name"] = "battery log"
      while true
        log_data if acquire_data
        sleep(@interval)
      end
    end
  end

  # Indicates whether read/log thread is running
  def is_running?
    if @thread
      return @thread.alive?
    else
      return false
    end
  end
  
end

# Overrides data read/log functions to provide simulation capability
#
class SimBattMan < BattMan 
  include LogHelper
  
  # The data reader must simulate the data interval provided
  #  
  def acquire_data
    sleep(@interval)
    return true
  end
  
  def log_data
    syslog("_ #{@name} logging data (no data)")
  end
  
end
