//=================================================================================================
//
// Company:       Paul Scherrer Institut
//                5232 Villigen PSI
//                Switzerland
//
//-------------------------------------------------------------------------------------------------
//
// Project:       Peltier Controller V2
// Author:        Noah Piqu� (noah.pique@psi.ch)
//
//-------------------------------------------------------------------------------------------------
//
// Module:        SPI-Driver
// Filename:      SPID_SpiDriver.c
// Date:          Handled by Subversion (version control system)
// Revision:      Handled by Subversion (version control system)
// History:       Handled by Subversion (version control system)
//
//-------------------------------------------------------------------------------------------------
//
// Description:   This source file contains all functions dealing with the SPI-Driver
//
//=================================================================================================



//=================================================================================================
// Section:       INCLUDES
// Description:   List of required include files.
//=================================================================================================

#include "../PDEF_ProjectDefinitions.h"
#include "SPID_SpiDriver.h"

// Application
//#include "../Application/ELOG_ErrorLogger.h"

// Toolbox 
#include "../Toolbox/UTIL_Utility.h"

// Drivers
#include "DIPO_DigitalPorts.h"

// include STM32 drivers
#include "stm32l4xx_hal.h"

#include "cmsis_os2.h" 

//=================================================================================================
// Section:       DEFINITIONS
// Description:   Definition of local constants (visible by this module only).
//=================================================================================================

#define OS_ADC_SPI_COMPLETE_FLAG      ((U32)(1<<0))
#define OS_ADC_SPI_ERROR_FLAG         ((U32)(1<<1))


//=================================================================================================
// Section:       MACROS
// Description:   Definition of local macros (visible by this module only).
//=================================================================================================



//=================================================================================================
// Section:       ENUMERATIONS
// Description:   Definition of local enumerations (visible by this module only).
//=================================================================================================



//=================================================================================================
// Section:       STRUCTURES
// Description:   Definition of local Structures (visible by this module only).
//=================================================================================================
 
typedef struct
{
  SPI_HandleTypeDef*      pstSPIHandle;
  osMutexId_t             pstMutexID;
  CONST osMutexAttr_t*    pstMutexAttribute;   
  U32                     u32SPICompleteFlag;
  U32                     u32SPIErrorFlag;
} StSPI;

//=================================================================================================
// Section:       LOCAL CONSTANTS
// Description:   Definition of local constants (visible by this module only).
//=================================================================================================


LOCAL CONST osMutexAttr_t m_stADCMutexAttr =
{
  "SPID_ADC_Mutex",                         // human readable mutex name
  osMutexRecursive | osMutexPrioInherit,    // attr_bits
  NULL,                                     // memory for control block   
  0U                                        // size for control block
};

LOCAL CONST osEventFlagsAttr_t stEventAttribute =
{ 
  "SPID_Event_Flags",               // name of the event flags 
  0,                                // attribute bits 
  NULL,                             // memory for control block
  0,                                // size of provided memory for control block
};
//=================================================================================================
// Section:       EXTERNAL VARIABLES
// Description:   Definition of external (global) variables.
//=================================================================================================
extern SPI_HandleTypeDef hspi1;

//=================================================================================================
// Section:       LOCAL VARIABLES
// Description:   Definition of local variables (visible by this module only).
//=================================================================================================

LOCAL StSPI m_astSPI[SPID_eNumberOfSPIs] =
{
  // SPID_eSPI2
  { 
    &hspi1,                           // SPI Handle
    NULL,                             // pstMutexID
    &m_stADCMutexAttr,                // pstMutexAttribute
    OS_ADC_SPI_COMPLETE_FLAG,         // u32SPICompleteFlag
    OS_ADC_SPI_ERROR_FLAG,            // u32SPIErrorFlag
  },
};

LOCAL osEventFlagsId_t  m_pstEventID  = NULL;

//=================================================================================================
// Section:       LOCAL FUNCTIONS (PROTOTYPES)
// Description:   Definition of local functions (visible by this module only).
//=================================================================================================

PRIVATE SPID_EnSPIs enGetSPI( SPI_HandleTypeDef* pstSPI );

//=================================================================================================
// Section:       EXTERNAL FUNCTIONS
// Description:   Definition of external (global) functions.
//=================================================================================================



//=================================================================================================
// Section:       GLOBAL FUNCTIONS
// Description:   Definition (implementation) of global functions.
//=================================================================================================

