/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : DropWeight.cc                                                 */
/* Author   : rsm                                                           */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include "DropWeight.h"
#define READ_TIMEOUT 3000           //Milliseconds
#define MAXRECORDBYTES 1025 
#include "StreamSerialDriver.h"
#include "SerialDevice.h"
#include "Syslog.h"

Boolean debug = False;

DropWeight::DropWeight(SerialDevice *device)
   : StreamSerialDriver("dropWeightDriver", device, MAXRECORDBYTES, "\xa",
			READ_TIMEOUT)
{
   WatchDogTimeout = 0;
   Counter = 0;
   _log = new DropWeightLog(this, DataLog::BinaryFormat);
   _dwOutput = new DropWeightOutput();
   _dwOutput->data.Release = 0;
   _dwOutput->data.Reset = 0;
   _dwOutput->data.FireGulper = 0;
   _dwOutput->write();
   ReleaseState = NotDropped;
}


DropWeight::~DropWeight()
{
   Syslog::write(" DropWeight Destructor Executing.");
   delete _log;
   delete _dwOutput;
}


DeviceIF::Status DropWeight::initialize()
{
   char *resetAll = "!R\r";
   //
   // Reset both the watchdog and the burn wire counters:
   //
   try{ _device->write( resetAll, strlen(resetAll) ); }
   catch(...) 
   {
      Syslog::write(" Dropweight::initialize - Error resetting the "
		    "dropweight watchdog timer.");
      return DeviceIF::Error;
   }
   Syslog::write(" DropWeight::initialize - Resetting counters.");
   return DeviceIF::Ok;
}

DeviceIF::Status DropWeight::processRecord(unsigned char *record,
					   int nRecordBytes)
{
   //
   // Read in the drop weight data.
   //
   // Beware that readRecord() is automatically called by the parent class.  
   // It fills in *record, using readUntil.  The read time out and terminating 
   // character are set at the head of this file and passed up by the 
   // constructor. 
   //
   int nRead = 0;
   printf(" %s", record);
   nRead = sscanf(  (char *)record,  "wdt = %hd,  bwt = %hd,  WDC = %hd,  "
		    "ACommsDN = %hd,  DW_out = %hd, "
		    "GulperSolenoidOut = %hd,  GulperProxIn = %hd, "
		    "GulperHighSideStat = %hd,    GulperSolenoidFB = %hd", 
		    &Wdt, &Bwt, &WDC, &ACommsDN, &DW_out,
		    &GulperSolenoidOut, &GulperProxIn, &GulperHighSideStat,
		    &GulperSolenoidFB);
   if( nRead != 9 && 0)
   {
      //
      // Make sure there is a terminating null before writing it.
      //
      if( strlen((char*)record) >= 1024 ) record[1024] = '\0';
      Syslog::write(" %s", record);
   }

   //
   // Note: If the support ship commands a weight release over the acoustic
   // modem, ACommsDN goes high, and the burn wire circuit is closed.  This
   // is outside of the PIC, and thus unaffected by resetting Wdt or Bwt.
   // Therefore, this driver doesn't need to check the state of ACommsDN, and
   // can continue to reset Wdt even if the acoustic modem commands a
   // release.
   //
   if (nRead == 9 && !ACommsDN) {exit(-1);}
   //
   // Either release the weight or reset the timer.
   //
   _dwOutput->read();
   if ( _dwOutput->data.Release == 1 ) 
   { 
      //
      // Release the weight if the behavior says to.  Only do this
      // once. (Really twice).
      //
      if( ReleaseState == NotDropped) 
      {
	 release();
	 //
	 // DW_out will be true on the next pass through.
	 //
	 //if( DW_out ) ReleaseState = Dropped;
	 ReleaseState = Dropped;
      }
   } 
   else
   {
      //
      // Otherwise reset the watchdog.
      //
      Counter++;
      if( Counter % 10 == 0 )
      {
	 Counter = 0;
	 resetWatchdog();
      }
      //
      // Give the behavior the ability to reset the ReleaseState, even if the
      // weight is actually gone.  Note: At this time there is no mechanism
      // to reset Release back to zero.
      //
      ReleaseState = NotDropped;
   }
   //
   // Perform externally requested resets.  Do not resume periodic watchdog
   // resets.  Do not reset the state to NotDropped.
   //
   if( _dwOutput->data.Reset == 1 )  
   {
      Counter = 0;
      Syslog::write(" Resetting the watchdog timer.");
      resetWatchdog();
      _dwOutput->data.Reset = 0; 
   }
   else if( _dwOutput->data.Reset == 2 )  
   {
      Counter = 0;
      Syslog::write(" Resetting the counters and the relay.");
      resetRelayAndCounters();
      _dwOutput->data.Reset = 0; 
   } 
   else if( _dwOutput->data.Reset == 3 )
   {
      Counter = 0;
      Syslog::write(" Resetting the relay and the PIC.");
      resetRelayAndPIC();
      _dwOutput->data.Reset = 0; 
   }
   if (_dwOutput->data.FireGulper) {
	fireGulper();
        _dwOutput->data.FireGulper = 0;
   }
   //
   // Write the data out.
   //
   _dwOutput->data.Wdt = Wdt;
   _dwOutput->data.Bwt = Bwt;
   _dwOutput->data.ACommsDN = ACommsDN;
   _dwOutput->data.DW_out = DW_out;
   _dwOutput->ReleaseState = ReleaseState;
   _dwOutput->write();
   //
   // Log the data.
   //
   _log->write();
   return DeviceIF::Ok;
}


void DropWeight::release(void)
{
   char *releaseWeight = "!D\r";
   Syslog::write(" DropWeight::release - Drop the weight!");
   try {_device->write( releaseWeight, strlen(releaseWeight) ); }
   catch( ... ) 
   { 
      Syslog::write(" Dropweight::release - "
		    "Error releasing the weight."); 
   }
}

void DropWeight::fireGulper(void)
{
     char *cmdStr = "!G\r";
     Syslog::write(" DropWeight::fireGulper - take a drink!");
     try {_device->write(cmdStr, strlen(cmdStr)); }
     catch( ... ) {
	Syslog::write("DropWeight::fireGuler - error");
     }
}

short DropWeight::watchdogTimeout(void)
{
   return Wdt;
}


void DropWeight::resetWatchdog(void)
{
   char *resetWDog = "!\r";
   dprintf(" Reset the countdown timer.\n");
   try {_device->write( resetWDog, strlen(resetWDog) ); }
   catch( ... ) 
   { 
      Syslog::write(" DropWeight::resetWatchdog - Error writing the !"); 
   }
}


void DropWeight::resetRelayAndCounters(void)
{
   char *reset = "!R\r";
   Syslog::write(" Reset both timers and also the Relay.");
   try {_device->write( reset, strlen(reset) ); }
   catch( ... ) 
   { 
      Syslog::write(" DropWeight::resetRelayAndCounters"
		    " - Error writing the !"); 
   }
}


void DropWeight::resetRelayAndPIC(void)
{
   char *reset = "!@\r";
   Syslog::write(" Reset the PIC and the Relay.");
   try {_device->write( reset, strlen(reset) ); }
   catch( ... ) 
   { 
      Syslog::write(" DropWeight::resetRelayAndPIC - Error writing the !@"); 
   }
}


int DropWeight::spawnAuxTasks()
{
   return 0;
}
