/*
 * Copyright 2018-2025 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "usb_device_config.h"
#include "usb.h"
#include "usb_device.h"

#include "usb_device_class.h"
#include "usb_device_cdc_acm.h"

#include "usb_device_audio.h"
#include "usb_device_ch9.h"
#include "usb_device_descriptor.h"

#include "Main.h"

#include "fsl_device_registers.h"
#include "clock_config.h"
#include "board.h"
#include "fsl_debug_console.h"

#include <stdio.h>
#include <stdlib.h>
#if (defined(FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT > 0U))
#include "fsl_sysmpu.h"
#endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */
#if defined(FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)
#include "usb_phy.h"
#endif

#include "pin_mux.h"
#include "fsl_i2c.h"
#include "fsl_i2s.h"
#include "fsl_i2s_dma.h"
#include "fsl_wm8904.h"
#include "fsl_codec_common.h"
#include "fsl_codec_adapter.h"

#include "fsl_inputmux.h"
#include "fsl_mu.h"
#include "fsl_sema42.h"
#include "fsl_power.h"
#include <stdbool.h>
#if defined(USB_DEVICE_AUDIO_USE_SYNC_MODE) && (USB_DEVICE_AUDIO_USE_SYNC_MODE > 0U)
#include "fsl_sctimer.h"
#endif

#include "dsp_support.h"
#include "GlobalDef.h"
#include "SubFunc.h"
#include "CircularBufManagement.h"
#include "CircularBuf.h"
#include "AudioIoInit.h"


#if 1		//folding
/*******************************************************************************
 * Definitions
 ******************************************************************************/


#define DEMO_I2C_MASTER_CLOCK_FREQUENCY CLOCK_GetMclkClkFreq()
#define DEMO_I2S_TX (I2S3)
#define DEMO_DMA (DMA0)
#define DEMO_I2S_TX_CHANNEL (7)
/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void BOARD_InitHardware(void);
void USB_DeviceClockInit(void);
void USB_DeviceIsrEnable(void);
#if USB_DEVICE_CONFIG_USE_TASK
void USB_DeviceTaskFn(void *deviceHandle);
#endif



usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param);

extern volatile unsigned char I2SRx0DmaTransferringIsUsingBufA;
extern volatile int RestartI2S2Cnt;
extern volatile unsigned int s_sendSize;
extern unsigned int VComReportValue_U32_1;
extern unsigned int VComReportValue_U32_2;
extern unsigned int VComReportValue_U32_3;
extern unsigned int VComReportValue_U32_4;

extern void Init_Board_Audio(void);
extern void USB_AudioSpeakerResetTask(void);

/*******************************************************************************
 * Variables
 ******************************************************************************/
extern usb_device_composite_struct_t g_composite;
//extern uint8_t audioPlayDataBuff[AUDIO_SPEAKER_DATA_WHOLE_BUFFER_LENGTH * FS_ISO_OUT_ENDP_PACKET_SIZE];

unsigned int AudioIoFrameCnt=0;
unsigned int CycCnt1,CycCnt2;
unsigned int AudioSourceIdx;
unsigned int DelayCntAsrcFeedIn_ExtI2S;
unsigned int DelayCntAsrcFeedIn_UsbAudioDn;
uint8_t domainId;

USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
uint8_t NowIsUsingDmaBufferA=1;
codec_handle_t codecHandle;

wm8904_config_t wm8904Config =
{
    .i2cConfig          = {.codecI2CInstance = BOARD_CODEC_I2C_INSTANCE},
    .recordSource       = kWM8904_RecordSourceLineInput,
    .recordChannelLeft  = kWM8904_RecordChannelLeft2,
    .recordChannelRight = kWM8904_RecordChannelRight2,
    .playSource         = kWM8904_PlaySourceDAC,
    .slaveAddress       = WM8904_I2C_ADDRESS,
    .protocol           = kWM8904_ProtocolI2S,
   	.format             = {.sampleRate = kWM8904_SampleRate48kHz, .bitWidth = kWM8904_BitWidth32},
    .master             = true,
};
codec_config_t boardCodecConfig = {.codecDevType = kCODEC_WM8904, .codecDevConfig = &wm8904Config};

#if defined(USB_DEVICE_AUDIO_USE_SYNC_MODE) && (USB_DEVICE_AUDIO_USE_SYNC_MODE > 0U)
static uint32_t eventCounterL = 0;
static uint32_t captureRegisterNumber;
static sctimer_config_t sctimerInfo;
#endif
/* Composite device structure. */
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
usb_device_composite_struct_t g_composite;
extern usb_device_class_struct_t g_UsbDeviceCdcVcomConfig;
extern usb_device_class_struct_t g_UsbDeviceAudioClassRecorder;
extern usb_device_class_struct_t g_UsbDeviceAudioClassSpeaker;

extern usb_device_composite_struct_t *g_UsbDeviceComposite;
extern usb_device_composite_struct_t *g_deviceAudioComposite;