//-------------------------------------------------------------------------------------------------
// Function:      SPID_boInitializeModule
// Description:   Initializes the module
// Parameters:    None
// Returns:       BOOL,     TRUE, if successful, otherwise FALSE
//-------------------------------------------------------------------------------------------------
BOOL SPID_boInitializeModule( VOID )
{
  BOOL boOK= TRUE;

  boOK &= ((m_pstEventID = osEventFlagsNew( &stEventAttribute )) == NULL) ? FALSE : TRUE;

  return( boOK );
}
//-------------------------------------------------------------------------------------------------
// Function:      SPID_boSend
// Description:   Sends a number of bytes
// Parameters:    SPID_StHandle* pstHandle
// Returns:       BOOL      TRUE, if successful, otherwise FALSE
//-------------------------------------------------------------------------------------------------
BOOL SPID_boSend( SPID_StHandle* pstHandle )
{
  BOOL boOK;
  U32 u32Flags  = 0;
  
  #if defined(PDEF_FUNCTION_PARAMETER_CHECK_ENABLED) && PDEF_FUNCTION_PARAMETER_CHECK_ENABLED == TRUE
  if( pstHandle == NULL || pstHandle->enSPI >= SPID_eNumberOfSPIs  )
  {
    ELOG_ADD_LOG( ELOG_eInvalidFunctionParameter );
    return( FALSE );
  }
  #endif

  osMutexAcquire( m_astSPI[pstHandle->enSPI].pstMutexID, osWaitForever );
 
  // clear all flags
  osEventFlagsClear( m_pstEventID, m_astSPI[pstHandle->enSPI].u32SPICompleteFlag | m_astSPI[pstHandle->enSPI].u32SPIErrorFlag );
  
  
  // start SPI transmission 
  boOK = HAL_SPI_Transmit_DMA( m_astSPI[pstHandle->enSPI].pstSPIHandle, pstHandle->pu8TxBuf, pstHandle->u16TransferSize ) == HAL_OK ? TRUE : FALSE;
  
  if( boOK )
  {
    // wait until transmisison done
    u32Flags  = osEventFlagsWait( m_pstEventID, m_astSPI[pstHandle->enSPI].u32SPICompleteFlag | m_astSPI[pstHandle->enSPI].u32SPIErrorFlag, osFlagsWaitAny, osWaitForever  );
  }
  
  boOK &= ( u32Flags & m_astSPI[pstHandle->enSPI].u32SPIErrorFlag ) ? FALSE : TRUE;

  osMutexRelease( m_astSPI[pstHandle->enSPI].pstMutexID );
  
  return( boOK );
}

//-------------------------------------------------------------------------------------------------
// Function:      SPID_boSendReceive
// Description:   Sends a and receives a number of bytes
// Parameters:    SPID_StHandle* pstHandle
//                DIPO_EnDigitalOutput enCS
// Returns:       BOOL      TRUE, if successful, otherwise FALSE
//-------------------------------------------------------------------------------------------------
BOOL SPID_boSendReceive( SPID_StHandle* pstHandle )
{
  BOOL boOK;
  U32 u32Flags  = 0;
  
  #if defined(PDEF_FUNCTION_PARAMETER_CHECK_ENABLED) && PDEF_FUNCTION_PARAMETER_CHECK_ENABLED == TRUE
  if( pstHandle == NULL || pstHandle->enSPI >= SPID_eNumberOfSPIs  )
  {
    ELOG_ADD_LOG( ELOG_eInvalidFunctionParameter );
    return( FALSE );
  }
  #endif

  osMutexAcquire( m_astSPI[pstHandle->enSPI].pstMutexID, osWaitForever );
  
  // clear all flags
  osEventFlagsClear( m_pstEventID, m_astSPI[pstHandle->enSPI].u32SPICompleteFlag | m_astSPI[pstHandle->enSPI].u32SPIErrorFlag );
  
// start SPI
  boOK = HAL_SPI_TransmitReceive_DMA( m_astSPI[pstHandle->enSPI].pstSPIHandle, pstHandle->pu8TxBuf,  pstHandle->pu8RxBuf, pstHandle->u16TransferSize ) == HAL_OK ? TRUE : FALSE;
  
  if( boOK )
  {
    // wait until transmisison done
    u32Flags  = osEventFlagsWait( m_pstEventID, m_astSPI[pstHandle->enSPI].u32SPICompleteFlag | m_astSPI[pstHandle->enSPI].u32SPIErrorFlag, osFlagsWaitAny, osWaitForever  );
  }
  
  boOK &= ( u32Flags & m_astSPI[pstHandle->enSPI].u32SPIErrorFlag ) ? FALSE : TRUE;

  osMutexRelease( m_astSPI[pstHandle->enSPI].pstMutexID );
  
  return( boOK );
}

//=================================================================================================
// Section:       LOCAL FUNCTIONS
// Descriptionn:  Definition (implementation) of local functions.
//=================================================================================================

///-------------------------------------------------------------------------------------------------
// Function:      HAL_SPI_TxRxCpltCallback
// Description:   HAL spi rx/tx complete callback function
// Parameters:    SPI_HandleTypeDef *hspi
// Returns:       None
//-------------------------------------------------------------------------------------------------
VOID HAL_SPI_TxRxCpltCallback( SPI_HandleTypeDef *hspi )
{
  #if defined(PDEF_FUNCTION_PARAMETER_CHECK_ENABLED) && PDEF_FUNCTION_PARAMETER_CHECK_ENABLED == TRUE
  if( hspi == NULL )
  {
    ELOG_ADD_LOG( ELOG_eInvalidFunctionParameter );
    return;
  }
  #endif
  
  SPID_EnSPIs enSPI = enGetSPI( hspi );
  osEventFlagsSet( m_pstEventID, m_astSPI[enSPI].u32SPICompleteFlag );
}

