diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_transport_layer.c')
-rw-r--r-- | thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_transport_layer.c | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_transport_layer.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_transport_layer.c new file mode 100644 index 0000000..f3191e6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/external/infineon/optiga_comms/ifx_i2c/ifx_i2c_transport_layer.c @@ -0,0 +1,502 @@ +/** +* \copyright +* Copyright (c) 2018, Infineon Technologies AG +* All rights reserved. +* +* This software is provided with terms and conditions as specified in OPTIGA(TM) Trust X Evaluation Kit License Agreement. +* \endcopyright +* +* \author Infineon AG +* +* \file ifx_i2c_transport_layer.c +* +* \brief This file implements the IFX I2C Transport Layer. +* +* \addtogroup grIFXI2C +* @{ +*/ +/*********************************************************************************************************************** +* HEADER FILES +**********************************************************************************************************************/ +#include "ifx_i2c_transport_layer.h" +#include "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 +#define LOG_TL IFX_I2C_LOG +#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); +} + + |