/** \file
 *
 *  Contains the LoadControl class declaration.
 *
 *  Copyright (c) 2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 *
 */

#ifndef LOADCONTROL_H_
#define LOADCONTROL_H_

#include "data/Slate.h"
#include "io/DeviceIOStream.h"

class Component;

/**
 *  This class allows one to control loads on a load controller
 *  channel.
 *
 *  \ingroup io
 */
class LoadControl
{
public:
    /// Constructor
    LoadControl( const ConfigURI& loadControlCfg, bool useHardware, Logger& logger, Component* component, const Str& name = Str::EMPTY_STR );

    virtual ~LoadControl();

    /// Turns on the device.
    bool powerUp();

    /// Turns off the device.
    bool powerDown();

    /// Turns off and isolates device.
    bool isolateLoad();

    /// Turns off and de-isolates device (i.e. closes relay)
    bool deisolateLoad();

    /// Turns on discrete;
    bool discreteOn();

    /// Turns off discrete;
    bool discreteOff();

    /// Requests voltage information from LCB and writes it to component writers
    void requestVoltageAndCurrent();

    /// Requests the fault byte
    void requestFaults();

    /// Reads back the fault byte. To be called after requestFaults
    void readFaults();

    /// LCB Fault Byte.
    /*
        //	MSB
    	7: 1 (end-of-transmission indicator)
    	6: spare
    	5: spare
    	4: Current Limiter Activated (1 if true)
    	3: Software overcurrent detection (1 if true)
    	2: Load power shutoff due to current limiter (1 if shutoff)
    	1: Invalid command error (1 if error)
    	0: WDT reset (1 if reset)
    	LSB
    */
    typedef enum { OK = 0,
                   WDT_RESET = 0x01,
                   INVALID_CMD = 0x02,
                   HW_OVERCURRENT_SHUTDOWN = 0x04,
                   SW_OVERCURRENT_WARNING = 0x08,
                   CL_ACTIVATED = 0x10
                 } LCBError;

    /// LCB Fault byte mask used to determine if a fault has occurred
    // NOTE: modifing the byte mask at this time to IGNORE
    // software overcurrent faults (bit 0x08). SW overcurrent requires pre-programing
    // the LCB per device limits, and we no longer maintain that in std vehicle
    // configurations.
    // static const int FAULT_BYTE_MASK = 0x1F;
    static const int FAULT_BYTE_MASK = 0x17;

    enum PowerState       // Correspondence to Component...
    {
        POWER_UNKNOWN,
        POWER_UP,         // ::STARTING & maybe ::RESETTING
        ON,               // ::RUNNABLE
        POWER_DOWN_READY, // ?
        POWER_DOWN,       // ::PAUSING & ::SHUTTING_DOWN & maybe ::RESETTING
        OFF,              // ::SHUTDOWN & maybe PAUSED
    };

    typedef enum
    {
        REQUESTVOLTAGE, // Send request
        PARSEVOLTAGE,   // Read response
        REQUESTCURRENT, // Send request
        PARSECURRENT,   // Read response
        DONE,           // Ready to run
    } LCBData;

    PowerState getPowerState()
    {
        return powerState_;
    }


    bool setPowerStateOn()
    {
        if( powerState_ == POWER_UP )
        {
            powerState_ = ON;
            return true;
        }
        else
            return false;
    }


    bool setPowerStateOff()
    {
        if( powerState_ == POWER_DOWN )
        {
            powerState_ = OFF;
            return true;
        }
        else
        {
            return false;
        }
    }

    bool hasError()
    {
        if( errorStatus_ & FAULT_BYTE_MASK )
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    Str errorString();

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    LoadControl( const LoadControl& old ); // disallow copy constructor};

    /// Initializes power switching to the load control backplane
    void initialize();

    void registerLoadControlWriters( const Str& nameSuffix = Str::EMPTY_STR );

    void logVoltage( float voltage, float averageVoltage );

    void logCurrent( float current, float averageCurrent );

    unsigned short extractCount( char * convertCount, int pos );

    LCBData dataState_;

    DeviceIOStream io_;

    PowerState powerState_;

    bool initialized_;

    Timespan requestTimeout_;
    Timestamp startTime_;

    // The errors reported by the LCB
    int errorStatus_;

    // Writers for load control values
    DataWriter *voltageWriter_;
    DataWriter *avgVoltageWriter_;
    DataWriter *currentWriter_;
    DataWriter *avgCurrentWriter_;

    Component* component_;
};

#endif /* LOADCONTROL_H_ */
