/**
 * @file    S2LP_CORE_SPI.c
 * @author  ST Microelectronics
 * @version 1.3.0
 * @date    June, 2019
 * @brief   This file provides functions to manage S2-LP debug.
 * @details
 *
 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
 * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
 *
 * THIS SOURCE CODE IS PROTECTED BY A LICENSE.
 * FOR MORE INFORMATION PLEASE CAREFULLY READ THE LICENSE AGREEMENT FILE LOCATED
 * IN THE ROOT DIRECTORY OF THIS FIRMWARE PACKAGE.
 *
 * <h2><center>&copy; COPYRIGHT 2019 STMicroelectronics</center></h2>
 *
 */

/* Includes ------------------------------------------------------------------*/
#include "app_main.h"
#include "S2LP_CORE_SPI.h"

/* Driver configuration */
#include "ti_drivers_config.h"

// static const nrf_drv_spi_t SpiHandle = NRF_DRV_SPI_INSTANCE(2); /**< SPI instance. */
static SPI_Handle controllerSpi;
SPI_Params spiParams;

/** @addtogroup S2LP_CORE_STM32                     S2LP CORE - STM32
* @{
*/

/** @defgroup S2LP_CORE_SPI					S2LP CORE SPI
  * @brief  S2-LP SPI handling module.
  * This module exports all the main operations to deal with SPI.
  * @details See the file <i>@ref S2LP_CORE_SPI.h</i> for more details.
  * @{
*/
#define DELAY_CS_SCLK			0x70   /* Delay between CSn falling edge & start of SCLK */
#define SPI_TIMEOUT			0xFFFFFFFF  /* SPI Xferb TIMEOUT */

#define HEADER_WRITE_MASK		  0x00 /* !< Write mask for header byte */
#define HEADER_READ_MASK		  0x01 /* !< Read mask for header byte */
#define HEADER_ADDRESS_MASK		0x00 /* !< Address mask for header byte */
#define HEADER_COMMAND_MASK		0x80 /* !< Command mask for header byte */

#define LINEAR_FIFO_ADDRESS		0xFF  /* !< Linear FIFO address */
#define RSSI_LEVEL_RUN_ADDRESS	0xEF	/* !< RSSI RUN Register address */

#define BUILT_HEADER(add_comm, w_r) (add_comm | w_r)  /*!< macro to build the header byte*/
#define WRITE_HEADER    BUILT_HEADER(HEADER_ADDRESS_MASK, HEADER_WRITE_MASK) /*!< macro to build the write header byte*/
#define READ_HEADER     BUILT_HEADER(HEADER_ADDRESS_MASK, HEADER_READ_MASK)  /*!< macro to build the read header byte*/
#define COMMAND_HEADER  BUILT_HEADER(HEADER_COMMAND_MASK, HEADER_WRITE_MASK) /*!< macro to build the command header byte*/

#define SPI_MSG_LENGTH (32)

//static SPI_HandleTypeDef SpiHandle;
//static DMA_HandleTypeDef hdma_tx;
//static DMA_HandleTypeDef hdma_rx;
//static uint8_t waiting_irq=0;

/* Semaphore to block peripheral until transfer is complete */
// sem_t peripheralSem;

/* Status indicating whether or not SPI transfer succeeded. */
bool transferStatus;

#define SPI_ENTER_CRITICAL()           __disable_irq()
#define SPI_EXIT_CRITICAL()            __enable_irq()

static volatile uint8_t spi_in_use=0;

static uint8_t controllerTxBuffer[SPI_MSG_LENGTH];        //CHECK
static uint8_t controllerRxBuffer[SPI_MSG_LENGTH];        //CHECK

void SPI_CSN_LOW()  {
  GPIO_write(S2LP_SPI_CS_PIN, 0);
} 

void SPI_CSN_HIGH() {
  GPIO_write(S2LP_SPI_CS_PIN, 1);
}     

static bool S2LPSpiTransfer(uint8_t* txBuf, uint8_t* rxBuf, uint16_t len)
{
    
    SPI_Transaction transaction;
    // memset(&transaction, 0, sizeof(transaction));
    transaction.count = len;
    transaction.txBuf = txBuf;
    transaction.rxBuf = rxBuf;

    return SPI_transfer(controllerSpi, &transaction);
}

// /**
//  * @brief SPI user event handler.
//  * @param event
//  */
void transferCompleteFxn(SPI_Handle handle, SPI_Transaction *transaction)
{
    if (transaction->status != SPI_TRANSFER_COMPLETED)
    {
        transferStatus = false;
    }
    else
    {
        transferStatus = true;
    }

    // sem_post(&peripheralSem);
}

void S2LPSpiInit(void)
{
    SPI_Params spiParams;

    /* Open SPI as controller (default) */
    SPI_Params_init(&spiParams);
    spiParams.frameFormat = SPI_POL0_PHA1;
    /* See device-specific technical reference manual for supported speeds */
    spiParams.bitRate     = 500000;
    controllerSpi         = SPI_open(CONFIG_SPI_0, &spiParams);
    if (controllerSpi == NULL)
    {
        printf("Error initializing controller SPI\n");
        // while (1) {}
    }
    // else
    // {
    //     printf("Controller SPI initialized\n");
    // }   
}

void S2LPSpiOpen(void)
{
    controllerSpi         = SPI_open(CONFIG_SPI_0, &spiParams);
    if (controllerSpi == NULL)
    {
        printf("Error initializing controller SPI\n");
        // while (1) {}
    }
    else
    {
        printf("Controller SPI initialized\n");
    }
}

