/*
 * Copyright 2018 NXP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*****************************************************************************
*
* \file nxp_sja1124_lin.c
*
* \author NXP
*
* \brief Functions for the LIN driver
*
*****************************************************************************/

#include <SJA1124_Drv/nxp_sja1124_lin.h>

/*****************************************************************************
* FUNCTIONS
*****************************************************************************/

/* Internal device configuration. */
Lin_ConfigType linConfigInternal;

/*
* \brief The function Init initializes the LIN channels.
*
* \param[in] uint8_t device         - Device number (0..3 in case of 4 devices).
* \param[in] Lin_ConfigType* config - Pointer to LIN driver configuration set.
* \return Std_ReturnType            - E_OK: Send command has been accepted.
*                                     E_NOT_OK: Send command has not been accepted.
*/
Std_ReturnType Lin_Init(uint8_t device, const Lin_ConfigType* config)
{
  Std_ReturnType error;
  uint8_t sendBufferTemp[9];
  uint8_t ch;

  if((device >= SJA1124_NUM_OF_DEVICES) || (config == NULL) || (config->maxHWChannels > LIN_HW_MAX_MODULES))
  {
    return E_NOT_OK;
  }

  /* Store number of channels for internal use. */
  linConfigInternal.maxHWChannels = config->maxHWChannels;

  /* config->linChannel[0]  = device 1, channel 1
   * config->linChannel[1]  = device 1, channel 2
   * config->linChannel[4]  = device 2, channel 1
   * config->linChannel[5]  = device 2, channel 2
   * config->linChannel[15] = device 4, channel 4 etc.
   */

  for(ch = 0; ch < 4; ch++)
  {
    sendBufferTemp[0] = 0x00u;
    sendBufferTemp[1] = 0x00u;

    error = SJA1124_RWRegister(device, false, SJA1124_LCOM1_ADDR, 2, sendBufferTemp, NULL);
    if(error != E_OK)
    {
      return error;
    }

    /* LCFG1 register - with INIT bit set. */
    sendBufferTemp[0] = ((uint8_t)config->linChannel[(device * 4) + ch].checksumCalcDisable << SJA1124_LIN1CFG1_CSCALCDIS_SHIFT) & SJA1124_LIN1CFG1_CSCALCDIS_MASK;
    sendBufferTemp[0] |= ((uint8_t)config->linChannel[(device * 4) + ch].masterBreakLength << SJA1124_LIN1CFG1_MASBREAKLEN_SHIFT) & SJA1124_LIN1CFG1_MASBREAKLEN_MASK;
    sendBufferTemp[0] |= ((uint8_t)config->linChannel[(device * 4) + ch].sleepMode << SJA1124_LIN1CFG1_SLEEP_SHIFT) & SJA1124_LIN1CFG1_SLEEP_MASK;
    sendBufferTemp[0] |= (1u << SJA1124_LIN1CFG1_INIT_SHIFT) & SJA1124_LIN1CFG1_INIT_MASK;
    /* LCFG2 register. */
    sendBufferTemp[1] = ((uint8_t)config->linChannel[(device * 4) + ch].twoBitDelimiter << SJA1124_LIN1CFG2_TWOBITDELIM_SHIFT) & SJA1124_LIN1CFG2_TWOBITDELIM_MASK;
    sendBufferTemp[1] |= ((uint8_t)config->linChannel[(device * 4) + ch].idleOnBitError << SJA1124_LIN1CFG2_IDLEONBITERR_SHIFT) & SJA1124_LIN1CFG2_IDLEONBITERR_MASK;
    /* LITC register. */
    sendBufferTemp[2] = ((uint8_t)config->linChannel[(device * 4) + ch].idleOnTimeout << SJA1124_LIN1ITC_IDLEONTIMEOUT_SHIFT) & SJA1124_LIN1ITC_IDLEONTIMEOUT_MASK;
    /* LGC register. */
    sendBufferTemp[3] = ((uint8_t)config->linChannel[(device * 4) + ch].stopBits << SJA1124_LIN1GC_STOPBITCONF_SHIFT) & SJA1124_LIN1GC_STOPBITCONF_MASK;
    sendBufferTemp[3] |= (0u << SJA1124_LIN1GC_SOFTRESET_SHIFT) & SJA1124_LIN1GC_SOFTRESET_MASK;
    /* LRTC register. */
    sendBufferTemp[4] = (config->linChannel[(device * 4) + ch].responseTimeout << SJA1124_LIN1RTC_RESPTIMEOUT_SHIFT) & SJA1124_LIN1RTC_RESPTIMEOUT_MASK;
    /* LFR register. */
    sendBufferTemp[5] = (config->linChannel[(device * 4) + ch].fracBaudrate << SJA1124_LIN1FR_FRACBAUDRATE_SHIFT) & SJA1124_LIN1FR_FRACBAUDRATE_MASK;
    /* LBRM and LBRL registers. */
    sendBufferTemp[6] = (uint8_t)((config->linChannel[(device * 4) + ch].intBaudrate & 0xFF00u) >> 8);
    sendBufferTemp[7] = (uint8_t)(config->linChannel[(device * 4) + ch].intBaudrate & 0x00FFu);
    /* LIE register. */
    sendBufferTemp[8] = config->linChannel[(device * 4) + ch].lie;

    error = SJA1124_RWRegister(device, false, (SJA1124_LIN1CFG1_ADDR + 0x30u * ch), 9, sendBufferTemp, NULL);
    if(error != E_OK)
    {
      return error;
    }

    /* Clear INIT bit in LCFG1 register. */
    sendBufferTemp[0] = sendBufferTemp[0] & 0xFEu;

    error = SJA1124_RWRegister(device, false, (SJA1124_LIN1CFG1_ADDR + 0x30u * ch), 1, sendBufferTemp, NULL);
    if(error != E_OK)
    {
      return error;
    }
  }

  return error;
}

