
/**
 ******************************************************************************
 *
 * @file        MG32x02z_DACOutput_API.c
 * @brief       Output audio data by DAC module.
 *
 * @par         Project
 *              MG32x02z
 * @version     V1.03
 * @date        2023/03/29
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 *
 ******************************************************************************* 
 * @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */


/* audio file is Untitled_222.c' */


/* Includes ------------------------------------------------------------------*/
#include "MG32x02z_DACOutput_API.h"
#include "MG32x02z_Flash_25_API.h"
#include "MG32x02z_USBD_Core.h"
#include "MG32x02z_USBD_Audio_Core.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define AudioFlashAddr1     0x00500000          // from 0x00500000, Size ~3M
#define AudioFlashAddr2     0x0059D000          // from 0x0059C400, Size ~3M
#define AudioFlashAddr3     0x0063A000          // from 0x0059D000, Size ~3M

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
DAC_HandleTypeDef   mDAC;
//DMA_HandleTypeDef   mDACDMA;
TM_HandleTypeDef    mTM10;

API_DAC_Parameters  API_DAC_Output;

// variable for DAC output from Flash
static uint32_t DACOutput_Adr; 
static __ALIGNED(4) uint16_t AudioBuf0[256];     // SRAM audio buffer0
static __ALIGNED(4) uint16_t AudioBuf1[256];     // SRAM audio buffer1

/* Private function prototypes -----------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/

/**
 *******************************************************************************
 * @brief       Initial DAC Audio output (DAC + DMA + Timer). 
 * @return      None
 *******************************************************************************
 */
void API_DACOutput_Init(void)
{
    TM_ClockConfigTypeDef   CKConfig;
    TM_MasterConfigTypeDef  TM_TRGOConfig;

    // ------------------------------------------------------------------------
    // Enable GPIOB clock in CSC module.
    // ------------------------------------------------------------------------

    // ------------------------------------------------------------------------
    // Config PB2 for DAC output.
    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------
    // 1.Initial DAC. 
    // ------------------------------------------------------------------------
    mDAC.Instance                   = DAC;
    mDAC.Init.TriggerConverionSrc   = DAC_TRIGGERSOURCE_WRITE_DAT0; 
    mDAC.Init.TriggerConverionEdge  = DAC_RISING_EDGE_UPDATE;       // DAC accept rising edge of TM10_TRGO to update DAC
    mDAC.Init.DataAlign             = DAC_ALIGN_12B_R;              // DAC data is 12bit /w right justif
    mDAC.Init.InterruptMode         = DAC_IT_READY;                 // DAC will trigger INT when READY flag happened.
    mDAC.State                      = MID_DAC_STATE_RESET;          // Reset state    

    MID_DAC_Init(&mDAC);

    // ------------------------------------------------------------------------
    // 2.DAC with DMA initial.
    // ------------------------------------------------------------------------
    MID_DAC_SetValue(&mDAC, 0);
    MID_DAC_Start(&mDAC);

    // ------------------------------------------------------------------------
    // 3.Initial TM10 timer : counter range is 8K in 48MHz.
    // ------------------------------------------------------------------------
    mTM10.Instance                  = TM10;
    mTM10.Init.TM_CounterMode       = TM_CASCADE_UP;
    mTM10.Init.TM_Period            = 5999;
    mTM10.Init.TM_Prescaler         = 0;
    mTM10.State                     = MID_TM_STATE_RESET;       // Reset state

    MID_TM_Base_Init(&mTM10);

    // ------------------------------------------------------------------------
    // 4.Initial TM10 clock mode.
    // ------------------------------------------------------------------------
    CKConfig.TM_ClockSource         = TM_INTERNAL_CLOCK;
    CKConfig.TM_ExternalClockSource = 0;
    CKConfig.TM_INTClockDivision    = TM_INTERNALCLOCK_DIVDER_DIV1;
    CKConfig.TM_InternalClockSource = TM_INTERNALCLOCK_PROC;
    MID_TM_ConfigClockSource(&mTM10, &CKConfig);

    // ------------------------------------------------------------------------
    // 5.Initial TM10 TRGO configuration.
    // ------------------------------------------------------------------------
    TM_TRGOConfig.MasterOutputTrigger   = TM_TRGO_UPDATE;
    TM_TRGOConfig.MasterOutputPolarity  = TM_MASTEROUTPUT_BYPASS;
    TM_TRGOConfig.MasterUpdateEvent     = TM_UPDATE_OVERFLOW;
    MID_TM_MasterConfigSynchronization(&mTM10, &TM_TRGOConfig);

    // ------------------------------------------------------------------------
    // 6.Config API_DAC_Output base parameters.
    // ------------------------------------------------------------------------
    API_DAC_Output.SongsSelect      = 1;
    API_DAC_Output.AudioVolume      = 4;
    API_DAC_Output.State            = ResetAudioState;
    API_DAC_Output.AudioDataFreq    = MID_DAC_8K;
    API_DAC_Output.AudioSource      = DAC_DATA_FLASH;
    API_DAC_Output.AudioBufIDX      = 0;
}

