#include "Hardware.h"

#include "../../software/signal_processing_bsp/system.h"

#include "../../software/signal_processing/system/task_sine.h"
#include "../../software/signal_processing/system/task_rand.h"
#include "../../software/signal_processing/system/task_add.h"
#include "../../software/signal_processing/system/task_fft.h"
#include "../../software/signal_processing/system/task_crc.h"

Hardware * Hardware::instance = nullptr;

Hardware * Hardware::getInstance() {
    if ( Hardware::instance == nullptr ) {
        Hardware::instance = new Hardware();
    }

    return Hardware::instance;
}

Hardware::~Hardware() {
    for ( uint32_t i = 0; i < 7; ++i ) {
        delete dataChannel[ i ];
    }
}

void Hardware::write( uint32_t base, uint32_t offset, uint32_t value ) {
    switch ( base ) {
    case DATA_CHANNEL_0_BASE: dataChannel[ 0 ]->write( offset, value ); break;
    case DATA_CHANNEL_1_BASE: dataChannel[ 1 ]->write( offset, value ); break;
    case DATA_CHANNEL_2_BASE: dataChannel[ 2 ]->write( offset, value ); break;
    case DATA_CHANNEL_3_BASE: dataChannel[ 3 ]->write( offset, value ); break;
    case DATA_CHANNEL_4_BASE: dataChannel[ 4 ]->write( offset, value ); break;
    case DATA_CHANNEL_5_BASE: dataChannel[ 5 ]->write( offset, value ); break;
    case DATA_CHANNEL_6_BASE: dataChannel[ 6 ]->write( offset, value ); break;
    case HARDWARE_TASK_0_BASE: task[ 0 ]->write( offset, value ); break;
    case HARDWARE_TASK_1_BASE: task[ 1 ]->write( offset, value ); break;
    case HARDWARE_TASK_2_BASE: task[ 2 ]->write( offset, value ); break;
    case HARDWARE_TASK_3_BASE: task[ 3 ]->write( offset, value ); break;
    case HARDWARE_TASK_4_BASE: task[ 4 ]->write( offset, value ); break;
    case HARDWARE_TASK_5_BASE: task[ 5 ]->write( offset, value ); break;
    case HARDWARE_TASK_6_BASE: task[ 6 ]->write( offset, value ); break;
    };
}

uint32_t Hardware::read( uint32_t base, uint32_t offset ) {
    switch ( base ) {
    case DATA_CHANNEL_0_BASE: return dataChannel[ 0 ]->read( offset );
    case DATA_CHANNEL_1_BASE: return dataChannel[ 1 ]->read( offset );
    case DATA_CHANNEL_2_BASE: return dataChannel[ 2 ]->read( offset );
    case DATA_CHANNEL_3_BASE: return dataChannel[ 3 ]->read( offset );
    case DATA_CHANNEL_4_BASE: return dataChannel[ 4 ]->read( offset );
    case DATA_CHANNEL_5_BASE: return dataChannel[ 5 ]->read( offset );
    case DATA_CHANNEL_6_BASE: return dataChannel[ 6 ]->read( offset );
    case HARDWARE_TASK_0_BASE: return task[ 0 ]->read( offset );
    case HARDWARE_TASK_1_BASE: return task[ 1 ]->read( offset );
    case HARDWARE_TASK_2_BASE: return task[ 2 ]->read( offset );
    case HARDWARE_TASK_3_BASE: return task[ 3 ]->read( offset );
    case HARDWARE_TASK_4_BASE: return task[ 4 ]->read( offset );
    case HARDWARE_TASK_5_BASE: return task[ 5 ]->read( offset );
    case HARDWARE_TASK_6_BASE: return task[ 6 ]->read( offset );
    default: return -1;
    };
}

Hardware::Hardware() {
    task.push_back( new HardwareTaskSimulation( task_sine_run ) );
    task.push_back( new HardwareTaskSimulation( task_sine_run ) );
    task.push_back( new HardwareTaskSimulation( task_rand_run ) );
    task.push_back( new HardwareTaskSimulation( task_add_run ) );
    task.push_back( new HardwareTaskSimulation( task_add_run ) );
    task.push_back( new HardwareTaskSimulation( task_fft_run ) );
    task.push_back( new HardwareTaskSimulation( task_crc_run ) );

    for ( uint32_t i = 0; i < 7; ++i ) {
        dataChannel.push_back( new DataChannelSimulation() );
    }
}

