/*!
 * @file        main.c
 *
 * @brief       Main program body
 *
 * @version     V1.0.0
 *
 * @date        2026-02-25
 *
 * @attention
 *
 *  Copyright (C) 2026 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the Geehy Semiconductor Software License Agreement for the governing permissions
 *  and limitations under the License.
 */

/* Includes */
#include "main.h"
#include "Board.h"
#include "stdio.h"
#include "string.h"
#include "g32a10xx_gpio.h"
#include "g32a10xx_misc.h"
#include "g32a10xx_eint.h"
#include "g32a10xx_dma.h"
#include "g32a10xx_syscfg.h"

/** @addtogroup Examples
  @{
  */

/** @addtogroup DMA_Examples
  @{
  */

/** @addtogroup DMA_MemoryToMemory
  @{
  */

/** @defgroup DMA_MemoryToMemory_Macros Macros
  @{
  */

#define BUF_SIZE     (32U)
/* printf function configs to USART1 */
#define DEBUG_USART  USART1

/**@} end of group DMA_MemoryToMemory_Macros*/

/** @defgroup DMA_MemoryToMemory_Variables Variables
  @{
  */

static const uint32_t g_srcBuf[BUF_SIZE] =
{
    0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10,
    0x11121314, 0x15161718, 0x191A1B1C, 0x1D1E1F20,
    0x21222324, 0x25262728, 0x292A2B2C, 0x2D2E2F30,
    0x31323334, 0x35363738, 0x393A3B3C, 0x3D3E3F40,
    0x41424344, 0x45464748, 0x494A4B4C, 0x4D4E4F50,
    0x51525354, 0x55565758, 0x595A5B5C, 0x5D5E5F60,
    0x61626364, 0x65666768, 0x696A6B6C, 0x6D6E6F70,
    0x71727374, 0x75767778, 0x797A7B7C, 0x7D7E7F80
};

static uint32_t g_desBuf[BUF_SIZE] = {0U};
volatile uint32_t g_currDataCounterEnd = 1U;

/**@} end of group DMA_MemoryToMemory_Variables */

/** @defgroup DMA_MemoryToMemory_Functions Functions
  @{
  */

/*!
 * @brief       Main program
 *
 * @param       None
 *
 * @retval      None
 *
 */
int main(void)
{
    Dma_ConfigType    damConfigStruct = {0U};
    uint32_t overTime = 0xFFFFFU;
    uint32_t i = 0U;

    /* COM1 init*/
    Board_ComInit(COM1);

    Board_LedInit(LED2);
    Board_LedInit(LED3);
    Board_LedOff(LED2);
    Board_LedOff(LED3);

    Rcm_Configuration();
    Nvic_Configuration();

    Dma_Reset(DMA1_CHANNEL_1);

    damConfigStruct.peripheralAddress = (uint32_t)g_srcBuf;
    damConfigStruct.memoryAddress = (uint32_t)g_desBuf;
    damConfigStruct.direction = DMA_DIR_PERIPHERAL;
    damConfigStruct.bufferSize = BUF_SIZE;
    damConfigStruct.peripheralInc = DMA_PERIPHERAL_INC_ENABLE;
    damConfigStruct.memoryInc = DMA_MEMORY_INC_ENABLE;
    damConfigStruct.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_WORD;
    damConfigStruct.memoryDataSize = DMA_MEMORY_DATASIZE_WORD;
    damConfigStruct.circular = DMA_CIRCULAR_DISABLE;
    damConfigStruct.priority = DMA_PRIORITY_LEVEL_HIGHT;
    damConfigStruct.memoryTomemory = DMA_M2M_ENABLE;

    Dma_Config(DMA1_CHANNEL_1, &damConfigStruct);
    Dma_EnableInterrupt(DMA1_CHANNEL_1, (uint32_t)DMA_INT_TFIE);
    Dma_Enable(DMA1_CHANNEL_1);

    while ((1U == g_currDataCounterEnd) && (overTime > 0U))
    {
        overTime -= 1U;
    }

    printf("Destination address data:\r\n");
    for(i = 0U; i < BUF_SIZE; i++)
    {
        printf("0x%08x\r\n", (unsigned int)g_desBuf[i]);
    }

    if ((uint8_t)PASSED == Dma_Buffercmp(g_srcBuf, g_desBuf, BUF_SIZE))
    {
        Board_LedOn(LED2);
        printf("Memory to memory successfully\r\n");
    }
    else
    {
        Board_LedOn(LED3);
        printf("Memory to memory failed\r\n");
    }

    memset(g_desBuf, 0, sizeof(g_desBuf));

    while (1)
    {
    }
}

