/*
 * grifo-expander_if.cpp
 *
 */

#include "grifo_fw_blob.h"
#include "grifo_expander_if.h"

namespace grifo_fw
{

class expander_blob_t: public grifo_fw_blob_typed_t<expander_raw_if_t, 0x80434F4D/*="PCOM"*/>
{
};

expander_blob_t* expander_default_blob__;
expander_blob_t* expander_hr_default_blob__;

}


grifo_fw::expander_raw_if_t* grifo_fw::expander_blob_payload(const grifo_fw::expander_blob_t* b)
{
    if (b==0)
        b=grifo_fw::expander_default_blob__;

    return &const_cast<grifo_fw::expander_blob_t*>(b)->payload;
}


static void exp_initialize_raw_default_blob(grifo_fw::expander_blob_t** bp, void* raw_memory)
{
    grifo_fw::expander_blob_t* b=reinterpret_cast<grifo_fw::expander_blob_t*>(raw_memory);
    b->initialize();

    b->payload.ctrl=1<<16;

    b->payload.mof_fifo[0]=grifo_fw::expander_raw_if_t::mof_cw;
    b->payload.wf1.amp_peak[0]=0x0FFFF;
    b->payload.wf1.frq_start[0]=grifo_fw::expander_frequency_convert_mhz(16);
    b->payload.wf1.len[0]=grifo_fw::expander_len_convert_usec(50);

    b->payload.wf2=b->payload.wf1;

    b->header.work_size=(sizeof b->payload)/4;
    *bp=b;
}

void grifo_fw::expander_initialize_raw_default_blob(void* raw_memory)
{
	exp_initialize_raw_default_blob(&expander_default_blob__, raw_memory);
#if 0
    grifo_fw::expander_blob_t* b=reinterpret_cast<grifo_fw::expander_blob_t*>(raw_memory);
    b->initialize();

    b->payload.ctrl=1<<16;

    b->payload.mof_fifo[0]=expander_raw_if_t::mof_cw;
    b->payload.wf1.amp_peak[0]=0x0FFFF;
    b->payload.wf1.frq_start[0]=expander_frequency_convert_mhz(16);
    b->payload.wf1.len[0]=expander_len_convert_usec(50);

    b->payload.wf2=b->payload.wf1;

    b->header.work_size=(sizeof b->payload)/4;
    expander_default_blob__=b;
#endif
}

grifo_fw::expander_blob_t* grifo_fw::expander_get_default_blob()
{
    return expander_default_blob__;
}

grifo_fw::expander_raw_if_t* grifo_fw::expander_get_default_if()
{
    return expander_blob_payload(0);
}

void grifo_fw::expander_initialize_raw_hr_blob(void* raw_memory)
{
	exp_initialize_raw_default_blob(&expander_hr_default_blob__, raw_memory);
}

grifo_fw::expander_blob_t* grifo_fw::expander_get_hr_blob()
{
    return expander_hr_default_blob__;
}

grifo_fw::expander_raw_if_t* grifo_fw::expander_get_hr_if()
{
    return expander_blob_payload(expander_hr_default_blob__);
}

static void exp2_off()
{
	grifo_fw::expander_blob_t* b2=grifo_fw::expander_hr_default_blob__;
	if (!b2)
		return;
	b2->payload.ctrl=1<<16;

    for(int i=0; i<grifo_fw::expander_raw_if_t::fifo_len; ++i)
    {
    	b2->payload.mof_fifo[0]=0;
    }
}

//void expander_mode_set(unsigned int different_prt_num);
void grifo_fw::expander_test_cw_setup(unsigned int exp_reset, float feq_mhz, float len_us, float delta_hz)
{
    expander_test_cw_raw_setup(expander_frequency_convert_mhz(feq_mhz), expander_len_convert_usec(len_us));

    grifo_fw::expander_blob_t* b=expander_default_blob__;
    if (!b)
        return;

    if (delta_hz)
    {
        //const float d_lsb=((4294.967296f/expander_raw_if_t::FRQ_BASE_MHZ)/float(expander_raw_if_t::FRQ_LEN_MHZ))*10000000;
        int delta=expander_delta_convert_hz_224(delta_hz);
        b->payload.mof_fifo[0]=expander_raw_if_t::mof_ramp;

        b->payload.wf1.incr[0]=delta; //*d_lsb;
    }
    else
    {

    }
    if (exp_reset)
    {
        b->payload.mof_fifo[0]|=(exp_reset<<8);
    }
    else
    {
        b->payload.mof_fifo[0]|=(7<<8);//reset on start|end of waveform|reset on star of batch
    }

    exp2_off();
}