/* USB device class information */
static usb_device_class_config_struct_t g_CompositeClassConfig[4] = {{
                                                                         USB_DeviceCdcVcomCallback,
                                                                         (class_handle_t)NULL,
                                                                         &g_UsbDeviceCdcVcomConfig,
                                                                     },
                                                                     {
                                                                         USB_DeviceAudioCompositeCallback,
                                                                         (class_handle_t)NULL,
                                                                         &g_UsbDeviceAudioClassRecorder,
                                                                     },
                                                                     {
                                                                         USB_DeviceAudioCompositeCallback,
                                                                         (class_handle_t)NULL,
                                                                         &g_UsbDeviceAudioClassSpeaker,
                                                                     }
};

/* USB device class configuraion information */
static usb_device_class_config_list_struct_t g_UsbDeviceCompositeConfigList = {
    g_CompositeClassConfig,
    USB_DeviceCallback,
    3
};

/*******************************************************************************
 * Code
 ******************************************************************************/
uint8_t APP_GetMCoreDomainID(void)
{
    return 1U;
}

// global volatile counter used for sleep/wait
uint32_t g_eventTimeMilliseconds;
volatile uint32_t g_systickCounter;
void SysTick_Handler(void)
{
#ifdef __CA7_REV
    SystemClearSystickFlag();
#endif
    g_eventTimeMilliseconds++;

	if (g_systickCounter != 0U)
	{
		g_systickCounter--;
	}
}

#if defined(USB_DEVICE_AUDIO_USE_SYNC_MODE) && (USB_DEVICE_AUDIO_USE_SYNC_MODE > 0U)
extern uint32_t USB_AudioSpeakerBufferSpaceUsed(void);
#endif

void BOARD_Codec_Init()
{
	if( CODEC_Init(&codecHandle, &boardCodecConfig)!=0 )
	{
	    PRINTF("RT685 MCU: Codec Init Failed!...\r\n");
		while(1){OpeningBlink(3);};
	}
    CODEC_SetVolume(&codecHandle, kCODEC_PlayChannelHeadphoneLeft | kCODEC_PlayChannelHeadphoneRight, 57);
}


#if defined(USB_DEVICE_AUDIO_USE_SYNC_MODE) && (USB_DEVICE_AUDIO_USE_SYNC_MODE > 0U)
void SCTIMER_SOF_TOGGLE_HANDLER()
{
	GET_CYCLE_COUNTER(CycCnt1);
    uint32_t currentSctCap = 0, pllCountPeriod = 0, pll_change = 0;
    //uint32_t usedSpace      = 0;
    static int32_t pllCount = 0, pllDiff = 0;
    static int32_t err, abs_err;

    //don't do PLL adjusting if ASRC is decided to be used for audio synchronizing
    if(AudioSourceIdx==AudioSrc1_UsbAudioDnSyncByAsrc) return;

    if (SCTIMER_GetStatusFlags(SCT0) & (1 << eventCounterL))
    {
        /* Clear interrupt flag.*/
        SCTIMER_ClearStatusFlags(SCT0, (1 << eventCounterL));
    }

    if (g_composite.audioUnified.speakerIntervalCount != 100)
    {
        g_composite.audioUnified.speakerIntervalCount++;
        return;
    }
    g_composite.audioUnified.speakerIntervalCount = 1;
    currentSctCap                                 = SCT0->CAP[0];
    pllCountPeriod                                = currentSctCap - g_composite.audioUnified.audioPllTicksPrev;
    g_composite.audioUnified.audioPllTicksPrev    = currentSctCap;
    pllCount                                      = pllCountPeriod;
    if (g_composite.audioUnified.attach)
    {
        if (abs(pllCount - AUDIO_PLL_USB1_SOF_INTERVAL_COUNT) < (AUDIO_PLL_USB1_SOF_INTERVAL_COUNT >> 7))
        {
            pllDiff = pllCount - g_composite.audioUnified.audioPllTicksEma;
            g_composite.audioUnified.audioPllTickEmaFrac += (pllDiff % 8);
            g_composite.audioUnified.audioPllTicksEma += (pllDiff / 8) + g_composite.audioUnified.audioPllTickEmaFrac / 8;
            g_composite.audioUnified.audioPllTickEmaFrac = (g_composite.audioUnified.audioPllTickEmaFrac % 8);

            err     = g_composite.audioUnified.audioPllTicksEma - AUDIO_PLL_USB1_SOF_INTERVAL_COUNT;
            abs_err = abs(err);
            if (abs_err > g_composite.audioUnified.audioPllStep)
            {
                if (err > 0)
                {
                    g_composite.audioUnified.curAudioPllFrac -= abs_err / g_composite.audioUnified.audioPllStep;
                }
                else
                {
                    g_composite.audioUnified.curAudioPllFrac += abs_err / g_composite.audioUnified.audioPllStep;
                }
                pll_change = 1;
            }
			#if 0
				if (g_composite.audioUnified.startPlayHalfFull)
				{
					usedSpace = CirAudioBuf_SpaceOccupiedInSamples_S32(&UsbDnSpkBuf_ForUacSyncModeL) * sizeof(float);
					if (usedSpace > ((AUDIO_SPEAKER_UsbDnBufLengthInMs / 2 + 1) * HS_ISO_OUT_ENDP_PACKET_SIZE))
					{
						g_composite.audioUnified.curAudioPllFrac++;
						pll_change = 1;
					}
					else if (usedSpace < ((AUDIO_SPEAKER_UsbDnBufLengthInMs / 2 - 1) * HS_ISO_OUT_ENDP_PACKET_SIZE))
					{
						g_composite.audioUnified.curAudioPllFrac--;
						pll_change = 1;
					}
				}
			#endif
            if (pll_change)
            {
                CLKCTL1->AUDIOPLL0NUM = g_composite.audioUnified.curAudioPllFrac;
            }
        }
    }
	GET_CYCLE_COUNTER(CycCnt2);
	//VarBlockSharedByDspAndMcu.CycCnt[12]=CycCnt2-CycCnt1;
}

