/*
 * H_Common_STM32F4_SPI.c
 *
 *  Created on: 2024/11/21
 *      Author: egaono-electronics
 */

#include "H_Common_STM32F4_SPI.h"



//----------------------------------------------------------
// SPIx : Handle SPI用パラメータの構造体を初期化
//----------------------------------------------------------
// 引数;
// uint8_t *puint8_aSPI_TxBuffer : SPI送信Bufferのポインタ
// uint8_t *puint8_aSPI_RxBuffer : SPI受信Bufferのポインタ

// struct sParam_Handle_SPIx  *pstructParam_Handle_SPIx
//              Handle SPI用パラメータの構造体のポインタ


// 戻り値;
//    なし
//----------------------------------------------------------
void Initialize_Parameter_SPIx(uint8_t *puint8_aSPI_TxBuffer,
                               uint8_t *puint8_aSPI_RxBuffer,
        struct sParam_Handle_SPIx  *pstructParam_Handle_SPIx)
{
  // 送信Bufferのポインタをセット
  pstructParam_Handle_SPIx->puint8_aSPI_TxBuffer
                                = puint8_aSPI_TxBuffer;

  // 受信Bufferのポインタをセット
  pstructParam_Handle_SPIx->puint8_aSPI_RxBuffer
                                = puint8_aSPI_RxBuffer;


  pstructParam_Handle_SPIx->int16_vSPI_TxIdx = 0;
  pstructParam_Handle_SPIx->int16_vSPI_RxIdx = 0;

  pstructParam_Handle_SPIx->int16_vSPI_TxNumber = 0;
  pstructParam_Handle_SPIx->int16_vSPI_RxNumber = 0;

  pstructParam_Handle_SPIx->uint16_vSPI_Mode = SPI_MODE_MASTER;

  pstructParam_Handle_SPIx->int16_vSPI_Semaphore = 0;

  pstructParam_Handle_SPIx->int16_vSPI_ReceiveEnd = -1;
  pstructParam_Handle_SPIx->int16_vSPI_Error = 0;

  // SPI Timeout
  pstructParam_Handle_SPIx->uint16_vTimerSPI = 0;
}



//----------------------------------------------------------
// SPIx 初期化
//----------------------------------------------------------
// 引数;
// SPI_TypeDef *SPIx :
//      where x can be 1 or 2 to select the SPI peripheral.

// SPI_HandleTypeDef *pHandle_SPIx : SPI handler declaration

// uint32_t uint32_SPI_Mode :
//                      SPI_MODE_MASTER or SPI_MODE_SLAVE

// uint32_t uint32_BaudRatePrescaler : SPIクロック 分周設定

// uint16_t uint16_CLKPolarity : clock polarity :
//          SPI_POLARITY_LOW or SPI_POLARITY_HIGH


// 戻り値;
//    0 : OK
//    1 : NG
//----------------------------------------------------------
int16_t Initialize_SPIx(SPI_TypeDef *SPIx,
                        SPI_HandleTypeDef *pHandle_SPIx,
                        uint32_t uint32_SPI_Mode,
                        uint32_t uint32_BaudRatePrescaler,
                        uint32_t uint32_CLKPolarity)
{
  //--------------------------------------------------------
  // Configure the SPI peripheral
  //--------------------------------------------------------
  // Set the SPI parameters
  pHandle_SPIx->Instance          = SPIx;

  pHandle_SPIx->Init.Mode         = uint32_SPI_Mode;

  pHandle_SPIx->Init.Direction    = SPI_DIRECTION_2LINES;
  pHandle_SPIx->Init.DataSize     = SPI_DATASIZE_8BIT;

  pHandle_SPIx->Init.CLKPolarity  = uint32_CLKPolarity;

  if(uint32_CLKPolarity == SPI_POLARITY_LOW){
    pHandle_SPIx->Init.CLKPhase   = SPI_PHASE_1EDGE;
  }
  else if(uint32_CLKPolarity == SPI_POLARITY_HIGH){
    pHandle_SPIx->Init.CLKPhase   = SPI_PHASE_2EDGE;
  }
  else{
    return(1);  // NG
  }

  pHandle_SPIx->Init.NSS               = SPI_NSS_SOFT;
  pHandle_SPIx->Init.BaudRatePrescaler
                            = uint32_BaudRatePrescaler;

  pHandle_SPIx->Init.FirstBit          = SPI_FIRSTBIT_MSB;
  pHandle_SPIx->Init.TIMode            = SPI_TIMODE_DISABLE;
  pHandle_SPIx->Init.CRCCalculation
                            = SPI_CRCCALCULATION_DISABLE;
  pHandle_SPIx->Init.CRCPolynomial     = 10;


  if(HAL_SPI_Init(pHandle_SPIx) != HAL_OK)
  {
    // Initialization Error
    return(1);  // NG
  }


  return(0);  // OK
}