/*
* \brief The function SendFrame sends the header part (Break Field,
*        Synch Byte Field and PID Field) and, depending on the direction
*        of the frame response, a complete LIN response part of a LIN
*        frame on the addressed LIN channel.
*
* \param[in] uint8_t channel     - LIN channel to be addressed (0..15 in case of 16 channels).
* \param[in] Lin_PduType* pduPtr - Pointer to PDU containing the PID, checksum model,
*                                  response type, Dl and SDU data pointer.
* \param[in] bool sendFrame      - true: Send the frame when calling this function.
*                                - false: Prepare necessary data, but don't send the frame
*                                         (might be used for synchronized frame sending).
* \return Std_ReturnType         - E_OK: Send command has been accepted.
*                                  E_NOT_OK: Send command has not been accepted.
*/
Std_ReturnType Lin_SendFrame(uint8_t channel, Lin_PduType* pduPtr, bool sendFrame)
{
  Std_ReturnType error;
  uint8_t sendBufferTemp[12];
  uint8_t dev, ch, bytes;
  uint8_t i;

  if((pduPtr == NULL) || (channel >= linConfigInternal.maxHWChannels))
  {
    return E_NOT_OK;
  }

  /* Get device number from channel number. */
  dev = channel / 4;
  /* Get corresponding channel of the device. */
  ch = channel - (4 * dev);
  /* Get number of data bytes. */
  bytes = pduPtr->dfl + 1;

  /* LC register. */
  sendBufferTemp[0] = ((uint8_t)sendFrame << SJA1124_LIN1C_HEADERTRANSREQ_SHIFT) & SJA1124_LIN1C_HEADERTRANSREQ_MASK;
  /* LBI register. */
  sendBufferTemp[1] = (pduPtr->id << SJA1124_LIN1BI_IDENTIFIER_SHIFT) & SJA1124_LIN1BI_IDENTIFIER_MASK;
  /* LBC register. */
  sendBufferTemp[2] = (pduPtr->dfl << SJA1124_LIN1BC_DTFIELDLEN_SHIFT) & SJA1124_LIN1BC_DTFIELDLEN_MASK;
  sendBufferTemp[2] |= ((uint8_t)pduPtr->dir << SJA1124_LIN1BC_DIRECTION_SHIFT) & SJA1124_LIN1BC_DIRECTION_MASK;
  sendBufferTemp[2] |= ((uint8_t)pduPtr->ccs << SJA1124_LIN1BC_CLASSICCS_SHIFT) & SJA1124_LIN1BC_CLASSICCS_MASK;
  if(pduPtr->dir == LIN_MASTER_RESPONSE)
  {
    /* LCF register. */
    sendBufferTemp[3] = pduPtr->cf;
    /* LBDx registers. */
    for(i = 0; i < bytes; i++)
    {
      sendBufferTemp[i + 4] = pduPtr->data[i];
    }

    error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1C_ADDR + 0x30u * ch), bytes + 4, sendBufferTemp, NULL);
  }
  else
  {
    error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1C_ADDR + 0x30u * ch), 3, sendBufferTemp, NULL);
  }
  return error;
}

