diff options
Diffstat (limited to 'lcmodule/source/cnh1605205_ldr_network_layer/source/r15_network_layer.c')
-rw-r--r-- | lcmodule/source/cnh1605205_ldr_network_layer/source/r15_network_layer.c | 931 |
1 files changed, 931 insertions, 0 deletions
diff --git a/lcmodule/source/cnh1605205_ldr_network_layer/source/r15_network_layer.c b/lcmodule/source/cnh1605205_ldr_network_layer/source/r15_network_layer.c new file mode 100644 index 0000000..3b3a2fc --- /dev/null +++ b/lcmodule/source/cnh1605205_ldr_network_layer/source/r15_network_layer.c @@ -0,0 +1,931 @@ +/******************************************************************************* + * Copyright (C) ST-Ericsson SA 2011 + * License terms: 3-clause BSD license + ******************************************************************************/ +/** + * @addtogroup ldr_communication_serv + * @{ + * @addtogroup r15_family + * @{ + * @addtogroup ldr_network_layer + * @{ + */ + +/******************************************************************************* + * Includes + ******************************************************************************/ +#include "r_r15_network_layer.h" +#include "r_basicdefinitions.h" +#include <stdlib.h> +#include "r_debug.h" +#include "r_debug_macro.h" +#include <string.h> +#include "c_system.h" +#include "r_r15_transport_layer.h" +#include "r_r15_family.h" +#include "r_communication_service.h" +#include "r_r15_header.h" +#include "r_bulk_protocol.h" +#include "r_command_protocol.h" + +#ifdef CFG_ENABLE_MEASUREMENT_TOOL +#include "r_measurement_tool.h" +#include "r_time_utilities.h" +#endif + +#define FREE_TRANSMITER 0 +#define BUSY_TRANSMITER 1 + +#ifdef CFG_ENABLE_MEASUREMENT_TOOL +extern Measurement_t *Measurement_p; +#endif + +static PacketMeta_t PacketMetaInfo[COMMAND_BUFFER_COUNT + BULK_BUFFER_COUNT] = {0}; /* Packet Meta Info vector*/ + +/******************************************************************************* + * Declaration of file local functions + ******************************************************************************/ +static ErrorCode_e R15_Network_ReceiveHeader(const Communication_t *const Communication_p); +static ErrorCode_e R15_Network_ReceiveExtendedHeader(Communication_t *Communication_p); +static ErrorCode_e R15_Network_ReceivePayload(Communication_t *Communication_p); +static ErrorCode_e R15_Network_RegisterRetransmission(Communication_t *Communication_p, PacketMeta_t *Packet_p); +static void R15_Network_RetransmissionCallback(Communication_t *Communication_p, const void *const Timer_p, void *Data_p); +static void R15_InHashCallback(const void *const Data_p, uint32 Length, const uint8 *const Hash_p, void *Param_p); +#ifdef CFG_ENABLE_LOADER_TYPE +static void R15_QueueOutCallback(const void *const Queue_p, void *Param_p); +static void R15_QueueInCallback(const void *const Queue_p, void *Param_p); +#endif +static PacketMeta_t *R15_Network_GetAvailableMetaPacket(void); + + +/******************************************************************************* + * File scope types, constants and variables + ******************************************************************************/ + +#define RESET_INBOUND(c, s) do { (c)->ReqData = 0; (c)->RecData = 0; (c)->ReqBuffOffset = 0; (c)->Target_p = NULL; (c)->State = (s); } while(0); +#define SYNC_HEADER(c, d, t) do { (c)->ReqData = d; (c)->Target_p = t; } while(0); +#define SET_INBOUND(c, s, d) do { (c)->ReqData = d; (c)->RecData = 0; (c)->ReqBuffOffset = 0; (c)->State = (s); } while(0); + +/******************************************************************************* + * Definition of external functions + ******************************************************************************/ + +/* + * Initializes the r15 network layer. + * + * @param [in,out] Communication_p Communication module context. + * + * @retval E_SUCCESS After successful execution. + * @retval E_FAILED_TO_INIT_COM_DEVICE Fail to initialize the communication + * device. + */ +ErrorCode_e R15_Network_Initialize(Communication_t *Communication_p) +{ + memset(R15_NETWORK(Communication_p), 0, sizeof(R15_NetworkContext_t)); + + /* Simulate a finished read to get the inbound state-machine going. */ + R15_Network_ReadCallback(NULL, 0, Communication_p); + R15_NETWORK(Communication_p)->Outbound.InLoad = FALSE; +#ifdef CFG_ENABLE_LOADER_TYPE + (void)QUEUE(Communication_p, Fifo_SetCallback_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Outbound_p, QUEUE_NONEMPTY, R15_QueueOutCallback, Communication_p); + (void)QUEUE(Communication_p, Fifo_SetCallback_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Inbound_p, QUEUE_NONEMPTY, R15_QueueInCallback, Communication_p); +#endif + R15_NETWORK(Communication_p)->Inbound.LCM_Error = E_SUCCESS; + R15_NETWORK(Communication_p)->Outbound.LCM_Error = E_SUCCESS; + + return E_SUCCESS; +} + +/* + * Shut down the r15 network layer. + * + * @param [in,out] Communication_p Communication module context. + * + * @retval E_SUCCESS After successful execution. + */ +ErrorCode_e R15_Network_Shutdown(const Communication_t *const Communication_p) +{ + ErrorCode_e ReturnValue = E_SUCCESS; + + (void)QUEUE(Communication_p, Fifo_SetCallback_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Outbound_p, QUEUE_NONEMPTY, NULL, NULL); + (void)QUEUE(Communication_p, Fifo_SetCallback_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Outbound_p, QUEUE_EMPTY, NULL, NULL); + + /* Wait until the all packets in the queue has released. */ + while (!QUEUE(Communication_p, Fifo_IsEmpty_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Outbound_p)) { + PacketMeta_t *Packet_p = (PacketMeta_t *)QUEUE(Communication_p, FifoDequeue_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Outbound_p); + BulkExtendedHeader_t ExtendedHeader = {0}; + + R15_DeserializeBulkExtendedHeader(&ExtendedHeader, Packet_p->ExtendedHeader_p); + + if (Packet_p->Header.Protocol != BULK_PROTOCOL || (ExtendedHeader.TypeFlags & MASK_BULK_COMMAND_SELECT) != CMD_BULK_DATA) { + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); + VERIFY(E_SUCCESS == ReturnValue, ReturnValue); + } + } + + (void)QUEUE(Communication_p, Fifo_SetCallback_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Inbound_p, QUEUE_NONEMPTY, NULL, NULL); + (void)QUEUE(Communication_p, Fifo_SetCallback_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Inbound_p, QUEUE_EMPTY, NULL, NULL); + + /* Wait until the all packets in the queue has released. */ + while (!QUEUE(Communication_p, Fifo_IsEmpty_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Inbound_p)) { + ReturnValue = R15_Network_PacketRelease(Communication_p, (PacketMeta_t *)QUEUE(Communication_p, FifoDequeue_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Inbound_p)); + } + +ErrorExit: + return ReturnValue; +} + + +/* + * Handler for received packets in R15 protocol family. + * + * This callback function handles the received packets. + * + * @param [in] Data_p Pointer to the received data. + * @param [in] Length Length of the received data. + * @param [in] Param_p Parameters; + * + * @return none. + */ +void R15_Network_ReadCallback(const void *Data_p, const uint32 Length, void *Param_p) +{ + Communication_t *Communication_p = (Communication_t *)Param_p; + + C_(printf("r15_network_layer.c (%d) RecLength(%d) RecBackupData (%d)\n", __LINE__, Length, R15_NETWORK(Communication_p)->Inbound.RecBackupData);) + R15_NETWORK(Communication_p)->Inbound.RecData = Length + R15_NETWORK(Communication_p)->Inbound.RecBackupData; + R15_NETWORK(Communication_p)->Inbound.RecBackupData = 0; + + if (R15_NETWORK(Communication_p)->Inbound.ReqData == 0) { + ErrorCode_e ReturnValue = E_GENERAL_COMMUNICATION_ERROR; + + switch (R15_NETWORK(Communication_p)->Inbound.State) { + case RECEIVE_HEADER: + ReturnValue = R15_Network_ReceiveHeader(Communication_p); + break; + + case RECEIVE_EXTENDED_HEADER: + ReturnValue = R15_Network_ReceiveExtendedHeader(Communication_p); + break; + + case RECEIVE_PAYLOAD: + ReturnValue = R15_Network_ReceivePayload(Communication_p); + break; + + default: + R15_NETWORK(Communication_p)->Inbound.State = RECEIVE_HEADER; + R15_NETWORK(Communication_p)->Inbound.RecData = 0; + R15_NETWORK(Communication_p)->Inbound.ReqData = ALIGNED_HEADER_LENGTH; + R15_NETWORK(Communication_p)->Inbound.Target_p = R15_NETWORK(Communication_p)->Inbound.Scratch; + R15_NETWORK(Communication_p)->Inbound.LCM_Error = E_SUCCESS; + ReturnValue = E_SUCCESS; + break; + } + +#ifdef CFG_ENABLE_LOADER_TYPE + ReturnValue = R15_Network_ReceiverHandler(Communication_p); +#endif + + if (E_SUCCESS != ReturnValue) { + R15_NETWORK(Communication_p)->Inbound.State = RECEIVE_ERROR; + } + + R15_NETWORK(Communication_p)->Inbound.LCM_Error = ReturnValue; + } +} + +/* + * Handler for receiving new data. + * + * This function checks if new data has been received. + * + * @param [in,out] Communication_p Communication module context. + * + * @return none. + */ +ErrorCode_e R15_Network_ReceiverHandler(Communication_t *Communication_p) +{ + uint32 ReqData; + uint32 ReqBuffOffset = 0; + R15_Inbound_t *In_p = &(R15_NETWORK(Communication_p)->Inbound); + + /* new data for receiving ? */ + if (In_p->ReqData > 0) { + if (Communication_p->BackupCommBufferSize != 0) { + if (Communication_p->BackupCommBufferSize < In_p->ReqData) { + memcpy(In_p->Target_p + In_p->ReqBuffOffset, Communication_p->BackupCommBuffer_p, Communication_p->BackupCommBufferSize); + In_p->RecBackupData = Communication_p->BackupCommBufferSize; + (void)Communication_p->CommunicationDevice_p->Read(In_p->Target_p + In_p->ReqBuffOffset + Communication_p->BackupCommBufferSize, + In_p->ReqData - Communication_p->BackupCommBufferSize, + R15_Network_ReadCallback, Communication_p); + C_(printf("r15_network_layer.c (%d) ReqData(%d) RecData(%d)\n", __LINE__, In_p->ReqData, In_p->RecData);) + C_(printf("r15_network_layer.c (%d) Communication_p->BackupCommBufferSize(%d) RecBackupData (%d)\n", __LINE__, Communication_p->BackupCommBufferSize, In_p->RecBackupData);) + In_p->RecData = 0; + In_p->ReqBuffOffset = 0; + Communication_p->BackupCommBufferSize = 0; + In_p->ReqData = 0; + } else { + memcpy(In_p->Target_p + In_p->ReqBuffOffset, Communication_p->BackupCommBuffer_p, In_p->ReqData); + Communication_p->BackupCommBufferSize = Communication_p->BackupCommBufferSize - In_p->ReqData; + ReqData = In_p->ReqData; + In_p->ReqData = 0; + R15_Network_ReadCallback(In_p->Target_p + In_p->ReqBuffOffset, ReqData, Communication_p); + In_p->RecData = 0; + } + } else { + ReqData = In_p->ReqData; + ReqBuffOffset = (uint32)(In_p->ReqBuffOffset); + In_p->ReqBuffOffset = 0; + In_p->ReqData = 0; + (void)Communication_p->CommunicationDevice_p->Read(In_p->Target_p + ReqBuffOffset, ReqData, R15_Network_ReadCallback, Communication_p); + C_(printf("r15_network_layer.c (%d) ReqData(%d) RecData(%d) \n", __LINE__, In_p->ReqData, In_p->RecData);) + C_(printf("r15_network_layer.c (%d) Communication_p->BackupCommBufferSize(%d) RecBackupData (%d)\n", __LINE__, Communication_p->BackupCommBufferSize, In_p->RecBackupData);) + In_p->RecData = 0; + } + } + + /* check for receiver sinhronization */ + if (In_p->State == RECEIVE_ERROR) { + In_p->ReqData = 0; + In_p->RecData = 0; + In_p->ReqBuffOffset = 0; + In_p->State = RECEIVE_HEADER; + (void)Communication_p->CommunicationDevice_p->Read(In_p->Target_p, ALIGNED_HEADER_LENGTH, R15_Network_ReadCallback, Communication_p); + } + + return R15_NETWORK(Communication_p)->Inbound.LCM_Error; +} + +ErrorCode_e R15_Network_TransmiterHandler(Communication_t *Communication_p) +{ + ErrorCode_e ReturnValue = E_SUCCESS; + R15_Outbound_t *Out_p = &(R15_NETWORK(Communication_p)->Outbound); + uint8 *HeaderStartInBuffer_p = NULL; + boolean IsBufferContinuous = FALSE; + boolean RegisterRetransmission = FALSE; + uint32 ContinuousBufferLength = 0; + uint32 ExtHdrLen = 0; + uint32 Aligned_Length = 0; + + if (Out_p->InLoad) { + return E_SUCCESS; + } + + Out_p->InLoad = TRUE; + + switch (Out_p->State) { + case SEND_IDLE: + /* check retransmission count before send */ + Out_p->Packet_p = (PacketMeta_t *)QUEUE(Communication_p, FifoDequeue_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Outbound_p); + + if (NULL != Out_p->Packet_p) { + if (Out_p->Packet_p->Resend < MAX_RESENDS) { + Out_p->Packet_p->Resend++; + /* get next packet for transmitting */ + Out_p->State = SEND_HEADER; + } else { + //Do_CommunicationInternalErrorHandler(E_RETRANSMITION_FAILED); + return E_RETRANSMITION_FAILED; + } + } else { + break; + } + + /* FALLTHROUGH */ + case SEND_HEADER: + HeaderStartInBuffer_p = Out_p->Packet_p->Buffer_p + HEADER_OFFSET_IN_BUFFER; + + if (Out_p->Packet_p->Header.ExtendedHeaderLength == COMMAND_EXTENDED_HEADER_LENGTH) { + ExtHdrLen = ALIGNED_COMMAND_EXTENDED_HEADER_LENGTH; + } else { + ExtHdrLen = ALIGNED_BULK_EXTENDED_HEADER_LENGTH; + } + + if ((HeaderStartInBuffer_p + ALIGNED_HEADER_LENGTH + ExtHdrLen) == Out_p->Packet_p->Payload_p) { + /* end of the header and beginning of the payload are same */ + IsBufferContinuous = TRUE; + } + + /* set next state before calling the communication device, to avoid race condition + where write callback is called before new state is set */ + if (IsBufferContinuous || Out_p->Packet_p->Header.PayloadLength == 0) { + /* we have a packet without payload or header and payload are contained in one + continuous buffer so it can be sent with one write request */ + ContinuousBufferLength = ALIGNED_HEADER_LENGTH + ExtHdrLen + Out_p->Packet_p->Header.PayloadLength; + ContinuousBufferLength = (ContinuousBufferLength + (ALIGN_SIZE - 1)) & (~(ALIGN_SIZE - 1)); + + Out_p->State = SENDING_PAYLOAD; + RegisterRetransmission = TRUE; + } else { + ContinuousBufferLength = ALIGNED_HEADER_LENGTH + ExtHdrLen; + Out_p->State = SENDING_HEADER; + } + + if (E_SUCCESS == Communication_p->CommunicationDevice_p->Write((Out_p->Packet_p->Buffer_p + HEADER_OFFSET_IN_BUFFER), + ContinuousBufferLength, + R15_Network_WriteCallback, Communication_p)) { + C_(printf("r15_network_layer.c (%d) Header Sent to comm device! \n", __LINE__);) + } else { + Out_p->State = SEND_HEADER; + RegisterRetransmission = FALSE; + C_(printf("r15_network_layer.c (%d) Error sending header to comm device! \n", __LINE__);) + } + + break; + case SENDING_HEADER: + /* nothing to do, wait until sending is finished and state changed by write callback */ + break; + case SEND_PAYLOAD: + Out_p->State = SENDING_PAYLOAD; + + Aligned_Length = (Out_p->Packet_p->Header.PayloadLength + (ALIGN_SIZE - 1)) & (~(ALIGN_SIZE - 1)); + + if (E_SUCCESS == Communication_p->CommunicationDevice_p->Write(Out_p->Packet_p->Payload_p, + Aligned_Length, + R15_Network_WriteCallback, Communication_p)) { + RegisterRetransmission = TRUE; + C_(printf("r15_network_layer.c (%d) Payload Sent to comm device! \n", __LINE__);) + } else { + Out_p->State = SEND_PAYLOAD; + C_(printf("r15_network_layer.c (%d) Error sending payload to comm device! \n", __LINE__);) + } + + break; + case SENDING_PAYLOAD: + /* nothing to do, wait until sending is finished and state changed by write callback */ + break; + } + + if (RegisterRetransmission) { + if (NULL != Out_p->Packet_p->Timer_p) { + C_(printf("r15_network_layer.c (%d) Register retransmission\n", __LINE__);) + (void)R15_Network_RegisterRetransmission(Communication_p, Out_p->Packet_p); + } + } + + Out_p->InLoad = FALSE; + + return ReturnValue; +} + +/* + * Cancel retransmission of packets. + * + * @param [in,out] Communication_p Communication module context. + * @param [in] UniqueKey Unique key used for identification of packet + * for retransmission. + * + * @return none. + */ +ErrorCode_e R15_Network_CancelRetransmission(const Communication_t *const Communication_p, uint32 UniqueKey) +{ + ErrorCode_e ReturnValue = E_NOT_FOUND_ELEMENT_IN_RETRANSMISSION_LIST; + uint32 Index = 0; + + do { + if ((R15_NETWORK(Communication_p)->RetransmissionList[Index] != NULL) && (R15_NETWORK(Communication_p)->RetransmissionList[Index]->Key == UniqueKey)) { + (void)TIMER(Communication_p, TimerRelease_Fn)(OBJECT_TIMER(Communication_p), R15_NETWORK(Communication_p)->RetransmissionList[Index]->TimerKey); + + free(R15_NETWORK(Communication_p)->RetransmissionList[Index]->Packet_p->Timer_p); + ReturnValue = R15_Network_PacketRelease(Communication_p, R15_NETWORK(Communication_p)->RetransmissionList[Index]->Packet_p); + + if (E_SUCCESS != ReturnValue) { + A_(printf("r15_network_layer.c(%d): Packet release failed!\n", __LINE__);) + return ReturnValue; + } + + free(R15_NETWORK(Communication_p)->RetransmissionList[Index]); + R15_NETWORK(Communication_p)->RetransmissionList[Index] = NULL; + R15_NETWORK(Communication_p)->RetransmissionListCount--; + + for (; Index < R15_NETWORK(Communication_p)->RetransmissionListCount; Index++) { + R15_NETWORK(Communication_p)->RetransmissionList[Index] = R15_NETWORK(Communication_p)->RetransmissionList[Index+1]; + } + + R15_NETWORK(Communication_p)->RetransmissionList[Index] = NULL; + ReturnValue = E_SUCCESS; + break; + } + + Index++; + } while (Index < R15_NETWORK(Communication_p)->RetransmissionListCount); + + return ReturnValue; +} + +/* + * Create unique key. + * + * This function combine the session number and protocol type in one + * unique key for command packet. For the bulk packet the unique key is the + * combination of protocol type, session number and command. + * + * @param [in] Packet_p Pointer to the packet. + * @param [in] ExternalKey External key for marking the packet for retransmision. + * + * @return Unique key. + */ +uint32 R15_Network_CreateUniqueKey(const PacketMeta_t *const Packet_p, const uint8 ExternalKey) +{ + uint32 Key = Packet_p->Header.Protocol; + + if (Key == PROTO_COMMAND) { + return((Key << 16) | *(Packet_p->ExtendedHeader_p) & MASK_CLR_STATE); + } else { + return ((Key << 16) | ((*(Packet_p->ExtendedHeader_p) & 0x00FF) << 8) | ExternalKey); + } +} + + +/* + * Network packet allocation in R15 protocol family. + * + * @param [in,out] Communication_p Communication module context. + * @param [in] BufferSize Size of buffer used for network packet. + * + * @retval Pointer Pointer to allocated packet meta info. + * @retval NULL if allocation fail. + */ +PacketMeta_t *R15_Network_PacketAllocate(const Communication_t *const Communication_p, int BufferSize) +{ + PacketMeta_t *Meta_p = NULL; + void *Buffer_p = NULL; + int BuffersNr = 0; + + /* Find the first unallocated buffers. */ + Buffer_p = BUFFER(Communication_p, BufferAllocate_Fn)(OBJECT_BUFFER(Communication_p), BufferSize); + + if (NULL == Buffer_p) { + A_(printf("r15_network_layer.c (%d): ** Buffer allocation fail! **\n", __LINE__);) + goto ErrorExit; + } + + B_(printf("r15_network_layer.c (%d): Buffer allocate (0x%x)! **\n", __LINE__, (uint32)Buffer_p);) + + /* packet meta info allocate, get free packet meta structure */ + + Meta_p = R15_Network_GetAvailableMetaPacket(); + + if (NULL == Meta_p) { + R15_NETWORK(Communication_p)->Inbound.LCM_Error = E_ALLOCATE_FAILED; + goto ErrorExit; + } + + /* packet meta info setup */ + C_( + + if (BULK_BUFFER_SIZE > BufferSize) + printf("CmdBuffGet:%x\n", Buffer_p); + else { + printf("ChunkBuffGet:%x\n", Buffer_p); + }) + + Meta_p->Buffer_p = (uint8 *)Buffer_p; + Meta_p->BufferSize = BufferSize; + SET_PACKET_FLAGS(Meta_p, PACKET_ALLOCATION_STATE_MASK, BUF_ALLOCATED); + + do { + if (NULL == R15_NETWORK(Communication_p)->MetaInfoList[BuffersNr]) { + R15_NETWORK(Communication_p)->MetaInfoList[BuffersNr] = Meta_p; + break; + } + + BuffersNr ++; + } while (BuffersNr < (COMMAND_BUFFER_COUNT + BULK_BUFFER_COUNT)); + +ErrorExit: + return Meta_p; +} + + +/* + * Network packet release in R15 protocol family. + * + * @param [in,out] Communication_p Communication module context. + * @param [in] Meta_p Meta info for used network packet. + * + * @retval E_SUCCESS Successful network packet release. + * @retval E_INVALID_INPUT_PARAMETERS Invalid input parameter. + */ +ErrorCode_e R15_Network_PacketRelease(const Communication_t *const Communication_p, PacketMeta_t *Meta_p) +{ + ErrorCode_e ReturnValue = E_SUCCESS; + int BuffersNr = 0; + + VERIFY(NULL != Meta_p, E_INVALID_INPUT_PARAMETERS); + + /* remove the meta info data from list */ + do { + if (Meta_p == R15_NETWORK(Communication_p)->MetaInfoList[BuffersNr]) { + R15_NETWORK(Communication_p)->MetaInfoList[BuffersNr] = NULL; + /* release buffer */ + B_(printf("r15_network_layer.c (%d): Buffer release (0x%x)! **\n", __LINE__, (uint32)(Meta_p->Buffer_p));) +#ifndef CFG_ENABLE_LOADER_TYPE + ReturnValue = BUFFER(Communication_p, BufferRelease_Fn)(OBJECT_BUFFER(Communication_p), Meta_p->Buffer_p, Meta_p->BufferSize); + VERIFY(E_SUCCESS == ReturnValue, ReturnValue); + B_(printf("r15_network_layer.c (%d): Buffer released! **\n", __LINE__);) +#else + C_( + + if (BULK_BUFFER_SIZE > Meta_p->BufferSize) + printf("CmdBuffRel:%x\n", Meta_p->Buffer_p); + else { + printf("ChunkBuffRel:%x\n", Meta_p->Buffer_p); + }) + ReturnValue = BUFFER(Communication_p, BufferRelease_Fn)(OBJECT_BUFFER(Communication_p), Meta_p->Buffer_p, Meta_p->BufferSize); + VERIFY(E_SUCCESS == ReturnValue, ReturnValue); + B_(printf("r15_network_layer.c (%d): Buffer released! **\n", __LINE__);) +#endif + + memset(Meta_p, 0, sizeof(PacketMeta_t)); + break; + } + + BuffersNr ++; + } while (BuffersNr < (COMMAND_BUFFER_COUNT + BULK_BUFFER_COUNT)); + +ErrorExit: + return ReturnValue; +} + +/* + * Handler function that is called after successful transmission of a packet. + * + * If new packet is ready for transmitting it starts + * the transmission of the packet. + * + * @param [in] Data_p Pointer to the data for transmitting. + * @param [in] Length Length of the received data. + * @param [in] Param_p Parameters. + * + * @return none. + */ +void R15_Network_WriteCallback(const void *Data_p, const uint32 Length, void *Param_p) +{ + Communication_t *Communication_p = (Communication_t *)Param_p; + R15_Outbound_t *Out_p = &(R15_NETWORK(Communication_p)->Outbound); + BulkExtendedHeader_t ExtendedHeader = {0}; + B_(printf("r15_network_layer.c (%d): Device write finished!! \n", __LINE__);) + + if (SENDING_HEADER == Out_p->State) { + Out_p->State = SEND_PAYLOAD; + } else if (SENDING_PAYLOAD == Out_p->State) { + if (NULL == Out_p->Packet_p->Timer_p) { + if (Out_p->Packet_p->Header.Protocol == BULK_PROTOCOL) { + R15_DeserializeBulkExtendedHeader(&ExtendedHeader, Out_p->Packet_p->ExtendedHeader_p); + } + + if (!((Out_p->Packet_p->Header.Protocol == BULK_PROTOCOL) && ((ExtendedHeader.TypeFlags & MASK_BULK_COMMAND_SELECT) == CMD_BULK_DATA))) { + (void)R15_Network_PacketRelease(Communication_p, Out_p->Packet_p); + } + } + + Out_p->State = SEND_IDLE; + SET_PACKET_FLAGS(Out_p->Packet_p, PACKET_TX_STATE_MASK, BUF_TX_SENT); + } + +#ifdef CFG_ENABLE_LOADER_TYPE + + if (E_SUCCESS != R15_Network_TransmiterHandler(Communication_p)) { + R15_NETWORK(Communication_p)->Outbound.LCM_Error = E_GENERAL_COMMUNICATION_ERROR; + } + +#endif +} + + +/******************************************************************************* + * Definition of internal functions + ******************************************************************************/ + +static ErrorCode_e R15_Network_ReceiveHeader(const Communication_t *const Communication_p) +{ + R15_Inbound_t *In_p = &(R15_NETWORK(Communication_p)->Inbound); + + if (In_p->RecData == 0) { + In_p->ReqData = ALIGNED_HEADER_LENGTH; + In_p->Target_p = In_p->Scratch; + } else { + if (R15_IsReceivedHeader(In_p)) { + if (R15_IsValidHeader(In_p->Scratch)) { + R15_DeserializeHeader(&In_p->Header, In_p->Scratch); + + In_p->Target_p += ALIGNED_HEADER_LENGTH; + if (In_p->Header.ExtendedHeaderLength == COMMAND_EXTENDED_HEADER_LENGTH) { + SET_INBOUND(In_p, RECEIVE_EXTENDED_HEADER, ALIGNED_COMMAND_EXTENDED_HEADER_LENGTH); + } else { + SET_INBOUND(In_p, RECEIVE_EXTENDED_HEADER, ALIGNED_BULK_EXTENDED_HEADER_LENGTH); + } + } else { + A_(printf("Not valid header!\n");) + /* Sync the header. */ + RESET_INBOUND(In_p, RECEIVE_HEADER); + SYNC_HEADER(In_p, ALIGNED_HEADER_LENGTH, In_p->Scratch); + } + } + else + { + uint32 Counter = 0; + + A_(printf("Invalid header! ");) + for (Counter = 0; Counter < 16; Counter++) + { + A_(printf(" %02X", In_p->Scratch[Counter]);) + } + A_(printf("\n\n");) + } + } + + return E_SUCCESS; +} + +static ErrorCode_e R15_Network_ReceiveExtendedHeader(Communication_t *Communication_p) +{ + R15_Inbound_t *In_p = &(R15_NETWORK(Communication_p)->Inbound); + ErrorCode_e ReturnValue = E_SUCCESS; + R15_Header_t R15Header = {0}; + BulkExtendedHeader_t BulkExtendedHeader = {0}; + boolean IsValidHeader = FALSE; + + VERIFY(NULL != In_p, E_GENERAL_FATAL_ERROR); + + R15_DeserializeHeader(&R15Header, In_p->Scratch); + R15_DeserializeBulkExtendedHeader(&BulkExtendedHeader, In_p->Target_p); + + IsValidHeader = R15_IsValidExtendedHeader(In_p->Target_p, + In_p->Header.ExtendedHeaderLength, + In_p->Header.ExtendedHeaderChecksum); + + if (IsValidHeader) { + if (R15Header.Protocol == BULK_PROTOCOL && + (BulkExtendedHeader.TypeFlags & MASK_BULK_COMMAND_SELECT) == CMD_BULK_DATA) { + In_p->Packet_p = R15_Network_PacketAllocate(Communication_p, BULK_BUFFER_SIZE); + } else { + In_p->Packet_p = R15_Network_PacketAllocate(Communication_p, COMMAND_BUFFER_SIZE); + } + + VERIFY(NULL != In_p->Packet_p, E_FAILED_TO_FIND_COMM_BUFFER); + + In_p->Packet_p->Header = R15Header; + In_p->Packet_p->ExtendedHeader_p = In_p->Packet_p->Buffer_p + HEADER_OFFSET_IN_BUFFER + ALIGNED_HEADER_LENGTH; + SET_PACKET_FLAGS(In_p->Packet_p, PACKET_RX_STATE_MASK, BUF_HDR_CRC_OK); + if (In_p->Packet_p->Header.ExtendedHeaderLength == COMMAND_EXTENDED_HEADER_LENGTH) { + In_p->Packet_p->Payload_p = In_p->Packet_p->ExtendedHeader_p + ALIGNED_COMMAND_EXTENDED_HEADER_LENGTH; + } else { + In_p->Packet_p->Payload_p = In_p->Packet_p->ExtendedHeader_p + ALIGNED_BULK_EXTENDED_HEADER_LENGTH; + } + memcpy(In_p->Packet_p->Buffer_p + HEADER_OFFSET_IN_BUFFER, &In_p->Packet_p->Header, HEADER_LENGTH); + memcpy(In_p->Packet_p->ExtendedHeader_p, In_p->Target_p, In_p->Header.ExtendedHeaderLength); + + In_p->Target_p = In_p->Packet_p->Payload_p; + + /* check for expected payload */ + if (In_p->Packet_p->Header.PayloadLength != 0) { + uint32 Aligned_Size = 0; + Aligned_Size = (In_p->Packet_p->Header.PayloadLength + (ALIGN_SIZE - 1)) & (~(ALIGN_SIZE - 1)); + + SET_INBOUND(In_p, RECEIVE_PAYLOAD, Aligned_Size); + } else { +#ifdef DISABLE_SECURITY + SET_PACKET_FLAGS(In_p->Packet_p, PACKET_RX_STATE_MASK, BUF_RX_READY); + (void)QUEUE(Communication_p, FifoEnqueue_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Inbound_p, In_p->Packet_p); +#else + PacketMeta_t *Packet_p = In_p->Packet_p; + Packet_p->Communication_p = Communication_p; + SET_PACKET_FLAGS(In_p->Packet_p, PACKET_RX_STATE_MASK, BUF_RX_READY); + // Copy the original packet checksum to avoid hash mismatch + memcpy(Packet_p->Hash, &Packet_p->Header.PayloadChecksum, 4); + + Communication_p->HashDevice_p->Calculate(OBJECT_HASH(Communication_p), + HASH_NONE, + Packet_p->Payload_p, Packet_p->Header.PayloadLength, + Packet_p->Hash, (HashCallback_t)R15_InHashCallback, + (void *)Packet_p); +#endif + + In_p->Packet_p = NULL; + RESET_INBOUND(In_p, RECEIVE_HEADER); + SYNC_HEADER(In_p, ALIGNED_HEADER_LENGTH, In_p->Scratch); + C_(printf("r15_network_layer.c (%d) ReqData(%d) RecData(%d) \n", __LINE__, In_p->ReqData, In_p->RecData);) + } + } else { + RESET_INBOUND(In_p, RECEIVE_HEADER); + SYNC_HEADER(In_p, ALIGNED_HEADER_LENGTH, In_p->Scratch); + } + +ErrorExit: + return ReturnValue; +} + +static ErrorCode_e R15_Network_ReceivePayload(Communication_t *Communication_p) +{ + R15_Inbound_t *In_p = &(R15_NETWORK(Communication_p)->Inbound); + PacketMeta_t *Packet_p = In_p->Packet_p; + + Packet_p->Communication_p = Communication_p; + SET_PACKET_FLAGS(In_p->Packet_p, PACKET_RX_STATE_MASK, BUF_RX_READY); + +#ifndef CFG_ENABLE_LOADER_TYPE + Communication_p->CurrentFamilyHash = (HashType_e)Packet_p->Header.Flags; +#endif + + if (HASH_NONE != Packet_p->Header.Flags) { +#ifdef CFG_ENABLE_MEASUREMENT_TOOL + if(In_p->Packet_p->Header.Protocol == BULK_PROTOCOL){ + BulkExtendedHeader_t ExtendedHeader = {0}; + R15_DeserializeBulkExtendedHeader(&ExtendedHeader, Packet_p->ExtendedHeader_p); + + if ((ExtendedHeader.TypeFlags & MASK_BULK_COMMAND_SELECT) == CMD_BULK_DATA){ + (void)MP(Measurement_p, ExtendedHeader.AcksChunk, START_HASHINGCHUNK_TIME); + } + } +#endif + Communication_p->HashDevice_p->Calculate(OBJECT_HASH(Communication_p), + Communication_p->CurrentFamilyHash, + Packet_p->Payload_p, Packet_p->Header.PayloadLength, + Packet_p->Hash, (HashCallback_t)R15_InHashCallback, + (void *)Packet_p); + } else { + SET_PACKET_FLAGS(Packet_p, PACKET_RX_STATE_MASK, BUF_PAYLOAD_CRC_OK); + (void)QUEUE((Packet_p->Communication_p), FifoEnqueue_Fn)(OBJECT_QUEUE(Packet_p->Communication_p), Packet_p->Communication_p->Inbound_p, Packet_p); + } + + In_p->Packet_p = NULL; + RESET_INBOUND(In_p, RECEIVE_HEADER); + SYNC_HEADER(In_p, ALIGNED_HEADER_LENGTH, In_p->Scratch); + return E_SUCCESS; +} + +static ErrorCode_e R15_Network_RegisterRetransmission(Communication_t *Communication_p, PacketMeta_t *Packet_p) +{ + int i; + int Index; + ErrorCode_e ReturnValue = E_SUCCESS; + static RetransmissionContext_t *R_Ctx_p = NULL; + + if (R15_NETWORK(Communication_p)->RetransmissionListCount < MAX_SIZE_RETRANSMISSION_LIST) { + if (NULL == Packet_p->Timer_p->HandleFunction_p) { + Packet_p->Timer_p->HandleFunction_p = (HandleFunction_t)R15_Network_RetransmissionCallback; + Packet_p->Timer_p->Param_p = Communication_p; + } + + R_Ctx_p = (RetransmissionContext_t *)malloc(sizeof(RetransmissionContext_t)); + + if (NULL == R_Ctx_p) { + return E_ALLOCATE_FAILED; + } + + R_Ctx_p->TimerKey = TIMER(Communication_p, TimerGet_Fn)(OBJECT_TIMER(Communication_p), Packet_p->Timer_p); + R_Ctx_p->Timeout = Packet_p->Timer_p->Time; + R_Ctx_p->Packet_p = Packet_p; + R_Ctx_p->Key = R15_Network_CreateUniqueKey(Packet_p, (uint8)(*(R_Ctx_p->Packet_p->ExtendedHeader_p + sizeof(uint16)))); + + Index = 0; + C_(printf("r15_network_layer.c (%d) Key(%d) TKey(%d) \n", __LINE__, R_Ctx_p->Key, R_Ctx_p->TimerKey);) + + do { + if (NULL != R15_NETWORK(Communication_p)->RetransmissionList[Index]) { + if (R_Ctx_p->Timeout < TIMER(Communication_p, ReadTime_Fn)(OBJECT_TIMER(Communication_p), R15_NETWORK(Communication_p)->RetransmissionList[Index]->TimerKey)) { + i = R15_NETWORK(Communication_p)->RetransmissionListCount; + + for (; Index < i; i--) { + R15_NETWORK(Communication_p)->RetransmissionList[i] = R15_NETWORK(Communication_p)->RetransmissionList[i-1]; + } + + R15_NETWORK(Communication_p)->RetransmissionList[Index] = R_Ctx_p; + R_Ctx_p = NULL; + R15_NETWORK(Communication_p)->RetransmissionListCount++; + break; + } + + Index++; + } else { + R15_NETWORK(Communication_p)->RetransmissionList[Index] = R_Ctx_p; + R_Ctx_p = NULL; + R15_NETWORK(Communication_p)->RetransmissionListCount++; + break; + } + } while (Index < MAX_SIZE_RETRANSMISSION_LIST); + } else { + A_(printf("r15_network_layer.c (%d) ** Err: Retransmision List is full! ** \n", __LINE__);) + } + + return ReturnValue; +} + + +static void R15_Network_RetransmissionCallback(Communication_t *Communication_p, const void *const Timer_p, void *Packet_p) +{ + uint32 Index = 0; + + /* get first in list of packets for retransmission and remove */ + if (NULL != R15_NETWORK(Communication_p)->RetransmissionList[Index]) { + free(R15_NETWORK(Communication_p)->RetransmissionList[Index]); + R15_NETWORK(Communication_p)->RetransmissionList[Index] = NULL; + } + + if (R15_NETWORK(Communication_p)->RetransmissionListCount > 0) { + C_(printf("r15_network_layer.c (%d) RetransmissionListCount(%d) \n", __LINE__, R15_NETWORK(Communication_p)->RetransmissionListCount);) + R15_NETWORK(Communication_p)->RetransmissionListCount--; + + for (; Index < R15_NETWORK(Communication_p)->RetransmissionListCount; Index++) { + R15_NETWORK(Communication_p)->RetransmissionList[Index] = R15_NETWORK(Communication_p)->RetransmissionList[Index+1]; + } + + R15_NETWORK(Communication_p)->RetransmissionList[Index] = NULL; + + /* enqueue the packet for retransmission */ + (void)QUEUE(Communication_p, FifoEnqueue_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Outbound_p, Packet_p); + } +} + + +static void R15_InHashCallback(const void *const Data_p, uint32 Length, const uint8 *const Hash_p, void *Param_p) +{ + PacketMeta_t *Packet_p = (PacketMeta_t *)Param_p; + +#ifdef CFG_ENABLE_MEASUREMENT_TOOL + if(Packet_p->Header.Protocol == BULK_PROTOCOL){ + BulkExtendedHeader_t ExtendedHeader = {0}; + R15_DeserializeBulkExtendedHeader(&ExtendedHeader, Packet_p->ExtendedHeader_p); + + if ((ExtendedHeader.TypeFlags & MASK_BULK_COMMAND_SELECT) == CMD_BULK_DATA){ + (void)MP(Measurement_p, ExtendedHeader.AcksChunk, END_HASHINGCHUNK_TIME); + } + } +#endif + + if (memcmp(Hash_p, &Packet_p->Header.PayloadChecksum, 4) == 0) { + SET_PACKET_FLAGS(Packet_p, PACKET_RX_STATE_MASK, BUF_PAYLOAD_CRC_OK); + (void)QUEUE((Packet_p->Communication_p), FifoEnqueue_Fn)(OBJECT_QUEUE(Packet_p->Communication_p), Packet_p->Communication_p->Inbound_p, Packet_p); + } else { + /* Invalid packet */ + ErrorCode_e ReturnValue = E_GENERAL_FATAL_ERROR; + + if (E_SUCCESS != (ReturnValue = R15_Network_PacketRelease((Communication_t *)Packet_p->Communication_p, Packet_p))) { + R15_NETWORK((Communication_t *)Packet_p->Communication_p)->Inbound.LCM_Error = ReturnValue; + } + } +} + +#ifdef CFG_ENABLE_LOADER_TYPE +static void R15_QueueOutCallback(const void *const Queue_p, void *Param_p) +{ + if (E_SUCCESS != R15_Network_TransmiterHandler((Communication_t *)Param_p)) { + R15_NETWORK((Communication_t *)Param_p)->Outbound.LCM_Error = E_GENERAL_COMMUNICATION_ERROR; + } +} + +static void R15_QueueInCallback(const void *const Queue_p, void *Param_p) +{ + ErrorCode_e ReturnValue = E_GENERAL_FATAL_ERROR; + Communication_t *Communication_p = (Communication_t *)Param_p; + PacketMeta_t *Packet_p = NULL; + + while ((Packet_p = (PacketMeta_t *)QUEUE(Communication_p, FifoDequeue_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Inbound_p)) != NULL) { + switch (Packet_p->Header.Protocol) { + case PROTO_BULK: + ReturnValue = R15_Bulk_Process(Communication_p, Packet_p); + + if (E_SUCCESS != ReturnValue) { + R15_NETWORK(Communication_p)->Inbound.LCM_Error = ReturnValue; + } + + break; + + case PROTO_COMMAND: + ReturnValue = R15_Command_Process(Communication_p, Packet_p); + + if (E_SUCCESS != ReturnValue) { + R15_NETWORK(Communication_p)->Inbound.LCM_Error = ReturnValue; + } + + break; + + default: + R15_NETWORK(Communication_p)->Inbound.LCM_Error = E_SUCCESS; + break; + } + } +} +#endif + +static PacketMeta_t *R15_Network_GetAvailableMetaPacket(void) +{ + uint8 i = 0; + PacketMeta_t *PacketMeta_p = NULL; + + do { + if (NULL == PacketMetaInfo[i].Buffer_p) { + PacketMeta_p = &PacketMetaInfo[i]; + break; + } + + i++; + } while (i < COMMAND_BUFFER_COUNT + BULK_BUFFER_COUNT); + + return PacketMeta_p; +} + +/** @} */ +/** @} */ +/** @} */ |