/** \file
 *
 *  Contains the DropWeight class implementation.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#include "DropWeight.h"
#include "DropWeightIF.h"

#include "data/Slate.h"
#include "io/LPC3Reg.h"
#include "units/Units.h"

/*
The minimum rated mechanical life is 5 x 10^7 and the electrical life (for
rated 30 mOhm resistance) is 2 x 10^5. So taking this at face value, worst case,
you can bang the relay continuously every 10 minutes for a minimum of 3.8 years
and still be within the electrical spec. and 950 years and be within the
mechanical spec. We do not care if the resistance goes up a bit in our
application, so the relay should be good for the life of the vehicle.
*/

DropWeight::DropWeight( const Module* module )
    : SyncSensorComponent( DropWeightIF::NAME, module ),
      dropWeightOK_( true ),
      countdownTimer_( Timestamp::NOT_SET_TIME ),
      dropWeightScanTimeout_( 1800 ), // Every 30 minutes
      dropweightcheck_( POWERON )
{
    dropWeightStateWriter_ = newDataWriter( DropWeightIF::DROP_WEIGHT_STATE );
}


DropWeight::~DropWeight()
{
}

void DropWeight::initialize()
{
    setRetryTimeout( Timespan( 900 ) );
    startTime_ = ( Timestamp::Now() - dropWeightScanTimeout_ ); // Check once in the beginning
    run();
}

void DropWeight::run()
{
    if( !simulateHardware() )
    {
        // Always check if the burnwire is active. Otherwise, just when it's time
        if( ( LPC3Reg::IsBurnwireActive() ) || ( startTime_.elapsed() > dropWeightScanTimeout_ ) )
        {
            switch( dropweightcheck_ )
            {
            case POWERON:
                LPC3Reg::ActivateDropweightSense();
                dropweightcheck_ = CHECK;
                break;

            // Actually check status
            case CHECK:
                dropWeightOK_ = LPC3Reg::IsDropweightOK();
                dropweightcheck_ = POWEROFF;
                break;

            // Remove power and isolate the circuit
            case POWEROFF:
                LPC3Reg::DeactivateDropweightSense();
                // Write the data and log any failure
                writeAndLog();
                dropweightcheck_ = DONE;
                break;

            case DONE:
                dropweightcheck_ = POWERON;
                startTime_ = Timestamp::Now(); // reset the clock
                break;

            default:
                logger_.syslog( "Unknown Dropweight state.", Syslog::FAULT );
                this->setFailure( FailureMode::HARDWARE );
                break;
            }
        }
    }
    else
    {
        if( LPC3Reg::IsBurnwireActive() )
        {
            if( countdownTimer_ == Timestamp::NOT_SET_TIME )
            {
                countdownTimer_ = Timestamp::Now();
            }
            else if( countdownTimer_.elapsed().asDouble() > 5.0 )
            {
                dropWeightOK_ = false;
            }
        }
        else
        {
            countdownTimer_ = Timestamp::NOT_SET_TIME;
        }
        // Write the data and log any failure
        writeAndLog();
    }
}


void DropWeight::writeAndLog( void )
{
    dropWeightStateWriter_->write( Units::BOOL, dropWeightOK_ );

    if( dropWeightOK_ )
    {
        setFailure( FailureMode::NONE );
    }
    else
    {
        logger_.syslog( Str( "DROP WEIGHT MISSING.\n" ), Syslog::CRITICAL );
        setFailure( FailureMode::HARDWARE );
    }

}


void DropWeight::uninitialize()
{}

/// Should return [myNamespace]::SIMULATE_HARDWARE, or [myNamespace]::POWER, etc
ConfigURI DropWeight::getConfigURI( ConfigOption configOption ) const
{
    return configOption == CONFIG_SIMULATE_HARDWARE ? DropWeightIF::SIMULATE_HARDWARE : ConfigURI::NO_CONFIG_URI;
}