/*
* \brief The function GoToSleep sends a go-to-sleep command on the addressed LIN channel
*        and puts corresponding master channel to sleep.
*
* \param[in] uint8_t channel - LIN channel to be addressed (0..15 in case of 16 channels).
* \return Std_ReturnType     - E_OK: Sleep command has been accepted.
*                              E_NOT_OK: Sleep command has not been accepted.
*/
Std_ReturnType Lin_GoToSleep(uint8_t channel)
{
  Std_ReturnType error;
  uint8_t sendBufferTemp[1];
  uint8_t rcvBufferTemp[1];
  Lin_PduType goToSleepCommand;
  uint8_t linPduData[8] = { 0x00U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU };
  uint8_t dev, ch, i;

  goToSleepCommand.id = 0x3CU;
  goToSleepCommand.dfl = 7U;
  goToSleepCommand.dir = LIN_MASTER_RESPONSE;
  goToSleepCommand.ccs = LIN_ENHANCED_CS;
  goToSleepCommand.cf = 0xC3U;
  for(i = 0; i < 8; i++)
  {
    goToSleepCommand.data[i] = linPduData[i];
  }

  /* Send go-to-sleep command. */
  error = Lin_SendFrame(channel, &goToSleepCommand, true);
  if(error != E_OK)
  {
    return error;
  }

  /* Get device number from channel number. */
  dev = channel / 4;
  /* Get corresponding channel of the device. */
  ch = channel - (4 * dev);

  /* Set SLEEP bit in LCFG1 register - read LCFG1, set SLEEP bit, write LCFG1. */
  error = SJA1124_RWRegister(dev, true, (SJA1124_LIN1CFG1_ADDR + 0x30u * ch), 1, NULL, rcvBufferTemp);
  if(error != E_OK)
  {
    return error;
  }

  sendBufferTemp[0] = rcvBufferTemp[0] | SJA1124_LIN1CFG1_SLEEP_MASK;
  error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1CFG1_ADDR + 0x30u * ch), 1, sendBufferTemp, NULL);

  return error;
}

/*
* \brief The function Wakeup wakes up corresponding master channel
*        and sends a wake-up command on the addressed LIN channel.
*
* \param[in] uint8_t channel - LIN channel to be addressed (0..15 in case of 16 channels).
* \return Std_ReturnType     - E_OK: Wake-up request has been accepted.
*                              E_NOT_OK: Wake-up request has not been accepted.
*/
Std_ReturnType Lin_Wakeup(uint8_t channel)
{
  Std_ReturnType error;
  uint8_t sendBufferTemp[1];
  uint8_t rcvBufferTemp[1];
  uint8_t dev, ch;

  /* Get device number from channel number. */
  dev = channel / 4;
  /* Get corresponding channel of the device. */
  ch = channel - (4 * dev);

  /* Clear SLEEP bit in LCFG1 register - read LCFG1, clear SLEEP bit, write LCFG1. */
  error = SJA1124_RWRegister(dev, true, (SJA1124_LIN1CFG1_ADDR + 0x30u * ch), 1, NULL, rcvBufferTemp);
  sendBufferTemp[0] = rcvBufferTemp[0] & (~SJA1124_LIN1CFG1_SLEEP_MASK);
  error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1CFG1_ADDR + 0x30u * ch), 1, sendBufferTemp, NULL);
  if(error != E_OK)
  {
    return error;
  }

  /* Wake-up data in LBD1 register. */
  sendBufferTemp[0] = 0xF0U;
  error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1BD1_ADDR + 0x30u * ch), 1, sendBufferTemp, NULL);
  if(error != E_OK)
  {
    return error;
  }

  /* Writing WURQ bit in LC register - wake-up request, sends the data in LBD1. */
  sendBufferTemp[0] = (1u << SJA1124_LIN1C_WAKEUPREQ_SHIFT) & SJA1124_LIN1C_WAKEUPREQ_MASK;
  error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1C_ADDR + 0x30u * ch), 1, sendBufferTemp, NULL);

  return error;
}

