/** * 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.
* *Pre Conditions: * - None
* *API Details: * - Initializes OPTIGA and establishes the communication channel.
* - Initializes the ifx i2c protocol stack and registers the event callbacks.
* - Negotiates the frame size and bit rate with the OPTIGA.
*
* *User Input:
* - The input #optiga_comms_t p_ctx must not be NULL.
* - The following parameters in #optiga_comms_t must be initialized with appropriate values.
* - The comms_ctx must be initialized with a valid #ifx_i2c_context.
* - The upper_layer_event_handler parameter must be properly initialized. * This is invoked when #optiga_comms_open is asynchronously completed.
* - The upper_layer_ctx must be properly initialized.
* *Notes: * - None
* *
* \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.
* *Pre Conditions: * - Communication channel must be established with OPTIGA.
* *API Details: * - Resets the OPTIGA device.
* - Initializes the ifx i2c protocol stack.
* - Re-Initializes and negotiates the frame size and bit rate with the OPTIGA. * The values remain same as that in previous #optiga_comms_open().
*
* *User Input:
* - The input #optiga_comms_t p_ctx must not be NULL. * *Notes: * For COLD and WARM reset type: If the gpio(vdd and/or reset) pins are not configured, * the API continues without returning error status
* * * \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.
* * *Pre Conditions: * - Communication channel must be established with OPTIGA.
* *API Details: * - Transmit data(Command) to OPTIGA.
* - Receive data(Response) from OPTIGA.
*
* *User Input:
* - The input #optiga_comms_t p_ctx must not be NULL.
* - The following parameters in #optiga_comms_t must be initialized with appropriate values
* - The comms_ctx must be initialized with a valid #ifx_i2c_context
* - The upper_layer_event_handler 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.
* - The upper_layer_ctx must be properly initialized, * if it is different from that in #optiga_comms_open().
* *Notes: * - The actual number of bytes received is stored in p_buffer_len. In case of error, p_buffer_len is set to 0.
* - 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.
* *Pre Conditions: * - None
* *API Details: * - De-Initializes the OPTIGA and closes the communication channel.
* - Power downs the OPTIGA.
*
* *User Input:
* - The input #optiga_comms_t p_ctx must not be NULL.
* - The #optiga_comms_t comms_ctx must be initialized with a valid #ifx_i2c_context
* * \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 /** * @} */