void SCTIMER_CaptureInit(void)
{
    INPUTMUX->SCT0_IN_SEL[eventCounterL] = 0xFU; /* 0xFU for USB1.*/
    SCTIMER_GetDefaultConfig(&sctimerInfo);

    /* Switch to 16-bit mode */
    sctimerInfo.clockMode   = kSCTIMER_Input_ClockMode;
    sctimerInfo.clockSelect = kSCTIMER_Clock_On_Rise_Input_7;

    /* Initialize SCTimer module */
    SCTIMER_Init(SCT0, &sctimerInfo);

    if (SCTIMER_SetupCaptureAction(SCT0, kSCTIMER_Counter_L, &captureRegisterNumber, eventCounterL) == kStatus_Fail)
    {
        usb_echo("SCT Setup Capture failed!\r\n");
    }
    SCT0->EV[0].STATE = 0x1;
    SCT0->EV[0].CTRL  = (0x01 << 10) | (0x2 << 12);

    /* Enable interrupt flag for event associated with out 4, we use the interrupt to update dutycycle */
    SCTIMER_EnableInterrupts(SCT0, (1 << eventCounterL));

    /* Receive notification when event is triggered */
    SCTIMER_SetCallback(SCT0, SCTIMER_SOF_TOGGLE_HANDLER, eventCounterL);

    /* Enable at the NVIC */
    EnableIRQ(SCT0_IRQn);

    /* Start the L counter */
    SCTIMER_StartTimer(SCT0, kSCTIMER_Counter_L);
}
#endif
void USB_IRQHandler(void)
{
	GET_CYCLE_COUNTER(CycCnt1);
    USB_DeviceLpcIp3511IsrFunction(g_composite.deviceHandle);
	GET_CYCLE_COUNTER(CycCnt2);
	//VarBlockSharedByDspAndMcu.CycCnt[15]=CycCnt2-CycCnt1;
}

void USB_DeviceClockInit(void)
{
    usb_phy_config_struct_t phyConfig = {
        BOARD_USB_PHY_D_CAL,
        BOARD_USB_PHY_TXCAL45DP,
        BOARD_USB_PHY_TXCAL45DM,
    };
    /* enable USB IP clock */
    CLOCK_SetClkDiv(kCLOCK_DivPfc1Clk, 5);
    CLOCK_AttachClk(kXTALIN_CLK_to_USB_CLK);
    CLOCK_SetClkDiv(kCLOCK_DivUsbHsFclk, 1);
    CLOCK_EnableUsbhsDeviceClock();
    RESET_PeripheralReset(kUSBHS_PHY_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kUSBHS_DEVICE_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kUSBHS_HOST_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kUSBHS_SRAM_RST_SHIFT_RSTn);
    /*Make sure USDHC ram buffer has power up*/
    POWER_DisablePD(kPDRUNCFG_APD_USBHS_SRAM);
    POWER_DisablePD(kPDRUNCFG_PPD_USBHS_SRAM);
    POWER_ApplyPD();



    /* save usb ip clock freq*/
    uint32_t usbClockFreq = g_xtalFreq / 1;
    /* enable USB PHY PLL clock, the phy bus clock (480MHz) source is same with USB IP */
    CLOCK_EnableUsbHs0PhyPllClock(kXTALIN_CLK_to_USB_CLK, usbClockFreq);

    //CLOCK_EnableUsbhsPhyClock();
    //CLOCK_EnableUsbHs0PhyPllClock(clock_attach_id_t src, uint32_t freq)


#if defined(FSL_FEATURE_USBHSD_USB_RAM) && (FSL_FEATURE_USBHSD_USB_RAM)
    for (int i = 0; i < FSL_FEATURE_USBHSD_USB_RAM; i++)
    {
        ((uint8_t *)FSL_FEATURE_USBHSD_USB_RAM_BASE_ADDRESS)[i] = 0x00U;
    }
#endif
    USB_EhciPhyInit(CONTROLLER_ID, BOARD_XTAL_SYS_CLK_HZ, &phyConfig);

    /* the following code should run after phy initialization and should wait some microseconds to make sure utmi clock
     * valid */
    /* enable usb1 host clock */
    CLOCK_EnableClock(kCLOCK_UsbhsHost);
    /*  Wait until host_needclk de-asserts */
    while (SYSCTL0->USBCLKSTAT & SYSCTL0_USBCLKSTAT_HOST_NEED_CLKST_MASK)
    {
        __ASM("nop");
    }
    /*According to reference mannual, device mode setting has to be set by access usb host register */
    USBHSH->PORTMODE |= USBHSH_PORTMODE_DEV_ENABLE_MASK;
    /* disable usb1 host clock */
    CLOCK_DisableClock(kCLOCK_UsbhsHost);
}
void USB_DeviceIsrEnable(void)
{
    uint8_t irqNumber;

    uint8_t usbDeviceIP3511Irq[] = USBHSD_IRQS;
    irqNumber                    = usbDeviceIP3511Irq[CONTROLLER_ID - kUSB_ControllerLpcIp3511Hs0];

    /* Install isr, set priority, and enable IRQ. */
    NVIC_SetPriority((IRQn_Type)irqNumber, USB_DEVICE_INTERRUPT_PRIORITY);
    EnableIRQ((IRQn_Type)irqNumber);
}
#if USB_DEVICE_CONFIG_USE_TASK
void USB_DeviceTaskFn(void *deviceHandle)
{
    USB_DeviceLpcIp3511TaskFunction(deviceHandle);
}
#endif

