/*-----------------------------------------------------------------------*
  CLASS: Watchdog

  DESCRIPTION: 

  $Id: Watchdog.cc,v 1.4 2000/09/15 19:50:53 jrieffel Exp $
  *-----------------------------------------------------------------------*/

#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <errno.h>
#include <iostream.h>


#include "Syslog.h"
#include "SerialDevice.h"
#include "Watchdog.h"
#include "WatchdogCommand.h"

//every second for now, but this should be read from a config file eventually
#define KEEPALIVE_PERIOD 1000
#define COMMAND_HANDLER_PERIOD 2000

//five minutes for now, but this should also be read form a config file
#define DEADMAN_TIMEOUT_HOURS 00
#define DEADMAN_TIMEOUT_MINUTES 05
#define DEADMAN_TIMEOUT_SECONDS 00

#define READ_TIMEOUT 500
#define SHORT_WAIT 500

SerialDevice::lineFormat watchdogLineFormat = { 9600, 8, 1, "NONE" };

//== The members =================================================

Watchdog::Watchdog(SerialDevice *device,  SerialParameters *serialParams)
     : PeriodicTask("Watchdog")
{
     _device = device;
     _serialParams = serialParams;

     _command = new WatchdogCommand(MessageQueue::Read);
     _command->flush();
     _output = new WatchdogOutput(SharedData::ReadWrite);
     
     init();

     // now add the periodic callback

     
     addPeriodicCallback(KEEPALIVE_PERIOD, (CallbackMethod)Watchdog::keepAlive_callback);   

     addPeriodicCallback(COMMAND_HANDLER_PERIOD, (CallbackMethod)Watchdog::wd_command_handler);
}

Watchdog::~Watchdog()
{
   delete _output;
}

DeviceIF::Status Watchdog::init()
{

  //== Initialize the serial port =================================

  _device->commsDebugMode(SerialDevice::DebugOff);
  //  _device->commsDebugMode(SerialDevice::DebugOn);
  
  // initialize serial port
  _device->setLineFormat( &watchdogLineFormat );
  
  // clear serial port
  _device->clearPort();
  _device->flushReceiveBuf();
  
  Syslog::write("Watchdog.cc -- Watchdog configured.");


  return DeviceIF::Ok;


} 


DeviceIF::Status Watchdog::keepAlive_callback()
{

  char buf[30];
  char command_string[30];
  char reply[50];

  int i;
  int nconv;

  // OKEY, first make sure that the deadman timer _should_ be on
  // so I put something in the Watchdog Output
  
  _output->read();
  
  if (_output->data.deadman_on)
    {
      //keepalive commands are of the form:
      // #WD K hh.mm.ss: <cr><lf>
      
      sprintf(command_string, "WD K %2.2d.%2.2d.%2.2d:", _output->data.deadman_time_hh, _output->data.deadman_time_mm, _output->data.deadman_time_ss);
	      
	      
      sprintf(buf,"#%s\xa\xd",command_string);
      _device->write(buf, strlen(buf));
      
      Syslog::write("Watchdog: sending the following string: %s\n", buf);
      // we should now get the command string back, preceded by a "$"
      sprintf(buf,"$%s", command_string);
      
      Syslog::write("Watching: expecting the following response: %s\n",buf);
      
      if (_device->confirm (buf, SHORT_WAIT) == -1)
	{
	  Syslog::write("Watchdog::keepAlive_callback() -- didn't get appropriate response from WD\n");
	  return DeviceIF::Error;
	}
      
      //ookey, so the remainder of the string should be of the form:
      // %c KT hh.mm.ss;WD %c;ST %2.2d;SP %2.2d;AM %c;ARB %c; <cr><lf>
      // see spec for details.
      
      _device->readUntil(reply, sizeof(reply), "\xa", READ_TIMEOUT);
      
      Syslog::write("Watchdog reply is: %s\n",reply);
      
      nconv = sscanf(reply, "%c KT %2d.%2d.%2d;WD %c;ST %d;SP %2.2d;AM %c;ARB %c;",
		     _wd_data.wd_error_status,
		     _wd_data.keepalive_time.hh,
		     _wd_data.keepalive_time.mm,
		     _wd_data.keepalive_time.ss,
		     _wd_data.wd_status,
		     _wd_data.sphere_temp,
		     _wd_data.sphere_pressure,
		     _wd_data.antenna_status,
		     _wd_data.arb_msg
		     );
      
      if (nconv == 9)
	{
	  
	  // data was read correctly
	  
	  // hm, maybe should trigger an event advertising the recieved ARB message?
	  // or simply take action via LayeredControlIF?
	  
	  // write to the output
	  _output->data.wd_error_status = _wd_data.wd_error_status;
	  _output->data.keepalive_time_hh = _wd_data.keepalive_time.hh;
	  _output->data.keepalive_time_mm = _wd_data.keepalive_time.mm;
	  _output->data.keepalive_time_ss = _wd_data.keepalive_time.ss;
	  _output->data.wd_status = _wd_data.wd_status;
	  _output->data.sphere_temp = _wd_data.sphere_temp;
	  _output->data.sphere_pressure = _wd_data.sphere_pressure;
	  _output->data.mast_status = _wd_data.antenna_status;
	  _output->data.arb_msg = _wd_data.arb_msg;
	  
	  _output->write();
	  
	}
      else
	{
	  Syslog::write("Watchdog.cc keepalive_callback(): erro sscanfing reply, nconv was : %d\n", nconv);
	  return DeviceIF::Error;
	}
    }
  else
    {
      Syslog::write("Watchdog.cc keepalive_callback(): Deadman is _off_\n");
    }
  

  return DeviceIF::Ok;
  
}


