/*!
 * @file        soft_spi.c
 *
 * @brief       This file provides all the soft spi functions
 *
 * @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.
 */

#include "soft_spi.h"
#include <string.h>
#include "g32a10xx_int.h"

/** @addtogroup Examples
  @{
*/

/** @addtogroup SPI_Examples
  @{
*/

/** @addtogroup SPI_Soft_Slave
  @{
  */

/** @defgroup SPI_Soft_Slave_Functions Functions
  @{
*/

extern void SysTick_Start(void);
extern void SysTick_Stop(void);

/*!
 * @brief       SoftSpi Spi_Delay Us
 *
 * @param       Us: delay us
 *
 * @retval      none
 *
 */
static void SoftSpi_DelayUs(uint32_t Us)
{
    g_sysTick = 0;
    SysTick_Start();
    while (g_sysTick < Us)
    {
        /* do nothing */
    }
    SysTick_Stop();
}

/*!
 * @brief       SoftSpi Init
 *
 * @param       CfgPtr: SoftSpi Config
 *
 * @retval      none
 *
 */
void SoftSpi_Init(SoftSpi_ConfigType *CfgPtr)
{
    if (CfgPtr == NULL)
    {
        /* do nothing */
    }
    else
    {
        CfgPtr->cpol = (uint8_t)(((uint32_t)CfgPtr->mode >> 1u) & 0x01u);
        CfgPtr->cpha = (uint8_t)((uint32_t)CfgPtr->mode & 0x01u);

        CfgPtr->set_sck(CfgPtr->cpol);
    }
}

/*!
 * @brief       SoftSpi Master Transfer Byte
 *
 * @param       CfgPtr: SoftSpi Config
 *
 * @param       Tx_data: Tx data
 *
 * @retval      rx data
 *
 */
uint8_t SoftSpi_MasterTransferByte(const SoftSpi_ConfigType *CfgPtr, uint8_t Tx_data)
{
    int i = 0;
    uint8_t rx_data = 0;

    if (CfgPtr != NULL)
    {
        CfgPtr->set_sck(CfgPtr->cpol);
    }
    else
    {
        /* nothing */
    }

    if (CfgPtr == NULL)
    {
        /* do nothing */
    }
    else
    {
        for (i = 7; i >= 0; i--)
        {
            uint8_t tx_bit = (Tx_data >> (uint32_t)i) & 1u;

            if (CfgPtr->cpha == 0u)
            {
                CfgPtr->set_mosi(tx_bit);
                SoftSpi_DelayUs(CfgPtr->half_clock_delay_us);
                CfgPtr->set_sck(CfgPtr->cpol ^ 1u);
                SoftSpi_DelayUs(CfgPtr->half_clock_delay_us);
                rx_data |= (CfgPtr->read_miso() << (uint32_t)i);
                CfgPtr->set_sck(CfgPtr->cpol);
            }
            else
            {
                CfgPtr->set_sck(CfgPtr->cpol ^ 1u);
                SoftSpi_DelayUs(CfgPtr->half_clock_delay_us);
                CfgPtr->set_mosi(tx_bit);
                SoftSpi_DelayUs(CfgPtr->half_clock_delay_us);
                CfgPtr->set_sck(CfgPtr->cpol);
                SoftSpi_DelayUs(CfgPtr->half_clock_delay_us);
                rx_data |= (CfgPtr->read_miso() << (uint32_t)i);
            }
        }
    }
    return rx_data;
}

/*!
 * @brief       SoftSpi Slave Init
 *
 * @param       CfgPtr: SoftSpi Config
 *
 * @param       CtxPtr: SoftSpi Config Tx
 *
 * @retval      none
 *
 */
void SoftSpi_SlaveInit(const SoftSpi_ConfigType *CfgPtr, SoftSpi_SlaveCtxType *CtxPtr)
{
    if ((CfgPtr == NULL) || (CtxPtr == NULL))
    {
        /* do nothing */
    }
    else
    {
        memset(CtxPtr, 0, sizeof(*CtxPtr));
        CtxPtr->cs_active = 0u;
        CtxPtr->bit_idx = 8;
        CtxPtr->edge_phase = 0;
        CtxPtr->rx_ready = 0u;
    }
}

/*!
 * @brief       SoftSpi Slave Sck Isr
 *
 * @param       CfgPtr: SoftSpi Config
 *
 * @param       CtxPtr: SoftSpi Config Tx
 *
 * @retval      none
 *
 */
void SoftSpi_SlaveSckIsr(const SoftSpi_ConfigType *CfgPtr, SoftSpi_SlaveCtxType *CtxPtr)
{
    uint8_t tx_byte_val = 0;
    uint8_t bit_idx_val = 0;
    uint8_t tx_bit = 0;

    if ((CfgPtr == NULL) || (CtxPtr == NULL))
    {
        /* do nothing */
    }
    else
    {
        if (0u == CtxPtr->cs_active)
        {
            /* do nothing */
        }
        else
        {
            if (CtxPtr->bit_idx >= 8u)
            {
                CtxPtr->rx_byte = 0;
                CtxPtr->tx_byte = CtxPtr->next_tx_byte;
                CtxPtr->next_tx_byte = 0;
                CtxPtr->bit_idx = 0;
                CtxPtr->edge_phase = 0;
                CtxPtr->rx_ready = 0u;
            }
            else
            {
                /* do nothing */
            }

            if (CfgPtr->cpha == 0u)
            {
                if (CtxPtr->edge_phase == (uint8_t)0)
                {
                    CtxPtr->rx_byte = (CtxPtr->rx_byte << 1) | CfgPtr->read_mosi();
                }
                else
                {
                    tx_byte_val = CtxPtr->tx_byte;
                    bit_idx_val = CtxPtr->bit_idx;
                    tx_bit = (tx_byte_val >> (7U - bit_idx_val - 1U)) & 1U;

                    CfgPtr->set_miso(tx_bit);
                }
            }
            else
            {
                if (CtxPtr->edge_phase == 0u)
                {
                    tx_byte_val = CtxPtr->tx_byte;
                    bit_idx_val = CtxPtr->bit_idx;
                    tx_bit = (tx_byte_val >> (7u - bit_idx_val)) & 1u;
                    CfgPtr->set_miso(tx_bit);
                }
                else
                {
                    CtxPtr->rx_byte = (CtxPtr->rx_byte << 1) | CfgPtr->read_mosi();
                }
            }

            if (CtxPtr->edge_phase == 1u)
            {
                CtxPtr->bit_idx = CtxPtr->bit_idx + 1u;
            }
            else
            {
                /* do nothing */
            }
            CtxPtr->edge_phase ^= 1u;

            if (CtxPtr->bit_idx >= 8u)
            {
                CtxPtr->rx_ready = 1u;
            }
            else
            {
                /* do nothing */
            }
        }
    }
}


/**@} end of group SPI_Soft_Slave_Functions */
/**@} end of group SPI_Soft_Slave */
/**@} end of group SPI_Examples */
/**@} end of group Examples */
