

/**
 ******************************************************************************
 *
 * @file        main.C
 * @brief       MG32F02U128 USB LCD demo main c Code. 
 *
 * @par         Project
 *              MG32x02z
 * @version     V1.01
 * @date        2022/09/26
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2021 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.
 *******************************************************************************
 */

/*
    MG32F02U128 DemoBoard use Middleware Portting.
    USB Descriptors VCOM x2 / HID Key, Mouse and other x3 / Mass storage x2 / Audio In or Out / Video Out.
    USB ISP.
    BLE from SPI or URT SPI Mode.
        Command or Data or State COM Port Mode.
    LCD SPI form I/F URT SPI Mode.
        from SPI 25-Series use DMA or CPU.
        Show Text. RTC, Clock, 
    LCD with I80 16Bits I/F from EMB.
        from SPI 25-Series use DMA or CPU.
        Menu use CPU.
    ADC Key Scan.
    ADC Line In.
    DAC Audio Outm from SPI 25-Series Memory or USB Speaker.
    Shuttle switch. use TM36 Module.
    RGB_LED use TM Module.
    ISP use DFU with USB I/F.
    Debug Information use URT4.
*/

/* Includes ------------------------------------------------------------------*/
#include "Common.h"
#include "MG32x02z_ChipInit.h"
#include "MG0404A_BSP.h"
#include "LCD.h"
#include "LCD1_Menu.h"
#include "MG32x02z_Flash_25_API.h"
#include "MG32x02z_USBD_Core.h"
#include "MG32x02z_USBD_Audio_Core.h"
#include "MG32x02z_DACOutput_API.h"
#include "MG32x02z_RGBLED_API.h"
#include "MG32x02z_ScanKey_API.h"
#include "MG32x02z_LM35DZ_API.h"
#include "MG32x02z_ARGB_API.h"
#include "mg_api.h"
//#include "MG32x02z_DS1621_API.h"
#include "UserEvent.h"

/* External Function --------------------------------------------------------*/
extern void ChipInit(void);
extern void SystemCoreClockUpdate(void);
extern void API_DS1621_Init(void);

/* External vairables --------------------------------------------------------*/
extern uint32_t SystemCoreClock;
extern API_FlashHandlerTypeDef API_Flash;


extern UEvent_HandleTypedef gUEvent;
extern GUIMenu_HandleTypedef gUMenu;

/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void IdleTask(void);

/* Private variables ---------------------------------------------------------*/

/* Exported variables --------------------------------------------------------*/
Display_HandleTypeDef LCD1st;
Display_HandleTypeDef LCD2nd;
static uint8_t *ble_mac_addr;    /* Add volatile */


/* Exported functions --------------------------------------------------------*/

/**
 *******************************************************************************
 * @brief       
 * @details     
 * @return      
 * @exception   No
 * @note
 * @par         Example
 * @code
 * @endcode
 *******************************************************************************
 */
//void URT4_Receive_Write_Flash(void)
//{
//    uint32_t Addr;
//    uint16_t PageSize;

//    //
//    Length = FileSize;
//    MID_URT_Transmit(&mURT4, (uint8_t*) "Erasing...\n", 16, 1000);
//    Addr = AudioFlashAddr;
//    
//    // Erase when first program. (1 psge = 4 Kbytes)
//    if (Addr == AudioFlashAddr)
//    {
//        Addr = AudioFlashAddr;
//        PageSize = (Length/4096)+1;
//        API_Flash_Erase (Addr, PageSize);
//    }

//    //
//    MID_URT_Transmit(&mURT4, (uint8_t*) "Wait receive...\n", 16, 1000);
//    Length = FileSize;
//    Addr = AudioFlashAddr;

//    //
//    if (Length <= 512)
//    {
//        MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff0, Length);
//        while(mURT4.RxState != MID_URT_STATE_READY);
//        API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, Length);               // programming
//    }
//    else if (Length > 2024)
//    {
//        // first 512 bytes - receive 
//        MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff0, 512);
//        while(mURT4.RxState != MID_URT_STATE_READY);

