#include "test_crc.h"

#include "../../software/signal_processing/system/task.h"
#include "../../software/signal_processing/system/task_sine.h"
#include "../../software/signal_processing/system/binding.h"
#include "../../software/signal_processing/system/data_channel.h"
#include "../../software/signal_processing/system/float_word.h"
#include "data_channel/test_data_channel.h"
#include "device_test.h"

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

void write_input_data( uint32_t base, uint32_t binding, void * data ) {
    if ( data == NULL ) return;

    DataChannelBinding data_channel_binding = { .sink = BINDING_SW, .source = binding };
    data_channel_clear( base );
    data_channel_bind( base, & data_channel_binding );
    data_channel_write_all( base, data, DATA_CHANNEL_DEPTH );
}

int test_task( uint32_t binding, void * task, void * input_a, void * input_b, void * expected, float epsilon ) {
    task_base_config * base = ( task_base_config * ) task;
    printf( "    %s %s %s ...", __func__, base->name, binding_to_string( binding ) );

    uint32_t output_channel_base = base->sink;

    write_input_data( base->sources[ 0 ], binding, input_a );
    write_input_data( base->sources[ 1 ], binding, input_b );

    task_bind( task, binding );
    DataChannelBinding channel_binding = { .sink = binding, .source = BINDING_SW };

    data_channel_clear( output_channel_base );
    data_channel_bind( output_channel_base, & channel_binding );

    if ( ! assert_data_channel_empty( output_channel_base ) ) {
        return 1;
    }

    task_run( task );

    uint32_t cycle_count = task_get_cycle_count( task );

    if ( ! assert_data_channel_level_eq( output_channel_base, 1 ) ) {
        return 1;
    }

    uint32_t output = 0;

    data_channel_read( output_channel_base, & output );

    uint32_t * expected_crc = ( uint32_t * ) expected;
    if ( ! assert_eq( expected_crc[ 0 ], output ) ) {
        return 1;
    }

    printf( TEST_OK "\n" );
    printf( "    cycles: %" PRIu32 "\n", cycle_count );

    return 0;
}

