#ifndef GRIFO_TIMER_IF_H_
#define GRIFO_TIMER_IF_H_

//#include "grifo_fw_blob.h"
#include <stdint.h>

namespace grifo_fw
{

#define GRIFO_FW_TIMER_IF_DBG_AREA  0 /*148*/

struct timer_raw_if_t
{
    template<unsigned int S_, unsigned int E_> struct spare_t {uint32_t xxx[(E_-S_)/4];};

    enum {
        batch_parity=2,
            batch_odd=0,
            batch_even=1,

        max_prt=128,
        max_unique_prt=8,

        spare_timing=8
    };

    struct prt_fifo_t
    {
        uint32_t fifo[max_prt];
    };

    struct unique_prt_fifo_t
    {
        uint32_t fifo[max_unique_prt];
    };

    struct shift_registers_t
    {
        int32_t B_Filter;   //Batch DET,PC,Dispatcher, reset filters, PC: reset filters
        int32_t B_RF;       //?
        int32_t PT_DET;     //DET: load offset phase
        int32_t PC_Win;     //PC output window
        int32_t RX_SYNC;    //STC and NAGC
    };

    uint32_t tcr;
    uint32_t tpr;
    uint32_t tor;
    uint32_t stsr;

    uint16_t prt_num;
    uint16_t diff_prt_num;

    uint32_t spares__[3];

    shift_registers_t shift;

    uint32_t spare__[19-(3+5)];

    unique_prt_fifo_t aesa_delay[batch_parity];

    spare_t<0x0bf,0x100> spare0__;

    unique_prt_fifo_t exp_pulse1_delay[batch_parity];
    unique_prt_fifo_t exp_pulse2_delay[batch_parity];

    unique_prt_fifo_t pretrigger_det_delay[batch_parity];

    spare_t<0x01bf,0x200> spare1__;

    struct delay_with_period_t
    {
        unique_prt_fifo_t delay;
        unique_prt_fifo_t width;
        unique_prt_fifo_t period;

        spare_t<0x025f,0x280> spare__;
    };
    delay_with_period_t rx_synch[batch_parity];
    delay_with_period_t cf_synch[batch_parity];

    delay_with_period_t ew_synch[batch_parity];
    //delay_with_period_t ant_rxn_synch[batch_parity];

    struct delay_width_t
    {
        unique_prt_fifo_t delay;
        unique_prt_fifo_t width;
    };

    delay_width_t ant_rxn[batch_parity];

    delay_width_t down_blank[batch_parity];
    delay_width_t up_enable[batch_parity];

    delay_width_t blank_out[batch_parity];

    delay_width_t acq_det_window[batch_parity];
    delay_width_t acq_pc_window[batch_parity];

    delay_width_t provision[batch_parity][spare_timing];

    spare_t<0x0bff,0x1000> spare_pre_prt__;

    prt_fifo_t prt_fifo_odd;

    spare_t<0x011ff,0x1400> spare_pre_prt_even__;

    prt_fifo_t prt_fifo_even;
#if GRIFO_FW_TIMER_IF_DBG_AREA>0
    uint32_t dbg_marker_prog_end;
    uint32_t dbg_info;
    uint32_t dbg_sw_data[148];
#endif
};


class timer_blob_t; //typedef grifo_fw_blob_typed_t<timer_raw_if_t, 0x54494d45/*="TIME"*/> timer_blob_t;

extern timer_raw_if_t* timer_blob_payload(const timer_blob_t* b=0);

extern void timer_initialize_raw_default_blob(void* raw_memory);

extern void timer_initialize_default_blob(timer_blob_t* blob);
extern timer_blob_t* timer_get_default_blob();
extern timer_raw_if_t* timer_get_default_if(void);

typedef uint32_t timer_ticks_t;

static inline timer_ticks_t timer_duration(timer_ticks_t ticks)
{
    return ticks<1 ? 1 : ticks;
}

static inline timer_ticks_t timer_delay(timer_ticks_t ticks)
{
    enum { k_invalid_duration=0x0FFFFF};
    return ticks<1 ? static_cast<timer_ticks_t>(k_invalid_duration) : ticks;
}


extern int timer_set_det_pretrigger_delay(grifo_fw::timer_raw_if_t* td, unsigned int delay_ticks, unsigned int pulses);

extern void timer_generate_align_check_test_pattern(timer_raw_if_t* buffer);
extern int timer_fix_unused_pri(timer_raw_if_t* td, unsigned int num_of_prt_dur);

extern void timer_fix_holes(timer_raw_if_t* buffer);

extern int timer_add_dbg_raw_data(timer_raw_if_t* buffer, const void* data, unsigned int size);

template<typename T_> static inline int timer_add_dbg_data(timer_raw_if_t* buffer, const T_* data)
{
    return timer_add_dbg_raw_data(buffer, data, sizeof *data);
}


//HR
extern void timer_initialize_raw_hr_blob(void* raw_memory);

extern void timer_initialize_hr_blob(timer_blob_t* blob);
extern timer_blob_t* timer_get_hr_blob();
extern timer_raw_if_t* timer_get_hr_if(void);

} /*namespace*/


#if 0
//TODO: the timer I/F could be independent on the blob, only the allocators and I/F implementation have to be dependent

#include "grifo_fw_blob.h"
namespace grifo_fw
{

class timer_blob_t: public grifo_fw_blob_typed_t<timer_raw_if_t, 0x54494d45/*="TIME"*/>
{
};

}
#endif

#endif /*GRIFO_TIMER_IF_H_*/