//-------------------------------------------------------------------------------------------------
// Function:      HAL_SPI_TxCpltCallback
// Description:   HAL spi tx complete callback function
// Parameters:    SPI_HandleTypeDef *hspi
// Returns:       None
//-------------------------------------------------------------------------------------------------
VOID HAL_SPI_TxCpltCallback( SPI_HandleTypeDef *hspi )
{
  #if defined(PDEF_FUNCTION_PARAMETER_CHECK_ENABLED) && PDEF_FUNCTION_PARAMETER_CHECK_ENABLED == TRUE
  if( hspi == NULL )
  {
    ELOG_ADD_LOG( ELOG_eInvalidFunctionParameter );
    return;
  }
  #endif
  
  SPID_EnSPIs enSPI = enGetSPI( hspi );
  osEventFlagsSet( m_pstEventID, m_astSPI[enSPI].u32SPICompleteFlag );
}

//-------------------------------------------------------------------------------------------------
// Function:      HAL_SPI_RxCpltCallback
// Description:   HAL SPI rx complete callback function
// Parameters:    SPI_HandleTypeDef *hspi
// Returns:       None
//-------------------------------------------------------------------------------------------------
VOID HAL_SPI_RxCpltCallback( SPI_HandleTypeDef *hspi )
{
  #if defined(PDEF_FUNCTION_PARAMETER_CHECK_ENABLED) && PDEF_FUNCTION_PARAMETER_CHECK_ENABLED == TRUE
  if( hspi == NULL )
  {
    ELOG_ADD_LOG( ELOG_eInvalidFunctionParameter );
    return;
  }
  #endif
  
  SPID_EnSPIs enSPI = enGetSPI( hspi );
  osEventFlagsSet( m_pstEventID, m_astSPI[enSPI].u32SPICompleteFlag );
}

//-------------------------------------------------------------------------------------------------
// Function:      HAL_SPI_ErrorCallback
// Description:   HAL SPI error callback function
// Parameters:    SPI_HandleTypeDef *hspi
// Returns:       None
//-------------------------------------------------------------------------------------------------
VOID HAL_SPI_ErrorCallback( SPI_HandleTypeDef *hspi )
{
  #if defined(PDEF_FUNCTION_PARAMETER_CHECK_ENABLED) && PDEF_FUNCTION_PARAMETER_CHECK_ENABLED == TRUE
  if( hspi == NULL )
  {
    ELOG_ADD_LOG( ELOG_eInvalidFunctionParameter );
    return;
  }
  #endif
  
  // check rx overrun error
  if( hspi->ErrorCode & HAL_SPI_ERROR_OVR )
  {
    //ELOG_ADD_LOG( ELOG_eSPIOverrunError );
  }
  
  // check rx dma transfer error
  if( hspi->hdmarx->ErrorCode & HAL_DMA_ERROR_TE )
  {
    //ELOG_ADD_LOG( ELOG_eDMAHTransferError );
  } 
   
  // check tx dma transfer error
  if( hspi->hdmatx->ErrorCode & HAL_DMA_ERROR_TE )
  {
    //ELOG_ADD_LOG( ELOG_eDMAHTransferError );
  } 
  
  SPID_EnSPIs enSPI = enGetSPI( hspi );
  osEventFlagsSet( m_pstEventID, m_astSPI[enSPI].u32SPIErrorFlag );    
}

//-------------------------------------------------------------------------------------------------
// Function:      enGetSPI
// Description:   Gets the SPI enumeration to the corresponding SPI handle
// Parameters:    SPI_HandleTypeDef* pstSPI
// Returns:       SPID_EnSPIs
//-------------------------------------------------------------------------------------------------
PRIVATE SPID_EnSPIs enGetSPI( SPI_HandleTypeDef* pstSPI )
{
  #if defined(PDEF_FUNCTION_PARAMETER_CHECK_ENABLED) && PDEF_FUNCTION_PARAMETER_CHECK_ENABLED == TRUE
  if( pstSPI == NULL )
  {
    ELOG_ADD_LOG( ELOG_eInvalidFunctionParameter );
    ASRT_ASSERT( FALSE );
  }
  #endif
  
  for( U8 u8Cnt = 0; u8Cnt < SPID_eNumberOfSPIs; u8Cnt++ )
  {
    if( m_astSPI[u8Cnt].pstSPIHandle == pstSPI )
    {
      return( u8Cnt );
    }
  }

  //ASRT_ASSERT( FALSE );
  return( 0 );
}