//----------------------------------------------------------
// SPIx  Master送受信
//----------------------------------------------------------
// 引数;
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

// SPI_HandleTypeDef *pHandle_SPIx : SPI handler declaration

// IRQn_Type DMA_Stream_IRQn_Transmit_SPIx : SPI DMA Transmit IRQn
// IRQn_Type DMA_Stream_IRQn_Receive_SPIx : SPI DMA Receive IRQn

// struct sParam_Handle_SPIx *pstructParam_Handle_SPIx :
//              Handle SPI用パラメータの構造体のポインタ

// GPIO_TypeDef *pGPIOx_SPIx_NSS : SPIx_NSS のGPIOポート
// uint16_t uint16_GPIO_Pin_x_SPIx_NSS : SPIx_NSS のGPIOピン

// int16_t int16_Value_Wait_SPI_TxRx : SPI送受信待ちの値

// int16_t int16_NSS_OnOff : 送信終了時NSS ON/OFF選択
//    0 : 送信後 NSSをOFFにする。
//    1 : 送信後 NSSをONのままにする。


// 戻り値;
//    -1 : 処理中
//    0 : OK
//    1 : NG
//----------------------------------------------------------
int16_t SPIx_Master_TxRxByte(uint8_t *puint8_JobNum,
                    SPI_HandleTypeDef *pHandle_SPIx,
                    IRQn_Type DMA_Stream_IRQn_Transmit_SPIx,
                    IRQn_Type DMA_Stream_IRQn_Receive_SPIx,
            struct sParam_Handle_SPIx *pstructParam_Handle_SPIx,
                             GPIO_TypeDef *pGPIOx_SPIx_NSS,
                             uint16_t uint16_GPIO_Pin_x_SPIx_NSS,
                             int16_t int16_Value_Wait_SPI_TxRx,
                             int16_t int16_NSS_OnOff)
{
  int16_t int16_Return;

  HAL_StatusTypeDef hal_Status;


  switch(*puint8_JobNum)
  {
  case 0:
    // 指定送信数チェック
    if((pstructParam_Handle_SPIx->int16_vSPI_TxNumber <= 0)
        || (pstructParam_Handle_SPIx->int16_vSPI_TxNumber
                                > def_SPI1_TxBufferSize)){
      // 指定送信数が正しくない。
      int16_Return = 1;  // NG終了
      break;
    }


    // 受信数セット
    pstructParam_Handle_SPIx->int16_vSPI_RxNumber
        = pstructParam_Handle_SPIx->int16_vSPI_TxNumber;


    // Semaphore ON
    pstructParam_Handle_SPIx->int16_vSPI_Semaphore = 1;


    pstructParam_Handle_SPIx->int16_vSPI_Error = 0;  // Clear Error


    pstructParam_Handle_SPIx->int16_vSPI_TxIdx = 0;  // 送信結果クリア
    pstructParam_Handle_SPIx->int16_vSPI_RxIdx = 0;  // 受信結果クリア

    // NSS ON
    HAL_GPIO_WritePin(pGPIOx_SPIx_NSS,
                      uint16_GPIO_Pin_x_SPIx_NSS,
                      GPIO_PIN_RESET);


    // Enable the TIMx global Interrupt
    HAL_NVIC_EnableIRQ(DMA_Stream_IRQn_Transmit_SPIx);  // Transmit
    HAL_NVIC_EnableIRQ(DMA_Stream_IRQn_Receive_SPIx);  // Receive


    (*puint8_JobNum)++;  // 次の処理番号に移行する。
    int16_Return = -1;   // 処理継続
    break;

  case 1:
    // Start the Full Duplex Communication process
    // While the SPI in TransmitReceive process,
    //                      user can transmit data through
    //  "aTxBuffer" buffer & receive data through "aRxBuffer"
    hal_Status = HAL_SPI_TransmitReceive_DMA(pHandle_SPIx,
                   pstructParam_Handle_SPIx->puint8_aSPI_TxBuffer,
                   pstructParam_Handle_SPIx->puint8_aSPI_RxBuffer,
        (uint16_t)pstructParam_Handle_SPIx->int16_vSPI_TxNumber);
    if(hal_Status != HAL_OK){
      // Transfer error in transmission process

      // Disable the TIMx global Interrupt
      HAL_NVIC_DisableIRQ(DMA_Stream_IRQn_Transmit_SPIx);  // Transmit
      HAL_NVIC_DisableIRQ(DMA_Stream_IRQn_Receive_SPIx);  // Receive

      // NSS OFF
      HAL_GPIO_WritePin(pGPIOx_SPIx_NSS,
                        uint16_GPIO_Pin_x_SPIx_NSS,
                        GPIO_PIN_SET);

      // Release Semaphore
      pstructParam_Handle_SPIx->int16_vSPI_Semaphore = 0;

      *puint8_JobNum = 0;  // 処理番号初期化
      int16_Return = 1;    // NG終了
      break;
    }


    // タイムアウト値セット
    pstructParam_Handle_SPIx->uint16_vTimerSPI
        = (uint16_t)(pstructParam_Handle_SPIx->int16_vSPI_TxNumber * 3);


    (*puint8_JobNum)++;  // 次の処理番号に移行する。
    int16_Return = -1;   // 処理継続
    break;

  case 2:
    // Check Timer
    if(pstructParam_Handle_SPIx->uint16_vTimerSPI == 0){
      // タイムアウト
      // NSS OFF
      HAL_GPIO_WritePin(pGPIOx_SPIx_NSS,
                        uint16_GPIO_Pin_x_SPIx_NSS,
                        GPIO_PIN_SET);

      // Disable the TIMx global Interrupt
      HAL_NVIC_DisableIRQ(DMA_Stream_IRQn_Transmit_SPIx);  // Transmit
      HAL_NVIC_DisableIRQ(DMA_Stream_IRQn_Receive_SPIx);  // Receive

      // Release Semaphore
      pstructParam_Handle_SPIx->int16_vSPI_Semaphore = 0;

      *puint8_JobNum = 0;  // 処理番号初期化
      int16_Return = 1;    // NG終了 : Timeout
      break;
    }


    // 送受信終了待ち
    if(HAL_SPI_GetState(pHandle_SPIx) != HAL_SPI_STATE_READY){
      // 送受信が終了していない。
      int16_Return = -1;  // 処理継続
      break;  // 処理番号維持 : 現在の処理番号をループ
    }


    // Disable the TIMx global Interrupt
    HAL_NVIC_DisableIRQ(DMA_Stream_IRQn_Transmit_SPIx);  // Transmit
    HAL_NVIC_DisableIRQ(DMA_Stream_IRQn_Receive_SPIx);   // Receive


    //--------------------------
    // SPI送受信待ちの値セット
    //--------------------------
    int16_Value_Wait_SPI_TxRx = 10;


    (*puint8_JobNum)++;  // 次の処理番号に移行する。
    int16_Return = -1;   // 処理継続
    break;

  case 3:
    // SPI送受信待ち
    int16_Value_Wait_SPI_TxRx--;
    if(int16_Value_Wait_SPI_TxRx > 0){
      // 時間が経過していない。
      int16_Return = -1;  // 処理継続
      break;  // 処理番号維持 : 現在の処理番号をループ
    }


    // 送信終了時 NSS ON/OFF判定
    if(int16_NSS_OnOff == 0){
      // End : NSS OFF
      HAL_GPIO_WritePin(pGPIOx_SPIx_NSS,
                        uint16_GPIO_Pin_x_SPIx_NSS,
                        GPIO_PIN_SET);
    }


    // エラー判定
    if(pstructParam_Handle_SPIx->int16_vSPI_Error == 0){
      int16_Return = 0;  // OK
    }
    else{
      int16_Return = 1;  // NG
    }

    // Release Semaphore
    pstructParam_Handle_SPIx->int16_vSPI_Semaphore = 0;


    *puint8_JobNum = 0;  // 処理番号初期化
    // int16_Return : 結果
    break;

  default:
    // Release Semaphore
    pstructParam_Handle_SPIx->int16_vSPI_Semaphore = 0;

    *puint8_JobNum = 0;  // 処理番号初期化
    int16_Return = 1;    // NG
    break;
  }

  return(int16_Return);
}