/*!
 * @brief       Configures the different system clocks
 *
 * @param       None
 *
 * @retval      None
 *
 */
void Rcm_Configuration(void)
{
    Rcm_EnableAhbPeriphClock(RCM_AHB_PERIPH_DMA1);
}
/*!
 * @brief       Configure the nested vectored interrupt controller
 *
 * @param       None
 *
 * @retval      None
 *
 */
void Nvic_Configuration(void)
{
    Nvic_EnableIrqRequest(DMA_CH1_IRQn, 0U);
}

/*!
 * @brief       Compares two buffers
 *
 * @param       BufferPtr: The buffer pointer
 *
 * @param       BufferPtr1: The buffer pointer
 *
 * @param       BufferLength: The buffer pointer
 * 
 * @retval      PASSED: pBuffer identical to pBuffer1. FAILED: pBuffer differs from pBuffer1
 *
 */
uint8_t Dma_Buffercmp(const uint32_t* BufferPtr, const uint32_t* BufferPtr1, uint16_t BufferLength)
{
    uint8_t cmpRes = (uint8_t)PASSED;
    uint32_t index = 0U;
    uint16_t bufLen = BufferLength;

    while (bufLen > 0U)
    {
        if (BufferPtr[index] != BufferPtr1[index])
        {
            cmpRes = FAILED;
            break;
        }
        else
        {
            /* do nothing */
        }

        index += 1U;
        bufLen -= 1U;
    }

    return cmpRes;
}


#if defined (__CC_ARM) || defined (__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))

/*!
* @brief       Redirect C Library function printf to serial port.
*              After Redirection, you can use printf function.
*
* @param       ch:  The characters that need to be send.
*
* @param       *f:  pointer to a FILE that can recording all information
*              needed to control a stream
*
* @retval      The characters that need to be send.
*
* @note
*/
int fputc(int ch, FILE* f)
{
    /* send a byte of data to the serial port */
    Usart_TxData(DEBUG_USART, (uint8_t)ch);

    /* wait for the data to be send  */
    while (Usart_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == (uint8_t)RESET)
    {
        /* do nothing */
    }

    return (ch);
}

#elif defined (__GNUC__)

/*!
* @brief       Redirect C Library function printf to serial port.
*              After Redirection, you can use printf function.
*
* @param       ch:  The characters that need to be send.
*
* @retval      The characters that need to be send.
*
* @note
*/
int __io_putchar(int ch)
{
    /* send a byte of data to the serial port */
    Usart_TxData(DEBUG_USART, ch);

    /* wait for the data to be send  */
    while (Usart_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

    return ch;
}

/*!
* @brief       Redirect C Library function printf to serial port.
*              After Redirection, you can use printf function.
*
* @param       file:  Meaningless in this function.
*
* @param       *ptr:  Buffer pointer for data to be sent.
*
* @param       len:  Length of data to be sent.
*
* @retval      The characters that need to be send.
*
* @note
*/
int _write(int file, char* ptr, int len)
{
    int i;
    for (i = 0; i < len; i++)
    {
        __io_putchar(*ptr++);
    }

    return len;
}

#else
#pragma message("Not supported compiler type")
#endif

/**@} end of group DMA_MemoryToMemory_Functions */
/**@} end of group DMA_MemoryToMemory */
/**@} end of group DMA_Examples */
/**@} end of group Examples */