DeviceIF::Status Watchdog::parse_wd_reply(char *reply)
{

  int nconv;
  
  nconv = sscanf(reply, "%c KT %2d.%2d.%2d;WD %c;ST %d;SP %2.2d;AM %c;ARB %c;",
		     _wd_data.wd_error_status,
		     _wd_data.keepalive_time.hh,
		     _wd_data.keepalive_time.mm,
		     _wd_data.keepalive_time.ss,
		     _wd_data.wd_status,
		     _wd_data.sphere_temp,
		     _wd_data.sphere_pressure,
		     _wd_data.antenna_status,
		     _wd_data.arb_msg
		     );
      
      if (nconv == 9)
	{
	  
	  // data was read correctly
	  
	  // hm, maybe should trigger an event advertising the recieved ARB message?
	  // or simply take action via LayeredControlIF?
	  
	  // write to the output
	  _output->data.wd_error_status = _wd_data.wd_error_status;
	  _output->data.keepalive_time_hh = _wd_data.keepalive_time.hh;
	  _output->data.keepalive_time_mm = _wd_data.keepalive_time.mm;
	  _output->data.keepalive_time_ss = _wd_data.keepalive_time.ss;
	  _output->data.wd_status = _wd_data.wd_status;
	  _output->data.sphere_temp = _wd_data.sphere_temp;
	  _output->data.sphere_pressure = _wd_data.sphere_pressure;
	  _output->data.mast_status = _wd_data.antenna_status;
	  _output->data.arb_msg = _wd_data.arb_msg;
	  
	  _output->write();
	  
	}
      else
	{
	  Syslog::write("Watchdog.cc parse_wd_reply(): erro sscanfing reply, nconv was : %d\n", nconv);
	  return DeviceIF::Error;
	}
      return DeviceIF::Ok;

}


