diff options
Diffstat (limited to 'lcmodule/source/cnh1605204_ldr_transport_layer/source/bulk_protocol.c')
-rw-r--r-- | lcmodule/source/cnh1605204_ldr_transport_layer/source/bulk_protocol.c | 1461 |
1 files changed, 1461 insertions, 0 deletions
diff --git a/lcmodule/source/cnh1605204_ldr_transport_layer/source/bulk_protocol.c b/lcmodule/source/cnh1605204_ldr_transport_layer/source/bulk_protocol.c new file mode 100644 index 0000000..173bb5b --- /dev/null +++ b/lcmodule/source/cnh1605204_ldr_transport_layer/source/bulk_protocol.c @@ -0,0 +1,1461 @@ +/******************************************************************************* + * Copyright (C) ST-Ericsson SA 2011 + * License terms: 3-clause BSD license + ******************************************************************************/ +/** + * @addtogroup ldr_communication_serv + * @{ + * @addtogroup r15_family + * @{ + * @addtogroup bulk_protocol + * @{ + */ + +/******************************************************************************* + * Includes + ******************************************************************************/ +#include "c_system.h" +#include "r_basicdefinitions.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "r_bulk_protocol.h" +#include "r_r15_transport_layer.h" +#include "r_r15_network_layer.h" +#include "r_r15_family.h" +#include "r_r15_header.h" +#include "r_debug.h" +#include "r_debug_macro.h" +#include "r_communication_service.h" +#include "t_security_algorithms.h" +#include "r_memmory_utils.h" + +#ifdef CFG_ENABLE_MEASUREMENT_TOOL +#include "r_measurement_tool.h" +#include "r_time_utilities.h" +#endif + +/*********************************************************************** + * Definition of external constants and variables + **********************************************************************/ +#define SESSION(x) ((R15_FamilyContext_t *)(x)->FamilyContext_p)->Transport.Session +#define CHUNKSIZE(x) ((R15_FamilyContext_t *)(x)->FamilyContext_p)->Transport.ChunkSize +#define LENGTH(x) ((R15_FamilyContext_t *)(x)->FamilyContext_p)->Transport.Length +#define OFFSET(x) ((R15_FamilyContext_t *)(x)->FamilyContext_p)->Transport.Offset +#define TOTALLENGTH(x) ((R15_FamilyContext_t *)(x)->FamilyContext_p)->Transport.BulkHandle.BulkVector_p->TotalLength +#define TRANSFEREDLENGTH(x) ((R15_FamilyContext_t *)(x)->FamilyContext_p)->Transport.BulkHandle.BulkVector_p->TransferedLength + +#ifdef CFG_ENABLE_MEASUREMENT_TOOL +extern Measurement_t *Measurement_p; +#endif + +static void R15_Bulk_ReadChunkCallBack(Communication_t *Communication_p, const void *const Timer_p, const void *const Data_p); +static void R15_Bulk_RetransmitChunks_CallBack(const Communication_t *const Communication_p, const void *const Timer_p, const void *const Data_p); +static ErrorCode_e R15_Bulk_Process_Read(Communication_t *Communication_p, TL_BulkVectorList_t *BulkVector_p, PacketMeta_t *Packet_p); +static ErrorCode_e R15_Bulk_SendReadRequest(Communication_t *Communication_p, TL_BulkVectorList_t *BulkVector_p, uint32 Chunks, void *ChunksList_p, void *CallBack_p); +static ErrorCode_e R15_Bulk_SendWriteRequest(Communication_t *Communication_p); +static void R15_Bulk_SendData(Communication_t *Communication_p, PacketMeta_t *Packet_p, uint32 ChunkId); +static boolean R15_Bulk_CheckTransmitedChunks(const TL_BulkVectorList_t *BulkVector_p); +static boolean R15_Bulk_CheckIdInList(const TL_BulkVectorList_t *BulkVector_p, const uint32 ChunkId, const uint8 *const Data_p, const uint32 Length); +static uint32 R15_Bulk_GetNextPacketChunkId(const TL_BulkVectorList_t *BulkVector_p); +static void R15_Bulk_GetListOfReceivedChunks(const TL_BulkVectorList_t *const BulkVector_p, uint32 *Chunks_p, uint8 *ChunkList_p); +static uint32 R15_Bulk_GetChunkId(const PacketMeta_t *const Packet_p); +static uint32 R15_Bulk_GetTimerChunkRetransmision(const Communication_t *const Communication_p, uint32 Time, HandleFunction_t CallBack_p); +static void R15_Bulk_MarkNotAckChunks(TL_BulkVectorList_t *BulkVector_p, const uint8 *const Payload_p, const uint32 Length); +static void R15_Bulk_MarkNotAckAllChunks(TL_BulkVectorList_t *BulkVector_p); +#ifdef CFG_ENABLE_LOADER_TYPE +static boolean R15_Bulk_CheckAcknowledgedChunks(const TL_BulkVectorList_t *BulkVector_p, const uint8 *const Payload_p); +#endif +static void R15_Bulk_OutHashCallback(const void *const Data_p, uint32 Length, const uint8 *const Hash_p, void *Param_p); +static TL_BulkVectorStatus_t R15_Bulk_GetVectorStatus(TL_BulkVectorList_t *BulkVector_p); +static TL_BulkSessionID_Status_t R15_Bulk_CheckBulkSession(Communication_t *Communication_p, uint16 SessionId); +static ErrorCode_e R15_Bulk_DataRequestHandler(Communication_t *Communication_p, PacketMeta_t *Packet_p); +static ErrorCode_e R15_Bulk_ReadRequestHandler(Communication_t *Communication_p, PacketMeta_t *Packet_p); + +#ifndef CFG_ENABLE_LOADER_TYPE +static void R15_Bulk_ClearBulkTmpParam(Communication_t *Communication_p); +static boolean IsChunkReceived(Communication_t *Communication_p, uint32 ChunkId); +#endif + + +/*********************************************************************** + * Definition of external functions + **********************************************************************/ +#ifndef CFG_ENABLE_LOADER_TYPE +void Do_R15_Bulk_SetCallbacks(Communication_t *Communication_p, void *BulkCommandCallback_p, void *BulkDataCallback_p, void *EndOfDump_p) +{ + R15_TRANSPORT(Communication_p)->BulkCommandCallback_p = BulkCommandCallback_p; + R15_TRANSPORT(Communication_p)->BulkDataCallback_p = BulkDataCallback_p; + R15_TRANSPORT(Communication_p)->EndOfDump_p = EndOfDump_p; +} +#endif + +/* + * Opens Bulk session. + * + * @param [in] Communication_p Communication module context. + * @param [in] SessionId Session ID. + * @param [in] Mode Type of operation(Read or Write). + * (send or receive) over the bulk protocol. + * + * @return Vector ID Vector ID of the newly opened session. + * @retval BULK_ERROR If the session can not be opened. + */ +uint32 Do_R15_Bulk_OpenSession(const Communication_t *const Communication_p, const uint16 SessionId, const TL_SessionMode_t Mode) +{ + uint32 VectorCounter; + + if (NULL == Communication_p) { + return BULK_ERROR; + } + + for (VectorCounter = 1; (VectorCounter < MAX_BULK_TL_PROCESSES) && (R15_TRANSPORT(Communication_p)->BulkVectorList[VectorCounter].Status != BULK_SESSION_IDLE); VectorCounter++); + + if (MAX_BULK_TL_PROCESSES != VectorCounter) { + if (R15_TRANSPORT(Communication_p)->BulkVectorList[VectorCounter].Status != BULK_SESSION_IDLE) { + VectorCounter = BULK_ERROR; + } else { + R15_TRANSPORT(Communication_p)->BulkVectorList[VectorCounter].Status = BULK_SESSION_OPEN; + R15_TRANSPORT(Communication_p)->BulkVectorList[VectorCounter].SessionId = SessionId; + R15_TRANSPORT(Communication_p)->BulkVectorList[VectorCounter].Mode = Mode; + R15_TRANSPORT(Communication_p)->BulkVectorList[VectorCounter].Length = 0; + R15_TRANSPORT(Communication_p)->BulkVectorList[VectorCounter].TransferedLength = 0; + R15_TRANSPORT(Communication_p)->BulkVectorList[VectorCounter].Offset = 0; + R15_TRANSPORT(Communication_p)->BulkVectorList[VectorCounter].ChunkSize = 0; + R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey = 0; + } + } else { + VectorCounter = BULK_ERROR; + } + + C_(printf("bulk_protocol.c (%d): Opened Bulk session(%d)with VId(%d)\n", __LINE__, SessionId, VectorCounter);) + return VectorCounter; +} + +/* + * Creates Bulk Vector. + * + * @param [in] Communication_p Communication module context. + * @param [in] BulkVector Index of Bulk Vector. + * @param [in] Length Data Length in bytes. + * @param [in] BuffSize Requested size of each Buffer. + * @param [in] CreatedBulkVector_p Already created bulk vector which + * need to be updated with correct + * information. + * + * @return Vector ID The ID of the Vector that has been created. + * @retval BULK_ERROR If creation of vector failed. + */ +TL_BulkVectorList_t *Do_R15_Bulk_CreateVector(const Communication_t *const Communication_p, const uint32 BulkVector, uint32 Length, const uint32 BuffSize, TL_BulkVectorList_t *CreatedBulkVector_p) +{ + uint32 Counter; + uint32 AvailableBuffers = 0; + uint32 Buffers; + PacketMeta_t *Packet_p = NULL; + TL_BulkVectorList_t *BulkVector_p = NULL; + + if (NULL == Communication_p) { + return NULL; + } + +#ifndef CFG_ENABLE_LOADER_TYPE + int BuffersNr = 0; +#endif + + /* check input parameters */ + if ((0 == BulkVector) || (MAX_BULK_TL_PROCESSES <= BulkVector) || (BuffSize == 0) || (BuffSize > (BULK_BUFFER_SIZE - ALIGNED_HEADER_LENGTH - ALIGNED_BULK_EXTENDED_HEADER_LENGTH)) || (Length == 0)) { + A_(printf("bulk_protocol.c (%d): ** Invalid input parameters! **\n", __LINE__);) + return NULL; + } + + BulkVector_p = &(R15_TRANSPORT(Communication_p)->BulkVectorList[BulkVector]); + + if (NULL == CreatedBulkVector_p) { + Buffers = ((Length + BuffSize - 1) / BuffSize); + + if (0 == Buffers) { + return NULL; + } + + AvailableBuffers = BUFFER(Communication_p, BuffersAvailable_Fn)(OBJECT_BUFFER(Communication_p), BULK_BUFFER_SIZE); + + if (AvailableBuffers >= Buffers) { + BulkVector_p->Length = Length; + BulkVector_p->Buffers = Buffers; + BulkVector_p->ChunkSize = BuffSize; + BulkVector_p->Offset = 0; + + for (Counter = 0; (Counter < Buffers); Counter++) { + BulkVector_p->Entries[Counter].Buffer_p = NULL; + + if (BULK_SEND == BulkVector_p->Mode) { +#ifdef CFG_ENABLE_LOADER_TYPE + Packet_p = R15_Network_PacketAllocate(Communication_p, BULK_BUFFER_SIZE); + + if (NULL == Packet_p) { + A_(printf("bulk_protocol.c (%d): ** Memory allocation failed! **\n", __LINE__);) + return NULL; + } + + Packet_p->ExtendedHeader_p = Packet_p->Buffer_p + HEADER_OFFSET_IN_BUFFER + ALIGNED_HEADER_LENGTH; + Packet_p->Payload_p = Packet_p->ExtendedHeader_p + ALIGNED_BULK_EXTENDED_HEADER_LENGTH; +#else + /* packet meta info allocate */ + Packet_p = (PacketMeta_t *)malloc(sizeof(PacketMeta_t)); + + if (NULL == Packet_p) { + return NULL; + } + + memset(Packet_p, 0, sizeof(PacketMeta_t)); + + /* packet meta info setup */ + Packet_p->Buffer_p = NULL; + Packet_p->BufferSize = BULK_BUFFER_SIZE; + SET_PACKET_FLAGS(Packet_p, PACKET_ALLOCATION_STATE_MASK, BUF_ALLOCATED); + Packet_p->Payload_p = (uint8 *)(HEADER_OFFSET_IN_BUFFER + ALIGNED_HEADER_LENGTH + ALIGNED_BULK_EXTENDED_HEADER_LENGTH); + Packet_p->ExtendedHeader_p = Packet_p->Buffer_p + HEADER_OFFSET_IN_BUFFER + ALIGNED_HEADER_LENGTH; + BuffersNr = 0; + + do { + if (NULL == R15_NETWORK(Communication_p)->MetaInfoList[BuffersNr]) { + R15_NETWORK(Communication_p)->MetaInfoList[BuffersNr] = Packet_p; + break; + } + + BuffersNr ++; + } while (BuffersNr < (COMMAND_BUFFER_COUNT + BULK_BUFFER_COUNT)); + + if (COMMAND_BUFFER_COUNT + BULK_BUFFER_COUNT <= BuffersNr) { + BUFFER_FREE(Packet_p); + return NULL; + } + +#endif // #ifdef CFG_ENABLE_LOADER_TYPE + + BulkVector_p->Entries[Counter].Buffer_p = Packet_p; + BulkVector_p->Entries[Counter].Payload_p = Packet_p->Payload_p; + BulkVector_p->Entries[Counter].Hash_p = Packet_p->Hash; + } + } + } else { + A_(printf("bulk_protocol.c (%d) ** Not enough buffers! ** \n", __LINE__);) + return NULL; + } + } else { + memcpy(BulkVector_p, CreatedBulkVector_p, sizeof(TL_BulkVectorList_t)); + } + + return BulkVector_p; +} + +/* + * Frees Bulk Vector. + * + * @param [in] Communication_p Communication module context. + * @param [in] BulkVector_p Pointer to the Bulk Vector. + * @param [in] ReqReleaseBuffer Defines if complete buffers with metadata will + * be released or only only the metadata will be cleared. + * + * @retval E_SUCCESS After successful execution. + * @retval BULK_ERROR Error while destroying vector. + */ +uint32 Do_R15_Bulk_DestroyVector(const Communication_t *const Communication_p, TL_BulkVectorList_t *BulkVector_p, boolean ReqReleaseBuffer) +{ + uint32 ReturnValue = E_SUCCESS; + uint32 Counter; + int BuffersNr = 0; + + if (NULL == Communication_p) { + return BULK_ERROR; + } + + if (NULL == BulkVector_p) { + A_(printf("bulk_protocol.c (%d): ** Invalid bulk vector! **\n", __LINE__);) + return BULK_ERROR; + } + + for (Counter = 0; (Counter < BulkVector_p->Buffers); Counter++) { + /* clear all flags by setting buffer as free */ + BulkVector_p->Entries[Counter].Buffer_p->Flags = BUF_FREE; + BulkVector_p->Entries[Counter].Hash_p = NULL; + + if (NULL != BulkVector_p->Entries[Counter].Buffer_p) { + if (ReqReleaseBuffer) { + ReturnValue = R15_Network_PacketRelease(Communication_p, BulkVector_p->Entries[Counter].Buffer_p); + BulkVector_p->Entries[Counter].Buffer_p = NULL; + } else { + C_(printf("bulk_protocol.c (%d): Destroyed meta info data (0x%x)for bulk buffers! \n", __LINE__, BulkVector_p->Entries[Counter].Buffer_p);) + BuffersNr = 0; + + do { + if (BulkVector_p->Entries[Counter].Buffer_p == R15_NETWORK(Communication_p)->MetaInfoList[BuffersNr]) { + R15_NETWORK(Communication_p)->MetaInfoList[BuffersNr] = NULL; + /* release meta info for buffer */ + free(BulkVector_p->Entries[Counter].Buffer_p); + BulkVector_p->Entries[Counter].Buffer_p = NULL; + break; + } + + BuffersNr ++; + } while (BuffersNr < (COMMAND_BUFFER_COUNT + BULK_BUFFER_COUNT)); + } + } + } + + C_(printf("bulk_protocol.c (%d): Destroyed bulk vector for session(%d)! \n", __LINE__, BulkVector_p->SessionId);) + BulkVector_p->Status = BULK_SESSION_IDLE; + BulkVector_p->SessionId = 0; + BulkVector_p->Mode = BULK_RECEIVE; + BulkVector_p->Length = 0; + BulkVector_p->Buffers = 0; + BulkVector_p->ChunkSize = 0; + BulkVector_p->Offset = 0; + + return ReturnValue; +} + +/* + * Start specified bulk session. + * + * @param [in] Communication_p Communication module context. + * @param [in] BulkVector_p Pointer to the Bulk Vector. + * @param [in] Offset Sets the offset from where data + * read/write should be performed. + * + * @retval E_INVALID_BULK_MODE Invalid bulk mode. + * @retval E_FAILED_TO_START_BULK_SESSION Either the session is + * invalid or the BulkVector is invalid. + * @retval E_SUCCESS After successful execution. + */ +ErrorCode_e Do_R15_Bulk_StartSession(Communication_t *Communication_p, TL_BulkVectorList_t *BulkVector_p, const uint64 Offset) +{ + ErrorCode_e ReturnValue = E_SUCCESS; + uint32 ChunkId; + + VERIFY(NULL != Communication_p, E_INVALID_INPUT_PARAMETERS); + + /* Verify the new bulk vector. */ + VERIFY(NULL != BulkVector_p, E_INVALID_INPUT_PARAMETERS); + /* Verify that the bulk session is opend for this bulk vector. */ + VERIFY(BULK_SESSION_IDLE != BulkVector_p->Status, E_FAILED_TO_START_BULK_SESSION); + /* Verify that the previouse bulk session is closed. */ + VERIFY(NULL == R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p, E_PREVIOUS_BULK_SESSION_IS_NOT_CLOSED); + + BulkVector_p->Status = BULK_SESSION_PROCESSING; + BulkVector_p->Offset = Offset; + + /* set the handle for the current bulk vector */ + R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p = BulkVector_p; + R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey = 0; + + C_(printf("bulk_protocol.c(%d) Session(%d) Started!\n", __LINE__, BulkVector_p->SessionId);) + C_(printf("bulk_protocol.c(%d) Req: Chunks(%d) ChunkSize(%d) Length(%d)\n", __LINE__, BulkVector_p->Buffers, BulkVector_p->ChunkSize, BulkVector_p->Length);) + + if (BULK_RECEIVE == BulkVector_p->Mode) { + /* Set BULK READ state machine */ +#ifdef CFG_ENABLE_LOADER_TYPE + BulkVector_p->State = SEND_READ_REQUEST; +#else + BulkVector_p->State = WAIT_WRITE_REQUEST; +#endif + ReturnValue = R15_Bulk_Process_Read(Communication_p, BulkVector_p, NULL); + } else { + VERIFY(BULK_SEND == BulkVector_p->Mode, E_INVALID_BULK_MODE); + + for (ChunkId = 0; ChunkId < BulkVector_p->Buffers; ChunkId++) { + SET_PACKET_FLAGS(BulkVector_p->Entries[ChunkId].Buffer_p, PACKET_TX_STATE_MASK, BUF_TX_READY); + } + + /* Set BULK WRITE state machine */ +#ifdef CFG_ENABLE_LOADER_TYPE + BulkVector_p->State = SEND_WRITE_REQUEST; +#else + BulkVector_p->State = WAIT_READ_REQUEST; +#endif + ReturnValue = R15_Bulk_Process_Write(Communication_p, BulkVector_p); + } + +#ifdef CFG_ENABLE_MEASUREMENT_TOOL + ReturnValue = Do_Measurement_CreateSessionMeasurementData(Communication_p, &(Measurement_p->MeasurementData_p->SessionMeasurement_p), + NULL, BulkVector_p->Buffers, BulkVector_p->SessionId); + ReturnValue = MP(Measurement_p, 0, START_SESSION_TIME); +#endif +ErrorExit: + return ReturnValue; +} + + +/* + * Get status of bulk transfer. + * + * @param [in] BulkVector_p Pointer to the Bulk Vector. + * + * @retval BULK_SESSION_IDLE Idle state of bulk protocol. + * @retval BULK_SESSION_OPEN Opened bulk protocol and ready for + * transmitting. + * @retval BULK_SESSION_PROCESSING Processing bulk transfer. + * @retval BULK_SESSION_FINISHED Bulk transfer finished. + */ +TL_BulkSessionState_t Do_R15_Bulk_GetStatusSession(const TL_BulkVectorList_t *BulkVector_p) +{ + if (NULL != BulkVector_p) { + return BulkVector_p->Status; + } + + return BULK_SESSION_IDLE; +} + +/* + * Close specified Bulk session. + * + * @param [in] Communication_p Communication module context. + * @param [in] BulkVector_p Pointer to the Bulk Vector. + * for the session you want to close. + * + * @retval E_SUCCESS After successful execution. + * @retval E_FAILED_TO_CLOSE_BULK_SESSION If the BulkVector is not valid. + */ +//lint -e{818} +ErrorCode_e Do_R15_Bulk_CloseSession(Communication_t *Communication_p, TL_BulkVectorList_t *BulkVector_p) +{ + ErrorCode_e ReturnValue = E_SUCCESS; + + VERIFY(NULL != Communication_p, E_INVALID_INPUT_PARAMETERS); + + /* Verify that the requested bulk session is started. */ + VERIFY(NULL != BulkVector_p, E_FAILED_TO_CLOSE_BULK_SESSION); + + R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p = NULL; + + C_(printf("bulk_protocol.c (%d): Bulk session(%d) closed! \n", __LINE__, BulkVector_p->SessionId);) +#ifdef CFG_ENABLE_MEASUREMENT_TOOL + ReturnValue = MP(Measurement_p, 0, END_SESSION_TIME); +#endif + +ErrorExit: + return ReturnValue; +} + + +/* + * Handling received bulk command. + * + * @param [in] Communication_p Communication module context. + * @param [in] Packet_p Pointer to the received buffer. + * + * @retval E_SUCCESS After successful execution. + * @retval E_INVALID_INPUT_PARAMETERS If Packet_p is NULL. + */ +ErrorCode_e R15_Bulk_Process(Communication_t *Communication_p, PacketMeta_t *Packet_p) +{ + ErrorCode_e ReturnValue = E_SUCCESS; + BulkExtendedHeader_t ExtendedHeader = {0}; +#ifdef CFG_ENABLE_LOADER_TYPE + TL_BulkVectorList_t *BulkVector_p = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p; + TL_BulkVectorList_t *PreviousBulkVector_p = &(R15_TRANSPORT(Communication_p)->PreviousBulkVector); + uint32 ChunksCount = 0; + uint8 ChunksList[MAX_BULK_TL_PROCESSES]; +#endif + + /* check input parameters */ + VERIFY(NULL != Packet_p, E_INVALID_INPUT_PARAMETERS); + + //lint --e(826) + R15_DeserializeBulkExtendedHeader(&ExtendedHeader, Packet_p->ExtendedHeader_p); + VERIFY(ExtendedHeader.Session > 0, E_INVALID_BULK_SESSION_ID); + + /* check bulk session opened? */ +#ifdef CFG_ENABLE_LOADER_TYPE + + if ((NULL == BulkVector_p) || (ExtendedHeader.Session != BulkVector_p->SessionId)) { + C_(printf("bulk_protocol.c (%d): Session is not opend(%d) or wrong session(%d)! \n", __LINE__, R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p, ExtendedHeader.Session);) + + if ((CMD_BULK_DATA == (ExtendedHeader.TypeFlags & MASK_BULK_COMMAND_SELECT)) && + NULL != PreviousBulkVector_p) { + // make the list of received chunks + R15_Bulk_GetListOfReceivedChunks(PreviousBulkVector_p, &ChunksCount, ChunksList); + // send read ACK for previous session + ReturnValue = R15_Bulk_SendReadRequest(Communication_p, PreviousBulkVector_p, ChunksCount, ChunksList, NULL); + } + + // release the buffer used for the invalid packet + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); + goto ErrorExit; + } + +#endif + + switch (ExtendedHeader.TypeFlags & MASK_BULK_COMMAND_SELECT) { + case CMD_BULK_DATA: + ReturnValue = R15_Bulk_DataRequestHandler(Communication_p, Packet_p); + break; + + case CMD_BULK_READ: + ReturnValue = R15_Bulk_ReadRequestHandler(Communication_p, Packet_p); + break; + +#ifndef CFG_ENABLE_LOADER_TYPE + case CMD_BULK_WRITE: + + if (NULL != R15_TRANSPORT(Communication_p)->BulkCommandCallback_p) { + BulkCommandReqCallback_t pcbf; + SESSION(Communication_p) = ExtendedHeader.Session; + CHUNKSIZE(Communication_p) = ExtendedHeader.ChunkSize; + OFFSET(Communication_p) = ExtendedHeader.Offset; + LENGTH(Communication_p) = ExtendedHeader.Length; + pcbf = (BulkCommandReqCallback_t)R15_TRANSPORT(Communication_p)->BulkCommandCallback_p; + pcbf(Communication_p->Object_p, &SESSION(Communication_p), &CHUNKSIZE(Communication_p), &OFFSET(Communication_p), &LENGTH(Communication_p), FALSE); + R15_Bulk_ClearBulkTmpParam(Communication_p); + } + + /* release the buffer for undefined command */ + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); + break; +#endif + case CMD_BULK_STATUS: + // not implemented. + A_(printf("bulk_protocol.c (%d): ** Not implemented bulk command! **\n", __LINE__);) + /* release the buffer for unimplemented command */ + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); + break; + + default: + A_(printf("bulk_protocol.c (%d): ** Undefined bulk command! **\n", __LINE__);) + /* release the buffer for undefined command */ + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); + break; + } + +ErrorExit: + return ReturnValue; +} + + +#ifdef CFG_ENABLE_LOADER_TYPE +/* + * Generate bulk Session ID. Allowed bulk session ID is from 1 to 65535. + * + * @param [in] Communication_p Communication module context. + * + * @retval Session ID Next free session ID. + */ +uint16 Do_R15_Bulk_GenerateBulkSessionID(Communication_t *Communication_p) +{ + if (NULL == Communication_p) { + return 0; + } + + R15_TRANSPORT(Communication_p)->BulkSessionCounter++; + + if (R15_TRANSPORT(Communication_p)->BulkSessionCounter == 0) { + R15_TRANSPORT(Communication_p)->BulkSessionCounter = 1; + } + + return R15_TRANSPORT(Communication_p)->BulkSessionCounter; +} +#endif + +/*********************************************************************** + * Definition of internal functions + **********************************************************************/ + +/* + * Get the Chunk ID for the next bulk packet which is ready for transmitting. + * + * @param [in] BulkVector_p Current bulk vector used for bulk transfer. + * + * @retval ChunkID Chunk ID for the next ready for transmitting packet. + * If none chunk is ready return last Chunk ID + 1. + */ +static uint32 R15_Bulk_GetNextPacketChunkId(const TL_BulkVectorList_t *BulkVector_p) +{ + uint32 ChunkId = 0; + + for (ChunkId = 0; ChunkId < BulkVector_p->Buffers; ChunkId++) { + if (CHECK_PACKET_FLAGS(BulkVector_p->Entries[ChunkId].Buffer_p, BUF_TX_READY)) { + break; + } + } + + return ChunkId; +} + +/* + * Check all created chunks is it transmited. + * + * @param [in] BulkVector_p Current bulk vector used for bulk transfer. + * @param [in] ChunkId ChunkID for the packet which need to be transmitted. + * + * @retval TRUE If all created chunks are transmitted. + * @retval FALSE If all created chunks are not transmitted. + */ +static boolean R15_Bulk_CheckTransmitedChunks(const TL_BulkVectorList_t *BulkVector_p) +{ + uint32 ChunkId; + + for (ChunkId = 0; ChunkId < BulkVector_p->Buffers; ChunkId++) { + if (!CHECK_PACKET_FLAGS(BulkVector_p->Entries[ChunkId].Buffer_p, BUF_TX_SENT)) { + return FALSE; + } + } + + return TRUE; +} + +#ifdef CFG_ENABLE_LOADER_TYPE +/* + * Check all acknowledged chunks. + * + * @param [in] BulkVector_p Current bulk vector used for bulk transfer. + * @param [in] Payload_p List of the acknowledged chunks. + * + * @retval TRUE If all transmitted chunks are acknowledged. + * @retval FALSE If all transmitted chunks are not acknowledged. + */ +static boolean R15_Bulk_CheckAcknowledgedChunks(const TL_BulkVectorList_t *BulkVector_p, const uint8 *const Payload_p) +{ + uint32 i; + uint8 Data[16]; + + memset(Data, 0, 16); + + for (i = 0; i < BulkVector_p->Buffers; i++) { + Data[i] = (uint8)i; + } + + if (memcmp(Data, Payload_p, BulkVector_p->Buffers) == 0) { + return TRUE; + } + + return FALSE; +} +#endif + +static void R15_Bulk_MarkNotAckChunks(TL_BulkVectorList_t *BulkVector_p, const uint8 *const Payload_p, const uint32 Length) +{ + uint32 ChunkId; + + for (ChunkId = 0; ChunkId < BulkVector_p->Buffers; ChunkId++) { + if (!R15_Bulk_CheckIdInList(BulkVector_p, ChunkId, Payload_p, Length) && + !CHECK_PACKET_FLAGS(BulkVector_p->Entries[ChunkId].Buffer_p, BUF_TX_SENDING)) { + SET_PACKET_FLAGS(BulkVector_p->Entries[ChunkId].Buffer_p, PACKET_TX_STATE_MASK, BUF_TX_READY); + BulkVector_p->State = SENDING_CHUNKS; + } + } +} + +static void R15_Bulk_MarkNotAckAllChunks(TL_BulkVectorList_t *BulkVector_p) +{ + uint32 ChunkId; + + for (ChunkId = 0; ChunkId < BulkVector_p->Buffers; ChunkId++) { + SET_PACKET_FLAGS(BulkVector_p->Entries[ChunkId].Buffer_p, PACKET_TX_STATE_MASK, BUF_TX_READY); + } + + BulkVector_p->State = SENDING_CHUNKS; +} + +static boolean R15_Bulk_CheckIdInList(const TL_BulkVectorList_t *BulkVector_p, const uint32 ChunkId, const uint8 *const Data_p, const uint32 Length) +{ + uint32 i; + + for (i = 0; i < Length; i++) { + if (ChunkId == *(Data_p + i)) { + return TRUE; + } + } + + return FALSE; +} + +static ErrorCode_e R15_Bulk_Process_Read(Communication_t *Communication_p, TL_BulkVectorList_t *BulkVector_p, PacketMeta_t *Packet_p) +{ + uint32 ChunkId = 0; + uint8 ChunksList[MAX_BULK_TL_PROCESSES]; + ErrorCode_e ReturnValue = E_SUCCESS; + TL_BulkVectorStatus_t ChunkReceivedStatus; +#ifndef CFG_ENABLE_LOADER_TYPE + BulkCommandReqCallback_t pcbf; +#endif + + if (NULL == BulkVector_p) { + return E_INVALID_INPUT_PARAMETERS; + } + + switch (BulkVector_p->State) { + /* Idle state */ + case BULK_IDLE_STATE: + // wait to start the bulk session + break; + +#ifndef CFG_ENABLE_LOADER_TYPE + /* coverity[unterminated_case] */ + case WAIT_WRITE_REQUEST: + BulkVector_p->State = SEND_READ_REQUEST; +#endif //CFG_ENABLE_LOADER_TYPE + + /* coverity[fallthrough] */ + case SEND_READ_REQUEST: + //lint --e(611) + ReturnValue = R15_Bulk_SendReadRequest(Communication_p, BulkVector_p, 0, NULL, (void *)R15_Bulk_ReadChunkCallBack); + + if (E_SUCCESS == ReturnValue) { + BulkVector_p->State = WAIT_CHUNKS; + } + + break; + + case WAIT_CHUNKS: + ChunkId = R15_Bulk_GetChunkId(Packet_p); + + /* Try to release the timer for the bulk read request */ + if (R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey > 0) { + (void)TIMER(Communication_p, TimerRelease_Fn)(OBJECT_TIMER(Communication_p), R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey); + R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey = 0; + } + + C_(printf("bulk_protocol.c(%d) Received Chunk(%d) Size(%d) Length(%d)\n", __LINE__, ChunkId, ((BulkExtendedHeader_t *)(Packet_p->ExtendedHeader_p))->ChunkSize, ((BulkExtendedHeader_t *)(Packet_p->ExtendedHeader_p))->Length);) + +#ifdef CFG_ENABLE_MEASUREMENT_TOOL + ReturnValue = MP(Measurement_p, ChunkId, RECEIVED_CHUNK_TIME); +#endif + + if (ChunkId >= BulkVector_p->Buffers) { + /* Packet with invalid chunk Id and release the buffer. */ + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); + break; + } else if (NULL == BulkVector_p->Entries[ChunkId].Buffer_p) { + BulkVector_p->Entries[ChunkId].Buffer_p = Packet_p; + + SET_PACKET_FLAGS(BulkVector_p->Entries[ChunkId].Buffer_p, PACKET_RX_STATE_MASK, BUF_ACK_READY); + //lint --e(413) + BulkVector_p->Entries[ChunkId].Payload_p = Packet_p->Payload_p; + //lint --e(413) + BulkVector_p->Entries[ChunkId].Hash_p = Packet_p->Hash; + + /* */ + C_(printf("bulk_protocol.c(%d) Received Chunks until (%d)\n", __LINE__, ChunkId);) + } else { + /* Packet with already received chunk Id. Release the network packet. */ + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); + } + + /* make the list of received chunks and send for retransmission of all missed chunks */ + R15_Bulk_GetListOfReceivedChunks(BulkVector_p, &ChunkId, ChunksList); + + /* check if all chunks are received */ + ChunkReceivedStatus = R15_Bulk_GetVectorStatus(BulkVector_p); + + if (VECTOR_COMPLETE == ChunkReceivedStatus) { + C_(printf("bulk_protocol.c(%d) Last Chunk Received (%d)\n", __LINE__, ChunkId);) + /* save the current bulk vector before is bulk session closed */ + memcpy(&(R15_TRANSPORT(Communication_p))->PreviousBulkVector, BulkVector_p, sizeof(TL_BulkVectorList_t)); + ReturnValue = R15_Bulk_SendReadRequest(Communication_p, BulkVector_p, ChunkId, ChunksList, NULL); + BulkVector_p->Status = BULK_SESSION_FINISHED; + BulkVector_p->State = BULK_IDLE_STATE; +#ifndef CFG_ENABLE_LOADER_TYPE + // notify session end + pcbf = (BulkCommandReqCallback_t)R15_TRANSPORT(Communication_p)->BulkCommandCallback_p; + pcbf(Communication_p->Object_p, &BulkVector_p->SessionId, &BulkVector_p->ChunkSize, &BulkVector_p->Offset, &BulkVector_p->Length, TRUE); +#endif + } else if (VECTOR_MISSING_CHUNK == ChunkReceivedStatus) { + ReturnValue = R15_Bulk_SendReadRequest(Communication_p, BulkVector_p, ChunkId, ChunksList, NULL); + } else { // Chunks are received in order + R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey = R15_Bulk_GetTimerChunkRetransmision(Communication_p, R15_TIMEOUTS(Communication_p)->TBDR, (HandleFunction_t)R15_Bulk_ReadChunkCallBack); + } + + break; + + case SEND_BULK_ACK: //TODO: check this state. look like unused state!!! + R15_Bulk_GetListOfReceivedChunks(BulkVector_p, &ChunkId, ChunksList); + ReturnValue = R15_Bulk_SendReadRequest(Communication_p, BulkVector_p, ChunkId, ChunksList, NULL); + break; + + default: + BulkVector_p->State = BULK_IDLE_STATE; + ReturnValue = E_INVALID_BULK_PROTOCOL_STATE; + break; + } + + return ReturnValue; +} + + +/* + * State machine for bulk transfer from ME to PC. + * + * @param [in] Communication_p Communication module context. + * @param [in] BulkVector_p Pointer to the received buffer. + * + */ +ErrorCode_e R15_Bulk_Process_Write(Communication_t *Communication_p, TL_BulkVectorList_t *BulkVector_p) +{ + ErrorCode_e ReturnValue = E_SUCCESS; + uint32 ChunkId; + static uint32 reentrant = 1; + + if (reentrant) { + reentrant = 0; + + if (BulkVector_p->Mode == BULK_SEND) { + switch (BulkVector_p->State) { + /* Idle state */ + case BULK_IDLE_STATE: + // wait to start the bulk session + break; + + case SEND_WRITE_REQUEST: + ReturnValue = R15_Bulk_SendWriteRequest(Communication_p); + + if (E_SUCCESS == ReturnValue) { + BulkVector_p->State = WAIT_READ_REQUEST; + } + + break; + + case WAIT_BULK_ACK: + //...? + break; + + case WAIT_READ_REQUEST: +#ifndef CFG_ENABLE_LOADER_TYPE + //TODO find end release timer for retransmision + BulkVector_p->State = SENDING_CHUNKS; +#else + //... + break; +#endif + + /* continue to send chunks */ + case SENDING_CHUNKS: + /* get Chunk ID of next packet! */ + ChunkId = R15_Bulk_GetNextPacketChunkId(BulkVector_p); + + if (ChunkId <= BulkVector_p->Buffers - 1) { + /* get and send packet with chunk ID */ + R15_Bulk_SendData(Communication_p, BulkVector_p->Entries[ChunkId].Buffer_p, ChunkId); +#ifndef CFG_ENABLE_LOADER_TYPE + + if (NULL != R15_TRANSPORT(Communication_p)->BulkDataCallback_p) { + BulkDataReqCallback_t pcbf; + SESSION(Communication_p) = BulkVector_p->SessionId; + CHUNKSIZE(Communication_p) = BulkVector_p->ChunkSize; + OFFSET(Communication_p) = BulkVector_p->Offset; + LENGTH(Communication_p) = BulkVector_p->Length; + TRANSFEREDLENGTH(Communication_p) += CHUNKSIZE(Communication_p); + pcbf = (BulkDataReqCallback_t)R15_TRANSPORT(Communication_p)->BulkDataCallback_p; + pcbf(Communication_p->Object_p, &SESSION(Communication_p), &CHUNKSIZE(Communication_p), &OFFSET(Communication_p), &LENGTH(Communication_p), &TOTALLENGTH(Communication_p), &TRANSFEREDLENGTH(Communication_p)); + } + +#endif + C_(printf("bulk_protocol.c(%d) Sent chunk (%d) session (%d)\n", __LINE__, ChunkId, BulkVector_p->SessionId);) + } else { + /* all chunks are in process of sending, wait for chunks to be sent */ + if (R15_Bulk_CheckTransmitedChunks(BulkVector_p)) { + /* save the current bulk vector before bulk session is closed */ + memcpy(&(R15_TRANSPORT(Communication_p))->PreviousBulkVector, BulkVector_p, sizeof(TL_BulkVectorList_t)); + R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey = R15_Bulk_GetTimerChunkRetransmision(Communication_p, R15_TIMEOUTS(Communication_p)->TBCR, (HandleFunction_t)R15_Bulk_RetransmitChunks_CallBack); + BulkVector_p->State = WAIT_BULK_ACK; + C_(printf("bulk_protocol.c(%d) Wait BULK ACK for session (%d)!\n", __LINE__, BulkVector_p->SessionId);) + } + } + +#ifdef CFG_ENABLE_MEASUREMENT_TOOL + ReturnValue = MP(Measurement_p, ChunkId, RECEIVED_CHUNK_TIME); +#endif + break; + + case WRITE_BULK_FINISH: + BulkVector_p->State = BULK_IDLE_STATE; + BulkVector_p->Status = BULK_SESSION_FINISHED; + C_(printf("bulk_protocol.c(%d) Write bulk process finished! \n", __LINE__);) + break; + + default: + BulkVector_p->State = BULK_IDLE_STATE; + break; + } + } + + reentrant = 1; + } + + return ReturnValue; +} + + +static ErrorCode_e R15_Bulk_SendReadRequest(Communication_t *Communication_p, TL_BulkVectorList_t *BulkVector_p, uint32 Chunks, void *ChunksList_p, void *CallBack_p) +{ + ErrorCode_e ReturnValue = E_GENERAL_COMMUNICATION_ERROR; + BulkExtendedHeader_t ExtendedHeader; + R15_Header_t Header; + SendData_LP_t Param; + + /* setup header data */ + Header.Protocol = BULK_PROTOCOL; + Header.Flags = Communication_p->CurrentFamilyHash; + Header.PayloadLength = Chunks * sizeof(uint8); + Header.PayloadChecksum = 0; + Header.ExtendedHeaderLength = BULK_EXTENDED_HEADER_LENGTH; + Header.ExtendedHeaderChecksum = 0; + + /* Set extended header parameters */ + ExtendedHeader.Session = BulkVector_p->SessionId; + ExtendedHeader.AcksChunk = (uint8)Chunks; + ExtendedHeader.ChunkSize = BulkVector_p->ChunkSize; + ExtendedHeader.Offset = BulkVector_p->Offset; + ExtendedHeader.Length = BulkVector_p->Length; + ExtendedHeader.TypeFlags = CMD_BULK_READ; + + Param.Header_p = &Header; + Param.ExtendedHeader_p = &ExtendedHeader; + + //TODO: (xvlapis) check if ChunksList_p=NULL meaning ReadCMD which requires retransmission timer, else ReadACK CMD which doesn't require retransmission + if (0 != Chunks) { + VERIFY(NULL != ChunksList_p, E_INVALID_INPUT_PARAMETERS); + Param.Payload_p = ChunksList_p; + Param.TimerCallBackFn_p = NULL; + Param.Time = 0; + } else { + Param.Time = R15_TIMEOUTS(Communication_p)->TBDR; // Receiving chunks + + if (Chunks != 0) { + VERIFY(NULL != ChunksList_p, E_INVALID_INPUT_PARAMETERS); + Param.Payload_p = ChunksList_p; + } + + VERIFY(NULL != CallBack_p, E_INVALID_INPUT_PARAMETERS); + //lint --e(611) + Param.TimerCallBackFn_p = (HandleFunction_t)CallBack_p; + } + + ReturnValue = R15_Transport_Send(Communication_p, &Param); + +ErrorExit: + return ReturnValue; +} + + +static ErrorCode_e R15_Bulk_SendWriteRequest(Communication_t *Communication_p) +{ + ErrorCode_e ReturnValue = E_GENERAL_COMMUNICATION_ERROR; + BulkExtendedHeader_t ExtendedHeader; + R15_Header_t Header; + SendData_LP_t Param; + TL_BulkVectorList_t *BulkVector_p = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p; + + /* setup header data */ + Header.Protocol = BULK_PROTOCOL; + Header.Flags = Communication_p->CurrentFamilyHash; + Header.PayloadLength = 0; + Header.PayloadChecksum = 0; + Header.ExtendedHeaderLength = BULK_EXTENDED_HEADER_LENGTH; + Header.ExtendedHeaderChecksum = 0; + + /* Set extended header parameters */ + ExtendedHeader.Session = BulkVector_p->SessionId; + ExtendedHeader.AcksChunk = 0; + ExtendedHeader.ChunkSize = BulkVector_p->ChunkSize; + ExtendedHeader.Offset = BulkVector_p->Offset; + ExtendedHeader.Length = BulkVector_p->Length; + ExtendedHeader.TypeFlags = CMD_BULK_WRITE; + + Param.Header_p = &Header; + Param.ExtendedHeader_p = &ExtendedHeader; + Param.Payload_p = NULL; + Param.Time = R15_TIMEOUTS(Communication_p)->TBCR; + Param.TimerCallBackFn_p = NULL; + ReturnValue = R15_Transport_Send(Communication_p, &Param); + return ReturnValue; +} + + +static void R15_Bulk_SendData(Communication_t *Communication_p, PacketMeta_t *Packet_p, uint32 ChunkId) +{ + BulkExtendedHeader_t ExtendedHeader; + R15_Header_t Header; + TL_BulkVectorList_t *BulkVector_p = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p; + uint32 DeltaLength = 0; + + /* check if packet is already serialized and calculated */ + if (!CHECK_PACKET_FLAGS(Packet_p, (BUF_ALLOCATED | BUF_TX_READY | BUF_PAYLOAD_CRC_CALCULATED))) { + Packet_p->Timer_p = NULL; + Packet_p->Resend = 0; + /* set call back function */ + Packet_p->CallBack_p = NULL; + + /* setup header data */ + memset(&Header, 0, HEADER_LENGTH); + Header.Protocol = BULK_PROTOCOL; + Header.Flags = Communication_p->CurrentFamilyHash; + + if ((ChunkId + 1) == BulkVector_p->Buffers) { + DeltaLength = (ChunkId + 1) * BulkVector_p->ChunkSize - BulkVector_p->Length; + + if (DeltaLength == 0) { + Header.PayloadLength = BulkVector_p->ChunkSize; + } else { + Header.PayloadLength = BulkVector_p->ChunkSize - DeltaLength; + } + } else { + Header.PayloadLength = BulkVector_p->ChunkSize; + } + + Header.ExtendedHeaderLength = BULK_EXTENDED_HEADER_LENGTH; + + /* Set extended header parameters */ + ExtendedHeader.Session = BulkVector_p->SessionId; + ExtendedHeader.AcksChunk = (uint8)ChunkId; + ExtendedHeader.ChunkSize = BulkVector_p->ChunkSize; + ExtendedHeader.Offset = BulkVector_p->Offset; + ExtendedHeader.Length = BulkVector_p->Length; + ExtendedHeader.TypeFlags = CMD_BULK_DATA; + + /* serialize and calculate extended header */ + Packet_p->ExtendedHeader_p = Packet_p->Buffer_p + HEADER_OFFSET_IN_BUFFER + ALIGNED_HEADER_LENGTH; + R15_SerializeExtendedHeader(Packet_p->ExtendedHeader_p, Header.Protocol, &ExtendedHeader, &(Header.ExtendedHeaderChecksum)); + /* setup header for serialization and calculation */ + memcpy(&Packet_p->Header, &Header, HEADER_LENGTH); + + /* Calculate Payload CRC */ + Packet_p->Communication_p = Communication_p; + SET_PACKET_FLAGS(Packet_p, PACKET_CRC_STATE_MASK, BUF_CRC_CALCULATING); + + if (HASH_NONE != Packet_p->Header.Flags) { + Communication_p->HashDevice_p->Calculate(OBJECT_HASH(Communication_p), + (HashType_e)Packet_p->Header.Flags, + (void *)Packet_p->Payload_p, Packet_p->Header.PayloadLength, + Packet_p->Hash, (HashCallback_t)R15_Bulk_OutHashCallback, + (void *)Packet_p); + } else { + SET_PACKET_FLAGS(Packet_p, PACKET_CRC_STATE_MASK, BUF_PAYLOAD_CRC_CALCULATED); + memset(&Packet_p->Header.PayloadChecksum, 0x0, sizeof(uint32)); + //SET_PACKET_FLAGS(Packet_p, PACKET_CRC_STATE_MASK, BUF_HEADER_CRC_CALCULATED); + R15_SerializeHeader(Packet_p->Buffer_p + HEADER_OFFSET_IN_BUFFER, &Packet_p->Header); + (void)QUEUE(Packet_p->Communication_p, FifoEnqueue_Fn)(OBJECT_QUEUE(Packet_p->Communication_p), Packet_p->Communication_p->Outbound_p, Packet_p); + } + } else { + (void)QUEUE(Packet_p->Communication_p, FifoEnqueue_Fn)(OBJECT_QUEUE(Packet_p->Communication_p), Packet_p->Communication_p->Outbound_p, Packet_p); + } + + /* mark packet as sent */ + SET_PACKET_FLAGS(BulkVector_p->Entries[ChunkId].Buffer_p, PACKET_TX_STATE_MASK, BUF_TX_SENDING); +} + +static void R15_Bulk_OutHashCallback(const void *const Data_p, uint32 Length, const uint8 *const Hash_p, void *Param_p) +{ + PacketMeta_t *Packet_p = (PacketMeta_t *)Param_p; + + SET_PACKET_FLAGS(Packet_p, PACKET_CRC_STATE_MASK, BUF_PAYLOAD_CRC_CALCULATED); + memcpy(&Packet_p->Header.PayloadChecksum, Hash_p, sizeof(uint32)); + + R15_SerializeHeader(Packet_p->Buffer_p + HEADER_OFFSET_IN_BUFFER, &Packet_p->Header); + (void)QUEUE(Packet_p->Communication_p, FifoEnqueue_Fn)(OBJECT_QUEUE(Packet_p->Communication_p), Packet_p->Communication_p->Outbound_p, Packet_p); +} + + +static void R15_Bulk_ReadChunkCallBack(Communication_t *Communication_p, const void *const Timer_p, const void *const Data_p) +{ + R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p->State = WAIT_CHUNKS; + (void)QUEUE((Communication_p), FifoEnqueue_Fn)(OBJECT_QUEUE(Communication_p), Communication_p->Outbound_p, (void *)Data_p); +} + +static void R15_Bulk_RetransmitChunks_CallBack(const Communication_t *const Communication_p, const void *const Timer_p, const void *const Data_p) +{ + /* set all chunks for retransmision . Max retransmision is 3. */ + uint32 ChunkId; + PacketMeta_t *Packet_p; + + for (ChunkId = 0; ChunkId < R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p->Buffers; ChunkId++) { + Packet_p = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p->Entries[ChunkId].Buffer_p; + /* set packet as ready for sending. */ + SET_PACKET_FLAGS(Packet_p, PACKET_TX_STATE_MASK, BUF_TX_READY); + } + + R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p->State = SENDING_CHUNKS; +} + +static void R15_Bulk_GetListOfReceivedChunks(const TL_BulkVectorList_t *const BulkVector_p, uint32 *Chunks_p, uint8 *ChunkList_p) +{ + uint8 ChunkCounter; + *Chunks_p = 0; + + for (ChunkCounter = 0; ChunkCounter < BulkVector_p->Buffers; ChunkCounter++) { + if (NULL != BulkVector_p->Entries[ChunkCounter].Buffer_p) { + ChunkList_p[*Chunks_p] = ChunkCounter; + (*Chunks_p)++; + } + } +} + +#ifndef CFG_ENABLE_LOADER_TYPE +static boolean IsChunkReceived(Communication_t *Communication_p, uint32 ChunkId) +{ + PacketMeta_t *Packet_p = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p->Entries[ChunkId].Buffer_p; + + if (NULL != Packet_p) { + return CHECK_PACKET_FLAGS(Packet_p, BUF_ACK_READY) || CHECK_PACKET_FLAGS(Packet_p, BUF_ACKNOWLEDGED); + } else { + return FALSE; + } +} +#endif + +static uint32 R15_Bulk_GetChunkId(const PacketMeta_t *const Packet_p) +{ + BulkExtendedHeader_t BulkExtendedHeader = {0}; + + R15_DeserializeBulkExtendedHeader(&BulkExtendedHeader, Packet_p->ExtendedHeader_p); + + //lint -e(413,826) + return BulkExtendedHeader.AcksChunk; +} + +static TL_BulkVectorStatus_t R15_Bulk_GetVectorStatus(TL_BulkVectorList_t *BulkVector_p) +{ + uint32 ChunkCounter; + PacketMeta_t *Packet_p; + TL_BulkVectorStatus_t Status = VECTOR_COMPLETE; + + for (ChunkCounter = 0; ChunkCounter < BulkVector_p->Buffers; ChunkCounter++) { + Packet_p = BulkVector_p->Entries[ChunkCounter].Buffer_p; + + if (Packet_p == NULL || + !(CHECK_PACKET_FLAGS(Packet_p, BUF_ACK_READY) || CHECK_PACKET_FLAGS(Packet_p, BUF_ACKNOWLEDGED))) { + Status = VECTOR_NOT_COMPLETE; + } else { + if (Status == VECTOR_NOT_COMPLETE) { + Status = VECTOR_MISSING_CHUNK; + break; + } + } + } + + return Status; +} + +static uint32 R15_Bulk_GetTimerChunkRetransmision(const Communication_t *const Communication_p, uint32 Time, HandleFunction_t CallBack_p) +{ + Timer_t Timer; + + Timer.Time = Time; + Timer.PeriodicalTime = 0; + Timer.HandleFunction_p = (HandleFunction_t)CallBack_p; + Timer.Data_p = NULL; + Timer.Param_p = (void *)Communication_p; + + return TIMER(Communication_p, TimerGet_Fn)(OBJECT_TIMER(Communication_p), &Timer); +} + +static ErrorCode_e R15_Bulk_ReadRequestHandler(Communication_t *Communication_p, PacketMeta_t *Packet_p) +{ + ErrorCode_e ReturnValue = E_SUCCESS; + BulkExtendedHeader_t ExtendedHeader = {0}; + TL_BulkVectorList_t *BulkVector_p = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p; + TL_BulkSessionID_Status_t BulkSessionIDStatus; +#ifndef CFG_ENABLE_LOADER_TYPE + boolean ACK_Read = FALSE; + uint32 Buffers; + BulkCommandReqCallback_t pcbf; +#endif + + R15_DeserializeBulkExtendedHeader(&ExtendedHeader, Packet_p->ExtendedHeader_p); + + // check the session ID of the received packet + BulkSessionIDStatus = R15_Bulk_CheckBulkSession(Communication_p, ExtendedHeader.Session); + VERIFY(BULK_SESSION_INVALID != BulkSessionIDStatus, E_INVALID_BULK_SESSION_ID); + +#ifdef CFG_ENABLE_LOADER_TYPE + + if (BULK_SESSION_NEW != BulkSessionIDStatus) { + // check witch chunks are acknowledged! + if (Packet_p->Header.PayloadLength > 0) { + if (!R15_Bulk_CheckAcknowledgedChunks(BulkVector_p, Packet_p->Payload_p)) { + /* mark all not ackonwledged chunks for retransmision */ + R15_Bulk_MarkNotAckChunks(BulkVector_p, Packet_p->Payload_p, ExtendedHeader.AcksChunk); + BulkVector_p->State = SENDING_CHUNKS; + } else { + BulkVector_p->State = WRITE_BULK_FINISH; + } + + /* Try to release the timer for the bulk session acknowledge */ + if (R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey > 0) { + (void)TIMER(Communication_p, TimerRelease_Fn)(OBJECT_TIMER(Communication_p), R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey); + R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey = 0; + } + } else { + if ((BulkVector_p->State == SENDING_CHUNKS) || (BulkVector_p->State == WAIT_BULK_ACK)) { + /* mark all chunks for retransmision */ + R15_Bulk_MarkNotAckAllChunks(BulkVector_p); + } else { + /* release the buffer for previous command BULK WRITE */ + uint32 Key = R15_Network_CreateUniqueKey(Packet_p, CMD_BULK_WRITE); + ReturnValue = R15_Network_CancelRetransmission(Communication_p, Key); + VERIFY((E_SUCCESS == ReturnValue) || (E_NOT_FOUND_ELEMENT_IN_RETRANSMISSION_LIST == ReturnValue), ReturnValue); + } + + BulkVector_p->State = SENDING_CHUNKS; + } + + ReturnValue = R15_Bulk_Process_Write(Communication_p, BulkVector_p); // state machine for WRITE BULK data + } + +#else + C_(printf("bulk_protocol.c(%d) Received READ packet!\n", __LINE__);) + C_(printf("bulk_protocol.c(%d) Session (%d)!\n", __LINE__, ExtendedHeader.Session);) + + /*ckeck the ACK */ + if (NULL != R15_TRANSPORT(Communication_p)->BulkCommandCallback_p) { + // check the session ID of the received packet + if (BULK_SESSION_NEW == BulkSessionIDStatus) { + /* request for new bulk session */ + // check the status of the current bulk session + if (Do_R15_Bulk_GetStatusSession(R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p) != BULK_SESSION_IDLE) { + if (BulkVector_p->State == WAIT_BULK_ACK) { + C_(printf("bulk_protocol.c(%d) Request for new session but current is not closed!\n", __LINE__);) + C_(printf("bulk_protocol.c(%d) Current: Session (%d)!\n", __LINE__, BulkVector_p->SessionId);) + C_(printf("bulk_protocol.c(%d) ReceivedPacket: Session (%d)!\n", __LINE__, ExtendedHeader.Session);) + + // close the current bulk session + (void)Do_R15_Bulk_CloseSession(Communication_p, BulkVector_p); //TODO: da se hendla return vrednosta! + + // notify session end + pcbf = (BulkCommandReqCallback_t)R15_TRANSPORT(Communication_p)->BulkCommandCallback_p; + pcbf(Communication_p->Object_p, &BulkVector_p->SessionId, &BulkVector_p->ChunkSize, &BulkVector_p->Offset, &BulkVector_p->Length, TRUE); + + // set bulk parameters for new bulk session + ACK_Read = FALSE; + SESSION(Communication_p) = ExtendedHeader.Session; + CHUNKSIZE(Communication_p) = ExtendedHeader.ChunkSize; + OFFSET(Communication_p) = ExtendedHeader.Offset; + LENGTH(Communication_p) = ExtendedHeader.Length; + pcbf(Communication_p->Object_p, &SESSION(Communication_p), &CHUNKSIZE(Communication_p), &OFFSET(Communication_p), &LENGTH(Communication_p), ACK_Read); + } else { + // can't be opened new bulk session until current session is not finished. + goto ErrorExit; + } + } else { + C_(printf("bulk_protocol.c(%d) Request for new bulk session!\n", __LINE__);) + // received request for new bulk session + ACK_Read = FALSE; + SESSION(Communication_p) = ExtendedHeader.Session; + CHUNKSIZE(Communication_p) = ExtendedHeader.ChunkSize; + OFFSET(Communication_p) = ExtendedHeader.Offset; + LENGTH(Communication_p) = ExtendedHeader.Length; + pcbf = (BulkCommandReqCallback_t)R15_TRANSPORT(Communication_p)->BulkCommandCallback_p; + pcbf(Communication_p->Object_p, &SESSION(Communication_p), &CHUNKSIZE(Communication_p), &OFFSET(Communication_p), &LENGTH(Communication_p), ACK_Read); + R15_Bulk_ClearBulkTmpParam(Communication_p); + } + } else { + // current bulk session + Buffers = ((ExtendedHeader.Length + ExtendedHeader.ChunkSize - 1) / ExtendedHeader.ChunkSize); + + if (((ExtendedHeader.AcksChunk == 0) && (Do_R15_Bulk_GetStatusSession(R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p) == BULK_SESSION_IDLE)) || (ExtendedHeader.AcksChunk == Buffers)) { + //BulkCommandReqCallback_t pcbf; + if (Buffers == ExtendedHeader.AcksChunk) { + C_(printf("bulk_protocol.c(%d) ACK for bulk session(%d)!\n", __LINE__, ExtendedHeader.Session);) + (void)TIMER(Communication_p, TimerRelease_Fn)(OBJECT_TIMER(Communication_p), R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey); + (void)Do_R15_Bulk_CloseSession(Communication_p, BulkVector_p); //TODO: da se hendla return vrednosta! + + // notify session end + pcbf = (BulkCommandReqCallback_t)R15_TRANSPORT(Communication_p)->BulkCommandCallback_p; + pcbf(Communication_p->Object_p, &BulkVector_p->SessionId, &BulkVector_p->ChunkSize, &BulkVector_p->Offset, &BulkVector_p->Length, TRUE); + } else { + C_(printf("bulk_protocol.c(%d) Request for new bulk session(%d)!\n", __LINE__, ExtendedHeader.Session);) + ACK_Read = FALSE; + SESSION(Communication_p) = ExtendedHeader.Session; + CHUNKSIZE(Communication_p) = ExtendedHeader.ChunkSize; + OFFSET(Communication_p) = ExtendedHeader.Offset; + LENGTH(Communication_p) = ExtendedHeader.Length; + + /* Try to release the timer for the bulk session acknowledge */ + if (R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey > 0) { + (void)TIMER(Communication_p, TimerRelease_Fn)(OBJECT_TIMER(Communication_p), R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey); // LCM MB bug fix: Timer should be released on request for retransmission + R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey = 0; + } + + pcbf = (BulkCommandReqCallback_t)R15_TRANSPORT(Communication_p)->BulkCommandCallback_p; + pcbf(Communication_p->Object_p, &SESSION(Communication_p), &CHUNKSIZE(Communication_p), &OFFSET(Communication_p), &LENGTH(Communication_p), ACK_Read); + R15_Bulk_ClearBulkTmpParam(Communication_p); + } + } else { + if (ExtendedHeader.AcksChunk == 0) { + /* mark all chunks for retransmision */ + R15_Bulk_MarkNotAckAllChunks(BulkVector_p); + } else { + /* mark all not ackonwledged chunks for retransmision */ + A_(printf("bulk_protocol.c (%d): Mark All NACK Chunks for Retransmission **\n", __LINE__);) + R15_Bulk_MarkNotAckChunks(BulkVector_p, Packet_p->Payload_p, ExtendedHeader.AcksChunk); + } + + BulkVector_p->State = SENDING_CHUNKS; + + /* Try to release the timer for the bulk session acknowledge */ + if (R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey > 0) { + (void)TIMER(Communication_p, TimerRelease_Fn)(OBJECT_TIMER(Communication_p), R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey); // LCM MB bug fix: Timer should be released on request for retransmission + R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey = 0; + } + } + } + } + +#endif + +ErrorExit: + /* release the buffer for command BULK READ */ + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); // TODO: proveri zosto ReturnValue se zema od ovde za posleden! + return ReturnValue; +} + +static ErrorCode_e R15_Bulk_DataRequestHandler(Communication_t *Communication_p, PacketMeta_t *Packet_p) +{ + ErrorCode_e ReturnValue = E_SUCCESS; + BulkExtendedHeader_t ExtendedHeader = {0}; + TL_BulkVectorList_t *BulkVector_p = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p; + TL_BulkVectorList_t *PreviousBulkVector_p = &(R15_TRANSPORT(Communication_p)->PreviousBulkVector); + uint32 ChunksCount = 0; + uint8 ChunksList[MAX_BULK_TL_PROCESSES]; +#ifndef CFG_ENABLE_LOADER_TYPE + uint32 ChunkId = 0; + BulkDataReqCallback_t pcbf; +#endif + + R15_DeserializeBulkExtendedHeader(&ExtendedHeader, Packet_p->ExtendedHeader_p); + +#ifdef CFG_ENABLE_LOADER_TYPE + + if (ExtendedHeader.AcksChunk == 0) { + BulkVector_p->State = WAIT_CHUNKS; + R15_TRANSPORT(Communication_p)->BulkHandle.TimerKey = 0; + } + + if (PreviousBulkVector_p->SessionId == BulkVector_p->SessionId) { + // make the list of received chunks + R15_Bulk_GetListOfReceivedChunks(PreviousBulkVector_p, &ChunksCount, ChunksList); + // send read ACK for previous session + ReturnValue = R15_Bulk_SendReadRequest(Communication_p, PreviousBulkVector_p, ChunksCount, ChunksList, NULL); + // release the buffer used for this data chunk + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); + goto ErrorExit; + } + + /* cancel retransmission, release buffer */ + ReturnValue = R15_Network_CancelRetransmission(Communication_p, R15_Network_CreateUniqueKey(Packet_p, CMD_BULK_READ)); + VERIFY(((E_SUCCESS == ReturnValue) || (ReturnValue == E_NOT_FOUND_ELEMENT_IN_RETRANSMISSION_LIST)), ReturnValue); + /* state machine for READ BULK data */ + ReturnValue = R15_Bulk_Process_Read(Communication_p, BulkVector_p, Packet_p); +#else + + if (Do_R15_Bulk_GetStatusSession(BulkVector_p) == BULK_SESSION_IDLE) { + //no opened current session + // make the list of received chunks + R15_Bulk_GetListOfReceivedChunks(PreviousBulkVector_p, &ChunksCount, ChunksList); + // send read ACK for previous session + ReturnValue = R15_Bulk_SendReadRequest(Communication_p, PreviousBulkVector_p, ChunksCount, ChunksList, NULL); + // release the buffer used for this data chunk + ReturnValue = R15_Network_PacketRelease(Communication_p, Packet_p); + } else { + if (NULL != R15_TRANSPORT(Communication_p)->BulkDataCallback_p) { + ChunkId = ExtendedHeader.AcksChunk; + + if (!IsChunkReceived(Communication_p, ChunkId)) { + SESSION(Communication_p) = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p->SessionId; + CHUNKSIZE(Communication_p) = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p->ChunkSize; + OFFSET(Communication_p) = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p->Offset; + LENGTH(Communication_p) = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p->Length; + TRANSFEREDLENGTH(Communication_p) += CHUNKSIZE(Communication_p); + pcbf = (BulkDataReqCallback_t)R15_TRANSPORT(Communication_p)->BulkDataCallback_p; + pcbf(Communication_p->Object_p, &SESSION(Communication_p), &CHUNKSIZE(Communication_p), &OFFSET(Communication_p), &LENGTH(Communication_p), &TOTALLENGTH(Communication_p), &TRANSFEREDLENGTH(Communication_p)); + C_(printf("S(%d) L(%d) CS(%d)\n", SESSION(Communication_p), LENGTH(Communication_p), CHUNKSIZE(Communication_p));) //xvsvlpi + } + } + + /* cancel retransmission, release buffer */ + ReturnValue = R15_Network_CancelRetransmission(Communication_p, R15_Network_CreateUniqueKey(Packet_p, CMD_BULK_READ)); + VERIFY(((E_SUCCESS == ReturnValue) || (ReturnValue == E_NOT_FOUND_ELEMENT_IN_RETRANSMISSION_LIST)), ReturnValue); + /* state machine for READ BULK data */ + ReturnValue = R15_Bulk_Process_Read(Communication_p, BulkVector_p, Packet_p); + } + +#endif + +ErrorExit: + return ReturnValue; +} + + +/* + * Check the bulk session ID. Can be new bulk session or the current opened bulk + * session. Session ID can't be the '0'. Allowed Session ID is 1-65535. + * + * @param[in] Communication_p Communication module context. + * @param[in] SessionId Session ID from the received bulk packet. + * + * @retval BULK_SESSION_INVALID If the Session ID=0. + * @retval BULK_SESSION_CURRENT If the session ID is same as current session ID. + * @retval BULK_SESSION_NEW New bulk session + */ +static TL_BulkSessionID_Status_t R15_Bulk_CheckBulkSession(Communication_t *Communication_p, uint16 SessionId) +{ + TL_BulkSessionID_Status_t ReturnStatus = BULK_SESSION_INVALID; + TL_BulkVectorList_t *CurrentBulkVector_p = R15_TRANSPORT(Communication_p)->BulkHandle.BulkVector_p; +#ifndef CFG_ENABLE_LOADER_TYPE + TL_BulkVectorList_t *PreviousBulkVector_p = &(R15_TRANSPORT(Communication_p)->PreviousBulkVector); +#endif + + if (SessionId == 0) { + return ReturnStatus; + } + +#ifndef CFG_ENABLE_LOADER_TYPE + + if (PreviousBulkVector_p == NULL) { + return BULK_SESSION_NEW; + } + + if ((PreviousBulkVector_p->SessionId != 0) && (Do_R15_Bulk_GetStatusSession(CurrentBulkVector_p) != BULK_IDLE_STATE)) { +#endif + + //lint --e(539) + if (CurrentBulkVector_p->SessionId == SessionId) { + ReturnStatus = BULK_SESSION_CURRENT; + } else { + ReturnStatus = BULK_SESSION_NEW; + } + +#ifndef CFG_ENABLE_LOADER_TYPE + } else { + if (PreviousBulkVector_p->SessionId < SessionId || + (SessionId == 1 && PreviousBulkVector_p->SessionId > SessionId)) { + ReturnStatus = BULK_SESSION_NEW; + } else { + ReturnStatus = BULK_SESSION_INVALID; + } + } + +#endif + return ReturnStatus; +} + +#ifndef CFG_ENABLE_LOADER_TYPE +/* + * Clear temporary saved bulk parameters + * + * @param[in] Communication_p Communication module context. + * + * return none. + */ +static void R15_Bulk_ClearBulkTmpParam(Communication_t *Communication_p) +{ + SESSION(Communication_p) = 0; + CHUNKSIZE(Communication_p) = 0; + OFFSET(Communication_p) = 0; + LENGTH(Communication_p) = 0; +} +#endif + +/** @} */ +/** @} */ +/** @} */ |