/*!
 * @brief USB device callback function.
 *
 * This function handles the usb device specific requests.
 *
 * @param handle		  The USB device handle.
 * @param event 		  The USB device event type.
 * @param param 		  The parameter of the device specific request.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param)
{
    usb_status_t error = kStatus_USB_Error;
    uint16_t *temp16   = (uint16_t *)param;
    uint8_t *temp8     = (uint8_t *)param;
    uint8_t count      = 0U;

    switch (event)
    {
        case kUSB_DeviceEventBusReset:
        {
            for(count = 0U; count < USB_DEVICE_INTERFACE_COUNT; count++)
            {
                g_composite.currentInterfaceAlternateSetting[count] = 0U;
            }
            g_composite.attach               = 0U;
            g_composite.currentConfiguration = 0U;
            error                            = kStatus_USB_Success;
#if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) || (defined(USB_DEVICE_CONFIG_LPCIP3511HS) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
            /* Get USB speed to configure the device, including max packet size and interval of the endpoints. */
            if (kStatus_USB_Success == USB_DeviceClassGetSpeed(CONTROLLER_ID, &g_composite.speed))
            {
                USB_DeviceSetSpeed(handle, g_composite.speed);
            }
			#if (USB_DEVICE_CONFIG_AUDIO_CLASS_2_0)
				#if defined(USB_DEVICE_AUDIO_USE_SYNC_MODE) && (USB_DEVICE_AUDIO_USE_SYNC_MODE > 0U)
				#else
							AUDIO_UPDATE_FEEDBACK_DATA(audioFeedBackBuffer, AUDIO_SAMPLING_RATE_TO_10_14);
				#endif
			#endif

#endif
        }
        break;
        case kUSB_DeviceEventSetConfiguration:
				if (0U == (*temp8))
				{
					g_composite.attach = 0U;
					g_composite.currentConfiguration = 0U;
				}
				else if (USB_COMPOSITE_CONFIGURE_INDEX == (*temp8))
				{
					g_composite.attach = 1;
					USB_DeviceAudioCompositeSetConfigure(g_composite.audioUnified.audioSpeakerHandle, *temp8);
					USB_DeviceAudioCompositeSetConfigure(g_composite.audioUnified.audioRecorderHandle, *temp8);
					USB_DeviceCdcVcomSetConfigure(g_composite.cdcVcom.cdcAcmHandle, *temp8);
					g_composite.currentConfiguration = *temp8;
					error = kStatus_USB_Success;
				}
				else
				{
					error = kStatus_USB_InvalidRequest;
				}
            break;
        case kUSB_DeviceEventSetInterface:

            if (g_composite.attach)
            {
                uint8_t interface                                       = (uint8_t)((*temp16 & 0xFF00U) >> 0x08U);
                uint8_t alternateSetting                                = (uint8_t)(*temp16 & 0x00FFU);

                if (interface < USB_DEVICE_INTERFACE_COUNT)
                {
                    g_composite.currentInterfaceAlternateSetting[interface] = alternateSetting;
                }

                if (USB_AUDIO_RECORDER_STREAM_INTERFACE_INDEX == interface)
                {
                    error = USB_DeviceAudioRecorderSetInterface(g_composite.audioUnified.audioRecorderHandle, interface,
                                                                alternateSetting);
                }
                else if (USB_AUDIO_SPEAKER_STREAM_INTERFACE_INDEX == interface)
                {
                    error = USB_DeviceAudioSpeakerSetInterface(g_composite.audioUnified.audioSpeakerHandle, interface,
                                                               alternateSetting);
                }
                else
                {
                    error = kStatus_USB_Success;
                }
            }
            break;
        case kUSB_DeviceEventGetConfiguration:
            if (param)
            {
                *temp8 = g_composite.currentConfiguration;
                error  = kStatus_USB_Success;
            }
            break;
        case kUSB_DeviceEventGetInterface:
            if (param)
            {
                uint8_t interface = (uint8_t)((*temp16 & 0xFF00U) >> 0x08U);
                if (interface < USB_DEVICE_INTERFACE_COUNT)
                {
                    *temp16 = (*temp16 & 0xFF00U) | g_composite.currentInterfaceAlternateSetting[interface];
                    error   = kStatus_USB_Success;
                }
                else
                {
                    error = kStatus_USB_InvalidRequest;
                }
            }
            break;
        case kUSB_DeviceEventGetDeviceDescriptor:
            if (param)
            {
                error = USB_DeviceGetDeviceDescriptor(handle, (usb_device_get_device_descriptor_struct_t *)param);
            }
            break;
        case kUSB_DeviceEventGetConfigurationDescriptor:
            if (param)
            {
                error = USB_DeviceGetConfigurationDescriptor(handle,
                                                             (usb_device_get_configuration_descriptor_struct_t *)param);
            }
            break;
        case kUSB_DeviceEventGetStringDescriptor:
            if (param)
            {
                error = USB_DeviceGetStringDescriptor(handle, (usb_device_get_string_descriptor_struct_t *)param);
            }
            break;
