/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2023. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */
/******************************************************************************
 * @version: V1.0.0 demo
 ******************************************************************************/

/*!
* @file spi.c
*
* @brief This file contains the user spi function..
*
*/

/* ===========================================  Includes  =========================================== */
#include "gpio.h"
#include "spi.h"
#include "ac780x_spi.h"
#include "ac780x_spi_reg.h"
#include "ac780x_timer.h"
/* ============================================  Define  ============================================ */
#define SPI_DATA_LEN    8u /* In the full-duplex mode of SPI, the data length of TX and RX must be the same */

/* Can be used in conjunction with slave demo  "04_SPI_Slave_Interrupt" and "05_SPI_Slave_DMA" */
//#define SPI_MASTER_SLAVE_TEST 

/* ===========================================  Typedef  ============================================ */

/* ==========================================  Variables  =========================================== */
uint32_t g_spiMasterRequest = 0;            /* Master request communication flag */
uint32_t g_spiSlaveAck = 0;                 /* Slave response communication flag */
uint32_t g_spiCommunicationCnt = 0;         /* Periodic communication time */
uint32_t g_spiCommunicationTimerOutCnt = 0; /* request timeout count */
uint8_t rxBuff[SPI_DATA_LEN] = {0};         /* SPI1 receive array */
uint8_t txBuff[SPI_DATA_LEN] = {0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55};  /* SPI1 send array */

/* ====================================  Functions declaration  ===================================== */

/* ======================================  Functions define  ======================================== */
/*!
* @brief  TIM1 module interrupt handler.
*
* @param[in] none
* @return none
*/
void TIM1_IRQnCallBack(void *device, uint32_t wpara, uint32_t lpara)
{
    
    if(g_spiCommunicationCnt < 500)
    {
        g_spiCommunicationCnt++;
    }
    if(g_spiCommunicationTimerOutCnt>0)
        g_spiCommunicationTimerOutCnt--;
}


/*!
* @brief  Initalize TIM1 module.
*
* @param[in] none
* @return none
*/
void TIMER_InitHardwr(void)
{
    TIMER_ConfigType timerConfig;
    
    memset((void *)&timerConfig, 0, (uint32_t)sizeof(TIMER_ConfigType));   
    
    timerConfig.timeMode = TIMER_WORKMODE_TIMER;   
    timerConfig.prescaler = TIMER_PRESCALE_16_GLITCHFILTER_7;
    timerConfig.periodValue = 2000;
    timerConfig.callback = TIM1_IRQnCallBack;
    timerConfig.interruptEn = ENABLE;
    timerConfig.bypEn = DISABLE;
    
    TIMER_Init(TIMER_CLKSR_APB);        
    TIMER_InitChannel(TIMER_CHANNEL1, &timerConfig);        /* Enable TIMER_CHANNEL1, 1ms generates an interrupt */
}

/*!
* @brief SPI master and slave test
*
* @param[in] none
* @return none
*/
void Spi1_MasterTest(void)
{
    ERROR_Type ret = ERROR;
    
    /* 500ms request communication */
    if(g_spiCommunicationCnt == 500 && g_spiMasterRequest == 0) 
    {
        /* 500ms overtime time */
        g_spiCommunicationTimerOutCnt = 500;
        /* pull request communication pin */
        GPIO_SetPinLevel(GPIOC , GPIO_PIN11, GPIO_LEVEL_HIGH);
        
        g_spiMasterRequest = 1;
        printf("Prepare\r\n");
    }
    /* start of communication */
    if(g_spiMasterRequest == 1 && g_spiSlaveAck == 1)
    {
        txBuff[0]++;
        printf("transmission\r\n");
        ret = SPI_TransmitReceiveInt(SPI1, rxBuff, txBuff, SPI_DATA_LEN);
        if(ERROR == ret)
        {
            printf("ERROR\r\n ");
        }
        else
        {
            /* Wait SPI receive(interrupt mode) finish */
            ret = SPI_WaitReceiveFinish(SPI1);

            if(ERROR == ret)
            {
                printf("Rx ERROR\r\n ");
            }
            else
            {
                printf("SPI rx data = 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X ",
                    rxBuff[0], rxBuff[1], rxBuff[2], rxBuff[3], rxBuff[4], rxBuff[5], rxBuff[6], rxBuff[7]);
            }
        }
        GPIO_SetPinLevel(GPIOC , GPIO_PIN11, GPIO_LEVEL_LOW);
        g_spiCommunicationCnt = 0;
        g_spiMasterRequest = 0;
        g_spiSlaveAck = 0;
        /* down request newsletter pin */
    }
    /* handshake timeout */
    else if(g_spiCommunicationTimerOutCnt == 0 && g_spiMasterRequest == 1)
    {
        printf("Timer out\r\n");
        g_spiCommunicationCnt = 0;
        g_spiMasterRequest = 0;
        g_spiSlaveAck = 0;
        /* down request newsletter pin */
        GPIO_SetPinLevel(GPIOC , GPIO_PIN11, GPIO_LEVEL_LOW);
    }
    else
    {
        
    }
}

/*!
* @brief SPI master test
*
* @param[in] none
* @return none
*/
void Spi1_Test(void)
{
    ERROR_Type ret = ERROR;
    
    txBuff[0]++;
    ret = SPI_TransmitReceiveInt(SPI1, rxBuff, txBuff, SPI_DATA_LEN);
    if(ERROR == ret)
    {
        printf("ERROR\r\n ");
    }
    else
    {
        /* Wait SPI receive(interrupt mode) finish */
        ret = SPI_WaitReceiveFinish(SPI1);
        if(ERROR == ret)
        {
            printf("Rx ERROR\r\n ");
        }
        else
        {
            printf("SPI rx data = 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X ",
                rxBuff[0], rxBuff[1], rxBuff[2], rxBuff[3], rxBuff[4], rxBuff[5], rxBuff[6], rxBuff[7]);
        }
    }
    mdelay(200);
}