/*
* \brief The function GetStatus shall return the current transmission,
*        reception or operation status of the LIN driver. Status bits
*        are cleared afterwards if any are set. If slave response is
*        expected, the function also returns the response and checksum.
*
* \param[in] uint8_t channel      - LIN channel to be checked (0..15 in case of 16 channels).
* \param[in] Lin_PduType* pduPtr  - Pointer to a buffer or memory where the current PDU is stored.
* \param[out] Lin_SduType* sduPtr - Pointer to a buffer or memory where the current SDU is stored.
* \return Lin_StatusType          - LIN status response:
*                                     - LIN_NOT_OK: Development or production error occurred.
*                                     - LIN_CH_OPERATIONAL: Normal state operation, sub-states are:
*                                         - LIN_TX_OK: Successful transmission
*                                         - LIN_TX_BUSY: Ongoing transmission (Header or Response).
*                                         - LIN_TX_HEADER_ERROR: Erroneous header transmission such as:
*                                             - Mismatch between sent and read back data.
*                                             - Identifier parity error or Physical bus error.
*                                         - LIN_TX_ERROR: Erroneous response transmission such as:
*                                             - Mismatch between sent and read back data.
*                                             - Physical bus error
*                                         - LIN_RX_OK: Reception of correct response.
*                                         - LIN_RX_BUSY: Ongoing reception: at least one response byte
*                                           has been received, but the checksum byte has not been received.
*                                         - LIN_RX_ERROR: Erroneous response reception such as:
*                                             - Framing error,
*                                             - Overrun error,
*                                             - Checksum error or Short response.
*                                         - LIN_RX_NO_RESPONSE: No response byte has been received so far.
*                                         - LIN_OPERATIONAL: Normal operation; the related LIN channel
*                                           is just initialized or waked up from the LIN_CH_SLEEP
*                                           and no data has been sent.
*                                     - LIN_CH_SLEEP: Sleep state operation; in this state wake-up
*                                       detection from slave nodes is enabled.
*/
Lin_StatusType Lin_GetStatus(uint8_t channel, Lin_PduType* pduPtr, Lin_SduType* sduPtr)
{
  Lin_StatusType status = LIN_NOT_OK;
  Std_ReturnType error;
  uint8_t sendBufferTemp[2];
  uint8_t rcvBufferTemp[12];
  uint8_t dev, ch, i;

  if((sduPtr == NULL) || (channel >= linConfigInternal.maxHWChannels))
  {
    return LIN_NOT_OK;
  }

  /* Get device number from channel number. */
  dev = channel / 4;
  /* Get corresponding channel of the device. */
  ch = channel - (4 * dev);

  if(pduPtr->dir == LIN_MASTER_RESPONSE)
  {
    /* Read channel status registers. */
    error = SJA1124_RWRegister(dev, true, (SJA1124_LIN1STATE_ADDR + 0x30u * ch), 3, NULL, rcvBufferTemp);
  }
  else
  {
    /* Read channel status and data registers. */
    error = SJA1124_RWRegister(dev, true, (SJA1124_LIN1STATE_ADDR + 0x30u * ch), (pduPtr->dfl + 5), NULL, rcvBufferTemp);
  }

  if(error != E_OK)
  {
    return LIN_NOT_OK;
  }
  else
  {
    /* LSTATE register. */
    sduPtr->rxbsy = (bool)((rcvBufferTemp[0] & SJA1124_LIN1STATE_RCVBUSY_MASK) >> SJA1124_LIN1STATE_RCVBUSY_SHIFT);
    sduPtr->lins = (rcvBufferTemp[0] & SJA1124_LIN1STATE_LINSTATE_MASK) >> SJA1124_LIN1STATE_LINSTATE_SHIFT;
    /* LES register. */
    sduPtr->les = rcvBufferTemp[1];
    /* LS register. */
    sduPtr->ls = rcvBufferTemp[2];
    /* Read checksum and data if expected. */
    if(pduPtr->dir == LIN_SLAVE_RESPONSE)
    {
      /* LCF register. */
      sduPtr->cf = rcvBufferTemp[3];
      /* LBDx registers. */
      for(i = 0; i < (pduPtr->dfl + 1); i++)
      {
        sduPtr->data[i] = rcvBufferTemp[i + 4];
      }
    }

    if(sduPtr->les == 0)
    {
      if(sduPtr->ls & SJA1124_LIN1S_TRANSCOMPFLG_MASK)
      {
        status = LIN_TX_OK;
      }
      else if(sduPtr->ls & SJA1124_LIN1S_RCVCOMPFLG_MASK)
      {
        status = LIN_RX_OK;
      }
      else if(sduPtr->ls & SJA1124_LIN1S_RCVBUFFFULLFLG_MASK)
      {
        status = LIN_RX_BUSY;
      }
      else
      {
        if(sduPtr->lins == 0)
        {
          status = LIN_CH_SLEEP;
        }
        else if(sduPtr->lins == 2)
        {
          status = LIN_OPERATIONAL;
        }
        else if(sduPtr->lins > 2)
        {
          status = LIN_TX_BUSY;
        }
        else
        {
          status = LIN_NOT_OK;
        }
      }
    }
    else if(sduPtr->les & SJA1124_LIN1ES_BITERRFLG_MASK)
    {
      if((sduPtr->lins >= 3) && (sduPtr->lins <=6))
      {
        status = LIN_TX_HEADER_ERROR;
      }
      else if((sduPtr->lins >= 7) && (sduPtr->lins <=9))
      {
        status = LIN_TX_ERROR;
      }
      else
      {
        status = LIN_NOT_OK;
      }
    }
    else if((sduPtr->les == 1) || (sduPtr->les == 65))
    {
      status = LIN_TX_ERROR;
    }
    else if(sduPtr->les == 64)
    {
      status = LIN_RX_NO_RESPONSE;
    }
    else
    {
      status = LIN_RX_ERROR;
    }

    sendBufferTemp[0] = rcvBufferTemp[1];
    sendBufferTemp[1] = rcvBufferTemp[2];

    /* Clear status flags if any are set. */
    if((rcvBufferTemp[1] != 0) && (rcvBufferTemp[2] != 0))
    {
      error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1ES_ADDR + 0x30u * ch), 2, sendBufferTemp, NULL);
    }
    else if(rcvBufferTemp[1] != 0)
    {
      error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1ES_ADDR + 0x30u * ch), 1, &sendBufferTemp[0], NULL);
    }
    else if(rcvBufferTemp[2] != 0)
    {
      error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1S_ADDR + 0x30u * ch), 1, &sendBufferTemp[1], NULL);
    }

    if(error != E_OK)
    {
      return LIN_NOT_OK;
    }
  }

  return status;
}

/*
* \brief The function GetStatusFast shall return the current transmission,
*        reception or operation status of the LIN driver. Status bits
*        are cleared during the same transmission. If slave response is
*        expected, the function also returns the response and checksum.
*
* \param[in] uint8_t channel      - LIN channel to be checked (0..15 in case of 16 channels).
* \param[in] Lin_PduType* pduPtr  - Pointer to a buffer or memory where the current PDU is stored.
* \param[out] Lin_SduType* sduPtr - Pointer to a buffer or memory where the current SDU is stored.
* \return Lin_StatusType          - LIN status response:
*                                     - LIN_NOT_OK: Development or production error occurred.
*                                     - LIN_CH_OPERATIONAL: Normal state operation, sub-states are:
*                                         - LIN_TX_OK: Successful transmission
*                                         - LIN_TX_BUSY: Ongoing transmission (Header or Response).
*                                         - LIN_TX_HEADER_ERROR: Erroneous header transmission such as:
*                                             - Mismatch between sent and read back data.
*                                             - Identifier parity error or Physical bus error.
*                                         - LIN_TX_ERROR: Erroneous response transmission such as:
*                                             - Mismatch between sent and read back data.
*                                             - Physical bus error
*                                         - LIN_RX_OK: Reception of correct response.
*                                         - LIN_RX_BUSY: Ongoing reception: at least one response byte
*                                           has been received, but the checksum byte has not been received.
*                                         - LIN_RX_ERROR: Erroneous response reception such as:
*                                             - Framing error,
*                                             - Overrun error,
*                                             - Checksum error or Short response.
*                                         - LIN_RX_NO_RESPONSE: No response byte has been received so far.
*                                         - LIN_OPERATIONAL: Normal operation; the related LIN channel
*                                           is just initialized or waked up from the LIN_CH_SLEEP
*                                           and no data has been sent.
*                                     - LIN_CH_SLEEP: Sleep state operation; in this state wake-up
*                                       detection from slave nodes is enabled.
*/
Lin_StatusType Lin_GetStatusFast(uint8_t channel, Lin_PduType* pduPtr, Lin_SduType* sduPtr)
{
  Lin_StatusType status = LIN_NOT_OK;
  Std_ReturnType error;
  uint8_t sendBufferTemp[12] = { 0x00u, 0xF1u, 0x46u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u };
  uint8_t rcvBufferTemp[12];
  uint8_t dev, ch, i;

  if((sduPtr == NULL) || (channel >= linConfigInternal.maxHWChannels))
  {
    return LIN_NOT_OK;
  }

  /* Get device number from channel number. */
  dev = channel / 4;
  /* Get corresponding channel of the device. */
  ch = channel - (4 * dev);

  if(pduPtr->dir == LIN_MASTER_RESPONSE)
  {
    /* Read and clear channel status registers. */
    error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1STATE_ADDR + 0x30u * ch), 3, sendBufferTemp, rcvBufferTemp);
  }
  else
  {
    /* Read and clear channel status and data registers. */
    error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1STATE_ADDR + 0x30u * ch), (pduPtr->dfl + 5), sendBufferTemp, rcvBufferTemp);
  }

  if(error != E_OK)
  {
    return LIN_NOT_OK;
  }
  else
  {
    /* LSTATE register. */
    sduPtr->rxbsy = (bool)((rcvBufferTemp[0] & SJA1124_LIN1STATE_RCVBUSY_MASK) >> SJA1124_LIN1STATE_RCVBUSY_SHIFT);
    sduPtr->lins = (rcvBufferTemp[0] & SJA1124_LIN1STATE_LINSTATE_MASK) >> SJA1124_LIN1STATE_LINSTATE_SHIFT;
    /* LES register. */
    sduPtr->les = rcvBufferTemp[1];
    /* LS register. */
    sduPtr->ls = rcvBufferTemp[2];
    /* Read checksum and data if expected. */
    if(pduPtr->dir == LIN_SLAVE_RESPONSE)
    {
      /* LCF register. */
      sduPtr->cf = rcvBufferTemp[3];
      /* LBDx registers. */
      for(i = 0; i < (pduPtr->dfl + 1); i++)
      {
        sduPtr->data[i] = rcvBufferTemp[i + 4];
      }
    }

    if(sduPtr->les == 0)
    {
      if(sduPtr->ls & SJA1124_LIN1S_TRANSCOMPFLG_MASK)
      {
        status = LIN_TX_OK;
      }
      else if(sduPtr->ls & SJA1124_LIN1S_RCVCOMPFLG_MASK)
      {
        status = LIN_RX_OK;
      }
      else if(sduPtr->ls & SJA1124_LIN1S_RCVBUFFFULLFLG_MASK)
      {
        status = LIN_RX_BUSY;
      }
      else
      {
        if(sduPtr->lins == 0)
        {
          status = LIN_CH_SLEEP;
        }
        else if(sduPtr->lins == 2)
        {
          status = LIN_OPERATIONAL;
        }
        else if(sduPtr->lins > 2)
        {
          status = LIN_TX_BUSY;
        }
        else
        {
          status = LIN_NOT_OK;
        }
      }
    }
    else if(sduPtr->les & SJA1124_LIN1ES_BITERRFLG_MASK)
    {
      if((sduPtr->lins >= 3) && (sduPtr->lins <=6))
      {
        status = LIN_TX_HEADER_ERROR;
      }
      else if((sduPtr->lins >= 7) && (sduPtr->lins <=9))
      {
        status = LIN_TX_ERROR;
      }
      else
      {
        status = LIN_NOT_OK;
      }
    }
    else if((sduPtr->les == 1) || (sduPtr->les == 65))
    {
      status = LIN_TX_ERROR;
    }
    else if(sduPtr->les == 64)
    {
      status = LIN_RX_NO_RESPONSE;
    }
    else
    {
      status = LIN_RX_ERROR;
    }
  }

  return status;
}