/**
 *******************************************************************************
 * @brief       Start TM10 period trigger
 * @param[in]   None
 * @return      None
 *******************************************************************************
 */
void API_DAC_StartOutput(void)
{
    uint32_t AudioDat;

    // update AudioBuf0 depend SongsSelect
    if (API_DAC_Output.SongsSelect == 1) DACOutput_Adr = AudioFlashAddr1;
    if (API_DAC_Output.SongsSelect == 2) DACOutput_Adr = AudioFlashAddr2;
    if (API_DAC_Output.SongsSelect == 3) DACOutput_Adr = AudioFlashAddr3;

    // Read audio data from Flash IC.
    API_Flash_MultiBytesRead (DACOutput_Adr, (uint8_t*) &AudioBuf0, 512);
    DACOutput_Adr += 512;

    // reset AudioBufIDX
    API_DAC_Output.AudioBufIDX = 0;

    // startuo TM10 to period output audio (DAC+TM26OC1H)
    MID_TM_Base_Start_IT(&mTM10);

    // initial Audio voice data
    AudioDat = AudioBuf0[0];
    AudioDat -= 0x8000;
    AudioDat = AudioDat >> API_DAC_Output.AudioVolume;         // control audio volume

    // Autio output R (DAC output)
    MID_DAC_SetValue(&mDAC, AudioDat);

    API_DAC_Output.AudioBufIDX      += 2;
    API_DAC_Output.AudioDataFreq    = MID_DAC_8K;
    API_DAC_Output.State            = 0;
    API_DAC_Output.AudioSource      = DAC_DATA_FLASH;
}

/**
 *******************************************************************************
 * @brief       Pause DAC output
 * @param[in]   None
 * @return      None
 *******************************************************************************
 */
void API_DAC_PauseOutput(void)
{
    MID_TM_Base_Stop_IT(&mTM10);

    API_DAC_Output.State        = ResetAudioState;
    API_DAC_Output.AudioSource  = DAC_DATA_FLASH;

    USB_Audio.AudioOUT_Busyflag = 0;
}


/**
 *******************************************************************************
 * @brief       Pause DAC output
 * @param[in]   None
 * @return      None
 *******************************************************************************
 */
void API_DAC_StartUSBOutput(uint8_t DataFreq)
{
    uint32_t AudioDat;
    uint16_t *ptr16;

    // return condition
    if ((API_DAC_Output.AudioSource == DAC_DATA_FLASH) && (API_DAC_Output.State != ResetAudioState))
        return;

    // Data frequency
    if (DataFreq == 32)
    {
        API_DAC_Output.AudioDataFreq = MID_DAC_8K;
    }
    else
    {
        API_DAC_Output.AudioDataFreq = MID_DAC_16K;
    }
    //
    if (API_DAC_Output.AudioSource == DAC_DATA_FLASH)
    {
        // initial DAC parameters
        API_DAC_Output.AudioSource  = DAC_DATA_USB;
        API_DAC_Output.State        = ResetAudioState - 15;
        API_DAC_Output.AudioBufIDX  = 0;

        // initial Audio voice data
        ptr16       = (uint16_t *) &TST_USB_AudioBuf;
        AudioDat    = *ptr16;
        AudioDat    -= 0x8000;
        AudioDat    = AudioDat >> API_DAC_Output.AudioVolume;         // control audio volume

        // Autio output R (DAC output)
        MID_DAC_SetValue(&mDAC, AudioDat);
        if (API_DAC_Output.AudioDataFreq == MID_DAC_16K)
            API_DAC_Output.AudioBufIDX += 4;
        else
            API_DAC_Output.AudioBufIDX += 2;

        // trigger TM10 to period output audio (DAC)
        MID_TM_Base_Start_IT(&mTM10);  

        __DRV_TM_SET_COUNTER(&mTM10, 5999/2);

        USB_Audio.AudioOUT_Busyflag = 0;
    }
    else
    {
        API_DAC_Output.AudioBufIDX  = 0;
        API_DAC_Output.State        = ResetAudioState - 16;

        USB_Audio.AudioOUT_Busyflag = 0;
    }
}


