#include "hal_data.h"

#include "ada_if/ada_if.h"
#include "sound_effect/sound_effect.h"
#include "sci/sci.h"
#include "board/board.h"

FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER

/*******************************************************************************************************************//**
 * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
 * is called by main() when no RTOS is used.
 **********************************************************************************************************************/
void hal_entry(void)
{
    /* TODO: add your own code here */

    unsigned char xc;
    short volume_up_down[3] = {0, 0, 0};
    unsigned long local_sw_state;

    int offset = 0;

    int i;
    int ret;

    const int data_handling_size = 128; //128データ（1/48kHz=20.83us　20.83us x 128 = 2.67ms）毎にデータを処理する

    sci_init();

    sci_write_str("\n");
    sci_write_str("Copyright (C) 2021 HokutoDenshi. All Rights Reserved.\n");
    sci_write_str("ADA-IF sample program for (HSBRA6M2F144).\n\n");

    sci_write_str("COMMAND USAGE:\n");
    sci_write_str("  SW1: Operation mode change\n");
    sci_write_str("  0-9: Operation mode change\n");
#if (USE_ADC == 0)  //ADCを使用しない場合は、キーボードでボリュームを調整する
    sci_write_str("  q,a,z: Volume1 down (q:100, a:10, z:1)\n");
    sci_write_str("  w,s,x: Volume1 up   (w:100, s:10, x:1)\n");
    sci_write_str("  e,d,c: Volume2 down (e:100, d:10, c:1)\n");
    sci_write_str("  r,f,v: Volume2 up   (r:100, f:10, v:1)\n");
    sci_write_str("  t,g,b: Volume3 down (t:100, g:10, b:1)\n");
    sci_write_str("  y,h,n: Volume3 up   (y:100, h:10, n:1)\n");
#endif
    sci_write_str("  p: print current status\n");
    sci_write_str("\n>");

    g_input_index = 0;                              //入力バッファは0から処理を開始する
    g_output_index = ada_if_output_index(-256);     //出力バッファはインデックスを256遅らせる（g_inbuf_indexが512のとき、g_output_indexは256）

    ada_if_init( );
    ret = ada_if_start( );

    if(ret != 0)
    {
        //ボード接続エラー
        sci_write_str("\n\n");
        sci_write_str("ADA-IF board cannot initialize.\n\n");
        sci_write_str("Please check board connection.\n\n");
        sci_write_str("Program operation stopped.\n");

        while(1)
        {
            __NOP();
        }
    }

    local_sw_state = g_sw_state;

    while(1)
    {
        //データ処理
        if(ada_if_input_index_diff(offset, g_input_index) > data_handling_size) //未処理のデータが data_handling_size 以上であればデータを処理（DATA_BUFFER_SIZEはdata_handling_sizeの整数倍とする）
        {
            switch(local_sw_state)
            {
                case 0:
                    //スルー
                    for(i=0; i<data_handling_size; i++)
                    {
                        g_pcm1[offset + i] = g_pcm0[offset + i];        //入力データをそのまま出力にコピー
                    }
                    break;

                case 1:
                    //ディレイ
                    delay(offset, data_handling_size);
                    break;

                case 2:
                    //リバーブ
                    reverb(offset, data_handling_size);
                    break;

                case 3:
                    //ディストーション
                    distortion(offset, data_handling_size);
                    break;

                case 4:
                    //ワウ
                    wah(offset, data_handling_size);
                    break;

                case 5:
                    //トレモロ
                    tremolo(offset, data_handling_size);
                    break;

                case 6:
                    //ビブラート
                    vibrart(offset, data_handling_size);
                    break;

                case 7:
                    //コーラス
                    chorus(offset, data_handling_size);
                    break;

                case 8:
                    //フランジャ
                    flanger(offset, data_handling_size);
                    break;

                case 9:
                    //ラジオボイス
                    radio_voice(offset, data_handling_size);
                    break;

                default:
                    break;
            }

            offset += data_handling_size;
            if(offset >= DATA_BUFFER_SIZE) offset -= DATA_BUFFER_SIZE;
        }

        if(local_sw_state != g_sw_state)
        {
            local_sw_state = g_sw_state;

            //スイッチが押されたか端末からモード変更した
            switch(local_sw_state)
            {
                case 0:
                    //スルー
                    sci_write_str("\nOperation mode(0) -> Thru\n");
                    g_led_pattern = 0;      //LED消灯
                    break;

                case 1:
                    //ディレイ
                    sci_write_str("\nOperation mode(1) -> Delay\n");
                    g_led_pattern = 0x1;    //LED1回点滅
                    break;

                case 2:
                    //リバーブ
                    sci_write_str("\nOperation mode(2) -> Reverb\n");
                    g_led_pattern = 0x5;    //LED2回点滅
                    break;

                case 3:
                    //ディストーション
                    sci_write_str("\nOperation mode(3) -> Distortion\n");
                    g_led_pattern = 0x15;   //LED3回点滅
                    break;

                case 4:
                    //ワウ
                    sci_write_str("\nOperation mode(4) -> Wah\n");
                    g_led_pattern = 0x55;   //LED4回点滅
                    break;

                case 5:
                    //トレモロ
                    sci_write_str("\nOperation mode(5) -> Tremolo\n");
                    g_led_pattern = 0x155;  //LED5回点滅
                    break;

                case 6:
                    //ビブラート
                    sci_write_str("\nOperation mode(6) -> Vibrart\n");
                    g_led_pattern = 0x555;  //LED6回点滅
                    break;

                case 7:
                    //コーラス
                    sci_write_str("\nOperation mode(7) -> Chorus\n");
                    g_led_pattern = 0x1555; //LED7回点滅
                    break;

                case 8:
                    //フランジャ
                    sci_write_str("\nOperation mode(8) -> Flanger\n");
                    g_led_pattern = 0x5555; //LED8回点滅
                    break;

                case 9:
                    //ラジオボイス
                    sci_write_str("\nOperation mode(9) -> Radio_voice\n");
                    g_led_pattern = 0x15555;    //LED9回点滅
                    break;
            }
            sci_write_str("\n>");
        }

#if (USE_SCI == 1)
        xc = sci_read_char();

        if(xc != 0xff)
        {
            switch(xc)
            {
                case '0':
                    sci_write_char(xc);
                    g_sw_state = 0;
                    break;

                case '1':
                    sci_write_char(xc);
                    g_sw_state = 1;
                    break;

                case '2':
                    sci_write_char(xc);
                    g_sw_state = 2;
                    break;

                case '3':
                    sci_write_char(xc);
                    g_sw_state = 3;
                    break;

                case '4':
                    sci_write_char(xc);
                    g_sw_state = 4;
                    break;

                case '5':
                    sci_write_char(xc);
                    g_sw_state = 5;
                    break;

                case '6':
                    sci_write_char(xc);
                    g_sw_state = 6;
                    break;

                case '7':
                    sci_write_char(xc);
                    g_sw_state = 7;
                    break;

                case '8':
                    sci_write_char(xc);
                    g_sw_state = 8;
                    break;

                case '9':
                    sci_write_char(xc);
                    g_sw_state = 9;
                    break;

#if (USE_ADC == 0)
                case 'q':
                    sci_write_char(xc);
                    volume_up_down[0] = -100;
                    break;

                case 'w':
                    sci_write_char(xc);
                    volume_up_down[0] = 100;
                    break;

                case 'e':
                    sci_write_char(xc);
                    volume_up_down[1] = -100;
                    break;

                case 'r':
                    sci_write_char(xc);
                    volume_up_down[1] = 100;
                    break;

                case 't':
                    sci_write_char(xc);
                    volume_up_down[2] = -100;
                    break;

                case 'y':
                    sci_write_char(xc);
                    volume_up_down[2] = 100;
                    break;

                case 'a':
                    sci_write_char(xc);
                    volume_up_down[0] = -10;
                    break;

                case 's':
                    sci_write_char(xc);
                    volume_up_down[0] = 10;
                    break;

                case 'd':
                    sci_write_char(xc);
                    volume_up_down[1] = -10;
                    break;

                case 'f':
                    sci_write_char(xc);
                    volume_up_down[1] = 10;
                    break;

                case 'g':
                    sci_write_char(xc);
                    volume_up_down[2] = -10;
                    break;

                case 'h':
                    sci_write_char(xc);
                    volume_up_down[2] = 10;
                    break;

                case 'z':
                    sci_write_char(xc);
                    volume_up_down[0] = -1;
                    break;

                case 'x':
                    sci_write_char(xc);
                    volume_up_down[0] = 1;
                    break;

                case 'c':
                    sci_write_char(xc);
                    volume_up_down[1] = -1;
                    break;

                case 'v':
                    sci_write_char(xc);
                    volume_up_down[1] = 1;
                    break;

                case 'b':
                    sci_write_char(xc);
                    volume_up_down[2] = -1;
                    break;

                case 'n':
                    sci_write_char(xc);
                    volume_up_down[2] = 1;
                    break;
#endif
                case 'p':
                    sci_write_char(xc);
                    sci_write_str("\nvolume(0, 1, 2) = (");
                    sci_write_uint16(g_ad_val[0]);
                    sci_write_str(", ");
                    sci_write_uint16(g_ad_val[1]);
                    sci_write_str(", ");
                    sci_write_uint16(g_ad_val[2]);
                    sci_write_str(") sw = ");
                    sci_write_uint32(g_sw_state);
                    sci_write_str("\n\n>");
                    break;
            }
        }

#if (USE_ADC == 0)
        for(i=0; i<3; i++)
        {
            if(volume_up_down[i] != 0)
            {
                sci_write_str("\nvolume(");
                sci_write_uint8((unsigned char)i);
                sci_write_str(") ");
                if(volume_up_down[i] > 0) sci_write_str("+");
                sci_write_int16(volume_up_down[i]);

                volume_up_down[i] += g_ad_val[i];
                if(volume_up_down[i] < 0) g_ad_val[i] = 0;
                else if(volume_up_down[i] > 4095) g_ad_val[i] = 4095;
                else g_ad_val[i] = volume_up_down[i];
                volume_up_down[i] = 0;

                sci_write_str(" -> ");
                sci_write_uint16(g_ad_val[i]);
                sci_write_str("\n");
                sci_write_str("\n\n>");
            }
        }
#endif

#endif

    }

#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

/*******************************************************************************************************************//**
 * This function is called at various points during the startup process.  This implementation uses the event that is
 * called right before main() to set up the pins.
 *
 * @param[in]  event    Where at in the start up process the code is currently at
 **********************************************************************************************************************/
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
    if (BSP_WARM_START_RESET == event)
    {
#if BSP_FEATURE_FLASH_LP_VERSION != 0

        /* Enable reading from data flash. */
        R_FACI_LP->DFLCTL = 1U;

        /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
         * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
    }

    if (BSP_WARM_START_POST_C == event)
    {
        /* C runtime environment and system clocks are setup. */

        /* Configure pins. */
        R_IOPORT_Open (&g_ioport_ctrl, &g_bsp_pin_cfg);
    }
}

#if BSP_TZ_SECURE_BUILD

BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();

/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{

}
#endif