void grifo_fw::expander_prt_set(unsigned int prt_n, const expander_prf_settings_t& s)
{
    grifo_fw::expander_blob_t* b=expander_default_blob__;
    if (!b)
        return;
    b->payload.ctrl=prt_n<<16;
    //b->payload.ctrl=1<<16;
    uint32_t cmd=s.mof|(s.reset<<8);

    for(int i=0; i<expander_raw_if_t::fifo_len; ++i)
    {
        b->payload.mof_fifo[i]=cmd;

        b->payload.wf1.amp_peak[i]=s.amp_peak;
        b->payload.wf1.frq_start[i]=s.frq_start;
        b->payload.wf1.incr[i]=s.frq_inc;
        b->payload.wf1.len[i]=s.frq_len;
        b->payload.wf1.address[i]=s.wf_address;

        b->payload.wf2.amp_peak[i]=s.amp_peak;
        b->payload.wf2.frq_start[i]=s.frq_start;
        b->payload.wf2.incr[i]=s.frq_inc;
        b->payload.wf2.len[i]=s.frq_len;
        b->payload.wf2.address[i]=s.wf_address;
    }

    exp2_off();
}

void grifo_fw::expander_prt_set1(unsigned int prt_n, const expander_prf_settings_t& s)
{
    grifo_fw::expander_blob_t* b=expander_default_blob__;
    if (!b)
        return;
    b->payload.ctrl=prt_n<<16;
    //b->payload.ctrl=1<<16;
    uint32_t cmd=s.mof|(s.reset<<8);

    for(int i=0; i<expander_raw_if_t::fifo_len; ++i)
    {
        b->payload.mof_fifo[i]=cmd;

        b->payload.wf1.amp_peak[i]=s.amp_peak;
        b->payload.wf1.frq_start[i]=s.frq_start;
        b->payload.wf1.incr[i]=s.frq_inc;
        b->payload.wf1.len[i]=s.frq_len;
        b->payload.wf1.address[i]=s.wf_address;

        b->payload.wf2.amp_peak[i]=s.amp_peak;
        b->payload.wf2.frq_start[i]=s.frq_start;
        b->payload.wf2.incr[i]=s.frq_inc;
        b->payload.wf2.len[i]=s.frq_len;
        b->payload.wf2.address[i]=s.wf_address;
    }
}

void grifo_fw::expander_prt_set2(unsigned int prt_n, const expander_prf_settings_t& s, const expander_prf_settings_t& s2)
{
    grifo_fw::expander_blob_t* b=expander_default_blob__;
    if (!b)
        return;
    b->payload.ctrl=prt_n<<16;
    //b->payload.ctrl=1<<16;
    uint32_t cmd=s.mof|(s.reset<<8);

    for(int i=0; i<expander_raw_if_t::fifo_len; ++i)
    {
        b->payload.mof_fifo[i]=cmd;

        b->payload.wf1.amp_peak[i]=s.amp_peak;
        b->payload.wf1.frq_start[i]=s.frq_start;
        b->payload.wf1.incr[i]=s.frq_inc;
        b->payload.wf1.len[i]=s.frq_len;
        b->payload.wf1.address[i]=s.wf_address;

        b->payload.wf2.amp_peak[i]=s2.amp_peak;
        b->payload.wf2.frq_start[i]=s2.frq_start;
        b->payload.wf2.incr[i]=s2.frq_inc;
        b->payload.wf2.len[i]=s2.frq_len;
        b->payload.wf2.address[i]=s2.wf_address;
    }

    grifo_fw::expander_blob_t* b2=expander_hr_default_blob__;
    if (!b2)
        return;
    b2->payload.ctrl=prt_n<<16;

    //uint32_t cmd=s.mof|(s.reset<<8);

    for(int i=0; i<expander_raw_if_t::fifo_len; ++i)
    {
        b2->payload.mof_fifo[i]=cmd;

        b2->payload.wf1.amp_peak[i]=s.amp_peak;
        b2->payload.wf1.frq_start[i]=s.frq_start;
        b2->payload.wf1.incr[i]=s.frq_inc;
        b2->payload.wf1.len[i]=s.frq_len;
        b2->payload.wf1.address[i]=s.wf_address;

        b2->payload.wf2.amp_peak[i]=s2.amp_peak;
        b2->payload.wf2.frq_start[i]=s2.frq_start;
        b2->payload.wf2.incr[i]=s2.frq_inc;
        b2->payload.wf2.len[i]=s2.frq_len;
        b2->payload.wf2.address[i]=s2.wf_address;
    }
}

