#include "task_sine.h"
#include "hardware_task.h"
#include "sine_config.h"
#include "data_channel.h"
#include "float_word.h"

#include <math.h>
#include <stdio.h>
#include <limits.h>
#include <system.h>

#define REG_STEP_SIZE_OFFSET 0
#define REG_PHASE_OFFSET 1
#define REG_AMPLITUDE_OFFSET 2

sine_config SINE_CONFIG = {
    .base = {
        .name = "sine",
        .binding = BINDING_SW,
        .software = task_sine_run,
        .configure = task_sine_configure,
        .hardware = HARDWARE_TASK_0_BASE,
        .sources = { 0, 0 },
        .sink = DATA_CHANNEL_0_BASE,
        .cycle_count = 0 },
    .samples_per_periode = 32,
    .phase = 0.0,
    .amplitude = 4.0 };

sine_config COSINE_CONFIG = {
    .base = { .name = "cosine",
        .binding = BINDING_SW,
        .software = task_sine_run,
        .configure = task_sine_configure,
        .hardware = HARDWARE_TASK_1_BASE,
        .sources = { 0, 0 },
        .sink = DATA_CHANNEL_1_BASE,
        .cycle_count = 0 },
    .samples_per_periode = 200,
    .phase = M_PI / 2.0,
    .amplitude = 2.0 };

uint32_t to_hardware_step_size( uint32_t steps ) {
    return UINT_MAX / steps + 1;
}

uint32_t to_hardware_phase( float phase ) {
    return ( phase / ( 2.0 * M_PI ) ) * UINT_MAX;
}

int task_sine_configure( void * data ) {
    sine_config * task = ( sine_config * ) data;
    uint32_t base = task->base.hardware;
    float_word amplitude;
    amplitude.value = task->amplitude;

    hardware_task_set_config( base, REG_STEP_SIZE_OFFSET,
        to_hardware_step_size( task->samples_per_periode ) );

    hardware_task_set_config( base, REG_PHASE_OFFSET,
        to_hardware_phase( task->phase ) );

    hardware_task_set_config( base, REG_AMPLITUDE_OFFSET, amplitude.word );
    return 0;
}