//        // second 512 bytes - receive and program first 512 bytes
//        MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff1, 512);
//        API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, 512);                  // programming
//        Length -= 512;
//        Addr += 512;

//        while(Length >= (1024+512))
//        {
//            // wait for VoiceBuff1
//            while(mURT4.RxState != MID_URT_STATE_READY);
//            MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff0, 512);                    // receive VoiceBuff0
//            API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff1, 512);              // programming VoiceBuff1
//            Length -= 512;
//            Addr += 512;

//            while(mURT4.RxState != MID_URT_STATE_READY);
//            MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff1, 512);                    // receive VoiceBuff1
//            API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, 512);              // programming VoiceBuff0
//            Length -= 512;
//            Addr += 512;
//            
//        }

//        // the second to last
//        while(mURT4.RxState != MID_URT_STATE_READY);
//        if ((Length - 512) < 512)
//        {
//            MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff0, (Length - 512));         // receive VoiceBuff0 (The last)
//            API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff1, 512);              // programming VoiceBuff1
//            Length -= 512;
//            Addr += 512;
//            while(mURT4.RxState != MID_URT_STATE_READY);
//            API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, Length);              // programming VoiceBuff1
//        }
//        else if (Length != 512)
//        {
//            MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff0, (Length - 512));         // receive VoiceBuff0 (the second to last)
//            API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff1, 512);              // programming VoiceBuff1
//            while(mURT4.RxState != MID_URT_STATE_READY);
//            Length -= 512;
//            Addr += 512;
//            while(mURT4.RxState != MID_URT_STATE_READY);
//            API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, Length);              // programming VoiceBuff1
//        
//        }
//    }
//    else        // No certify
//    {
//        // first 512 bytes - receive 
//        MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff0, 512);
//        while(mURT4.RxState != MID_URT_STATE_READY);

//        // second 512 bytes - receive and program first 512 bytes
//        if (Length < 1024)
//            MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff1, (Length - 512));
//        else
//            MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff1, 512);                    // receive VoiceBuff0 (the second to last)
//        API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, 512);                  // programming
//        Length -= 512;
//        Addr += 512;

//        // third
//        while(mURT4.RxState != MID_URT_STATE_READY);
//        if (Length < 512)
//            MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff0, (Length - 512));
//        else 
//            MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff0, 512);                    // receive VoiceBuff0 (the second to last)
//        API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, 512);                  // programming
//        Length -= 512;
//        Addr += 512;

//        // 4th
//        while(mURT4.RxState != MID_URT_STATE_READY);
//        if (Length != 0)
//        {
//            MID_URT_Receive_IT(&mURT4, (uint8_t*) &VoiceBuff1, (Length - 512)); 
//            API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, 512);              // programming
//            Length -= 512;  
//            Addr += 512;    
//            while(mURT4.RxState != MID_URT_STATE_READY);    
//            API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, Length);           // programming
//        }
//        else
//        {
//            API_Flash_MultiBytesWrite (Addr, (uint8_t*) &VoiceBuff0, Length);           // programming            
//        }
//    }

//    // printf vioce data from flash by UART4
//    Length = FileSize;
//    Addr = AudioFlashAddr;
//    do
//    {
//        API_Flash_MultiBytesRead (Addr, (uint8_t*) &VoiceBuff0, 512);
//        MID_URT_Transmit(&mURT4, (uint8_t*) &VoiceBuff0, 512, 9000000);
//       
//        Addr += 512;
//        Length -= 512;
//    } while (Length > 512);
//    
//    // remain data
//    API_Flash_MultiBytesRead (Addr, (uint8_t*) &VoiceBuff0, Length);
//    MID_URT_Transmit(&mURT4, (uint8_t*) &VoiceBuff0, Length, 9000000);
//}



