/*******************************************************************************
* @file             main.c
*
* @version          1.0.0
*
* @brief            Integration Framework -  main function
*
* 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.
*
*******************************************************************************/

#ifdef __cplusplus
extern "C"{
#endif


#include <string.h>
#include "CDD_Usart.h"
#include "Mcu.h"
#include "Port.h"
#include "Crypto.h"
#include "Crypto_App.h"
#include "modules.h"
#include "CDD_Pdl.h"
#include "g32a1085.h"


/***************************************************************************
                        GLOBAL VARIABLES                                    
***************************************************************************/ 
/* AES-128, the key must be 128 bits (16 bytes) */
CONST(uint8, AUTOMATIC) AES128Key[16] = {0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36,
                          0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38};

VAR(uint8, AUTOMATIC) AES192key[24] = {0x9A, 0xBC, 0xDE, 0xF0, 0x9A, 0xBC, 0xDE, 0xF0,
                         0x9A, 0xBC, 0xDE, 0xF0, 0x9A, 0xBC, 0xDE, 0xF0,
                         0x9A, 0xBC, 0xDE, 0xF0, 0x9A, 0xBC, 0xDE, 0xF0
                        };

VAR(uint8, AUTOMATIC) AES256key[32] = {0x9A, 0xBC, 0xDE, 0xF0, 0x9A, 0xBC, 0xDE, 0xF0,
                        0x9A, 0xBC, 0xDE, 0xF0, 0x9A, 0xBC, 0xDE, 0xF0,
                        0x9A, 0xBC, 0xDE, 0xF0, 0x9A, 0xBC, 0xDE, 0xF0,
                        0x9A, 0xBC, 0xDE, 0xF0, 0x9A, 0xBC, 0xDE, 0xF0
                       };

VAR(uint8, AUTOMATIC) AES256key_Initial[32] = {0x00};
/* initialization vector for CBC mode */
VAR(uint8, AUTOMATIC) IV_1[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
                   };

/* user data */
VAR(uint8, AUTOMATIC) unencryptedData[16] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
    0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
/* encrypted data */
VAR(uint8, AUTOMATIC) encryptedData[16] = {0xDB, 0x30, 0x2D, 0xD6, 0x80, 0x36, 0xC0, 0x50,
                                 0xAC, 0x76, 0xA1, 0xE8, 0x39, 0x75, 0x75, 0x85};
VAR(uint8, AUTOMATIC) encryptedData_192[16] = {0xB1, 0x24, 0x25, 0x08, 0x5F, 0xDF, 0x2B, 0xEF,
                                 0x63, 0x5C, 0x67, 0x31, 0x11, 0x9F, 0x02, 0xC8};

VAR(uint8, AUTOMATIC) Sha256InputData[56] ={"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};

/*******************************************************************************
                            LOCAL DEFINES AND MACROS
*******************************************************************************/

/** DMA transfer of AES-ECB ciphertext (see RunDmaCryptoCipherDemo). */
#define  TEST_DMA_CRYPTO_CIPHER
#define DMA_AES_BLK   16U

/**************************************************************************
                    GLOBAL & LOCAL FUNCTION
**************************************************************************/


FUNC(void, CRYPTO_CODE) delay(uint32 value)
{
    while(value--);
}
/*!
 * @brief       configure encryption tasks
 *
 * @param       Job:             the job ptr
 *              TestJob:         job task
 *              CryptoKeyId:     Crypto Key Id
 *              InputPtr:        Input value Ptr
 *              InputLength:     Input value Length
 *              OutputPtr:       Output value Ptr
 *              OutputLengthPtr: Output value Length Ptr
 *              ProcessingType:  processing type
 *
 * @retval      None
 *
 * @note        Note
 */

void PrepareJob(Crypto_JobType* Job,
                CryptoTestJobType TestJob,
                uint32 CryptoKeyId,
                uint32 KeyElementId,
                const uint8* InputPtr,
                uint32 InputLength,
                uint8* OutputPtr,
                uint32* OutputLengthPtr,
                Crypto_ProcessingType ProcessingType)
{
    Job->cryptoKeyId = CryptoKeyId;
    Job->KeyElementId = KeyElementId;
    Job->jobPrimitiveInputOutput.inputPtr = InputPtr;
    Job->jobPrimitiveInputOutput.inputLength = InputLength;
    Job->jobPrimitiveInputOutput.outputPtr = OutputPtr;
    Job->jobPrimitiveInputOutput.outputLengthPtr = OutputLengthPtr;

    Crypto_PrimitiveInfoType* primInfo = NULL_PTR;
    switch (TestJob)
    {
    case TEST_ENCRYPT_AES_ECB:
        primInfo = &g_primAesEcbEncrypt;
        break;
    case TEST_DECRYPT_AES_ECB:
        primInfo = &g_primAesEcbDecrypt;
        break;
    case TEST_ENCRYPT_AES_CBC:
        primInfo = &g_primAesCbcEncrypt;
        break;
    case TEST_DECRYPT_AES_CBC:
        primInfo = &g_primAesCbcDecrypt;
        break;
    case TEST_ENCRYPT_AES_CTR:
        primInfo = &g_primAesCtrEncrypt;
        break;
    case TEST_DECRYPT_AES_CTR:
        primInfo = &g_primAesCtrDecrypt;
                break;  
    case TEST_RANDOM_GENERATE:
        primInfo = &g_primRandom;
        break;
    case TEST_CMAC_GENERATE:
        primInfo = &g_primGenerateCmac;
        break;
    case TEST_CMAC_VERIFY:
        primInfo = &g_primVerifyCmac;
        break;
    case TEST_HASH_GENERATE:
        primInfo = &g_primHash;
    break;
    case TEST_MPC_GENERATE:
        primInfo = &g_primMpc;
        break;
    default:
        printf("Error: Not supported test job %d\r\n", TestJob);
        break;
    }

    if (ProcessingType == CRYPTO_PROCESSING_SYNC)
    {
        g_jobPrimSync.primitiveInfo = primInfo;
        Job->jobPrimitiveInfo = &g_jobPrimSync;
    }
    else
    {
        g_jobPrimAsync.primitiveInfo = primInfo;
        Job->jobPrimitiveInfo = &g_jobPrimAsync;
    }
}

/*!
 * @brief       Test prepare job
 *
 * @param       TestJob:         job task
 *              CryptoKeyId:     Crypto Key Id
 *              InputPtr:        Input value Ptr
 *              InputLength:     Input value Length
 *              OutputPtr:       Output value Ptr
 *              OutputLengthPtr: Output value Length Ptr
 *              ProcessingType:  processing type
 *
 * @retval      None
 *
 * @note        Note
 */
Crypto_JobType* PrepareTestJob(CryptoTestJobType TestJob,
                               uint32 CryptoKeyId,
                               uint32 KeyElementId,
                               const uint8* InputPtr,
                               uint32 InputLength,
                               uint8* OutputPtr,
                               uint32* OutputLengthPtr,
                               Crypto_ProcessingType ProcessingType)
{
    PrepareJob(&g_cryptoJob1, TestJob, CryptoKeyId, KeyElementId,InputPtr, InputLength,
               OutputPtr, OutputLengthPtr, ProcessingType);
    return &g_cryptoJob1;
}

#if (PDL_MODULE_ENABLE == STD_ON)
static volatile uint8_t s_dmaCryptoCh1Done;

void Dma_Channel1CompletionNotificaiton(void)
{
    s_dmaCryptoCh1Done = 1U;
}

/*!
 * @brief AES-ECB encrypt one block, copy ciphertext by DMA CH1 (memory-to-memory), then decrypt and verify.
 * @note  Follows Pdl_Dma_MemoryToMemory (PDL DMA) and IntegrationAppCrypto (Crypto stack) usage.
 */
static void RunDmaCryptoCipherDemo(void)
{
    VAR(uint8, AUTOMATIC) plainRef[DMA_AES_BLK];
    VAR(uint8, AUTOMATIC) plainOut[DMA_AES_BLK];
    VAR(uint8, AUTOMATIC) cipherHw[DMA_AES_BLK];
    VAR(uint8, AUTOMATIC) cipherDma[DMA_AES_BLK];
    VAR(uint32, AUTOMATIC) cipherLen = DMA_AES_BLK;
    VAR(uint32, AUTOMATIC) decLen = DMA_AES_BLK;
    VAR(uint32, AUTOMATIC) wait;
    P2VAR(Crypto_JobType, AUTOMATIC, CRYPTO_APPL_DATA) dmaJob = NULL_PTR;
    Pdl_DmaChHwConfigType dmaCfg;
    VAR(uint32, AUTOMATIC) k;

    printf("\r\n********************* DMA + AES-ECB ciphertext *************************\r\n");

    for (k = 0U; k < DMA_AES_BLK; k++)
    {
        plainRef[k] = (uint8)k;
    }

    Crypto_KeyElementSet(CRYPTO_KEY_1,
                         CRYPTO_KEYMATERIAL_256,
                         AES256key,
                         sizeof(AES256key));
    Crypto_KeyElementSet(CRYPTO_KEY_1,
                         CRYPTO_KEYMATERIAL_192,
                         AES192key,
                         sizeof(AES192key));
    Crypto_KeyElementSet(CRYPTO_KEY_1,
                         CRYPTO_KEYMATERIAL_128,
                         AES128Key,
                         sizeof(AES128Key));
    Crypto_KeySetValid(CRYPTO_KEY_1);

    dmaJob = PrepareTestJob(TEST_ENCRYPT_AES_ECB,
                            CRYPTO_KEY_1,
                            1U,
                            plainRef,
                            DMA_AES_BLK,
                            cipherHw,
                            &cipherLen,
                            CRYPTO_PROCESSING_SYNC);
    (void)Crypto_ProcessJob(CRYPTO_DRIVEROBJECT_WITHQUEUE, dmaJob);

    (void)memset(cipherDma, 0, sizeof(cipherDma));
    s_dmaCryptoCh1Done = 0U;

    NVIC_SetPriority(DMA_CH1_IRQn, 0x0FU);
    NVIC_EnableIRQ(DMA_CH1_IRQn);

    dmaCfg.periphAddr = (uint32)cipherDma;
    dmaCfg.memAddr = (uint32)cipherHw;
    dmaCfg.dir = DMA_DIR_MEMORY;
    dmaCfg.bufSize = DMA_AES_BLK;
    dmaCfg.periphInc = DMA_PERIPHERAL_INC_ENABLE;
    dmaCfg.memInc = DMA_MEMORY_INC_ENABLE;
    dmaCfg.periphDataWidth = DMA_PERIPHERAL_DATASIZE_BYTE;
    dmaCfg.memDataWidth = DMA_MEMORY_DATASIZE_BYTE;
    dmaCfg.circularMode = DMA_CIRCULAR_DISABLE;
    dmaCfg.priority = DMA_PRIORITY_LEVEL_VERYHIGH;
    dmaCfg.mem2Mem = DMA_M2M_ENABLE;

    Pdl_TopDmaChConfig(DMA_HW_CH1, &dmaCfg);
    Pdl_TopDmaChEn(DMA_HW_CH1);

    wait = 1000000U;
    while ((0U == s_dmaCryptoCh1Done) && (wait > 0U))
    {
        wait--;
    }

    if ((1U == s_dmaCryptoCh1Done) && (0 == memcmp(cipherHw, cipherDma, DMA_AES_BLK)))
    {
        printf("DMA Trans of AES ciphertext: OK\r\n");
    }
    else
    {
        printf("DMA M2M copy of AES ciphertext: FAIL (tc=%u)\r\n", s_dmaCryptoCh1Done);
    }

    decLen = DMA_AES_BLK;
    dmaJob = PrepareTestJob(TEST_DECRYPT_AES_ECB,
                            CRYPTO_KEY_1,
                            1U,
                            cipherDma,
                            DMA_AES_BLK,
                            plainOut,
                            &decLen,
                            CRYPTO_PROCESSING_SYNC);
    (void)Crypto_ProcessJob(CRYPTO_DRIVEROBJECT_WITHQUEUE, dmaJob);

    if (0 == memcmp(plainRef, plainOut, DMA_AES_BLK))
    {
        printf("AES-ECB decrypt after DMA buffer: OK\r\n");
    }
    else
    {
        printf("AES-ECB decrypt after DMA buffer: FAIL\r\n");
    }

    printf("------------------ IntegrationAppCrypto_DMA cipher End ------------------\r\n\r\n");

}
#endif /* PDL_MODULE_ENABLE */

int main()
{ 
    
    Mcu_Init(&g_mcuConfig);
    Mcu_InitClock(McuClockSettingConfig_0);
    Port_Init(&g_portConfig);
    Usart_Init(g_usartConfg);
    
    NVIC_EnableIRQ(USART2_IRQn);
    NVIC_EnableIRQ(USART1_IRQn);
    NVIC_EnableIRQ(SHA256_IRQn);
    NVIC_EnableIRQ(AES256_IRQn);
    NVIC_EnableIRQ(TRNG_IRQn);

    Usart_Init(g_usartConfg);
    printf("\r\n");
    printf("G32A1085 Crypto demo start!\r\n");
    
    Pdl_Init(&g_pdlConfig);
    Crypto_Init(NULL_PTR);

#if defined(TEST_DMA_CRYPTO_CIPHER) && (PDL_MODULE_ENABLE == STD_ON)
    RunDmaCryptoCipherDemo();
#endif
    
   while(1);
}

#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)
{
    int reVal = 0;
    reVal = Usart_PutRedefinition(USART1_ID,&ch);
    
    return reVal;
}

/* If configuring the full library using versions after IAR 9.30,
   it is necessary to implement the _write function for printf redirection.*/
size_t __write(int handle,const unsigned char *buf,size_t bufSize)
{
    int32 tempCh = 0;
    for(int i=0; i<bufSize; i++)
    {
        Usart_PutRedefinition(USART1_ID,&tempCh);
    }
    return bufSize;
}

#elif defined (__GNUC__)

/* For Arm Cross GCC: Eclipse */
int _write(int fd,const unsigned char *buf,int len)
{
    int32 tempCh = 0;
    for(int i=0; i<len; i++)
    {
        int32 tempCh = (int32)buf[i];
        Usart_PutRedefinition(USART1_ID,&tempCh);
    }
    return len;
}

#endif

#ifdef __cplusplus
}
#endif