/*!
* @brief  GPIO Interrupt Callback
*
* @param[in] none
* @return none
*/
 void GPIOC_10_Callback(void *device, uint32_t wpara, uint32_t lpara)
 {
     if(GPIO_GetPinLevel(GPIOC, GPIO_PIN10) == GPIO_LEVEL_HIGH)
     {
         if(g_spiSlaveAck == 0)
         {
            g_spiSlaveAck = 1;
         }
     }
 }
 
/*!
* @brief  Init spi1 pin 
*
* @param[in] none
* @return none
*/
void Spi1_Gpio_Init(void)
{
#ifdef SPI_MASTER_SLAVE_TEST
    GPIO_SetFunc(GPIOC, GPIO_PIN11, GPIO_FUN0);     /* Master initiates communication pin */
    GPIO_SetDir(GPIOC, GPIO_PIN11, GPIO_OUT);
    GPIO_SetPinLevel(GPIOC , GPIO_PIN11, GPIO_LEVEL_LOW);
    
    GPIO_SetFunc(GPIOC, GPIO_PIN10, GPIO_FUN0);     /* Slave communication feedback pin */
    GPIO_SetDir(GPIOC, GPIO_PIN10, GPIO_IN);
    GPIO_SetPulldown(GPIOC, GPIO_PIN10, ENABLE);
    GPIO_EnableExtInterrupt(GPIOC, GPIO_PIN10, EXTI_TRIGGER_RISING);
    GPIO_SetCallback(GPIO_PIN10, GPIOC_10_Callback);
#endif
    GPIO_SetFunc(GPIOB, GPIO_PIN12, GPIO_FUN3);     /* SCK */
    GPIO_SetFunc(GPIOB, GPIO_PIN11, GPIO_FUN3);     /* MOSI */
    GPIO_SetFunc(GPIOC, GPIO_PIN1, GPIO_FUN3);      /* CS */
    GPIO_SetFunc(GPIOC, GPIO_PIN0, GPIO_FUN3);      /* MISO */
}

/*!
* @brief  spi call back fun
*
* @param[in] none
* @return none
*/
void SPI1_Callback(void *device, uint32_t wpara, uint32_t lpara)
{
    if (wpara & SPI_STATUS_TXUF_Msk)
    {
        /* Software Reset SPI */
        SPI_SoftwareReset(SPI1);
    }
    if (wpara & SPI_STATUS_RXOF_Msk)
    {
        /* Software Reset SPI */
        SPI_SoftwareReset(SPI1);
    }
}

/*!
* @brief  Init spi
*
* @param[in] none
* @return none
*/
void Spi1_Init(void)
{
    SPI_ConfigType spi_config_t;
    
    memset(&spi_config_t, 0x00, sizeof(spi_config_t));
    
    /* The baud rate of SPI is 1Mhz */
    spi_config_t.csSetup = 20;   /* Chip Select Setup Time  = (CS_SETUP + 1) * CLK_PERIOD. */
    spi_config_t.csHold  = 20;   /* Chip Select Hold Time = (CS_HOLD + 1) * CLK_PERIOD. */
    spi_config_t.sckHigh = 15;   /* SCK clock high time= (SCK_HIGH + 1) * CLK_PERIOD. */
    spi_config_t.sckLow  = 15;   /* SCK clock low time = (SCK_LOW + 1) * CLK_PERIOD. */
    spi_config_t.csIdle  = 20;   /* CS free time = (CS_IDLE + 1) * CLK_PERIOD. */
    spi_config_t.mode      = SPI_MASTER;        /* set master */
    spi_config_t.cpha      = SPI_CPHA_1EDGE;    /* second edge sampling */
    spi_config_t.cpol      = SPI_CPOL_LOW;     /* SCK active high */
    spi_config_t.frmSize   = SPI_FRAME_SIZE_8BITS;  /* transfer byte width 8bits */
    spi_config_t.rxMsbFirstEn      = ENABLE;    /* RX MSB */
    spi_config_t.txMsbFirstEn      = ENABLE;    /* TX MSB */
    spi_config_t.csOutputEn        = ENABLE;    /* CS is hardware control */
    spi_config_t.continuousCSEn    = ENABLE;    /* CS is continuous mode */
    spi_config_t.dmaRxEn       = DISABLE;   /* RX DMA disable */
    spi_config_t.dmaTxEn       = DISABLE;   /* TX DMA disable */
    spi_config_t.modeFaultEn   = DISABLE;   /* Fault detection mode disable*/
    spi_config_t.wakeUpEn      = DISABLE;   /* wake up disable */
    spi_config_t.spiEn         = ENABLE;    /* Spi enable */
    spi_config_t.callBack      = SPI1_Callback;      /* call back fun */
    spi_config_t.interruptEn   = ENABLE;   /* interrupt enable */
    spi_config_t.txUFInterruptEn       = ENABLE;   /* TX buffer underflow interrupt enable */
    spi_config_t.rxOFInterruptEn       = ENABLE;   /* RX buffer overflow interrupt enable */
    spi_config_t.modeFaultInterruptEn = DISABLE;    /* Mode Fault Interrupt disable */
    
    SPI_Init(SPI1, &spi_config_t);  /* spi initialization */
    Spi1_Gpio_Init();               /* spi Pin initialization */
    TIMER_InitHardwr();
}


/* =============================================  EOF  ============================================== */
