/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : FuelCell.cc                                                    */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 06/05/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/

#include "FuelCell.h"
#include "mvc_fcc_api.h"
#include <sys/sys_msg.h>
#include "FuelCellIF.h"
#include "EventTriggers.h"
#include "Task.h"
#include "PeriodicTask.h"


#define GET_STATUS_PERIOD 1000
#define GET_DATA_PERIOD  2000

/*
CLASS 
FuelCell

DESCRIPTION
FuelCell ethernet driver, based upon Fuel Cell Interface Document.
The "Driver" (this code), is responsible for periodically calling both 
get_FCC_status() and get_FCC_data, and Publishing events as necessary.

Commands send from the MVC to the FCC are issued directly by the FuelCellServer object.


AUTHOR
John Rieffel
*/

FuelCell::FuelCell()
  :PeriodicTask("FuelCell")
{
  if (init() == -1)
    {
      Syslog::write("FuelCell -- FuelCell() error initializing\n");
      //error
    }
  _output = new FuelCellOutput();
  
  addPeriodicCallback(GET_STATUS_PERIOD, (CallbackMethod)FuelCell::get_status_callback);
  addPeriodicCallback(GET_DATA_PERIOD, (CallbackMethod)FuelCell::get_data_callback);
  
  //  _log = new FuelCellLog(this, DataLog::BinaryFormat);
  
}

FuelCell::~FuelCell()
{
  delete _output;
  //  delete _log;
}

// initialize
DeviceIF::Status  FuelCell::init()
{
  // nothing particular to do for now?
  return DeviceIF::Ok;
}

// get Fuel Cell Status (every 1 second) via fcc_api::get_FCC_status
DeviceIF::Status FuelCell::get_status_callback()
{
  int reply_code;
  FCC_STATUS fcc_status;
  
  if ((reply_code = get_FCC_status(&fcc_status))!=FCC_ERR_OK)
    {

      switch(reply_code)
	{
	case FCC_ERR_INVALID_PARAM:
	  
	  Syslog::write("FuelCell.cc:get_status)callback()-- invalid parameter sent");
	  throw Exception("FuelCell.cc:get_status)callback()-- invalid parameter sent");
	  return DeviceIF::Error;
	  
	  break;
	  
	case FCC_ERR_COMM:
	  Syslog::write("FuelCell.cc:get_status)callback()-- comm error");
	  throw Exception("FuelCell.cc:get_status)callback()-- comm error");
	  break;

	}
    }
  // no errors -- FCC Status is OK
  else
    {
      //check status of FCC
	// for debugging purposes
	
	if (fcc_status.health != FCC_HEALTHY)
	   {
		//it's not healthy, so it must be an alarm
		triggerEvent(FuelCellIF::NewAlarm); 
	   }
	else
	  {
		// it's healthy (again?)
		triggerEvent(FuelCellIF::ClearAlarm);
	}	  
      // now other statuses to return;
      _output->data.fcc_status.fc_control_state = (FuelCellIF::FC_Control_State)fcc_status.fc_control_state;
      _output->data.fcc_status.FC_remaining_kwh = fcc_status.FC_remaining_kwh;
      _output->data.fcc_status.RB_remaining_wh = fcc_status.RB_remaining_wh;
      _output->data.fcc_status.BIT_status = fcc_status.BIT_status;
      _output->data.fcc_status.BIT_result = fcc_status.BIT_result;
      try {
	_output->write();
      }
      catch(SharedData::AccessError error)
	{
	  fprintf(stderr,"%s",error.msg);
	  return DeviceIF::Error;
	}
    }
  return DeviceIF::Ok;
}


// get Fuel Cell Data (every 960 second == 15 minutes) via fcc_api::get_FCC_data
DeviceIF::Status FuelCell::get_data_callback()
{
  int reply_code;
  FCC_DATA fcc_data;
  if ((reply_code=get_FCC_data(&fcc_data))!=FCC_ERR_OK)
    {
      switch(reply_code)
	{
	case FCC_ERR_INVALID_PARAM:
	  
	  Syslog::write("FuelCell.cc:get_status)callback()-- invalid parameter sent");
	  throw Exception("FuelCell.cc:get_status)callback()-- invalid parameter sent");
	  return DeviceIF::Error;
	  break;

	case FCC_ERR_COMM:
	  Syslog::write("FuelCell.cc:get_status)callback()-- comm error");
	  throw Exception("FuelCell.cc:get_status)callback()-- comm error");
	  break;
	  
	  
	}
      
    }
  else
    {

      _output->data.fcc_data.elapsed_time = fcc_data.elapsed_time;
      _output->data.fcc_data.anolyte_pump_a_current = fcc_data.anolyte_pump_a_current;
      _output->data.fcc_data.anolyte_pump_b_current = fcc_data.anolyte_pump_b_current;
      _output->data.fcc_data.catholyte_pump_current = fcc_data.catholyte_pump_current;
      _output->data.fcc_data.peroxide_pump_current = fcc_data.peroxide_pump_current;
      _output->data.fcc_data.anolyte_temp = fcc_data.anolyte_temp;
      _output->data.fcc_data.catholyte_temp = fcc_data.catholyte_temp;
      _output->data.fcc_data.fwd_peroxide_temp = fcc_data.fwd_peroxide_temp;
      _output->data.fcc_data.aft_peroxide_temp = fcc_data.aft_peroxide_temp;
      _output->data.fcc_data.stack_voltage = fcc_data.stack_voltage;
      _output->data.fcc_data.stack_current = fcc_data.stack_current;
      _output->data.fcc_data.battery_voltage = fcc_data.battery_voltage;
      _output->data.fcc_data.battery_current = fcc_data.battery_current;
      _output->data.fcc_data.peroxide_used = fcc_data.peroxide_used;
      try {
	_output->write();
      }


      catch(SharedData::AccessError error)
	{
	  fprintf(stderr,"%s",error.msg);
	  return DeviceIF::Error;
	}

    }
  return DeviceIF::Ok;
}

