/*!
 * @file        common.c
 *
 * @brief       Include data convert and read and write operation to HyperTerminal
 *
 * @version     V1.0.0
 *
 * @date        2026-02-26
 *
 * @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 "common.h"

/** @addtogroup Examples
  @{
  */

/** @addtogroup IAP_Examples
  @{
*/

/** @addtogroup IAP_BootLoader
  @{
  */

/** @defgroup IAP_BootLoader_Functions Functions
  @{
*/

/*!
 * @brief       Integer number convert to string
 *
 * @param       StrPtr: string buffer
 *
 * @param       Conint: specific interger number
 *
 * @retval      None
 *
 * @note
 */
void Iap_IntConStr(uint8_t* StrPtr, uint32_t Conint)
{
    uint32_t i = 0U;
    uint32_t j = 0U;
    uint32_t div = 1000000000U;
    uint32_t convStatus = 0U;
    uint32_t conintTemp = Conint;

    do
    {
        StrPtr[j] = (uint8_t)((conintTemp / div) + 48U);
        j += 1U;

        conintTemp = conintTemp % div;
        div /= 10U;

        if ((StrPtr[j - 1U] == (uint8_t)'0') && (convStatus == 0U))
        {
            j = 0;
        }
        else
        {
            convStatus++;
        }

        i++;
    }
    while (i < 10U);
}

/*!
 * @brief       string convert to an integer number
 *
 * @param       HexstrPtr: hex string type data
 *
 * @param       ConintPtr: specific interger number
 *
 * @retval      SUCCESS
 *              ERROR
 * @note
 */
uint32_t Iap_StrHexConInt(const uint8_t* HexstrPtr, int32_t* ConintPtr)
{
    uint32_t i = 0U;
    uint32_t res = (uint32_t)ERROR;
    uint32_t val = 0U;
    uint32_t conHex = 0U;
    uint8_t breakCheck = 0U;

    if ((HexstrPtr[2U] != (uint8_t)'\0'))
    {
        i = 2U;

        do
        {
            if (HexstrPtr[i] == (uint8_t)'\0')
            {
                *ConintPtr = (int32_t)val;
                res = (uint32_t)SUCCESS;
                breakCheck = 1U;
            }
            else
            {
                /* do nothing */
            }

            if(0U == breakCheck)
            {
                if (CHECK_HEX(HexstrPtr[i]))
                {
                    conHex = (uint32_t)CON_HEX(HexstrPtr[i]);
                    val = (val << 4U) + conHex;
                }
                else
                {
                    res = (uint32_t)ERROR;
                    breakCheck = 1U;
                }
            }
            else
            {
                /* do nothing */
            }

            if(1U == breakCheck)
            {
                break;
            }
            else
            {
                /* do nothing */
            }
            
            i++;
        }
        while (i < 11U);

        /* over 8 digit hex */
        if (i >= 11U)
        {
            res = (uint32_t)ERROR;
        }
        else
        {
            /* do nothing */
        }

    }
    else
    {
        res = (uint32_t)ERROR;
    }

    return res;
}

/*!
 * @brief       decimal string convert to an integer
 *
 * @param       DecstrPtr: dec string buffer
 *
 * @param       ConintPtr: specific interger number
 *
 * @retval      SUCCESS
 *              ERROR
 * @note
 */
static uint32_t Str_Dec_ConInt(const uint8_t* DecstrPtr, int32_t* ConintPtr)
{
    uint32_t i = 0U;
    uint32_t res = (uint32_t)ERROR;
    uint32_t val = 0U;
    uint8_t breakCheck = 0U;

    i = 0U;
    do
    {
        if (DecstrPtr[i] == (uint8_t)'\0')
        {
            *ConintPtr = (int32_t)val;
            res = (uint32_t)SUCCESS;
            breakCheck = 1U;
        }
        else if (((DecstrPtr[i] == (uint8_t)'k') || (DecstrPtr[i] == (uint8_t)'K')) && (i > 0U))
        {
            val = val << 10U;
            *ConintPtr = (int32_t)val;
            res = (uint32_t)SUCCESS;
            breakCheck = 1U;
        }
        else if (((DecstrPtr[i] == (uint8_t)'m') || (DecstrPtr[i] == (uint8_t)'M')) && (i > 0U))
        {
            val = val << 20U;
            *ConintPtr = (int32_t)val;
            res = (uint32_t)SUCCESS;
            breakCheck = 1U;
        }
        else if (CHECK_DEC(DecstrPtr[i]))
        {
            val = (val * 10U) + (uint32_t)CON_DEC(DecstrPtr[i]);
        }
        else
        {
            res = (uint32_t)ERROR;
            breakCheck = 1U;
        }

        if(1U == breakCheck)
        {
            break;
        }
        else
        {
            /* do nothing */
        }

        i++;
    }
    while (i < 11U);

    /* Over 10 digit decimal */
    if (i >= 11U)
    {
        res = (uint32_t)ERROR;
    }
    else
    {
        /* do nothing */
    }

    return res;
}