DeviceIF::Status Watchdog::wd_command_handler()
{
  // do some stuff
  
  char buf[30];
  char command_string[30];
  char reply[50];
  
  int i;
  int nconv;
	  
  WatchdogCommand::Command cmdIn;
  
  while( (_command->read( &cmdIn )) > 0 ) 
    {
      switch( cmdIn.cmd ) 
	{
	case WatchdogCommand::DeadmanOn:
	  
	  sprintf(command_string, "WD DY:", _output->data.deadman_time_hh, _output->data.deadman_time_mm, _output->data.deadman_time_ss);
	  sprintf(buf,"#%s\xa\xd",command_string);
	  _device->write(buf, strlen(buf));
	  Syslog::write("Watchdog: sending the following string: %s\n", buf);
	  // we should now get the command string back, preceded by a "$"
	  sprintf(buf,"$%s", command_string);
	  Syslog::write("Watching: expecting the following response: %s\n",buf);
	  try{
	    _device->confirm (buf, SHORT_WAIT);
	      }
	  catch (...)
	    {
	      Syslog::write("Watchdog::keepAlive_callback() -- didn't get appropriate response from WD\n");
	      //	      return DeviceIF::Error;
	    }
	  
	  try {
	  _device->readUntil(reply, sizeof(reply), "\xa", READ_TIMEOUT);
	  }
	  catch (...)
	    {
	      Syslog::write("Watchodog::command_callback -- didn't get response from WD");
	    }
	  
	  Syslog::write("Watchdog reply is: %s\n",reply);
	  // thank goodness I wrote a parsing function!
	  // i should really write a send_command funciton too,
	  // but darn cut 'n' paste
	  parse_wd_reply(reply);
	  // now that everything has parsed, set deadman to on.
	  Syslog::write("Setting deadman on Anyway!\n");
	  _output->data.deadman_on = 1;
	  _output->write();
	  break;

	case WatchdogCommand::DeadmanOff:

	  sprintf(command_string, "WD DN:", _output->data.deadman_time_hh, _output->data.deadman_time_mm, _output->data.deadman_time_ss);
	  sprintf(buf,"#%s\xa\xd",command_string);
	  _device->write(buf, strlen(buf));
	  Syslog::write("Watchdog: sending the following string: %s\n", buf);
	  // we should now get the command string back, preceded by a "$"
	  sprintf(buf,"$%s", command_string);
	  Syslog::write("Watching: expecting the following response: %s\n",buf);
	  
	  try{
	    _device->confirm (buf, SHORT_WAIT);
	  }
	  catch (...)
	    {
	      Syslog::write("Watchdog::keepAlive_callback() -- didn't get appropriate response from WD\n");
	      //	      return DeviceIF::Error;
	    }
	  
	  try {
	  _device->readUntil(reply, sizeof(reply), "\xa", READ_TIMEOUT);
	  }
	  catch (...)
	    {
	      Syslog::write("Watchodog::command_callback -- didn't get response from WD");
	    }
	  
	  Syslog::write("Watchdog reply is: %s\n",reply);
	  // thank goodness I wrote a parsing function!
	  // i should really write a send_command funciton too,
	  // but darn cut 'n' paste
	  parse_wd_reply(reply);
	  // now that everything has parsed, set deadman to on.
	  
	  _output->data.deadman_on = 0;
	  _output->write();

	  break;

	case WatchdogCommand::RaiseAntenna:
	  // send the raise-antenna command via the serial port
	  
	  	  sprintf(command_string, "WD AMU:", _output->data.deadman_time_hh, _output->data.deadman_time_mm, _output->data.deadman_time_ss);
	  sprintf(buf,"#%s\xa\xd",command_string);
	  _device->write(buf, strlen(buf));
	  Syslog::write("Watchdog: sending the following string: %s\n", buf);
	  // we should now get the command string back, preceded by a "$"
	  sprintf(buf,"$%s", command_string);
	  Syslog::write("Watching: expecting the following response: %s\n",buf);
	    try{
	    _device->confirm (buf, SHORT_WAIT);
	      }
	  catch (...)
	    {
	      Syslog::write("Watchdog::keepAlive_callback() -- didn't get appropriate response from WD\n");
	      //	      return DeviceIF::Error;
	    }
	  
	  try {
	  _device->readUntil(reply, sizeof(reply), "\xa", READ_TIMEOUT);
	  }
	  catch (...)
	    {
	      Syslog::write("Watchodog::command_callback -- didn't get response from WD");
	    }
	  
	  Syslog::write("Watchdog reply is: %s\n",reply);
	  // thank goodness I wrote a parsing function!
	  // i should really write a send_command funciton too,
	  // but darn cut 'n' paste
	  parse_wd_reply(reply);
	  // now that everything has parsed, set deadman to on.
	  
	  break;
	  
	case WatchdogCommand::LowerAntenna:
	  // send the lower-antenna command
	  
	  	  sprintf(command_string, "WD AMD:", _output->data.deadman_time_hh, _output->data.deadman_time_mm, _output->data.deadman_time_ss);
	  sprintf(buf,"#%s\xa\xd",command_string);
	  _device->write(buf, strlen(buf));
	  Syslog::write("Watchdog: sending the following string: %s\n", buf);
	  // we should now get the command string back, preceded by a "$"
	  sprintf(buf,"$%s", command_string);
	  Syslog::write("Watching: expecting the following response: %s\n",buf);
	    try{
	    _device->confirm (buf, SHORT_WAIT);
	      }
	  catch (...)
	    {
	      Syslog::write("Watchdog::keepAlive_callback() -- didn't get appropriate response from WD\n");
	      //	      return DeviceIF::Error;
	    }
	  
	  try {
	  _device->readUntil(reply, sizeof(reply), "\xa", READ_TIMEOUT);
	  }
	  catch (...)
	    {
	      Syslog::write("Watchodog::command_callback -- didn't get response from WD");
	    }
	  Syslog::write("Watchdog reply is: %s\n",reply);
	  // thank goodness I wrote a parsing function!
	  // i should really write a send_command funciton too,
	  // but darn cut 'n' paste
	  parse_wd_reply(reply);
	  // now that everything has parsed, set deadman to on.
	  
	  break;
	  
	default:
	  break;
	}
    }
  return DeviceIF::Ok;
}

