#include "spi.h"
#include "ctrl_app_types.h"
#include "mcu_cs.h"
#include "led.h"

static MCU_cs_t mcu_cs[MCU_CS_MAX];

// ************************
//      INITIALIZATION
// ************************

static void _dds_init(dds_gen_t *dds_gen)
{
    dds_gen->link.next = &dds_gen->super;
    dds_gen->link.prev = &dds_gen->super;

    switch (dds_gen->dds_ch)
    {
    case DDS_CH1:
        mcu_cs_init(&mcu_cs[MCU_CS1], DDS1_CS_GPIO_Port, DDS1_CS_Pin, GPIO_PIN_SET);
        ad9833_init(&dds_gen->handle.hdds, &hspi2, &mcu_cs[MCU_CS1].super);

        mcu_cs_init(&mcu_cs[MCU_CS2], AMP1_CS_GPIO_Port, AMP1_CS_Pin, GPIO_PIN_SET);
        mcp41x_init(&dds_gen->handle.hampl, &hspi2, &mcu_cs[MCU_CS2].super, MCP41X_10K);

        led_init(&dds_gen->handle.hled, LED_CH1_GPIO_Port, LED_CH1_Pin);
        break;
    case DDS_CH2:
        mcu_cs_init(&mcu_cs[MCU_CS3], DDS2_CS_GPIO_Port, DDS2_CS_Pin, GPIO_PIN_SET);
        ad9833_init(&dds_gen->handle.hdds, &hspi2, &mcu_cs[MCU_CS3].super);

        mcu_cs_init(&mcu_cs[MCU_CS4], AMP2_CS_GPIO_Port, AMP2_CS_Pin, GPIO_PIN_SET);
        mcp41x_init(&dds_gen->handle.hampl, &hspi2, &mcu_cs[MCU_CS4].super, MCP41X_10K);

        led_init(&dds_gen->handle.hled, LED_CH2_GPIO_Port, LED_CH2_Pin);
        break;
    case DDS_CH3:

        break;

    default:
        break;
    }
}

static void _pwm_init(pwm_gen_t *pwm_gen)
{
    switch (pwm_gen->pwm_ch)
    {
    case PWM_CH1:

        break;
    case PWM_CH2:

        break;
    case PWM_CH3:

        break;

    default:
        break;
    }
}

void GEN_init(signal_gen_t **signal_gen)
{
    for (GEN_channel_t channel = CHANNEL1; channel < CHANNEL_MAX; channel++)
    {
        switch (signal_gen[channel]->type)
        {
        case GEN_FG_TYPE:
            _dds_init((dds_gen_t *)signal_gen[channel]);
        case GEN_PWM_TYPE:
            _pwm_init((pwm_gen_t *)signal_gen[channel]);
        default:
            break;
        }
    }

    // ad9833_init(&dds_gen[FG_CHAN3].hdds, &hspi2, DDS3_CS_PORT, DDS3_CS_PIN);

    // ltc2631_init(&dds_gen[FG_CHAN1].hoffs, &hi2c1, 0x00, LTC2631_8BIT, LTC_REF_2V5);
    // ltc2631_init(&dds_gen[FG_CHAN2].hoffs, &hi2c1, 0x01, LTC2631_8BIT, LTC_REF_2V5);
    // ltc2631_init(&dds_gen[FG_CHAN3].hoffs, &hi2c1, 0x02, LTC2631_8BIT, LTC_REF_2V5);

    // mcp41x_init(&dds_gen[FG_CHAN3].hampl, &hspi2, AMP3_CS_PORT, AMP3_CS_PIN, MCP41X_10K);
}

// ************************
//        AMPLITIUDE
// ************************

static void _setAmpliude(mcp41x_handle_t *hampl, uint16_t ampl_x100)
{
    uint8_t value = (ampl_x100 * UINT8_MAX) / MAX_VOLT_POS;
    ULOG_DEBUG("(%d:_setAmplitude) ampl_x100: %d, value: %d", __LINE__, ampl_x100, value);

    mcp41x_setValue(hampl, value);
}

void setAmplitude(signal_gen_t *sig_gen)
{
    static signal_gen_t *curr_sig_gen = NULL;

    if (curr_sig_gen == NULL)
    {
        curr_sig_gen = sig_gen;
    }

    switch (sig_gen->type)
    {
    case GEN_FG_TYPE:
    {
        dds_gen_t *dds_gen = (dds_gen_t *)sig_gen;
        signal_gen_t *next_sig_gen = dds_gen->link.next;

        _setAmpliude(&dds_gen->handle.hampl, dds_gen->settings.amplitude);

        if (next_sig_gen != curr_sig_gen)
        {
            setAmplitude(next_sig_gen);
        }
        else
        {
            curr_sig_gen = NULL;
        }

        break;
    }
    case GEN_PWM_TYPE:
    {
        pwm_gen_t *pwm_gen = (pwm_gen_t *)sig_gen;
        signal_gen_t *next_sig_gen = pwm_gen->link.next;

        _setAmpliude(&pwm_gen->handle.hampl, pwm_gen->settings.amplitude);

        if (next_sig_gen != curr_sig_gen)
        {
            setAmplitude(next_sig_gen);
        }
        else
        {
            curr_sig_gen = NULL;
        }

        break;
    }
    default:
        ULOG_ERROR("%s:%d: Unknown generator type: %d", __FILE__, __LINE__, sig_gen->type);
        break;
    }
}