#if (defined(USB_DEVICE_CONFIG_CV_TEST) && (USB_DEVICE_CONFIG_CV_TEST > 0U))
        case kUSB_DeviceEventGetDeviceQualifierDescriptor:
            if (param)
            {
                /* Get device descriptor request */
                error = USB_DeviceGetDeviceQualifierDescriptor(
                    handle, (usb_device_get_device_qualifier_descriptor_struct_t *)param);
            }
            break;
#endif
        default:
            break;
    }

    return error;
}

/*!
 * @brief Application initialization function.
 *
 * This function initializes the application.
 *
 * @return None.
 */

void APPInit(void)
{

    USB_DeviceClockInit();
#if (defined(FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT > 0U))
    SYSMPU_Enable(SYSMPU, 0);
#endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */

    g_composite.speed                            = USB_SPEED_FULL;
    g_composite.attach                           = 0U;
    g_composite.audioUnified.audioSpeakerHandle  = (class_handle_t)NULL;
    g_composite.audioUnified.audioRecorderHandle = (class_handle_t)NULL;
    g_composite.cdcVcom.cdcAcmHandle             = (class_handle_t)NULL;
    g_composite.deviceHandle                     = NULL;

    if (kStatus_USB_Success !=
        USB_DeviceClassInit(CONTROLLER_ID, &g_UsbDeviceCompositeConfigList, &g_composite.deviceHandle))
    {
        usb_echo("USB device composite demo init failed\r\n");
        return;
    }
    else
    {
        g_composite.cdcVcom.cdcAcmHandle             = g_UsbDeviceCompositeConfigList.config[0].classHandle;
        g_composite.audioUnified.audioRecorderHandle = g_UsbDeviceCompositeConfigList.config[1].classHandle;
        g_composite.audioUnified.audioSpeakerHandle  = g_UsbDeviceCompositeConfigList.config[2].classHandle;

        USB_DeviceAudioCompositeInit(&g_composite);
        USB_DeviceCdcVcomInit       (&g_composite);
    }

    //Init_Board_Audio();

    USB_DeviceIsrEnable();

    USB_DeviceRun(g_composite.deviceHandle);

    usb_echo("RT685 MCU: USB composite device of VCOM and audio started\r\n");

}

volatile unsigned int MU_U32InfoFromDsp;
void APP_MU_IRQHandler(void)
{
    uint32_t flag = 0;

    flag = MU_GetStatusFlags(APP_MU);
    if ((flag & kMU_Rx0FullFlag) == kMU_Rx0FullFlag)
    {
    	MU_U32InfoFromDsp = MU_ReceiveMsgNonBlocking(APP_MU, CHN_MU_REG_NUM);
    }
    SDK_ISR_EXIT_BARRIER;
}

#endif			//folding

