/** \file
 *
 *  Contains the NanoDVR class declaration.
 *
 *  NanoDVR.h should only be included by NanoDVR.cpp
 *  Other classes should include NanoDVRIF.h
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef NANODVR_H
#define NANODVR_H

#include "component/SyncComponent.h"
#include "io/UartStream.h"
#include "io/LoadControl.h"
#include "logger/Logger.h"

class UniversalDataWriter;

/**
 *  Provides software interface to the Nano DVR “Pro” Encoder.
 *
 *  \ingroup modules_science
 */

class NanoDVR : public SyncSensorComponent
{
public:

    NanoDVR( const Module* module );

    virtual ~NanoDVR();

    virtual void run();

    /// Do what needs to be done to run
    /// Similar to initialize, in old init/run/uninit sequence
    virtual RunState start();

    /// Might follow a STOP...START sequence
    virtual RunState starting();

    /// Pause for a short period (indicated by pauseTime)
    virtual RunState pause();

    /// Should eventually follow a PAUSE request: should set continueTime
    virtual RunState paused();

    /// Resume from PAUSE
    virtual RunState resume();

    /// Might follow a PAUSE...RESUME sequence
    virtual RunState resuming();

    /// Should eventually follow a START request or RESETTING
    virtual RunState runnable();

    /// Might occur in case of Error
    virtual RunState resetting()
    {
        return start();
    }

    /// Initial state -- can be later followed by START
    virtual RunState stop();

    virtual RunState stopping();

    /// Initial state -- can be later followed by START
    virtual RunState stopped();

    /// Should return [myNamespace]::SIMULATE_HARDWARE, or [myNamespace]::POWER, etc
    virtual ConfigURI getConfigURI( ConfigOption configOption ) const;

protected:

    /// Nano DVR constants
    static const unsigned char SYNC = 0xA5; /* Message Sync */
    static const unsigned char ACK  = 0xBB; /* ACK */
    static const unsigned char NACK = 0xCC; /* NACK */

    static const unsigned int NANO_DVR_HEADER_SIZE        =  4; /* Size of msg header (bytes) */
    static const unsigned int NANO_DVR_ACK_MSG_SIZE       =  7; /* Size of ack/nack msg (bytes) */
    static const unsigned int NANO_DVR_POWER_OFF_MSG_SIZE =  8; /* Size of power off msg (bytes) */
    static const unsigned int NANO_DVR_SET_TIME_MSG_SIZE  = 10; /* Size of set time msg (bytes) */
    static const unsigned int NANO_DVR_SET_REC_MSG_SIZE = 6; /* Size of set rec msg (bytes) */

    static const unsigned int NANO_DVR_MUX_NUM; /* Nano DVR Mux setting for connected camera */

#pragma pack(1)
    /// Nano DVR message header definition
    typedef struct NanoHeader_def
    {
        // packet header
        unsigned char msgSync_;    /* Sync byte */
        unsigned char msgID_;      /* Unique message identifier for ack/nack message */
        unsigned char checksum_;   /* Sum of all message elements (excluding the checksum element) */
        unsigned char dataLength_; /* Total number of bytes in packet payload */

        NanoHeader_def( unsigned char msgID, unsigned char dataLength, unsigned char checksum = 0x00 );

        NanoHeader_def( const NanoHeader_def& header );

    } NanoHeader;
#pragma pack()

#pragma pack(1)
    /// Nano DVR ACK/NACK message format definition
    typedef struct AckMsg_def
    {
        // packet header
        NanoHeader header_;

        // packet payload
        unsigned char ack_;      /* ACK (0xBB) or NACK (0xCC) */
        unsigned char ackMsgID_; /* Message ID the ACK/NAK refers to */
        unsigned char errNum_;   /* A unique error identifier (not implemented) */

        AckMsg_def();

    } AckMsg;
#pragma pack()

#pragma pack(1)
    /// Nano DVR power off message format definition
    typedef struct PowerOff_def
    {
        // packet header
        NanoHeader header_;

        // packet payload
        unsigned char magic1_;
        unsigned char magic2_;
        unsigned char magic3_;
        unsigned char magic4_;

        PowerOff_def();

    } PowerOffMsg;
#pragma pack()

#pragma pack(1)
    /// Nano DVR set time and date message format definition
    typedef struct SetTime_def
    {
        // packet header
        NanoHeader header_;

        // packet payload
        unsigned char hour_;   /* 0-23 */
        unsigned char minute_; /* 0-59 */
        unsigned char second_; /* 0-59 */
        unsigned char day_;    /* 1-31 */
        unsigned char month_;  /* 1-12 */
        unsigned char year_;   /* 2 last digits of year, startig from 2000 (e.g., 2013 - 2000 = 13) */

        SetTime_def();

    } SetTimeMsg;
#pragma pack()

#pragma pack(1)
    /// Nano DVR power off message format definition
    typedef struct SetRec_def
    {
        // packet header
        NanoHeader header_;

        // packet payload
        unsigned char muxNum_; /* Mux Number 0-N */
        unsigned char rec_;    /* 0 – Stop, 1 – Start */

        SetRec_def();

    } SetRecMsg;
#pragma pack()

    /// Sets the time on the NanoDVR to the current application time
    bool setTime( void );

    /// Commands the NanoDVR to start recording on NANO_DVR_MUX_NUM
    bool startRec( void );

    /// Commands the NanoDVR to stop recording
    bool stopRec( void );

    /// Formulates and sends NanoDVR set rec commands
    bool setRec( bool record );

    /// Commands the NanoDVR to power off
    bool powerNanoOff( void );

    /// Reads and parses NanoDVR Ack/Nack messages
    bool readNanoAck( void );

    /// Computes a checksum for NanoDVR messages
    unsigned char calcChecksum( char* msgBuffer, int msgSize );

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

    //*------------------- vehicle parameters --------------------------*/

    // Power for the Nano encoder
    LoadControl loadControl_;

    void logVoltageAndCurrent( void );

    // Holds the communications device
    UartStream uart_;

    ///////////////////////////////////

    // initialize vehicle config variables
    bool readConfig( void );

    // returns true if data is requested from one of the readers
    bool isDataRequested();

    /// Timeout for powering down/up
    Timespan powerOnTimeout_;

    // Time in seconds that the NanoDVR is programmed to sample plus the warmup time
    Timespan sampleTimeout_;

    /// Time data request started
    Timestamp startTime_;

    /// True when recording is in progress
    bool sampling_;

    /// Debugging outputs
    bool debug_;

    /// Stores the current response from NanoDVR
    char deviceResponse_[256];

    DataWriter* samplingNanoDVRDataWriter_;

    ConfigReader* sampleTimeCfgReader_;

    void sendCmd( char* cmd, unsigned int cmdSize );

    void printBufferHex( const char *prefix, const char *buffer, unsigned int length, Syslog::Severity severity = Syslog::ERROR );

};
#endif /*NANODVR_H*/
