初始版本
This commit is contained in:
433
external/infineon/optiga/comms/ifx_i2c/ifx_i2c.c
vendored
Normal file
433
external/infineon/optiga/comms/ifx_i2c/ifx_i2c.c
vendored
Normal file
@@ -0,0 +1,433 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018 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
|
||||
*
|
||||
*
|
||||
* \file ifx_i2c.c
|
||||
*
|
||||
* \brief This file implements the wrapper API Layer for IFX I2C protocol v1.65.
|
||||
*
|
||||
* \addtogroup grIFXI2C
|
||||
* @{
|
||||
*/
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* HEADER FILES
|
||||
**********************************************************************************************************************/
|
||||
#include "optiga/ifx_i2c/ifx_i2c.h"
|
||||
#include "optiga/ifx_i2c/ifx_i2c_transport_layer.h"
|
||||
#include "optiga/pal/pal_os_event.h"
|
||||
|
||||
/// @cond hidden
|
||||
/***********************************************************************************************************************
|
||||
* MACROS
|
||||
**********************************************************************************************************************/
|
||||
|
||||
// IFX I2C states
|
||||
#define IFX_I2C_STATE_UNINIT (0x01)
|
||||
#define IFX_I2C_STATE_IDLE (0x02)
|
||||
#define IFX_I2C_STATUS_BUSY (0x03)
|
||||
#define IFX_I2C_STATUS_NOT_BUSY (0x04)
|
||||
|
||||
/// IFX I2C Reset states
|
||||
#define IFX_I2C_STATE_RESET_PIN_LOW (0xB1)
|
||||
#define IFX_I2C_STATE_RESET_PIN_HIGH (0xB2)
|
||||
#define IFX_I2C_STATE_RESET_INIT (0xB3)
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* ENUMS
|
||||
**********************************************************************************************************************/
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* DATA STRUCTURES
|
||||
***********************************************************************************************************************/
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* GLOBAL
|
||||
***********************************************************************************************************************/
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* LOCAL ROUTINES
|
||||
***********************************************************************************************************************/
|
||||
/// Transport Layer event handler
|
||||
void ifx_i2c_tl_event_handler(ifx_i2c_context_t* p_ctx,host_lib_status_t event, const uint8_t* p_data, uint16_t data_len);
|
||||
|
||||
/// Performs initialization
|
||||
static host_lib_status_t ifx_i2c_init(ifx_i2c_context_t* ifx_i2c_context);
|
||||
|
||||
//lint --e{526} suppress "This API is defined in ifx_i2c_physical_layer. Since it is a low level API,
|
||||
//to avoid exposing, header file is not included "
|
||||
extern host_lib_status_t ifx_i2c_pl_write_slave_address(ifx_i2c_context_t *p_ctx, uint8_t slave_address, uint8_t storage_type);
|
||||
/// @endcond
|
||||
/***********************************************************************************************************************
|
||||
* API PROTOTYPES
|
||||
**********************************************************************************************************************/
|
||||
/**
|
||||
* Initializes the IFX I2C protocol stack for the given context.
|
||||
* <br>
|
||||
* <br>
|
||||
* \image html ifx_i2c_open.png "ifx_i2c_open()" width=20cm
|
||||
*
|
||||
*<b>Pre Conditions:</b>
|
||||
* - None<br>
|
||||
*
|
||||
*<b>API Details:</b>
|
||||
* - Performs a reset sequence.<br>
|
||||
* - Initializes the I2C slave device.<br>
|
||||
* - Initializes the ifx i2c protocol stack and registers the event callbacks.
|
||||
* - Negotiates the frame size and bit rate with the I2C slave.<br>
|
||||
*<br>
|
||||
*
|
||||
*<b>User Input:</b><br>
|
||||
* - The input #ifx_i2c_context_t p_ctx must not be NULL.
|
||||
* - The following parameters in #ifx_i2c_context_t must be initialized with appropriate values <br>
|
||||
* - <b>slave address</b> : Address of I2C slave
|
||||
* - <b>frame_size</b> : Frame size in bytes.Minimum supported value is 16 bytes.<br>
|
||||
* - It is recommended not to use a value greater than the slave's frame size.
|
||||
* - The user specified frame size is written to I2C slave's frame size register.
|
||||
* The frame size register is read back from I2C slave.
|
||||
* This frame value is used by the ifx-i2c protocol even if it is not equal to the user specified value.
|
||||
*
|
||||
* - <b>frequency</b> : Frequency/speed of I2C master in KHz.
|
||||
* - This must be lowest of the maximum frequency supported by the devices (master/slave) connected on the bus.
|
||||
* - Initial negotiation starts with a frequency of 100KHz.
|
||||
* - If the user specified frequency is more than 400 KHz, the I2C slave is configured to operate in "Fm+" mode,
|
||||
* otherwise the I2C slave is configured for "SM & Fm" mode. <br>
|
||||
* - If the user specified frequency frequency negotiation fails, the I2C master frequency remains at 100KHz<br>
|
||||
*
|
||||
* - <b>upper_layer_event_handler</b> : Upper layer event handler.This is invoked when #ifx_i2c_open() is asynchronously completed.
|
||||
* - <b>upper_layer_ctx</b> : Context of upper layer.
|
||||
* - <b>p_slave_vdd_pin</b> : GPIO pin for VDD. If not set, cold reset is not done.
|
||||
* - <b>p_slave_reset_pin</b> : GPIO pin for Reset. If not set, warm reset is not done.
|
||||
*
|
||||
*<b>Notes:</b>
|
||||
* - The values of registers MAX_SCL_FREQU and DATA_REG_LEN, read from slave are not validated.
|
||||
* - At present, only single instance of #ifx_i2c_context_t is supported.
|
||||
*
|
||||
*<br>
|
||||
*
|
||||
* \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
|
||||
*
|
||||
* \retval #IFX_I2C_STACK_SUCCESS
|
||||
* \retval #IFX_I2C_STACK_ERROR
|
||||
*/
|
||||
host_lib_status_t ifx_i2c_open(ifx_i2c_context_t *p_ctx)
|
||||
{
|
||||
host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
|
||||
|
||||
//If api status is not busy, proceed
|
||||
if ((IFX_I2C_STATUS_BUSY != p_ctx->status))
|
||||
{
|
||||
p_ctx->p_pal_i2c_ctx->upper_layer_ctx = p_ctx;
|
||||
#ifndef OPTIGA_USE_SOFT_RESET
|
||||
p_ctx->reset_type = (uint8_t)IFX_I2C_COLD_RESET;
|
||||
#else
|
||||
p_ctx->reset_type = (uint8_t)IFX_I2C_SOFT_RESET;
|
||||
#endif
|
||||
p_ctx->reset_state = IFX_I2C_STATE_RESET_PIN_LOW;
|
||||
p_ctx->do_pal_init = TRUE;
|
||||
p_ctx->state = IFX_I2C_STATE_UNINIT;
|
||||
|
||||
api_status = ifx_i2c_init(p_ctx);
|
||||
if(IFX_I2C_STACK_SUCCESS == api_status)
|
||||
{
|
||||
p_ctx->status = IFX_I2C_STATUS_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
return api_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the I2C slave and initializes the IFX I2C protocol stack for the given context.
|
||||
* <br>
|
||||
* <br>
|
||||
* \image html ifx_i2c_reset.png "ifx_i2c_reset()" width=20cm
|
||||
*
|
||||
*<b>Pre Conditions:</b>
|
||||
* - IFX I2C protocol stack must be initialized.<br>
|
||||
*
|
||||
*<b>API Details:</b>
|
||||
* - Resets the I2C slave.<br>
|
||||
* - Initializes the ifx i2c protocol stack.<br>
|
||||
* - Re-Initializes and negotiates the frame size and bit rate with the I2C slave.
|
||||
* The values remain same as that in previous #ifx_i2c_open().<br>
|
||||
*<br>
|
||||
*
|
||||
*<b>User Input:</b><br>
|
||||
* - The input #ifx_i2c_context_t p_ctx must not be NULL.
|
||||
*
|
||||
*<b>Notes:</b>
|
||||
* For COLD and WARM reset type: If the gpio(vdd and/or reset) pins are not configured,
|
||||
* the API continues without any failure return status<br>
|
||||
*
|
||||
* \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
|
||||
* \param[in,out] reset_type type of reset
|
||||
*
|
||||
* \retval #IFX_I2C_STACK_SUCCESS
|
||||
* \retval #IFX_I2C_STACK_ERROR
|
||||
*/
|
||||
host_lib_status_t ifx_i2c_reset(ifx_i2c_context_t *p_ctx, ifx_i2c_reset_type_t reset_type)
|
||||
{
|
||||
host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
|
||||
|
||||
// Proceed, if not busy and in idle state
|
||||
if ((IFX_I2C_STATE_IDLE == p_ctx->state) && (IFX_I2C_STATUS_BUSY != p_ctx->status))
|
||||
{
|
||||
p_ctx->reset_type = (uint8_t)reset_type;
|
||||
p_ctx->reset_state = IFX_I2C_STATE_RESET_PIN_LOW;
|
||||
p_ctx->do_pal_init = FALSE;
|
||||
|
||||
api_status = ifx_i2c_init(p_ctx);
|
||||
if(IFX_I2C_STACK_SUCCESS == api_status)
|
||||
{
|
||||
p_ctx->status = IFX_I2C_STATUS_BUSY;
|
||||
}
|
||||
}
|
||||
return api_status;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* Sends a command and receives a response for the command.<br>
|
||||
* <br>
|
||||
* \image html ifx_i2c_transceive.png "ifx_i2c_transceive()" width=20cm
|
||||
*
|
||||
*
|
||||
*<b>Pre Conditions:</b>
|
||||
* - IFX I2C protocol stack must be initialized.<br>
|
||||
*
|
||||
*<b>API Details:</b>
|
||||
* - Transmit data(Command) to I2C slave.<br>
|
||||
* - Receive data(Response) from I2C slave.<br>
|
||||
*<br>
|
||||
*
|
||||
*<b>User Input:</b><br>
|
||||
* - The input #ifx_i2c_context_t p_ctx must not be NULL.
|
||||
* - The following parameters in #ifx_i2c_context_t must be initialized with appropriate values <br>
|
||||
* - <b>upper_layer_event_handler</b> : Upper layer event handler, if it is different from that in #ifx_i2c_open().
|
||||
* This is invoked when #ifx_i2c_transceive is asynchronously completed.
|
||||
* - <b>upper_layer_ctx</b> : Context of upper layer, if it is different from that in #ifx_i2c_open.
|
||||
*
|
||||
*<b>Notes:</b>
|
||||
* - The actual number of bytes received is stored in p_rx_buffer_len. In case of error,p_rx_buffer_len is set to 0.<br>
|
||||
* - If the size of p_rx_buffer is zero or insufficient to copy the response bytes then
|
||||
* #IFX_I2C_STACK_MEM_ERROR error is returned.
|
||||
*
|
||||
* \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
|
||||
* \param[in] p_data Pointer to the write data buffer
|
||||
* \param[in] p_data_length Pointer to the length of the write data buffer
|
||||
* \param[in,out] p_rx_buffer Pointer to the receive data buffer
|
||||
* \param[in,out] p_rx_buffer_len Pointer to the length of the receive data buffer
|
||||
*
|
||||
* \retval #IFX_I2C_STACK_SUCCESS
|
||||
* \retval #IFX_I2C_STACK_ERROR
|
||||
* \retval #IFX_I2C_STACK_MEM_ERROR
|
||||
*/
|
||||
host_lib_status_t ifx_i2c_transceive(ifx_i2c_context_t *p_ctx,const uint8_t* p_data, const uint16_t* p_data_length,
|
||||
uint8_t* p_rx_buffer, uint16_t* p_rx_buffer_len)
|
||||
{
|
||||
host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
|
||||
// Proceed, if not busy and in idle state
|
||||
if ((IFX_I2C_STATE_IDLE == p_ctx->state) && (IFX_I2C_STATUS_BUSY != p_ctx->status))
|
||||
{
|
||||
p_ctx->p_upper_layer_rx_buffer = p_rx_buffer;
|
||||
p_ctx->p_upper_layer_rx_buffer_len = p_rx_buffer_len;
|
||||
api_status = ifx_i2c_tl_transceive(p_ctx,(uint8_t*)p_data, (*p_data_length),
|
||||
(uint8_t*)p_rx_buffer , p_rx_buffer_len);
|
||||
if (IFX_I2C_STACK_SUCCESS == api_status)
|
||||
{
|
||||
p_ctx->status = IFX_I2C_STATUS_BUSY;
|
||||
}
|
||||
}
|
||||
return api_status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes the IFX I2C protocol stack for a given context.
|
||||
* <br>
|
||||
* <br>
|
||||
* \image html ifx_i2c_close.png "ifx_i2c_close()" width=20cm
|
||||
*
|
||||
*<b>Pre Conditions:</b>
|
||||
* - None<br>
|
||||
*
|
||||
*<b>API Details:</b>
|
||||
* - De-Initializes the I2C slave device.<br>
|
||||
* - Power downs the I2C slave.<br>
|
||||
*<br>
|
||||
*
|
||||
*<b>User Input:</b><br>
|
||||
* - The input #ifx_i2c_context_t p_ctx must not be NULL.
|
||||
*
|
||||
*<b>Notes:</b>
|
||||
*
|
||||
* \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
|
||||
*
|
||||
* \retval #IFX_I2C_STACK_SUCCESS
|
||||
*/
|
||||
host_lib_status_t ifx_i2c_close(ifx_i2c_context_t *p_ctx)
|
||||
{
|
||||
host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
|
||||
// Proceed, if not busy and in idle state
|
||||
if (IFX_I2C_STATUS_BUSY != p_ctx->status)
|
||||
{
|
||||
api_status = IFX_I2C_STACK_SUCCESS;
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
// Close I2C master
|
||||
pal_i2c_deinit(p_ctx->p_pal_i2c_ctx);
|
||||
// Also power off the device
|
||||
pal_gpio_set_low(p_ctx->p_slave_vdd_pin);
|
||||
pal_gpio_set_low(p_ctx->p_slave_reset_pin);
|
||||
|
||||
ifx_i2c_tl_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS,NULL,0);
|
||||
p_ctx->state = IFX_I2C_STATE_UNINIT;
|
||||
p_ctx->status = IFX_I2C_STATUS_NOT_BUSY;
|
||||
}
|
||||
return api_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes new I2C slave Address to the target device.<br>
|
||||
*
|
||||
*<b>Pre Conditions:</b>
|
||||
* - IFX I2C protocol stack must be initialized.<br>
|
||||
*
|
||||
*<b>API Details:</b>
|
||||
* - This API is implemented in synchronous mode.
|
||||
* - If the write fails due to the following reasons, this API repeats the write for #PL_POLLING_MAX_CNT times
|
||||
* with a fixed interval of #PL_POLLING_INVERVAL_US microseconds and exits with respective return status.
|
||||
* - I2C bus is in busy state, returns #IFX_I2C_STACK_BUSY
|
||||
* - No-acknowledge(NACK) received from slave, returns #IFX_I2C_STACK_ERROR
|
||||
* - I2C errors, returns #IFX_I2C_STACK_ERROR
|
||||
* - Only bits [6:0] from parameter "slave_address" are considered as slave address. Hence the bit 7 is ignored.
|
||||
* - Slave address validation is not done in the implementation. Provide a valid slave address as input.
|
||||
*
|
||||
*<b>Notes:</b>
|
||||
* - If persistent mode is selected, the ifx i2c context slave address will be over-written with the new slave address.
|
||||
* Even after ifx i2c open/reset, all future executions will use the new slave address.<br>
|
||||
* - If volatile mode is selected, the pal_i2c_context slave address will be over-written with the new slave address.
|
||||
* This persists only till the next ifx_i2c open/reset is called.
|
||||
*
|
||||
* \param[in,out] p_ctx Pointer to #ifx_i2c_context_t
|
||||
* \param[in] slave_address Holds new slave address[7 Bit] to be set.
|
||||
* \param[in] persistent 0 - To set the Slave address until next reset.<br>
|
||||
* Non-zero - To set the slave address to persistent memory.
|
||||
*
|
||||
* \retval #IFX_I2C_STACK_SUCCESS
|
||||
* \retval #IFX_I2C_STACK_ERROR
|
||||
*/
|
||||
host_lib_status_t ifx_i2c_set_slave_address(ifx_i2c_context_t *p_ctx, uint8_t slave_address, uint8_t persistent)
|
||||
{
|
||||
host_lib_status_t api_status = (int32_t)IFX_I2C_STACK_ERROR;
|
||||
|
||||
if ((IFX_I2C_STATE_IDLE == p_ctx->state))
|
||||
{
|
||||
p_ctx->p_pal_i2c_ctx->upper_layer_ctx = p_ctx;
|
||||
|
||||
api_status = ifx_i2c_pl_write_slave_address(p_ctx, slave_address, persistent);
|
||||
}
|
||||
|
||||
return api_status;
|
||||
}
|
||||
|
||||
/// @cond hidden
|
||||
//lint --e{715} suppress "This is ignored as ifx_i2c_event_handler_t handler function prototype requires this argument"
|
||||
void ifx_i2c_tl_event_handler(ifx_i2c_context_t* p_ctx,host_lib_status_t event, const uint8_t* p_data, uint16_t data_len)
|
||||
{
|
||||
// If there is no upper layer handler, don't do anything and return
|
||||
if (NULL != p_ctx->upper_layer_event_handler)
|
||||
{
|
||||
p_ctx->upper_layer_event_handler(p_ctx->p_upper_layer_ctx,event);
|
||||
}
|
||||
p_ctx->status = IFX_I2C_STATUS_NOT_BUSY;
|
||||
switch(p_ctx->state)
|
||||
{
|
||||
case IFX_I2C_STATE_UNINIT:
|
||||
if (IFX_I2C_STACK_SUCCESS == event)
|
||||
{
|
||||
p_ctx->state = IFX_I2C_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static host_lib_status_t ifx_i2c_init(ifx_i2c_context_t* p_ifx_i2c_context)
|
||||
{
|
||||
host_lib_status_t api_status = IFX_I2C_STACK_ERROR;
|
||||
|
||||
if ((p_ifx_i2c_context->reset_type == (uint8_t)IFX_I2C_WARM_RESET)||
|
||||
(p_ifx_i2c_context->reset_type == (uint8_t)IFX_I2C_COLD_RESET))
|
||||
{
|
||||
switch(p_ifx_i2c_context->reset_state)
|
||||
{
|
||||
case IFX_I2C_STATE_RESET_PIN_LOW:
|
||||
// Setting the Vdd & Reset pin to low
|
||||
if (p_ifx_i2c_context->reset_type == (uint8_t)IFX_I2C_COLD_RESET)
|
||||
{
|
||||
pal_gpio_set_low(p_ifx_i2c_context->p_slave_vdd_pin);
|
||||
}
|
||||
pal_gpio_set_low(p_ifx_i2c_context->p_slave_reset_pin);
|
||||
p_ifx_i2c_context->reset_state = IFX_I2C_STATE_RESET_PIN_HIGH;
|
||||
pal_os_event_register_callback_oneshot((register_callback)ifx_i2c_init,
|
||||
(void *)p_ifx_i2c_context, RESET_LOW_TIME_MSEC);
|
||||
api_status = IFX_I2C_STACK_SUCCESS;
|
||||
break;
|
||||
|
||||
case IFX_I2C_STATE_RESET_PIN_HIGH:
|
||||
// Setting the Vdd & Reset pin to high
|
||||
if (p_ifx_i2c_context->reset_type == (uint8_t)IFX_I2C_COLD_RESET)
|
||||
{
|
||||
pal_gpio_set_high(p_ifx_i2c_context->p_slave_vdd_pin);
|
||||
}
|
||||
pal_gpio_set_high(p_ifx_i2c_context->p_slave_reset_pin);
|
||||
p_ifx_i2c_context->reset_state = IFX_I2C_STATE_RESET_INIT;
|
||||
pal_os_event_register_callback_oneshot((register_callback)ifx_i2c_init,
|
||||
(void *)p_ifx_i2c_context, STARTUP_TIME_MSEC);
|
||||
api_status = IFX_I2C_STACK_SUCCESS;
|
||||
break;
|
||||
|
||||
case IFX_I2C_STATE_RESET_INIT:
|
||||
//Frequency and frame size negotiation
|
||||
api_status = ifx_i2c_tl_init(p_ifx_i2c_context,ifx_i2c_tl_event_handler);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
//soft reset
|
||||
else
|
||||
{
|
||||
p_ifx_i2c_context->pl.request_soft_reset = (uint8_t)TRUE; //Soft reset
|
||||
api_status = ifx_i2c_tl_init(p_ifx_i2c_context,ifx_i2c_tl_event_handler);
|
||||
}
|
||||
|
||||
return api_status;
|
||||
}
|
||||
/// @endcond
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
86
external/infineon/optiga/comms/ifx_i2c/ifx_i2c_config.c
vendored
Normal file
86
external/infineon/optiga/comms/ifx_i2c/ifx_i2c_config.c
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018 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
|
||||
*
|
||||
*
|
||||
* \file ifx_i2c_config.c
|
||||
*
|
||||
* \brief This file provides the ifx i2c platform specific context configurations.
|
||||
*
|
||||
* \addtogroup grIFXI2C
|
||||
* @{
|
||||
*/
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* HEADER FILES
|
||||
**********************************************************************************************************************/
|
||||
// Protocol Stack Includes
|
||||
#include "optiga/pal/pal_ifx_i2c_config.h"
|
||||
#include "optiga/ifx_i2c/ifx_i2c_config.h"
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* MACROS
|
||||
**********************************************************************************************************************/
|
||||
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* ENUMS
|
||||
**********************************************************************************************************************/
|
||||
/***********************************************************************************************************************
|
||||
* DATA STRUCTURES
|
||||
***********************************************************************************************************************/
|
||||
|
||||
/** @brief This is IFX I2C context. Only one context is supported per slave.*/
|
||||
//lint --e{785} suppress "Only required fields are initialized, the rest are handled by consumer of this structure"
|
||||
ifx_i2c_context_t ifx_i2c_context_0 =
|
||||
{
|
||||
/// Slave address
|
||||
0x30,
|
||||
/// i2c-master frequency
|
||||
400,
|
||||
/// IFX-I2C frame size
|
||||
#if (DL_MAX_FRAME_SIZE >= 0x0115)
|
||||
0x0115,
|
||||
#else
|
||||
DL_MAX_FRAME_SIZE,
|
||||
#endif
|
||||
/// Vdd pin
|
||||
&optiga_vdd_0,
|
||||
/// Reset pin
|
||||
&optiga_reset_0,
|
||||
/// optiga pal i2c context
|
||||
&optiga_pal_i2c_context_0,
|
||||
};
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* GLOBAL
|
||||
***********************************************************************************************************************/
|
||||
/***********************************************************************************************************************
|
||||
* LOCAL ROUTINES
|
||||
***********************************************************************************************************************/
|
||||
/***********************************************************************************************************************
|
||||
* API PROTOTYPES
|
||||
**********************************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @}
|
||||
**/
|
||||
583
external/infineon/optiga/comms/ifx_i2c/ifx_i2c_data_link_layer.c
vendored
Normal file
583
external/infineon/optiga/comms/ifx_i2c/ifx_i2c_data_link_layer.c
vendored
Normal file
@@ -0,0 +1,583 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018 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
|
||||
*
|
||||
*
|
||||
* \file ifx_i2c_data_link_layer.c
|
||||
*
|
||||
* \brief This file implements the IFX I2C Datalink Layer.
|
||||
*
|
||||
* \addtogroup grIFXI2C
|
||||
* @{
|
||||
*/
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* HEADER FILES
|
||||
**********************************************************************************************************************/
|
||||
#include "optiga/ifx_i2c/ifx_i2c_data_link_layer.h"
|
||||
#include "optiga/ifx_i2c/ifx_i2c_physical_layer.h" // include lower layer header
|
||||
|
||||
/// @cond hidden
|
||||
/***********************************************************************************************************************
|
||||
* MACROS
|
||||
**********************************************************************************************************************/
|
||||
// Data Link layer internal states
|
||||
#define DL_STATE_UNINIT (0x00)
|
||||
#define DL_STATE_IDLE (0x01)
|
||||
#define DL_STATE_TX (0x02)
|
||||
#define DL_STATE_RX (0x03)
|
||||
#define DL_STATE_ACK (0x04)
|
||||
#define DL_STATE_RESEND (0x05)
|
||||
#define DL_STATE_NACK (0x06)
|
||||
#define DL_STATE_ERROR (0x08)
|
||||
#define DL_STATE_DISCARD (0x09)
|
||||
#define DL_STATE_RX_DF (0x0A)
|
||||
#define DL_STATE_RX_CF (0x0B)
|
||||
|
||||
// Data Link Layer Frame Control Constants
|
||||
#define DL_FCTR_FTYPE_MASK (0x80)
|
||||
#define DL_FCTR_FTYPE_OFFSET (7)
|
||||
#define DL_FCTR_VALUE_CONTROL_FRAME (0x01)
|
||||
|
||||
#define DL_FCTR_SEQCTR_MASK (0x60)
|
||||
#define DL_FCTR_SEQCTR_OFFSET (5)
|
||||
#define DL_FCTR_SEQCTR_VALUE_ACK (0x00)
|
||||
#define DL_FCTR_SEQCTR_VALUE_NACK (0x01)
|
||||
#define DL_FCTR_SEQCTR_VALUE_RESYNC (0x02)
|
||||
#define DL_FCTR_SEQCTR_VALUE_RFU (0x03)
|
||||
|
||||
#define DL_FCTR_FRNR_MASK (0x0C)
|
||||
#define DL_FCTR_FRNR_OFFSET (2)
|
||||
|
||||
#define DL_FCTR_ACKNR_MASK (0x03)
|
||||
#define DL_FCTR_ACKNR_OFFSET (0)
|
||||
|
||||
// Data Link Layer frame counter max value
|
||||
#define DL_MAX_FRAME_NUM (0x03)
|
||||
|
||||
// Data link layer length
|
||||
#define DL_CONTROL_FRAME_LENGTH (5)
|
||||
|
||||
// Setup debug log statements
|
||||
#if IFX_I2C_LOG_DL == 1
|
||||
#include "common/Log_api.h"
|
||||
#define LOG_DL(args...) ifx_debug_log(IFX_I2C_LOG_ID_DL, args)
|
||||
#else
|
||||
#define LOG_DL(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* ENUMS
|
||||
**********************************************************************************************************************/
|
||||
/***********************************************************************************************************************
|
||||
* DATA STRUCTURES
|
||||
***********************************************************************************************************************/
|
||||
/***********************************************************************************************************************
|
||||
* GLOBAL
|
||||
***********************************************************************************************************************/
|
||||
/***********************************************************************************************************************
|
||||
* LOCAL ROUTINES
|
||||
***********************************************************************************************************************/
|
||||
/// Helper function to calculate CRC of a byte
|
||||
_STATIC_H host_lib_status_t ifx_i2c_dl_calc_crc_byte(uint16_t wSeed, uint8_t bByte);
|
||||
/// Helper function to calculate CRC of a frame
|
||||
_STATIC_H host_lib_status_t ifx_i2c_dl_calc_crc(const uint8_t* p_data, uint16_t data_len);
|
||||
/// Internal function to send frame
|
||||
_STATIC_H host_lib_status_t ifx_i2c_dl_send_frame_internal(ifx_i2c_context_t *p_ctx,uint16_t frame_len,uint8_t seqctr_value, uint8_t resend);
|
||||
/// Helper function to send resync
|
||||
_STATIC_H host_lib_status_t ifx_i2c_dl_resync(ifx_i2c_context_t* p_ctx);
|
||||
/// Helper function to resend frame
|
||||
_STATIC_H void ifx_i2c_dl_resend_frame(ifx_i2c_context_t* p_ctx,uint8_t seqctr_value);
|
||||
/// Data Link Layer state machine
|
||||
_STATIC_H void ifx_i2c_pl_event_handler(ifx_i2c_context_t* p_ctx,host_lib_status_t event, const uint8_t* p_data, uint16_t data_len);
|
||||
|
||||
/// @endcond
|
||||
/***********************************************************************************************************************
|
||||
* API PROTOTYPES
|
||||
**********************************************************************************************************************/
|
||||
host_lib_status_t ifx_i2c_dl_init(ifx_i2c_context_t *p_ctx,ifx_i2c_event_handler_t handler)
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Init\n");
|
||||
|
||||
p_ctx->dl.state = DL_STATE_UNINIT;
|
||||
// Initialize Physical Layer (and register event handler)
|
||||
if (ifx_i2c_pl_init(p_ctx, ifx_i2c_pl_event_handler) != IFX_I2C_STACK_SUCCESS)
|
||||
{
|
||||
return IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
|
||||
// Initialize internal variables
|
||||
p_ctx->dl.upper_layer_event_handler = handler;
|
||||
p_ctx->dl.state = DL_STATE_IDLE;
|
||||
p_ctx->dl.tx_seq_nr = DL_MAX_FRAME_NUM;
|
||||
p_ctx->dl.rx_seq_nr = DL_MAX_FRAME_NUM;
|
||||
p_ctx->dl.resynced = 0;
|
||||
p_ctx->dl.error = 0;
|
||||
p_ctx->dl.p_tx_frame_buffer = p_ctx->tx_frame_buffer;
|
||||
p_ctx->dl.p_rx_frame_buffer = p_ctx->rx_frame_buffer;
|
||||
|
||||
return IFX_I2C_STACK_SUCCESS;
|
||||
}
|
||||
|
||||
host_lib_status_t ifx_i2c_dl_send_frame(ifx_i2c_context_t *p_ctx,uint16_t frame_len)
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Start TX Frame\n");
|
||||
// State must be idle and payload available
|
||||
if (p_ctx->dl.state != DL_STATE_IDLE || !frame_len)
|
||||
{
|
||||
return IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
|
||||
p_ctx->dl.state = DL_STATE_TX;
|
||||
p_ctx->dl.retransmit_counter = 0;
|
||||
p_ctx->dl.action_rx_only = 0;
|
||||
p_ctx->dl.tx_buffer_size = frame_len;
|
||||
p_ctx->dl.data_poll_timeout = PL_TRANS_TIMEOUT_MS;
|
||||
|
||||
return ifx_i2c_dl_send_frame_internal(p_ctx,frame_len, DL_FCTR_SEQCTR_VALUE_ACK, 0);
|
||||
}
|
||||
|
||||
host_lib_status_t ifx_i2c_dl_receive_frame(ifx_i2c_context_t *p_ctx)
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Start RX Frame\n");
|
||||
|
||||
if (p_ctx->dl.state != DL_STATE_IDLE)
|
||||
{
|
||||
return IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
|
||||
// Set internal state
|
||||
p_ctx->dl.state = DL_STATE_RX;
|
||||
p_ctx->dl.retransmit_counter = 0;
|
||||
p_ctx->dl.action_rx_only = 1;
|
||||
p_ctx->dl.frame_start_time = pal_os_timer_get_time_in_milliseconds();
|
||||
p_ctx->dl.data_poll_timeout = TL_MAX_EXIT_TIMEOUT*1000;
|
||||
|
||||
return ifx_i2c_pl_receive_frame(p_ctx);
|
||||
}
|
||||
|
||||
_STATIC_H host_lib_status_t ifx_i2c_dl_calc_crc_byte(uint16_t wSeed, uint8_t bByte)
|
||||
{
|
||||
uint16_t wh1;
|
||||
uint16_t wh2;
|
||||
uint16_t wh3;
|
||||
uint16_t wh4;
|
||||
|
||||
wh1 = (wSeed ^ bByte) & 0xFF;
|
||||
wh2 = wh1 & 0x0F;
|
||||
wh3 = ((uint16_t)(wh2 << 4)) ^ wh1;
|
||||
wh4 = wh3 >> 4;
|
||||
|
||||
return ((uint16_t)((((uint16_t)((((uint16_t)(wh3 << 1)) ^ wh4) << 4)) ^ wh2) << 3)) ^ wh4
|
||||
^ (wSeed >> 8);
|
||||
}
|
||||
|
||||
_STATIC_H host_lib_status_t ifx_i2c_dl_calc_crc(const uint8_t* p_data, uint16_t data_len)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t crc = 0;
|
||||
|
||||
for (i = 0; i < data_len; i++)
|
||||
{
|
||||
crc = ifx_i2c_dl_calc_crc_byte(crc, p_data[i]);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
_STATIC_H host_lib_status_t ifx_i2c_dl_send_frame_internal(ifx_i2c_context_t *p_ctx,uint16_t frame_len,
|
||||
uint8_t seqctr_value, uint8_t resend)
|
||||
{
|
||||
uint16_t crc;
|
||||
uint16_t ack_nr = p_ctx->dl.rx_seq_nr;
|
||||
uint8_t* p_buffer;
|
||||
|
||||
LOG_DL("[IFX-DL]: TX Frame len %d\n", frame_len);
|
||||
// In case of sending a NACK the next frame is referenced
|
||||
if (seqctr_value == DL_FCTR_SEQCTR_VALUE_NACK)
|
||||
{
|
||||
ack_nr = (p_ctx->dl.rx_seq_nr + 1) & DL_MAX_FRAME_NUM;
|
||||
}
|
||||
if(seqctr_value == DL_FCTR_SEQCTR_VALUE_RESYNC)
|
||||
{
|
||||
ack_nr = 0;
|
||||
// Use rx buffer to send resync
|
||||
p_buffer = p_ctx->dl.p_rx_frame_buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_buffer = p_ctx->dl.p_tx_frame_buffer;
|
||||
}
|
||||
// Set sequence control value (ACK or NACK) and referenced frame number
|
||||
p_buffer[0] = (uint8_t)(ack_nr << DL_FCTR_ACKNR_OFFSET);
|
||||
p_buffer[0] |= (uint8_t)(seqctr_value << DL_FCTR_SEQCTR_OFFSET);
|
||||
|
||||
if (frame_len) // Data frame
|
||||
{
|
||||
// Increment and set frame transmit sequence number
|
||||
if ((!resend)||(p_ctx->dl.resynced))
|
||||
{
|
||||
p_ctx->dl.tx_seq_nr = (p_ctx->dl.tx_seq_nr + 1) & DL_MAX_FRAME_NUM;
|
||||
}
|
||||
p_buffer[0] |= (uint8_t)(p_ctx->dl.tx_seq_nr << DL_FCTR_FRNR_OFFSET);
|
||||
// Reset resync received
|
||||
p_ctx->dl.resynced = 0;
|
||||
}
|
||||
else // Control frame
|
||||
{
|
||||
p_buffer[0] |= DL_FCTR_FTYPE_MASK;
|
||||
}
|
||||
|
||||
// Set frame length
|
||||
p_buffer[1] = (uint8_t)(frame_len >> 8);
|
||||
p_buffer[2] = (uint8_t)frame_len;
|
||||
|
||||
// Calculate frame CRC
|
||||
crc = ifx_i2c_dl_calc_crc(p_buffer, 3 + frame_len);
|
||||
p_buffer[3 + frame_len] = (uint8_t) (crc >> 8);
|
||||
p_buffer[4 + frame_len] = (uint8_t)crc;
|
||||
|
||||
// Transmit frame
|
||||
return ifx_i2c_pl_send_frame(p_ctx,p_buffer, DL_HEADER_SIZE + frame_len);
|
||||
}
|
||||
|
||||
_STATIC_H host_lib_status_t ifx_i2c_dl_resync(ifx_i2c_context_t* p_ctx)
|
||||
{
|
||||
host_lib_status_t api_status = IFX_I2C_STACK_SUCCESS;
|
||||
// Reset tx and rx counters
|
||||
p_ctx->dl.tx_seq_nr = DL_MAX_FRAME_NUM;
|
||||
p_ctx->dl.rx_seq_nr = DL_MAX_FRAME_NUM;
|
||||
p_ctx->dl.resynced = 1;
|
||||
LOG_DL("[IFX-DL]: Send Re-Sync Frame\n");
|
||||
p_ctx->dl.state = DL_STATE_RESEND;
|
||||
api_status = ifx_i2c_dl_send_frame_internal(p_ctx,0,DL_FCTR_SEQCTR_VALUE_RESYNC,0);
|
||||
return api_status;
|
||||
}
|
||||
|
||||
_STATIC_H void ifx_i2c_dl_resend_frame(ifx_i2c_context_t* p_ctx,uint8_t seqctr_value)
|
||||
{
|
||||
host_lib_status_t status;
|
||||
// If exit timeout not violated
|
||||
uint32_t current_time_stamp = pal_os_timer_get_time_in_milliseconds();
|
||||
if ((current_time_stamp - p_ctx->tl.api_start_time) < (TL_MAX_EXIT_TIMEOUT * 1000))
|
||||
{
|
||||
if(p_ctx->dl.retransmit_counter == DL_TRANS_REPEAT)
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Re-Sync counters\n");
|
||||
p_ctx->dl.retransmit_counter = 0;
|
||||
status = ifx_i2c_dl_resync(p_ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Re-TX Frame\n");
|
||||
p_ctx->dl.retransmit_counter++;
|
||||
p_ctx->dl.state = DL_STATE_TX;
|
||||
status = ifx_i2c_dl_send_frame_internal(p_ctx,p_ctx->dl.tx_buffer_size,seqctr_value, 1);
|
||||
}
|
||||
// Handle error in above case by sending NACK
|
||||
if (IFX_I2C_STACK_SUCCESS != status)
|
||||
{
|
||||
p_ctx->dl.state = DL_STATE_NACK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctx->dl.state = DL_STATE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
_STATIC_H void ifx_i2c_pl_event_handler(ifx_i2c_context_t* p_ctx,host_lib_status_t event, const uint8_t* p_data, uint16_t data_len)
|
||||
{
|
||||
uint8_t fctr = 0;
|
||||
uint8_t fr_nr = 0;
|
||||
uint8_t ack_nr = 0;
|
||||
uint8_t seqctr = 0;
|
||||
uint8_t current_event;
|
||||
uint8_t ftype;
|
||||
uint8_t continue_state_machine = TRUE;
|
||||
uint16_t packet_len = 0;
|
||||
uint16_t crc_received = 0;
|
||||
uint16_t crc_calculated = 0;
|
||||
LOG_DL("[IFX-DL]: #Enter DL Handler\n");
|
||||
do
|
||||
{
|
||||
if((event == IFX_I2C_FATAL_ERROR) && (DL_STATE_IDLE != p_ctx->dl.state))
|
||||
{ // Exit in case of fatal error
|
||||
LOG_DL("[IFX-DL]: Fatal error received\n");
|
||||
p_ctx->dl.state = DL_STATE_ERROR;
|
||||
}
|
||||
switch(p_ctx->dl.state)
|
||||
{
|
||||
case DL_STATE_IDLE:
|
||||
{
|
||||
current_event = (event != IFX_I2C_STACK_SUCCESS)?IFX_I2C_DL_EVENT_ERROR:IFX_I2C_DL_EVENT_TX_SUCCESS;
|
||||
continue_state_machine = FALSE;
|
||||
p_ctx->dl.upper_layer_event_handler(p_ctx,current_event, 0, 0);
|
||||
}
|
||||
break;
|
||||
case DL_STATE_TX:
|
||||
{
|
||||
// If writing a frame failed retry sending
|
||||
if (event == IFX_I2C_STACK_ERROR)
|
||||
{
|
||||
p_ctx->dl.state = DL_STATE_RESEND;
|
||||
break;
|
||||
}
|
||||
LOG_DL("[IFX-DL]: Frame Sent\n");
|
||||
// Transmission successful, start receiving frame
|
||||
p_ctx->dl.frame_start_time = pal_os_timer_get_time_in_milliseconds();
|
||||
p_ctx->dl.state = DL_STATE_RX;
|
||||
if (ifx_i2c_pl_receive_frame(p_ctx))
|
||||
{
|
||||
p_ctx->dl.state = DL_STATE_NACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue_state_machine = FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DL_STATE_RX:
|
||||
{
|
||||
if (event == IFX_I2C_STACK_ERROR)
|
||||
{ // If no frame was received retry sending
|
||||
p_ctx->dl.state = DL_STATE_RESEND;
|
||||
break;
|
||||
}
|
||||
// Received frame from device, start analyzing
|
||||
LOG_DL("[IFX-DL]: Received Frame of length %d\n",data_len);
|
||||
|
||||
if (data_len < DL_HEADER_SIZE)
|
||||
{ // Received length is less than minimum size
|
||||
LOG_DL("[IFX-DL]: received data_len < DL_HEADER_SIZE\n");
|
||||
p_ctx->dl.state = DL_STATE_NACK;
|
||||
break;
|
||||
}
|
||||
// Check transmit frame sequence number
|
||||
fctr = p_data[0];
|
||||
ftype = (fctr & DL_FCTR_FTYPE_MASK) >> DL_FCTR_FTYPE_OFFSET;
|
||||
seqctr = (fctr & DL_FCTR_SEQCTR_MASK) >> DL_FCTR_SEQCTR_OFFSET;
|
||||
ack_nr = (fctr & DL_FCTR_ACKNR_MASK) >> DL_FCTR_ACKNR_OFFSET;
|
||||
fr_nr = (fctr & DL_FCTR_FRNR_MASK) >> DL_FCTR_FRNR_OFFSET;
|
||||
packet_len = (p_data[1] << 8) | p_data[2];
|
||||
|
||||
// Check frame CRC value
|
||||
crc_received = (p_data[data_len - 2] << 8) | p_data[data_len - 1];
|
||||
crc_calculated = ifx_i2c_dl_calc_crc(p_data, data_len - 2);
|
||||
p_ctx->dl.state = (ftype == DL_FCTR_VALUE_CONTROL_FRAME)?DL_STATE_RX_CF:DL_STATE_RX_DF;
|
||||
}
|
||||
break;
|
||||
case DL_STATE_RX_DF:
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Data Frame Received\n");
|
||||
if ((crc_received != crc_calculated)||(packet_len == 0)||(data_len != DL_HEADER_SIZE + packet_len)||
|
||||
(seqctr == DL_FCTR_SEQCTR_VALUE_RFU) || (seqctr == DL_FCTR_SEQCTR_VALUE_RESYNC))
|
||||
{
|
||||
// CRC,Length of data frame is 0/ SEQCTR has RFU/Re-sync in Data frame
|
||||
LOG_DL("[IFX-DL]: NACK for CRC error,Data frame length is not correct,RFU in SEQCTR\n");
|
||||
p_ctx->dl.state = DL_STATE_NACK;
|
||||
break;
|
||||
}
|
||||
if (fr_nr != ((p_ctx->dl.rx_seq_nr + 1) & DL_MAX_FRAME_NUM))
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Data frame number not expected\n");
|
||||
p_ctx->dl.state = DL_STATE_DISCARD;
|
||||
continue_state_machine = FALSE;
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
ifx_i2c_dl_send_frame_internal(p_ctx,0, DL_FCTR_SEQCTR_VALUE_ACK, 0);
|
||||
break;
|
||||
}
|
||||
if (ack_nr != p_ctx->dl.tx_seq_nr)
|
||||
{
|
||||
// ack number error
|
||||
LOG_DL("[IFX-DL]: Error in ack number\n");
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
p_ctx->dl.state = DL_STATE_DISCARD;
|
||||
break;
|
||||
}
|
||||
if (seqctr == DL_FCTR_SEQCTR_VALUE_NACK)
|
||||
{
|
||||
// NACK for transmitted frame
|
||||
LOG_DL("[IFX-DL]: NACK received in data frame\n");
|
||||
p_ctx->dl.state = DL_STATE_RESEND;
|
||||
break;
|
||||
}
|
||||
p_ctx->dl.rx_seq_nr = (p_ctx->dl.rx_seq_nr + 1) & DL_MAX_FRAME_NUM;
|
||||
memcpy(p_ctx->dl.p_rx_frame_buffer, p_data, data_len);
|
||||
p_ctx->dl.rx_buffer_size = data_len;
|
||||
|
||||
// Send control frame to acknowledge reception of this data frame
|
||||
LOG_DL("[IFX-DL]: Read Data Frame -> Send ACK\n");
|
||||
p_ctx->dl.retransmit_counter = 0;
|
||||
p_ctx->dl.state = DL_STATE_ACK;
|
||||
continue_state_machine = FALSE;
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
ifx_i2c_dl_send_frame_internal(p_ctx,0, DL_FCTR_SEQCTR_VALUE_ACK, 0);
|
||||
}
|
||||
break;
|
||||
case DL_STATE_RX_CF:
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Control Frame Received\n");
|
||||
// Discard Control frame when in receiver mode except for Re-Sync
|
||||
//lint --e{514} suppress "The check is intended to be done this way"
|
||||
if((p_ctx->dl.action_rx_only) ^ (seqctr == DL_FCTR_SEQCTR_VALUE_RESYNC))
|
||||
{
|
||||
//If control frame already received for data frame, ignore any received control frame
|
||||
LOG_DL("[IFX-DL]: CF in receiver mode,Discard\n");
|
||||
p_ctx->dl.state = DL_STATE_DISCARD;
|
||||
break;
|
||||
}
|
||||
if (crc_received != crc_calculated)
|
||||
{
|
||||
// Re-Transmit frame in case of CF CRC error
|
||||
LOG_DL("[IFX-DL]: Retransmit frame for CF CRC error\n");
|
||||
p_ctx->dl.state = DL_STATE_RESEND;
|
||||
break;
|
||||
}
|
||||
if((data_len > DL_CONTROL_FRAME_LENGTH)||(packet_len != 0))
|
||||
{
|
||||
// Control frame is more than 5/Control frame with non-zero FRNR/packet len is not 0
|
||||
LOG_DL("[IFX-DL]: Errors in control frame\n");
|
||||
p_ctx->dl.state = DL_STATE_DISCARD;
|
||||
break;
|
||||
}
|
||||
if(seqctr == DL_FCTR_SEQCTR_VALUE_RESYNC)
|
||||
{ // Re-sync received
|
||||
LOG_DL("[IFX-DL]: Re-Sync received\n");
|
||||
p_ctx->dl.state = DL_STATE_DISCARD;
|
||||
p_ctx->dl.resynced = 1;
|
||||
p_ctx->dl.tx_seq_nr = DL_MAX_FRAME_NUM;
|
||||
p_ctx->dl.rx_seq_nr = DL_MAX_FRAME_NUM;
|
||||
break;
|
||||
}
|
||||
if((fr_nr!=0)||(seqctr == DL_FCTR_SEQCTR_VALUE_RFU)||(ack_nr != p_ctx->dl.tx_seq_nr))
|
||||
{
|
||||
// Control frame with non-zero FRNR/ ACK not received/ ack number != tx number
|
||||
LOG_DL("[IFX-DL]: Errors in control frame\n");
|
||||
p_ctx->dl.state = DL_STATE_DISCARD;
|
||||
break;
|
||||
}
|
||||
if (seqctr == DL_FCTR_SEQCTR_VALUE_NACK)
|
||||
{
|
||||
// NACK for transmitted frame
|
||||
LOG_DL("[IFX-DL]: NACK received\n");
|
||||
p_ctx->dl.state = DL_STATE_RESEND;
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_DL("[IFX-DL]: ACK received\n");
|
||||
// Report frame reception to upper layer and go in idle state
|
||||
p_ctx->dl.state = DL_STATE_IDLE;
|
||||
continue_state_machine = FALSE;
|
||||
p_ctx->dl.upper_layer_event_handler(p_ctx,IFX_I2C_DL_EVENT_TX_SUCCESS, 0, 0);
|
||||
}
|
||||
break;
|
||||
case DL_STATE_DISCARD:
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Discard frame\n");
|
||||
p_ctx->dl.state = DL_STATE_RX;
|
||||
continue_state_machine = FALSE;
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
ifx_i2c_pl_receive_frame(p_ctx);
|
||||
}
|
||||
break;
|
||||
case DL_STATE_ACK:
|
||||
{
|
||||
LOG_DL("[IFX-DL]: ACK sent\n");
|
||||
if (event == IFX_I2C_STACK_ERROR)
|
||||
{
|
||||
// If writing the ACK frame failed, Re-Send
|
||||
LOG_DL("[IFX-DL]: Physical Layer error -> Resend ACK\n");
|
||||
p_ctx->dl.state = DL_STATE_RESEND;
|
||||
break;
|
||||
}
|
||||
// Control frame successful transmitted
|
||||
p_ctx->dl.state = DL_STATE_IDLE;
|
||||
continue_state_machine = FALSE;
|
||||
if (p_ctx->dl.action_rx_only)
|
||||
{
|
||||
p_ctx->dl.upper_layer_event_handler(p_ctx,IFX_I2C_DL_EVENT_RX_SUCCESS, p_ctx->dl.p_rx_frame_buffer + 3,
|
||||
p_ctx->dl.rx_buffer_size - DL_HEADER_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctx->dl.upper_layer_event_handler(p_ctx,IFX_I2C_DL_EVENT_TX_SUCCESS | IFX_I2C_DL_EVENT_RX_SUCCESS,
|
||||
p_ctx->dl.p_rx_frame_buffer + 3, p_ctx->dl.rx_buffer_size - DL_HEADER_SIZE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DL_STATE_NACK:
|
||||
{
|
||||
// Sending NACK
|
||||
LOG_DL("[IFX-DL]: Sending NACK\n");
|
||||
p_ctx->dl.state = DL_STATE_TX;
|
||||
continue_state_machine = FALSE;
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
ifx_i2c_dl_send_frame_internal(p_ctx,0, DL_FCTR_SEQCTR_VALUE_NACK, 0);
|
||||
}
|
||||
break;
|
||||
case DL_STATE_RESEND:
|
||||
{
|
||||
//Resend frame
|
||||
ifx_i2c_dl_resend_frame(p_ctx,DL_FCTR_SEQCTR_VALUE_ACK);
|
||||
if(p_ctx->dl.state != DL_STATE_ERROR)
|
||||
{
|
||||
continue_state_machine = FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DL_STATE_ERROR:
|
||||
{
|
||||
if(!p_ctx->dl.resynced)
|
||||
{
|
||||
p_ctx->dl.error = 1;
|
||||
}
|
||||
if(0 == p_ctx->dl.error)
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Exit error after fatal error\n");
|
||||
//After sending resync, inform upper layer
|
||||
p_ctx->dl.state = DL_STATE_IDLE;
|
||||
p_ctx->dl.upper_layer_event_handler(p_ctx,IFX_I2C_DL_EVENT_ERROR, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DL("[IFX-DL]: Sending re-sync after fatal error\n");
|
||||
// Send re-sync to slave on error
|
||||
//lint --e{534} suppress "As this is last step, no effect of checking return code"
|
||||
ifx_i2c_dl_resync(p_ctx);
|
||||
p_ctx->dl.state = DL_STATE_ERROR;
|
||||
p_ctx->dl.error = 0;
|
||||
}
|
||||
continue_state_machine = FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_DL("[IFX-DL]: Default condition occurred. Exiting with error\n");
|
||||
p_ctx->dl.state = DL_STATE_IDLE;
|
||||
p_ctx->dl.upper_layer_event_handler(p_ctx,IFX_I2C_DL_EVENT_ERROR, 0, 0);
|
||||
continue_state_machine = FALSE;
|
||||
break;
|
||||
}
|
||||
}while(continue_state_machine == TRUE);
|
||||
LOG_DL("[IFX-DL]: #Exiting DL Handler\n");
|
||||
}
|
||||
755
external/infineon/optiga/comms/ifx_i2c/ifx_i2c_physical_layer.c
vendored
Normal file
755
external/infineon/optiga/comms/ifx_i2c/ifx_i2c_physical_layer.c
vendored
Normal file
@@ -0,0 +1,755 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018 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
|
||||
*
|
||||
*
|
||||
* \file ifx_i2c_physical_layer.c
|
||||
*
|
||||
* \brief This file implements the IFX I2C Physical Layer.
|
||||
*
|
||||
* \addtogroup grIFXI2C
|
||||
* @{
|
||||
*/
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* HEADER FILES
|
||||
**********************************************************************************************************************/
|
||||
#include "optiga/ifx_i2c/ifx_i2c_physical_layer.h"
|
||||
#include "optiga/pal/pal_os_event.h"
|
||||
|
||||
/// @cond hidden
|
||||
/***********************************************************************************************************************
|
||||
* MACROS
|
||||
**********************************************************************************************************************/
|
||||
// Physical Layer Register addresses
|
||||
#define PL_REG_DATA (0x80)
|
||||
#define PL_REG_DATA_REG_LEN (0x81)
|
||||
#define PL_REG_I2C_STATE (0x82)
|
||||
#define PL_REG_BASE_ADDR (0x83)
|
||||
#define PL_REG_MAX_SCL_FREQU (0x84)
|
||||
#define PL_REG_SOFT_RESET (0x88)
|
||||
#define PL_REG_I2C_MODE (0x89)
|
||||
|
||||
// Physical Layer Register lengths
|
||||
#define PL_REG_LEN_I2C_STATE (4)
|
||||
#define PL_REG_LEN_MAX_SCL_FREQU (4)
|
||||
#define PL_REG_LEN_I2C_MODE (2)
|
||||
#define PL_REG_LEN_DATA_REG_LEN (2)
|
||||
#define PL_REG_LEN_SOFT_RESET (2)
|
||||
#define PL_REG_LEN_BASE_ADDR (2)
|
||||
|
||||
// Physical Layer State Register masks
|
||||
#define PL_REG_I2C_STATE_RESPONSE_READY (0x40)
|
||||
#define PL_REG_I2C_STATE_SOFT_RESET (0x08)
|
||||
|
||||
// Physical Layer low level interface constants
|
||||
#define PL_ACTION_READ_REGISTER (0x01)
|
||||
#define PL_ACTION_WRITE_REGISTER (0x02)
|
||||
#define PL_I2C_CMD_WRITE (0x01)
|
||||
#define PL_I2C_CMD_READ (0x02)
|
||||
|
||||
// Physical Layer high level interface constants
|
||||
#define PL_ACTION_WRITE_FRAME (0x01)
|
||||
#define PL_ACTION_READ_FRAME (0x02)
|
||||
#define PL_STATE_UNINIT (0x00)
|
||||
#define PL_STATE_INIT (0x01)
|
||||
#define PL_STATE_READY (0x02)
|
||||
#define PL_STATE_DATA_AVAILABLE (0x03)
|
||||
#define PL_STATE_RXTX (0x04)
|
||||
#define PL_STATE_SOFT_RESET (0x05)
|
||||
|
||||
//Physical Layer negotiation constants
|
||||
#define PL_INIT_SET_DATA_REG_LEN (0x11)
|
||||
#define PL_INIT_GET_DATA_REG_LEN (0x22)
|
||||
#define PL_INIT_GET_FREQ_REG (0x33)
|
||||
#define PL_INIT_SET_FREQ_REG (0x44)
|
||||
#define PL_INIT_READ_FREQ (0x55)
|
||||
#define PL_INIT_VERIFY_FREQ (0x66)
|
||||
#define PL_INIT_AGREE_FREQ (0x77)
|
||||
#define PL_INIT_VERIFY_DATA_REG (0x88)
|
||||
#define PL_INIT_GET_STATUS_REG (0x99)
|
||||
#define PL_INIT_DONE (0xAA)
|
||||
#define PL_INIT_SET_FREQ_DEFAULT (0xBB)
|
||||
|
||||
//Physical layer soft reset states
|
||||
#define PL_RESET_INIT (0xA1)
|
||||
#define PL_RESET_WRITE (0xA2)
|
||||
#define PL_RESET_STARTUP (0xA3)
|
||||
|
||||
#define PL_REG_I2C_MODE_PERSISTANT (0x80)
|
||||
#define PL_REG_I2C_MODE_SM_FM (0x03)
|
||||
#define PL_REG_I2C_MODE_FM_PLUS (0x04)
|
||||
#define PL_SM_FM_MAX_FREQUENCY (0x190)
|
||||
#define PL_DEFAULT_FREQUENCY (0x64)
|
||||
#define PL_REG_BASE_ADDR_PERSISTANT (0x80)
|
||||
#define PL_REG_BASE_ADDR_VOLATILE (0x00)
|
||||
|
||||
// Physical Layer Base Address Register mask
|
||||
#define PL_REG_I2C_BASE_ADDRESS_MASK (0x7F)
|
||||
|
||||
// Setup debug log statements
|
||||
#if IFX_I2C_LOG_PL == 1
|
||||
#include "common/Log_api.h"
|
||||
#define LOG_PL(args...) ifx_debug_log(IFX_I2C_LOG_ID_PL, args)
|
||||
#else
|
||||
#define LOG_PL(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
/***********************************************************************************************************************
|
||||
* ENUMS
|
||||
**********************************************************************************************************************/
|
||||
/***********************************************************************************************************************
|
||||
* DATA STRUCTURES
|
||||
***********************************************************************************************************************/
|
||||
/***********************************************************************************************************************
|
||||
* GLOBAL
|
||||
***********************************************************************************************************************/
|
||||
|
||||
static host_lib_status_t pal_event_status;
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* LOCAL ROUTINES
|
||||
***********************************************************************************************************************/
|
||||
/// Physical Layer low level interface function
|
||||
static void ifx_i2c_pl_read_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len);
|
||||
/// Physical Layer low level interface function
|
||||
static void ifx_i2c_pl_write_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len, const uint8_t* p_content);
|
||||
/// Physical Layer high level interface timer callback (Status register polling)
|
||||
static void ifx_i2c_pl_status_poll_callback(void *p_ctx);
|
||||
/// Physical Layer intermediate state machine (Negotiation with slave)
|
||||
static void ifx_i2c_pl_negotiation_event_handler(void *p_input_ctx);
|
||||
/// Physical Layer intermediate state machine(Set bit rate)
|
||||
static host_lib_status_t ifx_i2c_pl_set_bit_rate(ifx_i2c_context_t *p_ctx, uint16_t bitrate);
|
||||
/// Physical Layer intermediate state machine (soft reset)
|
||||
static void ifx_i2c_pl_soft_reset(ifx_i2c_context_t *p_ctx);
|
||||
/// Physical Layer high level interface state machine (read/write frames)
|
||||
static void ifx_i2c_pl_frame_event_handler(ifx_i2c_context_t *p_ctx,host_lib_status_t event);
|
||||
/// Physical Layer low level interface timer callback (I2C Nack/Busy polling)
|
||||
static void ifx_i2c_pal_poll_callback(void *p_ctx);
|
||||
/// Physical Layer low level guard time callback
|
||||
static void ifx_i2c_pl_guard_time_callback(void *p_ctx);
|
||||
/// Physical Layer low level interface state machine (read/write registers)
|
||||
static void ifx_i2c_pl_pal_event_handler(void *p_ctx, host_lib_status_t event);
|
||||
/// Physical layer low level event handler for set slave address
|
||||
static void ifx_i2c_pl_pal_slave_addr_event_handler(void *p_input_ctx, host_lib_status_t event);
|
||||
|
||||
/// @endcond
|
||||
/***********************************************************************************************************************
|
||||
* API PROTOTYPES
|
||||
**********************************************************************************************************************/
|
||||
/// Physical Layer high level interface function
|
||||
host_lib_status_t ifx_i2c_pl_init(ifx_i2c_context_t *p_ctx,ifx_i2c_event_handler_t handler)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: Init\n");
|
||||
|
||||
p_ctx->pl.upper_layer_event_handler = handler;
|
||||
p_ctx->pl.frame_state = PL_STATE_UNINIT;
|
||||
p_ctx->pl.negotiate_state = PL_INIT_SET_FREQ_DEFAULT;
|
||||
p_ctx->p_pal_i2c_ctx->slave_address = p_ctx->slave_address;
|
||||
p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = (void*)ifx_i2c_pl_pal_event_handler;
|
||||
p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT;
|
||||
|
||||
if(TRUE == p_ctx->do_pal_init)
|
||||
{
|
||||
// Initialize I2C driver
|
||||
if (PAL_STATUS_SUCCESS != pal_i2c_init(p_ctx->p_pal_i2c_ctx))
|
||||
{
|
||||
return IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Set Physical Layer internal state
|
||||
if(p_ctx->pl.request_soft_reset == (uint8_t)TRUE)
|
||||
{
|
||||
//Set the soft reset request to initial state to read register
|
||||
p_ctx->pl.request_soft_reset = PL_INIT_GET_STATUS_REG;
|
||||
p_ctx->pl.frame_state = PL_STATE_SOFT_RESET;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctx->pl.frame_state = PL_STATE_INIT;
|
||||
}
|
||||
|
||||
ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS);
|
||||
|
||||
return IFX_I2C_STACK_SUCCESS;
|
||||
}
|
||||
|
||||
/// Physical Layer high level interface function
|
||||
host_lib_status_t ifx_i2c_pl_send_frame(ifx_i2c_context_t *p_ctx,uint8_t* p_frame, uint16_t frame_len)
|
||||
{
|
||||
// Physical Layer must be idle, set requested action
|
||||
if (p_ctx->pl.frame_state != PL_STATE_INIT && p_ctx->pl.frame_state != PL_STATE_READY)
|
||||
{
|
||||
return IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
p_ctx->pl.frame_action = PL_ACTION_WRITE_FRAME;
|
||||
|
||||
// Store reference to frame for sending it later
|
||||
p_ctx->pl.p_tx_frame = p_frame;
|
||||
p_ctx->pl.tx_frame_len = frame_len;
|
||||
|
||||
ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS);
|
||||
return IFX_I2C_STACK_SUCCESS;
|
||||
}
|
||||
|
||||
/// Physical Layer high level interface function
|
||||
host_lib_status_t ifx_i2c_pl_receive_frame(ifx_i2c_context_t *p_ctx)
|
||||
{
|
||||
// Physical Layer must be idle, set requested action
|
||||
if (p_ctx->pl.frame_state != PL_STATE_INIT && p_ctx->pl.frame_state != PL_STATE_READY)
|
||||
{
|
||||
return IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
p_ctx->pl.frame_action = PL_ACTION_READ_FRAME;
|
||||
|
||||
ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS);
|
||||
return IFX_I2C_STACK_SUCCESS;
|
||||
}
|
||||
|
||||
host_lib_status_t ifx_i2c_pl_write_slave_address(ifx_i2c_context_t *p_ctx, uint8_t slave_address, uint8_t persistent)
|
||||
{
|
||||
host_lib_status_t status = IFX_I2C_STACK_ERROR;
|
||||
app_event_handler_t * temp_upper_layer_event_handler;
|
||||
|
||||
/// @cond hidden
|
||||
#define PAL_WRITE_INIT_STATUS (0x00FF)
|
||||
#define ADDRESS_OFFSET (0x02)
|
||||
#define BASE_ADDRESS_REG_OFFSET (0x00)
|
||||
#define MODE_OFFSET (0x01)
|
||||
/// @endcond
|
||||
|
||||
//lint --e{611} suppress "void* function pointer is type casted to app_event_handler_t type"
|
||||
//ifx i2c wrapper api for setting slave address in synchronous. hence the event handler is backed up.
|
||||
temp_upper_layer_event_handler = (app_event_handler_t *)(p_ctx->p_pal_i2c_ctx->upper_layer_event_handler);
|
||||
//since the lower level APIs are asynchronous, a temporary event handler for set slave address is assigned
|
||||
p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = (void*)ifx_i2c_pl_pal_slave_addr_event_handler;
|
||||
|
||||
p_ctx->pl.buffer[BASE_ADDRESS_REG_OFFSET] = PL_REG_BASE_ADDR;
|
||||
p_ctx->pl.buffer[MODE_OFFSET] = PL_REG_BASE_ADDR_VOLATILE;
|
||||
//supported base addresses are 0x00 - 0x7F. Hence 8th bit is ignored
|
||||
p_ctx->pl.buffer[ADDRESS_OFFSET] = slave_address & PL_REG_I2C_BASE_ADDRESS_MASK;
|
||||
p_ctx->pl.buffer_tx_len = 1 + PL_REG_LEN_BASE_ADDR;
|
||||
|
||||
if(PL_REG_BASE_ADDR_VOLATILE != persistent)
|
||||
{
|
||||
p_ctx->pl.buffer[MODE_OFFSET] = PL_REG_BASE_ADDR_PERSISTANT;
|
||||
}
|
||||
|
||||
p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT;
|
||||
|
||||
while(p_ctx->pl.retry_counter)
|
||||
{
|
||||
pal_event_status = PAL_WRITE_INIT_STATUS;
|
||||
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
pal_i2c_write(p_ctx->p_pal_i2c_ctx,p_ctx->pl.buffer, p_ctx->pl.buffer_tx_len);
|
||||
while(PAL_WRITE_INIT_STATUS == pal_event_status){};
|
||||
if(PAL_I2C_EVENT_SUCCESS == pal_event_status)
|
||||
{
|
||||
break;
|
||||
}
|
||||
p_ctx->pl.retry_counter--;
|
||||
pal_os_timer_delay_in_milliseconds(PL_POLLING_INVERVAL_US);
|
||||
}
|
||||
|
||||
if(PAL_I2C_EVENT_SUCCESS == pal_event_status)
|
||||
{
|
||||
p_ctx->p_pal_i2c_ctx->slave_address = p_ctx->pl.buffer[ADDRESS_OFFSET];
|
||||
if(PL_REG_BASE_ADDR_VOLATILE != persistent)
|
||||
{
|
||||
p_ctx->slave_address = p_ctx->pl.buffer[ADDRESS_OFFSET];
|
||||
}
|
||||
status = IFX_I2C_STACK_SUCCESS;
|
||||
}
|
||||
//restoring the backed up event handler
|
||||
p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = temp_upper_layer_event_handler;
|
||||
|
||||
/// @cond hidden
|
||||
#undef PAL_WRITE_INIT_STATUS
|
||||
#undef ADDRESS_OFFSET
|
||||
#undef BASE_ADDRESS_REG_OFFSET
|
||||
#undef MODE_OFFSET
|
||||
/// @endcond
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void ifx_i2c_pl_read_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: Read register %x len %d\n", reg_addr, reg_len);
|
||||
|
||||
// Prepare transmit buffer to write register address
|
||||
p_ctx->pl.buffer[0] = reg_addr;
|
||||
p_ctx->pl.buffer_tx_len = 1;
|
||||
|
||||
// Set low level interface variables and start transmission
|
||||
p_ctx->pl.buffer_rx_len = reg_len;
|
||||
p_ctx->pl.register_action = PL_ACTION_READ_REGISTER;
|
||||
p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT;
|
||||
p_ctx->pl.i2c_cmd = PL_I2C_CMD_WRITE;
|
||||
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
pal_i2c_write(p_ctx->p_pal_i2c_ctx,p_ctx->pl.buffer, p_ctx->pl.buffer_tx_len);
|
||||
}
|
||||
|
||||
|
||||
static void ifx_i2c_pl_write_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len, const uint8_t* p_content)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: Write register %x len %d\n", reg_addr, reg_len);
|
||||
|
||||
// Prepare transmit buffer to write register address and content
|
||||
p_ctx->pl.buffer[0] = reg_addr;
|
||||
memcpy(p_ctx->pl.buffer + 1, p_content, reg_len);
|
||||
p_ctx->pl.buffer_tx_len = 1 + reg_len;
|
||||
|
||||
// Set Physical Layer low level interface variables and start transmission
|
||||
p_ctx->pl.register_action = PL_ACTION_WRITE_REGISTER;
|
||||
p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT;
|
||||
p_ctx->pl.i2c_cmd = PL_I2C_CMD_WRITE;
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
pal_i2c_write(p_ctx->p_pal_i2c_ctx,p_ctx->pl.buffer, p_ctx->pl.buffer_tx_len);
|
||||
}
|
||||
|
||||
|
||||
static void ifx_i2c_pl_status_poll_callback(void *p_ctx)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: Status poll Timer elapsed -> Read STATUS register\n");
|
||||
ifx_i2c_pl_read_register((ifx_i2c_context_t*)p_ctx,PL_REG_I2C_STATE, PL_REG_LEN_I2C_STATE);
|
||||
}
|
||||
|
||||
static host_lib_status_t ifx_i2c_pl_set_bit_rate(ifx_i2c_context_t *p_ctx, uint16_t bitrate)
|
||||
{
|
||||
host_lib_status_t status;
|
||||
void* pal_ctx_upper_layer_handler;
|
||||
// Save upper layer context in pal
|
||||
pal_ctx_upper_layer_handler = p_ctx->p_pal_i2c_ctx->upper_layer_event_handler;
|
||||
// Pass context as NULL to avoid callback invocation
|
||||
p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = NULL;
|
||||
status = pal_i2c_set_bitrate(p_ctx->p_pal_i2c_ctx , bitrate);
|
||||
// Restore callback
|
||||
p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = pal_ctx_upper_layer_handler;
|
||||
if(PAL_I2C_EVENT_SUCCESS != status)
|
||||
{
|
||||
if (p_ctx->pl.retry_counter--)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: Set bit rate failed, Retry setting.\n");
|
||||
pal_os_event_register_callback_oneshot(ifx_i2c_pl_negotiation_event_handler,((void*)p_ctx),PL_POLLING_INVERVAL_US);
|
||||
status = IFX_I2C_STACK_BUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = IFX_I2C_STACK_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
static void ifx_i2c_pl_negotiation_event_handler(void *p_input_ctx)
|
||||
{
|
||||
host_lib_status_t event = (uint8_t)IFX_I2C_STACK_ERROR;
|
||||
uint8_t continue_negotiation;
|
||||
ifx_i2c_context_t* p_ctx = (ifx_i2c_context_t*)p_input_ctx;
|
||||
uint8_t i2c_mode_value[2];
|
||||
uint8_t max_frame_size[2] = { (uint8_t)(p_ctx->frame_size >> 8), (uint8_t)(p_ctx->frame_size) };
|
||||
uint16_t buffer_len = 0;
|
||||
uint16_t slave_frequency;
|
||||
uint16_t slave_frame_len;
|
||||
uint8_t* p_buffer = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
continue_negotiation = FALSE;
|
||||
LOG_PL("[IFX-PL]: Negotiation started\n");
|
||||
switch(p_ctx->pl.negotiate_state)
|
||||
{
|
||||
// Set initial frequency to PL_DEFAULT_FREQUENCY to be able to negotiate with slave
|
||||
case PL_INIT_SET_FREQ_DEFAULT:
|
||||
{
|
||||
// Default frequency set to master
|
||||
event = ifx_i2c_pl_set_bit_rate(p_input_ctx,PL_DEFAULT_FREQUENCY);
|
||||
|
||||
if(IFX_I2C_STACK_SUCCESS == event)
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_GET_FREQ_REG;
|
||||
continue_negotiation = TRUE;
|
||||
}
|
||||
else if (IFX_I2C_STACK_ERROR == event)
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_DONE;
|
||||
p_buffer = NULL;
|
||||
buffer_len = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Read the current Max frequency supported by slave
|
||||
case PL_INIT_GET_FREQ_REG:
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_SET_FREQ_REG;
|
||||
ifx_i2c_pl_read_register(p_ctx,PL_REG_MAX_SCL_FREQU, PL_REG_LEN_MAX_SCL_FREQU);
|
||||
}
|
||||
break;
|
||||
// Set the I2C mode register
|
||||
case PL_INIT_SET_FREQ_REG:
|
||||
{
|
||||
slave_frequency = (p_ctx->pl.buffer[2] << 8) | p_ctx->pl.buffer[3];
|
||||
|
||||
i2c_mode_value[0] = PL_REG_I2C_MODE_PERSISTANT;
|
||||
if((p_ctx->frequency > PL_SM_FM_MAX_FREQUENCY)&&(slave_frequency<=PL_SM_FM_MAX_FREQUENCY))
|
||||
{
|
||||
//Change to FM+ mode if slave's current supported frequency is below user's requested frequency
|
||||
i2c_mode_value[1] = PL_REG_I2C_MODE_FM_PLUS;
|
||||
p_ctx->pl.negotiate_state = PL_INIT_READ_FREQ;
|
||||
ifx_i2c_pl_write_register(p_ctx,PL_REG_I2C_MODE, PL_REG_LEN_I2C_MODE, i2c_mode_value);
|
||||
}
|
||||
else if((p_ctx->frequency <= PL_SM_FM_MAX_FREQUENCY)&&(slave_frequency>PL_SM_FM_MAX_FREQUENCY))
|
||||
{
|
||||
//Change to SM&FM mode if slave's current supported frequency is above user's requested frequency
|
||||
i2c_mode_value[1] = PL_REG_I2C_MODE_SM_FM;
|
||||
p_ctx->pl.negotiate_state = PL_INIT_READ_FREQ;
|
||||
ifx_i2c_pl_write_register(p_ctx,PL_REG_I2C_MODE, PL_REG_LEN_I2C_MODE, i2c_mode_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_VERIFY_FREQ;
|
||||
continue_negotiation = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// After setting I2C mode register, read the slave's supported frequency
|
||||
case PL_INIT_READ_FREQ:
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_VERIFY_FREQ;
|
||||
ifx_i2c_pl_read_register(p_ctx,PL_REG_MAX_SCL_FREQU, PL_REG_LEN_MAX_SCL_FREQU);
|
||||
}
|
||||
break;
|
||||
// Verify the requested frequency and slave's supported frequency
|
||||
case PL_INIT_VERIFY_FREQ:
|
||||
{
|
||||
slave_frequency = (p_ctx->pl.buffer[2] << 8) | p_ctx->pl.buffer[3];
|
||||
if(p_ctx->frequency > slave_frequency)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: Unexpected frequency in MAX_SCL_FREQU\n");
|
||||
p_buffer = NULL;
|
||||
buffer_len = 0;
|
||||
p_ctx->pl.negotiate_state = PL_INIT_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_AGREE_FREQ;
|
||||
}
|
||||
continue_negotiation = TRUE;
|
||||
}
|
||||
break;
|
||||
// Frequency negotiated, Set frequency at master
|
||||
case PL_INIT_AGREE_FREQ:
|
||||
{
|
||||
// Frequency negotiation between master and slave is complete
|
||||
event = ifx_i2c_pl_set_bit_rate(p_input_ctx, p_ctx->frequency);
|
||||
if(IFX_I2C_STACK_SUCCESS == event)
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_SET_DATA_REG_LEN;
|
||||
continue_negotiation = TRUE;
|
||||
}
|
||||
else if (IFX_I2C_STACK_ERROR == event)
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_DONE;
|
||||
p_buffer = NULL;
|
||||
buffer_len = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Start frame length negotiation by writing the requested frame length
|
||||
case PL_INIT_SET_DATA_REG_LEN:
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_GET_DATA_REG_LEN;
|
||||
ifx_i2c_pl_write_register(p_ctx,PL_REG_DATA_REG_LEN, sizeof(max_frame_size), max_frame_size);
|
||||
}
|
||||
break;
|
||||
// Read the frame length to verify
|
||||
case PL_INIT_GET_DATA_REG_LEN:
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_VERIFY_DATA_REG;
|
||||
ifx_i2c_pl_read_register(p_ctx,PL_REG_DATA_REG_LEN,PL_REG_LEN_DATA_REG_LEN);
|
||||
}
|
||||
break;
|
||||
// Check is slave accepted the new frame length
|
||||
case PL_INIT_VERIFY_DATA_REG:
|
||||
{
|
||||
p_ctx->pl.negotiate_state = PL_INIT_DONE;
|
||||
slave_frame_len = (p_ctx->pl.buffer[0] << 8) | p_ctx->pl.buffer[1];
|
||||
// Error if slave's frame length is more than requested frame length
|
||||
if(p_ctx->frame_size >= slave_frame_len)
|
||||
{
|
||||
p_ctx->frame_size = slave_frame_len;
|
||||
event = IFX_I2C_STACK_SUCCESS;
|
||||
}
|
||||
p_buffer = NULL;
|
||||
buffer_len = 0;
|
||||
continue_negotiation = TRUE;
|
||||
}
|
||||
break;
|
||||
case PL_INIT_DONE:
|
||||
{
|
||||
if(IFX_I2C_STACK_SUCCESS == event)
|
||||
{
|
||||
p_ctx->pl.frame_state = PL_STATE_READY;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctx->pl.frame_state = PL_STATE_UNINIT;
|
||||
}
|
||||
// Negotiation between master and slave is complete
|
||||
p_ctx->pl.upper_layer_event_handler(p_ctx,event, p_buffer, buffer_len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}while(continue_negotiation);
|
||||
}
|
||||
|
||||
|
||||
static void ifx_i2c_pl_frame_event_handler(ifx_i2c_context_t *p_ctx,host_lib_status_t event)
|
||||
{
|
||||
uint16_t frame_size;
|
||||
if (event != IFX_I2C_STACK_SUCCESS)
|
||||
{
|
||||
p_ctx->pl.frame_state = PL_STATE_READY;
|
||||
// I2C read or write failed, report to upper layer
|
||||
p_ctx->pl.upper_layer_event_handler(p_ctx,event, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(p_ctx->pl.frame_state)
|
||||
{
|
||||
// Perform soft reset
|
||||
case PL_STATE_SOFT_RESET:
|
||||
{
|
||||
ifx_i2c_pl_soft_reset(p_ctx);
|
||||
}
|
||||
break;
|
||||
// Negotiate frame and frequency with slave
|
||||
case PL_STATE_INIT:
|
||||
{
|
||||
ifx_i2c_pl_negotiation_event_handler(p_ctx);
|
||||
}
|
||||
break;
|
||||
// Check status of slave data
|
||||
case PL_STATE_READY:
|
||||
{
|
||||
// Start polling status register
|
||||
p_ctx->pl.frame_state = PL_STATE_DATA_AVAILABLE;
|
||||
ifx_i2c_pl_read_register(p_ctx,PL_REG_I2C_STATE, PL_REG_LEN_I2C_STATE);
|
||||
}
|
||||
break;
|
||||
// Do read/write frame
|
||||
case PL_STATE_DATA_AVAILABLE:
|
||||
{
|
||||
// Read frame, if response is ready. Ignore busy flag
|
||||
if ((p_ctx->pl.frame_action == PL_ACTION_READ_FRAME)
|
||||
&& (p_ctx->pl.buffer[0] & PL_REG_I2C_STATE_RESPONSE_READY))
|
||||
{
|
||||
frame_size = (p_ctx->pl.buffer[2] << 8) | p_ctx->pl.buffer[3];
|
||||
if ((frame_size > 0) && (frame_size <= p_ctx->frame_size))
|
||||
{
|
||||
p_ctx->pl.frame_state = PL_STATE_RXTX;
|
||||
ifx_i2c_pl_read_register(p_ctx,PL_REG_DATA, frame_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Continue polling STATUS register if retry limit is not reached
|
||||
if ((pal_os_timer_get_time_in_milliseconds() - p_ctx->dl.frame_start_time) < p_ctx->dl.data_poll_timeout)
|
||||
{
|
||||
pal_os_event_register_callback_oneshot(ifx_i2c_pl_status_poll_callback, (void *)p_ctx, PL_DATA_POLLING_INVERVAL_US);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctx->pl.frame_state = PL_STATE_READY;
|
||||
p_ctx->pl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_ERROR, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Write frame is slave is not busy
|
||||
else if (p_ctx->pl.frame_action == PL_ACTION_WRITE_FRAME)
|
||||
{
|
||||
// Write frame if device is not busy, otherwise wait and poll STATUS again later
|
||||
p_ctx->pl.frame_state = PL_STATE_RXTX;
|
||||
ifx_i2c_pl_write_register(p_ctx,PL_REG_DATA, p_ctx->pl.tx_frame_len, (uint8_t*)p_ctx->pl.p_tx_frame);
|
||||
}
|
||||
// Continue checking the slave status register
|
||||
else
|
||||
{
|
||||
// Continue polling STATUS register if retry limit is not reached
|
||||
if ((pal_os_timer_get_time_in_milliseconds() - p_ctx->dl.frame_start_time) < p_ctx->dl.data_poll_timeout)
|
||||
{
|
||||
pal_os_event_register_callback_oneshot(ifx_i2c_pl_status_poll_callback, (void *)p_ctx, PL_DATA_POLLING_INVERVAL_US);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctx->pl.frame_state = PL_STATE_READY;
|
||||
p_ctx->pl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_ERROR, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Frame reading is complete
|
||||
case PL_STATE_RXTX:
|
||||
{
|
||||
// Writing/reading of frame to/from DATA register complete
|
||||
p_ctx->pl.frame_state = PL_STATE_READY;
|
||||
p_ctx->pl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS, p_ctx->pl.buffer, p_ctx->pl.buffer_rx_len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ifx_i2c_pal_poll_callback(void *p_ctx)
|
||||
{
|
||||
ifx_i2c_context_t* p_local_ctx = (ifx_i2c_context_t *)p_ctx;
|
||||
if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_WRITE)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: Poll Timer elapsed -> Restart TX\n");
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
pal_i2c_write(p_local_ctx->p_pal_i2c_ctx, p_local_ctx->pl.buffer, p_local_ctx->pl.buffer_tx_len);
|
||||
}
|
||||
else if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_READ)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: Poll Timer elapsed -> Restart Read Register -> Start TX\n");
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
pal_i2c_read(p_local_ctx->p_pal_i2c_ctx,p_local_ctx->pl.buffer, p_local_ctx->pl.buffer_rx_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ifx_i2c_pl_guard_time_callback(void *p_ctx)
|
||||
{
|
||||
ifx_i2c_context_t* p_local_ctx = (ifx_i2c_context_t*)p_ctx;
|
||||
if (p_local_ctx->pl.register_action == PL_ACTION_READ_REGISTER)
|
||||
{
|
||||
if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_WRITE)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: GT done-> Start RX\n");
|
||||
p_local_ctx->pl.i2c_cmd = PL_I2C_CMD_READ;
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
pal_i2c_read(p_local_ctx->p_pal_i2c_ctx,p_local_ctx->pl.buffer, p_local_ctx->pl.buffer_rx_len);
|
||||
}
|
||||
else if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_READ)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: GT done -> REG is read\n");
|
||||
ifx_i2c_pl_frame_event_handler(p_local_ctx,IFX_I2C_STACK_SUCCESS);
|
||||
}
|
||||
}
|
||||
else if (p_local_ctx->pl.register_action == PL_ACTION_WRITE_REGISTER)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: GT done -> REG written\n");
|
||||
ifx_i2c_pl_frame_event_handler(p_local_ctx,IFX_I2C_STACK_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
static void ifx_i2c_pl_pal_event_handler(void *p_ctx, host_lib_status_t event)
|
||||
{
|
||||
ifx_i2c_context_t* p_local_ctx = (ifx_i2c_context_t*)p_ctx;
|
||||
switch (event)
|
||||
{
|
||||
case PAL_I2C_EVENT_ERROR:
|
||||
case PAL_I2C_EVENT_BUSY:
|
||||
// Error event usually occurs when the device is in sleep mode and needs time to wake up
|
||||
if (p_local_ctx->pl.retry_counter--)
|
||||
{
|
||||
LOG_PL("[IFX-PL]: PAL Error -> Continue polling\n");
|
||||
pal_os_event_register_callback_oneshot(ifx_i2c_pal_poll_callback,p_local_ctx,PL_POLLING_INVERVAL_US);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PL("[IFX-PL]: PAL Error -> Stop\n");
|
||||
ifx_i2c_pl_frame_event_handler(p_local_ctx,IFX_I2C_FATAL_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case PAL_I2C_EVENT_SUCCESS:
|
||||
LOG_PL("[IFX-PL]: PAL Success -> Wait Guard Time\n");
|
||||
pal_os_event_register_callback_oneshot(ifx_i2c_pl_guard_time_callback,p_local_ctx,PL_GUARD_TIME_INTERVAL_US);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ifx_i2c_pl_soft_reset(ifx_i2c_context_t *p_ctx)
|
||||
{
|
||||
uint8_t i2c_mode_value[2] = {0};
|
||||
switch(p_ctx->pl.request_soft_reset)
|
||||
{
|
||||
case PL_INIT_GET_STATUS_REG:
|
||||
p_ctx->pl.request_soft_reset = PL_RESET_WRITE;
|
||||
//Read the status register to check if soft reset is supported
|
||||
ifx_i2c_pl_read_register(p_ctx, PL_REG_I2C_STATE, PL_REG_LEN_I2C_STATE);
|
||||
break;
|
||||
|
||||
case PL_RESET_WRITE:
|
||||
//Mask for soft reset bit(5th bit) from the 1st byte of status register
|
||||
p_ctx->pl.buffer[0] &= PL_REG_I2C_STATE_SOFT_RESET;
|
||||
if(p_ctx->pl.buffer[0] == PL_REG_I2C_STATE_SOFT_RESET)
|
||||
{
|
||||
p_ctx->pl.request_soft_reset = PL_RESET_STARTUP;
|
||||
//Write 88 register with 0 value
|
||||
ifx_i2c_pl_write_register(p_ctx, PL_REG_SOFT_RESET, PL_REG_LEN_SOFT_RESET, i2c_mode_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Soft reset is not supported by the slave
|
||||
p_ctx->pl.frame_state = PL_STATE_UNINIT;
|
||||
ifx_i2c_pl_frame_event_handler(p_ctx, IFX_I2C_STACK_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case PL_RESET_STARTUP:
|
||||
p_ctx->pl.request_soft_reset= PL_RESET_INIT;
|
||||
pal_os_event_register_callback_oneshot((register_callback)ifx_i2c_pl_soft_reset, (void *)p_ctx, STARTUP_TIME_MSEC);
|
||||
break;
|
||||
|
||||
case PL_RESET_INIT:
|
||||
p_ctx->pl.frame_state = PL_STATE_INIT;
|
||||
ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//lint --e{715} suppress "This is used for synchromous implementation, hence p_ctx not used"
|
||||
//lint --e{818} suppress "This is ignored as upper layer handler function prototype requires this argument"
|
||||
static void ifx_i2c_pl_pal_slave_addr_event_handler(void *p_ctx, host_lib_status_t event)
|
||||
{
|
||||
pal_event_status = event;
|
||||
}
|
||||
|
||||
517
external/infineon/optiga/comms/ifx_i2c/ifx_i2c_transport_layer.c
vendored
Normal file
517
external/infineon/optiga/comms/ifx_i2c/ifx_i2c_transport_layer.c
vendored
Normal file
@@ -0,0 +1,517 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018 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
|
||||
*
|
||||
*
|
||||
* \file ifx_i2c_transport_layer.c
|
||||
*
|
||||
* \brief This file implements the IFX I2C Transport Layer.
|
||||
*
|
||||
* \addtogroup grIFXI2C
|
||||
* @{
|
||||
*/
|
||||
/***********************************************************************************************************************
|
||||
* HEADER FILES
|
||||
**********************************************************************************************************************/
|
||||
#include "optiga/ifx_i2c/ifx_i2c_transport_layer.h"
|
||||
#include "optiga/ifx_i2c/ifx_i2c_data_link_layer.h" // include lower layer header
|
||||
|
||||
/// @cond hidden
|
||||
/***********************************************************************************************************************
|
||||
* MACROS
|
||||
**********************************************************************************************************************/
|
||||
// Transport Layer states
|
||||
#define TL_STATE_UNINIT (0x00)
|
||||
#define TL_STATE_IDLE (0x01)
|
||||
#define TL_STATE_TX (0x02)
|
||||
#define TL_STATE_RX (0x04)
|
||||
#define TL_STATE_CHAINING (0x05)
|
||||
#define TL_STATE_ERROR (0x06)
|
||||
#define TL_STATE_CHAINING_ERROR (0x07)
|
||||
#define TL_STATE_RESEND (0x08)
|
||||
// Transport Layer header size
|
||||
#define TL_HEADER_SIZE 1
|
||||
|
||||
// Transport Layer chaining values
|
||||
#define TL_CHAINING_NO (0x00)
|
||||
#define TL_CHAINING_FIRST (0x01)
|
||||
#define TL_CHAINING_INTERMEDIATE (0x02)
|
||||
#define TL_CHAINING_LAST (0x04)
|
||||
#define TL_CHAINING_ERROR (0x07)
|
||||
|
||||
#define TL_PCTR_CHANNEL_MASK (0xF8)
|
||||
#define TL_PCTR_CHAIN_MASK (0x07)
|
||||
// Setup debug log statements
|
||||
#if IFX_I2C_LOG_TL == 1
|
||||
#include "common/Log_api.h"
|
||||
#define LOG_TL(args...) ifx_debug_log(IFX_I2C_LOG_ID_TL, args)
|
||||
#else
|
||||
#define LOG_TL(...) //printf(__VA_ARGS__);
|
||||
#endif
|
||||
/***********************************************************************************************************************
|
||||
* ENUMS
|
||||
**********************************************************************************************************************/
|
||||
/***********************************************************************************************************************
|
||||
* DATA STRUCTURES
|
||||
***********************************************************************************************************************/
|
||||
static uint8_t pctr_states_table[5][2]={
|
||||
{TL_CHAINING_NO,TL_CHAINING_LAST},
|
||||
{TL_CHAINING_NO,TL_CHAINING_LAST},
|
||||
{TL_CHAINING_FIRST,TL_CHAINING_INTERMEDIATE},
|
||||
{0xFF,0xFF},
|
||||
{TL_CHAINING_FIRST,TL_CHAINING_INTERMEDIATE},
|
||||
};
|
||||
/***********************************************************************************************************************
|
||||
* GLOBAL
|
||||
***********************************************************************************************************************/
|
||||
|
||||
/***********************************************************************************************************************
|
||||
* LOCAL ROUTINES
|
||||
***********************************************************************************************************************/
|
||||
/// Sends available fragment
|
||||
_STATIC_H host_lib_status_t ifx_i2c_tl_send_next_fragment(ifx_i2c_context_t *p_ctx);
|
||||
/// Datalink Layer event handler
|
||||
_STATIC_H void ifx_i2c_dl_event_handler(ifx_i2c_context_t* p_ctx,host_lib_status_t event, const uint8_t* p_data, uint16_t data_len);
|
||||
/// Resends all the packets
|
||||
_STATIC_H host_lib_status_t ifx_i2c_tl_resend_packets(ifx_i2c_context_t *p_ctx);
|
||||
/// Sends chaining error to I2C slave
|
||||
_STATIC_H host_lib_status_t ifx_i2c_tl_send_chaining_error(ifx_i2c_context_t *p_ctx);
|
||||
/// Calculates the pctr value
|
||||
_STATIC_H uint8_t ifx_i2c_tl_calculate_pctr(const ifx_i2c_context_t *p_ctx);
|
||||
/// Checks if chaining error occured based on current and previous pctr
|
||||
_STATIC_H host_lib_status_t ifx_i2c_tl_check_chaining_error(uint8_t current_chaning, uint8_t previous_chaining);
|
||||
/// @endcond
|
||||
/***********************************************************************************************************************
|
||||
* API PROTOTYPES
|
||||
**********************************************************************************************************************/
|
||||
/// Transport Layer initialization function
|
||||
host_lib_status_t ifx_i2c_tl_init(ifx_i2c_context_t *p_ctx,ifx_i2c_event_handler_t handler)
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Init\n");
|
||||
|
||||
p_ctx->tl.state = TL_STATE_UNINIT;
|
||||
|
||||
// Initialize Data Link layer (and register event handler)
|
||||
if (ifx_i2c_dl_init(p_ctx,ifx_i2c_dl_event_handler) != IFX_I2C_STACK_SUCCESS)
|
||||
{
|
||||
return IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
|
||||
p_ctx->tl.upper_layer_event_handler = handler;
|
||||
p_ctx->tl.state = TL_STATE_IDLE;
|
||||
p_ctx->tl.max_packet_length = p_ctx->frame_size - (DL_HEADER_SIZE + TL_HEADER_SIZE);
|
||||
|
||||
return IFX_I2C_STACK_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
host_lib_status_t ifx_i2c_tl_transceive(ifx_i2c_context_t *p_ctx,uint8_t* p_packet, uint16_t packet_len,
|
||||
uint8_t* p_recv_packet, uint16_t* recv_packet_len)
|
||||
{
|
||||
host_lib_status_t status = IFX_I2C_STACK_ERROR;
|
||||
LOG_TL("[IFX-TL]: Transceive txlen %d\n", packet_len);
|
||||
|
||||
do
|
||||
{
|
||||
// Check function arguments
|
||||
if (p_packet == NULL || packet_len == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Transport Layer must be idle
|
||||
if (p_ctx->tl.state != TL_STATE_IDLE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
p_ctx->tl.state = TL_STATE_TX;
|
||||
p_ctx->tl.api_start_time = pal_os_timer_get_time_in_milliseconds();
|
||||
p_ctx->tl.p_actual_packet = p_packet;
|
||||
p_ctx->tl.actual_packet_length = packet_len;
|
||||
p_ctx->tl.packet_offset = 0;
|
||||
p_ctx->tl.p_recv_packet_buffer = p_recv_packet;
|
||||
p_ctx->tl.p_recv_packet_buffer_length = recv_packet_len;
|
||||
p_ctx->tl.total_recv_length = 0;
|
||||
p_ctx->tl.chaining_error_count = 0;
|
||||
p_ctx->tl.master_chaining_error_count = 0;
|
||||
p_ctx->tl.transmission_completed = 0;
|
||||
p_ctx->tl.error_event = IFX_I2C_STACK_ERROR;
|
||||
status = ifx_i2c_tl_send_next_fragment(p_ctx);
|
||||
}while(FALSE);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
_STATIC_H host_lib_status_t ifx_i2c_tl_resend_packets(ifx_i2c_context_t *p_ctx)
|
||||
{
|
||||
// Transport Layer must be idle
|
||||
if (p_ctx->tl.state != TL_STATE_IDLE)
|
||||
{
|
||||
return IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
|
||||
p_ctx->tl.packet_offset = 0;
|
||||
p_ctx->tl.total_recv_length = 0;
|
||||
p_ctx->tl.state = TL_STATE_TX;
|
||||
return ifx_i2c_tl_send_next_fragment(p_ctx);
|
||||
}
|
||||
|
||||
_STATIC_H uint8_t ifx_i2c_tl_calculate_pctr(const ifx_i2c_context_t *p_ctx)
|
||||
{
|
||||
uint8_t pctr;
|
||||
uint16_t fragment_size = p_ctx->tl.max_packet_length;
|
||||
uint16_t remaining_data = p_ctx->tl.actual_packet_length - p_ctx->tl.packet_offset;
|
||||
// No chain
|
||||
if((p_ctx->tl.packet_offset==0)&&(remaining_data<=fragment_size))
|
||||
{
|
||||
pctr = TL_CHAINING_NO;
|
||||
}
|
||||
// First chain
|
||||
else if((p_ctx->tl.packet_offset==0)&&(remaining_data>fragment_size))
|
||||
{
|
||||
pctr = TL_CHAINING_FIRST;
|
||||
}
|
||||
// Intermediate chain
|
||||
else if((p_ctx->tl.packet_offset!=0)&&(remaining_data>fragment_size))
|
||||
{
|
||||
pctr = TL_CHAINING_INTERMEDIATE;
|
||||
}
|
||||
// Last chain
|
||||
else
|
||||
{
|
||||
pctr = TL_CHAINING_LAST;
|
||||
}
|
||||
|
||||
return pctr;
|
||||
}
|
||||
_STATIC_H host_lib_status_t ifx_i2c_tl_send_next_fragment(ifx_i2c_context_t *p_ctx)
|
||||
{
|
||||
uint8_t pctr = 0;
|
||||
// Calculate size of fragment (last one might be shorter)
|
||||
uint16_t tl_fragment_size = p_ctx->tl.max_packet_length;
|
||||
pctr = ifx_i2c_tl_calculate_pctr(p_ctx);
|
||||
if ((p_ctx->tl.actual_packet_length - p_ctx->tl.packet_offset) < tl_fragment_size)
|
||||
{
|
||||
tl_fragment_size = p_ctx->tl.actual_packet_length - p_ctx->tl.packet_offset;
|
||||
}
|
||||
|
||||
// Assign the pctr
|
||||
p_ctx->tx_frame_buffer[IFX_I2C_TL_HEADER_OFFSET] = pctr;
|
||||
//copy the data
|
||||
memcpy(p_ctx->tx_frame_buffer+IFX_I2C_TL_HEADER_OFFSET+1,p_ctx->tl.p_actual_packet + p_ctx->tl.packet_offset,tl_fragment_size);
|
||||
p_ctx->tl.packet_offset += tl_fragment_size;
|
||||
//send the fragment to dl layer
|
||||
return ifx_i2c_dl_send_frame(p_ctx,tl_fragment_size+1);
|
||||
}
|
||||
|
||||
_STATIC_H host_lib_status_t ifx_i2c_tl_send_chaining_error(ifx_i2c_context_t *p_ctx)
|
||||
{
|
||||
uint16_t tl_fragment_size = 1;
|
||||
p_ctx->tx_frame_buffer[IFX_I2C_TL_HEADER_OFFSET] = 0x07;
|
||||
p_ctx->tl.total_recv_length = 0;
|
||||
//send the fragment to dl layer
|
||||
return ifx_i2c_dl_send_frame(p_ctx,tl_fragment_size);
|
||||
}
|
||||
|
||||
_STATIC_H host_lib_status_t ifx_i2c_tl_check_chaining_error(uint8_t current_chaning, uint8_t previous_chaining)
|
||||
{
|
||||
host_lib_status_t status = IFX_I2C_STACK_ERROR;
|
||||
if(((current_chaning == TL_CHAINING_ERROR) || (current_chaning == TL_CHAINING_NO) || (current_chaning == TL_CHAINING_LAST)
|
||||
|| (current_chaning == TL_CHAINING_INTERMEDIATE) || (current_chaning == TL_CHAINING_FIRST)))
|
||||
{
|
||||
if((pctr_states_table[current_chaning][0] == previous_chaining) || (pctr_states_table[current_chaning][1] == previous_chaining))
|
||||
{
|
||||
status = IFX_I2C_STACK_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_STATIC_H void ifx_i2c_dl_event_handler(ifx_i2c_context_t* p_ctx,host_lib_status_t event, const uint8_t* p_data, uint16_t data_len)
|
||||
{
|
||||
uint8_t pctr = 0;
|
||||
uint8_t chaining = 0;
|
||||
uint8_t exit_machine = TRUE;
|
||||
do
|
||||
{
|
||||
if(NULL != p_data)
|
||||
{
|
||||
pctr = p_data[0];
|
||||
chaining = pctr & TL_PCTR_CHAIN_MASK;
|
||||
}
|
||||
// Propagate errors to upper layer
|
||||
if ((event & IFX_I2C_DL_EVENT_ERROR)||(pctr & TL_PCTR_CHANNEL_MASK))
|
||||
{
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
p_ctx->tl.error_event = IFX_I2C_STACK_ERROR;
|
||||
}
|
||||
switch(p_ctx->tl.state)
|
||||
{
|
||||
case TL_STATE_IDLE:
|
||||
{
|
||||
exit_machine = FALSE;
|
||||
p_ctx->tl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS, 0, 0);
|
||||
}
|
||||
break;
|
||||
case TL_STATE_TX:
|
||||
{
|
||||
// Frame transmission in Data Link layer complete, start receiving frames
|
||||
if (event & IFX_I2C_DL_EVENT_TX_SUCCESS)
|
||||
{
|
||||
if (p_ctx->tl.packet_offset < p_ctx->tl.actual_packet_length)
|
||||
{
|
||||
// Transmission of one fragment complete, send next fragment
|
||||
LOG_TL("[IFX-TL]: Tx:Fragment sent,now send next\n");
|
||||
// Chaining error from slave
|
||||
if(TL_CHAINING_ERROR == chaining)
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Tx:Chaining error received while Tx\n");
|
||||
p_ctx->tl.state = TL_STATE_RESEND;
|
||||
break;
|
||||
}
|
||||
// Any fragment received before complete transmission is error
|
||||
if(data_len)
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Tx:Data received while Tx\n");
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
exit_machine = FALSE;
|
||||
//lint --e{534} suppress "Return value is not required to be checked"
|
||||
ifx_i2c_tl_send_next_fragment(p_ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transmission of all fragments complete, start receiving fragments
|
||||
LOG_TL("[IFX-TL]: Tx:All fragment sent\n");
|
||||
p_ctx->tl.state = TL_STATE_RX;
|
||||
p_ctx->tl.total_recv_length = 0;
|
||||
p_ctx->tl.previous_chaining = TL_CHAINING_NO;
|
||||
p_ctx->tl.transmission_completed = 1;
|
||||
// if data is received after sending last frame
|
||||
if (!(event & IFX_I2C_DL_EVENT_RX_SUCCESS))
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Tx:Data already received after Tx\n");
|
||||
// Received CTRL frame, trigger reception in Data Link layer
|
||||
if (ifx_i2c_dl_receive_frame(p_ctx))
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Tx:RX Received CTRL frame fail -> Inform UL\n");
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
}
|
||||
exit_machine = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Tx:IFX_I2C_DL_EVENT_TX_SUCCESS is not satisfied Tx\n");
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TL_STATE_RX:
|
||||
{
|
||||
// Reception of frame from Data Link layer
|
||||
if (event & IFX_I2C_DL_EVENT_RX_SUCCESS)
|
||||
{
|
||||
// Message must contain at least the transport layer header
|
||||
if (data_len < TL_HEADER_SIZE)
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Rx : Data received is more than header len\n");
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if(p_ctx->tl.error_event == IFX_I2C_STACK_MEM_ERROR)
|
||||
{
|
||||
if ((chaining == TL_CHAINING_LAST) || (ifx_i2c_dl_receive_frame(p_ctx)))
|
||||
{
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
p_ctx->tl.state = TL_STATE_RX;
|
||||
exit_machine = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
// If chaining error detected
|
||||
if(IFX_I2C_STACK_SUCCESS != ifx_i2c_tl_check_chaining_error(chaining,p_ctx->tl.previous_chaining))
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Rx : Chaining state is not correct\n");
|
||||
p_ctx->tl.state = TL_STATE_RESEND;
|
||||
break;
|
||||
}
|
||||
|
||||
p_ctx->tl.previous_chaining = chaining;
|
||||
if(NULL == p_data)
|
||||
{
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
// No chaining and Last
|
||||
if ((chaining == TL_CHAINING_NO)||(chaining == TL_CHAINING_LAST))
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Rx : No chain/Last chain received, Inform UL\n");
|
||||
|
||||
exit_machine = FALSE;
|
||||
// Copy frame payload to transport layer receive buffer
|
||||
memcpy(p_ctx->tl.p_recv_packet_buffer + p_ctx->tl.total_recv_length, p_data + 1, data_len - 1);
|
||||
p_ctx->tl.total_recv_length += (data_len - 1);
|
||||
// Inform upper layer that a packet has arrived
|
||||
p_ctx->tl.state = TL_STATE_IDLE;
|
||||
*p_ctx->tl.p_recv_packet_buffer_length = p_ctx->tl.total_recv_length;
|
||||
p_ctx->tl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS, p_ctx->tl.p_recv_packet_buffer, *p_ctx->tl.p_recv_packet_buffer_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctx->tl.state = TL_STATE_CHAINING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Tx:IFX_I2C_DL_EVENT_TX_SUCCESS is not satisfied Tx\n");
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TL_STATE_CHAINING:
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Chain : Chaining mode entered\n");
|
||||
// When receiving a starting fragment, fragment length must be max frame size for intermediate and last frame
|
||||
// the buffer should not be empty
|
||||
if (data_len != (p_ctx->tl.max_packet_length+1))
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Chain : Data len not equal to max frame size\n");
|
||||
p_ctx->tl.state = TL_STATE_CHAINING_ERROR;
|
||||
break;
|
||||
}
|
||||
// Check for possible receive buffer overflow
|
||||
if ((p_ctx->tl.total_recv_length + data_len - 1) > (*p_ctx->tl.p_recv_packet_buffer_length))
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Chain : Buffer overflow\n");
|
||||
p_ctx->tl.error_event = IFX_I2C_STACK_MEM_ERROR;
|
||||
p_ctx->tl.state = TL_STATE_RX;
|
||||
break;
|
||||
}
|
||||
if(NULL == p_data)
|
||||
{
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
// Copy frame payload to transport layer receive buffer
|
||||
memcpy(p_ctx->tl.p_recv_packet_buffer + p_ctx->tl.total_recv_length, p_data + 1, data_len - 1);
|
||||
p_ctx->tl.total_recv_length += (data_len - 1);
|
||||
|
||||
p_ctx->tl.previous_chaining = pctr;
|
||||
LOG_TL("[IFX-TL]: Chain : Continue in receive mode\n");
|
||||
p_ctx->tl.state = TL_STATE_RX;
|
||||
// Continue receiving frames until packet is complete
|
||||
if (ifx_i2c_dl_receive_frame(p_ctx))
|
||||
{
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
}
|
||||
exit_machine = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case TL_STATE_RESEND:
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Resend Enter\n");
|
||||
// In received mode , for wrong pctr with data
|
||||
if((data_len > 1) && (p_ctx->tl.transmission_completed == 1))
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Resend : Send chaining error\n");
|
||||
p_ctx->tl.state = TL_STATE_CHAINING_ERROR;
|
||||
break;
|
||||
}
|
||||
// Master Resend the packets,Resend only once, otherwise exit with error
|
||||
if(0 == (p_ctx->tl.chaining_error_count++))
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Resend : Resending\n");
|
||||
p_ctx->tl.state = TL_STATE_IDLE;
|
||||
if(ifx_i2c_tl_resend_packets(p_ctx))
|
||||
{
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
exit_machine = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Resend : chaining_error_count exceeded\n");
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TL_STATE_CHAINING_ERROR:
|
||||
{
|
||||
// Send chaining error to slave
|
||||
p_ctx->tl.state = TL_STATE_TX;
|
||||
if(0 == (p_ctx->tl.master_chaining_error_count++))
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Chain error : Sending chain error\n");
|
||||
// Send chaining error only once
|
||||
if(ifx_i2c_tl_send_chaining_error(p_ctx))
|
||||
{
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
exit_machine = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Chain error : master_chaining_error_count exceeded\n");
|
||||
p_ctx->tl.state = TL_STATE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TL_STATE_ERROR:
|
||||
{
|
||||
LOG_TL("[IFX-TL]: Error\n");
|
||||
exit_machine = FALSE;
|
||||
if ((event & IFX_I2C_DL_EVENT_ERROR) || (data_len))
|
||||
{
|
||||
p_ctx->tl.state = TL_STATE_IDLE;
|
||||
}
|
||||
p_ctx->tl.upper_layer_event_handler(p_ctx,p_ctx->tl.error_event, 0u, 0u);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_TL("[IFX-TL]: Exit from default case\n");
|
||||
p_ctx->tl.state = TL_STATE_IDLE;
|
||||
exit_machine = FALSE;
|
||||
p_ctx->tl.upper_layer_event_handler(p_ctx,p_ctx->tl.error_event, 0u, 0u);
|
||||
break;
|
||||
}
|
||||
}while(exit_machine);
|
||||
}
|
||||
|
||||
|
||||
264
external/infineon/optiga/comms/optiga_comms.c
vendored
Normal file
264
external/infineon/optiga/comms/optiga_comms.c
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018 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
|
||||
*
|
||||
*
|
||||
* \file
|
||||
*
|
||||
* \brief This file implements optiga comms abstraction layer for IFX I2C Protocol.
|
||||
*
|
||||
* \addtogroup grOptigaComms
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**********************************************************************************************************************
|
||||
* HEADER FILES
|
||||
*********************************************************************************************************************/
|
||||
#include "optiga/comms/optiga_comms.h"
|
||||
#include "optiga/ifx_i2c/ifx_i2c.h"
|
||||
/// @cond hidden
|
||||
/**********************************************************************************************************************
|
||||
* MACROS
|
||||
*********************************************************************************************************************/
|
||||
/// Optiga comms is in use
|
||||
#define OPTIGA_COMMS_INUSE (0x01)
|
||||
/// Optiga comms is free
|
||||
#define OPTIGA_COMMS_FREE (0x00)
|
||||
/**********************************************************************************************************************
|
||||
* LOCAL DATA
|
||||
*********************************************************************************************************************/
|
||||
/**********************************************************************************************************************
|
||||
* LOCAL ROUTINES
|
||||
*********************************************************************************************************************/
|
||||
static host_lib_status_t check_optiga_comms_state(optiga_comms_t *p_ctx);
|
||||
static void ifx_i2c_event_handler(void* upper_layer_ctx, host_lib_status_t event);
|
||||
|
||||
/// @endcond
|
||||
/**********************************************************************************************************************
|
||||
* API IMPLEMENTATION
|
||||
*********************************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Initializes the commmunication with OPTIGA.<br>
|
||||
*
|
||||
*<b>Pre Conditions:</b>
|
||||
* - None<br>
|
||||
*
|
||||
*<b>API Details:</b>
|
||||
* - Initializes OPTIGA and establishes the communication channel.<br>
|
||||
* - Initializes the ifx i2c protocol stack and registers the event callbacks.<br>
|
||||
* - Negotiates the frame size and bit rate with the OPTIGA.<br>
|
||||
*<br>
|
||||
*
|
||||
*<b>User Input:</b><br>
|
||||
* - The input #optiga_comms_t p_ctx must not be NULL.<br>
|
||||
* - The following parameters in #optiga_comms_t must be initialized with appropriate values.<br>
|
||||
* - The <b>comms_ctx</b> must be initialized with a valid #ifx_i2c_context.<br>
|
||||
* - The <b>upper_layer_event_handler</b> parameter must be properly initialized.
|
||||
* This is invoked when #optiga_comms_open is asynchronously completed.<br>
|
||||
* - The <b>upper_layer_ctx</b> must be properly initialized.<br>
|
||||
*
|
||||
*<b>Notes:</b>
|
||||
* - None<br>
|
||||
*
|
||||
*<br>
|
||||
* \param[in,out] p_ctx Pointer to optiga comms context
|
||||
*
|
||||
* \retval #OPTIGA_COMMS_SUCCESS
|
||||
* \retval #OPTIGA_COMMS_ERROR
|
||||
*/
|
||||
host_lib_status_t optiga_comms_open(optiga_comms_t *p_ctx)
|
||||
{
|
||||
host_lib_status_t status = OPTIGA_COMMS_ERROR;
|
||||
if (OPTIGA_COMMS_SUCCESS == check_optiga_comms_state(p_ctx))
|
||||
{
|
||||
((ifx_i2c_context_t*)(p_ctx->comms_ctx))->p_upper_layer_ctx = (void*)p_ctx;
|
||||
((ifx_i2c_context_t*)(p_ctx->comms_ctx))->upper_layer_event_handler = ifx_i2c_event_handler;
|
||||
status = ifx_i2c_open((ifx_i2c_context_t*)(p_ctx->comms_ctx));
|
||||
if (IFX_I2C_STACK_SUCCESS != status)
|
||||
{
|
||||
p_ctx->state = OPTIGA_COMMS_FREE;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the OPTIGA.<br>
|
||||
*
|
||||
*<b>Pre Conditions:</b>
|
||||
* - Communication channel must be established with OPTIGA.<br>
|
||||
*
|
||||
*<b>API Details:</b>
|
||||
* - Resets the OPTIGA device.<br>
|
||||
* - Initializes the ifx i2c protocol stack.<br>
|
||||
* - Re-Initializes and negotiates the frame size and bit rate with the OPTIGA.
|
||||
* The values remain same as that in previous #optiga_comms_open().<br>
|
||||
*<br>
|
||||
*
|
||||
*<b>User Input:</b><br>
|
||||
* - The input #optiga_comms_t p_ctx must not be NULL.
|
||||
*
|
||||
*<b>Notes:</b>
|
||||
* For COLD and WARM reset type: If the gpio(vdd and/or reset) pins are not configured,
|
||||
* the API continues without returning error status<br>
|
||||
*
|
||||
*
|
||||
* \param[in,out] p_ctx Pointer to #optiga_comms_t
|
||||
* \param[in,out] reset_type type of reset
|
||||
*
|
||||
* \retval #OPTIGA_COMMS_SUCCESS
|
||||
* \retval #OPTIGA_COMMS_ERROR
|
||||
*/
|
||||
host_lib_status_t optiga_comms_reset(optiga_comms_t *p_ctx,uint8_t reset_type)
|
||||
{
|
||||
host_lib_status_t status = OPTIGA_COMMS_ERROR;
|
||||
if (OPTIGA_COMMS_SUCCESS == check_optiga_comms_state(p_ctx))
|
||||
{
|
||||
((ifx_i2c_context_t*)(p_ctx->comms_ctx))->p_upper_layer_ctx = (void*)p_ctx;
|
||||
((ifx_i2c_context_t*)(p_ctx->comms_ctx))->upper_layer_event_handler = ifx_i2c_event_handler;
|
||||
status = ifx_i2c_reset((ifx_i2c_context_t*)(p_ctx->comms_ctx),(ifx_i2c_reset_type_t)reset_type);
|
||||
if (IFX_I2C_STACK_SUCCESS != status)
|
||||
{
|
||||
p_ctx->state = OPTIGA_COMMS_FREE;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command to OPTIGA and receives a response.<br>
|
||||
*
|
||||
*
|
||||
*<b>Pre Conditions:</b>
|
||||
* - Communication channel must be established with OPTIGA.<br>
|
||||
*
|
||||
*<b>API Details:</b>
|
||||
* - Transmit data(Command) to OPTIGA.<br>
|
||||
* - Receive data(Response) from OPTIGA.<br>
|
||||
*<br>
|
||||
*
|
||||
*<b>User Input:</b><br>
|
||||
* - The input #optiga_comms_t p_ctx must not be NULL.<br>
|
||||
* - The following parameters in #optiga_comms_t must be initialized with appropriate values <br>
|
||||
* - The <b>comms_ctx</b> must be initialized with a valid #ifx_i2c_context<br>
|
||||
* - The <b>upper_layer_event_handler</b> parameter must be properly initialized,
|
||||
* if it is different from that in #optiga_comms_open().
|
||||
* This is invoked when optiga_comms_transceive is asynchronously completed.<br>
|
||||
* - The <b>upper_layer_ctx</b> must be properly initialized,
|
||||
* if it is different from that in #optiga_comms_open().<br>
|
||||
*
|
||||
*<b>Notes:</b>
|
||||
* - The actual number of bytes received is stored in p_buffer_len. In case of error, p_buffer_len is set to 0.<br>
|
||||
* - If the size of p_buffer is zero or insufficient to copy the response bytes then
|
||||
* #IFX_I2C_STACK_MEM_ERROR error is returned.
|
||||
*
|
||||
*
|
||||
* \param[in,out] p_ctx Pointer to #optiga_comms_t
|
||||
* \param[in] p_data Pointer to the write data buffer
|
||||
* \param[in] p_data_length Pointer to the length of the write data buffer
|
||||
* \param[in,out] p_buffer Pointer to the receive data buffer
|
||||
* \param[in,out] p_buffer_len Pointer to the length of the receive data buffer
|
||||
*
|
||||
* \retval #OPTIGA_COMMS_SUCCESS
|
||||
* \retval #OPTIGA_COMMS_ERROR
|
||||
* \retval #IFX_I2C_STACK_MEM_ERROR
|
||||
*/
|
||||
host_lib_status_t optiga_comms_transceive(optiga_comms_t *p_ctx,const uint8_t* p_data,
|
||||
const uint16_t* p_data_length,
|
||||
uint8_t* p_buffer, uint16_t* p_buffer_len)
|
||||
{
|
||||
host_lib_status_t status = OPTIGA_COMMS_ERROR;
|
||||
if (OPTIGA_COMMS_SUCCESS == check_optiga_comms_state(p_ctx))
|
||||
{
|
||||
((ifx_i2c_context_t*)(p_ctx->comms_ctx))->p_upper_layer_ctx = (void*)p_ctx;
|
||||
((ifx_i2c_context_t*)(p_ctx->comms_ctx))->upper_layer_event_handler = ifx_i2c_event_handler;
|
||||
status = (ifx_i2c_transceive((ifx_i2c_context_t*)(p_ctx->comms_ctx),p_data,p_data_length,p_buffer,p_buffer_len));
|
||||
if (IFX_I2C_STACK_SUCCESS != status)
|
||||
{
|
||||
p_ctx->state = OPTIGA_COMMS_FREE;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the communication with OPTIGA.<br>
|
||||
*
|
||||
*<b>Pre Conditions:</b>
|
||||
* - None<br>
|
||||
*
|
||||
*<b>API Details:</b>
|
||||
* - De-Initializes the OPTIGA and closes the communication channel.<br>
|
||||
* - Power downs the OPTIGA.<br>
|
||||
*<br>
|
||||
*
|
||||
*<b>User Input:</b><br>
|
||||
* - The input #optiga_comms_t p_ctx must not be NULL.<br>
|
||||
* - The #optiga_comms_t comms_ctx must be initialized with a valid #ifx_i2c_context<br>
|
||||
*
|
||||
* \param[in,out] p_ctx Pointer to #optiga_comms_t
|
||||
*
|
||||
* \retval #OPTIGA_COMMS_SUCCESS
|
||||
* \retval #OPTIGA_COMMS_ERROR
|
||||
*/
|
||||
host_lib_status_t optiga_comms_close(optiga_comms_t *p_ctx)
|
||||
{
|
||||
host_lib_status_t status = OPTIGA_COMMS_ERROR;
|
||||
if (OPTIGA_COMMS_SUCCESS == check_optiga_comms_state(p_ctx))
|
||||
{
|
||||
((ifx_i2c_context_t*)(p_ctx->comms_ctx))->p_upper_layer_ctx = (void*)p_ctx;
|
||||
((ifx_i2c_context_t*)(p_ctx->comms_ctx))->upper_layer_event_handler = ifx_i2c_event_handler;
|
||||
status = ifx_i2c_close((ifx_i2c_context_t*)(p_ctx->comms_ctx));
|
||||
if (IFX_I2C_STACK_SUCCESS != status)
|
||||
{
|
||||
p_ctx->state = OPTIGA_COMMS_FREE;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// @cond hidden
|
||||
static host_lib_status_t check_optiga_comms_state(optiga_comms_t *p_ctx)
|
||||
{
|
||||
host_lib_status_t status = OPTIGA_COMMS_ERROR;
|
||||
if ((NULL != p_ctx) && (p_ctx->state != OPTIGA_COMMS_INUSE))
|
||||
{
|
||||
p_ctx->state = OPTIGA_COMMS_INUSE;
|
||||
status = OPTIGA_COMMS_SUCCESS;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
//lint --e{818} suppress "This is ignored as upper layer handler function prototype requires this argument"
|
||||
static void ifx_i2c_event_handler(void* upper_layer_ctx, host_lib_status_t event)
|
||||
{
|
||||
void* ctx = ((optiga_comms_t*)upper_layer_ctx)->upper_layer_ctx;
|
||||
((optiga_comms_t*)upper_layer_ctx)->upper_layer_handler(ctx,event);
|
||||
((optiga_comms_t*)upper_layer_ctx)->state = OPTIGA_COMMS_FREE;
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user