Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /***********************************************************************************
- * @file CANTS_CANTSProtocol.c
- ***********************************************************************************
- * _ _____ ____ ____ _____
- * | |/ /_ _/ ___|| _ \| ____|
- * | ' / | |\___ \| |_) | _|
- * | . \ | | ___) | __/| |___
- * |_|\_\___|____/|_| |_____|
- *
- ***********************************************************************************
- * Copyright (c) 2024 KISPE Space Systems Ltd.
- *
- *
- ***********************************************************************************
- * Created on: 07-Aug-2024 15:06:18
- * Implementation of the Class CANTS_CANTSProtocol
- * @author: Charlie Gallie
- ***********************************************************************************/
- #include "CANTS_CANTSProtocol.h"
- // If CANTS defined its own EH_ASSERT macro
- #ifdef CANTS_DEFINED_EH_ASSERT
- // Define the callback used for logging error messages
- void (*funcCANTS_LogErrorMessage)(const char*) = 0U;
- #endif // ifdef CANTS_DEFINED_EH_ASSERT
- /**
- * This class is a CAN-TS implementation. The user must provide callback functions
- * for things such as transmitting a CAN frame, getting the time, etc.
- * These callbacks do not need to have a realisation of CAN-TS, they must only be
- * able to transceive CAN2.0B Extended frames.
- * Due to this object being platform and schedule agnostic, it is the
- * responsibility of this object to handle timeouts, such as when you send a
- * telecommand request. This object has no notion of expecting a response or
- * having the ability to timeout.
- */
- /* PRIVATE ATTRIBUTES */
- /**
- * The maximum buffer size of pending frames during a transaction where
- * responsibility is taken away from the user. When callbacks to the user are
- * disabled, frames which need handled will instead be queued for this CAN-TS
- * Object to handle. This value is the maximum number of frames in each of these
- * queues.
- */
- #define CANTS_PENDING_FRAMES_QUEUE_SIZE (3U)
- /**
- * This is used to disable the Set Block callbacks while a Set Block transaction
- * is ongoing, as well as some basic, not 100% reliable, thread safety when
- * calling CANTS_SetBlock(...). The user is expected to provide their own thread
- * safety when calling that function but this can be used as a sanity check. While
- * this value is true and callbacks are not being called, all frames are queued
- * into their corresponding queue.
- */
- static tBOOL bCANTS_SetBlockBusy = FALSE;
- /**
- * The number of pending Set Block acknowledgements while there is a Set Block
- * transaction ongoing, initiated from CANTS_SetBlock(...). This represents the
- * queued frames within atsSetBlockPendingAcknowledgements.
- */
- static tUINT8 iCANTS_SetBlockPendingAcknowledgements = 0U;
- /**
- * The number of pending transfer frames in the queue.
- */
- static tUINT8 iCANTS_SetBlockPendingTransfers = 0U;
- /**
- * The number of pending report frames within the queue.
- */
- static tUINT8 iCANTS_SetBlockPendingStatusReports = 0U;
- /**
- * This is used while CANTS_SetBlock(...) is within a transaction. While callbacks
- * to the user are blocked, acknowledgement frames will be queued into here to
- * later be handled by CANTS_SetBlock(...).
- */
- static tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT atsCANTS_SetBlockPendingAcknowledgements[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
- /**
- * This is used while CANTS_SetBlock(...) is within a transaction. While callbacks
- * to the user are blocked, transfer frames will be queued into here to later be
- * handled by CANTS_SetBlock(...).
- */
- static tsCANTS_FRAME_SET_BLOCK_TRANSFER atsCANTS_SetBlockPendingTransfers[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
- /**
- * This is used while CANTS_SetBlock(...) has an ongoing transfer and callbacks to
- * the user are blocked. Incoming transfer status reports are queued into here to
- * be handled by CANTS_SetBlock(...).
- */
- static tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT atsCANTS_SetBlockPendingStatusReports[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
- /**
- * This is the current configuration of the CAN-TS object. This is assigned within
- * the Initialisation function, but the values can be modified via function calls
- * during later execution.
- */
- static tsCANTS_CONFIGURATION tsCANTS_Configuration = { 0U };
- /**
- * A function pointer assigned at initialisation. This function will either flip
- * or not flip the endianness based on the platform.
- * @returns BT_SUCCESS always
- */
- teFUNC_STATUS (*funcCANTS_LittleEndianToNativeEndianness)(tUINT64*) = 0U;
- /**
- * A function pointer assigned at initialisation. This function will either flip
- * or not flip the endianness based on the platform.
- * @returns BT_SUCCESS always
- */
- teFUNC_STATUS (*funcCANTS_NativeEndiannessToLittleEndian)(tUINT64*) = 0U;
- /**
- * The number of queued Set Block Status Request frames
- */
- static tUINT8 iCANTS_SetBlockPendingStatusRequests = 0U;
- /**
- * The queue of pending Set Block Status Requests
- */
- static tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST atsCANTS_SetBlockPendingStatusRequests[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
- /**
- * This is assigned to true while there is an ongoing Get Block transaction. While
- * this is true, user callbacks are disabled and any incoming frames used for Get
- * Block transactions are buffered into their respective queues.
- */
- static tBOOL bCANTS_GetBlockBusy = FALSE;
- /**
- * The number of queued Set Block Abort frames
- */
- static tUINT8 iCANTS_SetBlockPendingAborts = 0U;
- /**
- * The queue of pending Set Block Abort frames
- */
- static tsCANTS_FRAME_SET_BLOCK_ABORT atsCANTS_SetBlockPendingAborts[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
- /**
- * The number of queued Get Block acknowledgements
- */
- static tUINT8 iCANTS_GetBlockPendingAcknowledgements = 0U;
- /**
- * The queue of pending Get Block acknowledgement frames
- */
- static tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT atsCANTS_GetBlockPendingAcknowledgements[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
- /**
- * The number of pending Get Block start frames
- */
- static tUINT8 iCANTS_GetBlockPendingStarts = 0U;
- /**
- * The queue of pending Get Block start frames
- */
- static tsCANTS_FRAME_GET_BLOCK_START atsCANTS_GetBlockPendingStarts[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
- /**
- * The number of pending Get Block transfer frames
- */
- static tUINT8 iCANTS_GetBlockPendingTransfers = 0U;
- /**
- * The queue of pending Get Block transfer frames
- */
- static tsCANTS_FRAME_GET_BLOCK_TRANSFER atsCANTS_GetBlockPendingTransfers[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
- /**
- * The number of pending Get Block abort frames
- */
- static tUINT8 iCANTS_GetBlockPendingAborts = 0U;
- /**
- * The pending Get Block abort frames
- */
- static tsCANTS_FRAME_GET_BLOCK_ABORT atsCANTS_GetBlockPendingAborts[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
- /* PRIVATE FUNCTIONS */
- #ifndef UNIT_TEST
- static teFUNC_STATUS CANTS_HandleIncomingTelecommandRequest(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingTelecommandAcknowledgement(tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingTelemetryRequest(tsCANTS_FRAME_TELEMETRY_REQUEST* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingTelemetryAcknowledgement(tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingUnsolicitedTelemetry(tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingTimeSynchronisation(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingSetBlockRequest(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingSetBlockAcknowledgement(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingSetBlockTransfer(tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingSetBlockAbort(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingSetBlockStatusRequest(tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingSetBlockStatusReport(tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingGetBlockRequest(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingGetBlockAcknowledgement(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingGetBlockStart(tsCANTS_FRAME_GET_BLOCK_START* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingGetBlockTransfer(tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsFrame);
- static teFUNC_STATUS CANTS_HandleIncomingGetBlockAbort(tsCANTS_FRAME_GET_BLOCK_ABORT* ptsFrame);
- static teFUNC_STATUS CANTS_FlipEndianness(tUINT64* piValue);
- static teFUNC_STATUS CANTS_DoNotFlipEndianness(tUINT64* piValue);
- static teFUNC_STATUS CANTS_TranslateFrameTelecommandRequestToGeneric(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsTelecommandRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameTelecommandAcknowledgementToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsTelecommandAcknowledgement);
- static teFUNC_STATUS CANTS_TranslateFrameTelemetryRequestToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_REQUEST* ptsTelemetryRequest);
- static teFUNC_STATUS CANTS_TranslateFrameTelemetryAcknowledgementToGeneric(tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsTelemetryAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameUnsolicitedTelemetryToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsUnsolicitedTelemetry);
- static teFUNC_STATUS CANTS_TranslateFrameTimeSynchronisationToGeneric(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsTimeSynchronisation, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameSetBlockRequestToGeneric(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsSetBlockRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameSetBlockAcknowledgementToGeneric(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameSetBlockTransferToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsSetBlockTransfer);
- static teFUNC_STATUS CANTS_TranslateFrameSetBlockAbortToGeneric(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsSetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameSetBlockStatusRequestToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsSetBlockStatusRequest);
- static teFUNC_STATUS CANTS_TranslateFrameSetBlockStatusReportToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsSetBlockStatusReport);
- static teFUNC_STATUS CANTS_TranslateFrameGetBlockRequestToGeneric(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsGetBlockRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGetBlockAcknowledgementToGeneric(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsGetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGetBlockStartToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_START* ptsGetBlockStart);
- static teFUNC_STATUS CANTS_TranslateFrameGetBlockTransferToGeneric(tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsGetBlockTransfer, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGetBlockAbortToGeneric(tsCANTS_FRAME_GET_BLOCK_ABORT* ptsGetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToTelecommandRequest(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsTelecommandRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToTelecommandAcknowledgement(tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsTelecommandAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToTelemetryRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_REQUEST* ptsTelemetryRequest);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToTelemetryAcknowledgement(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsTelemetryAcknowledgement);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToUnsolicitedTelemetry(tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsUnsolicitedTelemetry, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToTimeSynchronisation(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsTimeSynchronisation, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsSetBlockRequest);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockAcknowledgement(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknoledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockTransfer(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsSetBlockTransferFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockAbort(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsSetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockStatusRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsSetBlockStatusRequest);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockStatusReport(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsSetBlockStatusReport);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsGetBlockRequest);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockAcknowledgement(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsGetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockStart(tsCANTS_FRAME_GET_BLOCK_START* ptsGetBlockStart, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockTransfer(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsGetBlockTransfer);
- static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockAbort(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_ABORT* ptsGetBlockAbort);
- #endif /* UNIT_TEST */
- /** TODO: Add exception CANTS_UNSUPPORTED_PLATFORM to EA
- * This initialises the CAN-TS Object. The configuration passed in is copied into memory contained
- * within this object and the only way to modify the values externally is via CANTS_SetNodeAddress(...
- * ) and CANTS_SetCallback(...).
- * This will also internally assign function pointers used for flipping endianness based on the
- * platform. It detects the platform endianness and assigns the function pointers accordingly.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_CONFIGURATION_ERROR if the configuration passed in is invalid.
- * @param ptsConfiguration: tsCANTS_CONFIGURATION*: The initial configuration of the CAN-TS object.
- * The value of this configuration is copied into this object, meaning modifying the contents of this
- * object has no impact after initialisation, though most values can be modified via function calls.
- * Ensure all callbacks are given a valid value and not left undefined.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_Initialise(tsCANTS_CONFIGURATION* ptsConfiguration)
- {
- // Ensure that we have a valid Send Frame function
- EH_ASSERT(ptsConfiguration->funcSendFrame != 0U, CANTS_CONFIGURATION_ERROR, "The Send Frame callback cannot be 0");
- // Copy the full configuration from the parameter value into this object's own copy
- for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_CONFIGURATION); ++iByteIndex)
- {
- // Copy the byte at each memory location from the parameter config to the local config
- ((tUINT8*)(&tsCANTS_Configuration))[iByteIndex] = ((tUINT8*)ptsConfiguration)[iByteIndex];
- }
- /* Determine the platform endianness - We do this because parts of CAN-TS Protocol rely on data being Little Endian vvv */
- // A number to check the order of in memory to determine endianness
- tUINT32 iCoolNumber = 0x11223344;
- /* The bytes for the specific endians */
- tUINT8 acLittleEndianByteOrder[4] = { 0x44, 0x33, 0x22, 0x11 };
- tUINT8 acBigEndianByteOrder[4] = { 0x11, 0x22, 0x33, 0x44 };
- // Check for little endian
- if (
- (((tUINT8*)&iCoolNumber)[0] == acLittleEndianByteOrder[0]) &&
- (((tUINT8*)&iCoolNumber)[1] == acLittleEndianByteOrder[1]) &&
- (((tUINT8*)&iCoolNumber)[2] == acLittleEndianByteOrder[2]) &&
- (((tUINT8*)&iCoolNumber)[3] == acLittleEndianByteOrder[3])
- ) {
- /* The platform is Little Endian vvv */
- funcCANTS_NativeEndiannessToLittleEndian = CANTS_DoNotFlipEndianness;
- funcCANTS_LittleEndianToNativeEndianness = CANTS_DoNotFlipEndianness;
- }
- // Check for big endian
- else if (
- (((tUINT8*)&iCoolNumber)[0] == acBigEndianByteOrder[0]) &&
- (((tUINT8*)&iCoolNumber)[1] == acBigEndianByteOrder[1]) &&
- (((tUINT8*)&iCoolNumber)[2] == acBigEndianByteOrder[2]) &&
- (((tUINT8*)&iCoolNumber)[3] == acBigEndianByteOrder[3])
- ) {
- /* The platform is Big Endian vvv */
- funcCANTS_NativeEndiannessToLittleEndian = CANTS_FlipEndianness;
- funcCANTS_LittleEndianToNativeEndianness = CANTS_FlipEndianness;
- }
- else
- {
- // The endianness of the platform is not supported
- EH_ASSERT(FALSE, CANTS_UNSUPPORTED_PLATFORM, "Cannot determine the endianness of the platfom - CAN-TS not initialised");
- }
- return BT_SUCCESS;
- CANTS_CONFIGURATION_ERROR:
- CANTS_UNSUPPORTED_PLATFORM:
- return BT_FAIL;
- }
- /**
- * This is called by the user of this interface to handle any frames received on the CAN Bus. This
- * function call will route the frame according to its type, and will subsequently invoke the
- * callbacks set by the user if necessary.
- * You must not any transaction handling functions while this function is executing, such as
- * CANTS_SetBlock(...) or CANTS_GetBlock(...).
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_FRAME if the frame contains invalid data.
- * @throws CANTS_HANDLING_ERROR if there was an error handling the frame.
- * @throws CANTS_TRANSLATE_ERROR if there was an error translating the frame from a generic frame
- * to a specific CAN-TS frame.
- * @param ptsFrame: tsCANTS_FRAME_GENERIC*: A pointer to the CAN-TS frame to handle.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_HandleFrame(tsCANTS_FRAME_GENERIC* ptsFrame)
- {
- // The return value to function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // Get the frame type as an enumeration value
- teCANTS_FRAME_TYPE teFrameType = (teCANTS_FRAME_TYPE)(ptsFrame->tsIdentifiers.iFrameType);
- // Handle the specific frame type
- // Each of these cases will determine the specific subtype of the frame, then translate and call the respective handling function for that type of frame
- switch (teFrameType)
- {
- case CANTS_FRAME_TYPE_TELECOMMAND:
- {
- // Get the frame subtype
- // The subtype for a telecommand is kept in the first 2 bits of the Command field
- teCANTS_FRAME_SUBTYPE teFrameSubtype = (teCANTS_FRAME_SUBTYPE)((ptsFrame->tsIdentifiers.iCommand & 0x300U) >> 8U);
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST:
- {
- // The Telecommand Request frame to format
- tsCANTS_FRAME_TELECOMMAND_REQUEST tsTelecommandRequest = { 0U };
- // Translate the generic frame to a Telecommand Request frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TELECOMMAND, CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST, (void*)(&tsTelecommandRequest));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Generic Frame to a Telecommand Request frame");
- // Handle the Telecommand Request
- teFuncStatus = CANTS_HandleIncomingTelecommandRequest(&tsTelecommandRequest);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Telecommand Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT:
- {
- // The Telecommand Acknowledgement frame to format
- tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT tsTelecommandAcknowledgement = { 0U };
- // Translate the generic frame to the Telecommand Acknowledgement frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TELECOMMAND, CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT, (void*)(&tsTelecommandAcknowledgement));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Telecommand Acknowledgement frame");
- // Handle the Telecommand Acknowledgement
- teFuncStatus = CANTS_HandleIncomingTelecommandAcknowledgement(&tsTelecommandAcknowledgement);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Telecommand Acknowledgement");
- break;
- }
- default:
- // The frame subtype is invalid and cannot be handled
- EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid Telecommand subtype was provided");
- break;
- }
- break;
- }
- case CANTS_FRAME_TYPE_TELEMETRY_REQUEST:
- {
- // Get the Telemetry Request subtype
- // The subtype is specified as the first two bits of the Command field
- teCANTS_FRAME_SUBTYPE teFrameSubtype = (teCANTS_FRAME_SUBTYPE)((ptsFrame->tsIdentifiers.iCommand & 0x300U) >> 8U);
- // Handle the specific Telemetry frame subtype
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST:
- {
- // The Telemetry Request frame to format
- tsCANTS_FRAME_TELEMETRY_REQUEST tsTelemetryRequest = { 0U };
- // Translate the generic frame to the Telemetry Request frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TELEMETRY_REQUEST, CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST, (void*)(&tsTelemetryRequest));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Telemetry Request frame");
- // Handle the Telemetry Request
- teFuncStatus = CANTS_HandleIncomingTelemetryRequest(&tsTelemetryRequest);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Telemetry Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_TELEMETRY_NEGATIVE_ACKNOWLEDGEMENT:
- {
- // The Telemetry Acknowledgement frame to format
- tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT tsTelemetryAcknowledgement = { 0U };
- // Translate the generic frame to the Telemetry Acknowledgement frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TELEMETRY_REQUEST, CANTS_FRAME_SUBTYPE_TELEMETRY_GENERIC_ACKNOWLEDGEMENT, (void*)(&tsTelemetryAcknowledgement));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Telemetry Acknoledgement frame");
- // Handle the Telemetry Acknowledgement
- teFuncStatus = CANTS_HandleIncomingTelemetryAcknowledgement(&tsTelemetryAcknowledgement);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Telemetry Acknowledgement");
- break;
- }
- default:
- // The frame subtype is invalid and cannot be handled
- EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid Telemetry subtype was provided");
- break;
- }
- }
- case CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY:
- {
- // Ensure the subtype is assigned correctly
- // The CAN-TS Protocol specifies that this must be set to 0, but it has no real meaning
- EH_ASSERT(
- ((ptsFrame->tsIdentifiers.iCommand & 0x300U) >> 8) == CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY,
- CANTS_INVALID_FRAME,
- "The subtype for Unsolicited Telemetry is incorrect"
- );
- // The Unsolicited Telemetry frame to format
- tsCANTS_FRAME_UNSOLICITED_TELEMETRY tsUnsolicitedTelemetry = { 0U };
- // Translate the generic frame to an unsolicited telemetry frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY, CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY, (void*)(&tsUnsolicitedTelemetry));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to an Unsolicited Telemetry frame");
- // Handle the Unsolicited Telemetry
- teFuncStatus = CANTS_HandleIncomingUnsolicitedTelemetry(&tsUnsolicitedTelemetry);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Unsolicited Telemetry");
- break;
- }
- case CANTS_FRAME_TYPE_TIME_SYNCHRONISATION:
- {
- // The Time Synchronisation frame to format
- tsCANTS_FRAME_TIME_SYNCHRONISATION tsTimeSynchronisation = { 0U };
- // Ensure it has the To Address of 0
- EH_ASSERT(
- ptsFrame->tsIdentifiers.iToAddress == 0U,
- CANTS_INVALID_FRAME,
- "A Time Synchronisation frame had a non-zero To Address"
- );
- /* We don't check the subtype - It's left undefined by the CAN-TS Protocol */
- // Translate the generic frame to a time synchronisation frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TIME_SYNCHRONISATION, CANTS_FRAME_SUBTYPE_TIME_SYNCHRONISATION, (void*)(&tsTimeSynchronisation));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Time Synchronisation frame");
- // Handle the Time Synchronisation
- teFuncStatus = CANTS_HandleIncomingTimeSynchronisation(&tsTimeSynchronisation);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle a Time Synchronisation");
- break;
- }
- case CANTS_FRAME_TYPE_SET_BLOCK:
- {
- // Get the enumeration value for the frame subtype
- teCANTS_FRAME_SUBTYPE teFrameSubtype = (teCANTS_FRAME_SUBTYPE)((ptsFrame->tsIdentifiers.iCommand & 0x700U) >> 8U);
- // Switch for the specific subtype of Set Block frame
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST:
- {
- // The Set Block Request frame to format
- tsCANTS_FRAME_SET_BLOCK_REQUEST tsSetBlockRequest = { 0U };
- // Tranlate from the generic frame to the set block request frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST, (void*)(&tsSetBlockRequest));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Request frame");
- // Handle the Set Block Request
- teFuncStatus = CANTS_HandleIncomingSetBlockRequest(&tsSetBlockRequest);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle a Set Block Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
- {
- // The Set Block Acknowledgement frame to format
- tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT tsSetBlockAcknowledgement = { 0U };
- // Translate from the generic frame to the set block acknowledgement frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_GENERIC_ACKNOWLEDGEMENT, (void*)(&tsSetBlockAcknowledgement));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Acknowledgement frame");
- // Handle the Set Block Acknowledgement
- teFuncStatus = CANTS_HandleIncomingSetBlockAcknowledgement(&tsSetBlockAcknowledgement);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle a Set Block Acknowledgement");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER:
- {
- // The Set Block Transfer frame to format
- tsCANTS_FRAME_SET_BLOCK_TRANSFER tsSetBlockTransfer = { 0U };
- // Translate from the generic frame to the set block transfer frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER, (void*)(&tsSetBlockTransfer));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Transfer frame");
- // Handle the Set Block Transfer
- teFuncStatus = CANTS_HandleIncomingSetBlockTransfer(&tsSetBlockTransfer);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle a Set Block Transfer");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST:
- {
- // The Set Block Status Request frame to format
- tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST tsSetBlockStatusRequest = { 0U };
- // Translate from the generic frame to the set block status request frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST, (void*)(&tsSetBlockStatusRequest));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Status Request frame");
- // Handle the Set Block Status Request
- teFuncStatus = CANTS_HandleIncomingSetBlockStatusRequest(&tsSetBlockStatusRequest);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Set Block Status Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT:
- {
- // The Set Block Status Report frame to format
- tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT tsSetBlockStatusReport = { 0U };
- // Translate from the generic frame to the set block status report frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT, (void*)(&tsSetBlockStatusReport));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Status Report frame");
- // Handle the Set Block Status Report
- teFuncStatus = CANTS_HandleIncomingSetBlockStatusReport(&tsSetBlockStatusReport);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Set Block Status Report");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT:
- {
- // The Set Block Abort frame to format
- tsCANTS_FRAME_SET_BLOCK_ABORT tsSetBlockAbort = { 0U };
- // Translate from the generic frame to the set block abort frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT, (void*)(&tsSetBlockAbort));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Abort frame");
- // Handle the Set Block Abort
- teFuncStatus = CANTS_HandleIncomingSetBlockAbort(&tsSetBlockAbort);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Set Block Abort");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid Set Block subtype was provided");
- break;
- }
- break;
- }
- case CANTS_FRAME_TYPE_GET_BLOCK:
- {
- // The enumeration value of the frame subtype
- teCANTS_FRAME_SUBTYPE teFrameSubtype = (teCANTS_FRAME_SUBTYPE)((ptsFrame->tsIdentifiers.iCommand & 0x700U) > 8U);
- // Switch for the specific frame type of the Get Block frame
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST:
- {
- // The Get Block Request frame to format
- tsCANTS_FRAME_GET_BLOCK_REQUEST tsGetBlockRequest = { 0U };
- // Translate the Generic Frame to the Get Block Request frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST, (void*)(&tsGetBlockRequest));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block request frame");
- // Handle the Get Block Request
- teFuncStatus = CANTS_HandleIncomingGetBlockRequest(&tsGetBlockRequest);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
- {
- // The Get Block Acknowledgement frame to format
- tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT tsGetBlockAcknowledgement = { 0U };
- // Translate the Generic Frame to the Get Block Acknowledgement frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_GENERIC_ACKNOWLEDGEMENT, (void*)(&tsGetBlockAcknowledgement));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block Acknowledgement frame");
- // Handle the Get Block Acknowledgement
- teFuncStatus = CANTS_HandleIncomingGetBlockAcknowledgement(&tsGetBlockAcknowledgement);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Acknowledgement");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_START:
- {
- // The Get Block Start frame to format
- tsCANTS_FRAME_GET_BLOCK_START tsGetBlockStart = { 0U };
- // Translate the Generic Frame to the Get Block Start frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_START, (void*)(&tsGetBlockStart));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block Start frame");
- // Handle the Get Block Start
- teFuncStatus = CANTS_HandleIncomingGetBlockStart(&tsGetBlockStart);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Start");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER:
- {
- // The Get Block Transfer frame to format
- tsCANTS_FRAME_GET_BLOCK_TRANSFER tsGetBlockTransfer = { 0U };
- // Translate the Generic Frame to the Get Block Transfer frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER, (void*)(&tsGetBlockTransfer));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block Transfer frame");
- // Handle the Get Block Transfer
- teFuncStatus = CANTS_HandleIncomingGetBlockTransfer(&tsGetBlockTransfer);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Transfer");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT:
- {
- // The Get Block Abort frame to format
- tsCANTS_FRAME_GET_BLOCK_ABORT tsGetBlockAbort = { 0U };
- // Translate from the Generic Frame to the Get Block Abort frame
- teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT, (void*)(&tsGetBlockAbort));
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block Abort frame");
- // Handle the Get Block Abort
- teFuncStatus = CANTS_HandleIncomingGetBlockAbort(&tsGetBlockAbort);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Abort");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid Get Block subtype was provided");
- break;
- }
- break;
- }
- default:
- // The type of frame is invalid and cannot be handled
- EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid frame type was provided");
- break;
- }
- return BT_SUCCESS;
- CANTS_INVALID_FRAME:
- CANTS_HANDLING_ERROR:
- CANTS_TRANSLATE_ERROR:
- return BT_FAIL;
- }
- /**
- * Sends a telecommand with arguments on a specific telecommand channel. The telecommand channel is
- * the telecommand being sent. The recipient of the telecommand request is expected to respond with
- * either a Positive Acknowledgement or a Negative Acknowledgement.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_TRANSLATE_ERROR if the frame couldn't be translated to a generic frame.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param iToAddress: tUINT8: The destination address of the telecommand
- * @param iChannel: tUINT8: The telecommand channel
- * @param acData[8]: tUINT8: The telecommand arguments
- * @param iDataLength: tUINT8: The length of the telecommand arguments
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_SendTelecommand(tUINT8 iToAddress, tUINT8 iChannel, tUINT8 acData[8], tUINT8 iDataLength)
- {
- // Ensure that the data length is not above 8
- EH_ASSERT(iDataLength <= 8U, CANTS_INVALID_PARAMETER, "The provided data length is invalid");
- // The return value to function call
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- /* Construct the Telecommand frame from the parameters vvv */
- tsCANTS_FRAME_TELECOMMAND_REQUEST tsTelecommandRequest = { 0U };
- // Set the fields
- tsTelecommandRequest.iToAddress = iToAddress;
- tsTelecommandRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsTelecommandRequest.iChannel = iChannel;
- tsTelecommandRequest.iDataLength = iDataLength;
- // Copy the telecommand argument bytes into the Telecommand Request frame
- for (tUINT32 iByteIndex = 0U; iByteIndex < iDataLength; ++iByteIndex)
- {
- // Assign the byte
- tsTelecommandRequest.acData[iByteIndex] = acData[iByteIndex];
- }
- // The generic version of the Telecommand frame to send
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the Telecommand Request frame to a Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)(&tsTelecommandRequest), CANTS_FRAME_TYPE_TELECOMMAND, CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telecommand Request frame into a Generic frame");
- // Send the frame over the CAN Bus
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Telecommand Request frame");
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * Sends an acknowledgement to a telecommand request.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_TRANSLATE_ERROR if the frame could not be translated to a generic frame.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param iChannel: tUINT8: The telecommand channel to send the acknowledgement on
- * @param iToAddress: tUINT8: The destination node to send the acknowledgement to
- * @param teAcknowledgement: teCANTS_ACKNOWLEDGEMENT: Either a positive or negative acknowledgement
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_SendTelecommandAcknowledgement(tUINT8 iChannel, tUINT8 iToAddress, teCANTS_ACKNOWLEDGEMENT teAcknowledgement)
- {
- // The return value of function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // The Telecommand Acknowledgement frame to construct
- tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT tsTelecommandAcknowledgement = { 0U };
- /* Assign the fields in the Telecommand Acknowledgement frame vvv */
- tsTelecommandAcknowledgement.iChannel = iChannel;
- tsTelecommandAcknowledgement.iToAddress = iToAddress;
- tsTelecommandAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsTelecommandAcknowledgement.teAcknowledgement = teAcknowledgement;
- // The generic version of the Telecommand Acknowledgement frame
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate from the Telecommand Acknowledgement frame to the Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTelecommandAcknowledgement, CANTS_FRAME_TYPE_TELECOMMAND, CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telecommand Acknowledgement frame to a Generic frame");
- // Send the frame over the CAN bus
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Telecommand Acknowledgement");
- return BT_SUCCESS;
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * Sends a telemetry request to a specific address with telemetry channel. The telemetry channel is
- * the telemetry point being requested. The recipient of the telemetry request is expected to respond
- * with either a Positive Acknowledgement or a Negative Acknowledgement, where the Positive
- * Acknowledgement will contain the telemetry point data.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_TRANSLATE_ERROR if the frame couldn't be translated to a generic frame.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param iChannel: tUINT8: The destination address of the telemetry request
- * @param iToAddress: tUINT8: The telemetry channel
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_SendTelemetryRequest(tUINT8 iChannel, tUINT8 iToAddress)
- {
- // The return value for function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // Construct the Telemetry request frame
- tsCANTS_FRAME_TELEMETRY_REQUEST tsTelemetryRequest = { 0U };
- /* Assign the fields within the Telemetry Request vvv */
- tsTelemetryRequest.iToAddress = iToAddress;
- tsTelemetryRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsTelemetryRequest.iChannel = iChannel;
- // The generic version of the Telemetry request frame to send
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the Telemetry Request frame to a Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTelemetryRequest, CANTS_FRAME_TYPE_TELEMETRY_REQUEST, CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telemetry Request frame into a Generic frame");
- // Send the frame over the CAN Bus
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Telemetry Request frame");
- return BT_SUCCESS;
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * This sends a Telemetry Acknowledgement in response to a Telemetry Request. If the acknowledgement
- * type is Negative, no telemetry data is sent. The data region within a Positive Acknowledgement is
- * interpreted as the telemetry point data.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_TRANSLATE_ERROR if the frame failed to translate to a generic frame.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param iChannel: tUINT8: The telemetry channel to send the acknowledgement on
- * @param iToAddress: tUINT8: The destination address to receive the acknowledgement
- * @param acData[8]: tUINT8: The telemetry point data. If a Negative Acknowledgement is sent, this
- * data goes unused. This data is the data for the requested telemetry point.
- * @param iDataLength: tUINT8: The length of the telemetry data
- * @param teAcknowledgement: teCANTS_ACKNOWLEDGEMENT: The telemetry request acknowledgement.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_SendTelemetryAcknowledgement(tUINT8 iChannel, tUINT8 iToAddress, tUINT8 acData[8], tUINT8 iDataLength, teCANTS_ACKNOWLEDGEMENT teAcknowledgement)
- {
- // Ensure the data length does not exceed 8
- EH_ASSERT(iDataLength <= 8, CANTS_INVALID_PARAMETER, "The provided data length for a Telemetry Acknowledgement exceeds 8");
- // The return value of function call
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // The Telemetry Acknowledgement frame to populate
- tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT tsTelemetryAcknowledgement = { 0U };
- /* Assign the values within the Telemetry Acknowledgement frame vvv */
- tsTelemetryAcknowledgement.iToAddress = iToAddress;
- tsTelemetryAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsTelemetryAcknowledgement.iChannel = iChannel;
- tsTelemetryAcknowledgement.teAcknowledgement = teAcknowledgement;
- tsTelemetryAcknowledgement.iDataLength = iDataLength;
- // Copy the telemetry bytes into the acknowledgement frame
- for (tUINT32 iByteIndex = 0U; iByteIndex < iDataLength; ++iByteIndex)
- {
- // Copy the byte
- tsTelemetryAcknowledgement.acData[iByteIndex] = acData[iByteIndex];
- }
- // The generic version of the Telemetry Acknowledgement frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // The Telemetry Acknowledgement subtype
- teCANTS_FRAME_SUBTYPE teFrameSubtype = 0U;
- // Assign the specific Telemetry Acknowledgement frame subtype to pass into the translate function
- switch (teAcknowledgement)
- {
- case CANTS_POSITIVE_ACKNOWLEDGEMENT:
- teFrameSubtype = CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT;
- break;
- case CANTS_NEGATIVE_ACKNOWLEDGEMENT:
- teFrameSubtype = CANTS_FRAME_SUBTYPE_TELEMETRY_NEGATIVE_ACKNOWLEDGEMENT;
- break;
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An unknown acknowledgement type was provided when sending a Telemetry Acknowledgement");
- break;
- }
- // Translate the Telemetry Acknowledgement frame to a Generic frame to be sent
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTelemetryAcknowledgement, CANTS_FRAME_TYPE_TELEMETRY_REQUEST, teFrameSubtype, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telemetry Acknowledgement frame to a Generic frame");
- // Send the frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send a Telemetry Acknowledgement frame");
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * This sends unsolicited telemetry to a destination address. The Channel represents the telemetry
- * point which the data region is associated with. The recipient should not return an acknowledgement
- * frame.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_TRANSLATE_ERROR if the frame could not be translated to a generic frame.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param iChannel: tUINT8: The telemetry channel. This represents the specific telemetry point.
- * @param iToAddress: tUINT8: The recipient of the telemetry.
- * @param acData[8]: tUINT8: The telemetry point data.
- * @param iDataLength: tUINT8: The length of the telemtry point data.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_SendUnsolicitedTelemetry(tUINT8 iChannel, tUINT8 iToAddress, tUINT8 acData[8], tUINT8 iDataLength)
- {
- // Ensure that the data length is not above 8
- EH_ASSERT(iDataLength <= 8, CANTS_INVALID_PARAMETER, "The provided data length cannot be above 8");
- // The return value from function call
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // The Unsolicited Telemetry frame to populate
- tsCANTS_FRAME_UNSOLICITED_TELEMETRY tsUnsolicitedTelemetry = { 0U };
- /* Assign the fields within the Unsolicited Telemetry frame vvv */
- tsUnsolicitedTelemetry.iToAddress = iToAddress;
- tsUnsolicitedTelemetry.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsUnsolicitedTelemetry.iChannel = iChannel;
- tsUnsolicitedTelemetry.iDataLength = iDataLength;
- // Copy the data into the Unsolicited Telemetry frame
- for (tUINT32 iByteIndex = 0U; iByteIndex < iDataLength; ++iByteIndex)
- {
- // Assign the byte
- tsUnsolicitedTelemetry.acData[iByteIndex] = acData[iByteIndex];
- }
- // The generic frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the Unsolicited Telemetry frame into a Generic frame to send over the CAN Bus
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsUnsolicitedTelemetry, CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY, CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate an Unsolicited Telemetry frame into a Generic frame");
- // Send the frame over the CAN Bus
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Unsolicited Telemetry frame");
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * This sends a time synchronisation which is received by all other nodes. This is transmitted to
- * address 0.
- * The units which the time is represented as is mission defined, therefore it could be milliseconds,
- * seconds, absolute time, relative time, etc.
- * This value is transmitted on the CAN Bus as little endian. You must provide the time in the native
- * endianness of the platform the code is executing on and this function will flip it if necessary.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL
- * @throws CANTS_TRANSLATE_ERROR if the frame failed to translate.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param iTime: tUINT64: The time point of the time synchronisation. The units of this value is
- * mission defined.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_SendTimeSynchronisation(tUINT64 iTime)
- {
- // This is the return value of function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // The Time Synchronisation frame to populate with data
- tsCANTS_FRAME_TIME_SYNCHRONISATION tsTimeSynchronisation = { 0U };
- /* Assign the frame fields vvv */
- tsTimeSynchronisation.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsTimeSynchronisation.iTime = iTime;
- // The generic frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the Time Synchronisation frame to the Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTimeSynchronisation, CANTS_FRAME_TYPE_TIME_SYNCHRONISATION, CANTS_FRAME_SUBTYPE_TIME_SYNCHRONISATION, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate the Time Synchronisation frame to a Generic frame");
- // Send the frame over CAN Bus
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Time Synchronisation frame");
- return BT_SUCCESS;
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * Sets a series of blocks on a receiving node from a buffer of memory. You provide a transaction
- * struct to specify the data, start address, etc., and continuously call this function until the
- * reported status is either Success or Failure (the status within the transaction struct, not the
- * return value).
- * After the transaction has complete, either successfully or unsuccessfully, you must call
- * CANTS_EndSetBlockTransaction(...) to Abort the transaction. You can also Abort the transaction at
- * any other time during the transfer.
- * While this function has some rudimentary thread safety for sanity sake, this function is not fully
- * thread safe and you must not call this function while another Set Block transaction is ongoing.
- * All Set Block associated callbacks are disabled while this function is handing the transaction so
- * that this process is fully automatic, and the transfer state isn't accidentally altered via
- * external handling of the frames.
- * You must not call CANTS_HandleFrame(...) while this function is executing - use something like a
- * Mutex Take prior to calling each function, then releasing the mutex after the call has complete.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided
- * @param ptsTransaction: tsCANTS_SET_BLOCK_OUTGOING_TRANSACTION*: A pointer to the ongoing
- * transaction. Refer to the structure description to know what to set this to in order to instantiate
- * a transaction.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_SetBlock(tsCANTS_SET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // Specify that there is an ongoing transfer
- // This is checked prior to any Set Block callbacks being invoked, if this value is TRUE, the callback will not be invoked
- bCANTS_SetBlockBusy = TRUE;
- // This is used as a flag to determine if the Set Block request has been sent yet
- static tBOOL bHasSentRequest = FALSE;
- // This is a bit field to store which blocks have not been sent within a transfer
- static tUINT64 iBlocksRemaining = 0U;
- // Switch for the transaction state
- switch (ptsTransaction->teStatus)
- {
- case CANTS_SET_BLOCK_STATUS_PENDING:
- {
- // If we have sent a request and are waiting for the response
- if (bHasSentRequest == TRUE)
- {
- // If there is at least one pending Set Block Acknowledgement frame
- if (iCANTS_SetBlockPendingAcknowledgements > 0U)
- {
- // Get a pointer to the first acknowledgement frame
- // There should never be more than one pending acknowledgement frame, therefore we assume the first one received is the one we're interested in
- tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknowledgement = &(atsCANTS_SetBlockPendingAcknowledgements[0U]);
- // Switch for the specific type of acknowledgement
- switch (ptsSetBlockAcknowledgement->teAcknowledgement)
- {
- case CANTS_POSITIVE_ACKNOWLEDGEMENT:
- /* Set the initial transaction state ready for the ONGOING state to use vvv */
- ptsTransaction->iBytesRemaining = ptsTransaction->iDataLength;
- ptsTransaction->iBytesSent = 0;
- // This will get the number of blocks which needs to be sent, rounded up to the closest 8 bytes
- tUINT32 iNumberOfBlocks = (tUINT32)((ptsTransaction->iDataLength + 7U) / 8U);
- // Limit the number of blocks to 64 - It's possible for it to round up to 65
- if (iNumberOfBlocks > 64U)
- {
- iNumberOfBlocks = 64U;
- }
- // Set all of the bits within the bit field to specify which blocks are remaining
- for (tUINT32 iBitIndex = 0U; iBitIndex < iNumberOfBlocks; ++iBitIndex)
- {
- // Shift the bit index to the very left-most bit within the bit field
- iBlocksRemaining |= (tUINT64)(1U << (63U - iBitIndex));
- }
- // Go into the ongoing transaction state
- ptsTransaction->teAddressSize = CANTS_SET_BLOCK_STATUS_ONGOING;
- break;
- case CANTS_NEGATIVE_ACKNOWLEDGEMENT:
- // Go to the failure state
- ptsTransaction->teAddressSize = CANTS_SET_BLOCK_STATUS_FAILURE;
- break;
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Acknowledgement value was provided");
- break;
- }
- }
- }
- // Else we haven't sent the request yet and need to
- else
- {
- // The request frame to populate
- tsCANTS_FRAME_SET_BLOCK_REQUEST tsSetBlockRequest = { 0U };
- // The number of blocks which will be sent
- // This formula ensures the integer division is always rounded upwards to the closest block size
- // blocks = (bytes + (blockSize - 1)) / blockSize
- // Therefore the magical '7' and '8' are respectively the block size minus one and the block size
- tUINT32 iNumberOfBlocks = (tUINT32)((ptsTransaction->iDataLength + 7U) / 8U);
- // The Start Address on the receiving end as Little Endian
- tUINT64 iAddressLittleEndian = ptsTransaction->iStartAddress;
- teFuncStatus = funcCANTS_NativeEndiannessToLittleEndian(&iAddressLittleEndian);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to get Address as Little Endian");
- // The minimal number of bytes which the address can fit within
- tUINT32 iAddressBytesSize = 0U;
- tUINT64 iAddressValueToShift = iAddressLittleEndian;
- // While all the bits have not yet been shifted out
- do
- {
- // Increment the required minimum number of bytes
- ++iAddressBytesSize;
- // Shift the address right by a byte
- iAddressValueToShift >>= 8U;
- }
- while (iAddressValueToShift > 0U);
- /* Assign the fields within the Set Block Request frame vvv */
- tsSetBlockRequest.iToAddress = ptsTransaction->iToAddress;
- tsSetBlockRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- // The CANTS Protocol specifies this number is represented as the number of blocks minus one
- // E.g., when sending 1 block, this value is 0
- tsSetBlockRequest.iNumberOfBlocks = iNumberOfBlocks - 1U;
- tsSetBlockRequest.iStartAddress = ptsTransaction->iStartAddress;
- tsSetBlockRequest.teAddressSize = (teCANTS_ADDRESS_SIZE)iAddressBytesSize;
- // The Generic version of the Set Block Request to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the Set Block Request frame to a Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsSetBlockRequest, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Request frame to a Generic frame");
- // Set the queues to be empty before starting the transaction
- iCANTS_SetBlockPendingAcknowledgements = 0U;
- iCANTS_SetBlockPendingStatusReports = 0U;
- // Send the Generic frame over the CAN Bus
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Request frame");
- // Specify that we have sent the Set Block request
- bHasSentRequest = TRUE;
- }
- break;
- }
- case CANTS_SET_BLOCK_STATUS_ONGOING:
- {
- // If there are blocks remaining to be sent
- if (iBlocksRemaining != 0U)
- {
- /* Get the 1 to 8 byte chunk of data to send in the block vvv */
- // The index of the block to sent
- // E.g., if this is 0, that corresponds with the left-most bit and the first block is due to be sent
- tUINT32 iBlockIndex = 0U;
- // Get the block index next due to be sent
- // This for loop is guaranteed to terminate because we've already checked the Blocks Remaining bit field is non-zero
- for (
- iBlockIndex = 0U;
- ((0x8000000000000000U >> iBlockIndex) & iBlocksRemaining) == 0U;
- ++iBlockIndex
- );
- // Get the starting index of the block within the data array
- tUINT32 iStartIndex = iBlockIndex * 8U;
- // The number of bytes within the block is 8, unless it's the very last block and is not aligned to 8 bytes
- tUINT32 iBlockSize = 8U;
- // If the block size extends past the end of the array
- if ((iStartIndex + iBlockSize) > ptsTransaction->iDataLength)
- {
- // Set the block size to the number of remaining bytes, which will be from 1 to 7 bytes
- iBlockSize = ptsTransaction->iDataLength - iStartIndex;
- }
- // The block to transfer containing the segment of bytes from the
- tsCANTS_FRAME_SET_BLOCK_TRANSFER tsTransferBlock = { 0U };
- /* Assign the fields within the transfer block vvv */
- tsTransferBlock.iToAddress = ptsTransaction->iToAddress;
- tsTransferBlock.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsTransferBlock.iSequence = iBlockIndex;
- tsTransferBlock.iDataLength = iBlockSize;
- // Copy the data from the buffer into the transfer block to be sent
- for (tUINT32 iByteIndex = 0U; iByteIndex < iBlockSize; ++iByteIndex)
- {
- // Assign the byte
- // The start index offsets into the buffer to get the correct block
- tsTransferBlock.acData[iByteIndex] = ptsTransaction->pcData[iStartIndex + iByteIndex];
- }
- // The generic version of the transfer block to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate into the generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTransferBlock, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Transfer frame into a Generic frame");
- // Send the frame over the CAN Bus
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Transfer frame");
- // If all was successful, clear the bit within the bit field to specify that we've sent it
- iBlocksRemaining &= ~((0x8000000000000000U) >> iBlockIndex);
- /* Update the number of bytes sent and remaining vvv */
- /* If a retransmission is required, this will executed too many times, giving invalid values, therefore we do a check before modifying them */
- // Update bytes sent
- if ((ptsTransaction->iBytesSent + iBlockSize) <= ptsTransaction->iDataLength)
- {
- ptsTransaction->iBytesSent += iBlockSize;
- }
- // Update bytes remaining
- if ((ptsTransaction->iBytesRemaining - iBlockSize) >= 0U)
- {
- ptsTransaction->iBytesRemaining -= iBlockSize;
- }
- }
- else
- {
- // The Set Block Status Request frame to populate
- tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST tsStatusRequest = { 0U };
- /* Assign the fields within the Status Request frame vvv */
- tsStatusRequest.iToAddress = ptsTransaction->iToAddress;
- tsStatusRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- // The generic version of the Status Request frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the Set Block Status Request frame into a Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsStatusRequest, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Status Request frame to a Generic frame");
- // Set there to initially have no status reports before sending the status request
- iCANTS_SetBlockPendingStatusReports = 0U;
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Status Request frame");
- // All blocks have been sent, so go to the verify state to ensure the destination node received them all
- ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_VERIFYING;
- }
- break;
- }
- case CANTS_SET_BLOCK_STATUS_VERIFYING:
- {
- // If there are status reports waiting to be read
- if (iCANTS_SetBlockPendingStatusReports > 0U)
- {
- // A bit field of all blocks received by the destination node
- tUINT64 iBlocksReceived = 0U;
- // Go through all of them and accumulate the bit field of blocks received
- // Under normal circumstances, there should only ever be 1 report, but doing this could prevent unnecessary retransmission
- for (tUINT32 iFrameIndex = 0U; iFrameIndex < iCANTS_SetBlockPendingStatusReports; ++iFrameIndex)
- {
- // Get a pointer to the status report
- tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsStatusReport = &(atsCANTS_SetBlockPendingStatusReports[iFrameIndex]);
- // If the destination node reports that all blocks have been received and handled
- if (ptsStatusReport->bComplete == TRUE)
- {
- // Signify the transaction has completed
- ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_SUCCESS;
- // Stop checking the status reports
- break;
- }
- // Set all of the bits from each frame
- iBlocksReceived |= ptsStatusReport->iBlocksReceived;
- }
- // The number of blocks expected to have been received
- // We round up to the nearest 8 byte chunk - the +7 ensures it's always rounded up when performing integer division
- tUINT32 iNumberOfExpectedBlocks = (tUINT32)((ptsTransaction->iDataLength + 7U) / 8U);
- // It's possible to round up to 65 therefore we cap it at 64
- if (iNumberOfExpectedBlocks > 64U)
- {
- // Cap the value at 64
- iNumberOfExpectedBlocks = 64U;
- }
- // A bit field of the blocks expected
- tUINT64 iExpectedBlocks = 0U;
- // Set all of the bits within the bit field to specify which blocks are expected
- for (tUINT32 iBitIndex = 0U; iBitIndex < iNumberOfExpectedBlocks; ++iBitIndex)
- {
- // Shift the bit index to the very left-most bit within the bit field
- iExpectedBlocks |= (tUINT64)(1U << (63U - iBitIndex));
- }
- // A bit field of any missing blocks
- tUINT64 iMissingBlocks = (iExpectedBlocks & iBlocksReceived);
- // If there are some blocks which haven't been received
- if (iMissingBlocks != 0U)
- {
- // Specify the blocks to retransmit
- iBlocksRemaining = iMissingBlocks;
- // Set the state to go back to transmitting blocks to send the remaining ones
- ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_ONGOING;
- }
- }
- // Signify we've handled all the frames
- // This isn't completely necessary but this will help ensure we don't get into a weird state if something were to go very wrong
- iCANTS_SetBlockPendingStatusReports = 0U;
- break;
- }
- case CANTS_SET_BLOCK_STATUS_SUCCESS: // Fall-through
- case CANTS_SET_BLOCK_STATUS_FAILURE:
- {
- // Restore the static state for the next transaction
- bHasSentRequest = FALSE;
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Transfer state was provided");
- break;
- }
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * You must call this function after a Set Block transfer has complete, regardless of whether the
- * transfer status was successful or not.
- * This will send the Abort frame to the destination node and re-enable the callbacks to the user for
- * incoming Set Block frames. This includes the Acknowledgement to the Abort frame, meaning once you
- * call this function, you should expect the callback for the Set Block Acknowledgement Frame to be
- * invoked (unless you don't have that callback registered).
- * This function can also be called during a transfer, say in the instance you want to timeout the
- * transfer or there has been some other error.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_TRANSLATE_ERROR if the frame could not be translated.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param ptsTransaction: tsCANTS_SET_BLOCK_OUTGOING_TRANSACTION*: The Set Block transaction to stop
- * terminate.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_EndSetBlockTransaction(tsCANTS_SET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // Store the status of the transaction so that we can set it back after resetting the CANTS_SetBlock(...) static state
- teCANTS_SET_BLOCK_STATUS teInitialStatus = ptsTransaction->teStatus;
- // Set the status to either SUCCESS or FAILURE
- ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_SUCCESS;
- // Call CANTS_SetBlock(...) with either the SUCCESS or FAILURE status so that it resets the static state internally
- // This is done in case the user calls this End Transaction function prior to a transaction naturally being terminated (e.g., timeout)
- teFuncStatus = CANTS_SetBlock(ptsTransaction);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_INVALID_PARAMETER, "An invalid transaction status was provided");
- // Restore the transaction status for consistency
- // This is so that the status doesn't seem to randomly change from the users perspective
- ptsTransaction->teStatus = teInitialStatus;
- // The Set Block Abort frame to conclude the transaction
- tsCANTS_FRAME_SET_BLOCK_ABORT tsSetBlockAbort = { 0U };
- /* Assign the fields within the Abort frame vvv */
- tsSetBlockAbort.iToAddress = ptsTransaction->iToAddress;
- tsSetBlockAbort.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- // The generic version of the abort frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the Set Block Abort frame to the Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsSetBlockAbort, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Abort frame to a Generic frame");
- // Specify that the transfer has complete
- // This is done before sending the Abort frame to return callback handing to the user
- bCANTS_SetBlockBusy = FALSE;
- // Send the abort frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Abort frame");
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * When you receive a Set Block request, this can be used to send a Positive Acknowledgement frame to
- * approve the transfer. To receive all of the blocks, you must use CANTS_ReceiveSetBlockTransfer(...).
- *
- * Calling this function to Accept the Set Block request will disable any Set Block receive callbacks
- * to ensure the transfer is handled fully automatically and without interference with anything else
- * handling Set Block frames.
- * If the buffer you provide is not large enough to store all of the blocks, this call will fail and a
- * Negative Acknowledgement will be sent.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_TRANSLATE_ERROR if there was an error translating a frame.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param ptsRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The request which you're accepting.
- * @param ptsTransaction: tsCANTS_SET_BLOCK_INCOMING_TRANSACTION*: A pointer to the transaction object
- * which will be used to transfer the Set Block data
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_AcceptSetBlockRequest(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsRequest, tsCANTS_SET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // Ensure the size of the receiving buffer is at least the minimum required number of bytes to write all of the blocks
- // We +1 to the number of blocks because the CANTS Protocol specifies that the Number Of Blocks value is the true number minus one
- // Multiplying by 8 refers to 8 bytes
- EH_ASSERT(((ptsRequest->iNumberOfBlocks + 1U) * 8U) <= ptsTransaction->iReceiveBufferSize, CANTS_INVALID_PARAMETER, "The receive buffer size is too small to accept a Set Block Request");
- // The Set Block Request Positive Acknowledgement frame
- tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT tsAcceptFrame = { 0U };
- /* Assign the fields within the Accept frame vvv */
- /* The command and data fields must match the request frame */
- tsAcceptFrame.teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
- tsAcceptFrame.iCommand = ptsRequest->iNumberOfBlocks;
- tsAcceptFrame.iToAddress = ptsRequest->iFromAddress;
- tsAcceptFrame.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsAcceptFrame.iDataLength = (tUINT32)ptsRequest->teAddressSize;
- // The start address of the Set Block request in little endian
- // This is used to write it back to the source node (just part of the CANTS Protocol)
- tUINT64 iAddressLittleEndian = ptsRequest->iStartAddress;
- // Convert the address to little endian
- teFuncStatus = funcCANTS_NativeEndiannessToLittleEndian(&iAddressLittleEndian);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate address of Set Block Request to little endian");
- // Copy the address bytes into the acknowledgement buffer
- for (tUINT32 iByteIndex = 0; iByteIndex < tsAcceptFrame.iDataLength; ++iByteIndex)
- {
- // Copy the byte
- tsAcceptFrame.acData[iByteIndex] = (((tUINT8*)(&iAddressLittleEndian))[iByteIndex]);
- }
- // The generic version of the positive acknowledgement frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the positive acknowledgement frame to a generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsAcceptFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Positive Acknowledgement to a Generic frame");
- /* Set the initial counters for received frames vvv */
- iCANTS_SetBlockPendingAborts = 0U;
- iCANTS_SetBlockPendingStatusRequests = 0U;
- iCANTS_SetBlockPendingTransfers = 0U;
- /* Set the initial transaction values */
- ptsTransaction->iBytesReceived = 0U;
- // This value is always aligned to 8 bytes despite the fact that <8 bytes can be transferred
- ptsTransaction->iBytesRemaining = (ptsRequest->iNumberOfBlocks + 1U) * 8U;
- // Specify that there is an ongoing Set Block transaction
- bCANTS_SetBlockBusy = TRUE;
- // Send the positive acknowledgement
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Positive Acknowledgement frame");
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- // Specify there are no ongoing Set Block transaction in the case of failure
- bCANTS_SetBlockBusy = FALSE;
- return BT_FAIL;
- }
- /**
- * This is to be sent after a Set Block request has been sent but cannot be fulfilled. If Set Block
- * requests aren't handled with a callback by the user, this function is automatically invoked.
- * @returns BT_SUCCESS if there was no excception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param ptsRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The Set Block Request to reject.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_RejectSetBlockRequest(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsRequest)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // The Negative Acknowledgement frame to send to the source node
- tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT tsRejectFrame = { 0U };
- /* Populate the fields within the Reject Frame vvv */
- tsRejectFrame.teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
- tsRejectFrame.iToAddress = ptsRequest->iFromAddress;
- tsRejectFrame.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- /* The data length and command fields go unused in a Negative Acknowledgement frame, but we assign them to value regardless */
- /* This is just in case the destination node can infer sensitive information from the undefined memory */
- tsRejectFrame.iCommand = 0U;
- tsRejectFrame.iDataLength = 0U;
- // The generic version of the negative acknowledgement frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the Negative Acknowledgement frame to the Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsRejectFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Negative Acknowledgement frame to a Generic frame");
- // Send the Negative Acknowledgement frame over the CAN Bus
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Negative Acknowledgement frame");
- return BT_SUCCESS;
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * This is used to receive blocks after a Set Block request has been Accepted via
- * CANTS_AcceptSetBlockRequest(...). This is to be continuously called until the transaction status is
- * either Successful or Failed.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @param ptsRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The request used to instantiate the
- * transaction.
- * @param ptsTransaction: tsCANTS_SET_BLOCK_INCOMING_TRANSACTION*: The current state of the
- * transaction.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_ReceiveSetBlockTransfer(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsRequest, tsCANTS_SET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // A bit field to indicate which blocks have and haven't been received
- static tUINT64 iBlocksReceived = 0U;
- // A bit field of the blocks expected to be received
- static tUINT64 iExpectedBlocks = 0U;
- // The number of bytes expected to be received within the ongoing transfer
- // This is stored statically just to reduce the number of times it needs to be calculated
- static tUINT32 iTotalExpectedBytes = 0U;
- // Switch to the specific transaction status
- switch (ptsTransaction->teStatus)
- {
- case CANTS_SET_BLOCK_STATUS_PENDING:
- {
- // Specify no blocks have been received yet
- iBlocksReceived = 0U;
- // Initially assign the expected blocks to 0 before setting any bits
- iExpectedBlocks = 0U;
- // Assign the bits within the bit field for the blocks expected to be received from the source node
- for (tUINT32 iBitIndex = 0U; iBitIndex < ptsRequest->iNumberOfBlocks; ++iBitIndex)
- {
- // Assign the bit
- iExpectedBlocks |= (0x8000000000000000U >> iBitIndex);
- }
- // Assign the number of expected bytes
- iTotalExpectedBytes = (ptsRequest->iNumberOfBlocks * 8U);
- // Go to the ongoing state
- ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_ONGOING;
- break;
- }
- case CANTS_SET_BLOCK_STATUS_ONGOING:
- {
- // Go though any pending transfer frames
- for (tUINT32 iFrameIndex = 0U; iFrameIndex < iCANTS_SetBlockPendingTransfers; ++iFrameIndex)
- {
- // Get a pointer to the transfer frame
- tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsTransfer = &(atsCANTS_SetBlockPendingTransfers[iFrameIndex]);
- // Get the starting index of the block
- tUINT32 iStartIndex = (8U * ptsTransfer->iSequence);
- // Ensure there is enough space within the receive buffer to write into
- // This check is already performed in CANTS_AcceptSetBlockRequest(...) but this is just an extra precaution
- EH_ASSERT((iStartIndex + ptsTransfer->iDataLength) <= ptsTransaction->iReceiveBufferSize, CANTS_INVALID_PARAMETER, "The receive buffer size is not large enough to write a transfer block to");
- // Copy the block from the transfer frame into the receive buffer
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsTransfer->iDataLength; ++iByteIndex)
- {
- // Copy the byte
- ptsTransaction->pcReceiveBuffer[iStartIndex + iByteIndex] = ptsTransfer->acData[iByteIndex];
- }
- /* Update the transaction status values vvv */
- /* We check the current values so that we do not overrun or underflow the values in the case that the source node retransmits even when we have a block */
- /* The Received and Remaining number of bytes are always aligned to 8 bytes despite being able to transfer less than 8 bytes at a time */
- // Update the bytes received value
- if ((ptsTransaction->iBytesReceived + 8U) <= iTotalExpectedBytes)
- {
- ptsTransaction->iBytesReceived += 8U;
- }
- // Update the bytes remaining value
- if (ptsTransaction->iBytesRemaining >= 8U)
- {
- ptsTransaction->iBytesRemaining -= 8U;
- }
- // Specify that we have received the respective block
- iBlocksReceived |= (0x8000000000000000U >> ptsTransfer->iSequence);
- }
- // Signify that we have handled all of the pending blocks
- iCANTS_SetBlockPendingTransfers = 0U;
- // If the source node has requested the transaction status
- if (iCANTS_SetBlockPendingStatusRequests > 0U)
- {
- // Go to the verifying state
- ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_VERIFYING;
- }
- // TODO: Check for abort frames here and if they exist then go into the verifying state?
- break;
- }
- case CANTS_SET_BLOCK_STATUS_VERIFYING:
- {
- // If there is at least 1 pending status request
- if (iCANTS_SetBlockPendingStatusRequests > 0U)
- {
- /* The Status Request frame doesn't actually include anything useful so there's no need to read it at this point */
- // Mute warning for unused value
- // TODO: Just remove this array all together?
- (void)atsCANTS_SetBlockPendingStatusRequests;
- // The status report to send to the Set Block source node
- tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT tsStatusReport = { 0U };
- /* Assign the fields within the Status Report frame vvv */
- tsStatusReport.iToAddress = ptsRequest->iFromAddress;
- tsStatusReport.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsStatusReport.bComplete = ptsTransaction->bComplete;
- tsStatusReport.iBlocksReceived = iBlocksReceived;
- // The generic version of the status report frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the status report to a generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsStatusReport, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Set Block Status Report to a Generic frame");
- // Send the status report frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Status Report frame");
- // Signify that we have handled the request(s)
- iCANTS_SetBlockPendingStatusRequests = 0U;
- }
- // If there are more transfer frames to handle
- if (iCANTS_SetBlockPendingTransfers > 0U)
- {
- // Change to the ongoing state
- ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_ONGOING;
- }
- // If there are any abort frames
- else if (iCANTS_SetBlockPendingAborts > 0U)
- {
- /* We acknowledge the abort frame regardless of whether the transaction has complete or not */
- // The positive acknowledgement to send to the source node
- tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT tsPositiveAcknowledgement = { 0U };
- /* We don't need to get the specific abort frame because they don't contain anything unique */
- /* Assign the fields within the acknowledgement frame vvv */
- /* The command and data length fields are unused but we define then to ensure we don't send random data in the memory */
- tsPositiveAcknowledgement.teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
- tsPositiveAcknowledgement.iToAddress = ptsRequest->iFromAddress;
- tsPositiveAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsPositiveAcknowledgement.iCommand = 0U;
- tsPositiveAcknowledgement.iDataLength = 0U;
- // The generic frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate from the Positive Acknowledgement frame to the Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsPositiveAcknowledgement, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Positive Acknowledgement frame to a Generic frame");
- // Send the Positive Acknowledgement frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Positive Acknowledgement frame");
- // If the transaction is confirmed to be completed by the user
- if (ptsTransaction->bComplete == TRUE)
- {
- // Set the state to SUCCESS
- ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_SUCCESS;
- }
- // Otherwise the source node is prematurely aborting, indicating a failed transfer
- else
- {
- // Set the state to FAILURE because the transaction aborted prior to the user calling CANTS_EndIncomingSetBlock(...)
- ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_FAILURE;
- }
- }
- else
- {
- /* Continue in the state we are currently in until the source node sends a frame */
- /* It is implementation defined to timeout if desired */
- (void)0;
- }
- break;
- }
- case CANTS_SET_BLOCK_STATUS_SUCCESS: // Fall-through
- case CANTS_SET_BLOCK_STATUS_FAILURE:
- {
- // Specify there is no longer an ongoing Set Block transaction
- bCANTS_SetBlockBusy = FALSE;
- break;
- }
- default:
- {
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Incoming Transaction status was provided");
- break;
- }
- }
- return BT_SUCCESS;
- CANTS_SEND_ERROR:
- CANTS_TRANSLATE_ERROR:
- CANTS_INVALID_PARAMETER:
- return BT_FAIL;
- }
- /**
- * This function is called once all blocks have been received and handled by the user. This must be
- * called exactly once after an incoming Set Block transaction has been handled via
- * CANTS_ReceiveSetBlockTransfer(...) and all bytes have been received and handled by the user (e.g.,
- * copying to memory elsewhere).
- * The CANTS Protocol does not support the ability for the receiving node of a Set Block to terminate
- * a transaction.
- * @returns BT_SUCCESS always
- * @param ptsTransaction: tsCANTS_SET_BLOCK_INCOMING_TRANSACTION*: A pointer to the transaction to end
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_EndIncomingSetBlock(tsCANTS_SET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
- {
- // Specify the received data has all been handled by the user
- ptsTransaction->bComplete = TRUE;
- // Specify there is no longer an ongoing Set Block transaction
- bCANTS_SetBlockBusy = FALSE;
- return BT_SUCCESS;
- }
- /** TODO: Add exceptions CANTS_TRANSLATE_ERROR and CANTS_SEND_ERROR to EA
- * Receives blocks from another node. You provide a transaction state then continuously call this
- * function until all blocks are received. It is up to your own implementation on how to handle
- * unreceived blocks, though you can use CANTS_RequestRemainingBlocks(...) to re-request remaining
- * blocks if you have determined the source node has not sent them all.
- * To end the transaction, you must call CANTS_EndGetBlockTransaction(...) regardless of whether all
- * blocks were received or not.
- * If the number of bytes you're attempting to receive cannot be contained within the buffer you
- * provide, the request will not be sent and the call will fail. Important to note, all Get Block
- * requests are aligned to 8 byte blocks, meaning your buffer must be able to contain the number of
- * bytes you want, rounded up to an 8 byte chunk, e.g., if you want to receive 9 bytes, you buffer
- * size must be at least 16 bytes in size.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @param ptsTransaction: tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION*:
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_GetBlock(tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
- {
- // The value returned from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // Ensure the receive buffer size is large enough for all bytes
- EH_ASSERT(ptsTransaction->iReceiveBufferSize >= ptsTransaction->iNumberOfBytes, CANTS_INVALID_PARAMETER, "The receive buffer size is less than the required minimum for a Get Block transaction");
- // Specify that there is an ongoing Get Block transaction
- bCANTS_GetBlockBusy = TRUE;
- // A flag to specify if the Get Block request has been sent
- static tBOOL bHasSentRequest = FALSE;
- // Switch to the specific Get Block Status
- switch (ptsTransaction->teStatus)
- {
- case CANTS_GET_BLOCK_STATUS_PENDING:
- {
- // If the Get Block Request frame has already been sent
- if (bHasSentRequest == TRUE)
- {
- // If there is at least one Get Block Acknowledgement waiting
- if (iCANTS_GetBlockPendingAcknowledgements > 0U)
- {
- // There should only ever be one acknowledgement after a Get Block Request has been sent, therefore just get the first one
- tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsAcknowledgement = &(atsCANTS_GetBlockPendingAcknowledgements[0U]);
- // Switch for the specific type of acknowledgement
- switch (ptsAcknowledgement->teAcknowledgement)
- {
- case CANTS_POSITIVE_ACKNOWLEDGEMENT:
- {
- // Request all of the blocks from the source node
- // "Remaining Blocks" in this instance is just all of the blocks
- teFuncStatus = CANTS_RequestRemainingBlocks(ptsTransaction);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to request remaining Get Block blocks");
- // Go to the ongoing transaction state
- ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_ONGOING;
- break;
- }
- case CANTS_NEGATIVE_ACKNOWLEDGEMENT:
- {
- // Go to the transaction failure state
- ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_FAILURE;
- break;
- }
- default:
- {
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block Acknowledgement enumeration value was provided");
- break;
- }
- }
- }
- // Reset the counter to specify that the frames have been handled
- iCANTS_GetBlockPendingAcknowledgements = 0U;
- }
- // No Get Block Request has been sent, so send one
- else
- {
- // The Get Block Request frame to send
- tsCANTS_FRAME_GET_BLOCK_REQUEST tsGetBlockRequest = { 0U };
- /* Populate the fields within the Get Block Request frame vvv */
- tsGetBlockRequest.iToAddress = ptsTransaction->iToAddress;
- tsGetBlockRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsGetBlockRequest.iStartAddress = ptsTransaction->iStartAddress;
- // Get the number of blocks to request rounded upwards to the nearest 8 bytes
- tUINT32 iNumberOfBlocks = (tUINT32)((ptsTransaction->iNumberOfBytes + 7U) / 8U);
- // Ensure the number of blocks doesn't exceed 63 - It's possible to round up to 64
- if (iNumberOfBlocks > 63U)
- {
- iNumberOfBlocks = 63U;
- }
- // We minus 1 because the CANTS Protocol states the number of blocks specified within the frame is the actual number minus 1 (i.e., 0 to 63 blocks)
- tsGetBlockRequest.iNumberOfBlocks = iNumberOfBlocks - 1U;
- /* Initialise the transaction state for the transaction vvv */
- // Initially assign all bits to 0
- ptsTransaction->iBlocksRequired = 0U;
- // Set the bit within the bit field for all required blocks
- for (tUINT32 iBitIndex = 0U; iBitIndex < iNumberOfBlocks; ++iBitIndex)
- {
- // Assign the bit
- ptsTransaction->iBlocksRequired |= (0x8000000000000000U >> iBitIndex);
- }
- // No blocks have been received yet
- ptsTransaction->iBlocksReceived = 0U;
- // The Generic version of the Get Block Request frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate from the Get Block Request frame to the Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsGetBlockRequest, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Get Block Request frame to a Generic frame");
- // Set the queues to be empty prior to starting the transfer
- iCANTS_GetBlockPendingAcknowledgements = 0U;
- iCANTS_GetBlockPendingTransfers = 0U;
- // Send the Get Block Request frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Get Block Request frame");
- // Specify that the Get Block Request has been sent
- bHasSentRequest = TRUE;
- }
- break;
- }
- case CANTS_GET_BLOCK_STATUS_ONGOING:
- {
- // Go through all pending Get Block Transfer frames
- for (tUINT32 iFrameIndex = 0U; iFrameIndex < iCANTS_GetBlockPendingTransfers; ++iFrameIndex)
- {
- // Get a pointer to the transfer frame
- tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsTransfer = &(atsCANTS_GetBlockPendingTransfers[iFrameIndex]);
- // Get the starting index of where the block should be inserted into the receive buffer
- tUINT32 iStartIndex = (ptsTransfer->iSequence * 8U);
- // Ensure there is enough capacity within the receive buffer
- // This check has already been performed prior to the Request even being made but this ensures redundancy
- EH_ASSERT((iStartIndex + 8U) <= ptsTransaction->iReceiveBufferSize, CANTS_INVALID_PARAMETER, "The receive buffer is not large enough to write a Get Block transfer into");
- // Copy the data from the transfer frame into the receive buffer
- // Get Block transactions are always sent in 8 byte chunks, therefore we copy all 8 bytes
- for (tUINT32 iByteIndex = 0U; iByteIndex < 8U; ++iByteIndex)
- {
- // Copy the byte
- ptsTransaction->pcReceiveBuffer[iStartIndex + iByteIndex] = ptsTransfer->acData[iByteIndex];
- }
- // Assign the bit corresponding to the bit which we have received
- ptsTransaction->iBlocksReceived |= (0x8000000000000000U >> ptsTransfer->iSequence);
- }
- // Signify that all pending frames have been handled
- iCANTS_GetBlockPendingTransfers = 0U;
- break;
- }
- case CANTS_GET_BLOCK_STATUS_SUCCESS: // Fall-through
- case CANTS_GET_BLOCK_STATUS_FAILURE:
- {
- // Restore the static state
- bHasSentRequest = FALSE;
- // Signify there is no longer an ongoing Get Block transaction
- bCANTS_GetBlockBusy = FALSE;
- break;
- }
- default:
- {
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block Status was provided");
- break;
- }
- }
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /** TODO: Add CANTS_TRANSLATE_ERROR to EA
- * This will request any remaining blocks which have not been received by the Destination node of a
- * Get Block transaction. The reason this exists is because CAN-TS supports no method to determine the
- * transfer status of a Get Block transaction, therefore it's implementation defined for at what point
- * to re-request blocks which are not yet received.
- * You would likely call this after a specified period of time multiplied by the number of expected
- * blocks, e.g., 5 milliseconds * Number of remaining blocks. If after this period, there are missing
- * blocks, you can determine they were likely lost during transmission.
- * It is valid to call this function at any point during a data transfer.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_SEND_ERROR if there was an error while sending a frame.
- * @param ptsTransaction: tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION*: The transaction to request the
- * remaining blocks for.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_RequestRemainingBlocks(tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // Ensure there's actually an ongoing transaction before requesting blocks
- EH_ASSERT(bCANTS_GetBlockBusy == TRUE, CANTS_INVALID_PARAMETER, "There is not currently an ongoing Get Block transaction");
- // A bit field of the blocks not yet received and must be requested
- tUINT64 iBlocksNotReceivedYet = 0U;
- // This is solved via the following:
- // BlocksNotYetReceived = (NOT(BlocksReceived) AND BlocksRequired)
- // This is done instead of an XOR so that blocks which aren't expected are not requested
- // E.g.:
- /*
- * Required | 11110000
- * Received | 11001000
- * -------------------+---------
- * Req. XOR Recv. | 00111000
- * -------------------+---------
- * NOT Recv. | 00110111
- * NOT Recv. AND Req. | 00110000
- *
- * -------------------+---------
- * Expected Value | 00110000
- */
- // NOT Received
- iBlocksNotReceivedYet = ~(ptsTransaction->iBlocksReceived);
- // AND Requested
- iBlocksNotReceivedYet &= ptsTransaction->iBlocksRequired;
- // The frame to send to the source node to request blocks
- // A Start frame can be sent more than once to request blocks
- tsCANTS_FRAME_GET_BLOCK_START tsGetBlockStart = { 0U };
- /* Populate the fields within the Start frame vvv */
- tsGetBlockStart.iBlocksToGet = iBlocksNotReceivedYet;
- tsGetBlockStart.iToAddress = ptsTransaction->iToAddress;
- tsGetBlockStart.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- // The generic version of the start frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate the Start frame into the Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsGetBlockStart, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_START, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Start frame into a Generic frame");
- // Send the start frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Get Block Start frame");
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /** TODO: Add CANTS_TRANSLATE_ERROR and CANTS_SEND_ERROR to EA
- * This will end a Get Block transaction. Internally, this will send the Abort frame to the
- * Destination node of the transfer and re-enable user callbacks.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @param ptsTransaction: tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION*: The transaction to end
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_EndGetBlockTransaction(tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // Ensure there is an ongoing Get Block transaction
- EH_ASSERT(bCANTS_GetBlockBusy == TRUE, CANTS_INVALID_PARAMETER, "Attempted to end a Get Block transaction while there is not one ongoing")
- // The Get Block abort frame
- tsCANTS_FRAME_GET_BLOCK_ABORT tsGetBlockAbort = { 0U };
- /* Populate the fields within the abort frame vvv */
- tsGetBlockAbort.iToAddress = ptsTransaction->iToAddress;
- tsGetBlockAbort.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- // The generic version of the Get Block Abort frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame;
- // Translate from Get Block Abort frame to a Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsGetBlockAbort, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Get Block Abort frame to a Generic frame");
- // Specify there is no longer an ongoing Get Block transaction
- bCANTS_GetBlockBusy = FALSE;
- // Send the Get Block Abort frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send a Get Block Abort frame");
- // If all blocks have been received
- // We check this using the AND operation instead of simply equality in case the Blocks Received value has some other arbitrary bits set
- if ((ptsTransaction->iBlocksRequired & ptsTransaction->iBlocksReceived) == ptsTransaction->iBlocksRequired)
- {
- // The transaction has successfully completed
- ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_SUCCESS;
- }
- else
- {
- // Not all blocks have been received, therefore the transaction has failed
- ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_FAILURE;
- }
- // Call the Get Block function a final time with the new transaction status so that it can reset the static state and such
- teFuncStatus = CANTS_GetBlock(ptsTransaction);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_INVALID_PARAMETER, "Failed to perform a final Get Block state transition");
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /** TODO: Add CANTS_TRANSLATE_ERROR to EA
- * This will send a Positive Acknowledgement to the node which made the Get Block request. Once you
- * have accepted the request, you must make calls to CANTS_TransmitGetBlockTransfer(...) until all
- * blocks have been sent to the recipient.
- * This will also disable any registered callbacks for Get Block packets to allow this object to
- * handle all of them. This avoids any other packet handling from changing the state of the
- * transaction.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param ptsRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The Get Block request
- * @param ptsTransaction: tsCANTS_GET_BLOCK_INCOMING_TRANSACTION*: A pointer to the incoming get block
- * transaction object.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_AcceptGetBlockRequest(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsRequest, tsCANTS_GET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // The Positive Acknowledgement frame for the Get Block Request
- tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT tsRequestAcknowledgement = { 0U };
- /* Populate the fields within the Positive Acknowledgement frame vvv */
- tsRequestAcknowledgement.iToAddress = ptsRequest->iFromAddress;
- tsRequestAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsRequestAcknowledgement.teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
- tsRequestAcknowledgement.iCommand = ptsRequest->iNumberOfBlocks;
- tsRequestAcknowledgement.iDataLength = (tUINT8)ptsRequest->teAddressSize;
- /* Get the address in Little Endian to send back to the requesting node */
- tUINT64 iAddressLittleEndian = ptsRequest->iStartAddress;
- // Convert into little endian
- teFuncStatus = funcCANTS_NativeEndiannessToLittleEndian(&iAddressLittleEndian);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to convert address to little endian");
- // Copy the bytes of the little endian address to the data field of the frame
- for (tUINT32 iByteIndex = 0U; iByteIndex < tsRequestAcknowledgement.iDataLength; ++iByteIndex)
- {
- // Copy the byte
- tsRequestAcknowledgement.acData[iByteIndex] = (((tUINT8*)&iAddressLittleEndian)[iByteIndex]);
- }
- // The generic version of the Positive Acknowledgement frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate from the Acknowledgement frame to a Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsRequestAcknowledgement, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Positive Acknowledgement frame to a Generic frame");
- // Specify there is now an ongoing Get Block transaction
- bCANTS_GetBlockBusy = TRUE;
- // Send the Positive Acknowledgement frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Get Block Request Positive Acknowledgement frame");
- return BT_SUCCESS;
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- // Specify there are no ongoing Get Block transaction in the case of failure
- bCANTS_GetBlockBusy = FALSE;
- return BT_FAIL;
- }
- /**
- * This rejects a Get Block Request by sending a Negative Acknowledgement packet in response.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param ptsRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The Get Block request you want to reject.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_RejectGetBlockRequest(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsRequest)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // The negative acknowledgement to send to the requesting node
- tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT tsNegativeAcknowledgement = { 0U };
- /* Populate the fields within the negative acknowledgement frame vvv */
- tsNegativeAcknowledgement.iToAddress = ptsRequest->iFromAddress;
- tsNegativeAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsNegativeAcknowledgement.teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
- // The command and data fields go unused
- tsNegativeAcknowledgement.iCommand = 0U;
- tsNegativeAcknowledgement.iDataLength = 0U;
- // The generic version of the negative acknowledgement frame to send on the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate from the Negative Acknowledgement frame to a Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsNegativeAcknowledgement, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Get Block Negative Acknowledgement frame to a Generic frame");
- // Send the negative acknowledgement frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send a Get Block Negative Acknowledgement frame");
- return BT_SUCCESS;
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * This will handle sending blocks to the node which requested a block. You must keep calling this
- * function until the status is either CANTS_GET_BLOCK_STATUS_SUCCESS or
- * CANTS_GET_BLOCK_STATUS_FAILURE.
- * Once one of those states have been hit, you must then call CANTS_EndGetBlockTransfer(...) to re-
- * enable any registered callbacks.
- * The CAN-TS protocol does not support the Source side aborting a transfer. If you require this
- * functionality, you can choose to stop sending blocks and call CANTS_EndGetBlockTransfer(...) during
- * the transmission - this will allow the receiving node to timeout. Note that the receiving node will
- * likely continue to send some Start Get Block Transfer frames until it times out. It is favoured to
- * fulfill the transfer.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @throws CANTS_SEND_ERROR if the frame failed to send.
- * @param ptsRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The request for the Get Block transaction
- * @param ptsTransaction: tsCANTS_GET_BLOCK_INCOMING_TRANSACTION*: The transaction state of the Get
- * Block request
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_TransmitGetBlockTransfer(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsRequest, tsCANTS_GET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
- {
- // The return value from function calls
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // A bit field of the requested blocks within start frames
- static tUINT64 iBlocksRequested = 0U;
- // Switch to the specific state within the transaction
- switch (ptsTransaction->teStatus)
- {
- case CANTS_GET_BLOCK_STATUS_PENDING:
- {
- // Set the initial state of the blocks required
- // This is only necessary in the first iteration of the state, subsequent state transitions from ONGOING to PENDING will already have this value assigned to 0
- iBlocksRequested = 0U;
- // If there are start frames waiting to be handled
- if (iCANTS_GetBlockPendingStarts > 0U)
- {
- // Go to the ONGOING state
- ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_ONGOING;
- }
- // Else if there are abort frame
- else if (iCANTS_GetBlockPendingAborts > 0U)
- {
- // Remove the compiler warning for the unused queue
- // TODO: Just remove the array?
- (void)atsCANTS_SetBlockPendingAborts;
- // If all blocks have been sent
- // This doesn't necessarily mean the blocks have been received but this is the best check we can perform to see if all blocks were even sent
- if (ptsTransaction->iBytesRemaining == 0U)
- {
- // It's most likely that we received the Abort frame because the receiving node received all blocks, therefore go to the SUCCESS state
- ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_SUCCESS;
- }
- // Else we have not even attempted to send all frames
- else
- {
- // We know there's no chance the receiving node has received all blocks so the transaction has failed
- ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_FAILURE;
- }
- }
- else
- {
- /* Else just wait until something has been received by the requesting node */
- /* It is the responsibility of the user to timeout if required */
- (void)0;
- }
- break;
- }
- case CANTS_GET_BLOCK_STATUS_ONGOING:
- {
- // Go through each pending start frame
- for (tUINT32 iFrameIndex = 0U; iFrameIndex < iCANTS_GetBlockPendingStarts; ++iFrameIndex)
- {
- // A pointer to the Start frame
- tsCANTS_FRAME_GET_BLOCK_START* ptsStartFrame = &(atsCANTS_GetBlockPendingStarts[iFrameIndex]);
- // Add any requested blocks to bit field of blocks which need sent
- iBlocksRequested |= ptsStartFrame->iBlocksToGet;
- }
- // Signify that all pending start frames have been handled
- iCANTS_GetBlockPendingStarts = 0U;
- // If there are blocks which need sent
- if (iBlocksRequested != 0U)
- {
- // Get the index of the first block which is requested
- tUINT32 iRequestedBlockIndex = 0U;
- // Shift to the left until the left-most bit is a 1 while keeping track of the index
- // This is guaranteed to terminate because we have already ensured iBlocksRequested is non-zero
- while ((0x8000000000000000U & (iBlocksRequested << iRequestedBlockIndex)) == 0U)
- {
- // Increment the block index
- ++iRequestedBlockIndex;
- }
- // The starting index of the block requested
- tUINT32 iStartingIndex = (iRequestedBlockIndex * 8U);
- // Ensure the buffer is large enough to provide the block requested
- EH_ASSERT((iStartingIndex + 8U) <= ptsTransaction->iDataLength, CANTS_INVALID_PARAMETER, "The data buffer is not large enough for the block index requested");
- // The block transfer to send to the requesting node
- tsCANTS_FRAME_GET_BLOCK_TRANSFER tsTransfer = { 0U };
- /* Assign the fields within the transfer frame vvv */
- tsTransfer.iToAddress = ptsRequest->iFromAddress;
- tsTransfer.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsTransfer.iSequence = iRequestedBlockIndex;
- // Copy the data from the data buffer into the frame
- // All Get Block Transfer frames have a data field of 8 bytes
- for (tUINT32 iByteIndex = 0U; iByteIndex < 8U; ++iByteIndex)
- {
- // Copy the byte
- tsTransfer.acData[iByteIndex] = ptsTransaction->pcData[iStartingIndex + iByteIndex];
- }
- // The generic version of the Get Block Transfer frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate from the Get Block Transfer frame to the Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTransfer, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Get Block Transfer frame to a Generic frame");
- // Send the Get Block Transfer frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Get Block Transfer frame");
- // Clear the requested block bit
- iBlocksRequested &= ~(0x8000000000000000U >> iRequestedBlockIndex);
- }
- // Else there are no more blocks expecting to be sent so go the pending state awaiting either a Start or Abort frame
- else
- {
- // Set the transaction state to PENDING
- ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_PENDING;
- }
- break;
- }
- case CANTS_GET_BLOCK_STATUS_SUCCESS: // Fall-through
- case CANTS_GET_BLOCK_STATUS_FAILURE:
- {
- // Specify that there are no ongoing Get Block transactions
- // This is done before sending a frame because the transaction is complete regardless
- bCANTS_GetBlockBusy = FALSE;
- // The acknowledgement frame to send to the requesting node
- // The reason this is sent under the SUCCESS and FAILURE state is because this state is only entered upon an ABORT frame being received
- // All ABORT frames should respond with a Positive Acknowledgement frame
- tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT tsPositiveAcknowledgement = { 0U };
- /* Populate the fields within the Positive Acknowledgement frame vvv */
- /* The command and data fields go undefined */
- tsPositiveAcknowledgement.iToAddress = ptsRequest->iFromAddress;
- tsPositiveAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
- tsPositiveAcknowledgement.iDataLength = 0U;
- // The generic version of the positive acknowledgement frame to send over the CAN Bus
- tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
- // Translate from the Positive Acknowledgement frame to the Generic frame
- teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsPositiveAcknowledgement, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Get Block Positive Acknowledgement frame to a Generic frame");
- // Send the Get Block Positive Acknowledgement frame
- teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send a Get Block Positive Acknowledgement frame");
- break;
- }
- default:
- {
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block state was provided");
- break;
- }
- }
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- CANTS_SEND_ERROR:
- return BT_FAIL;
- }
- /**
- * Translates a CAN-TS frame structure to a generic frame, which is a format able to be given to the
- * Send Frame function.
- * You provide a pointer to the CAN-TS frame and specify the frame type and subtype via the
- * enumeration values. You must make sure you pass in the correct types.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @param vpCANTSFrame: void*: A pointer to the CAN-TS frame you want to translate into a generic
- * frame.
- * @param teFrameType: teCANTS_FRAME_TYPE: The frame type
- * @param teFrameSubtype: teCANTS_FRAME_SUBTYPE: The frame subtype. If it is an Acknowledgement frame,
- * use the Generic Acknowledgement enumeration value.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The output generic frame.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_TranslateToGenericFrame(void* vpCANTSFrame, teCANTS_FRAME_TYPE teFrameType, teCANTS_FRAME_SUBTYPE teFrameSubtype, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // We use a switch case instead of some kind of map for efficiency
- // The frame type is first determined then the subtype
- // It's not possible to directly use the subtype because different frame types share some of the same subtype values
- switch (teFrameType)
- {
- /* Telecommand */
- case CANTS_FRAME_TYPE_TELECOMMAND:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameTelecommandRequestToGeneric((tsCANTS_FRAME_TELECOMMAND_REQUEST*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telecommand Request to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT: // Fall-though
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT:
- {
- teFuncStatus = CANTS_TranslateFrameTelecommandAcknowledgementToGeneric(ptsGenericFrame, (tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*)vpCANTSFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telecommand Acknowledgement to Generic frame");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Telecommand Subtype was provided");
- break;
- }
- break;
- }
- /* Telemetry */
- case CANTS_FRAME_TYPE_TELEMETRY_REQUEST:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameTelemetryRequestToGeneric(ptsGenericFrame, (tsCANTS_FRAME_TELEMETRY_REQUEST*)vpCANTSFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telemetry Request to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_TELEMETRY_GENERIC_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_TELEMETRY_NEGATIVE_ACKNOWLEDGEMENT:
- {
- teFuncStatus = CANTS_TranslateFrameTelemetryAcknowledgementToGeneric((tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telemetry Acknowledgement to Generic frame");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Telemetry Subtype was provided");
- break;
- }
- break;
- }
- /* Unsolicited telemetry */
- case CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY:
- {
- teFuncStatus = CANTS_TranslateFrameUnsolicitedTelemetryToGeneric(ptsGenericFrame, (tsCANTS_FRAME_UNSOLICITED_TELEMETRY*)vpCANTSFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Unsolicited Telemetry to Generic frame");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The Unsolicited Frame Subtype was invalid");
- break;
- }
- break;
- }
- /* Time synchronsation */
- case CANTS_FRAME_TYPE_TIME_SYNCHRONISATION:
- {
- // Time synchronisation frames have an undefined subtype, therefore we don't check it
- teFuncStatus = CANTS_TranslateFrameTimeSynchronisationToGeneric((tsCANTS_FRAME_TIME_SYNCHRONISATION*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Time Synchronisation to Generic frame");
- break;
- }
- /* Set block */
- case CANTS_FRAME_TYPE_SET_BLOCK:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameSetBlockRequestToGeneric((tsCANTS_FRAME_SET_BLOCK_REQUEST*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Request to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_GENERIC_ACKNOWLEDGEMENT: // Fall-though
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
- {
- teFuncStatus = CANTS_TranslateFrameSetBlockAcknowledgementToGeneric((tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Acknowledgement to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER:
- {
- teFuncStatus = CANTS_TranslateFrameSetBlockTransferToGeneric(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_TRANSFER*)vpCANTSFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Transfer to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameSetBlockStatusRequestToGeneric(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*)vpCANTSFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Status Request to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT:
- {
- teFuncStatus = CANTS_TranslateFrameSetBlockStatusReportToGeneric(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*)vpCANTSFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Status Report to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT:
- {
- teFuncStatus = CANTS_TranslateFrameSetBlockAbortToGeneric((tsCANTS_FRAME_SET_BLOCK_ABORT*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Abort to Generic frame");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Subtype was provided");
- break;
- }
- break;
- }
- /* Get block */
- case CANTS_FRAME_TYPE_GET_BLOCK:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameGetBlockRequestToGeneric((tsCANTS_FRAME_GET_BLOCK_REQUEST*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Request to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_GENERIC_ACKNOWLEDGEMENT: // Fall-though
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
- {
- teFuncStatus = CANTS_TranslateFrameGetBlockAcknowledgementToGeneric((tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Acknowledgement to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_START:
- {
- teFuncStatus = CANTS_TranslateFrameGetBlockStartToGeneric(ptsGenericFrame, (tsCANTS_FRAME_GET_BLOCK_START*)vpCANTSFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Start to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER:
- {
- teFuncStatus = CANTS_TranslateFrameGetBlockTransferToGeneric((tsCANTS_FRAME_GET_BLOCK_TRANSFER*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Transfer to Generic frame");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT:
- {
- teFuncStatus = CANTS_TranslateFrameGetBlockAbortToGeneric((tsCANTS_FRAME_GET_BLOCK_ABORT*)vpCANTSFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Abort to Generic frame");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block Subtype was provided");
- break;
- }
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Frame Type was provided");
- break;
- }
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- return BT_FAIL;
- }
- /**
- * This is used to translate from a generic frame to a specific frame type. You must know what frame
- * type you have and only convert to the correct type.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame being translated
- * @param teFrameType: teCANTS_FRAME_TYPE: The frame type to convert to
- * @param teFrameSubtype: teCANTS_FRAME_SUBTYPE: The frame subtype to convert to. In the case of
- * acknowledgement types, use the Generic Acknowledgement enumeration value.
- * @param vpTranslatedFrame: void*: A pointer to the frame type you're translating to. This is a void
- * pointer such that you can pass in various frame types.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_TranslateFromGenericFrame(tsCANTS_FRAME_GENERIC* ptsGenericFrame, teCANTS_FRAME_TYPE teFrameType, teCANTS_FRAME_SUBTYPE teFrameSubtype, void* vpTranslatedFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // We use a switch case instead of some kind of map for efficiency
- // The frame type is first determined then the subtype
- // It's not possible to directly use the subtype because different frame types share some of the same subtype values
- switch (teFrameType)
- {
- /* Telecommand */
- case CANTS_FRAME_TYPE_TELECOMMAND:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToTelecommandRequest((tsCANTS_FRAME_TELECOMMAND_REQUEST*)vpTranslatedFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Telecommand Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT: // Fall-though
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToTelecommandAcknowledgement((tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*)vpTranslatedFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Telecommand Acknowledgement");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Telecommand Subtype was provided");
- break;
- }
- break;
- }
- /* Telemetry */
- case CANTS_FRAME_TYPE_TELEMETRY_REQUEST:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToTelemetryRequest(ptsGenericFrame, (tsCANTS_FRAME_TELEMETRY_REQUEST*)vpTranslatedFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Telemetry Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_TELEMETRY_GENERIC_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_TELEMETRY_NEGATIVE_ACKNOWLEDGEMENT:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToTelemetryAcknowledgement(ptsGenericFrame, (tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*)vpTranslatedFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Telemetry Acknowledgement");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Telemetry Subtype was provided");
- break;
- }
- break;
- }
- /* Unsolicited telemetry */
- case CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToUnsolicitedTelemetry((tsCANTS_FRAME_UNSOLICITED_TELEMETRY*)vpTranslatedFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Unsolicited Telemetry");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The Unsolicited Frame Subtype was invalid");
- break;
- }
- break;
- }
- /* Time synchronsation */
- case CANTS_FRAME_TYPE_TIME_SYNCHRONISATION:
- {
- // Time synchronisation frames have an undefined subtype, therefore we don't check it
- teFuncStatus = CANTS_TranslateFrameGenericToTimeSynchronisation((tsCANTS_FRAME_TIME_SYNCHRONISATION*)vpTranslatedFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Time Synchronisation");
- break;
- }
- /* Set block */
- case CANTS_FRAME_TYPE_SET_BLOCK:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToSetBlockRequest(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_REQUEST*)vpTranslatedFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_GENERIC_ACKNOWLEDGEMENT: // Fall-though
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToSetBlockAcknowledgement((tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*)vpTranslatedFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Acknowledgement");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToSetBlockTransfer(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_TRANSFER*)vpTranslatedFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Transfer");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToSetBlockStatusRequest(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*)vpTranslatedFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Status Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToSetBlockStatusReport(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*)vpTranslatedFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Status Report");
- break;
- }
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToSetBlockAbort((tsCANTS_FRAME_SET_BLOCK_ABORT*)vpTranslatedFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Abort");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Subtype was provided");
- break;
- }
- break;
- }
- /* Get block */
- case CANTS_FRAME_TYPE_GET_BLOCK:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToGetBlockRequest(ptsGenericFrame, (tsCANTS_FRAME_GET_BLOCK_REQUEST*)vpTranslatedFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Request");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_GENERIC_ACKNOWLEDGEMENT: // Fall-though
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToGetBlockAcknowledgement((tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*)vpTranslatedFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Acknowledgemenet");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_START:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToGetBlockStart((tsCANTS_FRAME_GET_BLOCK_START*)vpTranslatedFrame, ptsGenericFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Start");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToGetBlockTransfer(ptsGenericFrame, (tsCANTS_FRAME_GET_BLOCK_TRANSFER*)vpTranslatedFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Transfer");
- break;
- }
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT:
- {
- teFuncStatus = CANTS_TranslateFrameGenericToGetBlockAbort(ptsGenericFrame, (tsCANTS_FRAME_GET_BLOCK_ABORT*)vpTranslatedFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Abort");
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block Subtype was provided");
- break;
- }
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Frame Type was provided");
- break;
- }
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- return BT_FAIL;
- }
- /**
- * Sets the source/from address for this node. You must not call this function while there is an
- * ongoing transaction or while CANTS_HandleFrame(...) is being executed.
- * @returns BT_SUCCESS always
- * @param iAddress: tUINT8: The new node address
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_SetNodeAddress(tUINT8 iAddress)
- {
- // Assign the new address
- tsCANTS_Configuration.iNodeAddress = iAddress;
- return BT_SUCCESS;
- }
- /**
- * Sets a callback for a specific frame reception. Ideally, you should assign all of the callbacks
- * during initialisation, but you can modify the function pointer with this call. To disable a
- * callback, assign it to 0 - Keep in mind, this may cause things such as an automatic Negative
- * Acknowledgement being sent as a response to frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
- * @param teFrameType: teCANTS_FRAME_TYPE: The frame type of the callback to handle
- * @param teFrameSubtype: teCANTS_FRAME_SUBTYPE: The specific type of frame. For acknowledgement
- * frames, use the Generic Acknowledgement enumeration value.
- * @param (*funcCallback)(): teFUNC_STATUS: The new callback or 0. The function signature must return
- * teFUNC_STATUS
- * and take a const pointer to the exact frame type being expected. Refer to tsCANTS_CONFIGURATION for
- * the function signatures.
- * @re-entrant:
- */
- teFUNC_STATUS CANTS_SetCallback(teCANTS_FRAME_TYPE teFrameType, teCANTS_FRAME_SUBTYPE teFrameSubtype, teFUNC_STATUS (*funcCallback)())
- {
- // Switch for the general frame type
- // As an implementation note, the reason this function requires the frame type and subtype is because some subtypes have the same underlying value
- // This means it's not possible to switch on the subtype alone
- // This could be implemented with a two-keyed map, but that would use more memory, and could potentially be slower, for little benefit
- switch (teFrameType)
- {
- case CANTS_FRAME_TYPE_TELECOMMAND:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST:
- tsCANTS_Configuration.funcCallbackOnTelecommandRequest = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT:
- tsCANTS_Configuration.funcCallbackOnTelecommandAcknowledgement = funcCallback;
- break;
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Telecommand subtype is invalid");
- break;
- }
- break;
- }
- case CANTS_FRAME_TYPE_TELEMETRY_REQUEST:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST:
- tsCANTS_Configuration.funcCallbackOnTelemetryRequest = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_TELEMETRY_GENERIC_ACKNOWLEDGEMENT:
- tsCANTS_Configuration.funcCallbackOnTelemetryAcknowledgement = funcCallback;
- break;
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Telemetry subtype is invalid");
- break;
- }
- break;
- }
- case CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY:
- tsCANTS_Configuration.funcCallbackOnUnsolicitedTelemetry = funcCallback;
- break;
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Unsolicited Telemetry subtype is invalid");
- break;
- }
- break;
- }
- case CANTS_FRAME_TYPE_TIME_SYNCHRONISATION:
- {
- /* Time Synchronisation frames have an undefined subtype, therefore we perform no check on it */
- tsCANTS_Configuration.funcCallbackOnTimeSynchronisation = funcCallback;
- break;
- }
- case CANTS_FRAME_TYPE_SET_BLOCK:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST:
- tsCANTS_Configuration.funcCallbackOnSetBlockRequest = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_GENERIC_ACKNOWLEDGEMENT:
- tsCANTS_Configuration.funcCallbackOnSetBlockAcknowledgement = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER:
- tsCANTS_Configuration.funcCallbackOnSetBlockTransfer = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST:
- tsCANTS_Configuration.funcCallbackOnSetBlockStatusRequest = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT:
- tsCANTS_Configuration.funcCallbackOnSetBlockStatusReport = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT:
- tsCANTS_Configuration.funcCallbackOnSetBlockAbort = funcCallback;
- break;
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Set Block subtype is invalid");
- break;
- }
- break;
- }
- case CANTS_FRAME_TYPE_GET_BLOCK:
- {
- switch (teFrameSubtype)
- {
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST:
- tsCANTS_Configuration.funcCallbackOnGetBlockRequest = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_GENERIC_ACKNOWLEDGEMENT:
- tsCANTS_Configuration.funcCallbackOnGetBlockAcknowledgement = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_START:
- tsCANTS_Configuration.funcCallbackOnGetBlockStart = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER:
- tsCANTS_Configuration.funcCallbackOnGetBlockTransfer = funcCallback;
- break;
- case CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT:
- tsCANTS_Configuration.funcCallbackOnGetBlockAbort = funcCallback;
- break;
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Get Block subtype is invalid");
- break;
- }
- break;
- }
- default:
- EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The frame subtype specified is not valid");
- break;
- }
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- return BT_FAIL;
- }
- /**
- * Handles incoming telecommand requests.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_TELECOMMAND_REQUEST*: A pointer to the CAN-TS frame to handle
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingTelecommandRequest(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnTelecommandRequest != 0U)
- {
- // Pass the request to the user
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnTelecommandRequest(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Telecommand Request");
- }
- // Else send a negative acknowledgement by default
- else
- {
- teFuncStatus = CANTS_SendTelecommandAcknowledgement(ptsFrame->iChannel, ptsFrame->iFromAddress, CANTS_NEGATIVE_ACKNOWLEDGEMENT);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to send Telecommand Negative Acknowledgement");
- }
- return BT_SUCCESS;
- CANTS_HANDLING_ISSUE:
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Handles the acknowledgement to a telecommand.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*: A pointer to the frame to handle
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingTelecommandAcknowledgement(tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsFrame)
- {
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnTelecommandAcknowledgement != 0U)
- {
- // Pass the acknowledgement to the user
- teFUNC_STATUS teFuncStatus = tsCANTS_Configuration.funcCallbackOnTelecommandAcknowledgement(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Telecommand Acknowledgement");
- }
- return BT_SUCCESS;
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Internally used to handle incoming telemetry request frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_TELEMETRY_REQUEST*: A pointer to the frame to handle
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingTelemetryRequest(tsCANTS_FRAME_TELEMETRY_REQUEST* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnTelemetryRequest != 0U)
- {
- // Pass the request to the user
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnTelemetryRequest(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Telemetry Request");
- }
- // Else send a negative acknowledgement by default
- else
- {
- teFuncStatus = CANTS_SendTelemetryAcknowledgement(ptsFrame->iChannel, ptsFrame->iFromAddress, 0, 0, CANTS_NEGATIVE_ACKNOWLEDGEMENT);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to send Telemetry Negative Acknowledgement");
- }
- return BT_SUCCESS;
- CANTS_HANDLING_ISSUE:
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- return BT_SUCCESS;
- }
- /**
- * Handles the response to a telemetry request.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*: A pointer to the frame to handle
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingTelemetryAcknowledgement(tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsFrame)
- {
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnTelemetryAcknowledgement != 0U)
- {
- teFUNC_STATUS teFuncStatus = tsCANTS_Configuration.funcCallbackOnTelemetryAcknowledgement(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Telemetry Acknowledgement");
- }
- return BT_SUCCESS;
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Internally used to handle unsolicited telemetry.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_UNSOLICITED_TELEMETRY*: A pointer to the CAN-TS frame to handle
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingUnsolicitedTelemetry(tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsFrame)
- {
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnUnsolicitedTelemetry != 0U)
- {
- teFUNC_STATUS teFuncStatus = tsCANTS_Configuration.funcCallbackOnUnsolicitedTelemetry(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Unsolicited Telemetry");
- }
- return BT_SUCCESS;
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Used to internally handle incoming time synchronisation frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_TIME_SYNCHRONISATION*: A pointer to the time synchronisation frame.
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingTimeSynchronisation(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsFrame)
- {
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnTimeSynchronisation != 0U)
- {
- teFUNC_STATUS teFuncStatus = tsCANTS_Configuration.funcCallbackOnTimeSynchronisation(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Time Synchronisation frame");
- }
- return BT_SUCCESS;
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Used to handle incoming set block requests.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_REQUEST*: A pointer to the set block request.
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingSetBlockRequest(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If there is currently an ongoing Set Block transaction
- if (bCANTS_SetBlockBusy)
- {
- // Reject the request
- teFuncStatus = CANTS_RejectSetBlockRequest(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to reject Set Block request");
- }
- // Else handle the request as normal
- else
- {
- // If the callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnSetBlockRequest != 0U)
- {
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockRequest(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Request");
- }
- // If no callback has been assigned
- else
- {
- // Automatically reject the request
- teFuncStatus = CANTS_RejectSetBlockRequest(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to reject Set Block Request");
- }
- }
- return BT_SUCCESS;
- CANTS_CALLBACK_ERROR:
- CANTS_HANDLING_ISSUE:
- return BT_FAIL;
- }
- /**
- * Handles incoming Set Block acknowledgement frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*: A pointer to the Set Block Request
- * acknowledgement frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingSetBlockAcknowledgement(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If this object needs to handle this frame
- if (bCANTS_SetBlockBusy)
- {
- // Ensure there is enough room to append the acknowledgement
- EH_ASSERT((iCANTS_SetBlockPendingAcknowledgements + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Set Block Pending Acknowledgement queue is full");
- // Append the acknowledgement frame to the queue
- tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsElementPointer = &(atsCANTS_SetBlockPendingAcknowledgements[iCANTS_SetBlockPendingAcknowledgements]);
- // We copy the bytes of the frame into the queue
- for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT); ++iByteIndex)
- {
- ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
- }
- // Increment the number of pending acknowledgements
- ++iCANTS_SetBlockPendingAcknowledgements;
- }
- // Else if this frame should be passed to the user
- else
- {
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnSetBlockAcknowledgement != 0U)
- {
- // Pass the frame to the callback
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockAcknowledgement(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Acknowledgement");
- }
- }
- return BT_SUCCESS;
- CANTS_CALLBACK_ERROR:
- CANTS_HANDLING_ISSUE:
- return BT_FAIL;
- }
- /**
- * Handles incoming Set Block transfer frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_TRANSFER*: A pointer to the Set Block Transfer frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingSetBlockTransfer(tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If this object needs to handle the transfer frame
- if (bCANTS_SetBlockBusy)
- {
- // Ensure the queue has enough space
- EH_ASSERT((iCANTS_SetBlockPendingTransfers + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ERROR, "Set Block Pending Transfer queue is full");
- // Get a pointer to the element which we're going to write to
- tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsElementPointer = &(atsCANTS_SetBlockPendingTransfers[iCANTS_SetBlockPendingTransfers]);
- // Copy the data to the queue
- for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_SET_BLOCK_TRANSFER); ++iByteIndex)
- {
- ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
- }
- // Increment the number of elements within the queue
- ++iCANTS_SetBlockPendingTransfers;
- }
- // The frame should be passed to the user
- else
- {
- // If the callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnSetBlockTransfer != 0U)
- {
- // Pass the frame to the user
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockTransfer(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Transfer frame");
- }
- }
- return BT_SUCCESS;
- CANTS_CALLBACK_ERROR:
- CANTS_HANDLING_ERROR:
- return BT_FAIL;
- }
- /**
- * Handles incoming Set Block abort frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_ABORT*: A pointer to the Set Block session abort frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingSetBlockAbort(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If this object needs to handle the abort frame
- if (bCANTS_SetBlockBusy)
- {
- // Ensure there is enough space within the queue
- EH_ASSERT((iCANTS_SetBlockPendingAborts + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Set Block Pending Abort queue is full");
- // Get a pointer to the element within the queue
- tsCANTS_FRAME_SET_BLOCK_ABORT* ptsElementPointer = &(atsCANTS_SetBlockPendingAborts[iCANTS_SetBlockPendingAborts]);
- // Copy the bytes of the frame into the queue
- for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_SET_BLOCK_ABORT); ++iByteIndex)
- {
- ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
- }
- // Increment the number of elements within the queue
- ++iCANTS_SetBlockPendingAborts;
- }
- // Else pass the frame to the user
- else
- {
- // If the callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnSetBlockAbort != 0U)
- {
- // Pass the frame to the callback
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockAbort(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Abort frame");
- }
- }
- return BT_SUCCESS;
- CANTS_CALLBACK_ERROR:
- CANTS_HANDLING_ISSUE:
- return BT_FAIL;
- }
- /**
- * Handles incoming Set Block status request frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*: A pointer to the Set Block Session report
- * request frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingSetBlockStatusRequest(tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If this object needs to handle the status request frame
- if (bCANTS_SetBlockBusy)
- {
- // Ensure there is enough space within the queue
- EH_ASSERT((iCANTS_SetBlockPendingStatusRequests + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Set Block Pending Status Requests queue is full");
- // Get a pointer to the element within the queue to write the bytes to
- tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsElementPointer = &(atsCANTS_SetBlockPendingStatusRequests[iCANTS_SetBlockPendingStatusRequests]);
- // Copy the bytes to the queue
- for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST); ++iByteIndex)
- {
- ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
- }
- // Increment the number of elements within the queue
- ++iCANTS_SetBlockPendingStatusRequests;
- }
- // Else pass the frame to the user
- else
- {
- // If the callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnSetBlockStatusRequest != 0U)
- {
- // Pass the frame to the callback
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockStatusRequest(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Status Request frame");
- }
- }
- return BT_SUCCESS;
- CANTS_HANDLING_ISSUE:
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Handles incoming Set Block status report frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*: A pointer to the Set Block status report
- * frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingSetBlockStatusReport(tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If this object needs to handle the status report frame
- if (bCANTS_SetBlockBusy)
- {
- // Ensure there is enough space within the queue
- EH_ASSERT((iCANTS_SetBlockPendingStatusReports + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Set Block Status Report queue is full");
- // Get a pointer to the queue element to copy the frame bytes to
- tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsElementPointer = &(atsCANTS_SetBlockPendingStatusReports[iCANTS_SetBlockPendingStatusReports]);
- // Copy the bytes of the frame into the queue
- for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(iCANTS_SetBlockPendingStatusReports); ++iByteIndex)
- {
- ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
- }
- // Increment the number of elements within the queue
- ++iCANTS_SetBlockPendingStatusReports;
- }
- // Else we need to pass the frame to the user
- else
- {
- // If the callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnSetBlockStatusReport != 0U)
- {
- // Pass the status report frame to the callback
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockStatusReport(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Status Report frame");
- }
- }
- return BT_SUCCESS;
- CANTS_HANDLING_ISSUE:
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Handles incoming Get Block request frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_REQUEST*: A pointer to the Get Block request frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingGetBlockRequest(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If there is currently an ongoing Get Block transaction
- if (bCANTS_GetBlockBusy)
- {
- // Reject the request
- teFuncStatus = CANTS_RejectGetBlockRequest(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to reject Get Block Request");
- }
- // Else handle the request
- else
- {
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnGetBlockRequest != 0U)
- {
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockRequest(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Request frame");
- }
- // Else no callback has been assigned so automatically reject the request
- else
- {
- teFuncStatus = CANTS_RejectGetBlockRequest(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to reject Get Block Request");
- }
- }
- return BT_SUCCESS;
- CANTS_HANDLING_ISSUE:
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Handles incoming Get Block acknowledgement frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*: A pointer to a Get Block acknowledgement
- * frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingGetBlockAcknowledgement(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If this object needs to handle the acknowledgement frame
- if(bCANTS_GetBlockBusy)
- {
- // Ensure there is enough space within the queue
- EH_ASSERT((iCANTS_GetBlockPendingAcknowledgements + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Get Block Acknowledgement queue is full");
- // Get a pointer to the queue element to copy the frame to
- tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsElementPointer = &(atsCANTS_GetBlockPendingAcknowledgements[iCANTS_GetBlockPendingAcknowledgements]);
- // Copy the bytes of the frame into the queue element
- for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(iCANTS_GetBlockPendingAcknowledgements); ++iByteIndex)
- {
- ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
- }
- // Increment the number of frames within the queue
- ++iCANTS_GetBlockPendingAcknowledgements;
- }
- // Else we need to pass the frame to the user
- else
- {
- // If the callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnGetBlockAcknowledgement != 0U)
- {
- // Pass the frame to the callback
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockAcknowledgement(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Acknowledgement frame");
- }
- }
- return BT_SUCCESS;
- CANTS_HANDLING_ISSUE:
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Handles incoming Get Block start frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_START*: A pointer to the Get Block start transfer frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingGetBlockStart(tsCANTS_FRAME_GET_BLOCK_START* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If the object needs to handle the start frame
- if (bCANTS_GetBlockBusy)
- {
- // Ensure there is enough space within the queue
- EH_ASSERT((iCANTS_GetBlockPendingStarts + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Get Block Pending Starts queue is full");
- // Get a pointer to the queue element to copy the frame to
- tsCANTS_FRAME_GET_BLOCK_START* ptsElementPointer = &(atsCANTS_GetBlockPendingStarts[iCANTS_GetBlockPendingStarts]);
- // Copy the bytes of the frame into the queue
- for (tUINT8 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_GET_BLOCK_START); ++iByteIndex)
- {
- ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
- }
- // Increment the number of elements which are in the queue
- ++iCANTS_GetBlockPendingStarts;
- }
- // Else pass the frame to the user
- else
- {
- // If the callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnGetBlockStart != 0U)
- {
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockStart(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Start frame");
- }
- }
- return BT_SUCCESS;
- CANTS_HANDLING_ISSUE:
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Handles incoming Get Block data transfer frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_TRANSFER*: A pointer to the Get Block transaction transfer
- * frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingGetBlockTransfer(tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If this object needs to handle the transfer frame
- if (bCANTS_GetBlockBusy)
- {
- // Ensure there is enough space within the queue
- EH_ASSERT((iCANTS_GetBlockPendingTransfers + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Get Block Pending Transfers queue is full");
- // Get a pointer to the queue element to copy the frame to
- tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsElementPointer = &(atsCANTS_GetBlockPendingTransfers[iCANTS_GetBlockPendingTransfers]);
- // Copy the bytes of the frame into the queue
- for (tUINT8 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_GET_BLOCK_TRANSFER); ++iByteIndex)
- {
- ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
- }
- // Increment the number of elements which are in the queue
- ++iCANTS_GetBlockPendingTransfers;
- }
- // Else pass the transfer frame to the user
- else
- {
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnGetBlockTransfer != 0U)
- {
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockTransfer(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Transfer frame");
- }
- }
- return BT_SUCCESS;
- CANTS_HANDLING_ISSUE:
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * Handles incoming Get Block abort frames.
- * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
- * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
- * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
- * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_ABORT*: A pointer to the Get Block transaction abort frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_HandleIncomingGetBlockAbort(tsCANTS_FRAME_GET_BLOCK_ABORT* ptsFrame)
- {
- teFUNC_STATUS teFuncStatus = BT_FAIL;
- // If this object needs to handle the abort frame
- if (bCANTS_GetBlockBusy)
- {
- // Ensure there is enough space within the queue
- EH_ASSERT((iCANTS_GetBlockPendingAborts + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Get Block Pending Aborts queue is full");
- // Get a pointer to the queue element to copy the frame to
- tsCANTS_FRAME_GET_BLOCK_ABORT* ptsElementPointer = &(atsCANTS_GetBlockPendingAborts[iCANTS_GetBlockPendingAborts]);
- // Copy the bytes of the frame into the queue
- for (tUINT8 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_GET_BLOCK_ABORT); ++iByteIndex)
- {
- ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
- }
- // Increment the number of elements which are in the queue
- ++iCANTS_GetBlockPendingAborts;
- }
- // Else pass the abort frame to the user
- else
- {
- // If a callback has been assigned
- if (tsCANTS_Configuration.funcCallbackOnGetBlockAbort != 0U)
- {
- teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockAbort(ptsFrame);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Abort frame");
- }
- }
- return BT_SUCCESS;
- CANTS_HANDLING_ISSUE:
- CANTS_CALLBACK_ERROR:
- return BT_FAIL;
- }
- /**
- * This flips the endianness of the given value. The point of this function is to assign it to the
- * function pointers to go between Native Endianness <-> Little Endian based on the platform.
- * @returns BT_SUCCESS always
- * @param piValue: tUINT64*:
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_FlipEndianness(tUINT64* piValue)
- {
- // The value of this will eventually be the input value but with its endianness flipped
- tUINT64 iFlipped = 0U;
- tUINT64 iOriginal = *piValue;
- // Move the last 4 bytes to the first 4 bytes in reverse order
- iFlipped |= (iOriginal & (tUINT64)0x00000000000000FF) << 56;
- iFlipped |= (iOriginal & (tUINT64)0x000000000000FF00) << 40;
- iFlipped |= (iOriginal & (tUINT64)0x0000000000FF0000) << 24;
- iFlipped |= (iOriginal & (tUINT64)0x00000000FF000000) << 8;
- // Move the first 4 bytes to the last 4 bytes in reverse order
- iFlipped |= (iOriginal & (tUINT64)0x000000FF00000000) >> 8;
- iFlipped |= (iOriginal & (tUINT64)0x0000FF0000000000) >> 24;
- iFlipped |= (iOriginal & (tUINT64)0x00FF000000000000) >> 40;
- iFlipped |= (iOriginal & (tUINT64)0xFF00000000000000) >> 56;
- // Assign the new value
- *piValue = iFlipped;
- return BT_SUCCESS;
- }
- /**
- * This function will do nothing with the value. The point of this function is to assign it to the
- * function pointers to go between Native Endianness <-> Little Endian based on the platform.
- * @returns BT_SUCCESS always
- * @param piValue: tUINT64*:
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_DoNotFlipEndianness(tUINT64* piValue)
- {
- // Remove compiler warning for unused value
- (void)piValue;
- return BT_SUCCESS;
- }
- /**
- * Translates a Telemetry Request frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsTelecommandRequest: tsCANTS_FRAME_TELECOMMAND_REQUEST*: The telemetry request frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameTelecommandRequestToGeneric(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsTelecommandRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- /* Copy the data */
- ptsGenericFrame->iDataLength = ptsTelecommandRequest->iDataLength;
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ptsTelecommandRequest->acData[iByteIndex];
- }
- /* Populate the identifiers */
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsTelecommandRequest->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTelecommandRequest->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TELECOMMAND;
- ptsGenericFrame->tsIdentifiers.iCommand = ((CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST << 8) | ptsTelecommandRequest->iChannel);
- return BT_SUCCESS;
- }
- /**
- * Translates a Telecommand Acknowledgement frame to a Generic frame.
- * @returns BT_SUCCESS always
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsTelecommandAcknowledgement: tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*: The telecommand
- * acknowledgement frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameTelecommandAcknowledgementToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsTelecommandAcknowledgement)
- {
- /* Populate the fields */
- // The acknowledgement never contains any data
- ptsGenericFrame->iDataLength = 0U;
- // Get the value of the subtype
- tUINT8 iSubtypeValue = 0U;
- if (ptsTelecommandAcknowledgement->teAcknowledgement == CANTS_POSITIVE_ACKNOWLEDGEMENT)
- {
- iSubtypeValue = CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT;
- }
- else
- {
- iSubtypeValue = CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT;
- }
- ptsGenericFrame->tsIdentifiers.iCommand = ((iSubtypeValue << 8) | ptsTelecommandAcknowledgement->iChannel);
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsTelecommandAcknowledgement->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTelecommandAcknowledgement->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TELECOMMAND;
- return BT_SUCCESS;
- }
- /**
- * Translates a Telemetry Request frame to a Generic frame.
- * @returns BT_SUCCESS always
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsTelemetryRequest: tsCANTS_FRAME_TELEMETRY_REQUEST*: The telemetry request frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameTelemetryRequestToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_REQUEST* ptsTelemetryRequest)
- {
- /* Populate the fields */
- // Telemetry requests never contain any data
- ptsGenericFrame->iDataLength = 0U;
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsTelemetryRequest->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTelemetryRequest->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TELEMETRY_REQUEST;
- ptsGenericFrame->tsIdentifiers.iCommand = ((CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST << 8) | ptsTelemetryRequest->iChannel);
- return BT_SUCCESS;
- }
- /**
- * Translates a Telemetry Acknowledgement frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsTelemetryAcknowledgement: tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*: The telemetry
- * acknowledgement frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameTelemetryAcknowledgementToGeneric(tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsTelemetryAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- /* Populate the fields */
- tUINT8 iSubtypeValue = 0U;
- // If it's a positive telemetry request with data
- if (ptsTelemetryAcknowledgement->teAcknowledgement == CANTS_POSITIVE_ACKNOWLEDGEMENT)
- {
- ptsGenericFrame->iDataLength = ptsTelemetryAcknowledgement->iDataLength;
- // Copy the data
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsTelemetryAcknowledgement->iDataLength; ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ptsTelemetryAcknowledgement->acData[iByteIndex];
- }
- iSubtypeValue = CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT;
- }
- else
- {
- // Negative acknowledgement frames contain no data
- ptsGenericFrame->iDataLength = 0U;
- iSubtypeValue = CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT;
- }
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsTelemetryAcknowledgement->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTelemetryAcknowledgement->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TELEMETRY_REQUEST;
- ptsGenericFrame->tsIdentifiers.iCommand = ((iSubtypeValue << 8) | ptsTelemetryAcknowledgement->iChannel);
- return BT_SUCCESS;
- }
- /**
- * Translates an Unsolicited Telemetry frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsUnsolicitedTelemetry: tsCANTS_FRAME_UNSOLICITED_TELEMETRY*: The unsolicited telemetry
- * frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameUnsolicitedTelemetryToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsUnsolicitedTelemetry)
- {
- /* Populate the fields */
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsUnsolicitedTelemetry->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsUnsolicitedTelemetry->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY;
- ptsGenericFrame->tsIdentifiers.iCommand = ((CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY << 8) | ptsUnsolicitedTelemetry->iChannel);
- // Copy the data of the frame
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsUnsolicitedTelemetry->iDataLength; ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ptsUnsolicitedTelemetry->acData[iByteIndex];
- }
- ptsGenericFrame->iDataLength = ptsUnsolicitedTelemetry->iDataLength;
- return BT_SUCCESS;
- }
- /** TODO: Add exception CANTS_TRANSLATE_ERROR to EA
- * Translates a Time Synchronisation frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsTimeSynchronisation: tsCANTS_FRAME_TIME_SYNCHRONISATION*: The time synchronisation frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameTimeSynchronisationToGeneric(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsTimeSynchronisation, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- /* Populate the fields */
- // Time synchronisation frame To Address is always 0
- ptsGenericFrame->tsIdentifiers.iToAddress = 0U;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTimeSynchronisation->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TIME_SYNCHRONISATION;
- ptsGenericFrame->tsIdentifiers.iCommand = 0U; // Unused but this is to make sure it's initialised to something
- // Data length is always 8 bytes to contain the timestamp
- ptsGenericFrame->iDataLength = 8U;
- // Get the time as Little Endian
- tUINT64 iLittleEndianTime = ptsTimeSynchronisation->iTime;
- teFUNC_STATUS teFuncStatus = funcCANTS_NativeEndiannessToLittleEndian(&iLittleEndianTime);
- EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to set the time endainness");
- // Copy the bytes of the timestamp
- for (tUINT32 iByteIndex = 0U; iByteIndex < 8U; ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)(&iLittleEndianTime))[iByteIndex];
- }
- return BT_SUCCESS;
- CANTS_TRANSLATE_ERROR:
- return BT_FAIL;
- }
- /**
- * Translates a Set Block Request frame to a Generic frame.
- * @returns BT_SUCCESS.
- * @param ptsSetBlockRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The set block request frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameSetBlockRequestToGeneric(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsSetBlockRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- /* Populate the fields */
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockRequest->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockRequest->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST << 7) | ptsSetBlockRequest->iNumberOfBlocks;
- // Copy the data of the frame
- for (tUINT32 iByteIndex = 0U; iByteIndex < (tUINT32)ptsSetBlockRequest->teAddressSize; ++iByteIndex)
- {
- // TODO: Check the logic for this because the data might not be stored correctly in memory
- ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)&ptsSetBlockRequest->iStartAddress)[iByteIndex];
- }
- ptsGenericFrame->iDataLength = (tUINT8)ptsSetBlockRequest->teAddressSize;
- return BT_SUCCESS;
- }
- /**
- * Translates a Set Block Acknowledgement frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsSetBlockAcknowledgement: tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*: The set block
- * acknowledgement frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameSetBlockAcknowledgementToGeneric(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockAcknowledgement->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockAcknowledgement->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
- // The data bytes are only used for a positive acknowledgement
- if (ptsSetBlockAcknowledgement->teAcknowledgement == CANTS_POSITIVE_ACKNOWLEDGEMENT)
- {
- ptsGenericFrame->iDataLength = ptsSetBlockAcknowledgement->iDataLength;
- // Copy each byte
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsSetBlockAcknowledgement->iDataLength; ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ptsSetBlockAcknowledgement->acData[iByteIndex];
- }
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT << 7) | ptsSetBlockAcknowledgement->iCommand;
- }
- else
- {
- // A negative acknowledgement has no data
- ptsGenericFrame->iDataLength = 0U;
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT << 7);
- }
- return BT_SUCCESS;
- }
- /**
- * Translates a Set Block Transfer frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsSetBlockTransfer: tsCANTS_FRAME_SET_BLOCK_TRANSFER*: The set block transfer frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameSetBlockTransferToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsSetBlockTransfer)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockTransfer->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockTransfer->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER << 7) | ptsSetBlockTransfer->iSequence;
- // Copy the transfer data
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsSetBlockTransfer->iDataLength; ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ptsSetBlockTransfer->acData[iByteIndex];
- }
- return BT_SUCCESS;
- }
- /**
- * Translates a Set Block Abort frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsSetBlockAbort: tsCANTS_FRAME_SET_BLOCK_ABORT*: The set block abort frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameSetBlockAbortToGeneric(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsSetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockAbort->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockAbort->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT << 7);
- // Abort frame contains no data
- ptsGenericFrame->iDataLength = 0U;
- return BT_SUCCESS;
- }
- /**
- * Translates a Set Block Status Request frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsSetBlockStatusRequest: tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*: The set block status
- * request
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameSetBlockStatusRequestToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsSetBlockStatusRequest)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockStatusRequest->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockStatusRequest->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST << 7);
- // Status request frame contains no data
- ptsGenericFrame->iDataLength = 0U;
- return BT_SUCCESS;
- }
- /**
- * Translates a Set Block Status Report frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsSetBlockStatusReport: tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*: The set block status report
- * frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameSetBlockStatusReportToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsSetBlockStatusReport)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockStatusReport->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockStatusReport->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
- // The command contains a flag specifying if the transfer is complete
- // Even if the bitfield is all 1 - meaning all blocks have been received - 'complete' can be 0 indicating the receiving node is still processing it
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT << 7) | ptsSetBlockStatusReport->bComplete;
- // Copy the bitfield into the data section of the frame
- for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(ptsSetBlockStatusReport->iBlocksReceived); ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)&ptsSetBlockStatusReport->iBlocksReceived)[iByteIndex];
- }
- return BT_SUCCESS;
- }
- /**
- * Translates a Get Block Request frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsGetBlockRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The get block request frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGetBlockRequestToGeneric(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsGetBlockRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockRequest->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockRequest->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST << 7) | ptsGetBlockRequest->iNumberOfBlocks;
- // Copy the address
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGetBlockRequest->teAddressSize; ++iByteIndex)
- {
- // TODO: Check that address is stored correctly in memory for when we index into it
- ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)&ptsGetBlockRequest->teAddressSize)[iByteIndex];
- }
- return BT_SUCCESS;
- }
- /**
- * Translates a Get Block Acknowledgement frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsGetBlockAcknowledgement: tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*: The get block
- * acknowledgement frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGetBlockAcknowledgementToGeneric(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsGetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockAcknowledgement->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockAcknowledgement->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
- if (ptsGetBlockAcknowledgement->teAcknowledgement == CANTS_POSITIVE_ACKNOWLEDGEMENT)
- {
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT << 7) | ptsGetBlockAcknowledgement->iCommand;
- // Copy the data
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGetBlockAcknowledgement->iDataLength; ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ptsGetBlockAcknowledgement->acData[iByteIndex];
- }
- }
- else
- {
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT << 7);
- // A negative acknowledgement never contains any data
- ptsGenericFrame->iDataLength = 0U;
- }
- return BT_SUCCESS;
- }
- /**
- * Translates a Get Block Start frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsGetBlockStart: tsCANTS_FRAME_GET_BLOCK_START*: The get block start frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGetBlockStartToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_START* ptsGetBlockStart)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockStart->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockStart->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_START << 7);
- // Copy the bitfield of blocks to send
- for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(ptsGetBlockStart->iBlocksToGet); ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)&ptsGetBlockStart->iBlocksToGet)[iByteIndex];
- }
- ptsGenericFrame->iDataLength = sizeof(ptsGetBlockStart->iBlocksToGet);
- return BT_SUCCESS;
- }
- /**
- * Translates a Get Block Transfer frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsGetBlockTransfer: tsCANTS_FRAME_GET_BLOCK_TRANSFER*: The get block transfer frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGetBlockTransferToGeneric(tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsGetBlockTransfer, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockTransfer->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockTransfer->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER << 7) | ptsGetBlockTransfer->iSequence;
- // Copy the transfer data
- // The specification states this is always 8 bytes
- for (tUINT32 iByteIndex = 0U; iByteIndex < 8U; ++iByteIndex)
- {
- ptsGenericFrame->acData[iByteIndex] = ptsGetBlockTransfer->acData[iByteIndex];
- }
- // Same as comment above
- ptsGenericFrame->iDataLength = 8U;
- return BT_SUCCESS;
- }
- /**
- * Translates a Get Block Abort frame to a Generic frame.
- * @returns BT_SUCCESS always.
- * @param ptsGetBlockAbort: tsCANTS_FRAME_GET_BLOCK_ABORT*: The get block abort frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGetBlockAbortToGeneric(tsCANTS_FRAME_GET_BLOCK_ABORT* ptsGetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockAbort->iToAddress;
- ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockAbort->iFromAddress;
- ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
- ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT << 7);
- // An abort frame contains no data
- ptsGenericFrame->iDataLength = 0U;
- return BT_SUCCESS;
- }
- /**
- * Translates a Generic frame to a Telecommand request frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsTelecommandRequest: tsCANTS_FRAME_TELECOMMAND_REQUEST*: The telecommand request frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToTelecommandRequest(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsTelecommandRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsTelecommandRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsTelecommandRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- ptsTelecommandRequest->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
- // Copy the telecommand argument data
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ptsTelecommandRequest->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- ptsTelecommandRequest->iDataLength = ptsGenericFrame->iDataLength;
- return BT_SUCCESS;
- }
- /**
- * Translates a Generic frame to a Telecommand Acknowledgement frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsTelecommandAcknowledgement: tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*: The telecommand
- * acknowledgement frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToTelecommandAcknowledgement(tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsTelecommandAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsTelecommandAcknowledgement->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsTelecommandAcknowledgement->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- ptsTelecommandAcknowledgement->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
- // If the frame subtype is a positive telecommand acknowledgement
- if ((ptsGenericFrame->tsIdentifiers.iCommand >> 8) == CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT)
- {
- ptsTelecommandAcknowledgement->teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
- }
- else
- {
- ptsTelecommandAcknowledgement->teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
- }
- return BT_SUCCESS;
- }
- /**
- * Translates a Generic frame to a Telemetry request frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsTelemetryRequest: tsCANTS_FRAME_TELEMETRY_REQUEST*: The telemetry request frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToTelemetryRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_REQUEST* ptsTelemetryRequest)
- {
- ptsTelemetryRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsTelemetryRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- ptsTelemetryRequest->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
- return BT_SUCCESS;
- }
- /**
- * Translates a Generic frame to a Telemetry Acknowledgement frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsTelemetryAcknowledgement: tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*: The telemetry
- * acknowledgement frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToTelemetryAcknowledgement(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsTelemetryAcknowledgement)
- {
- ptsTelemetryAcknowledgement->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsTelemetryAcknowledgement->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- ptsTelemetryAcknowledgement->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
- // If the subtype is a positive telemetry request acknowledgement
- if ((ptsGenericFrame->tsIdentifiers.iCommand >> 8) == CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT)
- {
- // Copy the telemetry request response data
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ptsTelemetryAcknowledgement->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- // Set the data length
- ptsTelemetryAcknowledgement->iDataLength = ptsGenericFrame->iDataLength;
- ptsTelemetryAcknowledgement->teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
- }
- else
- {
- // A negative acknowledgement contains no data
- ptsTelemetryAcknowledgement->iDataLength = 0U;
- ptsTelemetryAcknowledgement->teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
- }
- return BT_SUCCESS;
- }
- /**
- * Translates a Generic frame to an Unsolicited Telemetry frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsUnsolicitedTelemetry: tsCANTS_FRAME_UNSOLICITED_TELEMETRY*: The unsolicited telemetry
- * frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToUnsolicitedTelemetry(tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsUnsolicitedTelemetry, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsUnsolicitedTelemetry->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsUnsolicitedTelemetry->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- ptsUnsolicitedTelemetry->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
- // Copy the telemetry data
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ptsUnsolicitedTelemetry->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- ptsUnsolicitedTelemetry->iDataLength = ptsGenericFrame->iDataLength;
- return BT_SUCCESS;
- }
- /** TODO: Add exception CANTS_TRANSLATE_ERROR to EA
- * Translates a Generic frame to a Time Synchronisation frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsTimeSynchronisation: tsCANTS_FRAME_TIME_SYNCHRONISATION*: The time synchronisation frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToTimeSynchronisation(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsTimeSynchronisation, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- EH_ASSERT(ptsGenericFrame->iDataLength == 8, CANTS_INVALID_PARAMETER, "A generic time synchronisation frame did not have 8 bytes");
- ptsTimeSynchronisation->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- // The timestamp is always 8 bytes
- for (tUINT32 iByteIndex = 0U; iByteIndex < 8; ++iByteIndex)
- {
- ((tUINT8*)&ptsTimeSynchronisation->iTime)[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- // Convert the time to the native endianness
- teFUNC_STATUS teSetEndianStatus = funcCANTS_LittleEndianToNativeEndianness(&ptsTimeSynchronisation->iTime);
- EH_ASSERT(teSetEndianStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from little endian to native endianness");
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- return BT_FAIL;
- }
- /** TODO: Add exception CANTS_TRANSLATE_ERROR to EA
- * Translates a Generic frame to a Set Block Request frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsSetBlockRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The set block request frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsSetBlockRequest)
- {
- // There must be at least one byte to specify the address
- EH_ASSERT(ptsGenericFrame->iDataLength > 0, CANTS_INVALID_PARAMETER, "A generic set block request had a data length of 0");
- ptsSetBlockRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsSetBlockRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- // 0x3F gets the last 6 bits which is the number of blocks
- ptsSetBlockRequest->iNumberOfBlocks = (ptsGenericFrame->tsIdentifiers.iCommand & 0x3F);
- // Get the address
- tUINT64 iAddressLittleEndian = 0U;
- // Copy the address bytes into the address variable keeping in mind that it's stored as little endian
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- iAddressLittleEndian |= (((tUINT64)ptsGenericFrame->acData[iByteIndex]) << (8 * iByteIndex));
- }
- // Assign the address but then flip it to native endianness
- ptsSetBlockRequest->iStartAddress = iAddressLittleEndian;
- teFUNC_STATUS teFlipEndianStatus = funcCANTS_LittleEndianToNativeEndianness(&ptsSetBlockRequest->iStartAddress);
- EH_ASSERT(teFlipEndianStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to flip address to native endianness");
- ptsSetBlockRequest->teAddressSize = (teCANTS_ADDRESS_SIZE)ptsGenericFrame->iDataLength;
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- return BT_FAIL;
- }
- /** TODO: Remove exception CANTS_INVALID_PARAMETER from EA
- * Translates a Generic frame to a Set Block Acknowledgement frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsSetBlockAcknoledgement: tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*: The set block
- * acknowledgement frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockAcknowledgement(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknoledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsSetBlockAcknoledgement->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsSetBlockAcknoledgement->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- // 0x7F are the last 7 bits which need is a copy of the set block request command
- ptsSetBlockAcknoledgement->iCommand = (ptsGenericFrame->tsIdentifiers.iCommand & 0x7F);
- if ((ptsGenericFrame->tsIdentifiers.iCommand >> 7) == CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT)
- {
- ptsSetBlockAcknoledgement->teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
- ptsSetBlockAcknoledgement->iDataLength = ptsGenericFrame->iDataLength;
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ptsSetBlockAcknoledgement->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- }
- else
- {
- ptsSetBlockAcknoledgement->teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
- // A negative acknowledgement contains no data
- ptsSetBlockAcknoledgement->iDataLength = 0U;
- }
- return BT_SUCCESS;
- }
- /**
- * Translates a Generic frame to a Set Block Transfer frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsSetBlockTransferFrame: tsCANTS_FRAME_SET_BLOCK_TRANSFER*: The set block transfer frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockTransfer(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsSetBlockTransferFrame)
- {
- EH_ASSERT(ptsGenericFrame->iDataLength > 0U, CANTS_INVALID_PARAMETER, "A set block transfer contained 0 bytes");
- ptsSetBlockTransferFrame->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsSetBlockTransferFrame->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- // 0x3F is the last 6 bits which is the block sequence
- ptsSetBlockTransferFrame->iSequence = (ptsGenericFrame->tsIdentifiers.iCommand & 0x3F);
- // Copy the block data
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ptsSetBlockTransferFrame->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- ptsSetBlockTransferFrame->iDataLength = ptsGenericFrame->iDataLength;
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- return BT_FAIL;
- }
- /**
- * Translates a Generic frame to a Set Block Abort frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsSetBlockAbort: tsCANTS_FRAME_SET_BLOCK_ABORT*: The set block abort frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockAbort(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsSetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsSetBlockAbort->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsSetBlockAbort->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- return BT_SUCCESS;
- }
- /**
- * Translates a Generic frame to a Set Block Status Request frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsSetBlockStatusRequest: tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*: The set block status
- * request frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockStatusRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsSetBlockStatusRequest)
- {
- ptsSetBlockStatusRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsSetBlockStatusRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- return BT_SUCCESS;
- }
- /**
- * Translates a Generic frame to a Set Block Status Report frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsSetBlockStatusReport: tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*: The set block status report
- * frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockStatusReport(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsSetBlockStatusReport)
- {
- // The status report needs at least one byte
- EH_ASSERT(ptsGenericFrame->iDataLength > 0, CANTS_INVALID_PARAMETER, "A set block status report contained 0 bytes");
- ptsSetBlockStatusReport->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsSetBlockStatusReport->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- // All are assumed zero except the ones actually given in the data
- ptsSetBlockStatusReport->iBlocksReceived = 0U;
- // Copy the bitfield
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ((tUINT8*)&ptsSetBlockStatusReport->iBlocksReceived)[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- // 0x40 is the 'is complete' bit
- ptsSetBlockStatusReport->bComplete = (tBOOL)((ptsGenericFrame->tsIdentifiers.iCommand & 0x40) >> 6);
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- return BT_FAIL;
- }
- /** TODO: Add exception CANTS_TRANSLATE_ERROR to EA
- * Translates a Generic frame to a Get Block Request frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsGetBlockRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The get block request frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsGetBlockRequest)
- {
- // Ensure there's at least 1 byte for the start address
- EH_ASSERT(ptsGenericFrame->iDataLength > 0U, CANTS_INVALID_PARAMETER, "A get block request had 0 data bytes");
- ptsGetBlockRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsGetBlockRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- // 0x3F is the last six bits which the number of blocks
- ptsGetBlockRequest->iNumberOfBlocks = (ptsGenericFrame->tsIdentifiers.iCommand & 0x3F);
- ptsGetBlockRequest->teAddressSize = (teCANTS_ADDRESS_SIZE)ptsGenericFrame->iDataLength;
- // Assign the address as zero to begin with
- ptsGetBlockRequest->iStartAddress = 0U;
- // Copy the bytes keeping in mind it's little endian
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ptsGetBlockRequest->iStartAddress |= (((tUINT64)ptsGenericFrame->acData[iByteIndex]) << (8 * iByteIndex));
- }
- // Flip the endianness to native
- teFUNC_STATUS teFlipEndianStatus = funcCANTS_LittleEndianToNativeEndianness(&(ptsGetBlockRequest->iStartAddress));
- EH_ASSERT(teFlipEndianStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to flip get block request address endianness");
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- CANTS_TRANSLATE_ERROR:
- return BT_FAIL;
- }
- /**
- * Translates a Generic frame to a Get Block Acknowledgement frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGetBlockAcknowledgement: tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*: The get block
- * acknowledgement frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockAcknowledgement(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsGetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- ptsGetBlockAcknowledgement->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsGetBlockAcknowledgement->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- // If the get block acknowledgement was positive
- if ((ptsGenericFrame->tsIdentifiers.iCommand >> 7) == CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT)
- {
- ptsGetBlockAcknowledgement->teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
- // Copy the acknowledgement response
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ptsGetBlockAcknowledgement->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- ptsGetBlockAcknowledgement->iDataLength = ptsGenericFrame->iDataLength;
- }
- else
- {
- ptsGetBlockAcknowledgement->teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
- // Negative acknowledgements have zero bytes
- ptsGetBlockAcknowledgement->iDataLength = 0U;
- }
- return BT_SUCCESS;
- }
- /**
- * Translates a Generic frame to a Get Block Start frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGetBlockStart: tsCANTS_FRAME_GET_BLOCK_START*: The get block start frame
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockStart(tsCANTS_FRAME_GET_BLOCK_START* ptsGetBlockStart, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
- {
- // Ensure there's at least 1 byte for the bitmap
- EH_ASSERT(ptsGenericFrame->iDataLength > 0U, CANTS_INVALID_PARAMETER, "Get block start frame had 0 bytes");
- ptsGetBlockStart->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsGetBlockStart->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- ptsGetBlockStart->iBlocksToGet = 0U;
- // Copy the bitmap of blocks to send
- for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
- {
- ((tUINT8*)&ptsGetBlockStart->iBlocksToGet)[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- return BT_FAIL;
- }
- /**
- * Translates a Generic frame to a Get Block Transfer frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsGetBlockTransfer: tsCANTS_FRAME_GET_BLOCK_TRANSFER*: The get block transfer frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockTransfer(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsGetBlockTransfer)
- {
- // The standard says all get block transfers need to be 8 bytes
- EH_ASSERT(ptsGenericFrame->iDataLength == 8, CANTS_INVALID_PARAMETER, "Get block transfer did not contain 8 bytes");
- ptsGetBlockTransfer->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsGetBlockTransfer->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- // 0x3F is the last 6 bits which is the block sequence
- ptsGetBlockTransfer->iSequence = (ptsGenericFrame->tsIdentifiers.iCommand & 0x3F);
- // Copy the transfer data
- for (tUINT32 iByteIndex = 0U; iByteIndex < 8; ++iByteIndex)
- {
- ptsGetBlockTransfer->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
- }
- return BT_SUCCESS;
- CANTS_INVALID_PARAMETER:
- return BT_FAIL;
- }
- /**
- * Translates a Generic frame to a Get Block Abort frame.
- * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
- * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
- * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
- * @param ptsGetBlockAbort: tsCANTS_FRAME_GET_BLOCK_ABORT*: The get block abort frame
- * @re-entrant:
- */
- #ifndef UNIT_TEST
- static
- #endif /* UNIT_TEST */
- teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockAbort(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_ABORT* ptsGetBlockAbort)
- {
- ptsGetBlockAbort->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
- ptsGetBlockAbort->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
- return BT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement