/*!
    \file    spi.c
    \brief   the spi configuration file

*/

#include "lisoc_test.h"
#include "spi.h"
#include "gpio.h"
#include "SPI_Register_Table_slv.h"
#include "interrupt_test.h"

/*****************************************************************************************
*spi flash select,pgio poarta 1
******************************************************************************************/
void spi_master_cs(uint8_t en)
{
  if (en)
  {
    /* QSPI CS = active low */
    gpiob_out(GPIOB_SPI_CS_OUT, OFF);
  }
  else
  {
    gpiob_out(GPIOB_SPI_CS_OUT, ON);
  }
}

/*!
    \brief      spi_master_init
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_master_init(void)
{
  gpiob_SetSPIMode();
  //gpiob_setPinDreict(GPIOB_SPI_CS_OUT, GPIO_OUT);

  //Disable DWC_ssi
  spi_master_disable();

  //Configure Master by writing CTRLR0. CTRLR1,BAUDR, TXFTLR, RXFTLR, IMR, SER,  SPI_CTRLR0 (if Dual/Quad SPI)
  //CTRLR0--TX 8BIT
  //SPI0_MST_CTRLR0 = 0x0107 | (1<<7) |(1<<6);
  spi_master_SetDataWidth(APB_SPI_DAT_FRM_SIZ_8bit);
  spi_master_SetPolarity(APB_SPI_CLOCK_POLARITY_LOW);
  spi_master_SetPhase(APB_SPI_CLOCK_PHASE_MIDDLE);
  spi_master_SetSpiFrmFormat(APB_SPI_SPI_FRF_STD);
  // CTRLR1

  //IMR
  spi_master_MaskInt(0x3E);
  //TXFTLR
  spi_master_SetFIFOTransThrsld(1);
  //RXFTLR
  spi_master_SetFIFORecvThrsld(7);

  // BAUDR
  spi_master_SetBaudrate(6);

  // SER slave enable
  spi_master_SelectSlave(APB_SPI_CS0);

  // Enable DWC_ss
  //spi_master_enable();

  //debug("SPI master init complete!\n");
}

/*!
    \brief      spi_master_send
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_master_send(uint8_t *buff, uint32_t txlen)
{
  unsigned int block_df;      /*the bumber of date frame block*/
  unsigned int resid_df;      /*the number of residuel data frame*/
  unsigned int i;         /*temporary variable*/
  uint8_t *txbuf = buff;

  //CTRLR0--TX 8BIT
  spi_master_SetMode(APB_SPI_TMOD_TX_RX);

  // Enable DWC_ss
  spi_master_enable();
  spi_master_cs(ON);

  block_df = txlen / APB_SPI_TXFIFO_DEPTH;
  resid_df = txlen % APB_SPI_TXFIFO_DEPTH;

  if(resid_df)
  {
    for(i = 0; i < resid_df; i++)
    {
      SPI0_MST_DR0 = *txbuf++;
      while((SPI0_MST_SR & 0x4) == 0x00);
    }
    while((SPI0_MST_SR & 0x5) != 0x4);
  }

  while(block_df)
  {
    for(i = 0; i < APB_SPI_TXFIFO_DEPTH; i++)
    {
      SPI0_MST_DR0 = *txbuf++;
      while((SPI0_MST_SR & 0x4) == 0x00);
    }
    block_df --;
    while((SPI0_MST_SR & 0x5) != 0x4);
  }

  spi_master_cs(OFF);
  //debug("spi send end!\n");
  // Disable DWC_ss
  spi_master_disable();

}

/*!
    \brief      spi_slave_init
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_slave_init(void)
{
  gpioa_SetSPIMode();

  //Disable DWC_ssi
  spi_slave_disable();

  //Configure Master by writing CTRLR0. CTRLR1,BAUDR, TXFTLR, RXFTLR, IMR, SER,  SPI_CTRLR0 (if Dual/Quad SPI)
  //CTRLR0-RX 8BIT
  //SPI0_SLV_CTRLR0 = 0x0007 | (1<<7) |(1<<6);
  spi_slave_SetDataWidth(APB_SPI_DAT_FRM_SIZ_8bit);
  spi_slave_SetSpiFrmFormat(APB_SPI_SPI_FRF_STD);
  spi_slave_SetMode(APB_SPI_TMOD_RX);
  spi_slave_SetSlaveSlectToggleEn(APB_SPI_TOGGLE_DISABLE);

  // CTRLR1

  // BAUDR--only master device valid

  //IMR
  spi_slave_MaskInt(0x3E);
  //TXFTLR
  spi_slave_SetFIFOTransThrsld(1);
  //RXFTLR
  spi_slave_SetFIFORecvThrsld(1);

  // SER slave enable--only master device valid

  // Enable DWC_ssi
  spi_slave_enable();

  //Read Rx FIFO
  //debug("SPI slave init complete!\n");
}

/*!
    \brief      spi_slave_recv
    \param[in]  none
    \param[out] none
    \retval     none
*/
uint32_t spi_slave_recv(uint8_t *buff, uint32_t rxlen)
{
  uint32_t rdata;
  uint32_t len;
  uint32_t actual_rx_len = 0;

  //while((SPI0_SLV_SR & 0x9) != 0x8);

  // Read SPI
  len = SPI0_SLV_RXFLR;
  while(len)
  {
    rdata = SPI0_SLV_DR0;
    //debug("slv r:%x\n",rdata);
    if(actual_rx_len < rxlen)
    {
      buff[actual_rx_len++] = rdata;
    }
    len --;
  }

  return actual_rx_len;
}

/*!
    \brief      spi_slave_recv
    \param[in]  none
    \param[out] none
    \retval     none
*/
uint32_t spi_slave_GetIntSts(void)
{
  return SPI0_SLV_ISR;
}

/*!
    \brief      spi_master_GetIntSts
    \param[in]  none
    \param[out] none
    \retval     none
*/
uint32_t spi_master_GetIntSts(void)
{
  return SPI0_MST_ISR;
}

/*!
    \brief      spi_master_GetIntSts
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_master_SetIntMask(uint32_t mask)
{
  SPI0_MST_IMR = mask;
}

/*!
    \brief      spi_slave_GetIntSts
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_slave_SetIntMask(uint32_t mask)
{
  SPI0_SLV_IMR = mask;
}

/*!
    \brief      spi_slave_GetIntSts
    \param[in]  none
    \param[out] none
    \retval     none
*/
uint32_t spi_slave_ClrIntSts(void)
{
  uint32_t reg;
  /* read register clear interrupt status. */
  reg = SPI0_SLV_ICR;
  return reg;
}

/*!
    \brief      spi_master_GetIntSts
    \param[in]  none
    \param[out] none
    \retval     none
*/
uint32_t spi_master_ClrIntSts(void)
{
  uint32_t reg;
  /* read register clear interrupt status. */
  reg = SPI0_MST_ICR;
  return reg;
}

/*!
    \brief      spi_slave_send
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_slave_send(uint8_t *buff, uint32_t txlen)
{
  uint32_t i = 0;
  debug("spi slave send!\n");

  //Disable DWC_ssi
  //spi_slave_disable();

  //slave tx
  //SPI0_SLV_CTRLR0 = 0x0107 | (1<<7) |(1<<6);
  //spi_slave_SetMode(APB_SPI_TMOD_TX);

  //Enable DWC_ssi
  //spi_slave_enable();

  for(i = 0; i < txlen; i++)
  {
    SPI0_SLV_DR0 = buff[i];
    //while((SPI0_SLV_SR & 0x4) == 0x00);
  }
  debug("slv fifo len:%d\n",SPI0_SLV_TXFLR);

#if 0
  while((SPI0_SLV_SR & 0x5) != 0x4)
  {
    debug("resid:%d\n",SPI0_SLV_TXFLR);
  }
#endif

  //debug("spi recv ok!\n");

}

/*!
    \brief      spi_master_recv
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_master_recv(uint8_t *buff, uint32_t rxlen)
{
#if 0
  uint32_t len;
  uint32_t rdata;
  debug("spi master recv!\n");

  //slave rx
  spi_master_SetMode(APB_SPI_TMOD_RX);
  //recv len
  SPI0_MST_CTRLR1 = rxlen - 1;
  spi_master_enable();
  spi_master_cs(ON);

  /* receive start. */
  SPI0_MST_DR0 = 0u;

  len = 0u;
  while (len < rxlen)
  {
    if(SPI0_MST_RXFLR > 0u)
    {
      buff[len] = SPI0_MST_DR0;
      debug("%02x\n",buff[len]);
      len ++;
    }
  }

  while(SPI0_MST_RXFLR > 0u)
  {
    rdata = SPI0_MST_DR0;
    debug("%02x\n",rdata);
    len ++;
  }

  spi_master_cs(OFF);
  //Disable DWC_ssi
  spi_master_disable();
#else
  uint32_t len;
  debug("spi master recv!\n");

  //slave rx
  spi_master_SetMode(APB_SPI_TMOD_TX_RX);
  spi_master_enable();
  debug("slv fifo len:%d\n",SPI0_SLV_TXFLR);
  spi_master_cs(ON);
  for(len = 0; len < rxlen; len++)
  {
    SPI0_MST_DR0 = 0;
    while((SPI0_MST_SR & 0x5) != 0x04);
    while(SPI0_MST_RXFLR > 0u)
    {
      buff[len] = SPI0_MST_DR0;
      debug("mst r:%02x\n",buff[len]);
    }
  }
  debug("slv fifo len:%d\n",SPI0_SLV_TXFLR);

  spi_master_cs(OFF);
  //Disable DWC_ssi
  spi_master_disable();

#endif
}
/*!
    \brief      spi_master_int_recv
    \param[in]  none
    \param[out] none
    \retval     none
*/
uint32_t spi_master_int_recv(uint8_t *buff, uint32_t rxlen)
{
  uint32_t rdata;
  uint32_t len;
  uint32_t actual_rx_len = 0;

  len = SPI0_MST_RXFLR;
  while(len)
  {
    rdata = SPI0_MST_DR0;
    //debug("mst r:%x\n",rdata);
    if(actual_rx_len < rxlen)
    {
      buff[actual_rx_len++] = rdata;
    }
    len --;
  }

  return actual_rx_len;
}

/**************************************************************************
* FreeRTOS SPI slave driver (Interrupt mode)
**************************************************************************/

uint32_t spis_state = SPIS_ST_IRQTEST;
TimerHandle_t spis_txtmo_tmr;

static uint16_t spis_txbuf[SPIS_TXBUF_SIZ];
static uint16_t spis_txlen;
static uint16_t spis_txcnt;

static uint16_t spis_rxbuf[SPIS_RXBUF_SIZ];
static uint16_t spis_rxbuf_w;
static uint16_t spis_rxbuf_r;
static uint16_t spis_rxovrflw;
static uint16_t spis_rxlen;
static uint16_t spis_rxcnt;


/**************************************************************************
* Description:  SPI slave Interrupt mode driver init
* Input:        none
* Output:       none
* Return:       none
**************************************************************************/
void spis_isr_init(void)
{

  /**************************************************************************
  * Init SPI slave Tx buffer
  **************************************************************************/
  spis_txlen = 0u;

  /**************************************************************************
  * Init SPI slave Rx ring buffer
  **************************************************************************/
  spis_rxbuf_w = 0u;
  spis_rxbuf_r = 0u;
  spis_rxovrflw = FALSE;

  /**************************************************************************
  * Forbid SPI ISR until we enter Tx/Rx mode
  **************************************************************************/
  NVIC_SetPriority(SPIS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 2u);
  LISOC_SPIS->IMR_W = 0u;

  spis_state = SPIS_ST_IDLE;
  LISOC_SPIS->SSIENR.SSI_EN = OFF;
  NVIC_EnableIRQ(SPIS_IRQn);

}


/**************************************************************************
* Description:  SPI slave Rx buffer write (1 16-bit word)
* Input:        dat:    16-bit word to be written into Rx ring buffer.
* Output:       none
* Return:       none
**************************************************************************/
void spis_rxbuf_wr(uint16_t dat)
{
  spis_rxbuf[spis_rxbuf_w] = dat;

  spis_rxbuf_w ++;
  if (spis_rxbuf_w == (uint16_t)SPIS_RXBUF_SIZ)
  {
    spis_rxbuf_w = 0u;
  }
}


/**************************************************************************
* Description:  SPI slave Rx buffer read (1 16-bit word)
* Input:        none
* Output:       none
* Return:       16-bit word read out from Rx ring buffer.
**************************************************************************/
uint16_t spis_rxbuf_rd(void)
{
  uint16_t dat = spis_rxbuf[spis_rxbuf_r];

  spis_rxbuf_r ++;
  if (spis_rxbuf_r == (uint16_t)SPIS_RXBUF_SIZ)
  {
    spis_rxbuf_r = 0u;
  }
  return dat;
}