// ************************
//          OFFSET
// ************************

static void _setOffset(ltc2631_handle_t *hoffs, int16_t offs_x100)
{
    uint32_t value = (offs_x100 + MAX_VOLT_POS) * LTC_REF_2V5;
    ULOG_DEBUG("(%d:_setOffset) offs_x100: %d, value: %d", __LINE__, offs_x100, value);
    ltc2631_setOutputVoltage_u(hoffs, value);
}

void setOfsset(signal_gen_t *sig_gen)
{
    static signal_gen_t *curr_sig_gen = NULL;

    if (curr_sig_gen == NULL)
    {
        curr_sig_gen = sig_gen;
    }

    switch (sig_gen->type)
    {
    case GEN_FG_TYPE:
    {
        dds_gen_t *dds_gen = (dds_gen_t *)sig_gen;
        signal_gen_t *next_sig_gen = dds_gen->link.next;

        _setOffset(&dds_gen->handle.hoffs, dds_gen->settings.offset);

        if (next_sig_gen != curr_sig_gen)
        {
            setOfsset(next_sig_gen);
        }
        else
        {
            curr_sig_gen = NULL;
        }
        break;
    }
    case GEN_PWM_TYPE:
    {
        pwm_gen_t *pwm_gen = (pwm_gen_t *)sig_gen;
        signal_gen_t *next_sig_gen = pwm_gen->link.next;

        _setOffset(&pwm_gen->handle.hoffs, pwm_gen->settings.offset);

        if (next_sig_gen != curr_sig_gen)
        {
            setOfsset(next_sig_gen);
        }
        else
        {
            curr_sig_gen = NULL;
        }
        break;
    }

    default:
        ULOG_ERROR("%s:%d: Unknown generator type: %d", __FILE__, __LINE__, sig_gen->type);
        break;
    }
}

// ************************
//         FREQUENCY
// ************************

static void _setFreqDdsGen(ad9833_handle_t *hdds, uint32_t freq)
{
    ULOG_DEBUG("(%d:_setFreqDdsGen) freq: %d", __LINE__, freq);
    ad9833_setFrequency(hdds, CHAN_0, freq);
}

static void _setFreqPwmGen(timer_handle_t *hpwm, uint32_t freq)
{
}

void setFrequency(signal_gen_t *sig_gen)
{
    static signal_gen_t *curr_sig_gen = NULL;

    if (curr_sig_gen == NULL)
    {
        curr_sig_gen = sig_gen;
    }

    switch (sig_gen->type)
    {
    case GEN_FG_TYPE:
    {
        dds_gen_t *dds_gen = (dds_gen_t *)sig_gen;
        signal_gen_t *next_sig_gen = dds_gen->link.next;

        ad9833_spi_activate(&dds_gen->handle.hdds);

        if (next_sig_gen != curr_sig_gen)
        {
            setFrequency(next_sig_gen);
        }
        else
        {
            _setFreqDdsGen(&dds_gen->handle.hdds, dds_gen->settings.frequency);
            curr_sig_gen = NULL;
        }

        ad9833_spi_deactivate(&dds_gen->handle.hdds);
        break;
    }
    case GEN_PWM_TYPE:
    {
        pwm_gen_t *pwm_gen = (pwm_gen_t *)sig_gen;
        signal_gen_t *next_sig_gen = pwm_gen->link.next;

        _setFreqPwmGen(&pwm_gen->handle.hpwm, pwm_gen->settings.frequency);

        if (next_sig_gen != curr_sig_gen)
        {
            setFrequency(next_sig_gen);
        }
        else
        {
            curr_sig_gen = NULL;
        }
        break;
    }

    default:
        ULOG_ERROR("%s:%d: Unknown generator type: %d", __FILE__, __LINE__, sig_gen->type);
        break;
    }
}

// ************************
//           PHASE
// ************************

static void _setPhaseDdsGen(ad9833_handle_t *hdds, uint32_t phas)
{
    ULOG_DEBUG("(%d:_setPhaseDdsGen) phase: %d", __LINE__, phas);
    ad9833_setPhase(hdds, CHAN_0, phas);
}

static void _setPhasePwmGen(timer_handle_t *hpwm, uint16_t phas)
{
}