/*
* \brief The function GetStatusPoll shall return the current transmission,
*        reception or operation status of the LIN driver. Status bits
*        are cleared during the same transmission.
*
* \param[in] uint8_t channel - LIN channel to be checked (0..15 in case of 16 channels).
* \return Lin_StatusType     - LIN status response:
*                                - LIN_NOT_OK: Development or production error occurred.
*                                - LIN_CH_OPERATIONAL: Normal state operation, sub-states are:
*                                    - LIN_TX_OK: Successful transmission
*                                    - LIN_TX_BUSY: Ongoing transmission (Header or Response).
*                                    - LIN_TX_HEADER_ERROR: Erroneous header transmission such as:
*                                        - Mismatch between sent and read back data.
*                                        - Identifier parity error or Physical bus error.
*                                    - LIN_TX_ERROR: Erroneous response transmission such as:
*                                        - Mismatch between sent and read back data.
*                                        - Physical bus error
*                                    - LIN_RX_OK: Reception of correct response.
*                                    - LIN_RX_BUSY: Ongoing reception: at least one response byte
*                                      has been received, but the checksum byte has not been received.
*                                    - LIN_RX_ERROR: Erroneous response reception such as:
*                                        - Framing error,
*                                        - Overrun error,
*                                        - Checksum error or Short response.
*                                    - LIN_RX_NO_RESPONSE: No response byte has been received so far.
*                                    - LIN_OPERATIONAL: Normal operation; the related LIN channel
*                                      is just initialized or waked up from the LIN_CH_SLEEP
*                                      and no data has been sent.
*                                - LIN_CH_SLEEP: Sleep state operation; in this state wake-up
*                                  detection from slave nodes is enabled.
*/
Lin_StatusType Lin_GetStatusPoll(uint8_t channel)
{
  Lin_SduType sduPtr;
  Lin_StatusType status = LIN_NOT_OK;
  Std_ReturnType error;
  uint8_t sendBufferTemp[3] = { 0x00u, 0xF1u, 0x46u };
  uint8_t rcvBufferTemp[3];
  uint8_t dev, ch;

  if(channel >= linConfigInternal.maxHWChannels)
  {
    return LIN_NOT_OK;
  }

  /* Get device number from channel number. */
  dev = channel / 4;
  /* Get corresponding channel of the device. */
  ch = channel - (4 * dev);

  /* Read and clear channel status registers. */
  error = SJA1124_RWRegister(dev, false, (SJA1124_LIN1STATE_ADDR + 0x30u * ch), 3, sendBufferTemp, rcvBufferTemp);

  if(error != E_OK)
  {
    return LIN_NOT_OK;
  }
  else
  {
    /* LSTATE register. */
    sduPtr.rxbsy = (bool)((rcvBufferTemp[0] & SJA1124_LIN1STATE_RCVBUSY_MASK) >> SJA1124_LIN1STATE_RCVBUSY_SHIFT);
    sduPtr.lins = (rcvBufferTemp[0] & SJA1124_LIN1STATE_LINSTATE_MASK) >> SJA1124_LIN1STATE_LINSTATE_SHIFT;
    /* LES register. */
    sduPtr.les = rcvBufferTemp[1];
    /* LS register. */
    sduPtr.ls = rcvBufferTemp[2];

    if(sduPtr.les == 0)
    {
      if(sduPtr.ls & SJA1124_LIN1S_TRANSCOMPFLG_MASK)
      {
        status = LIN_TX_OK;
      }
      else if(sduPtr.ls & SJA1124_LIN1S_RCVCOMPFLG_MASK)
      {
        status = LIN_RX_OK;
      }
      else if(sduPtr.ls & SJA1124_LIN1S_RCVBUFFFULLFLG_MASK)
      {
        status = LIN_RX_BUSY;
      }
      else
      {
        if(sduPtr.lins == 0)
        {
          status = LIN_CH_SLEEP;
        }
        else if(sduPtr.lins == 2)
        {
          status = LIN_OPERATIONAL;
        }
        else if(sduPtr.lins > 2)
        {
          status = LIN_TX_BUSY;
        }
        else
        {
          status = LIN_NOT_OK;
        }
      }
    }
    else if(sduPtr.les & SJA1124_LIN1ES_BITERRFLG_MASK)
    {
      if((sduPtr.lins >= 3) && (sduPtr.lins <=6))
      {
        status = LIN_TX_HEADER_ERROR;
      }
      else if((sduPtr.lins >= 7) && (sduPtr.lins <=9))
      {
        status = LIN_TX_ERROR;
      }
      else
      {
        status = LIN_NOT_OK;
      }
    }
    else if((sduPtr.les == 1) || (sduPtr.les == 65))
    {
      status = LIN_TX_ERROR;
    }
    else if(sduPtr.les == 64)
    {
      status = LIN_RX_NO_RESPONSE;
    }
    else
    {
      status = LIN_RX_ERROR;
    }
  }

  return status;
}
