#include "grifo_synth_if.h"

#include "grifo_ctrlink_common.h"

#include <stdint.h>

namespace grifo_fw
{

enum fid_synth_t
{
    synth_ctrl=0x90,
    synth_freq_sel=0xA0,
    synth_freq_sel_ew=0xB0,
};

static ctrlink_blob_t* blob(ctrlink_blob_t* b)
{
    return b==0 ? ctrlink_exciter_bus : b;
}

template<typename T_> static T_* synth_msg_alloc_size(ctrlink_blob_t* ld, fid_synth_t fid, unsigned int size, T_* msg=0, ctrlink_pingpong_t pingpong=ctrlink_pingpong_auto, ctrlink_append_mode_t mode=ctrlink_append_write)
{
    ld=blob(ld); //ld=ctrlink_exciter_bus;
    unsigned int payload_size=size; //sizeof(T_);
    uint32_t dst=ctrlink_address(ctrlink_synth, static_cast<function_id_t>(fid), pingpong); //ctrlink_pingpong_auto);

    T_* m=reinterpret_cast<T_*>(ctrlink_append_raw_message(ld, dst, mode, msg, payload_size));
    return m;
}

template<typename T_> static T_* synth_msg_alloc(ctrlink_blob_t* ld, fid_synth_t fid, T_* msg, ctrlink_pingpong_t pp, ctrlink_append_mode_t mode=ctrlink_append_write)
{
    return synth_msg_alloc_size(ld, fid, sizeof(T_), msg, pp, mode);
}

int synth_append_status_request(ctrlink_blob_t* ld)
{
    ld=blob(ld); //ld=ctrlink_exciter_bus;

    return ctrlink_append_status_request(ld, ctrlink_synth);
}

struct synth_freq_sel_t
{
    uint16_t num_values;
    uint16_t cfg; //@#AC 19/12/22: was spare. I/F change: First bit used to select HR configuration - requires FW update!!!!
    uint32_t frq[synth_freq_max_values];
};

int synth_append_frequency_operative_message(ctrlink_blob_t* ld, unsigned int num_values, const unsigned int* frq /*[num_values]*/, ctrlink_pingpong_t pingpong)
{
	return synth_append_frequency_operative_message_ext(ld, num_values, 0, frq, pingpong);
}

int synth_append_frequency_operative_message_ext(ctrlink_blob_t* ld, unsigned int num_values, unsigned int cfg, const unsigned int* frq /*[num_values]*/, ctrlink_pingpong_t pingpong)
{
    if (num_values>synth_freq_max_values)
    {
        num_values=synth_freq_max_values;
    }
    if (num_values<1)
    	return 1;

    uint32_t* f=synth_allocate_frequency_operative_message_ext(ld, num_values, cfg, pingpong);

    for(unsigned int i=0; i<num_values; ++i)
    {
        f[i]=frq[i];
    }
    return 0;
}

uint32_t* synth_allocate_frequency_operative_message(ctrlink_blob_t* ld, unsigned int num_values, ctrlink_pingpong_t pingpong)
{
	return synth_allocate_frequency_operative_message_ext(ld, num_values, 0, pingpong);
}

uint32_t* synth_allocate_frequency_operative_message_ext(ctrlink_blob_t* ld, unsigned int num_values, unsigned int cfg, ctrlink_pingpong_t pingpong)
{
    if (num_values>synth_freq_max_values)
    {
        num_values=synth_freq_max_values;
    }
    unsigned int payload_size=4+4*num_values;

    synth_freq_sel_t* msg=synth_msg_alloc_size<synth_freq_sel_t>(ld, synth_freq_sel, payload_size, 0, pingpong);
    msg->num_values=num_values;
    msg->cfg=cfg;

    return &msg->frq[0];
}

int synth_append_frequency_asynch_message(ctrlink_blob_t* ld, unsigned int frq)
{
    uint32_t* f=synth_msg_alloc<uint32_t>(ld, synth_freq_sel, 0, ctrlink_pingpong_aynch);
    f[0]=frq;
    return 0;
}


int synth_append_frequency_sel_ew_operative_message(ctrlink_blob_t* ld, unsigned int num_values, const unsigned int* frq /*[num_values]*/, ctrlink_pingpong_t pingpong)
{
    uint32_t* f=synth_allocate_frequency_sel_ew_operative_message(ld, num_values, pingpong);
    for(unsigned int i=0; i<num_values; ++i)
    {
        f[i]=frq[i];
    }
    return 0;
}

uint32_t* synth_allocate_frequency_sel_ew_operative_message(ctrlink_blob_t* ld, unsigned int num_values, ctrlink_pingpong_t pingpong)
{
    if (num_values>synth_freq_max_values)
    {
        num_values=synth_freq_max_values;
    }
    unsigned int payload_size=4+num_values;

    synth_freq_sel_t* msg=synth_msg_alloc_size<synth_freq_sel_t>(ld, synth_freq_sel_ew, payload_size, 0, pingpong);
    msg->num_values=num_values;
    return &msg->frq[0];
}

int synth_append_frequency_sel_ew_asynch_message(ctrlink_blob_t* ld, unsigned int frq)
{
    uint32_t* f=synth_msg_alloc<uint32_t>(ld, synth_freq_sel_ew, 0, ctrlink_pingpong_aynch);
    f[0]=frq;
    return 0;
}

struct synch_ctrl_t
{
    unsigned int ew_rdr: 1;
    unsigned int cal: 1;
    unsigned int spare: 14;

    unsigned int spare1: 16; //warning: FW I/F change: ctrl link is 32bit, so the message must size be multiple of 32bits
};

int synth_append_control_opeative_message(ctrlink_blob_t* ld, unsigned int cal, unsigned int ew_rdr, ctrlink_pingpong_t pingpong)
{
    synch_ctrl_t* m=synth_msg_alloc<synch_ctrl_t>(ld, synth_ctrl, 0, pingpong);
    m->ew_rdr=ew_rdr;
    m->cal=cal;
    m->spare=0;
    m->spare1=0;
    return 0;
}


int synth_append_control_asynch_message(ctrlink_blob_t* ld, unsigned int cal, unsigned int ew_rdr)
{
    return synth_append_control_opeative_message(ld, cal, ew_rdr, ctrlink_pingpong_aynch);
#if 0
    synch_ctrl_t* m=synth_msg_alloc<synch_ctrl_t>(ld, synth_ctrl, 0, ctrlink_pingpong_aynch);
    m->ew_rdr=ew_rdr;
    m->cal=cal;
    m->spare=0;
    m->spare1=0;
    return 1;
#endif
}

}