void setPhase(signal_gen_t *sig_gen)
{
    static signal_gen_t *curr_sig_gen = NULL;

    if (curr_sig_gen == NULL)
    {
        curr_sig_gen = sig_gen;
    }

    switch (sig_gen->type)
    {
    case GEN_FG_TYPE:
    {
        dds_gen_t *dds_gen = (dds_gen_t *)sig_gen;
        signal_gen_t *next_sig_gen = dds_gen->link.next;

        ad9833_spi_activate(&dds_gen->handle.hdds);

        if (next_sig_gen != curr_sig_gen)
        {
            setPhase(next_sig_gen);
        }
        else
        {
            _setPhaseDdsGen(&dds_gen->handle.hdds, dds_gen->settings.phase);
            curr_sig_gen = NULL;
        }

        ad9833_spi_deactivate(&dds_gen->handle.hdds);
        break;
    }
    case GEN_PWM_TYPE:
    {
        pwm_gen_t *pwm_gen = (pwm_gen_t *)sig_gen;
        signal_gen_t *next_sig_gen = pwm_gen->link.next;

        _setPhasePwmGen(&pwm_gen->handle.hpwm, pwm_gen->settings.phase);

        if (next_sig_gen != curr_sig_gen)
        {
            setPhase(next_sig_gen);
        }
        else
        {
            curr_sig_gen = NULL;
        }
        break;
    }

    default:
        ULOG_ERROR("%s:%d: Unknown generator type: %d", __FILE__, __LINE__, sig_gen->type);
        break;
    }
}

// ************************
//           DUTY
// ************************

static void _setDutyPwmGen(timer_handle_t *hpwm, uint8_t duty)
{
}

void setDuty(signal_gen_t *sig_gen)
{
    switch (sig_gen->type)
    {
    case GEN_PWM_TYPE:
    {
        pwm_gen_t *pwm_gen = (pwm_gen_t *)sig_gen;
        _setDutyPwmGen(&pwm_gen->handle.hpwm, pwm_gen->settings.duty);
        break;
    }
    default:
        ULOG_ERROR("%s:%d: Unknown generator type: %d", __FILE__, __LINE__, sig_gen->type);
        break;
    }
}

// ************************
//           WAVE
// ************************

static void _setWaveDdsGen(ad9833_handle_t *hdds, GEN_wave_t wave)
{
    ULOG_DEBUG("(%d:_setWaveDdsGen) wave: %d", __LINE__, wave);
    switch (wave)
    {
    case GEN_SIN:
        ad9833_setMode(hdds, MODE_SINE);
        break;
    case GEN_TRI:
        ad9833_setMode(hdds, MODE_TRIANGLE);
        break;
    case GEN_SQR:
        ad9833_setMode(hdds, MODE_SQUARE1);
        break;

    default:
        ULOG_ERROR("%s:%d: Unknown wave type: %d", __FILE__, __LINE__, wave);
        break;
    }
}

void setWave(signal_gen_t *sig_gen)
{
    switch (sig_gen->type)
    {
    case GEN_FG_TYPE:
    {
        dds_gen_t *dds_gen = (dds_gen_t *)sig_gen;
        _setWaveDdsGen(&dds_gen->handle.hdds, dds_gen->settings.wave);
        break;
    }

    default:
        ULOG_ERROR("%s:%d: Unknown generator type: %d", __FILE__, __LINE__, sig_gen->type);
        break;
    }
}

// ************************
//          ENABLE
// ************************

static void _setEnabledDdsGen(dds_handle_t *hfg, dds_settings_t *settings)
{
    ULOG_DEBUG("(%d:_setEnabledDdsGen) enabled: %d", __LINE__, settings->enabled);
    switch (settings->enabled)
    {
    case FALSE:
        ad9833_setMode(&hfg->hdds, MODE_OFF);
        led_off(&hfg->hled);
        break;
    case TRUE:
        _setWaveDdsGen(&hfg->hdds, settings->wave);
        led_on(&hfg->hled);
        break;

    default:
        ULOG_ERROR("%s:%d: Value out of range: %d", __FILE__, __LINE__, settings->enabled);
        break;
    }
}

static void _setEnabledPwmGen(timer_handle_t *hpwm, bool_t en)
{
}

void setEnabled(signal_gen_t *sig_gen)
{
    switch (sig_gen->type)
    {
    case GEN_FG_TYPE:
    {
        dds_gen_t *dds_gen = (dds_gen_t *)sig_gen;
        _setEnabledDdsGen(&dds_gen->handle, &dds_gen->settings);
        break;
    }
    case GEN_PWM_TYPE:
    {
        pwm_gen_t *pwm_gen = (pwm_gen_t *)sig_gen;
        _setEnabledPwmGen(&pwm_gen->handle.hpwm, pwm_gen->settings.enabled);
        break;
    }

    default:
        ULOG_ERROR("%s:%d: Unknown generator type: %d", __FILE__, __LINE__, sig_gen->type);
        break;
    }
}

// ************************
//           LINK
// ************************

void setLink(signal_gen_t *source_gen, signal_gen_t *dest_gen)
{
}