void HAL_SPI_TransmitReceive_DMA(uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
{
    S2LPSpiInit();
    usleep(100);

    S2LPSpiTransfer(pTxData, pRxData, Size);

    S2LPSpiClose();
}

void SdkEvalSpiDeinit(void)
{
    if (controllerSpi != NULL) {
        SPI_close(controllerSpi);
        controllerSpi = NULL;
    }
}

void S2LPSpiClose(void)
{
    SPI_close(controllerSpi);
}

uint16_t S2LPSpiReadRegisters(uint8_t address, uint8_t n_bytes, uint8_t* buffer)
{
    controllerTxBuffer[0] = READ_HEADER;
    controllerTxBuffer[1] = address;

    memset(&controllerTxBuffer[2], 0, n_bytes);
    memset(controllerRxBuffer, 0, 2 + n_bytes);

    // SPI_CSN_LOW();
    // usleep(100);
    
    if (!S2LPSpiTransfer(controllerTxBuffer, controllerRxBuffer, 2 + n_bytes)) {
        SPI_CSN_HIGH();
        return 0xFFFF; // error
    }

    // usleep(100);
    // SPI_CSN_HIGH();

    memcpy(buffer, &controllerRxBuffer[2], n_bytes);

    return ((uint16_t)controllerRxBuffer[0] << 8) | controllerRxBuffer[1];
}

uint16_t S2LPSpiWriteRegisters(uint8_t RegisterAddr, uint8_t NumByteToWrite, uint8_t* pBuffer)
{
    controllerTxBuffer[0] = WRITE_HEADER;
    controllerTxBuffer[1] = RegisterAddr;
    memcpy(&controllerTxBuffer[2], pBuffer, NumByteToWrite);
    memset(controllerRxBuffer, 0, 2 + NumByteToWrite);

    // SPI_CSN_LOW();
    // usleep(100);

    if (!S2LPSpiTransfer(controllerTxBuffer, controllerRxBuffer, 2 + NumByteToWrite)) {
        SPI_CSN_HIGH();
        return 0xFFFF; // error
    }

    // usleep(100);
    // SPI_CSN_HIGH();

    return ((uint16_t)controllerRxBuffer[0] << 8) | controllerRxBuffer[1];
}


uint16_t S2LPSpiCommandStrobes(uint8_t command)
{
    controllerTxBuffer[0] = COMMAND_HEADER;
    controllerTxBuffer[1] = command;
    memset(controllerRxBuffer, 0, 2);

    // SPI_CSN_LOW();
    // usleep(100);

    if (!S2LPSpiTransfer(controllerTxBuffer, controllerRxBuffer, 2)) {
        SPI_CSN_HIGH();
        return 0xFFFF;
    }

    // usleep(100);
    // SPI_CSN_HIGH();

    return ((uint16_t)controllerRxBuffer[0] << 8) | controllerRxBuffer[1];
}


uint16_t S2LPSpiReadFifo(uint8_t n_bytes, uint8_t* buffer)
{
    controllerTxBuffer[0] = READ_HEADER;
    controllerTxBuffer[1] = LINEAR_FIFO_ADDRESS;
    memset(&controllerTxBuffer[2], 0, n_bytes);
    memset(controllerRxBuffer, 0, 2 + n_bytes);

    // SPI_CSN_LOW();
    // usleep(100);

    if (!S2LPSpiTransfer(controllerTxBuffer, controllerRxBuffer, 2 + n_bytes)) {
        SPI_CSN_HIGH();
        return 0xFFFF;
    }

    // usleep(100);
    // SPI_CSN_HIGH();

    memcpy(buffer, &controllerRxBuffer[2], n_bytes);

    return ((uint16_t)controllerRxBuffer[0] << 8) | controllerRxBuffer[1];
}

uint16_t S2LPSpiWriteFifo(uint8_t n_bytes, uint8_t* buffer)
{
    controllerTxBuffer[0] = WRITE_HEADER;
    controllerTxBuffer[1] = LINEAR_FIFO_ADDRESS;
    memcpy(&controllerTxBuffer[2], buffer, n_bytes);
    memset(controllerRxBuffer, 0, 2 + n_bytes);

    // SPI_CSN_LOW();
    // usleep(100);

    if (!S2LPSpiTransfer(controllerTxBuffer, controllerRxBuffer, 2 + n_bytes)) {
        SPI_CSN_HIGH();
        return 0xFFFF;
    }

    // usleep(100);
    // SPI_CSN_HIGH();

    return ((uint16_t)controllerRxBuffer[0] << 8) | controllerRxBuffer[1];
}

void Sub1G_Sleep(void)
{
    GPIO_setConfig(CONFIG_GPIO_SPI_0_PICO, GPIO_CFG_INPUT);
    GPIO_setConfig(CONFIG_GPIO_SPI_0_POCI, GPIO_CFG_INPUT);
    GPIO_setConfig(CONFIG_GPIO_SPI_0_SCLK,  GPIO_CFG_INPUT);
    GPIO_setConfig(CONFIG_GPIO_SPI_0_CSN,   GPIO_CFG_INPUT);
}

void Sub1G_Wakeup(void)
{
    GPIO_setConfig(CONFIG_GPIO_SPI_0_PICO, GPIO_CFG_OUT_STD);
    GPIO_setConfig(CONFIG_GPIO_SPI_0_SCLK,  GPIO_CFG_OUT_STD);
    GPIO_setConfig(CONFIG_GPIO_SPI_0_CSN,   GPIO_CFG_OUT_STD);
    GPIO_setConfig(CONFIG_GPIO_SPI_0_POCI, GPIO_CFG_IN_PD);
}


/**
 * @}
 */

/**
 * @}
 */

/******************* (C) COPYRIGHT 2020 STMicroelectronics *****END OF FILE****/





