// $Header: https://oberon.oapd.inaf.it/shins/trunk/shins/src/tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/SharknirBcuSlopeDiagnosticRecord.h 1147 2019-01-23 15:59:35Z depa $
#pragma once
// #include "basda/service/bcu/worker/ArgosBcuDiagnosticRecordHeader.h"
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/SharknirBcuDiagnosticRecordHeader.h"
#include "tiptilt_ctrl/bcu/util/Assertions.h"

#include <Basda/Microgate/Mgp/MgpHeader.h>
#include <Basda/Microgate/Mgp/ByteBuffer.h>

#include <boost/cstdint.hpp>
#include <boost/static_assert.hpp>

#include <cstring>
#include <string>


namespace Sharknir { namespace Bcu {

/**
 * @brief Structure of the diagnostic record for slopes of the Sharknir BCU.
 *
 * The field names are the same names as in the Argos BCU user manual.
 */
struct SharknirBcuSlopeDiagnosticRecord
{
    enum {
        N_TOTAL_SLOPES= 1600,
        N_SLOPES_PER_SUBAP= 2,
        N_MPIFR_DUMMY_SLOPES= 2,
        N_MPIFR_SLOPES= 2 + N_MPIFR_DUMMY_SLOPES,
        N_LGS_TT_SLOPES= 8,
        N_START_RTR_DWORDS= 4,
        // N_HVC_MEAN_VOLTAGES= 16,
        // N_HVC_MEAN_POSITIONS= 16,
        N_APD_COUNTERS= 4,
        N_FRAME_COUNTERS= 8
    };

    struct FrameCounters
    {
        uint32_t dsc_FrameCounter;
        uint32_t pnCcd_FrameNumber;
        uint32_t timeStamp_MSW;
        uint32_t timeStamp_LSW;
        uint32_t mpifr_FrameNumber;
        uint32_t mpifr_StatusByte;
        uint32_t flao_FramesCounter;
        uint32_t na_FramesCounter;
    };
    BOOST_STATIC_ASSERT(sizeof(FrameCounters) == 32);
    BOOST_STATIC_ASSERT(
       sizeof(FrameCounters)/Basda::Microgate::MgpHeader::DWORD_SIZE_IN_BYTE ==
                        N_FRAME_COUNTERS);

    typedef float Slope;

    DiagnosticRecordHeader sc_HeaderDiag;
    Slope sc_TotalSlopeVector[N_TOTAL_SLOPES];
    uint32_t sc_StartRTR[N_START_RTR_DWORDS];
    Slope sc_TTSlopesVector[N_LGS_TT_SLOPES];
    // float sc_HVCMeanVoltage[N_HVC_MEAN_VOLTAGES];
    // float sc_HVCMeanPosition[N_HVC_MEAN_POSITIONS];
    uint32_t sc_APDCounters[N_APD_COUNTERS];
    FrameCounters sc_FCVector;
    DiagnosticRecordFooter sc_FooterDiag;


    inline bool isBroken() const
    {
        BOOST_STATIC_ASSERT(sizeof(DiagnosticRecordHeader) ==
            sizeof(DiagnosticRecordFooter));
        return 0 != memcmp(&sc_HeaderDiag, &sc_FooterDiag,
            sizeof(DiagnosticRecordHeader));
    }

    static bool isSlopeDiagnosticRecord(
                                    const Basda::Microgate::ByteBufferPtr& b)
    {
        return sizeof(SharknirBcuSlopeDiagnosticRecord) == b->size();
    }

    static std::string getRawSlopesAsString(
            const Basda::Microgate::ByteBufferPtr& b)
    {
        return std::string(reinterpret_cast<const char*>(
                recordCast(b)->sc_TotalSlopeVector),
                sizeof(SharknirBcuSlopeDiagnosticRecord::sc_TotalSlopeVector));
    }

    static uint32_t getMpifrFrameCounter(
                                    const Basda::Microgate::ByteBufferPtr& b)
    {
        return recordCast(b)->sc_FCVector.mpifr_FrameNumber;
    }

    static uint32_t getMpifrStatusByte(
                                   const Basda::Microgate::ByteBufferPtr&  b)
    {
        return recordCast(b)->sc_FCVector.mpifr_StatusByte;
    }

   static uint32_t getDscFrameCounter(
                                   const Basda::Microgate::ByteBufferPtr& b)
   {
       return recordCast(b)->sc_FCVector.dsc_FrameCounter;
   }

   static uint32_t getPnCcdFrameNumber(
                                   const Basda::Microgate::ByteBufferPtr& b)
   {
       return recordCast(b)->sc_FCVector.pnCcd_FrameNumber;
   }

   static uint32_t getApdCounter(const Basda::Microgate::ByteBufferPtr& b,
                                 size_t apdCounterIndex)
   {
       SHARKNIR_PRECONDITION(N_APD_COUNTERS > apdCounterIndex,
               "Valid APD counter accessed");
       return recordCast(b)->sc_APDCounters[apdCounterIndex];
   }


   static std::string getRawTTSlopesAsString(
           const Basda::Microgate::ByteBufferPtr&);

   static std::string getRawMeanVoltageFloatsAsString(
           const Basda::Microgate::ByteBufferPtr&);

   static std::string getRawMeanPositionFloatsAsString(
           const Basda::Microgate::ByteBufferPtr&);

   static std::string getRawFCVectorAsString(
           const Basda::Microgate::ByteBufferPtr&);

private:
   static inline SharknirBcuSlopeDiagnosticRecord* recordCast(
                                   const Basda::Microgate::ByteBufferPtr& b)
   {
        SHARKNIR_PRECONDITION(isSlopeDiagnosticRecord(b), "Must be slope record");
        return (reinterpret_cast<SharknirBcuSlopeDiagnosticRecord*>(&b->front()));

   }
};

// BOOST_STATIC_ASSERT(6656 == sizeof(SharknirBcuSlopeDiagnosticRecord));
BOOST_STATIC_ASSERT(6528 == sizeof(SharknirBcuSlopeDiagnosticRecord)); // new size because HVC rel. members removed
}
}