/**************************************************************************
* Description:  SPI slave Rx ring buffer available space
* Input:        none
* Output:       none
* Return:       Number of 16-bit words that can be written into the Rx ring buffer.
**************************************************************************/
uint16_t spis_rxbuf_space(void)
{
  uint16_t w = spis_rxbuf_w;
  uint16_t r = spis_rxbuf_r;

  if (w >= r)
  {
    return SPIS_RXBUF_SIZ - 1u - (w - r);
  }
  else
  {
    return r - w - 1u;
  }
}


#ifdef CFG_RTOS
/**************************************************************************
* Description:  SPI slave Tx time-out timer callback function
* Input:        xTimer: timer handle.
* Output:       none
* Return:       none
**************************************************************************/
void spis_cb_txtmo(TimerHandle_t xTimer)
{
  uint16_t resp;
  (void) xTimer;

  /* Send Tx time-out indication message to upper layer task */
  resp = SPIS_TX_MSG_TMO;
  spis_txlen = 0u;
  xQueueSend(ADJ_Queue, (void *)&resp, NULL);
}
#endif

/**************************************************************************
* Description:  SPI slave Tx request
* Input:        tx_buf: array of 16-bit words to be sent out by SPI slave.
*               data_send: number of 16-bit words to be sent
*               timeout_ms: time-out value in milli-seconds.
* Output:       none
* Return:       1= pdPASS,    0= pdFAIL
* Note:         After returning success:
*               Driver emits SPIS_TX_MSG_SENT when Tx data is successfully sent,
*               Driver emits SPIS_TX_MSG_TMO when Tx timeout happens.
**************************************************************************/
BaseType_t spis_tx(const uint16_t * tx_buf, uint16_t data_send, uint16_t timeout_ms)
{
  uint16_t i;
  BaseType_t xTimer1Started;

  if (spis_txlen != 0u)
  {
    /**************************************************************************
    * Last Tx transaction not finished. Return failure to this Tx request.
    **************************************************************************/
    return pdFAIL;
  }
  else if (data_send > (uint16_t)(SPIS_TXBUF_SIZ + SPIS_HW_FIFO_SIZ))
  {
    /**************************************************************************
    * Tx data length too large.
    **************************************************************************/
    return pdFAIL;
  }

  /**************************************************************************
  * Kick off timeout timer
  **************************************************************************/
  xTimer1Started = xTimerChangePeriod( spis_txtmo_tmr,
                    timeout_ms,         /* time-out period */
                    0 );                /* effect immediately */
  if (xTimer1Started == pdFAIL)
  {
    return pdFAIL;
  }

  /**************************************************************************
  * SPI slave Tx processing
  **************************************************************************/
  LISOC_SPIS->SSIENR.SSI_EN = OFF;
  LISOC_SPIS->IMR_W = 0u;

  /* Set data width to 16 bit */
  LISOC_SPIS->CTRLR0.DFS = APB_SPI_DAT_FRM_SIZ_16bit;

  /* Set frame format to standard Motorola SPI */
  LISOC_SPIS->CTRLR0.FRF = APB_SPI_SPI_FRF_STD;

  /* Set work mode to Tx */
  LISOC_SPIS->CTRLR0.TMOD = APB_SPI_TMOD_TX;

  /* Disable slave select toggling */
  LISOC_SPIS->CTRLR0.SSTE = OFF;

  /* Transit to Tx mode, get prepared to accept Tx request */
  spis_state = SPIS_ST_TX;

  /**************************************************************************
  * Kick off SPI slave Tx
  **************************************************************************/
  LISOC_SPIS->SSIENR.SSI_EN = ON;

  /* Fill up Tx fifo */
  for (i = 0u; i < data_send && i < (uint16_t)SPIS_HW_FIFO_SIZ; i ++)
  {
    LISOC_SPIS->DR0_W = (uint32_t)(tx_buf[i]);
  }

  spis_txlen = data_send;
  if (data_send <= (uint16_t)SPIS_HW_FIFO_SIZ)
  {
    spis_txcnt = spis_txlen;
    /* Set TX FIFO empty threshold to 0 16-bit words */
    LISOC_SPIS->TXFTLR.TFT = 0u;
  }
  else
  {
    spis_txcnt = SPIS_HW_FIFO_SIZ;
    memcpy((void *)&spis_txbuf[0u], &tx_buf[SPIS_HW_FIFO_SIZ], 2u * (data_send - SPIS_HW_FIFO_SIZ));

    /* Set TX FIFO empty threshold to 4 16-bit words */
    LISOC_SPIS->TXFTLR.TFT = SPIS_TX_FIFO_THRES;
  }

  /* Writing 1 to IMR's TXE, TXO, RXU, RXO, RXF bits enables corresponding interrupt */
  LISOC_SPIS->IMR.TXEIM = 1u;

  return pdPASS;

}


