text: /**
  * \copyright
  * MIT License
  *
  * Copyright (c) 2020 Infineon Technologies AG
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be included in all
  * copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE
  *
  * \endcopyright
  *
  * \author Infineon Technologies AG
  *
  * \file pal_i2c.c
  *
  * \brief   This file implements the platform abstraction layer(pal) APIs for I2C.
  *
  * \ingroup  grPAL
  *
  * @{
  */
  
  
  
  #include <DAVE.h>
  #include "optiga/pal/pal_i2c.h"
  
  #define PAL_I2C_MASTER_MAX_BITRATE  (400U)
  /// @cond hidden
  
  _STATIC_H volatile uint32_t g_entry_count = 0;
  _STATIC_H const pal_i2c_t * gp_pal_i2c_current_ctx;
  
  //lint --e{715} suppress "This is implemented for overall completion of API"
  _STATIC_H pal_status_t pal_i2c_acquire(const void * p_i2c_context)
  {
      if (0 == g_entry_count)
      {
          g_entry_count++;
          if (1 == g_entry_count)
          {
              return PAL_STATUS_SUCCESS;
          }
      }
      return PAL_STATUS_FAILURE;
  }
  
  //lint --e{715} suppress "The unused p_i2c_context variable is kept for future enhancements"
  _STATIC_H void pal_i2c_release(const void * p_i2c_context)
  {
      g_entry_count = 0;
  }
  /// @endcond
  
  void invoke_upper_layer_callback (const pal_i2c_t * p_pal_i2c_ctx, optiga_lib_status_t event)
  {
      upper_layer_callback_t upper_layer_handler;
      //lint --e{611} suppress "void* function pointer is type casted to upper_layer_callback_t type"
      upper_layer_handler = (upper_layer_callback_t)p_pal_i2c_ctx->upper_layer_event_handler;
  
      upper_layer_handler(p_pal_i2c_ctx->p_upper_layer_ctx, event);
  
      //Release I2C Bus
      pal_i2c_release(p_pal_i2c_ctx->p_upper_layer_ctx);
  }
  
  /// @cond hidden
  void i2c_master_end_of_transmit_callback(void)
  {
      invoke_upper_layer_callback(gp_pal_i2c_current_ctx, PAL_I2C_EVENT_SUCCESS);
  }
  
  void i2c_master_end_of_receive_callback(void)
  {
      invoke_upper_layer_callback(gp_pal_i2c_current_ctx, PAL_I2C_EVENT_SUCCESS);
  }
  
  void i2c_master_error_detected_callback(void)
  {
      I2C_MASTER_t * p_i2c_master;
  
      p_i2c_master = gp_pal_i2c_current_ctx->p_i2c_hw_config;
      if (0 != I2C_MASTER_IsTxBusy(p_i2c_master))
      {
          //lint --e{534} suppress "Error handling is not required so return value is not checked"
          I2C_MASTER_AbortTransmit(p_i2c_master);
          while (I2C_MASTER_IsTxBusy(p_i2c_master)){}
      }
  
      if (0 != I2C_MASTER_IsRxBusy(p_i2c_master))
      {
          //lint --e{534} suppress "Error handling is not required so return value is not checked"
          I2C_MASTER_AbortReceive(p_i2c_master);
          while (I2C_MASTER_IsRxBusy(p_i2c_master)){}
      }
  
      invoke_upper_layer_callback(gp_pal_i2c_current_ctx, PAL_I2C_EVENT_ERROR);
  }
  
  void i2c_master_nack_received_callback(void)
  {
      i2c_master_error_detected_callback();
  }
  
  void i2c_master_arbitration_lost_callback(void)
  {
      i2c_master_error_detected_callback();
  }
  /// @endcond
  
  pal_status_t pal_i2c_init(const pal_i2c_t * p_i2c_context)
  {
      return PAL_STATUS_SUCCESS;
  }
  
  pal_status_t pal_i2c_deinit(const pal_i2c_t * p_i2c_context)
  {
      return PAL_STATUS_SUCCESS;
  }
  
  pal_status_t pal_i2c_write(const pal_i2c_t * p_i2c_context, uint8_t * p_data, uint16_t length)
  {
      pal_status_t status = PAL_STATUS_FAILURE;
  
      //Acquire the I2C bus before read/write
      if (PAL_STATUS_SUCCESS == pal_i2c_acquire(p_i2c_context))
      {
          gp_pal_i2c_current_ctx = p_i2c_context;
  
          //Invoke the low level i2c master driver API to write to the bus
          if (I2C_MASTER_STATUS_SUCCESS != I2C_MASTER_Transmit(p_i2c_context->p_i2c_hw_config,
                                                               (bool)TRUE,
                                                               (p_i2c_context->slave_address << 1),
                                                               p_data,
                                                               length,
                                                               (bool)TRUE))
          {
              //If I2C Master fails to invoke the write operation, invoke upper layer event handler with error.
  
              //lint --e{611} suppress "void* function pointer is type casted to upper_layer_callback_t type"
              ((upper_layer_callback_t)(p_i2c_context->upper_layer_event_handler))
                                                         (p_i2c_context->p_upper_layer_ctx , PAL_I2C_EVENT_ERROR);
              
              //Release I2C Bus
              pal_i2c_release((void * )p_i2c_context);
          }
          else
          {
              status = PAL_STATUS_SUCCESS;
          }
      }
      else
      {
          status = PAL_STATUS_I2C_BUSY;
          //lint --e{611} suppress "void* function pointer is type casted to upper_layer_callback_t type"
          ((upper_layer_callback_t)(p_i2c_context->upper_layer_event_handler))
                                                          (p_i2c_context->p_upper_layer_ctx , PAL_I2C_EVENT_BUSY);
      }
      return status;
  }
  
  pal_status_t pal_i2c_read(const pal_i2c_t * p_i2c_context, uint8_t * p_data, uint16_t length)
  {
      pal_status_t status = PAL_STATUS_FAILURE;
  
      //Acquire the I2C bus before read/write
      if (PAL_STATUS_SUCCESS == pal_i2c_acquire(p_i2c_context))
      {
          gp_pal_i2c_current_ctx = p_i2c_context;
  
          //Invoke the low level i2c master driver API to read from the bus
          if (I2C_MASTER_STATUS_SUCCESS != I2C_MASTER_Receive(p_i2c_context->p_i2c_hw_config,
                                                              (bool)TRUE,
                                                              (p_i2c_context->slave_address << 1),
                                                              p_data,
                                                              length,
                                                              (bool)TRUE,
                                                              (bool)TRUE))
          {
              //If I2C Master fails to invoke the read operation, invoke upper layer event handler with error.
  
              //lint --e{611} suppress "void* function pointer is type casted to upper_layer_callback_t type"
              ((upper_layer_callback_t)(p_i2c_context->upper_layer_event_handler))
                                                         (p_i2c_context->p_upper_layer_ctx , PAL_I2C_EVENT_ERROR);
  
              //Release I2C Bus
              pal_i2c_release((void * )p_i2c_context);
          }
          else
          {
              status = PAL_STATUS_SUCCESS;
          }
      }
      else
      {
          status = PAL_STATUS_I2C_BUSY;
          //lint --e{611} suppress "void* function pointer is type casted to upper_layer_callback_t type"
          ((upper_layer_callback_t)(p_i2c_context->upper_layer_event_handler))
                                                          (p_i2c_context->p_upper_layer_ctx , PAL_I2C_EVENT_BUSY);
      }
      return status;
  }
  
  pal_status_t pal_i2c_set_bitrate(const pal_i2c_t * p_i2c_context, uint16_t bitrate)
  {
      pal_status_t return_status = PAL_STATUS_FAILURE;
      optiga_lib_status_t event = PAL_I2C_EVENT_ERROR;
  
      //Acquire the I2C bus before setting the bitrate
      if (PAL_STATUS_SUCCESS == pal_i2c_acquire(p_i2c_context))
      {
          // If the user provided bitrate is greater than the I2C master hardware maximum supported value,
          // set the I2C master to its maximum supported value.
          if (bitrate > PAL_I2C_MASTER_MAX_BITRATE)
          {
              bitrate = PAL_I2C_MASTER_MAX_BITRATE;
          }
          if (XMC_I2C_CH_STATUS_OK != XMC_I2C_CH_SetBaudrate(((I2C_MASTER_t * )p_i2c_context->p_i2c_hw_config)->channel,
                                                              bitrate * 1000))
          {
              return_status = PAL_STATUS_FAILURE;
          }
          else
          {
              return_status = PAL_STATUS_SUCCESS;
              event = PAL_I2C_EVENT_SUCCESS;
          }
      }
      else
      {
          return_status = PAL_STATUS_I2C_BUSY;
          event = PAL_I2C_EVENT_BUSY;
      }
      if (0 != p_i2c_context->upper_layer_event_handler)
      {
          //lint --e{611} suppress "void* function pointer is type casted to upper_layer_callback_t type"
          ((callback_handler_t)(p_i2c_context->upper_layer_event_handler))(p_i2c_context->p_upper_layer_ctx , event);
      }
      //Release I2C Bus if its acquired 
      if (PAL_STATUS_I2C_BUSY != return_status)
      {
          pal_i2c_release((void * )p_i2c_context);
      }
      return return_status;
  }
  
  /**
  * @}
  */
  