void AudioIoProcess_AfterI2SRxInputBufIsReady(void)
{
	int *TmpPtrS32;

	if(OneFrameI2SAudioOutputTxIsFinished)
	{
		DbgPin1Up;

		GET_CYCLE_COUNTER(CycCnt1);

		AudioIoFrameCnt++;
		OneFrameI2SAudioOutputTxIsFinished=0;

		if(I2STxDmaTransferringIsUsingBufA)
		{	//now DMA is using I2S BufA, the MCU code should use I2S DMA buffer B, which is just ready
			VarBlockSharedByDspAndMcu.I2SOtputCh01Ptr=I2STxBufCh0And1Mixed_B;
			VarBlockSharedByDspAndMcu.I2SOtputCh23Ptr=I2STxBufCh2And3Mixed_B;
		}else
		{	//now DMA is using I2S BufB, the MCU code should use I2S DMA buffer A, which is just ready
			VarBlockSharedByDspAndMcu.I2SOtputCh01Ptr=I2STxBufCh0And1Mixed_A;
			VarBlockSharedByDspAndMcu.I2SOtputCh23Ptr=I2STxBufCh2And3Mixed_A;
		}

		// --- USB synch process and downstreaming
		//get USB down streaming audio data to VarBlockSharedByDspAndMcu.SpkAudioBufDnStreamingL(R)_Flt. format is int32, effective 32 bits
		#if 1	//--- folding
			static uint32_t lastUsbRecvTimes = 0, usbAudioNoInputCounter = 0;
			if (lastUsbRecvTimes != g_composite.audioUnified.usbRecvTimes)
			{
				lastUsbRecvTimes       = g_composite.audioUnified.usbRecvTimes;
				usbAudioNoInputCounter = 0;
			}
			else if (g_composite.audioUnified.usbRecvTimes)
			{
				usbAudioNoInputCounter++;
				if (usbAudioNoInputCounter == 30)
				{
					//audio intrrupt has come here for many times, but no USB audio Rx event occurs ---- this means USB audio Rx is borken
					g_composite.audioUnified.startPlayHalfFull      = 0;
					g_composite.audioUnified.speakerDetachOrNoInput = 1;
					lastUsbRecvTimes                                = 0;
					usbAudioNoInputCounter                          = 0;
				}
			}


			if(AudioSourceIdx!=AudioSrc0_UsbAudioDnSyncByCTimer)
			{
				//USB down-streaming sync by Cadence ASRC, or external I2S source input to be converted by Cadence ASRC
				if ((g_composite.audioUnified.startPlayHalfFull)||
						(AudioSourceIdx==AudioSrc2_External33KHzI2S)||(AudioSourceIdx==AudioSrc3_External48KHzI2S))
				{	//has enough down-streaming audio
					//copy audio samples to UsbAudioDnStreamingOneFrameBufL and UsbAudioDnStreamingOneFrameBufR from VarBlockSharedByDspAndMcu.CirBufUsbAudioDnStreamingL/R, which is Cadence ASRC converted
					//and will be converted to float in DSP side
				    SEMA42_Lock(APP_SEMA42, SEMA42_GATE, domainId);
					if(CirAudioBuf_SpaceOccupiedInSamples_S32(&VarBlockSharedByDspAndMcu.CirBufUsbAudioDnStreamingL) >= AudioFrameSizeInSamplePerCh)
					{
						TmpPtrS32=CirAudioBuf_ReadSamples_GetRdPtr_S32(&VarBlockSharedByDspAndMcu.CirBufUsbAudioDnStreamingL, AudioFrameSizeInSamplePerCh);
						memcpy(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL, TmpPtrS32, AudioFrameSizeInSamplePerCh*sizeof(int));
					}else
					{
						memset(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL,0,sizeof(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL));
						PRINTF("E");
					}
					if(CirAudioBuf_SpaceOccupiedInSamples_S32(&VarBlockSharedByDspAndMcu.CirBufUsbAudioDnStreamingR) >= AudioFrameSizeInSamplePerCh)
					{
						TmpPtrS32=CirAudioBuf_ReadSamples_GetRdPtr_S32(&VarBlockSharedByDspAndMcu.CirBufUsbAudioDnStreamingR, AudioFrameSizeInSamplePerCh);
						memcpy(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR, TmpPtrS32, AudioFrameSizeInSamplePerCh*sizeof(int));
					}else
					{
						memset(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR,0,sizeof(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR));
						PRINTF("E");
					}
				    SEMA42_Unlock(APP_SEMA42, SEMA42_GATE);

				}else
				{
					memset(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL,0,sizeof(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL));
					memset(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR,0,sizeof(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR));
				}
			}
			else
			{
				//USB audio down-streaming sync by CTimer
				if (g_composite.audioUnified.startPlayHalfFull)
				{	//has enough down-streaming audio
					//copy audio samples to UsbAudioDnStreamingOneFrameBufL and UsbAudioDnStreamingOneFrameBufR from UsbDnSpkBuf_ForUacSyncModeL/R, and will be converted to float in DSP side
					if(CirAudioBuf_SpaceOccupiedInSamples_S32(&UsbDnSpkBuf_ForUacSyncModeL) >= AudioFrameSizeInSamplePerCh)
					{
						TmpPtrS32=CirAudioBuf_ReadSamples_GetRdPtr_S32(&UsbDnSpkBuf_ForUacSyncModeL, AudioFrameSizeInSamplePerCh);
						//g_composite.audioUnified.audioSendCount += AudioFrameSizeInSamplePerCh * AUDIO_OUT_FORMAT_CHANNELS * AUDIO_OUT_FORMAT_SIZE;
						//g_composite.audioUnified.audioSendTimes++;
						memcpy(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL, TmpPtrS32, AudioFrameSizeInSamplePerCh*sizeof(int));
					}else
					{
						memset(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL,0,sizeof(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL));
					}
					if(CirAudioBuf_SpaceOccupiedInSamples_S32(&UsbDnSpkBuf_ForUacSyncModeR) >= AudioFrameSizeInSamplePerCh)
					{
						TmpPtrS32=CirAudioBuf_ReadSamples_GetRdPtr_S32(&UsbDnSpkBuf_ForUacSyncModeR, AudioFrameSizeInSamplePerCh);
						memcpy(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR, TmpPtrS32, AudioFrameSizeInSamplePerCh*sizeof(int));
					}else
					{
						memset(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR,0,sizeof(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR));
					}
				}else
				{	//no USB down streaming data --- set all to zeros
					memset(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL,0,sizeof(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufL));
					memset(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR,0,sizeof(VarBlockSharedByDspAndMcu.UsbAudioDnStreamingOneFrameBufR));
				}
			}

		#endif


		//audio input is ready, DSP needs to process
		MU_SendMsgNonBlocking(APP_MU, CHN_MU_REG_NUM, 0x1000);		//send 0x1000 to DSP, to trigger DSP MU interrupt

		//report cycle count info to host PC through VCOM
		static int CycCntInfoIdx=0;
		//if(!(AudioIoFrameCnt%(5000)))
		//if(!(AudioIoFrameCnt%(2000)))
		if(!(AudioIoFrameCnt%(100)))
		//if(!(AudioIoFrameCnt%(8)))
		{
			CycCntInfoIdx=0;	//this is to only display the first 4 watching values --- close this line to display all the 16 watch values
			VComReportValue_U32_1=VarBlockSharedByDspAndMcu.CycCnt[CycCntInfoIdx*4+0];
			VComReportValue_U32_2=VarBlockSharedByDspAndMcu.CycCnt[CycCntInfoIdx*4+1];
			VComReportValue_U32_3=VarBlockSharedByDspAndMcu.CycCnt[CycCntInfoIdx*4+2];
			VComReportValue_U32_4=VarBlockSharedByDspAndMcu.CycCnt[CycCntInfoIdx*4+3];
			s_sendSize=CycCntInfoIdx+1;				//command to do VCOM send in the main loop!
			CycCntInfoIdx++;						//using CycCntInfoIdx from 0 to 3, can have 16 cycle cnt values to be printed
			if(CycCntInfoIdx>3) CycCntInfoIdx=0;
		}

		GET_CYCLE_COUNTER(CycCnt2);
		//VarBlockSharedByDspAndMcu.CycCnt[13]=CycCnt2-CycCnt1;

		if(RestartI2S2Cnt)
		{
			RestartI2S2Cnt--;
			if(RestartI2S2Cnt==1)
			{
				//restart I2S2
				//start flexcomm I2S
				((I2S_Type *)DEMO_I2S_RX0)->FIFOCFG |= (1<<16);	//empty fifo
				((I2S_Type *)DEMO_I2S_RX0)->CFG1|= 0x01;		//enalbe
				((I2S_Type *)DEMO_I2S_RX0)->CFG1&=~0x02;		//continue
				((I2S_Type *)DEMO_I2S_RX0)->FIFOCFG |= I2S_FIFOCFG_DMARX_MASK;

				I2S_EnableInterrupts(DEMO_I2S_RX0, (uint32_t)kI2S_RxErrorFlag | (uint32_t)kI2S_RxLevelFlag);
			    NVIC_SetPriority((IRQn_Type)FLEXCOMM2_IRQn, 1);
			    EnableIRQ((IRQn_Type)FLEXCOMM2_IRQn);

				//set the flag variables to initial value
				I2SRx0DmaTransferringIsUsingBufA=0;
			}
		}
		DbgPin1Dn;
    }
}