/**************************************************************************
* Description:  SPI slave Rx request
* Input:        none
* Output:       none
* Return:       none
* Note:         After SPI slave Rx is kicked off,
*               Driver emits SPIS_RX_MSG_RCVD when a msg is successfully received,
*               Driver emits SPIS_RX_LEN_ERR when msg length field indicates the msg is too long.
*               Driver emits SPIS_RX_FIFO_OVRFLW when Rx ring buffer is full (the msg is dropped).
**************************************************************************/
void spis_rx(void)
{
  LISOC_SPIS->SSIENR.SSI_EN = OFF;

  /* Set data width to 16 bit */
  LISOC_SPIS->CTRLR0.DFS = APB_SPI_DAT_FRM_SIZ_16bit;

  /* Set frame format to standard Motorola SPI */
  LISOC_SPIS->CTRLR0.FRF = APB_SPI_SPI_FRF_STD;

  /* Set work mode to Rx */
  LISOC_SPIS->CTRLR0.TMOD = APB_SPI_TMOD_RX;

  /* Disable slave select toggling */
  LISOC_SPIS->CTRLR0.SSTE = OFF;

  /* Set RX FIFO full threshold to one 16-bit words */
  LISOC_SPIS->RXFTLR.RFT = 0u;

  /* Enable Rx FIFO full interrupt */
  LISOC_SPIS->IMR_W = 0u;
  LISOC_SPIS->IMR.RXFIM = 1u;

  spis_rxlen = 0u;
  spis_state = SPIS_ST_RX;

  spis_rxbuf_w = 0u;
  spis_rxbuf_r = 0u;
  spis_rxovrflw = FALSE;

  /**************************************************************************
  * Kick off SPI slave Rx
  **************************************************************************/
  LISOC_SPIS->SSIENR.SSI_EN = ON;
}


