#!/usr/local/bin/ruby
#
=begin
 ******************************************************************************
 * Copyright 2015 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : USBTenki interface and logger
 * Filename : usbtenki.rb
 * Author   : Henthorn
 * Project  : Benthic Rover
 * Version  :
 * Created  : Oct-15   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'

##########
# Temperature and humidity level logging class that uses usbtenkiget command
# to acquire data.
# Set-up to acquire data at a desired interval (e.g., 60 secs).
# The driver simply executes the usbtenki program, reads the response,
# and logs the data in log file.
#
class UsbTenki
  include SyslogWriter

  attr_accessor :rawdata, :humidity, :temp, :name, :interval, :thread

  ##
  #
  def initialize(p_name='usbtenki',p_interval=60)
    @name = p_name
    @interval = p_interval.to_f
    
    # Initialize the object variables and constants
    @humidity  = -1
    @temp      = -1
    @thread = nil
    @RAWDATA_ELEMENTS = 2

    @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("! UsbTenki 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),Humidity (%),Temperature (C)\n")
    end

    # Start the monitor thread and log data
    #
    syslog("_ Getting UsbTenki data every #{@interval} seconds")
    @thread = Thread.new do
      Thread.current["name"] = "usbtenki 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

  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  #

  ##
  # 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),Humidity (%),Temperature (C)\n")

  end

  ##
  # Execute the usbtenkiget program and read the results 
  #
  def acquire_data
    # Process data
    #
    com = "usbtenkiget -i 0,1"
    @rawdata = `#{com}`
    @data = @rawdata.strip.split(',')
    
    if @data.length == @RAWDATA_ELEMENTS
      @humidity  = @data[0].to_f
      @temp      = @data[1].to_f
    else
      syslog("! usbtenkiget execution error")
      return false
    end
        
    syslog("_ #{@name}: humidity/temp=#{@humidity}/#{@temp}")
    return true
  end

  ##
  # Write data to log file
  #
  def log_data
    @datafile.write("#{@humidity},#{@temp}")
  end



end

##
# Overrides data read function to provide simulation capability
#
class SimUsbTenki < UsbTenki
  # The data reader must simulate the data interval provided
  #  
  def acquire_data
    @humidity = 60.16
    @temp     = 23.8
    return true
  end
  
end

##
# Standalone unit test (recommended)
#
if __FILE__ == $0
  # Print the % humidity and temperature
  #
  if (ARGV.length > 0)
     puts("59.51 21.76")
  else
     hs = UsbTenki.new("UsbTenki_test")
     hs.acquire_data()
     puts("#{hs.humidity} #{hs.temp}")
  end
end