#if 0
//only for watching PID coefficient
float *f1;
float *f2;
float *f3;
float *f4;
#endif


#if defined(__CC_ARM) || (defined(__ARMCC_VERSION)) || defined(__GNUC__)
int main(void)
#else
void main(void)
#endif
{

    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();

    PRINTF("RT685 MCU: Started...\r\n");
    PRINTF("RT685 MCU: size of shared memory struct is %d \r\n", sizeof(VarBlockSharedByDspAndMcu));

    InitDbgPin();
    OpeningBlink(3);


//init the peripherals, external AMP and/or CODEC, and USB dev
#if 1	//---folding

    CLOCK_EnableClock(kCLOCK_InputMux);

	PRINTF("RT685 MCU: Setting up clocks\r\n");

	/* attach main clock to I3C */
	CLOCK_AttachClk(kMAIN_CLK_to_I3C_CLK);
	CLOCK_SetClkDiv(kCLOCK_DivI3cClk, 20);


	/* attach AUDIO PLL clock to FLEXCOMM1 (I2S1) */
	CLOCK_AttachClk(kAUDIO_PLL_to_FLEXCOMM1);
	/* attach AUDIO PLL clock to FLEXCOMM2 (I2S2) */
	CLOCK_AttachClk(kAUDIO_PLL_to_FLEXCOMM2);
	/* attach AUDIO PLL clock to FLEXCOMM3 (I2S3) */
	CLOCK_AttachClk(kAUDIO_PLL_to_FLEXCOMM3);

	/* attach AUDIO PLL clock to MCLK */
	CLOCK_AttachClk(kAUDIO_PLL_to_MCLK_CLK);
	CLOCK_SetClkDiv(kCLOCK_DivMclkClk, 1);	//mclk=24.576MHz
	SYSCTL1->MCLKPINDIR = SYSCTL1_MCLKPINDIR_MCLKPINDIR_MASK;

	/* Set shared signal set 0: SCK, WS from Flexcomm1 */
	SYSCTL1->SHAREDCTRLSET[0] = SYSCTL1_SHAREDCTRLSET_SHAREDSCKSEL(1) | SYSCTL1_SHAREDCTRLSET_SHAREDWSSEL(1);
	/* Set flexcomm2 SCK, WS from shared signal set 0 */
	//SYSCTL1->FCCTRLSEL[2] = SYSCTL1_FCCTRLSEL_SCKINSEL(1) | SYSCTL1_FCCTRLSEL_WSINSEL(1);	//flexcomm2 is to be driven by external I2S source clock signals
	/* Set flexcomm3 SCK, WS from shared signal set 0 */
	SYSCTL1->FCCTRLSEL[3] = SYSCTL1_FCCTRLSEL_SCKINSEL(1) | SYSCTL1_FCCTRLSEL_WSINSEL(1);


    wm8904Config.i2cConfig.codecI2CSourceClock = CLOCK_GetI3cClkFreq();
    wm8904Config.mclk_HZ                       = CLOCK_GetMclkClkFreq();

	#if defined(USB_DEVICE_AUDIO_USE_SYNC_MODE) && (USB_DEVICE_AUDIO_USE_SYNC_MODE > 0U)
		/* attach AUDIO PLL clock to SCTimer input7. */
		CLOCK_AttachClk(kAUDIO_PLL_to_SCT_CLK);
		CLOCK_SetClkDiv(kCLOCK_DivSctClk, 1);
		g_composite.audioUnified.curAudioPllFrac = CLKCTL1->AUDIOPLL0NUM;
	#endif


    PRINTF("RT685 MCU: Initializing Codec\r\n");

	BOARD_Codec_Init();

    APPInit();

	PRINTF("RT685 MCU: Initializing DMA\r\n");
	BOARD_Init_DMA();
    PRINTF("RT685 MCU: Initializing I2S\r\n");
	BOARD_Init_I2S();

#endif


//boot DSP and handshake with DSP
#if 1	//---folding

	PRINTF("RT685 MCU: Booting DSP\r\n");
	/* Clear MUA reset before run DSP core */
	RESET_PeripheralReset(kMU_RST_SHIFT_RSTn);

	INPUTMUX_Init(INPUTMUX);
	INPUTMUX_AttachSignal(INPUTMUX, 1U, kINPUTMUX_MuBToDspInterrupt);
	INPUTMUX_Deinit(INPUTMUX);

	/* Clear MUA reset */
	RESET_PeripheralReset(kMU_RST_SHIFT_RSTn);

	MU_Init(APP_MU);
	EnableIRQ(MU_A_IRQn);

    /* Enable transmit and receive interrupt */
    MU_EnableInterrupts(APP_MU, kMU_Rx0FullInterruptEnable);


    /* Clear SEMA42 reset */
    RESET_PeripheralReset(kSEMA_RST_SHIFT_RSTn);
    /* Clear MUA reset */
    RESET_PeripheralReset(kMU_RST_SHIFT_RSTn);
    /* SEMA42 init */
    SEMA42_Init(APP_SEMA42);
    /* Reset the sema42 gate */
    SEMA42_ResetAllGates(APP_SEMA42);
    domainId = APP_GetMCoreDomainID();

	memset(&VarBlockSharedByDspAndMcu, 0, sizeof(VarBlockSharedByDspAndMcu));
	VarBlockSharedByDspAndMcu.ControlPara[0]=48000;		//input aidio to ASRC is USB down streaming 48KHz


	#if 0
	//only for watching PID coefficient
		f1=(float *)&VarBlockSharedByDspAndMcu.ControlPara[8];
		f2=(float *)&VarBlockSharedByDspAndMcu.ControlPara[9];
		f3=(float *)&VarBlockSharedByDspAndMcu.ControlPara[10];
		f4=(float *)&VarBlockSharedByDspAndMcu.ControlPara[11];
	#endif

	PRINTF("RT685 MCU: Waiting for DSP handshake\r\n");
	BOARD_DSP_Init();


	/* Wait DSP core is Boot Up */
	while (BOOT_FLAG != MU_GetFlags(APP_MU))
	{
		delay_ms(1);
	};

    SEMA42_Lock(APP_SEMA42, SEMA42_GATE, domainId);
	PRINTF("RT685 MCU: DSP handshake is received\r\n");
    SEMA42_Unlock(APP_SEMA42, SEMA42_GATE);


#endif

	//select filter1 as the default filter
	AudioSourceIdx=AudioSrc0_UsbAudioDnSyncByCTimer;
	DelayCntAsrcFeedIn_ExtI2S=0;
	DelayCntAsrcFeedIn_UsbAudioDn=0;

	InitAudioCircularBuf();
	CreateAndStartFlexcommTxAudioDMA();

	OneFrameI2SAudioOutputTxIsFinished=0;
    while (1)
    {

        USB_DeviceCdcVcomTask();
        USB_AudioSpeakerResetTask();

        AudioIoProcess_AfterI2SRxInputBufIsReady();

		if(MU_U32InfoFromDsp)
		{
		}

#if USB_DEVICE_CONFIG_USE_TASK
        USB_DeviceTaskFn(g_composite.deviceHandle);
#endif
    }

}