extern uint32_t const IdleTimeValue[];
extern __IO uint32_t gIdleCount;
extern __IO uint8_t gOldSelect;
extern __IO uint8_t gOldMenu;

/**
 *******************************************************************************
 * @brief       
 * @details     
 * @return      
 * @exception   No
 * @note
 * @par         
 * @code
 * @endcode
 *******************************************************************************
 */
void IdleTask(void)
{
    uint8_t lArrayU8[80];
    uint32_t lTemp32;

    if(gUEvent.SetIdleTime == 0)
    {
        gIdleCount = MID_GetTick();
        sprintf((char *)lArrayU8, "IDLE Time Disable             ");
        LCD_ShowStringX(&LCD2nd, 0,303, LCD2nd.Width, 16, GBLUE, BLACK, 16, ((__I uint8_t *)(&lArrayU8)));
        return;
    }

    lTemp32 = MID_GetTick();
    if(MID_GetTick() < gIdleCount)
        lTemp32 = lTemp32 + (0xFFFFFFFF - gIdleCount);
    else
        lTemp32 -= gIdleCount;

    sprintf((char *)lArrayU8, "IDLE Time %6dms  ", lTemp32);
    LCD_ShowStringX(&LCD2nd, 0,303, LCD2nd.Width, 16, GBLUE, BLACK, 16, ((__I uint8_t *)(&lArrayU8)));

    if(lTemp32 >= IdleTimeValue[gUEvent.SetIdleTime])
        sprintf((char *)lArrayU8, "IDLE");
    else
        sprintf((char *)lArrayU8, "Busy");

    LCD_ShowStringX(&LCD2nd, 200, 303, LCD2nd.Width, 16, GBLUE, BLACK, 16, ((__I uint8_t *)(&lArrayU8)));

    if(lTemp32 >= IdleTimeValue[gUEvent.SetIdleTime])
    {
        gOldMenu = 6;
        gOldSelect = 1;
        API_ARGB_UpdateTrigger(ARGB_DRAMA_DISABLE);
        API_ARGB_main();
        AutoDemo(&gUMenu, &gUEvent);
    }
}

/**
 *******************************************************************************
 * @brief       
 * @details     
 * @return      
 * @exception   No
 * @note
 * @par         
 * @code
 * @endcode
 *******************************************************************************
 */