/**
 *******************************************************************************
 * @brief       Period elapsed callback in non blocking mode.
 * @param[in]   mTM : pointer to a TM_HandleTypeDef
 * @return      None
 *******************************************************************************
 */
void MID_TM_PeriodElapsedCallback(TM_HandleTypeDef* mTM)
{
    uint16_t AudioDat;
    uint16_t *ptr16;

    // ------------------------------------------------------------------------
    // TM10 for DAC output
    // ------------------------------------------------------------------------
    if(mTM == &mTM10)
    {
        // --------------------------------------------------------------------
        // Audio data from Flash IC
        // --------------------------------------------------------------------
        if (API_DAC_Output.AudioSource == DAC_DATA_FLASH)
        {
            // get audio data from AudioBuf0/AudioBuf1
            if ((API_DAC_Output.AudioBufIDX & 0x0100) == 0)
                ptr16 = (uint16_t *) &AudioBuf0;
            else
                ptr16 = (uint16_t *) &AudioBuf1;

            ptr16 += (API_DAC_Output.AudioBufIDX & 0x00FF);
            AudioDat = *(ptr16);

            // WAV convert to DAC
            AudioDat -= 0x8000;
            AudioDat = AudioDat >> (4 + API_DAC_Output.AudioVolume);

            // Autio output R (DAC output)
            MID_DAC_SetValue(&mDAC, AudioDat);

            API_DAC_Output.AudioBufIDX += 2;
            API_DAC_Output.AudioBufIDX &= 0x01FF;

            // if remain half bytes --> to update another buffer
            if (API_DAC_Output.AudioBufIDX == 0x0080) 
            {
                API_Flash_MultiBytesRead (DACOutput_Adr, (uint8_t*) &AudioBuf1, 512);
                DACOutput_Adr += 512;
            }
            else if (API_DAC_Output.AudioBufIDX == 0x0180) 
            {
                API_Flash_MultiBytesRead (DACOutput_Adr, (uint8_t*) &AudioBuf0, 512);
                DACOutput_Adr += 512;
            }

            // Stop DAC output
            API_DAC_Output.State  ++;
            if (API_DAC_Output.State  == ResetAudioState)
            {
                MID_DAC_SetValue(&mDAC, 0);
                MID_TM_Base_Stop_IT(&mTM10);
            }
            return;
        }
        // --------------------------------------------------------------------
        // Audio data from USB 
        // --------------------------------------------------------------------
        else if (API_DAC_Output.AudioSource == DAC_DATA_USB)
        {
            // get audio data
            ptr16 = ((uint16_t *) &TST_USB_AudioBuf) + API_DAC_Output.AudioBufIDX;
            AudioDat = *ptr16;

            AudioDat -= 0x8000;
//            AudioDat = AudioDat >> (API_DAC_Output.AudioVolume);    // control audio volume
            AudioDat = AudioDat >> (4);

            // Autio output R (DAC output)
            MID_DAC_SetValue(&mDAC, AudioDat);

            // AudioBufIDX routine
            if (API_DAC_Output.AudioDataFreq == MID_DAC_16K)
            {
                API_DAC_Output.AudioBufIDX += 4;
                if (API_DAC_Output.AudioBufIDX == 32)
                    API_DAC_Output.AudioBufIDX = 0;
            }
            else
            {
                API_DAC_Output.AudioBufIDX += 2;
                if (API_DAC_Output.AudioBufIDX == 16)
                    API_DAC_Output.AudioBufIDX = 0;
            }

            // Stop DAC output
            API_DAC_Output.State  ++;
            if (API_DAC_Output.State  == ResetAudioState)
            {
                MID_DAC_SetValue(&mDAC, 0);
                MID_TM_Base_Stop_IT(&mTM10);
                API_DAC_Output.AudioSource = DAC_DATA_FLASH;
            }
            return;
        }
    }
}

/**
 *******************************************************************************
 * @brief       This call back for it when USB receive audio data.
 * @details     
 * @return      None
 * @exception   
 * @note        
 *******************************************************************************
*/
void USB_Audio_OUTDataCallback(uint8_t AudioData_Byte)
{    
    API_DAC_StartUSBOutput(AudioData_Byte);             // To set DAC to output audio

    //===============================================
    USB_Audio.AudioOUT_Busyflag = 0;
}