/**************************************************************************
* Description:  SPI slave IRQ handler
* Input:        none
* Output:       none
* Return:       none
**************************************************************************/
void SPISLV_Handler(void)
{
  uint16_t fifo_lvl;
  uint16_t len;
  uint16_t dat;
  uint16_t resp;

  /* Disable all SPI slave IRQs for now */
  LISOC_SPIS->IMR_W = 0u;

  /**************************************************************************
  * Design for compatibility with irq test
  **************************************************************************/
  if (spis_state == SPIS_ST_IRQTEST)
  {
    spi_slv_irq_handle();
    return;
  }
#ifdef CFG_RTOS

  /* A read of ICR clears TXO, RXU, and RXO interrupts */
  //(void)LISOC_SPIS->ICR_W;

  if (spis_state == SPIS_ST_IDLE)
  {
    /**************************************************************************
    * Do nothing before scheduler starts
    **************************************************************************/
  }
  else if (spis_state == SPIS_ST_RX)
  {
    fifo_lvl = (uint16_t)(LISOC_SPIS->RXFLR_W);
    if (fifo_lvl == (uint16_t)0u)
    {
      /* Failsafe processing for extra unwanted Rx IRQ */
      LISOC_SPIS->IMR.RXFIM = 1u;
      return;
    }
    if (spis_rxlen == (uint16_t)0u)
    {
      /* Interpret 1st received 16-bit word as param payload len */
      len = (uint16_t)(LISOC_SPIS->DR0_W);
      fifo_lvl --;
      if (len > (uint16_t)SPIS_MSG_PAYLOAD_SZ || len ==0)
      {
        len = 0;

        /* Report Rx length error */
        resp = SPIS_RX_LEN_ERR;
        xQueueSendToBackFromISR(ADJ_Queue, (void *)&resp, NULL);
        return;
      }
      /* Calculate number of words to be further received */
      spis_rxlen = len + SPIS_MSG_CRC_SZ;
      spis_rxcnt = 0u;

      if (SPIS_MSG_LEN_SZ + spis_rxlen <= spis_rxbuf_space())
      {
        spis_rxovrflw = FALSE;
        spis_rxbuf_wr(len);
      }
      else
      {
        spis_rxovrflw = TRUE;
        /* Report Rx fifo overflow error */
        resp = SPIS_RX_FIFO_OVRFLW;
        xQueueSendToBackFromISR(ADJ_Queue, (void *)&resp, NULL);
        return;
      }
    }

#if (CFG_SPIS_CASCADE_IRQ == 0)
    /**************************************************************************
    * Blocking mode Rx
    **************************************************************************/
    /* Read SPI Rx FIFO until the end of Rx message */
    while (spis_rxcnt < spis_rxlen)
    {
      fifo_lvl = (uint16_t)(LISOC_SPIS->RXFLR_W);
      spis_rxcnt += fifo_lvl;
      if (spis_rxcnt > spis_rxlen)
      {
        fifo_lvl = spis_rxlen - (spis_rxcnt - fifo_lvl);
        spis_rxcnt = spis_rxlen;
      }

      while (fifo_lvl != (uint16_t)0u)
      {
        dat = (uint16_t)(LISOC_SPIS->DR0_W);
        if (spis_rxovrflw == (uint16_t)FALSE)
        {
          spis_rxbuf_wr(dat);
        }
        fifo_lvl --;
      }
    }

#else
    /**************************************************************************
    * Cascading IRQ mode Rx
    **************************************************************************/
    /* Read SPI Rx FIFO until the end of Rx message, or until FIFO becomes empty */
    while ((fifo_lvl != (uint16_t)0u) && (spis_rxcnt < spis_rxlen))
    {
      spis_rxcnt += fifo_lvl;
      if (spis_rxcnt > spis_rxlen)
      {
        fifo_lvl = spis_rxlen - (spis_rxcnt - fifo_lvl);
        spis_rxcnt = spis_rxlen;
      }

      while (fifo_lvl != (uint16_t)0u)
      {
        dat = (uint16_t)(LISOC_SPIS->DR0_W);
        if (spis_rxovrflw == (uint16_t)FALSE)
        {
          spis_rxbuf_wr(dat);
        }
        fifo_lvl --;
      }
      fifo_lvl = (uint16_t)(LISOC_SPIS->RXFLR_W);
    }

    if (spis_rxcnt < spis_rxlen)
    {
      /* Rx message not finished yet. Expect further cascaded Rx IRQ */
      LISOC_SPIS->IMR.RXFIM = 1u;
      return;
    }
#endif

    /* Send Rx message notification to upper layer task */
    resp = SPIS_RX_MSG_RCVD;
    xQueueSendToBackFromISR(ADJ_Queue, (void *)&resp, NULL);

    /**************************************************************************
    * Get ready for new Rx message
    **************************************************************************/
    spis_rxlen = 0u;
    LISOC_SPIS->IMR.RXFIM = 1u;

  }
  else if (spis_state == SPIS_ST_TX)
  {
    if (spis_txcnt < spis_txlen)
    {
      /* Fill up Tx FIFO again */
      fifo_lvl = (uint16_t)(LISOC_SPIS->TXFLR_W);

      len = spis_txcnt + SPIS_HW_FIFO_SIZ - fifo_lvl;
      if (len > spis_txlen)
      {
        len = spis_txlen;
      }

      while (spis_txcnt < len)
      {
        LISOC_SPIS->DR0_W =(uint32_t)(spis_txbuf[spis_txcnt - SPIS_HW_FIFO_SIZ]);
        spis_txcnt ++;
      }

      if (spis_txcnt < spis_txlen)
      {
        /* Tx data sending not finished yet. Expect further IRQ */
        LISOC_SPIS->IMR.TXEIM = 1u;
        return;
      }

      /* Change TX FIFO empty threshold to 0 16-bit words */
      LISOC_SPIS->TXFTLR.TFT = 0u;

      /* Refresh Tx fifo depth */
      fifo_lvl = (uint16_t)(LISOC_SPIS->TXFLR_W);
      if (fifo_lvl != (uint16_t)0u)
      {
        /* There's still data in Tx fifo. Expect further IRQ */
        LISOC_SPIS->IMR.TXEIM = 1u;
        return;
      }
    }

    /* Make sure we have finished sending out all the bits */
    while (LISOC_SPIS->SR.BUSY == TRUE)
    {
      /* Do nothing */
    }

    /* Send "Tx message sent" notification to upper layer task */
    resp = SPIS_TX_MSG_SENT;
    xQueueSendToBackFromISR(ADJ_Queue, (void *)&resp, NULL);

    /**************************************************************************
    * Get prepared for next Tx/Rx processing
    **************************************************************************/
    spis_txlen = 0u;
    LISOC_SPIS->SSIENR.SSI_EN = OFF;
  }
  else
  {
    /* Do nothing */
  }
#endif
}