/*!
 * @brief       string type convert to integer type
 *
 * @param       StrPtr: string buffer
 *
 * @param       ConintPtr: specific interger number
 *
 * @retval      SUCCESS
 *              ERROR
 * @note
 */
uint32_t Iap_StrConInt(const uint8_t* StrPtr, int32_t* ConintPtr)
{
    uint32_t res = (uint32_t)ERROR;

    if ((StrPtr[0U] == (uint8_t)'0') && ((StrPtr[1U] == (uint8_t)'x') || (StrPtr[1U] == (uint8_t)'X')))
    {
        res = Iap_StrHexConInt(StrPtr, ConintPtr);
    }
    else
    {
        res = Str_Dec_ConInt(StrPtr, ConintPtr);
    }

    return res;
}

/*!
 * @brief       Get a key from the HyperTerminal
 *
 * @param       InputKeyPtr: User input key pressed
 *
 * @retval      SUCCESS
 *              ERROR
 * @note
 */
uint32_t Iap_GetKeyPressed(uint8_t* InputKeyPtr)
{
    uint32_t res = (uint32_t)ERROR;

    if (USART_COM_RXREADY)
    {
        *InputKeyPtr = (uint8_t)USART_COM_RXDATA;
        res = (uint32_t)SUCCESS;
    }
    else
    {
        /* do nothing */
    }

    return res;
}

/*!
 * @brief       Read a key from the HyperTerminal
 *
 * @param       None
 *
 * @retval      The input key pressed
 *
 * @note
 */
uint8_t Iap_ReadKey(void)
{
    uint8_t inputKey = 0U;

    /* Waiting for user input */
    while (1U)
    {
        if (Iap_GetKeyPressed((uint8_t*) & inputKey) == (uint32_t)SUCCESS)
        {
            break;
        }
        else
        {
            /* do nothing */
        }
    }

    return inputKey;

}

/*!
 * @brief       Read a key from the HyperTerminal
 *
 * @param       DelayTimeOut:read input key timeout
 *
 * @retval      The input key pressed
 *
 * @note
 */
uint8_t Iap_ReadKeyTimeOut(uint32_t DelayTimeOut)
{
    uint8_t inputKey = 0xFF;
    volatile uint32_t delayTime = DelayTimeOut;
    uint32_t keyVal = 0U;
    uint8_t breakCheck = 0U;

    /* Waiting for user input */
    while (1U)
    {
        keyVal = Iap_GetKeyPressed((uint8_t*) & inputKey);

        if (keyVal== (uint32_t)SUCCESS)
        {
            breakCheck = 1U;
        }
        else
        {
            /* do nothing */
        }
        
		if(0U == breakCheck)
		{
			if (delayTime < 10U)
            {
                breakCheck = 1U;
            }
            else
            {
                /* do nothing */
            }
		}
        else
        {
            /* do nothing */
        }

        if(1U == breakCheck)
        {
            break;
        }
        else
        {
            /* do nothing */
        }

        delayTime -= 1U;
    }

    return inputKey;
}
/*!
 * @brief       Send a character on the HyperTerminal
 *
 * @param       Character: The character need to be sent
 *
 * @retval      None
 *
 * @note
 */
void Iap_SendChar(uint8_t Character)
{
    USART_COM_TXDATA(Character);

    while (USART_COM_TXFINISH)
    {
        /* do nothing */
    }
}

/*!
 * @brief       Send a string on the HyperTerminal
 *
 * @param       StrPtr: The string need to be sent
 *
 * @retval      None
 *
 * @note
 */
void Iap_SerialSendString(const uint8_t* StrPtr)
{
    const uint8_t * strTempPtr = StrPtr;

    while (*strTempPtr != (uint8_t)'\0')
    {
        Iap_SendChar(*strTempPtr);
        strTempPtr++;
    }
}

/**@} end of group IAP_BootLoader_Functions */
/**@} end of group IAP_BootLoader */
/**@} end of group IAP_Examples */
/**@} end of group Examples */