//=============================================================================
int main(void)
{
    __IO uint32_t lTempU32;
         uint8_t  lArrayU8[80];

    // ------------------------------------------------------------------------
    // chip initial (User can enable CSC, GPIO, TM, ADC, EXIC ... wizard)
    // ------------------------------------------------------------------------
    UnProtectModuleReg(MEMprotect);
    MEM->CR0.MBIT.FWAIT  = 1;
    MEM->CR0.MBIT.HSP_EN = 1;
    ProtectModuleReg(MEMprotect);
    
    ChipInit();
    SystemCoreClockUpdate();

    BSP_Init();

    SPI_LCD_Reset(0);  // LCD Reset use H/W Reset Pin
    MID_Delay(50);

    LCD1st.HWIF = 0;
    LCD1st.Reset         = I80_LCD_Reset;
    LCD1st.BackLight     = I80_LCD_BackLight;
    LCD1st.DataReverse   = I80_LCD_DataReverse;
    LCD1st.SelectReg     = I80_LCD_SelectRegister;
    LCD1st.WriteData     = I80_LCD_WriteData;
    LCD1st.WriteData8    = I80_LCD_WriteData8;
    LCD1st.ReadData      = I80_LCD_ReadData;
    LCD1st.WriteRegister = I80_LCD_WriteRegister;
    LCD1st.PointColor    = WHITE;
    LCD1st.BackColor     = BLACK;
    LCD_Init(&LCD1st);

    LCD2nd.HWIF = 1;
    LCD2nd.Reset         = SPI_LCD_Reset;
    LCD2nd.BackLight     = SPI_LCD_BackLight;
    LCD2nd.DataReverse   = SPI_LCD_DataReverse;
    LCD2nd.SelectReg     = SPI_LCD_SelectRegister;
    LCD2nd.WriteData     = SPI_LCD_WriteData;
    LCD2nd.WriteData8    = SPI_LCD_WriteData8;
    LCD2nd.ReadData      = SPI_LCD_ReadData;
    LCD2nd.WriteRegister = SPI_LCD_WriteRegister;
    LCD2nd.PointColor    = WHITE;
    LCD2nd.BackColor     = BLACK;
    LCD_Init(&LCD2nd);

    /*=== API flash access ===*/
    /* Initial SPI0 */
    API_Flash_Init();

    UserEvent_Initial();

    API_ARGB_Init();
    API_ADC_Init();                 // for Serial/Parallel key and LM35DZ (temperature)
    API_DS1621_Init();              // for sampling DS1621 (temperature) by I2C
    API_DACOutput_Init();           // mono audio output 
    API_DAC_Output.AudioVolume = 3;
    API_DAC_Output.SongsSelect = 1;

    API_RGBLED_Init();

    USB_Audio_Inital();
    USB_Inital();

    // IWDT 
    BSP_IWDT_Init();

    // BLE Initial
    SetBleIntRunningMode();
    radio_initBle(TXPWR_0DBM, &ble_mac_addr);
    ble_run_interrupt_start(160*2); //320*0.625=200 ms

    // URT4 receive voice data to program to flash IC. (stereo 8KHz ~ 20 seconds)
    //URT4_Init();
    //URT4_Receive_Write_Flash();

    sprintf((char *)lArrayU8, "%dKHz", SystemCoreClock / 1000);//?LCD ID???lcd_id??
    LCD_ShowStringX(&LCD2nd, 0, 0, LCD2nd.Width, 16, GBLUE, BLACK, 16, ((__I uint8_t *)(&lArrayU8)));

    sprintf((char *)lArrayU8, "BLE Ready");
    LCD_ShowString(&LCD2nd, 0, 60, LCD2nd.Width, 16, WHITE, 16, ((uint8_t *)(&lArrayU8)));

    // Check flash ID
    lTempU32 = API_Flash_GetID();
    if((lTempU32 != MX25R512) && (lTempU32 != MX25R6435) && (lTempU32 != S25FL256LAVF01))
    {
        LCD_ShowString(&LCD2nd, 0, 76, LCD2nd.Width, 16, WHITE, 16, (uint8_t *)"SPI Filsh Not Ready");
    }
    else
    {
        sprintf((char *)lArrayU8, "SPI Flash ID:%X", lTempU32);
        LCD_ShowString(&LCD2nd, 0, 76, LCD2nd.Width, 16, WHITE, 16, ((uint8_t *)(&lArrayU8)));

        if(API_Flsh_QuadEnable_Cmd(ENABLE) != MID_SUCCESS)
        {
            while(1){__NOP();}
        }
    }

    sprintf((char *)lArrayU8, "LCD1st ID:%04X",LCD1st.ID);//?LCD ID???lcd_id??
    LCD_ShowString(&LCD2nd, 0, 92, LCD2nd.Width, 16, GBLUE, 16, ((uint8_t *)(&lArrayU8)));
    sprintf((char *)lArrayU8, "Resolution %d x %d", LCD1st.Width, LCD1st.Height);//?LCD ID???lcd_id??
    LCD_ShowString(&LCD2nd, 0, 108, LCD2nd.Width, 16, YELLOW, 16, ((uint8_t *)(&lArrayU8)));
    sprintf((char *)lArrayU8, "LCD2nd ID:%04X",LCD2nd.ID);//?LCD ID???lcd_id??
    LCD_ShowString(&LCD2nd, 0, 124, LCD2nd.Width, 16, GBLUE, 16, ((uint8_t *)(&lArrayU8)));
    sprintf((char *)lArrayU8, "Resolution %d x %d", LCD2nd.Width, LCD2nd.Height);//?LCD ID???lcd_id??
    LCD_ShowString(&LCD2nd, 0, 140, LCD2nd.Width, 16, YELLOW, 16, ((uint8_t *)(&lArrayU8)));

    LCD_ShowString(&LCD2nd, 0, 156, LCD2nd.Width, 16, GREEN, 16, (uint8_t *)"Initial Ready");

    printf("%c[2J",27);
    printf("%c[H",27);
    printf("  Initial Ready\n\r");

    while(1)
    {
        // IrqMcuGotoSleepAndWakeup();
        if(ble_run_interrupt_McuCanSleep())
        {
            //mcu lowpower
        }

        API_ADC_GetSerialKey();
        API_ADC_GetParallelKey();
        UserEvent_Decode(&gUEvent);

        API_ARGB_main();

        sprintf((char *)lArrayU8, "Menu %2d, %2d, %2d", gUEvent.Menu, gUEvent.Option, gUEvent.Select);//?LCD ID???lcd_id??
        LCD_ShowStringX(&LCD2nd, 0, 204, LCD2nd.Width, 16, GBLUE, BLACK, 16, ((__I uint8_t *)(&lArrayU8)));

//        sprintf((char *)lArrayU8, "LED %2d, %2d, %2d", gUEvent.LEDPWMSpeed, gUEvent.LEDBreathingSpeed, gUEvent.LEDBLinkingSpeed);
//        LCD_ShowStringX(&LCD2nd, 0, 220, LCD2nd.Width, 16, GBLUE, BLACK, 16, ((__I uint8_t *)(&lArrayU8)));

//        sprintf((char *)lArrayU8, "LCD %3d", gUEvent.LCDPicture);
//        LCD_ShowStringX(&LCD2nd, 0, 236, LCD2nd.Width, 16, GBLUE, BLACK, 16, ((__I uint8_t *)(&lArrayU8)));

//        sprintf((char *)lArrayU8, "Sound %2d, %2d, %2d", gUEvent.SoundSelect, gUEvent.SoundPlayStop, gUEvent.SoundVolume);
//        LCD_ShowStringX(&LCD2nd, 0, 252, LCD2nd.Width, 16, GBLUE, BLACK, 16, ((__I uint8_t *)(&lArrayU8)));

//        sprintf((char *)lArrayU8, "Set %2d, %2d, %2d, %2d", gUEvent.SetIdleTime, gUEvent.SetBLE, gUEvent.SetWIFI, gUEvent.SetUpdate);
//        LCD_ShowStringX(&LCD2nd, 0, 268, LCD2nd.Width, 16, GBLUE, BLACK, 16, ((__I uint8_t *)(&lArrayU8)));

        //sprintf((char *)lArrayU8, "Play %2d",gUEvent.SoundPlay);//?LCD ID???lcd_id??
        //LCD_ShowStringX(&LCD2nd, 120, 271, LCD2nd.Width, 24, GBLUE, BLACK, 24, ((__I uint8_t *)(&lArrayU8)));
        //sprintf((char *)lArrayU8, "Volume %2d",gUEvent.SoundVolume);//?LCD ID???lcd_id??
        //LCD_ShowStringX(&LCD2nd, 120, 247, LCD2nd.Width, 24, GBLUE, BLACK, 24, ((__I uint8_t *)(&lArrayU8)));

        //sprintf((char *)lArrayU8, "IDLE %2d",gUEvent.SetIdleTime);//?LCD ID???lcd_id??
        //LCD_ShowStringX(&LCD2nd, 0, 295, LCD2nd.Width, 24, GBLUE, BLACK, 24, ((__I uint8_t *)(&lArrayU8)));
        //sprintf((char *)lArrayU8, "BLE %2d",gUEvent.SetBLE);//?LCD ID???lcd_id??
        //LCD_ShowStringX(&LCD2nd, 120, 295, LCD2nd.Width, 24, GBLUE, BLACK, 24, ((__I uint8_t *)(&lArrayU8)));

        LCD_1st_Show();

        IdleTask();
    }
}




