#--
#******************************************************************************
#* Copyright 1990-2008 MBARI
#* MBARI Proprietary Information. All rights reserved.
#******************************************************************************
#* Summary  : Interface to Prosilica camera (real and simulated)
#* Filename : prosilica.rb
#* Author   : Henthorn
#* Project  : Benthic Rover
#* Version  : V1.0
#* Created  : Apr-08   Basic functionality
#* Modified : 
#******************************************************************************

require 'monitor'
require 'rover_environment'
require 'rover_utils'
require 'configman'

class Prosilica < Monitor
  include LogHelper
  
  # Default configuration - video server at 134.89.12.148 (transit cam)
  #
  def initialize ip = '134.89.12.148'
    super()

    @time_limit = 10 # seconds to accomplish the image capture task
    
    # The ip serves as the camera identifier
    # Will need to pass that into the Snap command
    #    
    @ip = ip
    syslog("_ Prosilica object instantiated to addr #{@ip}")
  end

  # Capture image and place the image file in the images directory.
  # The target filename is constructed using the given prefix
  # supplmented with a suffix that virtually guarantees a unique
  # filename.
  #
  # Thread syncronization is implemented here via MonitorMixin
  #
  # prefix - use to label the file (e.g., "measurement_site")
  #
  def capture_image(prefix="")
    self.synchronize do
      ret_stat = false
      start_time = Time.now
    
      # Make sure this task does not hang us up
      # by watching the thread for a given time limit
      #
      @capture_thread = RoverThread.new do  
        # Take an image. If successful copy file to image directory
        #
        if (frame_grab())
          ret_stat = move_image(prefix)
        end
      end

      # See how long it takes up to @time_limit
      #
      elapsed = 0
      while ( (elapsed = (Time.now - start_time)) < @time_limit)
        unless (@capture_thread.alive?)
          syslog("_ Frame grab took #{elapsed} seconds")
          break
        end
        sleep(1)
      end
      
      unless(ret_stat)
        syslog("! Frame grab taking too long, probably hung-up")
        @capture_thread.kill if (@capture_thread && @capture_thread.alive?)
        kill_snap
      end
      
      return ret_stat
    end
  end

  # Kill lazy Snap processes
  #
  def kill_snap
    pid = 0

    # Look for Snap processes
    prc = `ps | grep Snap | grep -v grep`
    lines = prc.split('\n')

    # Kill all the ones we find
    if (lines.length > 0)
      lines.each { |line|
        tokens = line.split if line
        pid = tokens[0].to_i if tokens

        if (pid > 0)
          syslog("! Killing Snap process id #{pid}")
          syslog(line)
          `kill -9 #{pid}`
        end
      }
    else
      syslog("_ No Snap processes found")
    end
  end
  
#~~~~~~~~~~~~~~~~~~~~~~ PRIVATE METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~

private

  # Capture image from camera. The image file is placed in the
  # current directory and named ps.b16
  #
  #
  def frame_grab()
  
    snapcmd = "/cf/rover/lib/Snap"
    syslog("_ " + snapcmd)
    
    # On error, log it and return false
    #
    unless (send_system_call(snapcmd))
      syslog("! Fault: failed to retrieve frame grab on camera #{@ip}")
      return false
    end
    
    true
  end

  # Trap system calls 
  #
  def send_system_call(cmd)
    return system(cmd)
  end
 
  # Move latest image file from local to the images directory. 
  # The target filename is constructed using the given prefix
  # supplmented with a suffix that virtually guarantees a unique
  # filename.
  #
  def move_image(prefix)
    
    # Create a unique suffix from the current time down to 1/100 of a second,
    # then copy the image to the log directory
    # 
    suffix = "%10.2f" % Time.now.to_f
    cpcmd = "mv ps.b16 " + LogDir.instance.datalog_dir + 
            "#{prefix}_" + suffix + ".b16"
    syslog(cpcmd)
    
    # On error, log it and return false
    #
    unless (send_system_call(cpcmd))
      syslog("! Fault: failed to move image")
      return false
    end
    
    true
  end
 
end   # class Prosilica


# SimProsilica class implements Prosilica interface. Logs calls, no real action
#
class SimProsilica < Prosilica
  include LogHelper
  
  # Simply log the command that would be executed
  #
  def send_system_call(cmd)
    syslog("_ #{cmd}")
    true
  end
end