void grifo_fw::expander_test_cw_raw_setup(unsigned int frq, unsigned int len)
{
    grifo_fw::expander_blob_t* b=expander_default_blob__;
    if (!b)
        return;

    b->payload.ctrl=1<<16;

    b->payload.mof_fifo[0]=expander_raw_if_t::mof_cw;
    //b->payload.mof_fifo[0]|=expander_raw_if_t::batch_start;
    b->payload.wf1.amp_peak[0]=0x0FFFF;
    b->payload.wf1.frq_start[0]=frq;
    b->payload.wf1.incr[0]=0;
    b->payload.wf1.len[0]=len;

    exp2_off();
}

unsigned int grifo_fw::expander_frequency_convert_mhz(float mhz)
{
    //const float lsb=4294.967296f/expander_raw_if_t::FRQ_BASE_MHZ;
    //return (mhz*1000*1000)*lsb;
    float x=mhz/expander_raw_if_t::FRQ_BASE_MHZ;
    //x=x*0x100000; //over 20 bits
    x=x*0x10000;
    x=x*0x10000;
    if (x>=0)
    	return x+0.5;	//round
    else
    	return x-0.5;	//warning: should never be negative
    return x;
}

unsigned int grifo_fw::expander_frequency_convert_hz(float hz)
{
    //const float lsb=4294.967296f/expander_raw_if_t::FRQ_BASE_MHZ;
    //return (mhz*1000*1000)*lsb;
    float x=hz/(expander_raw_if_t::FRQ_BASE_MHZ*1E6);
    //x=x*0x100000; //over 20 bits
    x=x*0x10000;
    x=x*0x10000;
    if (x>=0)
    	return x+0.5;	//round
    else
    	return x-0.5;	//warning: should never be negative
}

unsigned int grifo_fw::expander_len_convert_usec(float us)
{
    const float lsb_us=expander_raw_if_t::FRQ_LEN_MHZ;
    unsigned int x=(us*lsb_us)+0.5;
    return x; //nsec
}

int grifo_fw::expander_delta_convert_hz_224(float hz)
{
    //const float incr_lsb=337.0f/139.5089f;
    const float incr_lsb=(1ull<<32)*1.0e-6f/expander_raw_if_t::FRQ_BASE_MHZ;
    //const float d_lsb=((4294.967296f/expander_raw_if_t::FRQ_BASE_MHZ)/float(expander_raw_if_t::FRQ_LEN_MHZ))*10000000;
    //return hz*d_lsb;

    float x=hz*incr_lsb; ///expander_raw_if_t::FRQ_BASE_MHZ;
    //x=x*1000000; //Hz
    if (x>=0)
    	return (x+0.5f);
    else
    	return (x-0.5f);
}

int grifo_fw::expander_delta_convert_mhz_224(float mhz)  //do not reuse expander_delta_convert_hz_224() to try to get higher precision
{
    //const float incr_lsb=337.0f/139.5089f;
    const float incr_lsb=(1ull<<32)/expander_raw_if_t::FRQ_BASE_MHZ;
    //const float d_lsb=((4294.967296f/expander_raw_if_t::FRQ_BASE_MHZ)/float(expander_raw_if_t::FRQ_LEN_MHZ))*10000000;
    //return hz*d_lsb;

    float x=mhz*incr_lsb; ///expander_raw_if_t::FRQ_BASE_MHZ;
    //x=x*1000000; //Hz
    if (x>=0)
    	return (x+0.5f);
    else
    	return (x-0.5f);
}

int grifo_fw::expander_delta_convert_mhz(float mhz, float us)
{
	const float incr_lsb_mhz_us=0.00009346008f; //(93.46008 Hz/us(;//=(expander_raw_if_t::FRQ_BASE_MHZ/2^32)*expander_raw_if_t::FRQ_LEN_MHZ

	float x=mhz/us;
	x/=incr_lsb_mhz_us;
	if (x>=0)
    	return (x+0.5f);
    else
    	return (x-0.5f);
}




