Advertisement
SolarisFalls

Untitled

Mar 2nd, 2025
384
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 209.05 KB | None | 0 0
  1. /***********************************************************************************
  2.  *  @file CANTS_CANTSProtocol.c
  3.  ***********************************************************************************
  4.  *   _  _____ ____  ____  _____
  5.  *  | |/ /_ _/ ___||  _ \| ____|
  6.  *  | ' / | |\___ \| |_) |  _|  
  7.  *  | . \ | | ___) |  __/| |___
  8.  *  |_|\_\___|____/|_|   |_____|
  9.  *
  10.  ***********************************************************************************
  11.  *  Copyright (c) 2024 KISPE Space Systems Ltd.
  12.  *  
  13.  *  
  14.  ***********************************************************************************
  15.  *  Created on: 07-Aug-2024 15:06:18                      
  16.  *  Implementation of the Class CANTS_CANTSProtocol      
  17.  *  @author: Charlie Gallie                    
  18.  ***********************************************************************************/
  19.  
  20. #include "CANTS_CANTSProtocol.h"
  21.  
  22. // If CANTS defined its own EH_ASSERT macro
  23. #ifdef CANTS_DEFINED_EH_ASSERT
  24.  
  25. // Define the callback used for logging error messages
  26. void (*funcCANTS_LogErrorMessage)(const char*) = 0U;
  27.  
  28. #endif // ifdef CANTS_DEFINED_EH_ASSERT
  29.  
  30. /**
  31.  * This class is a CAN-TS implementation. The user must provide callback functions
  32.  * for things such as transmitting a CAN frame, getting the time, etc.
  33.  * These callbacks do not need to have a realisation of CAN-TS, they must only be
  34.  * able to transceive CAN2.0B Extended frames.
  35.  * Due to this object being platform and schedule agnostic, it is the
  36.  * responsibility of this object to handle timeouts, such as when you send a
  37.  * telecommand request. This object has no notion of expecting a response or
  38.  * having the ability to timeout.
  39.  */
  40.  
  41. /* PRIVATE ATTRIBUTES */
  42.  
  43. /**
  44.  * The maximum buffer size of pending frames during a transaction where
  45.  * responsibility is taken away from the user. When callbacks to the user are
  46.  * disabled, frames which need handled will instead be queued for this CAN-TS
  47.  * Object to handle. This value is the maximum number of frames in each of these
  48.  * queues.
  49.  */
  50. #define CANTS_PENDING_FRAMES_QUEUE_SIZE (3U)
  51. /**
  52.  * This is used to disable the Set Block callbacks while a Set Block transaction
  53.  * is ongoing, as well as some basic, not 100% reliable, thread safety when
  54.  * calling CANTS_SetBlock(...). The user is expected to provide their own thread
  55.  * safety when calling that function but this can be used as a sanity check. While
  56.  * this value is true and callbacks are not being called, all frames are queued
  57.  * into their corresponding queue.
  58.  */
  59. static tBOOL bCANTS_SetBlockBusy = FALSE;
  60. /**
  61.  * The number of pending Set Block acknowledgements while there is a Set Block
  62.  * transaction ongoing, initiated from CANTS_SetBlock(...). This represents the
  63.  * queued frames within atsSetBlockPendingAcknowledgements.
  64.  */
  65. static tUINT8 iCANTS_SetBlockPendingAcknowledgements = 0U;
  66. /**
  67.  * The number of pending transfer frames in the queue.
  68.  */
  69. static tUINT8 iCANTS_SetBlockPendingTransfers = 0U;
  70. /**
  71.  * The number of pending report frames within the queue.
  72.  */
  73. static tUINT8 iCANTS_SetBlockPendingStatusReports = 0U;
  74. /**
  75.  * This is used while CANTS_SetBlock(...) is within a transaction. While callbacks
  76.  * to the user are blocked, acknowledgement frames will be queued into here to
  77.  * later be handled by CANTS_SetBlock(...).
  78.  */
  79. static tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT atsCANTS_SetBlockPendingAcknowledgements[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
  80. /**
  81.  * This is used while CANTS_SetBlock(...) is within a transaction. While callbacks
  82.  * to the user are blocked, transfer frames will be queued into here to later be
  83.  * handled by CANTS_SetBlock(...).
  84.  */
  85. static tsCANTS_FRAME_SET_BLOCK_TRANSFER atsCANTS_SetBlockPendingTransfers[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
  86. /**
  87.  * This is used while CANTS_SetBlock(...) has an ongoing transfer and callbacks to
  88.  * the user are blocked. Incoming transfer status reports are queued into here to
  89.  * be handled by CANTS_SetBlock(...).
  90.  */
  91. static tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT atsCANTS_SetBlockPendingStatusReports[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
  92. /**
  93.  * This is the current configuration of the CAN-TS object. This is assigned within
  94.  * the Initialisation function, but the values can be modified via function calls
  95.  * during later execution.
  96.  */
  97. static tsCANTS_CONFIGURATION tsCANTS_Configuration = { 0U };
  98. /**
  99.  * A function pointer assigned at initialisation. This function will either flip
  100.  * or not flip the endianness based on the platform.
  101.  * @returns BT_SUCCESS always
  102.  */
  103. teFUNC_STATUS (*funcCANTS_LittleEndianToNativeEndianness)(tUINT64*) = 0U;
  104. /**
  105.  * A function pointer assigned at initialisation. This function will either flip
  106.  * or not flip the endianness based on the platform.
  107.  * @returns BT_SUCCESS always
  108.  */
  109. teFUNC_STATUS (*funcCANTS_NativeEndiannessToLittleEndian)(tUINT64*) = 0U;
  110. /**
  111.  * The number of queued Set Block Status Request frames
  112.  */
  113. static tUINT8 iCANTS_SetBlockPendingStatusRequests = 0U;
  114. /**
  115.  * The queue of pending Set Block Status Requests
  116.  */
  117. static tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST atsCANTS_SetBlockPendingStatusRequests[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
  118. /**
  119.  * This is assigned to true while there is an ongoing Get Block transaction. While
  120.  * this is true, user callbacks are disabled and any incoming frames used for Get
  121.  * Block transactions are buffered into their respective queues.
  122.  */
  123. static tBOOL bCANTS_GetBlockBusy = FALSE;
  124. /**
  125.  * The number of queued Set Block Abort frames
  126.  */
  127. static tUINT8 iCANTS_SetBlockPendingAborts = 0U;
  128. /**
  129.  * The queue of pending Set Block Abort frames
  130.  */
  131. static tsCANTS_FRAME_SET_BLOCK_ABORT atsCANTS_SetBlockPendingAborts[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
  132. /**
  133.  * The number of queued Get Block acknowledgements
  134.  */
  135. static tUINT8 iCANTS_GetBlockPendingAcknowledgements = 0U;
  136. /**
  137.  * The queue of pending Get Block acknowledgement frames
  138.  */
  139. static tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT atsCANTS_GetBlockPendingAcknowledgements[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
  140. /**
  141.  * The number of pending Get Block start frames
  142.  */
  143. static tUINT8 iCANTS_GetBlockPendingStarts = 0U;
  144. /**
  145.  * The queue of pending Get Block start frames
  146.  */
  147. static tsCANTS_FRAME_GET_BLOCK_START atsCANTS_GetBlockPendingStarts[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
  148. /**
  149.  * The number of pending Get Block transfer frames
  150.  */
  151. static tUINT8 iCANTS_GetBlockPendingTransfers = 0U;
  152. /**
  153.  * The queue of pending Get Block transfer frames
  154.  */
  155. static tsCANTS_FRAME_GET_BLOCK_TRANSFER atsCANTS_GetBlockPendingTransfers[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
  156. /**
  157.  * The number of pending Get Block abort frames
  158.  */
  159. static tUINT8 iCANTS_GetBlockPendingAborts = 0U;
  160. /**
  161.  * The pending Get Block abort frames
  162.  */
  163. static tsCANTS_FRAME_GET_BLOCK_ABORT atsCANTS_GetBlockPendingAborts[CANTS_PENDING_FRAMES_QUEUE_SIZE] = { 0U };
  164.  
  165. /* PRIVATE FUNCTIONS */
  166.  
  167. #ifndef UNIT_TEST
  168.  
  169. static teFUNC_STATUS CANTS_HandleIncomingTelecommandRequest(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsFrame);
  170. static teFUNC_STATUS CANTS_HandleIncomingTelecommandAcknowledgement(tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsFrame);
  171. static teFUNC_STATUS CANTS_HandleIncomingTelemetryRequest(tsCANTS_FRAME_TELEMETRY_REQUEST* ptsFrame);
  172. static teFUNC_STATUS CANTS_HandleIncomingTelemetryAcknowledgement(tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsFrame);
  173. static teFUNC_STATUS CANTS_HandleIncomingUnsolicitedTelemetry(tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsFrame);
  174. static teFUNC_STATUS CANTS_HandleIncomingTimeSynchronisation(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsFrame);
  175. static teFUNC_STATUS CANTS_HandleIncomingSetBlockRequest(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsFrame);
  176. static teFUNC_STATUS CANTS_HandleIncomingSetBlockAcknowledgement(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsFrame);
  177. static teFUNC_STATUS CANTS_HandleIncomingSetBlockTransfer(tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsFrame);
  178. static teFUNC_STATUS CANTS_HandleIncomingSetBlockAbort(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsFrame);
  179. static teFUNC_STATUS CANTS_HandleIncomingSetBlockStatusRequest(tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsFrame);
  180. static teFUNC_STATUS CANTS_HandleIncomingSetBlockStatusReport(tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsFrame);
  181. static teFUNC_STATUS CANTS_HandleIncomingGetBlockRequest(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsFrame);
  182. static teFUNC_STATUS CANTS_HandleIncomingGetBlockAcknowledgement(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsFrame);
  183. static teFUNC_STATUS CANTS_HandleIncomingGetBlockStart(tsCANTS_FRAME_GET_BLOCK_START* ptsFrame);
  184. static teFUNC_STATUS CANTS_HandleIncomingGetBlockTransfer(tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsFrame);
  185. static teFUNC_STATUS CANTS_HandleIncomingGetBlockAbort(tsCANTS_FRAME_GET_BLOCK_ABORT* ptsFrame);
  186. static teFUNC_STATUS CANTS_FlipEndianness(tUINT64* piValue);
  187. static teFUNC_STATUS CANTS_DoNotFlipEndianness(tUINT64* piValue);
  188. static teFUNC_STATUS CANTS_TranslateFrameTelecommandRequestToGeneric(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsTelecommandRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  189. static teFUNC_STATUS CANTS_TranslateFrameTelecommandAcknowledgementToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsTelecommandAcknowledgement);
  190. static teFUNC_STATUS CANTS_TranslateFrameTelemetryRequestToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_REQUEST* ptsTelemetryRequest);
  191. static teFUNC_STATUS CANTS_TranslateFrameTelemetryAcknowledgementToGeneric(tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsTelemetryAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  192. static teFUNC_STATUS CANTS_TranslateFrameUnsolicitedTelemetryToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsUnsolicitedTelemetry);
  193. static teFUNC_STATUS CANTS_TranslateFrameTimeSynchronisationToGeneric(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsTimeSynchronisation, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  194. static teFUNC_STATUS CANTS_TranslateFrameSetBlockRequestToGeneric(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsSetBlockRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  195. static teFUNC_STATUS CANTS_TranslateFrameSetBlockAcknowledgementToGeneric(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  196. static teFUNC_STATUS CANTS_TranslateFrameSetBlockTransferToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsSetBlockTransfer);
  197. static teFUNC_STATUS CANTS_TranslateFrameSetBlockAbortToGeneric(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsSetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  198. static teFUNC_STATUS CANTS_TranslateFrameSetBlockStatusRequestToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsSetBlockStatusRequest);
  199. static teFUNC_STATUS CANTS_TranslateFrameSetBlockStatusReportToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsSetBlockStatusReport);
  200. static teFUNC_STATUS CANTS_TranslateFrameGetBlockRequestToGeneric(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsGetBlockRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  201. static teFUNC_STATUS CANTS_TranslateFrameGetBlockAcknowledgementToGeneric(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsGetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  202. static teFUNC_STATUS CANTS_TranslateFrameGetBlockStartToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_START* ptsGetBlockStart);
  203. static teFUNC_STATUS CANTS_TranslateFrameGetBlockTransferToGeneric(tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsGetBlockTransfer, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  204. static teFUNC_STATUS CANTS_TranslateFrameGetBlockAbortToGeneric(tsCANTS_FRAME_GET_BLOCK_ABORT* ptsGetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  205. static teFUNC_STATUS CANTS_TranslateFrameGenericToTelecommandRequest(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsTelecommandRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  206. static teFUNC_STATUS CANTS_TranslateFrameGenericToTelecommandAcknowledgement(tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsTelecommandAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  207. static teFUNC_STATUS CANTS_TranslateFrameGenericToTelemetryRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_REQUEST* ptsTelemetryRequest);
  208. static teFUNC_STATUS CANTS_TranslateFrameGenericToTelemetryAcknowledgement(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsTelemetryAcknowledgement);
  209. static teFUNC_STATUS CANTS_TranslateFrameGenericToUnsolicitedTelemetry(tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsUnsolicitedTelemetry, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  210. static teFUNC_STATUS CANTS_TranslateFrameGenericToTimeSynchronisation(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsTimeSynchronisation, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  211. static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsSetBlockRequest);
  212. static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockAcknowledgement(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknoledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  213. static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockTransfer(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsSetBlockTransferFrame);
  214. static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockAbort(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsSetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  215. static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockStatusRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsSetBlockStatusRequest);
  216. static teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockStatusReport(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsSetBlockStatusReport);
  217. static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsGetBlockRequest);
  218. static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockAcknowledgement(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsGetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  219. static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockStart(tsCANTS_FRAME_GET_BLOCK_START* ptsGetBlockStart, tsCANTS_FRAME_GENERIC* ptsGenericFrame);
  220. static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockTransfer(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsGetBlockTransfer);
  221. static teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockAbort(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_ABORT* ptsGetBlockAbort);
  222.  
  223. #endif /* UNIT_TEST */
  224.  
  225.  
  226. /** TODO: Add exception CANTS_UNSUPPORTED_PLATFORM to EA
  227.  * This initialises the CAN-TS Object. The configuration passed in is copied into memory contained
  228.  * within this object and the only way to modify the values externally is via CANTS_SetNodeAddress(...
  229.  * ) and CANTS_SetCallback(...).
  230.  * This will also internally assign function pointers used for flipping endianness based on the
  231.  * platform. It detects the platform endianness and assigns the function pointers accordingly.
  232.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  233.  * @throws CANTS_CONFIGURATION_ERROR if the configuration passed in is invalid.
  234.  * @param ptsConfiguration: tsCANTS_CONFIGURATION*: The initial configuration of the CAN-TS object.
  235.  * The value of this configuration is copied into this object, meaning modifying the contents of this
  236.  * object has no impact after initialisation, though most values can be modified via function calls.
  237.  * Ensure all callbacks are given a valid value and not left undefined.
  238.  * @re-entrant:
  239.  */
  240. teFUNC_STATUS CANTS_Initialise(tsCANTS_CONFIGURATION* ptsConfiguration)
  241. {
  242.     // Ensure that we have a valid Send Frame function
  243.     EH_ASSERT(ptsConfiguration->funcSendFrame != 0U, CANTS_CONFIGURATION_ERROR, "The Send Frame callback cannot be 0");
  244.  
  245.     // Copy the full configuration from the parameter value into this object's own copy
  246.     for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_CONFIGURATION); ++iByteIndex)
  247.     {
  248.         // Copy the byte at each memory location from the parameter config to the local config
  249.         ((tUINT8*)(&tsCANTS_Configuration))[iByteIndex] = ((tUINT8*)ptsConfiguration)[iByteIndex];
  250.     }
  251.  
  252.     /* Determine the platform endianness - We do this because parts of CAN-TS Protocol rely on data being Little Endian vvv */
  253.  
  254.     // A number to check the order of in memory to determine endianness
  255.     tUINT32 iCoolNumber = 0x11223344;
  256.  
  257.     /* The bytes for the specific endians */
  258.     tUINT8 acLittleEndianByteOrder[4] = { 0x44, 0x33, 0x22, 0x11 };
  259.     tUINT8 acBigEndianByteOrder[4] = { 0x11, 0x22, 0x33, 0x44 };
  260.  
  261.     // Check for little endian
  262.     if (
  263.         (((tUINT8*)&iCoolNumber)[0] == acLittleEndianByteOrder[0]) &&
  264.         (((tUINT8*)&iCoolNumber)[1] == acLittleEndianByteOrder[1]) &&
  265.         (((tUINT8*)&iCoolNumber)[2] == acLittleEndianByteOrder[2]) &&
  266.         (((tUINT8*)&iCoolNumber)[3] == acLittleEndianByteOrder[3])
  267.     ) {
  268.         /* The platform is Little Endian vvv */
  269.         funcCANTS_NativeEndiannessToLittleEndian = CANTS_DoNotFlipEndianness;
  270.         funcCANTS_LittleEndianToNativeEndianness = CANTS_DoNotFlipEndianness;
  271.     }
  272.     // Check for big endian
  273.     else if (
  274.         (((tUINT8*)&iCoolNumber)[0] == acBigEndianByteOrder[0]) &&
  275.         (((tUINT8*)&iCoolNumber)[1] == acBigEndianByteOrder[1]) &&
  276.         (((tUINT8*)&iCoolNumber)[2] == acBigEndianByteOrder[2]) &&
  277.         (((tUINT8*)&iCoolNumber)[3] == acBigEndianByteOrder[3])
  278.     ) {
  279.         /* The platform is Big Endian vvv */
  280.         funcCANTS_NativeEndiannessToLittleEndian = CANTS_FlipEndianness;
  281.         funcCANTS_LittleEndianToNativeEndianness = CANTS_FlipEndianness;
  282.     }
  283.     else
  284.     {
  285.         // The endianness of the platform is not supported
  286.         EH_ASSERT(FALSE, CANTS_UNSUPPORTED_PLATFORM, "Cannot determine the endianness of the platfom - CAN-TS not initialised");
  287.     }
  288.  
  289.     return BT_SUCCESS;
  290.  
  291. CANTS_CONFIGURATION_ERROR:
  292. CANTS_UNSUPPORTED_PLATFORM:
  293.     return BT_FAIL;
  294. }
  295.  
  296. /**
  297.  * This is called by the user of this interface to handle any frames received on the CAN Bus. This
  298.  * function call will route the frame according to its type, and will subsequently invoke the
  299.  * callbacks set by the user if necessary.
  300.  * You must not any transaction handling functions while this function is executing, such as
  301.  * CANTS_SetBlock(...) or CANTS_GetBlock(...).
  302.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  303.  * @throws CANTS_INVALID_FRAME if the frame contains invalid data.
  304.  * @throws CANTS_HANDLING_ERROR if there was an error handling the frame.
  305.  * @throws CANTS_TRANSLATE_ERROR if there was an error translating the frame from a generic frame
  306.  * to a specific CAN-TS frame.
  307.  * @param ptsFrame: tsCANTS_FRAME_GENERIC*: A pointer to the CAN-TS frame to handle.
  308.  * @re-entrant:
  309.  */
  310. teFUNC_STATUS CANTS_HandleFrame(tsCANTS_FRAME_GENERIC* ptsFrame)
  311. {
  312.     // The return value to function calls
  313.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  314.  
  315.     // Get the frame type as an enumeration value
  316.     teCANTS_FRAME_TYPE teFrameType = (teCANTS_FRAME_TYPE)(ptsFrame->tsIdentifiers.iFrameType);
  317.  
  318.     // Handle the specific frame type
  319.     // 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
  320.     switch (teFrameType)
  321.     {
  322.     case CANTS_FRAME_TYPE_TELECOMMAND:
  323.     {
  324.         // Get the frame subtype
  325.         // The subtype for a telecommand is kept in the first 2 bits of the Command field
  326.         teCANTS_FRAME_SUBTYPE teFrameSubtype = (teCANTS_FRAME_SUBTYPE)((ptsFrame->tsIdentifiers.iCommand & 0x300U) >> 8U);
  327.  
  328.         switch (teFrameSubtype)
  329.         {
  330.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST:
  331.         {
  332.             // The Telecommand Request frame to format
  333.             tsCANTS_FRAME_TELECOMMAND_REQUEST tsTelecommandRequest = { 0U };
  334.  
  335.             // Translate the generic frame to a Telecommand Request frame
  336.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TELECOMMAND, CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST, (void*)(&tsTelecommandRequest));
  337.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Generic Frame to a Telecommand Request frame");
  338.  
  339.             // Handle the Telecommand Request
  340.             teFuncStatus = CANTS_HandleIncomingTelecommandRequest(&tsTelecommandRequest);
  341.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Telecommand Request");
  342.  
  343.             break;
  344.         }
  345.  
  346.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  347.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT:
  348.         {
  349.             // The Telecommand Acknowledgement frame to format
  350.             tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT tsTelecommandAcknowledgement = { 0U };
  351.  
  352.             // Translate the generic frame to the Telecommand Acknowledgement frame
  353.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TELECOMMAND, CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT, (void*)(&tsTelecommandAcknowledgement));
  354.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Telecommand Acknowledgement frame");
  355.  
  356.             // Handle the Telecommand Acknowledgement
  357.             teFuncStatus = CANTS_HandleIncomingTelecommandAcknowledgement(&tsTelecommandAcknowledgement);
  358.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Telecommand Acknowledgement");
  359.  
  360.             break;
  361.         }
  362.  
  363.         default:
  364.             // The frame subtype is invalid and cannot be handled
  365.             EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid Telecommand subtype was provided");
  366.             break;
  367.         }
  368.  
  369.         break;
  370.     }
  371.  
  372.     case CANTS_FRAME_TYPE_TELEMETRY_REQUEST:
  373.     {
  374.         // Get the Telemetry Request subtype
  375.         // The subtype is specified as the first two bits of the Command field
  376.         teCANTS_FRAME_SUBTYPE teFrameSubtype = (teCANTS_FRAME_SUBTYPE)((ptsFrame->tsIdentifiers.iCommand & 0x300U) >> 8U);
  377.  
  378.         // Handle the specific Telemetry frame subtype
  379.         switch (teFrameSubtype)
  380.         {
  381.         case CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST:
  382.         {
  383.             // The Telemetry Request frame to format
  384.             tsCANTS_FRAME_TELEMETRY_REQUEST tsTelemetryRequest = { 0U };
  385.  
  386.             // Translate the generic frame to the Telemetry Request frame
  387.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TELEMETRY_REQUEST, CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST, (void*)(&tsTelemetryRequest));
  388.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Telemetry Request frame");
  389.  
  390.             // Handle the Telemetry Request
  391.             teFuncStatus = CANTS_HandleIncomingTelemetryRequest(&tsTelemetryRequest);
  392.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Telemetry Request");
  393.  
  394.             break;
  395.         }
  396.  
  397.         case CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  398.         case CANTS_FRAME_SUBTYPE_TELEMETRY_NEGATIVE_ACKNOWLEDGEMENT:
  399.         {
  400.             // The Telemetry Acknowledgement frame to format
  401.             tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT tsTelemetryAcknowledgement = { 0U };
  402.  
  403.             // Translate the generic frame to the Telemetry Acknowledgement frame
  404.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TELEMETRY_REQUEST, CANTS_FRAME_SUBTYPE_TELEMETRY_GENERIC_ACKNOWLEDGEMENT, (void*)(&tsTelemetryAcknowledgement));
  405.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Telemetry Acknoledgement frame");
  406.  
  407.             // Handle the Telemetry Acknowledgement
  408.             teFuncStatus = CANTS_HandleIncomingTelemetryAcknowledgement(&tsTelemetryAcknowledgement);
  409.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Telemetry Acknowledgement");
  410.  
  411.             break;
  412.         }
  413.  
  414.         default:
  415.             // The frame subtype is invalid and cannot be handled
  416.             EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid Telemetry subtype was provided");
  417.             break;
  418.         }
  419.     }
  420.  
  421.     case CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY:
  422.     {
  423.         // Ensure the subtype is assigned correctly
  424.         // The CAN-TS Protocol specifies that this must be set to 0, but it has no real meaning
  425.         EH_ASSERT(
  426.             ((ptsFrame->tsIdentifiers.iCommand & 0x300U) >> 8) == CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY,
  427.             CANTS_INVALID_FRAME,
  428.             "The subtype for Unsolicited Telemetry is incorrect"
  429.         );
  430.  
  431.         // The Unsolicited Telemetry frame to format
  432.         tsCANTS_FRAME_UNSOLICITED_TELEMETRY tsUnsolicitedTelemetry = { 0U };
  433.  
  434.         // Translate the generic frame to an unsolicited telemetry frame
  435.         teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY, CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY, (void*)(&tsUnsolicitedTelemetry));
  436.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to an Unsolicited Telemetry frame");
  437.  
  438.         // Handle the Unsolicited Telemetry
  439.         teFuncStatus = CANTS_HandleIncomingUnsolicitedTelemetry(&tsUnsolicitedTelemetry);
  440.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Unsolicited Telemetry");
  441.  
  442.         break;
  443.     }
  444.  
  445.     case CANTS_FRAME_TYPE_TIME_SYNCHRONISATION:
  446.     {
  447.         // The Time Synchronisation frame to format
  448.         tsCANTS_FRAME_TIME_SYNCHRONISATION tsTimeSynchronisation = { 0U };
  449.  
  450.         // Ensure it has the To Address of 0
  451.         EH_ASSERT(
  452.             ptsFrame->tsIdentifiers.iToAddress == 0U,
  453.             CANTS_INVALID_FRAME,
  454.             "A Time Synchronisation frame had a non-zero To Address"
  455.         );
  456.  
  457.         /* We don't check the subtype - It's left undefined by the CAN-TS Protocol */
  458.  
  459.         // Translate the generic frame to a time synchronisation frame
  460.         teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_TIME_SYNCHRONISATION, CANTS_FRAME_SUBTYPE_TIME_SYNCHRONISATION, (void*)(&tsTimeSynchronisation));
  461.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Time Synchronisation frame");
  462.  
  463.         // Handle the Time Synchronisation
  464.         teFuncStatus = CANTS_HandleIncomingTimeSynchronisation(&tsTimeSynchronisation);
  465.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle a Time Synchronisation");
  466.  
  467.         break;
  468.     }
  469.  
  470.     case CANTS_FRAME_TYPE_SET_BLOCK:
  471.     {
  472.         // Get the enumeration value for the frame subtype
  473.         teCANTS_FRAME_SUBTYPE teFrameSubtype = (teCANTS_FRAME_SUBTYPE)((ptsFrame->tsIdentifiers.iCommand & 0x700U) >> 8U);
  474.  
  475.         // Switch for the specific subtype of Set Block frame
  476.         switch (teFrameSubtype)
  477.         {
  478.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST:
  479.         {
  480.             // The Set Block Request frame to format
  481.             tsCANTS_FRAME_SET_BLOCK_REQUEST tsSetBlockRequest = { 0U };
  482.  
  483.             // Tranlate from the generic frame to the set block request frame
  484.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST, (void*)(&tsSetBlockRequest));
  485.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Request frame");
  486.  
  487.             // Handle the Set Block Request
  488.             teFuncStatus = CANTS_HandleIncomingSetBlockRequest(&tsSetBlockRequest);
  489.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle a Set Block Request");
  490.  
  491.             break;
  492.         }
  493.  
  494.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  495.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
  496.         {
  497.             // The Set Block Acknowledgement frame to format
  498.             tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT tsSetBlockAcknowledgement = { 0U };
  499.  
  500.             // Translate from the generic frame to the set block acknowledgement frame
  501.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_GENERIC_ACKNOWLEDGEMENT, (void*)(&tsSetBlockAcknowledgement));
  502.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Acknowledgement frame");
  503.  
  504.             // Handle the Set Block Acknowledgement
  505.             teFuncStatus = CANTS_HandleIncomingSetBlockAcknowledgement(&tsSetBlockAcknowledgement);
  506.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle a Set Block Acknowledgement");
  507.  
  508.             break;
  509.         }
  510.  
  511.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER:
  512.         {
  513.             // The Set Block Transfer frame to format
  514.             tsCANTS_FRAME_SET_BLOCK_TRANSFER tsSetBlockTransfer = { 0U };
  515.  
  516.             // Translate from the generic frame to the set block transfer frame
  517.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER, (void*)(&tsSetBlockTransfer));
  518.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Transfer frame");
  519.  
  520.             // Handle the Set Block Transfer
  521.             teFuncStatus = CANTS_HandleIncomingSetBlockTransfer(&tsSetBlockTransfer);
  522.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle a Set Block Transfer");
  523.  
  524.             break;
  525.         }
  526.  
  527.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST:
  528.         {
  529.             // The Set Block Status Request frame to format
  530.             tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST tsSetBlockStatusRequest = { 0U };
  531.  
  532.             // Translate from the generic frame to the set block status request frame
  533.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST, (void*)(&tsSetBlockStatusRequest));
  534.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Status Request frame");
  535.  
  536.             // Handle the Set Block Status Request
  537.             teFuncStatus = CANTS_HandleIncomingSetBlockStatusRequest(&tsSetBlockStatusRequest);
  538.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Set Block Status Request");
  539.  
  540.             break;
  541.         }
  542.  
  543.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT:
  544.         {
  545.             // The Set Block Status Report frame to format
  546.             tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT tsSetBlockStatusReport = { 0U };
  547.  
  548.             // Translate from the generic frame to the set block status report frame
  549.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT, (void*)(&tsSetBlockStatusReport));
  550.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Status Report frame");
  551.  
  552.             // Handle the Set Block Status Report
  553.             teFuncStatus = CANTS_HandleIncomingSetBlockStatusReport(&tsSetBlockStatusReport);
  554.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Set Block Status Report");
  555.  
  556.             break;
  557.         }
  558.  
  559.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT:
  560.         {
  561.             // The Set Block Abort frame to format
  562.             tsCANTS_FRAME_SET_BLOCK_ABORT tsSetBlockAbort = { 0U };
  563.  
  564.             // Translate from the generic frame to the set block abort frame
  565.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT, (void*)(&tsSetBlockAbort));
  566.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Set Block Abort frame");
  567.  
  568.             // Handle the Set Block Abort
  569.             teFuncStatus = CANTS_HandleIncomingSetBlockAbort(&tsSetBlockAbort);
  570.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Set Block Abort");
  571.  
  572.             break;
  573.         }
  574.  
  575.         default:
  576.             EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid Set Block subtype was provided");
  577.             break;
  578.         }
  579.  
  580.         break;
  581.     }
  582.  
  583.     case CANTS_FRAME_TYPE_GET_BLOCK:
  584.     {
  585.         // The enumeration value of the frame subtype
  586.         teCANTS_FRAME_SUBTYPE teFrameSubtype = (teCANTS_FRAME_SUBTYPE)((ptsFrame->tsIdentifiers.iCommand & 0x700U) > 8U);
  587.  
  588.         // Switch for the specific frame type of the Get Block frame
  589.         switch (teFrameSubtype)
  590.         {
  591.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST:
  592.         {
  593.             // The Get Block Request frame to format
  594.             tsCANTS_FRAME_GET_BLOCK_REQUEST tsGetBlockRequest = { 0U };
  595.  
  596.             // Translate the Generic Frame to the Get Block Request frame
  597.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST, (void*)(&tsGetBlockRequest));
  598.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block request frame");
  599.  
  600.             // Handle the Get Block Request
  601.             teFuncStatus = CANTS_HandleIncomingGetBlockRequest(&tsGetBlockRequest);
  602.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Request");
  603.  
  604.             break;
  605.         }
  606.  
  607.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  608.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
  609.         {
  610.             // The Get Block Acknowledgement frame to format
  611.             tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT tsGetBlockAcknowledgement = { 0U };
  612.  
  613.             // Translate the Generic Frame to the Get Block Acknowledgement frame
  614.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_GENERIC_ACKNOWLEDGEMENT, (void*)(&tsGetBlockAcknowledgement));
  615.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block Acknowledgement frame");
  616.  
  617.             // Handle the Get Block Acknowledgement
  618.             teFuncStatus = CANTS_HandleIncomingGetBlockAcknowledgement(&tsGetBlockAcknowledgement);
  619.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Acknowledgement");
  620.  
  621.             break;
  622.         }
  623.  
  624.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_START:
  625.         {
  626.             // The Get Block Start frame to format
  627.             tsCANTS_FRAME_GET_BLOCK_START tsGetBlockStart = { 0U };
  628.  
  629.             // Translate the Generic Frame to the Get Block Start frame
  630.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_START, (void*)(&tsGetBlockStart));
  631.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block Start frame");
  632.  
  633.             // Handle the Get Block Start
  634.             teFuncStatus = CANTS_HandleIncomingGetBlockStart(&tsGetBlockStart);
  635.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Start");
  636.  
  637.             break;
  638.         }
  639.  
  640.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER:
  641.         {
  642.             // The Get Block Transfer frame to format
  643.             tsCANTS_FRAME_GET_BLOCK_TRANSFER tsGetBlockTransfer = { 0U };
  644.  
  645.             // Translate the Generic Frame to the Get Block Transfer frame
  646.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER, (void*)(&tsGetBlockTransfer));
  647.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block Transfer frame");
  648.  
  649.             // Handle the Get Block Transfer
  650.             teFuncStatus = CANTS_HandleIncomingGetBlockTransfer(&tsGetBlockTransfer);
  651.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Transfer");
  652.  
  653.             break;
  654.         }
  655.  
  656.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT:
  657.         {
  658.             // The Get Block Abort frame to format
  659.             tsCANTS_FRAME_GET_BLOCK_ABORT tsGetBlockAbort = { 0U };
  660.  
  661.             // Translate from the Generic Frame to the Get Block Abort frame
  662.             teFuncStatus = CANTS_TranslateFromGenericFrame(ptsFrame, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT, (void*)(&tsGetBlockAbort));
  663.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Generic Frame to a Get Block Abort frame");
  664.  
  665.             // Handle the Get Block Abort
  666.             teFuncStatus = CANTS_HandleIncomingGetBlockAbort(&tsGetBlockAbort);
  667.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ERROR, "Failed to handle Get Block Abort");
  668.  
  669.             break;
  670.         }
  671.  
  672.         default:
  673.             EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid Get Block subtype was provided");
  674.             break;
  675.         }
  676.  
  677.         break;
  678.     }
  679.  
  680.     default:
  681.         // The type of frame is invalid and cannot be handled
  682.         EH_ASSERT(FALSE, CANTS_INVALID_FRAME, "An invalid frame type was provided");
  683.         break;
  684.     }
  685.  
  686.     return BT_SUCCESS;
  687.  
  688. CANTS_INVALID_FRAME:
  689. CANTS_HANDLING_ERROR:
  690. CANTS_TRANSLATE_ERROR:
  691.     return BT_FAIL;
  692. }
  693.  
  694. /**
  695.  * Sends a telecommand with arguments on a specific telecommand channel. The telecommand channel is
  696.  * the telecommand being sent. The recipient of the telecommand request is expected to respond with
  697.  * either a Positive Acknowledgement or a Negative Acknowledgement.
  698.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  699.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  700.  * @throws CANTS_TRANSLATE_ERROR if the frame couldn't be translated to a generic frame.
  701.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  702.  * @param iToAddress: tUINT8: The destination address of the telecommand
  703.  * @param iChannel: tUINT8: The telecommand channel
  704.  * @param acData[8]: tUINT8: The telecommand arguments
  705.  * @param iDataLength: tUINT8: The length of the telecommand arguments
  706.  * @re-entrant:
  707.  */
  708. teFUNC_STATUS CANTS_SendTelecommand(tUINT8 iToAddress, tUINT8 iChannel, tUINT8 acData[8], tUINT8 iDataLength)
  709. {
  710.     // Ensure that the data length is not above 8
  711.     EH_ASSERT(iDataLength <= 8U, CANTS_INVALID_PARAMETER, "The provided data length is invalid");
  712.  
  713.     // The return value to function call
  714.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  715.  
  716.     /* Construct the Telecommand frame from the parameters vvv */
  717.  
  718.     tsCANTS_FRAME_TELECOMMAND_REQUEST tsTelecommandRequest = { 0U };
  719.  
  720.     // Set the fields
  721.     tsTelecommandRequest.iToAddress = iToAddress;
  722.     tsTelecommandRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  723.     tsTelecommandRequest.iChannel = iChannel;
  724.     tsTelecommandRequest.iDataLength = iDataLength;
  725.  
  726.     // Copy the telecommand argument bytes into the Telecommand Request frame
  727.     for (tUINT32 iByteIndex = 0U; iByteIndex < iDataLength; ++iByteIndex)
  728.     {
  729.         // Assign the byte
  730.         tsTelecommandRequest.acData[iByteIndex] = acData[iByteIndex];
  731.     }
  732.  
  733.     // The generic version of the Telecommand frame to send
  734.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  735.  
  736.     // Translate the Telecommand Request frame to a Generic frame
  737.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)(&tsTelecommandRequest), CANTS_FRAME_TYPE_TELECOMMAND, CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST, &tsGenericFrame);
  738.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telecommand Request frame into a Generic frame");
  739.  
  740.     // Send the frame over the CAN Bus
  741.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  742.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Telecommand Request frame");
  743.  
  744.     return BT_SUCCESS;
  745.  
  746. CANTS_INVALID_PARAMETER:
  747. CANTS_TRANSLATE_ERROR:
  748. CANTS_SEND_ERROR:
  749.     return BT_FAIL;
  750. }
  751.  
  752. /**
  753.  * Sends an acknowledgement to a telecommand request.
  754.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  755.  * @throws CANTS_TRANSLATE_ERROR if the frame could not be translated to a generic frame.
  756.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  757.  * @param iChannel: tUINT8: The telecommand channel to send the acknowledgement on
  758.  * @param iToAddress: tUINT8: The destination node to send the acknowledgement to
  759.  * @param teAcknowledgement: teCANTS_ACKNOWLEDGEMENT: Either a positive or negative acknowledgement
  760.  * @re-entrant:
  761.  */
  762. teFUNC_STATUS CANTS_SendTelecommandAcknowledgement(tUINT8 iChannel, tUINT8 iToAddress, teCANTS_ACKNOWLEDGEMENT teAcknowledgement)
  763. {
  764.     // The return value of function calls
  765.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  766.  
  767.     // The Telecommand Acknowledgement frame to construct
  768.     tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT tsTelecommandAcknowledgement = { 0U };
  769.  
  770.     /* Assign the fields in the Telecommand Acknowledgement frame vvv */
  771.  
  772.     tsTelecommandAcknowledgement.iChannel = iChannel;
  773.     tsTelecommandAcknowledgement.iToAddress = iToAddress;
  774.     tsTelecommandAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  775.     tsTelecommandAcknowledgement.teAcknowledgement = teAcknowledgement;
  776.  
  777.     // The generic version of the Telecommand Acknowledgement frame
  778.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  779.  
  780.     // Translate from the Telecommand Acknowledgement frame to the Generic frame
  781.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTelecommandAcknowledgement, CANTS_FRAME_TYPE_TELECOMMAND, CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT, &tsGenericFrame);
  782.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telecommand Acknowledgement frame to a Generic frame");
  783.  
  784.     // Send the frame over the CAN bus
  785.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  786.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Telecommand Acknowledgement");
  787.  
  788.     return BT_SUCCESS;
  789.  
  790. CANTS_TRANSLATE_ERROR:
  791. CANTS_SEND_ERROR:
  792.     return BT_FAIL;
  793. }
  794.  
  795. /**
  796.  * Sends a telemetry request to a specific address with telemetry channel. The telemetry channel is
  797.  * the telemetry point being requested. The recipient of the telemetry request is expected to respond
  798.  * with either a Positive Acknowledgement or a Negative Acknowledgement, where the Positive
  799.  * Acknowledgement will contain the telemetry point data.
  800.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  801.  * @throws CANTS_TRANSLATE_ERROR if the frame couldn't be translated to a generic frame.
  802.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  803.  * @param iChannel: tUINT8: The destination address of the telemetry request
  804.  * @param iToAddress: tUINT8: The telemetry channel
  805.  * @re-entrant:
  806.  */
  807. teFUNC_STATUS CANTS_SendTelemetryRequest(tUINT8 iChannel, tUINT8 iToAddress)
  808. {
  809.     // The return value for function calls
  810.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  811.  
  812.     // Construct the Telemetry request frame
  813.     tsCANTS_FRAME_TELEMETRY_REQUEST tsTelemetryRequest = { 0U };
  814.  
  815.     /* Assign the fields within the Telemetry Request vvv */
  816.  
  817.     tsTelemetryRequest.iToAddress = iToAddress;
  818.     tsTelemetryRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  819.     tsTelemetryRequest.iChannel = iChannel;
  820.  
  821.     // The generic version of the Telemetry request frame to send
  822.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  823.  
  824.     // Translate the Telemetry Request frame to a Generic frame
  825.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTelemetryRequest, CANTS_FRAME_TYPE_TELEMETRY_REQUEST, CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST, &tsGenericFrame);
  826.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telemetry Request frame into a Generic frame");
  827.  
  828.     // Send the frame over the CAN Bus
  829.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  830.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Telemetry Request frame");
  831.  
  832.     return BT_SUCCESS;
  833.  
  834. CANTS_TRANSLATE_ERROR:
  835. CANTS_SEND_ERROR:
  836.     return BT_FAIL;
  837. }
  838.  
  839. /**
  840.  * This sends a Telemetry Acknowledgement in response to a Telemetry Request. If the acknowledgement
  841.  * type is Negative, no telemetry data is sent. The data region within a Positive Acknowledgement is
  842.  * interpreted as the telemetry point data.
  843.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  844.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  845.  * @throws CANTS_TRANSLATE_ERROR if the frame failed to translate to a generic frame.
  846.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  847.  * @param iChannel: tUINT8: The telemetry channel to send the acknowledgement on
  848.  * @param iToAddress: tUINT8: The destination address to receive the acknowledgement
  849.  * @param acData[8]: tUINT8: The telemetry point data. If a Negative Acknowledgement is sent, this
  850.  * data goes unused. This data is the data for the requested telemetry point.
  851.  * @param iDataLength: tUINT8: The length of the telemetry data
  852.  * @param teAcknowledgement: teCANTS_ACKNOWLEDGEMENT: The telemetry request acknowledgement.
  853.  * @re-entrant:
  854.  */
  855. teFUNC_STATUS CANTS_SendTelemetryAcknowledgement(tUINT8 iChannel, tUINT8 iToAddress, tUINT8 acData[8], tUINT8 iDataLength, teCANTS_ACKNOWLEDGEMENT teAcknowledgement)
  856. {
  857.     // Ensure the data length does not exceed 8
  858.     EH_ASSERT(iDataLength <= 8, CANTS_INVALID_PARAMETER, "The provided data length for a Telemetry Acknowledgement exceeds 8");
  859.  
  860.     // The return value of function call
  861.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  862.  
  863.     // The Telemetry Acknowledgement frame to populate
  864.     tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT tsTelemetryAcknowledgement = { 0U };
  865.  
  866.     /* Assign the values within the Telemetry Acknowledgement frame vvv */
  867.  
  868.     tsTelemetryAcknowledgement.iToAddress = iToAddress;
  869.     tsTelemetryAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  870.     tsTelemetryAcknowledgement.iChannel = iChannel;
  871.     tsTelemetryAcknowledgement.teAcknowledgement = teAcknowledgement;
  872.     tsTelemetryAcknowledgement.iDataLength = iDataLength;
  873.  
  874.     // Copy the telemetry bytes into the acknowledgement frame
  875.     for (tUINT32 iByteIndex = 0U; iByteIndex < iDataLength; ++iByteIndex)
  876.     {
  877.         // Copy the byte
  878.         tsTelemetryAcknowledgement.acData[iByteIndex] = acData[iByteIndex];
  879.     }
  880.  
  881.     // The generic version of the Telemetry Acknowledgement frame to send over the CAN Bus
  882.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  883.  
  884.     // The Telemetry Acknowledgement subtype
  885.     teCANTS_FRAME_SUBTYPE teFrameSubtype = 0U;
  886.  
  887.     // Assign the specific Telemetry Acknowledgement frame subtype to pass into the translate function
  888.     switch (teAcknowledgement)
  889.     {
  890.     case CANTS_POSITIVE_ACKNOWLEDGEMENT:
  891.         teFrameSubtype = CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT;
  892.         break;
  893.  
  894.     case CANTS_NEGATIVE_ACKNOWLEDGEMENT:
  895.         teFrameSubtype = CANTS_FRAME_SUBTYPE_TELEMETRY_NEGATIVE_ACKNOWLEDGEMENT;
  896.         break;
  897.  
  898.     default:
  899.         EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An unknown acknowledgement type was provided when sending a Telemetry Acknowledgement");
  900.         break;
  901.     }
  902.  
  903.     // Translate the Telemetry Acknowledgement frame to a Generic frame to be sent
  904.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTelemetryAcknowledgement, CANTS_FRAME_TYPE_TELEMETRY_REQUEST, teFrameSubtype, &tsGenericFrame);
  905.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telemetry Acknowledgement frame to a Generic frame");
  906.  
  907.     // Send the frame
  908.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  909.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send a Telemetry Acknowledgement frame");
  910.  
  911.     return BT_SUCCESS;
  912.  
  913. CANTS_INVALID_PARAMETER:
  914. CANTS_TRANSLATE_ERROR:
  915. CANTS_SEND_ERROR:
  916.     return BT_FAIL;
  917. }
  918.  
  919. /**
  920.  * This sends unsolicited telemetry to a destination address. The Channel represents the telemetry
  921.  * point which the data region is associated with. The recipient should not return an acknowledgement
  922.  * frame.
  923.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  924.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  925.  * @throws CANTS_TRANSLATE_ERROR if the frame could not be translated to a generic frame.
  926.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  927.  * @param iChannel: tUINT8: The telemetry channel. This represents the specific telemetry point.
  928.  * @param iToAddress: tUINT8: The recipient of the telemetry.
  929.  * @param acData[8]: tUINT8: The telemetry point data.
  930.  * @param iDataLength: tUINT8: The length of the telemtry point data.
  931.  * @re-entrant:
  932.  */
  933. teFUNC_STATUS CANTS_SendUnsolicitedTelemetry(tUINT8 iChannel, tUINT8 iToAddress, tUINT8 acData[8], tUINT8 iDataLength)
  934. {
  935.     // Ensure that the data length is not above 8
  936.     EH_ASSERT(iDataLength <= 8, CANTS_INVALID_PARAMETER, "The provided data length cannot be above 8");
  937.  
  938.     // The return value from function call
  939.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  940.  
  941.     // The Unsolicited Telemetry frame to populate
  942.     tsCANTS_FRAME_UNSOLICITED_TELEMETRY tsUnsolicitedTelemetry = { 0U };
  943.  
  944.     /* Assign the fields within the Unsolicited Telemetry frame vvv */
  945.     tsUnsolicitedTelemetry.iToAddress = iToAddress;
  946.     tsUnsolicitedTelemetry.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  947.     tsUnsolicitedTelemetry.iChannel = iChannel;
  948.     tsUnsolicitedTelemetry.iDataLength = iDataLength;
  949.  
  950.     // Copy the data into the Unsolicited Telemetry frame
  951.     for (tUINT32 iByteIndex = 0U; iByteIndex < iDataLength; ++iByteIndex)
  952.     {
  953.         // Assign the byte
  954.         tsUnsolicitedTelemetry.acData[iByteIndex] = acData[iByteIndex];
  955.     }
  956.  
  957.     // The generic frame to send over the CAN Bus
  958.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  959.  
  960.     // Translate the Unsolicited Telemetry frame into a Generic frame to send over the CAN Bus
  961.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsUnsolicitedTelemetry, CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY, CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY, &tsGenericFrame);
  962.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate an Unsolicited Telemetry frame into a Generic frame");
  963.  
  964.     // Send the frame over the CAN Bus
  965.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  966.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Unsolicited Telemetry frame");
  967.  
  968.     return BT_SUCCESS;
  969.  
  970. CANTS_INVALID_PARAMETER:
  971. CANTS_TRANSLATE_ERROR:
  972. CANTS_SEND_ERROR:
  973.     return BT_FAIL;
  974. }
  975.  
  976. /**
  977.  * This sends a time synchronisation which is received by all other nodes. This is transmitted to
  978.  * address 0.
  979.  * The units which the time is represented as is mission defined, therefore it could be milliseconds,
  980.  * seconds, absolute time, relative time, etc.
  981.  * This value is transmitted on the CAN Bus as little endian. You must provide the time in the native
  982.  * endianness of the platform the code is executing on and this function will flip it if necessary.
  983.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL
  984.  * @throws CANTS_TRANSLATE_ERROR if the frame failed to translate.
  985.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  986.  * @param iTime: tUINT64: The time point of the time synchronisation. The units of this value is
  987.  * mission defined.
  988.  * @re-entrant:
  989.  */
  990. teFUNC_STATUS CANTS_SendTimeSynchronisation(tUINT64 iTime)
  991. {
  992.     // This is the return value of function calls
  993.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  994.  
  995.     // The Time Synchronisation frame to populate with data
  996.     tsCANTS_FRAME_TIME_SYNCHRONISATION tsTimeSynchronisation = { 0U };
  997.  
  998.     /* Assign the frame fields vvv */
  999.  
  1000.     tsTimeSynchronisation.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1001.     tsTimeSynchronisation.iTime = iTime;
  1002.  
  1003.     // The generic frame to send over the CAN Bus
  1004.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1005.  
  1006.     // Translate the Time Synchronisation frame to the Generic frame
  1007.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTimeSynchronisation, CANTS_FRAME_TYPE_TIME_SYNCHRONISATION, CANTS_FRAME_SUBTYPE_TIME_SYNCHRONISATION, &tsGenericFrame);
  1008.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate the Time Synchronisation frame to a Generic frame");
  1009.  
  1010.     // Send the frame over CAN Bus
  1011.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1012.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Time Synchronisation frame");
  1013.  
  1014.     return BT_SUCCESS;
  1015.  
  1016. CANTS_TRANSLATE_ERROR:
  1017. CANTS_SEND_ERROR:
  1018.     return BT_FAIL;
  1019. }
  1020.  
  1021. /**
  1022.  * Sets a series of blocks on a receiving node from a buffer of memory. You provide a transaction
  1023.  * struct to specify the data, start address, etc., and continuously call this function until the
  1024.  * reported status is either Success or Failure (the status within the transaction struct, not the
  1025.  * return value).
  1026.  * After the transaction has complete, either successfully or unsuccessfully, you must call
  1027.  * CANTS_EndSetBlockTransaction(...) to Abort the transaction. You can also Abort the transaction at
  1028.  * any other time during the transfer.
  1029.  * While this function has some rudimentary thread safety for sanity sake, this function is not fully
  1030.  * thread safe and you must not call this function while another Set Block transaction is ongoing.
  1031.  * All Set Block associated callbacks are disabled while this function is handing the transaction so
  1032.  * that this process is fully automatic, and the transfer state isn't accidentally altered via
  1033.  * external handling of the frames.
  1034.  * You must not call CANTS_HandleFrame(...) while this function is executing - use something like a
  1035.  * Mutex Take prior to calling each function, then releasing the mutex after the call has complete.
  1036.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  1037.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided
  1038.  * @param ptsTransaction: tsCANTS_SET_BLOCK_OUTGOING_TRANSACTION*: A pointer to the ongoing
  1039.  * transaction. Refer to the structure description to know what to set this to in order to instantiate
  1040.  * a transaction.
  1041.  * @re-entrant:
  1042.  */
  1043. teFUNC_STATUS CANTS_SetBlock(tsCANTS_SET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
  1044. {
  1045.     // The return value from function calls
  1046.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  1047.  
  1048.     // Specify that there is an ongoing transfer
  1049.     // This is checked prior to any Set Block callbacks being invoked, if this value is TRUE, the callback will not be invoked
  1050.     bCANTS_SetBlockBusy = TRUE;
  1051.  
  1052.     // This is used as a flag to determine if the Set Block request has been sent yet
  1053.     static tBOOL bHasSentRequest = FALSE;
  1054.  
  1055.     // This is a bit field to store which blocks have not been sent within a transfer
  1056.     static tUINT64 iBlocksRemaining = 0U;
  1057.  
  1058.     // Switch for the transaction state
  1059.     switch (ptsTransaction->teStatus)
  1060.     {
  1061.     case CANTS_SET_BLOCK_STATUS_PENDING:
  1062.     {
  1063.         // If we have sent a request and are waiting for the response
  1064.         if (bHasSentRequest == TRUE)
  1065.         {
  1066.             // If there is at least one pending Set Block Acknowledgement frame
  1067.             if (iCANTS_SetBlockPendingAcknowledgements > 0U)
  1068.             {
  1069.                 // Get a pointer to the first acknowledgement frame
  1070.                 // There should never be more than one pending acknowledgement frame, therefore we assume the first one received is the one we're interested in
  1071.                 tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknowledgement = &(atsCANTS_SetBlockPendingAcknowledgements[0U]);
  1072.  
  1073.                 // Switch for the specific type of acknowledgement
  1074.                 switch (ptsSetBlockAcknowledgement->teAcknowledgement)
  1075.                 {
  1076.                 case CANTS_POSITIVE_ACKNOWLEDGEMENT:
  1077.                     /* Set the initial transaction state ready for the ONGOING state to use vvv */
  1078.                     ptsTransaction->iBytesRemaining = ptsTransaction->iDataLength;
  1079.                     ptsTransaction->iBytesSent = 0;
  1080.  
  1081.                     // This will get the number of blocks which needs to be sent, rounded up to the closest 8 bytes
  1082.                     tUINT32 iNumberOfBlocks = (tUINT32)((ptsTransaction->iDataLength + 7U) / 8U);
  1083.  
  1084.                     // Limit the number of blocks to 64 - It's possible for it to round up to 65
  1085.                     if (iNumberOfBlocks > 64U)
  1086.                     {
  1087.                         iNumberOfBlocks = 64U;
  1088.                     }
  1089.  
  1090.                     // Set all of the bits within the bit field to specify which blocks are remaining
  1091.                     for (tUINT32 iBitIndex = 0U; iBitIndex < iNumberOfBlocks; ++iBitIndex)
  1092.                     {
  1093.                         // Shift the bit index to the very left-most bit within the bit field
  1094.                         iBlocksRemaining |= (tUINT64)(1U << (63U - iBitIndex));
  1095.                     }
  1096.  
  1097.                     // Go into the ongoing transaction state
  1098.                     ptsTransaction->teAddressSize = CANTS_SET_BLOCK_STATUS_ONGOING;
  1099.  
  1100.                     break;
  1101.  
  1102.                 case CANTS_NEGATIVE_ACKNOWLEDGEMENT:
  1103.                     // Go to the failure state
  1104.                     ptsTransaction->teAddressSize = CANTS_SET_BLOCK_STATUS_FAILURE;
  1105.                     break;
  1106.  
  1107.                 default:
  1108.                     EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Acknowledgement value was provided");
  1109.                     break;
  1110.                 }
  1111.             }
  1112.         }
  1113.         // Else we haven't sent the request yet and need to
  1114.         else
  1115.         {
  1116.             // The request frame to populate
  1117.             tsCANTS_FRAME_SET_BLOCK_REQUEST tsSetBlockRequest = { 0U };
  1118.  
  1119.             // The number of blocks which will be sent
  1120.             // This formula ensures the integer division is always rounded upwards to the closest block size
  1121.             // blocks = (bytes + (blockSize - 1)) / blockSize
  1122.             // Therefore the magical '7' and '8' are respectively the block size minus one and the block size
  1123.             tUINT32 iNumberOfBlocks = (tUINT32)((ptsTransaction->iDataLength + 7U) / 8U);
  1124.  
  1125.             // The Start Address on the receiving end as Little Endian
  1126.             tUINT64 iAddressLittleEndian = ptsTransaction->iStartAddress;
  1127.             teFuncStatus = funcCANTS_NativeEndiannessToLittleEndian(&iAddressLittleEndian);
  1128.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to get Address as Little Endian");
  1129.  
  1130.             // The minimal number of bytes which the address can fit within
  1131.             tUINT32 iAddressBytesSize = 0U;
  1132.             tUINT64 iAddressValueToShift = iAddressLittleEndian;
  1133.  
  1134.             // While all the bits have not yet been shifted out
  1135.             do
  1136.             {
  1137.                 // Increment the required minimum number of bytes
  1138.                 ++iAddressBytesSize;
  1139.  
  1140.                 // Shift the address right by a byte
  1141.                 iAddressValueToShift >>= 8U;
  1142.             }
  1143.             while (iAddressValueToShift > 0U);
  1144.  
  1145.             /* Assign the fields within the Set Block Request frame vvv */
  1146.  
  1147.             tsSetBlockRequest.iToAddress = ptsTransaction->iToAddress;
  1148.             tsSetBlockRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1149.             // The CANTS Protocol specifies this number is represented as the number of blocks minus one
  1150.             // E.g., when sending 1 block, this value is 0
  1151.             tsSetBlockRequest.iNumberOfBlocks = iNumberOfBlocks - 1U;
  1152.             tsSetBlockRequest.iStartAddress = ptsTransaction->iStartAddress;
  1153.             tsSetBlockRequest.teAddressSize = (teCANTS_ADDRESS_SIZE)iAddressBytesSize;
  1154.  
  1155.             // The Generic version of the Set Block Request to send over the CAN Bus
  1156.             tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1157.  
  1158.             // Translate the Set Block Request frame to a Generic frame
  1159.             teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsSetBlockRequest, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST, &tsGenericFrame);
  1160.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Request frame to a Generic frame");
  1161.  
  1162.             // Set the queues to be empty before starting the transaction
  1163.             iCANTS_SetBlockPendingAcknowledgements = 0U;
  1164.             iCANTS_SetBlockPendingStatusReports = 0U;
  1165.  
  1166.             // Send the Generic frame over the CAN Bus
  1167.             teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1168.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Request frame");
  1169.  
  1170.             // Specify that we have sent the Set Block request
  1171.             bHasSentRequest = TRUE;
  1172.         }
  1173.  
  1174.         break;
  1175.     }
  1176.  
  1177.     case CANTS_SET_BLOCK_STATUS_ONGOING:
  1178.     {
  1179.         // If there are blocks remaining to be sent
  1180.         if (iBlocksRemaining != 0U)
  1181.         {
  1182.             /* Get the 1 to 8 byte chunk of data to send in the block vvv */
  1183.  
  1184.             // The index of the block to sent
  1185.             // E.g., if this is 0, that corresponds with the left-most bit and the first block is due to be sent
  1186.             tUINT32 iBlockIndex = 0U;
  1187.  
  1188.             // Get the block index next due to be sent
  1189.             // This for loop is guaranteed to terminate because we've already checked the Blocks Remaining bit field is non-zero
  1190.             for (
  1191.                 iBlockIndex = 0U;
  1192.                 ((0x8000000000000000U >> iBlockIndex) & iBlocksRemaining) == 0U;
  1193.                 ++iBlockIndex
  1194.             );
  1195.  
  1196.             // Get the starting index of the block within the data array
  1197.             tUINT32 iStartIndex = iBlockIndex * 8U;
  1198.  
  1199.             // The number of bytes within the block is 8, unless it's the very last block and is not aligned to 8 bytes
  1200.             tUINT32 iBlockSize = 8U;
  1201.  
  1202.             // If the block size extends past the end of the array
  1203.             if ((iStartIndex + iBlockSize) > ptsTransaction->iDataLength)
  1204.             {
  1205.                 // Set the block size to the number of remaining bytes, which will be from 1 to 7 bytes
  1206.                 iBlockSize = ptsTransaction->iDataLength - iStartIndex;
  1207.             }
  1208.  
  1209.             // The block to transfer containing the segment of bytes from the
  1210.             tsCANTS_FRAME_SET_BLOCK_TRANSFER tsTransferBlock = { 0U };
  1211.  
  1212.             /* Assign the fields within the transfer block vvv */
  1213.  
  1214.             tsTransferBlock.iToAddress = ptsTransaction->iToAddress;
  1215.             tsTransferBlock.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1216.             tsTransferBlock.iSequence = iBlockIndex;
  1217.             tsTransferBlock.iDataLength = iBlockSize;
  1218.  
  1219.             // Copy the data from the buffer into the transfer block to be sent
  1220.             for (tUINT32 iByteIndex = 0U; iByteIndex < iBlockSize; ++iByteIndex)
  1221.             {
  1222.                 // Assign the byte
  1223.                 // The start index offsets into the buffer to get the correct block
  1224.                 tsTransferBlock.acData[iByteIndex] = ptsTransaction->pcData[iStartIndex + iByteIndex];
  1225.             }
  1226.  
  1227.             // The generic version of the transfer block to send over the CAN Bus
  1228.             tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1229.  
  1230.             // Translate into the generic frame
  1231.             teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTransferBlock, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER, &tsGenericFrame);
  1232.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Transfer frame into a Generic frame");
  1233.  
  1234.             // Send the frame over the CAN Bus
  1235.             teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1236.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Transfer frame");
  1237.  
  1238.             // If all was successful, clear the bit within the bit field to specify that we've sent it
  1239.             iBlocksRemaining &= ~((0x8000000000000000U) >> iBlockIndex);
  1240.  
  1241.             /* Update the number of bytes sent and remaining vvv */
  1242.             /* If a retransmission is required, this will executed too many times, giving invalid values, therefore we do a check before modifying them */
  1243.  
  1244.             // Update bytes sent
  1245.             if ((ptsTransaction->iBytesSent + iBlockSize) <= ptsTransaction->iDataLength)
  1246.             {
  1247.                 ptsTransaction->iBytesSent += iBlockSize;
  1248.             }
  1249.  
  1250.             // Update bytes remaining
  1251.             if ((ptsTransaction->iBytesRemaining - iBlockSize) >= 0U)
  1252.             {
  1253.                 ptsTransaction->iBytesRemaining -= iBlockSize;
  1254.             }
  1255.         }
  1256.         else
  1257.         {
  1258.             // The Set Block Status Request frame to populate
  1259.             tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST tsStatusRequest = { 0U };
  1260.  
  1261.             /* Assign the fields within the Status Request frame vvv */
  1262.  
  1263.             tsStatusRequest.iToAddress = ptsTransaction->iToAddress;
  1264.             tsStatusRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1265.  
  1266.             // The generic version of the Status Request frame to send over the CAN Bus
  1267.             tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1268.  
  1269.             // Translate the Set Block Status Request frame into a Generic frame
  1270.             teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsStatusRequest, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST, &tsGenericFrame);
  1271.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Status Request frame to a Generic frame");
  1272.  
  1273.             // Set there to initially have no status reports before sending the status request
  1274.             iCANTS_SetBlockPendingStatusReports = 0U;
  1275.  
  1276.             teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1277.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Status Request frame");
  1278.  
  1279.             // All blocks have been sent, so go to the verify state to ensure the destination node received them all
  1280.             ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_VERIFYING;
  1281.         }
  1282.  
  1283.         break;
  1284.     }
  1285.  
  1286.     case CANTS_SET_BLOCK_STATUS_VERIFYING:
  1287.     {
  1288.         // If there are status reports waiting to be read
  1289.         if (iCANTS_SetBlockPendingStatusReports > 0U)
  1290.         {
  1291.             // A bit field of all blocks received by the destination node
  1292.             tUINT64 iBlocksReceived = 0U;
  1293.  
  1294.             // Go through all of them and accumulate the bit field of blocks received
  1295.             // Under normal circumstances, there should only ever be 1 report, but doing this could prevent unnecessary retransmission
  1296.             for (tUINT32 iFrameIndex = 0U; iFrameIndex < iCANTS_SetBlockPendingStatusReports; ++iFrameIndex)
  1297.             {
  1298.                 // Get a pointer to the status report
  1299.                 tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsStatusReport = &(atsCANTS_SetBlockPendingStatusReports[iFrameIndex]);
  1300.  
  1301.                 // If the destination node reports that all blocks have been received and handled
  1302.                 if (ptsStatusReport->bComplete == TRUE)
  1303.                 {
  1304.                     // Signify the transaction has completed
  1305.                     ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_SUCCESS;
  1306.  
  1307.                     // Stop checking the status reports
  1308.                     break;
  1309.                 }
  1310.  
  1311.                 // Set all of the bits from each frame
  1312.                 iBlocksReceived |= ptsStatusReport->iBlocksReceived;
  1313.             }
  1314.  
  1315.             // The number of blocks expected to have been received
  1316.             // We round up to the nearest 8 byte chunk - the +7 ensures it's always rounded up when performing integer division
  1317.             tUINT32 iNumberOfExpectedBlocks = (tUINT32)((ptsTransaction->iDataLength + 7U) / 8U);
  1318.  
  1319.             // It's possible to round up to 65 therefore we cap it at 64
  1320.             if (iNumberOfExpectedBlocks > 64U)
  1321.             {
  1322.                 // Cap the value at 64
  1323.                 iNumberOfExpectedBlocks = 64U;
  1324.             }
  1325.  
  1326.             // A bit field of the blocks expected
  1327.             tUINT64 iExpectedBlocks = 0U;
  1328.  
  1329.             // Set all of the bits within the bit field to specify which blocks are expected
  1330.             for (tUINT32 iBitIndex = 0U; iBitIndex < iNumberOfExpectedBlocks; ++iBitIndex)
  1331.             {
  1332.                 // Shift the bit index to the very left-most bit within the bit field
  1333.                 iExpectedBlocks |= (tUINT64)(1U << (63U - iBitIndex));
  1334.             }
  1335.  
  1336.             // A bit field of any missing blocks
  1337.             tUINT64 iMissingBlocks = (iExpectedBlocks & iBlocksReceived);
  1338.  
  1339.             // If there are some blocks which haven't been received
  1340.             if (iMissingBlocks != 0U)
  1341.             {
  1342.                 // Specify the blocks to retransmit
  1343.                 iBlocksRemaining = iMissingBlocks;
  1344.  
  1345.                 // Set the state to go back to transmitting blocks to send the remaining ones
  1346.                 ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_ONGOING;
  1347.             }
  1348.         }
  1349.  
  1350.         // Signify we've handled all the frames
  1351.         // 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
  1352.         iCANTS_SetBlockPendingStatusReports = 0U;
  1353.  
  1354.         break;
  1355.     }
  1356.  
  1357.     case CANTS_SET_BLOCK_STATUS_SUCCESS: // Fall-through
  1358.     case CANTS_SET_BLOCK_STATUS_FAILURE:
  1359.     {
  1360.         // Restore the static state for the next transaction
  1361.         bHasSentRequest = FALSE;
  1362.  
  1363.         break;
  1364.     }
  1365.  
  1366.     default:
  1367.         EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Transfer state was provided");
  1368.         break;
  1369.     }
  1370.  
  1371.     return BT_SUCCESS;
  1372.  
  1373. CANTS_INVALID_PARAMETER:
  1374. CANTS_TRANSLATE_ERROR:
  1375. CANTS_SEND_ERROR:
  1376.     return BT_FAIL;
  1377. }
  1378.  
  1379. /**
  1380.  * You must call this function after a Set Block transfer has complete, regardless of whether the
  1381.  * transfer status was successful or not.
  1382.  * This will send the Abort frame to the destination node and re-enable the callbacks to the user for
  1383.  * incoming Set Block frames. This includes the Acknowledgement to the Abort frame, meaning once you
  1384.  * call this function, you should expect the callback for the Set Block Acknowledgement Frame to be
  1385.  * invoked (unless you don't have that callback registered).
  1386.  * This function can also be called during a transfer, say in the instance you want to timeout the
  1387.  * transfer or there has been some other error.
  1388.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  1389.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  1390.  * @throws CANTS_TRANSLATE_ERROR if the frame could not be translated.
  1391.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  1392.  * @param ptsTransaction: tsCANTS_SET_BLOCK_OUTGOING_TRANSACTION*: The Set Block transaction to stop
  1393.  * terminate.
  1394.  * @re-entrant:
  1395.  */
  1396. teFUNC_STATUS CANTS_EndSetBlockTransaction(tsCANTS_SET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
  1397. {
  1398.     // The return value from function calls
  1399.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  1400.  
  1401.     // Store the status of the transaction so that we can set it back after resetting the CANTS_SetBlock(...) static state
  1402.     teCANTS_SET_BLOCK_STATUS teInitialStatus = ptsTransaction->teStatus;
  1403.  
  1404.     // Set the status to either SUCCESS or FAILURE
  1405.     ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_SUCCESS;
  1406.  
  1407.     // Call CANTS_SetBlock(...) with either the SUCCESS or FAILURE status so that it resets the static state internally
  1408.     // This is done in case the user calls this End Transaction function prior to a transaction naturally being terminated (e.g., timeout)
  1409.     teFuncStatus = CANTS_SetBlock(ptsTransaction);
  1410.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_INVALID_PARAMETER, "An invalid transaction status was provided");
  1411.  
  1412.     // Restore the transaction status for consistency
  1413.     // This is so that the status doesn't seem to randomly change from the users perspective
  1414.     ptsTransaction->teStatus = teInitialStatus;
  1415.  
  1416.     // The Set Block Abort frame to conclude the transaction
  1417.     tsCANTS_FRAME_SET_BLOCK_ABORT tsSetBlockAbort = { 0U };
  1418.  
  1419.     /* Assign the fields within the Abort frame vvv */
  1420.  
  1421.     tsSetBlockAbort.iToAddress = ptsTransaction->iToAddress;
  1422.     tsSetBlockAbort.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1423.  
  1424.     // The generic version of the abort frame to send over the CAN Bus
  1425.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1426.  
  1427.     // Translate the Set Block Abort frame to the Generic frame
  1428.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsSetBlockAbort, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT, &tsGenericFrame);
  1429.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Abort frame to a Generic frame");
  1430.  
  1431.     // Specify that the transfer has complete
  1432.     // This is done before sending the Abort frame to return callback handing to the user
  1433.     bCANTS_SetBlockBusy = FALSE;
  1434.  
  1435.     // Send the abort frame
  1436.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1437.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Abort frame");
  1438.  
  1439.     return BT_SUCCESS;
  1440.  
  1441. CANTS_INVALID_PARAMETER:
  1442. CANTS_TRANSLATE_ERROR:
  1443. CANTS_SEND_ERROR:
  1444.     return BT_FAIL;
  1445. }
  1446.  
  1447. /**
  1448.  * When you receive a Set Block request, this can be used to send a Positive Acknowledgement frame to
  1449.  * approve the transfer. To receive all of the blocks, you must use CANTS_ReceiveSetBlockTransfer(...).
  1450.  *
  1451.  * Calling this function to Accept the Set Block request will disable any Set Block receive callbacks
  1452.  * to ensure the transfer is handled fully automatically and without interference with anything else
  1453.  * handling Set Block frames.
  1454.  * If the buffer you provide is not large enough to store all of the blocks, this call will fail and a
  1455.  * Negative Acknowledgement will be sent.
  1456.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL
  1457.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  1458.  * @throws CANTS_TRANSLATE_ERROR if there was an error translating a frame.
  1459.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  1460.  * @param ptsRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The request which you're accepting.
  1461.  * @param ptsTransaction: tsCANTS_SET_BLOCK_INCOMING_TRANSACTION*: A pointer to the transaction object
  1462.  * which will be used to transfer the Set Block data
  1463.  * @re-entrant:
  1464.  */
  1465. teFUNC_STATUS CANTS_AcceptSetBlockRequest(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsRequest, tsCANTS_SET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
  1466. {
  1467.     // The return value from function calls
  1468.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  1469.  
  1470.     // Ensure the size of the receiving buffer is at least the minimum required number of bytes to write all of the blocks
  1471.     // We +1 to the number of blocks because the CANTS Protocol specifies that the Number Of Blocks value is the true number minus one
  1472.     // Multiplying by 8 refers to 8 bytes
  1473.     EH_ASSERT(((ptsRequest->iNumberOfBlocks + 1U) * 8U) <= ptsTransaction->iReceiveBufferSize, CANTS_INVALID_PARAMETER, "The receive buffer size is too small to accept a Set Block Request");
  1474.  
  1475.     // The Set Block Request Positive Acknowledgement frame
  1476.     tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT tsAcceptFrame = { 0U };
  1477.  
  1478.     /* Assign the fields within the Accept frame vvv */
  1479.     /* The command and data fields must match the request frame */
  1480.  
  1481.     tsAcceptFrame.teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
  1482.     tsAcceptFrame.iCommand = ptsRequest->iNumberOfBlocks;
  1483.     tsAcceptFrame.iToAddress = ptsRequest->iFromAddress;
  1484.     tsAcceptFrame.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1485.     tsAcceptFrame.iDataLength = (tUINT32)ptsRequest->teAddressSize;
  1486.  
  1487.     // The start address of the Set Block request in little endian
  1488.     // This is used to write it back to the source node (just part of the CANTS Protocol)
  1489.     tUINT64 iAddressLittleEndian = ptsRequest->iStartAddress;
  1490.  
  1491.     // Convert the address to little endian
  1492.     teFuncStatus = funcCANTS_NativeEndiannessToLittleEndian(&iAddressLittleEndian);
  1493.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate address of Set Block Request to little endian");
  1494.  
  1495.     // Copy the address bytes into the acknowledgement buffer
  1496.     for (tUINT32 iByteIndex = 0; iByteIndex < tsAcceptFrame.iDataLength; ++iByteIndex)
  1497.     {
  1498.         // Copy the byte
  1499.         tsAcceptFrame.acData[iByteIndex] = (((tUINT8*)(&iAddressLittleEndian))[iByteIndex]);
  1500.     }
  1501.  
  1502.     // The generic version of the positive acknowledgement frame to send over the CAN Bus
  1503.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1504.  
  1505.     // Translate the positive acknowledgement frame to a generic frame
  1506.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsAcceptFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
  1507.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Positive Acknowledgement to a Generic frame");
  1508.  
  1509.     /* Set the initial counters for received frames vvv */
  1510.  
  1511.     iCANTS_SetBlockPendingAborts = 0U;
  1512.     iCANTS_SetBlockPendingStatusRequests = 0U;
  1513.     iCANTS_SetBlockPendingTransfers = 0U;
  1514.  
  1515.     /* Set the initial transaction values */
  1516.  
  1517.     ptsTransaction->iBytesReceived = 0U;
  1518.     // This value is always aligned to 8 bytes despite the fact that <8 bytes can be transferred
  1519.     ptsTransaction->iBytesRemaining = (ptsRequest->iNumberOfBlocks + 1U) * 8U;
  1520.  
  1521.     // Specify that there is an ongoing Set Block transaction
  1522.     bCANTS_SetBlockBusy = TRUE;
  1523.  
  1524.     // Send the positive acknowledgement
  1525.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1526.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Positive Acknowledgement frame");
  1527.  
  1528.     return BT_SUCCESS;
  1529.  
  1530. CANTS_INVALID_PARAMETER:
  1531. CANTS_TRANSLATE_ERROR:
  1532. CANTS_SEND_ERROR:
  1533.     // Specify there are no ongoing Set Block transaction in the case of failure
  1534.     bCANTS_SetBlockBusy = FALSE;
  1535.  
  1536.     return BT_FAIL;
  1537. }
  1538.  
  1539. /**
  1540.  * This is to be sent after a Set Block request has been sent but cannot be fulfilled. If Set Block
  1541.  * requests aren't handled with a callback by the user, this function is automatically invoked.
  1542.  * @returns BT_SUCCESS if there was no excception, otherwise BT_FAIL
  1543.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  1544.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  1545.  * @param ptsRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The Set Block Request to reject.
  1546.  * @re-entrant:
  1547.  */
  1548. teFUNC_STATUS CANTS_RejectSetBlockRequest(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsRequest)
  1549. {
  1550.     // The return value from function calls
  1551.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  1552.  
  1553.     // The Negative Acknowledgement frame to send to the source node
  1554.     tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT tsRejectFrame = { 0U };
  1555.  
  1556.     /* Populate the fields within the Reject Frame vvv */
  1557.  
  1558.     tsRejectFrame.teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
  1559.     tsRejectFrame.iToAddress = ptsRequest->iFromAddress;
  1560.     tsRejectFrame.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1561.     /* The data length and command fields go unused in a Negative Acknowledgement frame, but we assign them to value regardless */
  1562.     /* This is just in case the destination node can infer sensitive information from the undefined memory */
  1563.     tsRejectFrame.iCommand = 0U;
  1564.     tsRejectFrame.iDataLength = 0U;
  1565.  
  1566.     // The generic version of the negative acknowledgement frame to send over the CAN Bus
  1567.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1568.  
  1569.     // Translate the Negative Acknowledgement frame to the Generic frame
  1570.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsRejectFrame, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
  1571.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Negative Acknowledgement frame to a Generic frame");
  1572.  
  1573.     // Send the Negative Acknowledgement frame over the CAN Bus
  1574.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1575.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Negative Acknowledgement frame");
  1576.  
  1577.     return BT_SUCCESS;
  1578.  
  1579. CANTS_TRANSLATE_ERROR:
  1580. CANTS_SEND_ERROR:
  1581.     return BT_FAIL;
  1582. }
  1583.  
  1584. /**
  1585.  * This is used to receive blocks after a Set Block request has been Accepted via
  1586.  * CANTS_AcceptSetBlockRequest(...). This is to be continuously called until the transaction status is
  1587.  * either Successful or Failed.
  1588.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  1589.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  1590.  * @param ptsRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The request used to instantiate the
  1591.  * transaction.
  1592.  * @param ptsTransaction: tsCANTS_SET_BLOCK_INCOMING_TRANSACTION*: The current state of the
  1593.  * transaction.
  1594.  * @re-entrant:
  1595.  */
  1596. teFUNC_STATUS CANTS_ReceiveSetBlockTransfer(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsRequest, tsCANTS_SET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
  1597. {
  1598.     // The return value from function calls
  1599.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  1600.  
  1601.     // A bit field to indicate which blocks have and haven't been received
  1602.     static tUINT64 iBlocksReceived = 0U;
  1603.  
  1604.     // A bit field of the blocks expected to be received
  1605.     static tUINT64 iExpectedBlocks = 0U;
  1606.  
  1607.     // The number of bytes expected to be received within the ongoing transfer
  1608.     // This is stored statically just to reduce the number of times it needs to be calculated
  1609.     static tUINT32 iTotalExpectedBytes = 0U;
  1610.  
  1611.     // Switch to the specific transaction status
  1612.     switch (ptsTransaction->teStatus)
  1613.     {
  1614.     case CANTS_SET_BLOCK_STATUS_PENDING:
  1615.     {
  1616.         // Specify no blocks have been received yet
  1617.         iBlocksReceived = 0U;
  1618.  
  1619.         // Initially assign the expected blocks to 0 before setting any bits
  1620.         iExpectedBlocks = 0U;
  1621.  
  1622.         // Assign the bits within the bit field for the blocks expected to be received from the source node
  1623.         for (tUINT32 iBitIndex = 0U; iBitIndex < ptsRequest->iNumberOfBlocks; ++iBitIndex)
  1624.         {
  1625.             // Assign the bit
  1626.             iExpectedBlocks |= (0x8000000000000000U >> iBitIndex);
  1627.         }
  1628.  
  1629.         // Assign the number of expected bytes
  1630.         iTotalExpectedBytes = (ptsRequest->iNumberOfBlocks * 8U);
  1631.  
  1632.         // Go to the ongoing state
  1633.         ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_ONGOING;
  1634.  
  1635.         break;
  1636.     }
  1637.  
  1638.     case CANTS_SET_BLOCK_STATUS_ONGOING:
  1639.     {
  1640.         // Go though any pending transfer frames
  1641.         for (tUINT32 iFrameIndex = 0U; iFrameIndex < iCANTS_SetBlockPendingTransfers; ++iFrameIndex)
  1642.         {
  1643.             // Get a pointer to the transfer frame
  1644.             tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsTransfer = &(atsCANTS_SetBlockPendingTransfers[iFrameIndex]);
  1645.  
  1646.             // Get the starting index of the block
  1647.             tUINT32 iStartIndex = (8U * ptsTransfer->iSequence);
  1648.  
  1649.             // Ensure there is enough space within the receive buffer to write into
  1650.             // This check is already performed in CANTS_AcceptSetBlockRequest(...) but this is just an extra precaution
  1651.             EH_ASSERT((iStartIndex + ptsTransfer->iDataLength) <= ptsTransaction->iReceiveBufferSize, CANTS_INVALID_PARAMETER, "The receive buffer size is not large enough to write a transfer block to");
  1652.  
  1653.             // Copy the block from the transfer frame into the receive buffer
  1654.             for (tUINT32 iByteIndex = 0U; iByteIndex < ptsTransfer->iDataLength; ++iByteIndex)
  1655.             {
  1656.                 // Copy the byte
  1657.                 ptsTransaction->pcReceiveBuffer[iStartIndex + iByteIndex] = ptsTransfer->acData[iByteIndex];
  1658.             }
  1659.  
  1660.             /* Update the transaction status values vvv */
  1661.             /* 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 */
  1662.             /* 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 */
  1663.  
  1664.             // Update the bytes received value
  1665.             if ((ptsTransaction->iBytesReceived + 8U) <= iTotalExpectedBytes)
  1666.             {
  1667.                 ptsTransaction->iBytesReceived += 8U;
  1668.             }
  1669.  
  1670.             // Update the bytes remaining value
  1671.             if (ptsTransaction->iBytesRemaining >= 8U)
  1672.             {
  1673.                 ptsTransaction->iBytesRemaining -= 8U;
  1674.             }
  1675.  
  1676.             // Specify that we have received the respective block
  1677.             iBlocksReceived |= (0x8000000000000000U >> ptsTransfer->iSequence);
  1678.         }
  1679.  
  1680.         // Signify that we have handled all of the pending blocks
  1681.         iCANTS_SetBlockPendingTransfers = 0U;
  1682.  
  1683.         // If the source node has requested the transaction status
  1684.         if (iCANTS_SetBlockPendingStatusRequests > 0U)
  1685.         {
  1686.             // Go to the verifying state
  1687.             ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_VERIFYING;
  1688.         }
  1689.  
  1690.         // TODO: Check for abort frames here and if they exist then go into the verifying state?
  1691.  
  1692.         break;
  1693.     }
  1694.  
  1695.     case CANTS_SET_BLOCK_STATUS_VERIFYING:
  1696.     {
  1697.         // If there is at least 1 pending status request
  1698.         if (iCANTS_SetBlockPendingStatusRequests > 0U)
  1699.         {
  1700.             /* The Status Request frame doesn't actually include anything useful so there's no need to read it at this point */
  1701.             // Mute warning for unused value
  1702.             // TODO: Just remove this array all together?
  1703.             (void)atsCANTS_SetBlockPendingStatusRequests;
  1704.  
  1705.             // The status report to send to the Set Block source node
  1706.             tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT tsStatusReport = { 0U };
  1707.  
  1708.             /* Assign the fields within the Status Report frame vvv */
  1709.  
  1710.             tsStatusReport.iToAddress = ptsRequest->iFromAddress;
  1711.             tsStatusReport.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1712.             tsStatusReport.bComplete = ptsTransaction->bComplete;
  1713.             tsStatusReport.iBlocksReceived = iBlocksReceived;
  1714.  
  1715.             // The generic version of the status report frame to send over the CAN Bus
  1716.             tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1717.  
  1718.             // Translate the status report to a generic frame
  1719.             teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsStatusReport, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT, &tsGenericFrame);
  1720.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Set Block Status Report to a Generic frame");
  1721.  
  1722.             // Send the status report frame
  1723.             teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1724.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Status Report frame");
  1725.  
  1726.             // Signify that we have handled the request(s)
  1727.             iCANTS_SetBlockPendingStatusRequests = 0U;
  1728.         }
  1729.  
  1730.         // If there are more transfer frames to handle
  1731.         if (iCANTS_SetBlockPendingTransfers > 0U)
  1732.         {
  1733.             // Change to the ongoing state
  1734.             ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_ONGOING;
  1735.         }
  1736.         // If there are any abort frames
  1737.         else if (iCANTS_SetBlockPendingAborts > 0U)
  1738.         {
  1739.             /* We acknowledge the abort frame regardless of whether the transaction has complete or not */
  1740.  
  1741.             // The positive acknowledgement to send to the source node
  1742.             tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT tsPositiveAcknowledgement = { 0U };
  1743.  
  1744.             /* We don't need to get the specific abort frame because they don't contain anything unique */
  1745.  
  1746.             /* Assign the fields within the acknowledgement frame vvv */
  1747.             /* The command and data length fields are unused but we define then to ensure we don't send random data in the memory */
  1748.  
  1749.             tsPositiveAcknowledgement.teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
  1750.             tsPositiveAcknowledgement.iToAddress = ptsRequest->iFromAddress;
  1751.             tsPositiveAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1752.             tsPositiveAcknowledgement.iCommand = 0U;
  1753.             tsPositiveAcknowledgement.iDataLength = 0U;
  1754.  
  1755.             // The generic frame to send over the CAN Bus
  1756.             tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1757.  
  1758.             // Translate from the Positive Acknowledgement frame to the Generic frame
  1759.             teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsPositiveAcknowledgement, CANTS_FRAME_TYPE_SET_BLOCK, CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
  1760.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Set Block Positive Acknowledgement frame to a Generic frame");
  1761.  
  1762.             // Send the Positive Acknowledgement frame
  1763.             teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1764.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Set Block Positive Acknowledgement frame");
  1765.  
  1766.             // If the transaction is confirmed to be completed by the user
  1767.             if (ptsTransaction->bComplete == TRUE)
  1768.             {
  1769.                 // Set the state to SUCCESS
  1770.                 ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_SUCCESS;
  1771.             }
  1772.             // Otherwise the source node is prematurely aborting, indicating a failed transfer
  1773.             else
  1774.             {
  1775.                 // Set the state to FAILURE because the transaction aborted prior to the user calling CANTS_EndIncomingSetBlock(...)
  1776.                 ptsTransaction->teStatus = CANTS_SET_BLOCK_STATUS_FAILURE;
  1777.             }
  1778.         }
  1779.         else
  1780.         {
  1781.             /* Continue in the state we are currently in until the source node sends a frame */
  1782.             /* It is implementation defined to timeout if desired */
  1783.             (void)0;
  1784.         }
  1785.  
  1786.         break;
  1787.     }
  1788.  
  1789.     case CANTS_SET_BLOCK_STATUS_SUCCESS: // Fall-through
  1790.     case CANTS_SET_BLOCK_STATUS_FAILURE:
  1791.     {
  1792.         // Specify there is no longer an ongoing Set Block transaction
  1793.         bCANTS_SetBlockBusy = FALSE;
  1794.  
  1795.         break;
  1796.     }
  1797.  
  1798.     default:
  1799.     {
  1800.         EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Incoming Transaction status was provided");
  1801.         break;
  1802.     }
  1803.     }
  1804.  
  1805.     return BT_SUCCESS;
  1806.  
  1807. CANTS_SEND_ERROR:
  1808. CANTS_TRANSLATE_ERROR:
  1809. CANTS_INVALID_PARAMETER:
  1810.     return BT_FAIL;
  1811. }
  1812.  
  1813. /**
  1814.  * This function is called once all blocks have been received and handled by the user. This must be
  1815.  * called exactly once after an incoming Set Block transaction has been handled via
  1816.  * CANTS_ReceiveSetBlockTransfer(...) and all bytes have been received and handled by the user (e.g.,
  1817.  * copying to memory elsewhere).
  1818.  * The CANTS Protocol does not support the ability for the receiving node of a Set Block to terminate
  1819.  * a transaction.
  1820.  * @returns BT_SUCCESS always
  1821.  * @param ptsTransaction: tsCANTS_SET_BLOCK_INCOMING_TRANSACTION*: A pointer to the transaction to end
  1822.  * @re-entrant:
  1823.  */
  1824. teFUNC_STATUS CANTS_EndIncomingSetBlock(tsCANTS_SET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
  1825. {
  1826.     // Specify the received data has all been handled by the user
  1827.     ptsTransaction->bComplete = TRUE;
  1828.  
  1829.     // Specify there is no longer an ongoing Set Block transaction
  1830.     bCANTS_SetBlockBusy = FALSE;
  1831.  
  1832.     return BT_SUCCESS;
  1833. }
  1834.  
  1835. /** TODO: Add exceptions CANTS_TRANSLATE_ERROR and CANTS_SEND_ERROR to EA
  1836.  * Receives blocks from another node. You provide a transaction state then continuously call this
  1837.  * function until all blocks are received. It is up to your own implementation on how to handle
  1838.  * unreceived blocks, though you can use CANTS_RequestRemainingBlocks(...) to re-request remaining
  1839.  * blocks if you have determined the source node has not sent them all.
  1840.  * To end the transaction, you must call CANTS_EndGetBlockTransaction(...) regardless of whether all
  1841.  * blocks were received or not.
  1842.  * If the number of bytes you're attempting to receive cannot be contained within the buffer you
  1843.  * provide, the request will not be sent and the call will fail. Important to note, all Get Block
  1844.  * requests are aligned to 8 byte blocks, meaning your buffer must be able to contain the number of
  1845.  * bytes you want, rounded up to an 8 byte chunk, e.g., if you want to receive 9 bytes, you buffer
  1846.  * size must be at least 16 bytes in size.
  1847.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  1848.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  1849.  * @param ptsTransaction: tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION*:
  1850.  * @re-entrant:
  1851.  */
  1852. teFUNC_STATUS CANTS_GetBlock(tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
  1853. {
  1854.     // The value returned from function calls
  1855.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  1856.  
  1857.     // Ensure the receive buffer size is large enough for all bytes
  1858.     EH_ASSERT(ptsTransaction->iReceiveBufferSize >= ptsTransaction->iNumberOfBytes, CANTS_INVALID_PARAMETER, "The receive buffer size is less than the required minimum for a Get Block transaction");
  1859.  
  1860.     // Specify that there is an ongoing Get Block transaction
  1861.     bCANTS_GetBlockBusy = TRUE;
  1862.  
  1863.     // A flag to specify if the Get Block request has been sent
  1864.     static tBOOL bHasSentRequest = FALSE;
  1865.  
  1866.     // Switch to the specific Get Block Status
  1867.     switch (ptsTransaction->teStatus)
  1868.     {
  1869.     case CANTS_GET_BLOCK_STATUS_PENDING:
  1870.     {
  1871.         // If the Get Block Request frame has already been sent
  1872.         if (bHasSentRequest == TRUE)
  1873.         {
  1874.             // If there is at least one Get Block Acknowledgement waiting
  1875.             if (iCANTS_GetBlockPendingAcknowledgements > 0U)
  1876.             {
  1877.                 // There should only ever be one acknowledgement after a Get Block Request has been sent, therefore just get the first one
  1878.                 tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsAcknowledgement = &(atsCANTS_GetBlockPendingAcknowledgements[0U]);
  1879.  
  1880.                 // Switch for the specific type of acknowledgement
  1881.                 switch (ptsAcknowledgement->teAcknowledgement)
  1882.                 {
  1883.                 case CANTS_POSITIVE_ACKNOWLEDGEMENT:
  1884.                 {
  1885.                     // Request all of the blocks from the source node
  1886.                     // "Remaining Blocks" in this instance is just all of the blocks
  1887.                     teFuncStatus = CANTS_RequestRemainingBlocks(ptsTransaction);
  1888.                     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to request remaining Get Block blocks");
  1889.  
  1890.                     // Go to the ongoing transaction state
  1891.                     ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_ONGOING;
  1892.  
  1893.                     break;
  1894.                 }
  1895.  
  1896.                 case CANTS_NEGATIVE_ACKNOWLEDGEMENT:
  1897.                 {
  1898.                     // Go to the transaction failure state
  1899.                     ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_FAILURE;
  1900.  
  1901.                     break;
  1902.                 }
  1903.  
  1904.                 default:
  1905.                 {
  1906.                     EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block Acknowledgement enumeration value was provided");
  1907.                     break;
  1908.                 }
  1909.                 }
  1910.             }
  1911.  
  1912.             // Reset the counter to specify that the frames have been handled
  1913.             iCANTS_GetBlockPendingAcknowledgements = 0U;
  1914.         }
  1915.         // No Get Block Request has been sent, so send one
  1916.         else
  1917.         {
  1918.             // The Get Block Request frame to send
  1919.             tsCANTS_FRAME_GET_BLOCK_REQUEST tsGetBlockRequest = { 0U };
  1920.  
  1921.             /* Populate the fields within the Get Block Request frame vvv */
  1922.  
  1923.             tsGetBlockRequest.iToAddress = ptsTransaction->iToAddress;
  1924.             tsGetBlockRequest.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  1925.             tsGetBlockRequest.iStartAddress = ptsTransaction->iStartAddress;
  1926.  
  1927.             // Get the number of blocks to request rounded upwards to the nearest 8 bytes
  1928.             tUINT32 iNumberOfBlocks = (tUINT32)((ptsTransaction->iNumberOfBytes + 7U) / 8U);
  1929.  
  1930.             // Ensure the number of blocks doesn't exceed 63 - It's possible to round up to 64
  1931.             if (iNumberOfBlocks > 63U)
  1932.             {
  1933.                 iNumberOfBlocks = 63U;
  1934.             }
  1935.  
  1936.             // 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)
  1937.             tsGetBlockRequest.iNumberOfBlocks = iNumberOfBlocks - 1U;
  1938.  
  1939.             /* Initialise the transaction state for the transaction vvv */
  1940.  
  1941.             // Initially assign all bits to 0
  1942.             ptsTransaction->iBlocksRequired = 0U;
  1943.  
  1944.             // Set the bit within the bit field for all required blocks
  1945.             for (tUINT32 iBitIndex = 0U; iBitIndex < iNumberOfBlocks; ++iBitIndex)
  1946.             {
  1947.                 // Assign the bit
  1948.                 ptsTransaction->iBlocksRequired |= (0x8000000000000000U >> iBitIndex);
  1949.             }
  1950.  
  1951.             // No blocks have been received yet
  1952.             ptsTransaction->iBlocksReceived = 0U;
  1953.  
  1954.             // The Generic version of the Get Block Request frame to send over the CAN Bus
  1955.             tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  1956.  
  1957.             // Translate from the Get Block Request frame to the Generic frame
  1958.             teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsGetBlockRequest, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST, &tsGenericFrame);
  1959.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Get Block Request frame to a Generic frame");
  1960.  
  1961.             // Set the queues to be empty prior to starting the transfer
  1962.             iCANTS_GetBlockPendingAcknowledgements = 0U;
  1963.             iCANTS_GetBlockPendingTransfers = 0U;
  1964.  
  1965.             // Send the Get Block Request frame
  1966.             teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  1967.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Get Block Request frame");
  1968.  
  1969.             // Specify that the Get Block Request has been sent
  1970.             bHasSentRequest = TRUE;
  1971.         }
  1972.  
  1973.         break;
  1974.     }
  1975.  
  1976.     case CANTS_GET_BLOCK_STATUS_ONGOING:
  1977.     {
  1978.         // Go through all pending Get Block Transfer frames
  1979.         for (tUINT32 iFrameIndex = 0U; iFrameIndex < iCANTS_GetBlockPendingTransfers; ++iFrameIndex)
  1980.         {
  1981.             // Get a pointer to the transfer frame
  1982.             tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsTransfer = &(atsCANTS_GetBlockPendingTransfers[iFrameIndex]);
  1983.  
  1984.             // Get the starting index of where the block should be inserted into the receive buffer
  1985.             tUINT32 iStartIndex = (ptsTransfer->iSequence * 8U);
  1986.  
  1987.             // Ensure there is enough capacity within the receive buffer
  1988.             // This check has already been performed prior to the Request even being made but this ensures redundancy
  1989.             EH_ASSERT((iStartIndex + 8U) <= ptsTransaction->iReceiveBufferSize, CANTS_INVALID_PARAMETER, "The receive buffer is not large enough to write a Get Block transfer into");
  1990.  
  1991.             // Copy the data from the transfer frame into the receive buffer
  1992.             // Get Block transactions are always sent in 8 byte chunks, therefore we copy all 8 bytes
  1993.             for (tUINT32 iByteIndex = 0U; iByteIndex < 8U; ++iByteIndex)
  1994.             {
  1995.                 // Copy the byte
  1996.                 ptsTransaction->pcReceiveBuffer[iStartIndex + iByteIndex] = ptsTransfer->acData[iByteIndex];
  1997.             }
  1998.  
  1999.             // Assign the bit corresponding to the bit which we have received
  2000.             ptsTransaction->iBlocksReceived |= (0x8000000000000000U >> ptsTransfer->iSequence);
  2001.         }
  2002.  
  2003.         // Signify that all pending frames have been handled
  2004.         iCANTS_GetBlockPendingTransfers = 0U;
  2005.  
  2006.         break;
  2007.     }
  2008.  
  2009.     case CANTS_GET_BLOCK_STATUS_SUCCESS: // Fall-through
  2010.     case CANTS_GET_BLOCK_STATUS_FAILURE:
  2011.     {
  2012.         // Restore the static state
  2013.         bHasSentRequest = FALSE;
  2014.  
  2015.         // Signify there is no longer an ongoing Get Block transaction
  2016.         bCANTS_GetBlockBusy = FALSE;
  2017.  
  2018.         break;
  2019.     }
  2020.  
  2021.     default:
  2022.     {
  2023.         EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block Status was provided");
  2024.         break;
  2025.     }
  2026.     }
  2027.  
  2028.     return BT_SUCCESS;
  2029.  
  2030. CANTS_INVALID_PARAMETER:
  2031. CANTS_TRANSLATE_ERROR:
  2032. CANTS_SEND_ERROR:
  2033.     return BT_FAIL;
  2034. }
  2035.  
  2036. /** TODO: Add CANTS_TRANSLATE_ERROR to EA
  2037.  * This will request any remaining blocks which have not been received by the Destination node of a
  2038.  * Get Block transaction. The reason this exists is because CAN-TS supports no method to determine the
  2039.  * transfer status of a Get Block transaction, therefore it's implementation defined for at what point
  2040.  * to re-request blocks which are not yet received.
  2041.  * You would likely call this after a specified period of time multiplied by the number of expected
  2042.  * blocks, e.g., 5 milliseconds * Number of remaining blocks. If after this period, there are missing
  2043.  * blocks, you can determine they were likely lost during transmission.
  2044.  * It is valid to call this function at any point during a data transfer.
  2045.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  2046.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  2047.  * @throws CANTS_SEND_ERROR if there was an error while sending a frame.
  2048.  * @param ptsTransaction: tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION*: The transaction to request the
  2049.  * remaining blocks for.
  2050.  * @re-entrant:
  2051.  */
  2052. teFUNC_STATUS CANTS_RequestRemainingBlocks(tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
  2053. {
  2054.     // The return value from function calls
  2055.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  2056.  
  2057.     // Ensure there's actually an ongoing transaction before requesting blocks
  2058.     EH_ASSERT(bCANTS_GetBlockBusy == TRUE, CANTS_INVALID_PARAMETER, "There is not currently an ongoing Get Block transaction");
  2059.  
  2060.     // A bit field of the blocks not yet received and must be requested
  2061.     tUINT64 iBlocksNotReceivedYet = 0U;
  2062.  
  2063.     // This is solved via the following:
  2064.     // BlocksNotYetReceived = (NOT(BlocksReceived) AND BlocksRequired)
  2065.     // This is done instead of an XOR so that blocks which aren't expected are not requested
  2066.     // E.g.:
  2067.     /*
  2068.      * Required           | 11110000
  2069.      * Received           | 11001000
  2070.      * -------------------+---------
  2071.      * Req. XOR Recv.     | 00111000
  2072.      * -------------------+---------
  2073.      * NOT Recv.          | 00110111
  2074.      * NOT Recv. AND Req. | 00110000
  2075.      *
  2076.      * -------------------+---------
  2077.      * Expected Value     | 00110000
  2078.      */
  2079.  
  2080.     // NOT Received
  2081.     iBlocksNotReceivedYet = ~(ptsTransaction->iBlocksReceived);
  2082.  
  2083.     // AND Requested
  2084.     iBlocksNotReceivedYet &= ptsTransaction->iBlocksRequired;
  2085.  
  2086.     // The frame to send to the source node to request blocks
  2087.     // A Start frame can be sent more than once to request blocks
  2088.     tsCANTS_FRAME_GET_BLOCK_START tsGetBlockStart = { 0U };
  2089.  
  2090.     /* Populate the fields within the Start frame vvv */
  2091.  
  2092.     tsGetBlockStart.iBlocksToGet = iBlocksNotReceivedYet;
  2093.     tsGetBlockStart.iToAddress = ptsTransaction->iToAddress;
  2094.     tsGetBlockStart.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  2095.  
  2096.     // The generic version of the start frame to send over the CAN Bus
  2097.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  2098.  
  2099.     // Translate the Start frame into the Generic frame
  2100.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsGetBlockStart, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_START, &tsGenericFrame);
  2101.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Start frame into a Generic frame");
  2102.  
  2103.     // Send the start frame
  2104.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  2105.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Get Block Start frame");
  2106.  
  2107.     return BT_SUCCESS;
  2108.  
  2109. CANTS_INVALID_PARAMETER:
  2110. CANTS_TRANSLATE_ERROR:
  2111. CANTS_SEND_ERROR:
  2112.     return BT_FAIL;
  2113. }
  2114.  
  2115. /** TODO: Add CANTS_TRANSLATE_ERROR and CANTS_SEND_ERROR to EA
  2116.  * This will end a Get Block transaction. Internally, this will send the Abort frame to the
  2117.  * Destination node of the transfer and re-enable user callbacks.
  2118.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  2119.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  2120.  * @param ptsTransaction: tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION*: The transaction to end
  2121.  * @re-entrant:
  2122.  */
  2123. teFUNC_STATUS CANTS_EndGetBlockTransaction(tsCANTS_GET_BLOCK_OUTGOING_TRANSACTION* ptsTransaction)
  2124. {
  2125.     // The return value from function calls
  2126.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  2127.  
  2128.     // Ensure there is an ongoing Get Block transaction
  2129.     EH_ASSERT(bCANTS_GetBlockBusy == TRUE, CANTS_INVALID_PARAMETER, "Attempted to end a Get Block transaction while there is not one ongoing")
  2130.  
  2131.     // The Get Block abort frame
  2132.     tsCANTS_FRAME_GET_BLOCK_ABORT tsGetBlockAbort = { 0U };
  2133.  
  2134.     /* Populate the fields within the abort frame vvv */
  2135.  
  2136.     tsGetBlockAbort.iToAddress = ptsTransaction->iToAddress;
  2137.     tsGetBlockAbort.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  2138.  
  2139.     // The generic version of the Get Block Abort frame to send over the CAN Bus
  2140.     tsCANTS_FRAME_GENERIC tsGenericFrame;
  2141.  
  2142.     // Translate from Get Block Abort frame to a Generic frame
  2143.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsGetBlockAbort, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT, &tsGenericFrame);
  2144.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Get Block Abort frame to a Generic frame");
  2145.  
  2146.     // Specify there is no longer an ongoing Get Block transaction
  2147.     bCANTS_GetBlockBusy = FALSE;
  2148.  
  2149.     // Send the Get Block Abort frame
  2150.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  2151.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send a Get Block Abort frame");
  2152.  
  2153.     // If all blocks have been received
  2154.     // We check this using the AND operation instead of simply equality in case the Blocks Received value has some other arbitrary bits set
  2155.     if ((ptsTransaction->iBlocksRequired & ptsTransaction->iBlocksReceived) == ptsTransaction->iBlocksRequired)
  2156.     {
  2157.         // The transaction has successfully completed
  2158.         ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_SUCCESS;
  2159.     }
  2160.     else
  2161.     {
  2162.         // Not all blocks have been received, therefore the transaction has failed
  2163.         ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_FAILURE;
  2164.     }
  2165.  
  2166.     // Call the Get Block function a final time with the new transaction status so that it can reset the static state and such
  2167.     teFuncStatus = CANTS_GetBlock(ptsTransaction);
  2168.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_INVALID_PARAMETER, "Failed to perform a final Get Block state transition");
  2169.  
  2170.     return BT_SUCCESS;
  2171.  
  2172. CANTS_INVALID_PARAMETER:
  2173. CANTS_TRANSLATE_ERROR:
  2174. CANTS_SEND_ERROR:
  2175.     return BT_FAIL;
  2176. }
  2177.  
  2178. /** TODO: Add CANTS_TRANSLATE_ERROR to EA
  2179.  * This will send a Positive Acknowledgement to the node which made the Get Block request. Once you
  2180.  * have accepted the request, you must make calls to CANTS_TransmitGetBlockTransfer(...) until all
  2181.  * blocks have been sent to the recipient.
  2182.  * This will also disable any registered callbacks for Get Block packets to allow this object to
  2183.  * handle all of them. This avoids any other packet handling from changing the state of the
  2184.  * transaction.
  2185.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  2186.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  2187.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  2188.  * @param ptsRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The Get Block request
  2189.  * @param ptsTransaction: tsCANTS_GET_BLOCK_INCOMING_TRANSACTION*: A pointer to the incoming get block
  2190.  * transaction object.
  2191.  * @re-entrant:
  2192.  */
  2193. teFUNC_STATUS CANTS_AcceptGetBlockRequest(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsRequest, tsCANTS_GET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
  2194. {
  2195.     // The return value from function calls
  2196.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  2197.  
  2198.     // The Positive Acknowledgement frame for the Get Block Request
  2199.     tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT tsRequestAcknowledgement = { 0U };
  2200.  
  2201.     /* Populate the fields within the Positive Acknowledgement frame vvv */
  2202.  
  2203.     tsRequestAcknowledgement.iToAddress = ptsRequest->iFromAddress;
  2204.     tsRequestAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  2205.     tsRequestAcknowledgement.teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
  2206.     tsRequestAcknowledgement.iCommand = ptsRequest->iNumberOfBlocks;
  2207.     tsRequestAcknowledgement.iDataLength = (tUINT8)ptsRequest->teAddressSize;
  2208.  
  2209.     /* Get the address in Little Endian to send back to the requesting node */
  2210.     tUINT64 iAddressLittleEndian = ptsRequest->iStartAddress;
  2211.  
  2212.     // Convert into little endian
  2213.     teFuncStatus = funcCANTS_NativeEndiannessToLittleEndian(&iAddressLittleEndian);
  2214.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to convert address to little endian");
  2215.  
  2216.     // Copy the bytes of the little endian address to the data field of the frame
  2217.     for (tUINT32 iByteIndex = 0U; iByteIndex < tsRequestAcknowledgement.iDataLength; ++iByteIndex)
  2218.     {
  2219.         // Copy the byte
  2220.         tsRequestAcknowledgement.acData[iByteIndex] = (((tUINT8*)&iAddressLittleEndian)[iByteIndex]);
  2221.     }
  2222.  
  2223.     // The generic version of the Positive Acknowledgement frame to send over the CAN Bus
  2224.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  2225.  
  2226.     // Translate from the Acknowledgement frame to a Generic frame
  2227.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsRequestAcknowledgement, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
  2228.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Positive Acknowledgement frame to a Generic frame");
  2229.  
  2230.     // Specify there is now an ongoing Get Block transaction
  2231.     bCANTS_GetBlockBusy = TRUE;
  2232.  
  2233.     // Send the Positive Acknowledgement frame
  2234.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  2235.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Get Block Request Positive Acknowledgement frame");
  2236.  
  2237.     return BT_SUCCESS;
  2238.  
  2239. CANTS_TRANSLATE_ERROR:
  2240. CANTS_SEND_ERROR:
  2241.     // Specify there are no ongoing Get Block transaction in the case of failure
  2242.     bCANTS_GetBlockBusy = FALSE;
  2243.  
  2244.     return BT_FAIL;
  2245. }
  2246.  
  2247. /**
  2248.  * This rejects a Get Block Request by sending a Negative Acknowledgement packet in response.
  2249.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  2250.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  2251.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  2252.  * @param ptsRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The Get Block request you want to reject.
  2253.  * @re-entrant:
  2254.  */
  2255. teFUNC_STATUS CANTS_RejectGetBlockRequest(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsRequest)
  2256. {
  2257.     // The return value from function calls
  2258.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  2259.  
  2260.     // The negative acknowledgement to send to the requesting node
  2261.     tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT tsNegativeAcknowledgement = { 0U };
  2262.  
  2263.     /* Populate the fields within the negative acknowledgement frame vvv */
  2264.  
  2265.     tsNegativeAcknowledgement.iToAddress = ptsRequest->iFromAddress;
  2266.     tsNegativeAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  2267.     tsNegativeAcknowledgement.teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
  2268.  
  2269.     // The command and data fields go unused
  2270.     tsNegativeAcknowledgement.iCommand = 0U;
  2271.     tsNegativeAcknowledgement.iDataLength = 0U;
  2272.  
  2273.     // The generic version of the negative acknowledgement frame to send on the CAN Bus
  2274.     tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  2275.  
  2276.     // Translate from the Negative Acknowledgement frame to a Generic frame
  2277.     teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsNegativeAcknowledgement, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
  2278.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Get Block Negative Acknowledgement frame to a Generic frame");
  2279.  
  2280.     // Send the negative acknowledgement frame
  2281.     teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  2282.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send a Get Block Negative Acknowledgement frame");
  2283.  
  2284.     return BT_SUCCESS;
  2285.  
  2286. CANTS_TRANSLATE_ERROR:
  2287. CANTS_SEND_ERROR:
  2288.     return BT_FAIL;
  2289. }
  2290.  
  2291. /**
  2292.  * This will handle sending blocks to the node which requested a block. You must keep calling this
  2293.  * function until the status is either CANTS_GET_BLOCK_STATUS_SUCCESS or
  2294.  * CANTS_GET_BLOCK_STATUS_FAILURE.
  2295.  * Once one of those states have been hit, you must then call CANTS_EndGetBlockTransfer(...) to re-
  2296.  * enable any registered callbacks.
  2297.  * The CAN-TS protocol does not support the Source side aborting a transfer. If you require this
  2298.  * functionality, you can choose to stop sending blocks and call CANTS_EndGetBlockTransfer(...) during
  2299.  * the transmission - this will allow the receiving node to timeout. Note that the receiving node will
  2300.  * likely continue to send some Start Get Block Transfer frames until it times out. It is favoured to
  2301.  * fulfill the transfer.
  2302.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  2303.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  2304.  * @throws CANTS_SEND_ERROR if the frame failed to send.
  2305.  * @param ptsRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The request for the Get Block transaction
  2306.  * @param ptsTransaction: tsCANTS_GET_BLOCK_INCOMING_TRANSACTION*: The transaction state of the Get
  2307.  * Block request
  2308.  * @re-entrant:
  2309.  */
  2310. teFUNC_STATUS CANTS_TransmitGetBlockTransfer(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsRequest, tsCANTS_GET_BLOCK_INCOMING_TRANSACTION* ptsTransaction)
  2311. {
  2312.     // The return value from function calls
  2313.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  2314.  
  2315.     // A bit field of the requested blocks within start frames
  2316.     static tUINT64 iBlocksRequested = 0U;
  2317.  
  2318.     // Switch to the specific state within the transaction
  2319.     switch (ptsTransaction->teStatus)
  2320.     {
  2321.     case CANTS_GET_BLOCK_STATUS_PENDING:
  2322.     {
  2323.         // Set the initial state of the blocks required
  2324.         // 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
  2325.         iBlocksRequested = 0U;
  2326.  
  2327.         // If there are start frames waiting to be handled
  2328.         if (iCANTS_GetBlockPendingStarts > 0U)
  2329.         {
  2330.             // Go to the ONGOING state
  2331.             ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_ONGOING;
  2332.         }
  2333.         // Else if there are abort frame
  2334.         else if (iCANTS_GetBlockPendingAborts > 0U)
  2335.         {
  2336.             // Remove the compiler warning for the unused queue
  2337.             // TODO: Just remove the array?
  2338.             (void)atsCANTS_SetBlockPendingAborts;
  2339.  
  2340.             // If all blocks have been sent
  2341.             // 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
  2342.             if (ptsTransaction->iBytesRemaining == 0U)
  2343.             {
  2344.                 // It's most likely that we received the Abort frame because the receiving node received all blocks, therefore go to the SUCCESS state
  2345.                 ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_SUCCESS;
  2346.             }
  2347.             // Else we have not even attempted to send all frames
  2348.             else
  2349.             {
  2350.                 // We know there's no chance the receiving node has received all blocks so the transaction has failed
  2351.                 ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_FAILURE;
  2352.             }
  2353.         }
  2354.         else
  2355.         {
  2356.             /* Else just wait until something has been received by the requesting node */
  2357.             /* It is the responsibility of the user to timeout if required */
  2358.             (void)0;
  2359.         }
  2360.  
  2361.         break;
  2362.     }
  2363.  
  2364.     case CANTS_GET_BLOCK_STATUS_ONGOING:
  2365.     {
  2366.         // Go through each pending start frame
  2367.         for (tUINT32 iFrameIndex = 0U; iFrameIndex < iCANTS_GetBlockPendingStarts; ++iFrameIndex)
  2368.         {
  2369.             // A pointer to the Start frame
  2370.             tsCANTS_FRAME_GET_BLOCK_START* ptsStartFrame = &(atsCANTS_GetBlockPendingStarts[iFrameIndex]);
  2371.  
  2372.             // Add any requested blocks to bit field of blocks which need sent
  2373.             iBlocksRequested |= ptsStartFrame->iBlocksToGet;
  2374.         }
  2375.  
  2376.         // Signify that all pending start frames have been handled
  2377.         iCANTS_GetBlockPendingStarts = 0U;
  2378.  
  2379.         // If there are blocks which need sent
  2380.         if (iBlocksRequested != 0U)
  2381.         {
  2382.             // Get the index of the first block which is requested
  2383.             tUINT32 iRequestedBlockIndex = 0U;
  2384.  
  2385.             // Shift to the left until the left-most bit is a 1 while keeping track of the index
  2386.             // This is guaranteed to terminate because we have already ensured iBlocksRequested is non-zero
  2387.             while ((0x8000000000000000U & (iBlocksRequested << iRequestedBlockIndex)) == 0U)
  2388.             {
  2389.                 // Increment the block index
  2390.                 ++iRequestedBlockIndex;
  2391.             }
  2392.  
  2393.             // The starting index of the block requested
  2394.             tUINT32 iStartingIndex = (iRequestedBlockIndex * 8U);
  2395.  
  2396.             // Ensure the buffer is large enough to provide the block requested
  2397.             EH_ASSERT((iStartingIndex + 8U) <= ptsTransaction->iDataLength, CANTS_INVALID_PARAMETER, "The data buffer is not large enough for the block index requested");
  2398.  
  2399.             // The block transfer to send to the requesting node
  2400.             tsCANTS_FRAME_GET_BLOCK_TRANSFER tsTransfer = { 0U };
  2401.  
  2402.             /* Assign the fields within the transfer frame vvv */
  2403.  
  2404.             tsTransfer.iToAddress = ptsRequest->iFromAddress;
  2405.             tsTransfer.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  2406.             tsTransfer.iSequence = iRequestedBlockIndex;
  2407.  
  2408.             // Copy the data from the data buffer into the frame
  2409.             // All Get Block Transfer frames have a data field of 8 bytes
  2410.             for (tUINT32 iByteIndex = 0U; iByteIndex < 8U; ++iByteIndex)
  2411.             {
  2412.                 // Copy the byte
  2413.                 tsTransfer.acData[iByteIndex] = ptsTransaction->pcData[iStartingIndex + iByteIndex];
  2414.             }
  2415.  
  2416.             // The generic version of the Get Block Transfer frame to send over the CAN Bus
  2417.             tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  2418.  
  2419.             // Translate from the Get Block Transfer frame to the Generic frame
  2420.             teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsTransfer, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER, &tsGenericFrame);
  2421.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate a Get Block Transfer frame to a Generic frame");
  2422.  
  2423.             // Send the Get Block Transfer frame
  2424.             teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  2425.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send Get Block Transfer frame");
  2426.  
  2427.             // Clear the requested block bit
  2428.             iBlocksRequested &= ~(0x8000000000000000U >> iRequestedBlockIndex);
  2429.         }
  2430.         // Else there are no more blocks expecting to be sent so go the pending state awaiting either a Start or Abort frame
  2431.         else
  2432.         {
  2433.             // Set the transaction state to PENDING
  2434.             ptsTransaction->teStatus = CANTS_GET_BLOCK_STATUS_PENDING;
  2435.         }
  2436.  
  2437.         break;
  2438.     }
  2439.  
  2440.     case CANTS_GET_BLOCK_STATUS_SUCCESS: // Fall-through
  2441.     case CANTS_GET_BLOCK_STATUS_FAILURE:
  2442.     {
  2443.         // Specify that there are no ongoing Get Block transactions
  2444.         // This is done before sending a frame because the transaction is complete regardless
  2445.         bCANTS_GetBlockBusy = FALSE;
  2446.  
  2447.         // The acknowledgement frame to send to the requesting node
  2448.         // The reason this is sent under the SUCCESS and FAILURE state is because this state is only entered upon an ABORT frame being received
  2449.         // All ABORT frames should respond with a Positive Acknowledgement frame
  2450.         tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT tsPositiveAcknowledgement = { 0U };
  2451.  
  2452.         /* Populate the fields within the Positive Acknowledgement frame vvv */
  2453.         /* The command and data fields go undefined */
  2454.  
  2455.         tsPositiveAcknowledgement.iToAddress = ptsRequest->iFromAddress;
  2456.         tsPositiveAcknowledgement.iFromAddress = tsCANTS_Configuration.iNodeAddress;
  2457.         tsPositiveAcknowledgement.iDataLength = 0U;
  2458.  
  2459.         // The generic version of the positive acknowledgement frame to send over the CAN Bus
  2460.         tsCANTS_FRAME_GENERIC tsGenericFrame = { 0U };
  2461.  
  2462.         // Translate from the Positive Acknowledgement frame to the Generic frame
  2463.         teFuncStatus = CANTS_TranslateToGenericFrame((void*)&tsPositiveAcknowledgement, CANTS_FRAME_TYPE_GET_BLOCK, CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT, &tsGenericFrame);
  2464.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from a Get Block Positive Acknowledgement frame to a Generic frame");
  2465.  
  2466.         // Send the Get Block Positive Acknowledgement frame
  2467.         teFuncStatus = tsCANTS_Configuration.funcSendFrame(&tsGenericFrame);
  2468.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_SEND_ERROR, "Failed to send a Get Block Positive Acknowledgement frame");
  2469.  
  2470.         break;
  2471.     }
  2472.  
  2473.     default:
  2474.     {
  2475.         EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block state was provided");
  2476.         break;
  2477.     }
  2478.     }
  2479.  
  2480.     return BT_SUCCESS;
  2481.  
  2482. CANTS_INVALID_PARAMETER:
  2483. CANTS_TRANSLATE_ERROR:
  2484. CANTS_SEND_ERROR:
  2485.     return BT_FAIL;
  2486. }
  2487.  
  2488. /**
  2489.  * Translates a CAN-TS frame structure to a generic frame, which is a format able to be given to the
  2490.  * Send Frame function.
  2491.  * You provide a pointer to the CAN-TS frame and specify the frame type and subtype via the
  2492.  * enumeration values. You must make sure you pass in the correct types.
  2493.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  2494.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  2495.  * @param vpCANTSFrame: void*: A pointer to the CAN-TS frame you want to translate into a generic
  2496.  * frame.
  2497.  * @param teFrameType: teCANTS_FRAME_TYPE: The frame type
  2498.  * @param teFrameSubtype: teCANTS_FRAME_SUBTYPE: The frame subtype. If it is an Acknowledgement frame,
  2499.  * use the Generic Acknowledgement enumeration value.
  2500.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The output generic frame.
  2501.  * @re-entrant:
  2502.  */
  2503. teFUNC_STATUS CANTS_TranslateToGenericFrame(void* vpCANTSFrame, teCANTS_FRAME_TYPE teFrameType, teCANTS_FRAME_SUBTYPE teFrameSubtype, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  2504. {
  2505.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  2506.  
  2507.     // We use a switch case instead of some kind of map for efficiency
  2508.     // The frame type is first determined then the subtype
  2509.     // It's not possible to directly use the subtype because different frame types share some of the same subtype values
  2510.     switch (teFrameType)
  2511.     {
  2512.     /* Telecommand */
  2513.     case CANTS_FRAME_TYPE_TELECOMMAND:
  2514.     {
  2515.         switch (teFrameSubtype)
  2516.         {
  2517.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST:
  2518.         {
  2519.             teFuncStatus = CANTS_TranslateFrameTelecommandRequestToGeneric((tsCANTS_FRAME_TELECOMMAND_REQUEST*)vpCANTSFrame, ptsGenericFrame);
  2520.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telecommand Request to Generic frame");
  2521.  
  2522.             break;
  2523.         }
  2524.  
  2525.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT: // Fall-through
  2526.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT: // Fall-though
  2527.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT:
  2528.         {
  2529.             teFuncStatus = CANTS_TranslateFrameTelecommandAcknowledgementToGeneric(ptsGenericFrame, (tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*)vpCANTSFrame);
  2530.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telecommand Acknowledgement to Generic frame");
  2531.  
  2532.             break;
  2533.         }
  2534.  
  2535.         default:
  2536.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Telecommand Subtype was provided");
  2537.             break;
  2538.         }
  2539.  
  2540.         break;
  2541.     }
  2542.  
  2543.     /* Telemetry */
  2544.     case CANTS_FRAME_TYPE_TELEMETRY_REQUEST:
  2545.     {
  2546.         switch (teFrameSubtype)
  2547.         {
  2548.         case CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST:
  2549.         {
  2550.             teFuncStatus = CANTS_TranslateFrameTelemetryRequestToGeneric(ptsGenericFrame, (tsCANTS_FRAME_TELEMETRY_REQUEST*)vpCANTSFrame);
  2551.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telemetry Request to Generic frame");
  2552.  
  2553.             break;
  2554.         }
  2555.  
  2556.         case CANTS_FRAME_SUBTYPE_TELEMETRY_GENERIC_ACKNOWLEDGEMENT: // Fall-through
  2557.         case CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  2558.         case CANTS_FRAME_SUBTYPE_TELEMETRY_NEGATIVE_ACKNOWLEDGEMENT:
  2559.         {
  2560.             teFuncStatus = CANTS_TranslateFrameTelemetryAcknowledgementToGeneric((tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*)vpCANTSFrame, ptsGenericFrame);
  2561.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Telemetry Acknowledgement to Generic frame");
  2562.  
  2563.             break;
  2564.         }
  2565.  
  2566.         default:
  2567.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Telemetry Subtype was provided");
  2568.             break;
  2569.         }
  2570.  
  2571.         break;
  2572.     }
  2573.  
  2574.     /* Unsolicited telemetry */
  2575.     case CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY:
  2576.     {
  2577.         switch (teFrameSubtype)
  2578.         {
  2579.         case CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY:
  2580.         {
  2581.             teFuncStatus = CANTS_TranslateFrameUnsolicitedTelemetryToGeneric(ptsGenericFrame, (tsCANTS_FRAME_UNSOLICITED_TELEMETRY*)vpCANTSFrame);
  2582.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Unsolicited Telemetry to Generic frame");
  2583.  
  2584.             break;
  2585.         }
  2586.  
  2587.         default:
  2588.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The Unsolicited Frame Subtype was invalid");
  2589.             break;
  2590.         }
  2591.  
  2592.         break;
  2593.     }
  2594.  
  2595.     /* Time synchronsation */
  2596.     case CANTS_FRAME_TYPE_TIME_SYNCHRONISATION:
  2597.     {
  2598.         // Time synchronisation frames have an undefined subtype, therefore we don't check it
  2599.  
  2600.         teFuncStatus = CANTS_TranslateFrameTimeSynchronisationToGeneric((tsCANTS_FRAME_TIME_SYNCHRONISATION*)vpCANTSFrame, ptsGenericFrame);
  2601.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Time Synchronisation to Generic frame");
  2602.  
  2603.         break;
  2604.     }
  2605.  
  2606.     /* Set block */
  2607.     case CANTS_FRAME_TYPE_SET_BLOCK:
  2608.     {
  2609.         switch (teFrameSubtype)
  2610.         {
  2611.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST:
  2612.         {
  2613.             teFuncStatus = CANTS_TranslateFrameSetBlockRequestToGeneric((tsCANTS_FRAME_SET_BLOCK_REQUEST*)vpCANTSFrame, ptsGenericFrame);
  2614.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Request to Generic frame");
  2615.  
  2616.             break;
  2617.         }
  2618.  
  2619.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_GENERIC_ACKNOWLEDGEMENT: // Fall-though
  2620.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  2621.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
  2622.         {
  2623.             teFuncStatus = CANTS_TranslateFrameSetBlockAcknowledgementToGeneric((tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*)vpCANTSFrame, ptsGenericFrame);
  2624.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Acknowledgement to Generic frame");
  2625.  
  2626.             break;
  2627.         }
  2628.  
  2629.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER:
  2630.         {
  2631.             teFuncStatus = CANTS_TranslateFrameSetBlockTransferToGeneric(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_TRANSFER*)vpCANTSFrame);
  2632.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Transfer to Generic frame");
  2633.  
  2634.             break;
  2635.         }
  2636.  
  2637.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST:
  2638.         {
  2639.             teFuncStatus = CANTS_TranslateFrameSetBlockStatusRequestToGeneric(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*)vpCANTSFrame);
  2640.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Status Request to Generic frame");
  2641.  
  2642.             break;
  2643.         }
  2644.  
  2645.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT:
  2646.         {
  2647.             teFuncStatus = CANTS_TranslateFrameSetBlockStatusReportToGeneric(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*)vpCANTSFrame);
  2648.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Status Report to Generic frame");
  2649.  
  2650.             break;
  2651.         }
  2652.  
  2653.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT:
  2654.         {
  2655.             teFuncStatus = CANTS_TranslateFrameSetBlockAbortToGeneric((tsCANTS_FRAME_SET_BLOCK_ABORT*)vpCANTSFrame, ptsGenericFrame);
  2656.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Set Block Abort to Generic frame");
  2657.  
  2658.             break;
  2659.         }
  2660.  
  2661.         default:
  2662.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Subtype was provided");
  2663.             break;
  2664.         }
  2665.  
  2666.         break;
  2667.     }
  2668.  
  2669.     /* Get block */
  2670.     case CANTS_FRAME_TYPE_GET_BLOCK:
  2671.     {
  2672.         switch (teFrameSubtype)
  2673.         {
  2674.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST:
  2675.         {
  2676.             teFuncStatus = CANTS_TranslateFrameGetBlockRequestToGeneric((tsCANTS_FRAME_GET_BLOCK_REQUEST*)vpCANTSFrame, ptsGenericFrame);
  2677.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Request to Generic frame");
  2678.  
  2679.             break;
  2680.         }
  2681.  
  2682.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_GENERIC_ACKNOWLEDGEMENT: // Fall-though
  2683.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  2684.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
  2685.         {
  2686.             teFuncStatus = CANTS_TranslateFrameGetBlockAcknowledgementToGeneric((tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*)vpCANTSFrame, ptsGenericFrame);
  2687.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Acknowledgement to Generic frame");
  2688.  
  2689.             break;
  2690.         }
  2691.  
  2692.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_START:
  2693.         {
  2694.             teFuncStatus = CANTS_TranslateFrameGetBlockStartToGeneric(ptsGenericFrame, (tsCANTS_FRAME_GET_BLOCK_START*)vpCANTSFrame);
  2695.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Start to Generic frame");
  2696.  
  2697.             break;
  2698.         }
  2699.  
  2700.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER:
  2701.         {
  2702.             teFuncStatus = CANTS_TranslateFrameGetBlockTransferToGeneric((tsCANTS_FRAME_GET_BLOCK_TRANSFER*)vpCANTSFrame, ptsGenericFrame);
  2703.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Transfer to Generic frame");
  2704.  
  2705.             break;
  2706.         }
  2707.  
  2708.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT:
  2709.         {
  2710.             teFuncStatus = CANTS_TranslateFrameGetBlockAbortToGeneric((tsCANTS_FRAME_GET_BLOCK_ABORT*)vpCANTSFrame, ptsGenericFrame);
  2711.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Get Block Abort to Generic frame");
  2712.  
  2713.             break;
  2714.         }
  2715.  
  2716.         default:
  2717.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block Subtype was provided");
  2718.             break;
  2719.         }
  2720.  
  2721.         break;
  2722.     }
  2723.  
  2724.     default:
  2725.         EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Frame Type was provided");
  2726.         break;
  2727.     }
  2728.  
  2729.     return BT_SUCCESS;
  2730.  
  2731. CANTS_INVALID_PARAMETER:
  2732. CANTS_TRANSLATE_ERROR:
  2733.     return BT_FAIL;
  2734. }
  2735.  
  2736. /**
  2737.  * This is used to translate from a generic frame to a specific frame type. You must know what frame
  2738.  * type you have and only convert to the correct type.
  2739.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  2740.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  2741.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame being translated
  2742.  * @param teFrameType: teCANTS_FRAME_TYPE: The frame type to convert to
  2743.  * @param teFrameSubtype: teCANTS_FRAME_SUBTYPE: The frame subtype to convert to. In the case of
  2744.  * acknowledgement types, use the Generic Acknowledgement enumeration value.
  2745.  * @param vpTranslatedFrame: void*: A pointer to the frame type you're translating to. This is a void
  2746.  * pointer such that you can pass in various frame types.
  2747.  * @re-entrant:
  2748.  */
  2749. teFUNC_STATUS CANTS_TranslateFromGenericFrame(tsCANTS_FRAME_GENERIC* ptsGenericFrame, teCANTS_FRAME_TYPE teFrameType, teCANTS_FRAME_SUBTYPE teFrameSubtype, void* vpTranslatedFrame)
  2750. {
  2751.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  2752.  
  2753.     // We use a switch case instead of some kind of map for efficiency
  2754.     // The frame type is first determined then the subtype
  2755.     // It's not possible to directly use the subtype because different frame types share some of the same subtype values
  2756.     switch (teFrameType)
  2757.     {
  2758.     /* Telecommand */
  2759.     case CANTS_FRAME_TYPE_TELECOMMAND:
  2760.     {
  2761.         switch (teFrameSubtype)
  2762.         {
  2763.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST:
  2764.         {
  2765.             teFuncStatus = CANTS_TranslateFrameGenericToTelecommandRequest((tsCANTS_FRAME_TELECOMMAND_REQUEST*)vpTranslatedFrame, ptsGenericFrame);
  2766.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Telecommand Request");
  2767.  
  2768.             break;
  2769.         }
  2770.  
  2771.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT: // Fall-through
  2772.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT: // Fall-though
  2773.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT:
  2774.         {
  2775.             teFuncStatus = CANTS_TranslateFrameGenericToTelecommandAcknowledgement((tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*)vpTranslatedFrame, ptsGenericFrame);
  2776.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Telecommand Acknowledgement");
  2777.  
  2778.             break;
  2779.         }
  2780.  
  2781.         default:
  2782.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Telecommand Subtype was provided");
  2783.             break;
  2784.         }
  2785.  
  2786.         break;
  2787.     }
  2788.  
  2789.     /* Telemetry */
  2790.     case CANTS_FRAME_TYPE_TELEMETRY_REQUEST:
  2791.     {
  2792.         switch (teFrameSubtype)
  2793.         {
  2794.         case CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST:
  2795.         {
  2796.             teFuncStatus = CANTS_TranslateFrameGenericToTelemetryRequest(ptsGenericFrame, (tsCANTS_FRAME_TELEMETRY_REQUEST*)vpTranslatedFrame);
  2797.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Telemetry Request");
  2798.  
  2799.             break;
  2800.         }
  2801.  
  2802.         case CANTS_FRAME_SUBTYPE_TELEMETRY_GENERIC_ACKNOWLEDGEMENT: // Fall-through
  2803.         case CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  2804.         case CANTS_FRAME_SUBTYPE_TELEMETRY_NEGATIVE_ACKNOWLEDGEMENT:
  2805.         {
  2806.             teFuncStatus = CANTS_TranslateFrameGenericToTelemetryAcknowledgement(ptsGenericFrame, (tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*)vpTranslatedFrame);
  2807.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Telemetry Acknowledgement");
  2808.  
  2809.             break;
  2810.         }
  2811.  
  2812.         default:
  2813.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Telemetry Subtype was provided");
  2814.             break;
  2815.         }
  2816.  
  2817.         break;
  2818.     }
  2819.  
  2820.     /* Unsolicited telemetry */
  2821.     case CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY:
  2822.     {
  2823.         switch (teFrameSubtype)
  2824.         {
  2825.         case CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY:
  2826.         {
  2827.             teFuncStatus = CANTS_TranslateFrameGenericToUnsolicitedTelemetry((tsCANTS_FRAME_UNSOLICITED_TELEMETRY*)vpTranslatedFrame, ptsGenericFrame);
  2828.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Unsolicited Telemetry");
  2829.  
  2830.             break;
  2831.         }
  2832.  
  2833.         default:
  2834.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The Unsolicited Frame Subtype was invalid");
  2835.             break;
  2836.         }
  2837.  
  2838.         break;
  2839.     }
  2840.  
  2841.     /* Time synchronsation */
  2842.     case CANTS_FRAME_TYPE_TIME_SYNCHRONISATION:
  2843.     {
  2844.         // Time synchronisation frames have an undefined subtype, therefore we don't check it
  2845.  
  2846.         teFuncStatus = CANTS_TranslateFrameGenericToTimeSynchronisation((tsCANTS_FRAME_TIME_SYNCHRONISATION*)vpTranslatedFrame, ptsGenericFrame);
  2847.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Time Synchronisation");
  2848.  
  2849.         break;
  2850.     }
  2851.  
  2852.     /* Set block */
  2853.     case CANTS_FRAME_TYPE_SET_BLOCK:
  2854.     {
  2855.         switch (teFrameSubtype)
  2856.         {
  2857.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST:
  2858.         {
  2859.             teFuncStatus = CANTS_TranslateFrameGenericToSetBlockRequest(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_REQUEST*)vpTranslatedFrame);
  2860.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Request");
  2861.  
  2862.             break;
  2863.         }
  2864.  
  2865.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_GENERIC_ACKNOWLEDGEMENT: // Fall-though
  2866.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  2867.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
  2868.         {
  2869.             teFuncStatus = CANTS_TranslateFrameGenericToSetBlockAcknowledgement((tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*)vpTranslatedFrame, ptsGenericFrame);
  2870.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Acknowledgement");
  2871.  
  2872.             break;
  2873.         }
  2874.  
  2875.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER:
  2876.         {
  2877.             teFuncStatus = CANTS_TranslateFrameGenericToSetBlockTransfer(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_TRANSFER*)vpTranslatedFrame);
  2878.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Transfer");
  2879.  
  2880.             break;
  2881.         }
  2882.  
  2883.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST:
  2884.         {
  2885.             teFuncStatus = CANTS_TranslateFrameGenericToSetBlockStatusRequest(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*)vpTranslatedFrame);
  2886.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Status Request");
  2887.  
  2888.             break;
  2889.         }
  2890.  
  2891.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT:
  2892.         {
  2893.             teFuncStatus = CANTS_TranslateFrameGenericToSetBlockStatusReport(ptsGenericFrame, (tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*)vpTranslatedFrame);
  2894.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Status Report");
  2895.  
  2896.             break;
  2897.         }
  2898.  
  2899.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT:
  2900.         {
  2901.             teFuncStatus = CANTS_TranslateFrameGenericToSetBlockAbort((tsCANTS_FRAME_SET_BLOCK_ABORT*)vpTranslatedFrame, ptsGenericFrame);
  2902.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Set Block Abort");
  2903.  
  2904.             break;
  2905.         }
  2906.  
  2907.         default:
  2908.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Set Block Subtype was provided");
  2909.             break;
  2910.         }
  2911.  
  2912.         break;
  2913.     }
  2914.  
  2915.     /* Get block */
  2916.     case CANTS_FRAME_TYPE_GET_BLOCK:
  2917.     {
  2918.         switch (teFrameSubtype)
  2919.         {
  2920.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST:
  2921.         {
  2922.             teFuncStatus = CANTS_TranslateFrameGenericToGetBlockRequest(ptsGenericFrame, (tsCANTS_FRAME_GET_BLOCK_REQUEST*)vpTranslatedFrame);
  2923.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Request");
  2924.  
  2925.             break;
  2926.         }
  2927.  
  2928.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_GENERIC_ACKNOWLEDGEMENT: // Fall-though
  2929.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT: // Fall-through
  2930.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT:
  2931.         {
  2932.             teFuncStatus = CANTS_TranslateFrameGenericToGetBlockAcknowledgement((tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*)vpTranslatedFrame, ptsGenericFrame);
  2933.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Acknowledgemenet");
  2934.  
  2935.             break;
  2936.         }
  2937.  
  2938.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_START:
  2939.         {
  2940.             teFuncStatus = CANTS_TranslateFrameGenericToGetBlockStart((tsCANTS_FRAME_GET_BLOCK_START*)vpTranslatedFrame, ptsGenericFrame);
  2941.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Start");
  2942.  
  2943.             break;
  2944.         }
  2945.  
  2946.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER:
  2947.         {
  2948.             teFuncStatus = CANTS_TranslateFrameGenericToGetBlockTransfer(ptsGenericFrame, (tsCANTS_FRAME_GET_BLOCK_TRANSFER*)vpTranslatedFrame);
  2949.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Transfer");
  2950.  
  2951.             break;
  2952.         }
  2953.  
  2954.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT:
  2955.         {
  2956.             teFuncStatus = CANTS_TranslateFrameGenericToGetBlockAbort(ptsGenericFrame, (tsCANTS_FRAME_GET_BLOCK_ABORT*)vpTranslatedFrame);
  2957.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate Generic frame to Get Block Abort");
  2958.  
  2959.             break;
  2960.         }
  2961.  
  2962.         default:
  2963.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Get Block Subtype was provided");
  2964.             break;
  2965.         }
  2966.  
  2967.         break;
  2968.     }
  2969.  
  2970.     default:
  2971.         EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "An invalid Frame Type was provided");
  2972.         break;
  2973.     }
  2974.  
  2975.     return BT_SUCCESS;
  2976.  
  2977. CANTS_INVALID_PARAMETER:
  2978. CANTS_TRANSLATE_ERROR:
  2979.     return BT_FAIL;
  2980. }
  2981.  
  2982. /**
  2983.  * Sets the source/from address for this node. You must not call this function while there is an
  2984.  * ongoing transaction or while CANTS_HandleFrame(...) is being executed.
  2985.  * @returns BT_SUCCESS always
  2986.  * @param iAddress: tUINT8: The new node address
  2987.  * @re-entrant:
  2988.  */
  2989. teFUNC_STATUS CANTS_SetNodeAddress(tUINT8 iAddress)
  2990. {
  2991.     // Assign the new address
  2992.     tsCANTS_Configuration.iNodeAddress = iAddress;
  2993.  
  2994.     return BT_SUCCESS;
  2995. }
  2996.  
  2997. /**
  2998.  * Sets a callback for a specific frame reception. Ideally, you should assign all of the callbacks
  2999.  * during initialisation, but you can modify the function pointer with this call. To disable a
  3000.  * callback, assign it to 0 - Keep in mind, this may cause things such as an automatic Negative
  3001.  * Acknowledgement being sent as a response to frames.
  3002.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3003.  * @throws CANTS_INVALID_PARAMETER if an invalid parameter was provided.
  3004.  * @param teFrameType: teCANTS_FRAME_TYPE: The frame type of the callback to handle
  3005.  * @param teFrameSubtype: teCANTS_FRAME_SUBTYPE: The specific type of frame. For acknowledgement
  3006.  * frames, use the Generic Acknowledgement enumeration value.
  3007.  * @param (*funcCallback)(): teFUNC_STATUS: The new callback or 0. The function signature must return
  3008.  * teFUNC_STATUS
  3009.  * and take a const pointer to the exact frame type being expected. Refer to tsCANTS_CONFIGURATION for
  3010.  * the function signatures.
  3011.  * @re-entrant:
  3012.  */
  3013. teFUNC_STATUS CANTS_SetCallback(teCANTS_FRAME_TYPE teFrameType, teCANTS_FRAME_SUBTYPE teFrameSubtype, teFUNC_STATUS (*funcCallback)())
  3014. {
  3015.     // Switch for the general frame type
  3016.     // As an implementation note, the reason this function requires the frame type and subtype is because some subtypes have the same underlying value
  3017.     // This means it's not possible to switch on the subtype alone
  3018.     // This could be implemented with a two-keyed map, but that would use more memory, and could potentially be slower, for little benefit
  3019.     switch (teFrameType)
  3020.     {
  3021.     case CANTS_FRAME_TYPE_TELECOMMAND:
  3022.     {
  3023.         switch (teFrameSubtype)
  3024.         {
  3025.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST:
  3026.             tsCANTS_Configuration.funcCallbackOnTelecommandRequest = funcCallback;
  3027.             break;
  3028.  
  3029.         case CANTS_FRAME_SUBTYPE_TELECOMMAND_GENERIC_ACKNOWLEDGEMENT:
  3030.             tsCANTS_Configuration.funcCallbackOnTelecommandAcknowledgement = funcCallback;
  3031.             break;
  3032.  
  3033.         default:
  3034.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Telecommand subtype is invalid");
  3035.             break;
  3036.         }
  3037.  
  3038.         break;
  3039.     }
  3040.  
  3041.     case CANTS_FRAME_TYPE_TELEMETRY_REQUEST:
  3042.     {
  3043.         switch (teFrameSubtype)
  3044.         {
  3045.         case CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST:
  3046.             tsCANTS_Configuration.funcCallbackOnTelemetryRequest = funcCallback;
  3047.             break;
  3048.  
  3049.         case CANTS_FRAME_SUBTYPE_TELEMETRY_GENERIC_ACKNOWLEDGEMENT:
  3050.             tsCANTS_Configuration.funcCallbackOnTelemetryAcknowledgement = funcCallback;
  3051.             break;
  3052.  
  3053.         default:
  3054.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Telemetry subtype is invalid");
  3055.             break;
  3056.         }
  3057.  
  3058.         break;
  3059.     }
  3060.  
  3061.     case CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY:
  3062.     {
  3063.         switch (teFrameSubtype)
  3064.         {
  3065.         case CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY:
  3066.             tsCANTS_Configuration.funcCallbackOnUnsolicitedTelemetry = funcCallback;
  3067.             break;
  3068.  
  3069.         default:
  3070.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Unsolicited Telemetry subtype is invalid");
  3071.             break;
  3072.         }
  3073.  
  3074.         break;
  3075.     }
  3076.  
  3077.     case CANTS_FRAME_TYPE_TIME_SYNCHRONISATION:
  3078.     {
  3079.         /* Time Synchronisation frames have an undefined subtype, therefore we perform no check on it */
  3080.  
  3081.         tsCANTS_Configuration.funcCallbackOnTimeSynchronisation = funcCallback;
  3082.  
  3083.         break;
  3084.     }
  3085.  
  3086.     case CANTS_FRAME_TYPE_SET_BLOCK:
  3087.     {
  3088.         switch (teFrameSubtype)
  3089.         {
  3090.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_REQUEST:
  3091.             tsCANTS_Configuration.funcCallbackOnSetBlockRequest = funcCallback;
  3092.             break;
  3093.  
  3094.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_GENERIC_ACKNOWLEDGEMENT:
  3095.             tsCANTS_Configuration.funcCallbackOnSetBlockAcknowledgement = funcCallback;
  3096.             break;
  3097.  
  3098.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER:
  3099.             tsCANTS_Configuration.funcCallbackOnSetBlockTransfer = funcCallback;
  3100.             break;
  3101.  
  3102.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST:
  3103.             tsCANTS_Configuration.funcCallbackOnSetBlockStatusRequest = funcCallback;
  3104.             break;
  3105.  
  3106.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT:
  3107.             tsCANTS_Configuration.funcCallbackOnSetBlockStatusReport = funcCallback;
  3108.             break;
  3109.  
  3110.         case CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT:
  3111.             tsCANTS_Configuration.funcCallbackOnSetBlockAbort = funcCallback;
  3112.             break;
  3113.  
  3114.         default:
  3115.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Set Block subtype is invalid");
  3116.             break;
  3117.         }
  3118.  
  3119.         break;
  3120.     }
  3121.  
  3122.     case CANTS_FRAME_TYPE_GET_BLOCK:
  3123.     {
  3124.         switch (teFrameSubtype)
  3125.         {
  3126.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST:
  3127.             tsCANTS_Configuration.funcCallbackOnGetBlockRequest = funcCallback;
  3128.             break;
  3129.  
  3130.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_GENERIC_ACKNOWLEDGEMENT:
  3131.             tsCANTS_Configuration.funcCallbackOnGetBlockAcknowledgement = funcCallback;
  3132.             break;
  3133.  
  3134.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_START:
  3135.             tsCANTS_Configuration.funcCallbackOnGetBlockStart = funcCallback;
  3136.             break;
  3137.  
  3138.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER:
  3139.             tsCANTS_Configuration.funcCallbackOnGetBlockTransfer = funcCallback;
  3140.             break;
  3141.  
  3142.         case CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT:
  3143.             tsCANTS_Configuration.funcCallbackOnGetBlockAbort = funcCallback;
  3144.             break;
  3145.  
  3146.         default:
  3147.             EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The provided Get Block subtype is invalid");
  3148.             break;
  3149.         }
  3150.  
  3151.         break;
  3152.     }
  3153.  
  3154.     default:
  3155.         EH_ASSERT(FALSE, CANTS_INVALID_PARAMETER, "The frame subtype specified is not valid");
  3156.         break;
  3157.     }
  3158.  
  3159.     return BT_SUCCESS;
  3160.  
  3161. CANTS_INVALID_PARAMETER:
  3162.     return BT_FAIL;
  3163. }
  3164.  
  3165. /**
  3166.  * Handles incoming telecommand requests.
  3167.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3168.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3169.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3170.  * @param ptsFrame: tsCANTS_FRAME_TELECOMMAND_REQUEST*: A pointer to the CAN-TS frame to handle
  3171.  * @re-entrant:
  3172.  */
  3173. #ifndef UNIT_TEST
  3174. static
  3175. #endif /* UNIT_TEST */
  3176.  teFUNC_STATUS CANTS_HandleIncomingTelecommandRequest(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsFrame)
  3177. {
  3178.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3179.  
  3180.     // If a callback has been assigned
  3181.     if (tsCANTS_Configuration.funcCallbackOnTelecommandRequest != 0U)
  3182.     {
  3183.         // Pass the request to the user
  3184.         teFuncStatus = tsCANTS_Configuration.funcCallbackOnTelecommandRequest(ptsFrame);
  3185.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Telecommand Request");
  3186.     }
  3187.     // Else send a negative acknowledgement by default
  3188.     else
  3189.     {
  3190.         teFuncStatus = CANTS_SendTelecommandAcknowledgement(ptsFrame->iChannel, ptsFrame->iFromAddress, CANTS_NEGATIVE_ACKNOWLEDGEMENT);
  3191.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to send Telecommand Negative Acknowledgement");
  3192.     }
  3193.  
  3194.     return BT_SUCCESS;
  3195.  
  3196. CANTS_HANDLING_ISSUE:
  3197. CANTS_CALLBACK_ERROR:
  3198.     return BT_FAIL;
  3199. }
  3200.  
  3201. /**
  3202.  * Handles the acknowledgement to a telecommand.
  3203.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3204.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3205.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3206.  * @param ptsFrame: tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*: A pointer to the frame to handle
  3207.  * @re-entrant:
  3208.  */
  3209. #ifndef UNIT_TEST
  3210. static
  3211. #endif /* UNIT_TEST */
  3212.  teFUNC_STATUS CANTS_HandleIncomingTelecommandAcknowledgement(tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsFrame)
  3213. {
  3214.     // If a callback has been assigned
  3215.     if (tsCANTS_Configuration.funcCallbackOnTelecommandAcknowledgement != 0U)
  3216.     {
  3217.         // Pass the acknowledgement to the user
  3218.         teFUNC_STATUS teFuncStatus = tsCANTS_Configuration.funcCallbackOnTelecommandAcknowledgement(ptsFrame);
  3219.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Telecommand Acknowledgement");
  3220.     }
  3221.  
  3222.     return BT_SUCCESS;
  3223.  
  3224. CANTS_CALLBACK_ERROR:
  3225.     return BT_FAIL;
  3226. }
  3227.  
  3228. /**
  3229.  * Internally used to handle incoming telemetry request frames.
  3230.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3231.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3232.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3233.  * @param ptsFrame: tsCANTS_FRAME_TELEMETRY_REQUEST*: A pointer to the frame to handle
  3234.  * @re-entrant:
  3235.  */
  3236. #ifndef UNIT_TEST
  3237. static
  3238. #endif /* UNIT_TEST */
  3239.  teFUNC_STATUS CANTS_HandleIncomingTelemetryRequest(tsCANTS_FRAME_TELEMETRY_REQUEST* ptsFrame)
  3240. {
  3241.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3242.  
  3243.     // If a callback has been assigned
  3244.     if (tsCANTS_Configuration.funcCallbackOnTelemetryRequest != 0U)
  3245.     {
  3246.         // Pass the request to the user
  3247.         teFuncStatus = tsCANTS_Configuration.funcCallbackOnTelemetryRequest(ptsFrame);
  3248.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Telemetry Request");
  3249.     }
  3250.     // Else send a negative acknowledgement by default
  3251.     else
  3252.     {
  3253.         teFuncStatus = CANTS_SendTelemetryAcknowledgement(ptsFrame->iChannel, ptsFrame->iFromAddress, 0, 0, CANTS_NEGATIVE_ACKNOWLEDGEMENT);
  3254.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to send Telemetry Negative Acknowledgement");
  3255.     }
  3256.  
  3257.     return BT_SUCCESS;
  3258.  
  3259. CANTS_HANDLING_ISSUE:
  3260. CANTS_CALLBACK_ERROR:
  3261.     return BT_FAIL;
  3262.  
  3263.     return BT_SUCCESS;
  3264. }
  3265.  
  3266. /**
  3267.  * Handles the response to a telemetry request.
  3268.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3269.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3270.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3271.  * @param ptsFrame: tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*: A pointer to the frame to handle
  3272.  * @re-entrant:
  3273.  */
  3274. #ifndef UNIT_TEST
  3275. static
  3276. #endif /* UNIT_TEST */
  3277.  teFUNC_STATUS CANTS_HandleIncomingTelemetryAcknowledgement(tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsFrame)
  3278. {
  3279.     // If a callback has been assigned
  3280.     if (tsCANTS_Configuration.funcCallbackOnTelemetryAcknowledgement != 0U)
  3281.     {
  3282.         teFUNC_STATUS teFuncStatus = tsCANTS_Configuration.funcCallbackOnTelemetryAcknowledgement(ptsFrame);
  3283.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Telemetry Acknowledgement");
  3284.     }
  3285.  
  3286.     return BT_SUCCESS;
  3287.  
  3288. CANTS_CALLBACK_ERROR:
  3289.     return BT_FAIL;
  3290. }
  3291.  
  3292. /**
  3293.  * Internally used to handle unsolicited telemetry.
  3294.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3295.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3296.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3297.  * @param ptsFrame: tsCANTS_FRAME_UNSOLICITED_TELEMETRY*: A pointer to the CAN-TS frame to handle
  3298.  * @re-entrant:
  3299.  */
  3300. #ifndef UNIT_TEST
  3301. static
  3302. #endif /* UNIT_TEST */
  3303.  teFUNC_STATUS CANTS_HandleIncomingUnsolicitedTelemetry(tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsFrame)
  3304. {
  3305.     // If a callback has been assigned
  3306.     if (tsCANTS_Configuration.funcCallbackOnUnsolicitedTelemetry != 0U)
  3307.     {
  3308.         teFUNC_STATUS teFuncStatus = tsCANTS_Configuration.funcCallbackOnUnsolicitedTelemetry(ptsFrame);
  3309.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Unsolicited Telemetry");
  3310.     }
  3311.  
  3312.     return BT_SUCCESS;
  3313.  
  3314. CANTS_CALLBACK_ERROR:
  3315.     return BT_FAIL;
  3316. }
  3317.  
  3318. /**
  3319.  * Used to internally handle incoming time synchronisation frames.
  3320.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3321.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3322.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3323.  * @param ptsFrame: tsCANTS_FRAME_TIME_SYNCHRONISATION*: A pointer to the time synchronisation frame.
  3324.  * @re-entrant:
  3325.  */
  3326. #ifndef UNIT_TEST
  3327. static
  3328. #endif /* UNIT_TEST */
  3329.  teFUNC_STATUS CANTS_HandleIncomingTimeSynchronisation(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsFrame)
  3330. {
  3331.     // If a callback has been assigned
  3332.     if (tsCANTS_Configuration.funcCallbackOnTimeSynchronisation != 0U)
  3333.     {
  3334.         teFUNC_STATUS teFuncStatus = tsCANTS_Configuration.funcCallbackOnTimeSynchronisation(ptsFrame);
  3335.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Time Synchronisation frame");
  3336.     }
  3337.  
  3338.     return BT_SUCCESS;
  3339.  
  3340. CANTS_CALLBACK_ERROR:
  3341.     return BT_FAIL;
  3342. }
  3343.  
  3344. /**
  3345.  * Used to handle incoming set block requests.
  3346.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3347.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3348.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3349.  * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_REQUEST*: A pointer to the set block request.
  3350.  * @re-entrant:
  3351.  */
  3352. #ifndef UNIT_TEST
  3353. static
  3354. #endif /* UNIT_TEST */
  3355.  teFUNC_STATUS CANTS_HandleIncomingSetBlockRequest(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsFrame)
  3356. {
  3357.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3358.  
  3359.     // If there is currently an ongoing Set Block transaction
  3360.     if (bCANTS_SetBlockBusy)
  3361.     {
  3362.         // Reject the request
  3363.         teFuncStatus = CANTS_RejectSetBlockRequest(ptsFrame);
  3364.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to reject Set Block request");
  3365.     }
  3366.     // Else handle the request as normal
  3367.     else
  3368.     {
  3369.         // If the callback has been assigned
  3370.         if (tsCANTS_Configuration.funcCallbackOnSetBlockRequest != 0U)
  3371.         {
  3372.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockRequest(ptsFrame);
  3373.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Request");
  3374.         }
  3375.         // If no callback has been assigned
  3376.         else
  3377.         {
  3378.             // Automatically reject the request
  3379.             teFuncStatus = CANTS_RejectSetBlockRequest(ptsFrame);
  3380.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to reject Set Block Request");
  3381.         }
  3382.     }
  3383.  
  3384.     return BT_SUCCESS;
  3385.  
  3386. CANTS_CALLBACK_ERROR:
  3387. CANTS_HANDLING_ISSUE:
  3388.     return BT_FAIL;
  3389. }
  3390.  
  3391. /**
  3392.  * Handles incoming Set Block acknowledgement frames.
  3393.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3394.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3395.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3396.  * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*: A pointer to the Set Block Request
  3397.  * acknowledgement frame
  3398.  * @re-entrant:
  3399.  */
  3400. #ifndef UNIT_TEST
  3401. static
  3402. #endif /* UNIT_TEST */
  3403.  teFUNC_STATUS CANTS_HandleIncomingSetBlockAcknowledgement(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsFrame)
  3404. {
  3405.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3406.  
  3407.     // If this object needs to handle this frame
  3408.     if (bCANTS_SetBlockBusy)
  3409.     {
  3410.         // Ensure there is enough room to append the acknowledgement
  3411.         EH_ASSERT((iCANTS_SetBlockPendingAcknowledgements + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Set Block Pending Acknowledgement queue is full");
  3412.  
  3413.         // Append the acknowledgement frame to the queue
  3414.         tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsElementPointer = &(atsCANTS_SetBlockPendingAcknowledgements[iCANTS_SetBlockPendingAcknowledgements]);
  3415.  
  3416.         // We copy the bytes of the frame into the queue
  3417.         for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT); ++iByteIndex)
  3418.         {
  3419.             ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
  3420.         }
  3421.  
  3422.         // Increment the number of pending acknowledgements
  3423.         ++iCANTS_SetBlockPendingAcknowledgements;
  3424.     }
  3425.     // Else if this frame should be passed to the user
  3426.     else
  3427.     {
  3428.         // If a callback has been assigned
  3429.         if (tsCANTS_Configuration.funcCallbackOnSetBlockAcknowledgement != 0U)
  3430.         {
  3431.             // Pass the frame to the callback
  3432.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockAcknowledgement(ptsFrame);
  3433.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Acknowledgement");
  3434.         }
  3435.     }
  3436.  
  3437.     return BT_SUCCESS;
  3438.  
  3439. CANTS_CALLBACK_ERROR:
  3440. CANTS_HANDLING_ISSUE:
  3441.     return BT_FAIL;
  3442. }
  3443.  
  3444. /**
  3445.  * Handles incoming Set Block transfer frames.
  3446.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3447.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3448.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3449.  * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_TRANSFER*: A pointer to the Set Block Transfer frame
  3450.  * @re-entrant:
  3451.  */
  3452. #ifndef UNIT_TEST
  3453. static
  3454. #endif /* UNIT_TEST */
  3455.  teFUNC_STATUS CANTS_HandleIncomingSetBlockTransfer(tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsFrame)
  3456. {
  3457.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3458.  
  3459.     // If this object needs to handle the transfer frame
  3460.     if (bCANTS_SetBlockBusy)
  3461.     {
  3462.         // Ensure the queue has enough space
  3463.         EH_ASSERT((iCANTS_SetBlockPendingTransfers + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ERROR, "Set Block Pending Transfer queue is full");
  3464.  
  3465.         // Get a pointer to the element which we're going to write to
  3466.         tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsElementPointer = &(atsCANTS_SetBlockPendingTransfers[iCANTS_SetBlockPendingTransfers]);
  3467.  
  3468.         // Copy the data to the queue
  3469.         for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_SET_BLOCK_TRANSFER); ++iByteIndex)
  3470.         {
  3471.             ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
  3472.         }
  3473.  
  3474.         // Increment the number of elements within the queue
  3475.         ++iCANTS_SetBlockPendingTransfers;
  3476.     }
  3477.     // The frame should be passed to the user
  3478.     else
  3479.     {
  3480.         // If the callback has been assigned
  3481.         if (tsCANTS_Configuration.funcCallbackOnSetBlockTransfer != 0U)
  3482.         {
  3483.             // Pass the frame to the user
  3484.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockTransfer(ptsFrame);
  3485.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Transfer frame");
  3486.         }
  3487.     }
  3488.  
  3489.     return BT_SUCCESS;
  3490.  
  3491. CANTS_CALLBACK_ERROR:
  3492. CANTS_HANDLING_ERROR:
  3493.     return BT_FAIL;
  3494. }
  3495.  
  3496. /**
  3497.  * Handles incoming Set Block abort frames.
  3498.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3499.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3500.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3501.  * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_ABORT*: A pointer to the Set Block session abort frame
  3502.  * @re-entrant:
  3503.  */
  3504. #ifndef UNIT_TEST
  3505. static
  3506. #endif /* UNIT_TEST */
  3507.  teFUNC_STATUS CANTS_HandleIncomingSetBlockAbort(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsFrame)
  3508. {
  3509.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3510.  
  3511.     // If this object needs to handle the abort frame
  3512.     if (bCANTS_SetBlockBusy)
  3513.     {
  3514.         // Ensure there is enough space within the queue
  3515.         EH_ASSERT((iCANTS_SetBlockPendingAborts + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Set Block Pending Abort queue is full");
  3516.  
  3517.         // Get a pointer to the element within the queue
  3518.         tsCANTS_FRAME_SET_BLOCK_ABORT* ptsElementPointer = &(atsCANTS_SetBlockPendingAborts[iCANTS_SetBlockPendingAborts]);
  3519.  
  3520.         // Copy the bytes of the frame into the queue
  3521.         for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_SET_BLOCK_ABORT); ++iByteIndex)
  3522.         {
  3523.             ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
  3524.         }
  3525.  
  3526.         // Increment the number of elements within the queue
  3527.         ++iCANTS_SetBlockPendingAborts;
  3528.     }
  3529.     // Else pass the frame to the user
  3530.     else
  3531.     {
  3532.         // If the callback has been assigned
  3533.         if (tsCANTS_Configuration.funcCallbackOnSetBlockAbort != 0U)
  3534.         {
  3535.             // Pass the frame to the callback
  3536.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockAbort(ptsFrame);
  3537.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Abort frame");
  3538.         }
  3539.     }
  3540.  
  3541.     return BT_SUCCESS;
  3542.  
  3543. CANTS_CALLBACK_ERROR:
  3544. CANTS_HANDLING_ISSUE:
  3545.     return BT_FAIL;
  3546. }
  3547.  
  3548. /**
  3549.  * Handles incoming Set Block status request frames.
  3550.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3551.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3552.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3553.  * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*: A pointer to the Set Block Session report
  3554.  * request frame
  3555.  * @re-entrant:
  3556.  */
  3557. #ifndef UNIT_TEST
  3558. static
  3559. #endif /* UNIT_TEST */
  3560.  teFUNC_STATUS CANTS_HandleIncomingSetBlockStatusRequest(tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsFrame)
  3561. {
  3562.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3563.  
  3564.     // If this object needs to handle the status request frame
  3565.     if (bCANTS_SetBlockBusy)
  3566.     {
  3567.         // Ensure there is enough space within the queue
  3568.         EH_ASSERT((iCANTS_SetBlockPendingStatusRequests + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Set Block Pending Status Requests queue is full");
  3569.  
  3570.         // Get a pointer to the element within the queue to write the bytes to
  3571.         tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsElementPointer = &(atsCANTS_SetBlockPendingStatusRequests[iCANTS_SetBlockPendingStatusRequests]);
  3572.  
  3573.         // Copy the bytes to the queue
  3574.         for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST); ++iByteIndex)
  3575.         {
  3576.             ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
  3577.         }
  3578.  
  3579.         // Increment the number of elements within the queue
  3580.         ++iCANTS_SetBlockPendingStatusRequests;
  3581.     }
  3582.     // Else pass the frame to the user
  3583.     else
  3584.     {
  3585.         // If the callback has been assigned
  3586.         if (tsCANTS_Configuration.funcCallbackOnSetBlockStatusRequest != 0U)
  3587.         {
  3588.             // Pass the frame to the callback
  3589.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockStatusRequest(ptsFrame);
  3590.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Status Request frame");
  3591.         }
  3592.     }
  3593.  
  3594.     return BT_SUCCESS;
  3595.  
  3596. CANTS_HANDLING_ISSUE:
  3597. CANTS_CALLBACK_ERROR:
  3598.     return BT_FAIL;
  3599. }
  3600.  
  3601. /**
  3602.  * Handles incoming Set Block status report frames.
  3603.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3604.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3605.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3606.  * @param ptsFrame: tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*: A pointer to the Set Block status report
  3607.  * frame
  3608.  * @re-entrant:
  3609.  */
  3610. #ifndef UNIT_TEST
  3611. static
  3612. #endif /* UNIT_TEST */
  3613.  teFUNC_STATUS CANTS_HandleIncomingSetBlockStatusReport(tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsFrame)
  3614. {
  3615.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3616.  
  3617.     // If this object needs to handle the status report frame
  3618.     if (bCANTS_SetBlockBusy)
  3619.     {
  3620.         // Ensure there is enough space within the queue
  3621.         EH_ASSERT((iCANTS_SetBlockPendingStatusReports + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Set Block Status Report queue is full");
  3622.  
  3623.         // Get a pointer to the queue element to copy the frame bytes to
  3624.         tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsElementPointer = &(atsCANTS_SetBlockPendingStatusReports[iCANTS_SetBlockPendingStatusReports]);
  3625.  
  3626.         // Copy the bytes of the frame into the queue
  3627.         for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(iCANTS_SetBlockPendingStatusReports); ++iByteIndex)
  3628.         {
  3629.             ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
  3630.         }
  3631.  
  3632.         // Increment the number of elements within the queue
  3633.         ++iCANTS_SetBlockPendingStatusReports;
  3634.     }
  3635.     // Else we need to pass the frame to the user
  3636.     else
  3637.     {
  3638.         // If the callback has been assigned
  3639.         if (tsCANTS_Configuration.funcCallbackOnSetBlockStatusReport != 0U)
  3640.         {
  3641.             // Pass the status report frame to the callback
  3642.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnSetBlockStatusReport(ptsFrame);
  3643.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Set Block Status Report frame");
  3644.         }
  3645.     }
  3646.  
  3647.     return BT_SUCCESS;
  3648.  
  3649. CANTS_HANDLING_ISSUE:
  3650. CANTS_CALLBACK_ERROR:
  3651.     return BT_FAIL;
  3652. }
  3653.  
  3654. /**
  3655.  * Handles incoming Get Block request frames.
  3656.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3657.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3658.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3659.  * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_REQUEST*: A pointer to the Get Block request frame
  3660.  * @re-entrant:
  3661.  */
  3662. #ifndef UNIT_TEST
  3663. static
  3664. #endif /* UNIT_TEST */
  3665.  teFUNC_STATUS CANTS_HandleIncomingGetBlockRequest(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsFrame)
  3666. {
  3667.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3668.  
  3669.     // If there is currently an ongoing Get Block transaction
  3670.     if (bCANTS_GetBlockBusy)
  3671.     {
  3672.         // Reject the request
  3673.         teFuncStatus = CANTS_RejectGetBlockRequest(ptsFrame);
  3674.         EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to reject Get Block Request");
  3675.     }
  3676.     // Else handle the request
  3677.     else
  3678.     {
  3679.         // If a callback has been assigned
  3680.         if (tsCANTS_Configuration.funcCallbackOnGetBlockRequest != 0U)
  3681.         {
  3682.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockRequest(ptsFrame);
  3683.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Request frame");
  3684.         }
  3685.         // Else no callback has been assigned so automatically reject the request
  3686.         else
  3687.         {
  3688.             teFuncStatus = CANTS_RejectGetBlockRequest(ptsFrame);
  3689.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_HANDLING_ISSUE, "Failed to reject Get Block Request");
  3690.         }
  3691.     }
  3692.  
  3693.     return BT_SUCCESS;
  3694.  
  3695. CANTS_HANDLING_ISSUE:
  3696. CANTS_CALLBACK_ERROR:
  3697.     return BT_FAIL;
  3698. }
  3699.  
  3700. /**
  3701.  * Handles incoming Get Block acknowledgement frames.
  3702.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3703.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3704.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3705.  * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*: A pointer to a Get Block acknowledgement
  3706.  * frame
  3707.  * @re-entrant:
  3708.  */
  3709. #ifndef UNIT_TEST
  3710. static
  3711. #endif /* UNIT_TEST */
  3712.  teFUNC_STATUS CANTS_HandleIncomingGetBlockAcknowledgement(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsFrame)
  3713. {
  3714.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3715.  
  3716.     // If this object needs to handle the acknowledgement frame
  3717.     if(bCANTS_GetBlockBusy)
  3718.     {
  3719.         // Ensure there is enough space within the queue
  3720.         EH_ASSERT((iCANTS_GetBlockPendingAcknowledgements + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Get Block Acknowledgement queue is full");
  3721.  
  3722.         // Get a pointer to the queue element to copy the frame to
  3723.         tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsElementPointer = &(atsCANTS_GetBlockPendingAcknowledgements[iCANTS_GetBlockPendingAcknowledgements]);
  3724.  
  3725.         // Copy the bytes of the frame into the queue element
  3726.         for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(iCANTS_GetBlockPendingAcknowledgements); ++iByteIndex)
  3727.         {
  3728.             ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
  3729.         }
  3730.  
  3731.         // Increment the number of frames within the queue
  3732.         ++iCANTS_GetBlockPendingAcknowledgements;
  3733.     }
  3734.     // Else we need to pass the frame to the user
  3735.     else
  3736.     {
  3737.         // If the callback has been assigned
  3738.         if (tsCANTS_Configuration.funcCallbackOnGetBlockAcknowledgement != 0U)
  3739.         {
  3740.             // Pass the frame to the callback
  3741.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockAcknowledgement(ptsFrame);
  3742.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Acknowledgement frame");
  3743.         }
  3744.     }
  3745.  
  3746.     return BT_SUCCESS;
  3747.  
  3748. CANTS_HANDLING_ISSUE:
  3749. CANTS_CALLBACK_ERROR:
  3750.     return BT_FAIL;
  3751. }
  3752.  
  3753. /**
  3754.  * Handles incoming Get Block start frames.
  3755.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3756.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3757.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3758.  * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_START*: A pointer to the Get Block start transfer frame
  3759.  * @re-entrant:
  3760.  */
  3761. #ifndef UNIT_TEST
  3762. static
  3763. #endif /* UNIT_TEST */
  3764.  teFUNC_STATUS CANTS_HandleIncomingGetBlockStart(tsCANTS_FRAME_GET_BLOCK_START* ptsFrame)
  3765. {
  3766.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3767.  
  3768.     // If the object needs to handle the start frame
  3769.     if (bCANTS_GetBlockBusy)
  3770.     {
  3771.         // Ensure there is enough space within the queue
  3772.         EH_ASSERT((iCANTS_GetBlockPendingStarts + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Get Block Pending Starts queue is full");
  3773.  
  3774.         // Get a pointer to the queue element to copy the frame to
  3775.         tsCANTS_FRAME_GET_BLOCK_START* ptsElementPointer = &(atsCANTS_GetBlockPendingStarts[iCANTS_GetBlockPendingStarts]);
  3776.  
  3777.         // Copy the bytes of the frame into the queue
  3778.         for (tUINT8 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_GET_BLOCK_START); ++iByteIndex)
  3779.         {
  3780.             ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
  3781.         }
  3782.  
  3783.         // Increment the number of elements which are in the queue
  3784.         ++iCANTS_GetBlockPendingStarts;
  3785.     }
  3786.     // Else pass the frame to the user
  3787.     else
  3788.     {
  3789.         // If the callback has been assigned
  3790.         if (tsCANTS_Configuration.funcCallbackOnGetBlockStart != 0U)
  3791.         {
  3792.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockStart(ptsFrame);
  3793.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Start frame");
  3794.         }
  3795.     }
  3796.  
  3797.     return BT_SUCCESS;
  3798.  
  3799. CANTS_HANDLING_ISSUE:
  3800. CANTS_CALLBACK_ERROR:
  3801.     return BT_FAIL;
  3802. }
  3803.  
  3804. /**
  3805.  * Handles incoming Get Block data transfer frames.
  3806.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3807.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3808.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3809.  * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_TRANSFER*: A pointer to the Get Block transaction transfer
  3810.  * frame
  3811.  * @re-entrant:
  3812.  */
  3813. #ifndef UNIT_TEST
  3814. static
  3815. #endif /* UNIT_TEST */
  3816.  teFUNC_STATUS CANTS_HandleIncomingGetBlockTransfer(tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsFrame)
  3817. {
  3818.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3819.  
  3820.     // If this object needs to handle the transfer frame
  3821.     if (bCANTS_GetBlockBusy)
  3822.     {
  3823.         // Ensure there is enough space within the queue
  3824.         EH_ASSERT((iCANTS_GetBlockPendingTransfers + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Get Block Pending Transfers queue is full");
  3825.  
  3826.         // Get a pointer to the queue element to copy the frame to
  3827.         tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsElementPointer = &(atsCANTS_GetBlockPendingTransfers[iCANTS_GetBlockPendingTransfers]);
  3828.  
  3829.         // Copy the bytes of the frame into the queue
  3830.         for (tUINT8 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_GET_BLOCK_TRANSFER); ++iByteIndex)
  3831.         {
  3832.             ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
  3833.         }
  3834.  
  3835.         // Increment the number of elements which are in the queue
  3836.         ++iCANTS_GetBlockPendingTransfers;
  3837.     }
  3838.     // Else pass the transfer frame to the user
  3839.     else
  3840.     {
  3841.         // If a callback has been assigned
  3842.         if (tsCANTS_Configuration.funcCallbackOnGetBlockTransfer != 0U)
  3843.         {
  3844.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockTransfer(ptsFrame);
  3845.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Transfer frame");
  3846.         }
  3847.     }
  3848.  
  3849.     return BT_SUCCESS;
  3850.  
  3851. CANTS_HANDLING_ISSUE:
  3852. CANTS_CALLBACK_ERROR:
  3853.     return BT_FAIL;
  3854. }
  3855.  
  3856. /**
  3857.  * Handles incoming Get Block abort frames.
  3858.  * @returns BT_SUCCESS if there was no exception, otherwise BT_FAIL
  3859.  * @throws CANTS_HANDLING_ISSUE if there was an error while handling the frame.
  3860.  * @throws CANTS_CALLBACK_ERROR if the call to the callback fails.
  3861.  * @param ptsFrame: tsCANTS_FRAME_GET_BLOCK_ABORT*: A pointer to the Get Block transaction abort frame
  3862.  * @re-entrant:
  3863.  */
  3864. #ifndef UNIT_TEST
  3865. static
  3866. #endif /* UNIT_TEST */
  3867.  teFUNC_STATUS CANTS_HandleIncomingGetBlockAbort(tsCANTS_FRAME_GET_BLOCK_ABORT* ptsFrame)
  3868. {
  3869.     teFUNC_STATUS teFuncStatus = BT_FAIL;
  3870.  
  3871.     // If this object needs to handle the abort frame
  3872.     if (bCANTS_GetBlockBusy)
  3873.     {
  3874.         // Ensure there is enough space within the queue
  3875.         EH_ASSERT((iCANTS_GetBlockPendingAborts + 1) <= CANTS_PENDING_FRAMES_QUEUE_SIZE, CANTS_HANDLING_ISSUE, "Get Block Pending Aborts queue is full");
  3876.  
  3877.         // Get a pointer to the queue element to copy the frame to
  3878.         tsCANTS_FRAME_GET_BLOCK_ABORT* ptsElementPointer = &(atsCANTS_GetBlockPendingAborts[iCANTS_GetBlockPendingAborts]);
  3879.  
  3880.         // Copy the bytes of the frame into the queue
  3881.         for (tUINT8 iByteIndex = 0U; iByteIndex < sizeof(tsCANTS_FRAME_GET_BLOCK_ABORT); ++iByteIndex)
  3882.         {
  3883.             ((tUINT8*)ptsElementPointer)[iByteIndex] = ((tUINT8*)ptsFrame)[iByteIndex];
  3884.         }
  3885.  
  3886.         // Increment the number of elements which are in the queue
  3887.         ++iCANTS_GetBlockPendingAborts;
  3888.     }
  3889.     // Else pass the abort frame to the user
  3890.     else
  3891.     {
  3892.         // If a callback has been assigned
  3893.         if (tsCANTS_Configuration.funcCallbackOnGetBlockAbort != 0U)
  3894.         {
  3895.             teFuncStatus = tsCANTS_Configuration.funcCallbackOnGetBlockAbort(ptsFrame);
  3896.             EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_CALLBACK_ERROR, "Callback failed to handle Get Block Abort frame");
  3897.         }
  3898.     }
  3899.  
  3900.     return BT_SUCCESS;
  3901.  
  3902. CANTS_HANDLING_ISSUE:
  3903. CANTS_CALLBACK_ERROR:
  3904.     return BT_FAIL;
  3905. }
  3906.  
  3907. /**
  3908.  * This flips the endianness of the given value. The point of this function is to assign it to the
  3909.  * function pointers to go between Native Endianness <-> Little Endian based on the platform.
  3910.  * @returns BT_SUCCESS always
  3911.  * @param piValue: tUINT64*:
  3912.  * @re-entrant:
  3913.  */
  3914. #ifndef UNIT_TEST
  3915. static
  3916. #endif /* UNIT_TEST */
  3917.  teFUNC_STATUS CANTS_FlipEndianness(tUINT64* piValue)
  3918. {
  3919.     // The value of this will eventually be the input value but with its endianness flipped
  3920.     tUINT64 iFlipped = 0U;
  3921.     tUINT64 iOriginal = *piValue;
  3922.  
  3923.     // Move the last 4 bytes to the first 4 bytes in reverse order
  3924.     iFlipped |= (iOriginal & (tUINT64)0x00000000000000FF) << 56;
  3925.     iFlipped |= (iOriginal & (tUINT64)0x000000000000FF00) << 40;
  3926.     iFlipped |= (iOriginal & (tUINT64)0x0000000000FF0000) << 24;
  3927.     iFlipped |= (iOriginal & (tUINT64)0x00000000FF000000) << 8;
  3928.  
  3929.     // Move the first 4 bytes to the last 4 bytes in reverse order
  3930.     iFlipped |= (iOriginal & (tUINT64)0x000000FF00000000) >> 8;
  3931.     iFlipped |= (iOriginal & (tUINT64)0x0000FF0000000000) >> 24;
  3932.     iFlipped |= (iOriginal & (tUINT64)0x00FF000000000000) >> 40;
  3933.     iFlipped |= (iOriginal & (tUINT64)0xFF00000000000000) >> 56;
  3934.  
  3935.     // Assign the new value
  3936.     *piValue = iFlipped;
  3937.  
  3938.     return BT_SUCCESS;
  3939. }
  3940.  
  3941. /**
  3942.  * This function will do nothing with the value. The point of this function is to assign it to the
  3943.  * function pointers to go between Native Endianness <-> Little Endian based on the platform.
  3944.  * @returns BT_SUCCESS always
  3945.  * @param piValue: tUINT64*:
  3946.  * @re-entrant:
  3947.  */
  3948. #ifndef UNIT_TEST
  3949. static
  3950. #endif /* UNIT_TEST */
  3951.  teFUNC_STATUS CANTS_DoNotFlipEndianness(tUINT64* piValue)
  3952. {
  3953.     // Remove compiler warning for unused value
  3954.     (void)piValue;
  3955.  
  3956.     return BT_SUCCESS;
  3957. }
  3958.  
  3959. /**
  3960.  * Translates a Telemetry Request frame to a Generic frame.
  3961.  * @returns BT_SUCCESS always.
  3962.  * @param ptsTelecommandRequest: tsCANTS_FRAME_TELECOMMAND_REQUEST*: The telemetry request frame
  3963.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  3964.  * @re-entrant:
  3965.  */
  3966. #ifndef UNIT_TEST
  3967. static
  3968. #endif /* UNIT_TEST */
  3969.  teFUNC_STATUS CANTS_TranslateFrameTelecommandRequestToGeneric(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsTelecommandRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  3970. {
  3971.     /* Copy the data */
  3972.     ptsGenericFrame->iDataLength = ptsTelecommandRequest->iDataLength;
  3973.  
  3974.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  3975.     {
  3976.         ptsGenericFrame->acData[iByteIndex] = ptsTelecommandRequest->acData[iByteIndex];
  3977.     }
  3978.  
  3979.     /* Populate the identifiers */
  3980.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsTelecommandRequest->iToAddress;
  3981.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTelecommandRequest->iFromAddress;
  3982.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TELECOMMAND;
  3983.     ptsGenericFrame->tsIdentifiers.iCommand = ((CANTS_FRAME_SUBTYPE_TELECOMMAND_REQUEST << 8) | ptsTelecommandRequest->iChannel);
  3984.  
  3985.     return BT_SUCCESS;
  3986. }
  3987.  
  3988. /**
  3989.  * Translates a Telecommand Acknowledgement frame to a Generic frame.
  3990.  * @returns BT_SUCCESS always
  3991.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  3992.  * @param ptsTelecommandAcknowledgement: tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*: The telecommand
  3993.  * acknowledgement frame
  3994.  * @re-entrant:
  3995.  */
  3996. #ifndef UNIT_TEST
  3997. static
  3998. #endif /* UNIT_TEST */
  3999.  teFUNC_STATUS CANTS_TranslateFrameTelecommandAcknowledgementToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsTelecommandAcknowledgement)
  4000. {
  4001.     /* Populate the fields */
  4002.  
  4003.     // The acknowledgement never contains any data
  4004.     ptsGenericFrame->iDataLength = 0U;
  4005.  
  4006.     // Get the value of the subtype
  4007.     tUINT8 iSubtypeValue = 0U;
  4008.  
  4009.     if (ptsTelecommandAcknowledgement->teAcknowledgement == CANTS_POSITIVE_ACKNOWLEDGEMENT)
  4010.     {
  4011.         iSubtypeValue = CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT;
  4012.     }
  4013.     else
  4014.     {
  4015.         iSubtypeValue = CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT;
  4016.     }
  4017.  
  4018.     ptsGenericFrame->tsIdentifiers.iCommand = ((iSubtypeValue << 8) | ptsTelecommandAcknowledgement->iChannel);
  4019.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsTelecommandAcknowledgement->iToAddress;
  4020.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTelecommandAcknowledgement->iFromAddress;
  4021.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TELECOMMAND;
  4022.  
  4023.     return BT_SUCCESS;
  4024. }
  4025.  
  4026. /**
  4027.  * Translates a Telemetry Request frame to a Generic frame.
  4028.  * @returns BT_SUCCESS always
  4029.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4030.  * @param ptsTelemetryRequest: tsCANTS_FRAME_TELEMETRY_REQUEST*: The telemetry request frame
  4031.  * @re-entrant:
  4032.  */
  4033. #ifndef UNIT_TEST
  4034. static
  4035. #endif /* UNIT_TEST */
  4036.  teFUNC_STATUS CANTS_TranslateFrameTelemetryRequestToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_REQUEST* ptsTelemetryRequest)
  4037. {
  4038.     /* Populate the fields */
  4039.  
  4040.     // Telemetry requests never contain any data
  4041.     ptsGenericFrame->iDataLength = 0U;
  4042.  
  4043.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsTelemetryRequest->iToAddress;
  4044.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTelemetryRequest->iFromAddress;
  4045.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TELEMETRY_REQUEST;
  4046.     ptsGenericFrame->tsIdentifiers.iCommand = ((CANTS_FRAME_SUBTYPE_TELEMETRY_REQUEST << 8) | ptsTelemetryRequest->iChannel);
  4047.  
  4048.     return BT_SUCCESS;
  4049. }
  4050.  
  4051. /**
  4052.  * Translates a Telemetry Acknowledgement frame to a Generic frame.
  4053.  * @returns BT_SUCCESS always.
  4054.  * @param ptsTelemetryAcknowledgement: tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*: The telemetry
  4055.  * acknowledgement frame
  4056.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4057.  * @re-entrant:
  4058.  */
  4059. #ifndef UNIT_TEST
  4060. static
  4061. #endif /* UNIT_TEST */
  4062.  teFUNC_STATUS CANTS_TranslateFrameTelemetryAcknowledgementToGeneric(tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsTelemetryAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4063. {
  4064.     /* Populate the fields */
  4065.  
  4066.     tUINT8 iSubtypeValue = 0U;
  4067.  
  4068.     // If it's a positive telemetry request with data
  4069.     if (ptsTelemetryAcknowledgement->teAcknowledgement == CANTS_POSITIVE_ACKNOWLEDGEMENT)
  4070.     {
  4071.         ptsGenericFrame->iDataLength = ptsTelemetryAcknowledgement->iDataLength;
  4072.  
  4073.         // Copy the data
  4074.         for (tUINT32 iByteIndex = 0U; iByteIndex < ptsTelemetryAcknowledgement->iDataLength; ++iByteIndex)
  4075.         {
  4076.             ptsGenericFrame->acData[iByteIndex] = ptsTelemetryAcknowledgement->acData[iByteIndex];
  4077.         }
  4078.  
  4079.         iSubtypeValue = CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT;
  4080.     }
  4081.     else
  4082.     {
  4083.         // Negative acknowledgement frames contain no data
  4084.         ptsGenericFrame->iDataLength = 0U;
  4085.  
  4086.         iSubtypeValue = CANTS_FRAME_SUBTYPE_TELECOMMAND_NEGATIVE_ACKNOWLEDGEMENT;
  4087.     }
  4088.  
  4089.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsTelemetryAcknowledgement->iToAddress;
  4090.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTelemetryAcknowledgement->iFromAddress;
  4091.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TELEMETRY_REQUEST;
  4092.     ptsGenericFrame->tsIdentifiers.iCommand = ((iSubtypeValue << 8) | ptsTelemetryAcknowledgement->iChannel);
  4093.  
  4094.     return BT_SUCCESS;
  4095. }
  4096.  
  4097. /**
  4098.  * Translates an Unsolicited Telemetry frame to a Generic frame.
  4099.  * @returns BT_SUCCESS always.
  4100.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4101.  * @param ptsUnsolicitedTelemetry: tsCANTS_FRAME_UNSOLICITED_TELEMETRY*: The unsolicited telemetry
  4102.  * frame
  4103.  * @re-entrant:
  4104.  */
  4105. #ifndef UNIT_TEST
  4106. static
  4107. #endif /* UNIT_TEST */
  4108.  teFUNC_STATUS CANTS_TranslateFrameUnsolicitedTelemetryToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsUnsolicitedTelemetry)
  4109. {
  4110.     /* Populate the fields */
  4111.  
  4112.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsUnsolicitedTelemetry->iToAddress;
  4113.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsUnsolicitedTelemetry->iFromAddress;
  4114.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_UNSOLICITED_TELEMETRY;
  4115.     ptsGenericFrame->tsIdentifiers.iCommand = ((CANTS_FRAME_SUBTYPE_UNSOLICITED_TELEMETRY << 8) | ptsUnsolicitedTelemetry->iChannel);
  4116.  
  4117.     // Copy the data of the frame
  4118.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsUnsolicitedTelemetry->iDataLength; ++iByteIndex)
  4119.     {
  4120.         ptsGenericFrame->acData[iByteIndex] = ptsUnsolicitedTelemetry->acData[iByteIndex];
  4121.     }
  4122.  
  4123.     ptsGenericFrame->iDataLength = ptsUnsolicitedTelemetry->iDataLength;
  4124.  
  4125.     return BT_SUCCESS;
  4126. }
  4127.  
  4128. /** TODO: Add exception CANTS_TRANSLATE_ERROR to EA
  4129.  * Translates a Time Synchronisation frame to a Generic frame.
  4130.  * @returns BT_SUCCESS always.
  4131.  * @param ptsTimeSynchronisation: tsCANTS_FRAME_TIME_SYNCHRONISATION*: The time synchronisation frame
  4132.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4133.  * @re-entrant:
  4134.  */
  4135. #ifndef UNIT_TEST
  4136. static
  4137. #endif /* UNIT_TEST */
  4138.  teFUNC_STATUS CANTS_TranslateFrameTimeSynchronisationToGeneric(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsTimeSynchronisation, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4139. {
  4140.     /* Populate the fields */
  4141.  
  4142.     // Time synchronisation frame To Address is always 0
  4143.     ptsGenericFrame->tsIdentifiers.iToAddress = 0U;
  4144.  
  4145.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsTimeSynchronisation->iFromAddress;
  4146.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_TIME_SYNCHRONISATION;
  4147.     ptsGenericFrame->tsIdentifiers.iCommand = 0U; // Unused but this is to make sure it's initialised to something
  4148.  
  4149.     // Data length is always 8 bytes to contain the timestamp
  4150.     ptsGenericFrame->iDataLength = 8U;
  4151.  
  4152.     // Get the time as Little Endian
  4153.     tUINT64 iLittleEndianTime = ptsTimeSynchronisation->iTime;
  4154.     teFUNC_STATUS teFuncStatus = funcCANTS_NativeEndiannessToLittleEndian(&iLittleEndianTime);
  4155.     EH_ASSERT(teFuncStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to set the time endainness");
  4156.  
  4157.     // Copy the bytes of the timestamp
  4158.     for (tUINT32 iByteIndex = 0U; iByteIndex < 8U; ++iByteIndex)
  4159.     {
  4160.         ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)(&iLittleEndianTime))[iByteIndex];
  4161.     }
  4162.  
  4163.     return BT_SUCCESS;
  4164.  
  4165. CANTS_TRANSLATE_ERROR:
  4166.     return BT_FAIL;
  4167. }
  4168.  
  4169. /**
  4170.  * Translates a Set Block Request frame to a Generic frame.
  4171.  * @returns BT_SUCCESS.
  4172.  * @param ptsSetBlockRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The set block request frame
  4173.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4174.  * @re-entrant:
  4175.  */
  4176. #ifndef UNIT_TEST
  4177. static
  4178. #endif /* UNIT_TEST */
  4179.  teFUNC_STATUS CANTS_TranslateFrameSetBlockRequestToGeneric(tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsSetBlockRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4180. {
  4181.     /* Populate the fields */
  4182.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockRequest->iToAddress;
  4183.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockRequest->iFromAddress;
  4184.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
  4185.     ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST << 7) | ptsSetBlockRequest->iNumberOfBlocks;
  4186.  
  4187.     // Copy the data of the frame
  4188.     for (tUINT32 iByteIndex = 0U; iByteIndex < (tUINT32)ptsSetBlockRequest->teAddressSize; ++iByteIndex)
  4189.     {
  4190.         // TODO: Check the logic for this because the data might not be stored correctly in memory
  4191.         ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)&ptsSetBlockRequest->iStartAddress)[iByteIndex];
  4192.     }
  4193.  
  4194.     ptsGenericFrame->iDataLength = (tUINT8)ptsSetBlockRequest->teAddressSize;
  4195.  
  4196.     return BT_SUCCESS;
  4197. }
  4198.  
  4199. /**
  4200.  * Translates a Set Block Acknowledgement frame to a Generic frame.
  4201.  * @returns BT_SUCCESS always.
  4202.  * @param ptsSetBlockAcknowledgement: tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*: The set block
  4203.  * acknowledgement frame
  4204.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4205.  * @re-entrant:
  4206.  */
  4207. #ifndef UNIT_TEST
  4208. static
  4209. #endif /* UNIT_TEST */
  4210.  teFUNC_STATUS CANTS_TranslateFrameSetBlockAcknowledgementToGeneric(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4211. {
  4212.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockAcknowledgement->iToAddress;
  4213.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockAcknowledgement->iFromAddress;
  4214.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
  4215.  
  4216.     // The data bytes are only used for a positive acknowledgement
  4217.     if (ptsSetBlockAcknowledgement->teAcknowledgement == CANTS_POSITIVE_ACKNOWLEDGEMENT)
  4218.     {
  4219.         ptsGenericFrame->iDataLength = ptsSetBlockAcknowledgement->iDataLength;
  4220.  
  4221.         // Copy each byte
  4222.         for (tUINT32 iByteIndex = 0U; iByteIndex < ptsSetBlockAcknowledgement->iDataLength; ++iByteIndex)
  4223.         {
  4224.             ptsGenericFrame->acData[iByteIndex] = ptsSetBlockAcknowledgement->acData[iByteIndex];
  4225.         }
  4226.  
  4227.         ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT << 7) | ptsSetBlockAcknowledgement->iCommand;
  4228.     }
  4229.     else
  4230.     {
  4231.         // A negative acknowledgement has no data
  4232.         ptsGenericFrame->iDataLength = 0U;
  4233.  
  4234.         ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT << 7);
  4235.     }
  4236.  
  4237.     return BT_SUCCESS;
  4238. }
  4239.  
  4240. /**
  4241.  * Translates a Set Block Transfer frame to a Generic frame.
  4242.  * @returns BT_SUCCESS always.
  4243.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4244.  * @param ptsSetBlockTransfer: tsCANTS_FRAME_SET_BLOCK_TRANSFER*: The set block transfer frame
  4245.  * @re-entrant:
  4246.  */
  4247. #ifndef UNIT_TEST
  4248. static
  4249. #endif /* UNIT_TEST */
  4250.  teFUNC_STATUS CANTS_TranslateFrameSetBlockTransferToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsSetBlockTransfer)
  4251. {
  4252.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockTransfer->iToAddress;
  4253.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockTransfer->iFromAddress;
  4254.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
  4255.     ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_TRANSFER << 7) | ptsSetBlockTransfer->iSequence;
  4256.  
  4257.     // Copy the transfer data
  4258.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsSetBlockTransfer->iDataLength; ++iByteIndex)
  4259.     {
  4260.         ptsGenericFrame->acData[iByteIndex] = ptsSetBlockTransfer->acData[iByteIndex];
  4261.     }
  4262.  
  4263.     return BT_SUCCESS;
  4264. }
  4265.  
  4266. /**
  4267.  * Translates a Set Block Abort frame to a Generic frame.
  4268.  * @returns BT_SUCCESS always.
  4269.  * @param ptsSetBlockAbort: tsCANTS_FRAME_SET_BLOCK_ABORT*: The set block abort frame
  4270.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4271.  * @re-entrant:
  4272.  */
  4273. #ifndef UNIT_TEST
  4274. static
  4275. #endif /* UNIT_TEST */
  4276.  teFUNC_STATUS CANTS_TranslateFrameSetBlockAbortToGeneric(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsSetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4277. {
  4278.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockAbort->iToAddress;
  4279.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockAbort->iFromAddress;
  4280.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
  4281.     ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_ABORT << 7);
  4282.  
  4283.     // Abort frame contains no data
  4284.     ptsGenericFrame->iDataLength = 0U;
  4285.  
  4286.     return BT_SUCCESS;
  4287. }
  4288.  
  4289. /**
  4290.  * Translates a Set Block Status Request frame to a Generic frame.
  4291.  * @returns BT_SUCCESS always.
  4292.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4293.  * @param ptsSetBlockStatusRequest: tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*: The set block status
  4294.  * request
  4295.  * @re-entrant:
  4296.  */
  4297. #ifndef UNIT_TEST
  4298. static
  4299. #endif /* UNIT_TEST */
  4300.  teFUNC_STATUS CANTS_TranslateFrameSetBlockStatusRequestToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsSetBlockStatusRequest)
  4301. {
  4302.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockStatusRequest->iToAddress;
  4303.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockStatusRequest->iFromAddress;
  4304.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
  4305.     ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REQUEST << 7);
  4306.  
  4307.     // Status request frame contains no data
  4308.     ptsGenericFrame->iDataLength = 0U;
  4309.  
  4310.     return BT_SUCCESS;
  4311. }
  4312.  
  4313. /**
  4314.  * Translates a Set Block Status Report frame to a Generic frame.
  4315.  * @returns BT_SUCCESS always.
  4316.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4317.  * @param ptsSetBlockStatusReport: tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*: The set block status report
  4318.  * frame
  4319.  * @re-entrant:
  4320.  */
  4321. #ifndef UNIT_TEST
  4322. static
  4323. #endif /* UNIT_TEST */
  4324.  teFUNC_STATUS CANTS_TranslateFrameSetBlockStatusReportToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsSetBlockStatusReport)
  4325. {
  4326.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsSetBlockStatusReport->iToAddress;
  4327.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsSetBlockStatusReport->iFromAddress;
  4328.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_SET_BLOCK;
  4329.  
  4330.     // The command contains a flag specifying if the transfer is complete
  4331.     // 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
  4332.     ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_SET_BLOCK_STATUS_REPORT << 7) | ptsSetBlockStatusReport->bComplete;
  4333.  
  4334.     // Copy the bitfield into the data section of the frame
  4335.     for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(ptsSetBlockStatusReport->iBlocksReceived); ++iByteIndex)
  4336.     {
  4337.         ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)&ptsSetBlockStatusReport->iBlocksReceived)[iByteIndex];
  4338.     }
  4339.  
  4340.     return BT_SUCCESS;
  4341. }
  4342.  
  4343. /**
  4344.  * Translates a Get Block Request frame to a Generic frame.
  4345.  * @returns BT_SUCCESS always.
  4346.  * @param ptsGetBlockRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The get block request frame
  4347.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4348.  * @re-entrant:
  4349.  */
  4350. #ifndef UNIT_TEST
  4351. static
  4352. #endif /* UNIT_TEST */
  4353.  teFUNC_STATUS CANTS_TranslateFrameGetBlockRequestToGeneric(tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsGetBlockRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4354. {
  4355.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockRequest->iToAddress;
  4356.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockRequest->iFromAddress;
  4357.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
  4358.     ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_REQUEST << 7) | ptsGetBlockRequest->iNumberOfBlocks;
  4359.  
  4360.     // Copy the address
  4361.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGetBlockRequest->teAddressSize; ++iByteIndex)
  4362.     {
  4363.         // TODO: Check that address is stored correctly in memory for when we index into it
  4364.         ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)&ptsGetBlockRequest->teAddressSize)[iByteIndex];
  4365.     }
  4366.  
  4367.     return BT_SUCCESS;
  4368. }
  4369.  
  4370. /**
  4371.  * Translates a Get Block Acknowledgement frame to a Generic frame.
  4372.  * @returns BT_SUCCESS always.
  4373.  * @param ptsGetBlockAcknowledgement: tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*: The get block
  4374.  * acknowledgement frame
  4375.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4376.  * @re-entrant:
  4377.  */
  4378. #ifndef UNIT_TEST
  4379. static
  4380. #endif /* UNIT_TEST */
  4381.  teFUNC_STATUS CANTS_TranslateFrameGetBlockAcknowledgementToGeneric(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsGetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4382. {
  4383.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockAcknowledgement->iToAddress;
  4384.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockAcknowledgement->iFromAddress;
  4385.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
  4386.  
  4387.     if (ptsGetBlockAcknowledgement->teAcknowledgement == CANTS_POSITIVE_ACKNOWLEDGEMENT)
  4388.     {
  4389.         ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT << 7) | ptsGetBlockAcknowledgement->iCommand;
  4390.  
  4391.         // Copy the data
  4392.         for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGetBlockAcknowledgement->iDataLength; ++iByteIndex)
  4393.         {
  4394.             ptsGenericFrame->acData[iByteIndex] = ptsGetBlockAcknowledgement->acData[iByteIndex];
  4395.         }
  4396.     }
  4397.     else
  4398.     {
  4399.         ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_NEGATIVE_ACKNOWLEDGEMENT << 7);
  4400.  
  4401.         // A negative acknowledgement never contains any data
  4402.         ptsGenericFrame->iDataLength = 0U;
  4403.     }
  4404.  
  4405.     return BT_SUCCESS;
  4406. }
  4407.  
  4408. /**
  4409.  * Translates a Get Block Start frame to a Generic frame.
  4410.  * @returns BT_SUCCESS always.
  4411.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4412.  * @param ptsGetBlockStart: tsCANTS_FRAME_GET_BLOCK_START*: The get block start frame
  4413.  * @re-entrant:
  4414.  */
  4415. #ifndef UNIT_TEST
  4416. static
  4417. #endif /* UNIT_TEST */
  4418.  teFUNC_STATUS CANTS_TranslateFrameGetBlockStartToGeneric(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_START* ptsGetBlockStart)
  4419. {
  4420.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockStart->iToAddress;
  4421.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockStart->iFromAddress;
  4422.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
  4423.     ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_START << 7);
  4424.  
  4425.     // Copy the bitfield of blocks to send
  4426.     for (tUINT32 iByteIndex = 0U; iByteIndex < sizeof(ptsGetBlockStart->iBlocksToGet); ++iByteIndex)
  4427.     {
  4428.         ptsGenericFrame->acData[iByteIndex] = ((tUINT8*)&ptsGetBlockStart->iBlocksToGet)[iByteIndex];
  4429.     }
  4430.  
  4431.     ptsGenericFrame->iDataLength = sizeof(ptsGetBlockStart->iBlocksToGet);
  4432.  
  4433.     return BT_SUCCESS;
  4434. }
  4435.  
  4436. /**
  4437.  * Translates a Get Block Transfer frame to a Generic frame.
  4438.  * @returns BT_SUCCESS always.
  4439.  * @param ptsGetBlockTransfer: tsCANTS_FRAME_GET_BLOCK_TRANSFER*: The get block transfer frame
  4440.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4441.  * @re-entrant:
  4442.  */
  4443. #ifndef UNIT_TEST
  4444. static
  4445. #endif /* UNIT_TEST */
  4446.  teFUNC_STATUS CANTS_TranslateFrameGetBlockTransferToGeneric(tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsGetBlockTransfer, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4447. {
  4448.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockTransfer->iToAddress;
  4449.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockTransfer->iFromAddress;
  4450.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
  4451.     ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_TRANSFER << 7) | ptsGetBlockTransfer->iSequence;
  4452.  
  4453.     // Copy the transfer data
  4454.     // The specification states this is always 8 bytes
  4455.     for (tUINT32 iByteIndex = 0U; iByteIndex < 8U; ++iByteIndex)
  4456.     {
  4457.         ptsGenericFrame->acData[iByteIndex] = ptsGetBlockTransfer->acData[iByteIndex];
  4458.     }
  4459.  
  4460.     // Same as comment above
  4461.     ptsGenericFrame->iDataLength = 8U;
  4462.  
  4463.     return BT_SUCCESS;
  4464. }
  4465.  
  4466. /**
  4467.  * Translates a Get Block Abort frame to a Generic frame.
  4468.  * @returns BT_SUCCESS always.
  4469.  * @param ptsGetBlockAbort: tsCANTS_FRAME_GET_BLOCK_ABORT*: The get block abort frame
  4470.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4471.  * @re-entrant:
  4472.  */
  4473. #ifndef UNIT_TEST
  4474. static
  4475. #endif /* UNIT_TEST */
  4476.  teFUNC_STATUS CANTS_TranslateFrameGetBlockAbortToGeneric(tsCANTS_FRAME_GET_BLOCK_ABORT* ptsGetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4477. {
  4478.     ptsGenericFrame->tsIdentifiers.iToAddress = ptsGetBlockAbort->iToAddress;
  4479.     ptsGenericFrame->tsIdentifiers.iFromAddress = ptsGetBlockAbort->iFromAddress;
  4480.     ptsGenericFrame->tsIdentifiers.iFrameType = CANTS_FRAME_TYPE_GET_BLOCK;
  4481.     ptsGenericFrame->tsIdentifiers.iCommand = (CANTS_FRAME_SUBTYPE_GET_BLOCK_ABORT << 7);
  4482.  
  4483.     // An abort frame contains no data
  4484.     ptsGenericFrame->iDataLength = 0U;
  4485.  
  4486.     return BT_SUCCESS;
  4487. }
  4488.  
  4489. /**
  4490.  * Translates a Generic frame to a Telecommand request frame.
  4491.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4492.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4493.  * @param ptsTelecommandRequest: tsCANTS_FRAME_TELECOMMAND_REQUEST*: The telecommand request frame
  4494.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4495.  * @re-entrant:
  4496.  */
  4497. #ifndef UNIT_TEST
  4498. static
  4499. #endif /* UNIT_TEST */
  4500.  teFUNC_STATUS CANTS_TranslateFrameGenericToTelecommandRequest(tsCANTS_FRAME_TELECOMMAND_REQUEST* ptsTelecommandRequest, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4501. {
  4502.     ptsTelecommandRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4503.     ptsTelecommandRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4504.     ptsTelecommandRequest->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
  4505.  
  4506.     // Copy the telecommand argument data
  4507.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4508.     {
  4509.         ptsTelecommandRequest->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  4510.     }
  4511.  
  4512.     ptsTelecommandRequest->iDataLength = ptsGenericFrame->iDataLength;
  4513.  
  4514.     return BT_SUCCESS;
  4515. }
  4516.  
  4517. /**
  4518.  * Translates a Generic frame to a Telecommand Acknowledgement frame.
  4519.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4520.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4521.  * @param ptsTelecommandAcknowledgement: tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT*: The telecommand
  4522.  * acknowledgement frame
  4523.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4524.  * @re-entrant:
  4525.  */
  4526. #ifndef UNIT_TEST
  4527. static
  4528. #endif /* UNIT_TEST */
  4529.  teFUNC_STATUS CANTS_TranslateFrameGenericToTelecommandAcknowledgement(tsCANTS_FRAME_TELECOMMAND_ACKNOWLEDGEMENT* ptsTelecommandAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4530. {
  4531.     ptsTelecommandAcknowledgement->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4532.     ptsTelecommandAcknowledgement->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4533.     ptsTelecommandAcknowledgement->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
  4534.  
  4535.     // If the frame subtype is a positive telecommand acknowledgement
  4536.     if ((ptsGenericFrame->tsIdentifiers.iCommand >> 8) == CANTS_FRAME_SUBTYPE_TELECOMMAND_POSITIVE_ACKNOWLEDGEMENT)
  4537.     {
  4538.         ptsTelecommandAcknowledgement->teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
  4539.     }
  4540.     else
  4541.     {
  4542.         ptsTelecommandAcknowledgement->teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
  4543.     }
  4544.  
  4545.     return BT_SUCCESS;
  4546. }
  4547.  
  4548. /**
  4549.  * Translates a Generic frame to a Telemetry request frame.
  4550.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4551.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4552.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4553.  * @param ptsTelemetryRequest: tsCANTS_FRAME_TELEMETRY_REQUEST*: The telemetry request frame
  4554.  * @re-entrant:
  4555.  */
  4556. #ifndef UNIT_TEST
  4557. static
  4558. #endif /* UNIT_TEST */
  4559.  teFUNC_STATUS CANTS_TranslateFrameGenericToTelemetryRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_REQUEST* ptsTelemetryRequest)
  4560. {
  4561.     ptsTelemetryRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4562.     ptsTelemetryRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4563.     ptsTelemetryRequest->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
  4564.  
  4565.     return BT_SUCCESS;
  4566. }
  4567.  
  4568. /**
  4569.  * Translates a Generic frame to a Telemetry Acknowledgement frame.
  4570.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4571.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4572.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4573.  * @param ptsTelemetryAcknowledgement: tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT*: The telemetry
  4574.  * acknowledgement frame
  4575.  * @re-entrant:
  4576.  */
  4577. #ifndef UNIT_TEST
  4578. static
  4579. #endif /* UNIT_TEST */
  4580.  teFUNC_STATUS CANTS_TranslateFrameGenericToTelemetryAcknowledgement(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_TELEMETRY_ACKNOWLEDGEMENT* ptsTelemetryAcknowledgement)
  4581. {
  4582.     ptsTelemetryAcknowledgement->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4583.     ptsTelemetryAcknowledgement->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4584.     ptsTelemetryAcknowledgement->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
  4585.  
  4586.     // If the subtype is a positive telemetry request acknowledgement
  4587.     if ((ptsGenericFrame->tsIdentifiers.iCommand >> 8) == CANTS_FRAME_SUBTYPE_TELEMETRY_POSITIVE_ACKNOWLEDGEMENT)
  4588.     {
  4589.         // Copy the telemetry request response data
  4590.         for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4591.         {
  4592.             ptsTelemetryAcknowledgement->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  4593.         }
  4594.  
  4595.         // Set the data length
  4596.         ptsTelemetryAcknowledgement->iDataLength = ptsGenericFrame->iDataLength;
  4597.  
  4598.         ptsTelemetryAcknowledgement->teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
  4599.     }
  4600.     else
  4601.     {
  4602.         // A negative acknowledgement contains no data
  4603.         ptsTelemetryAcknowledgement->iDataLength = 0U;
  4604.  
  4605.         ptsTelemetryAcknowledgement->teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
  4606.     }
  4607.  
  4608.     return BT_SUCCESS;
  4609. }
  4610.  
  4611. /**
  4612.  * Translates a Generic frame to an Unsolicited Telemetry frame.
  4613.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4614.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4615.  * @param ptsUnsolicitedTelemetry: tsCANTS_FRAME_UNSOLICITED_TELEMETRY*: The unsolicited telemetry
  4616.  * frame
  4617.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4618.  * @re-entrant:
  4619.  */
  4620. #ifndef UNIT_TEST
  4621. static
  4622. #endif /* UNIT_TEST */
  4623.  teFUNC_STATUS CANTS_TranslateFrameGenericToUnsolicitedTelemetry(tsCANTS_FRAME_UNSOLICITED_TELEMETRY* ptsUnsolicitedTelemetry, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4624. {
  4625.     ptsUnsolicitedTelemetry->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4626.     ptsUnsolicitedTelemetry->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4627.     ptsUnsolicitedTelemetry->iChannel = (ptsGenericFrame->tsIdentifiers.iCommand & 0xFF);
  4628.  
  4629.     // Copy the telemetry data
  4630.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4631.     {
  4632.         ptsUnsolicitedTelemetry->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  4633.     }
  4634.  
  4635.     ptsUnsolicitedTelemetry->iDataLength = ptsGenericFrame->iDataLength;
  4636.  
  4637.     return BT_SUCCESS;
  4638. }
  4639.  
  4640. /** TODO: Add exception CANTS_TRANSLATE_ERROR to EA
  4641.  * Translates a Generic frame to a Time Synchronisation frame.
  4642.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4643.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4644.  * @param ptsTimeSynchronisation: tsCANTS_FRAME_TIME_SYNCHRONISATION*: The time synchronisation frame
  4645.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4646.  * @re-entrant:
  4647.  */
  4648. #ifndef UNIT_TEST
  4649. static
  4650. #endif /* UNIT_TEST */
  4651.  teFUNC_STATUS CANTS_TranslateFrameGenericToTimeSynchronisation(tsCANTS_FRAME_TIME_SYNCHRONISATION* ptsTimeSynchronisation, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4652. {
  4653.     EH_ASSERT(ptsGenericFrame->iDataLength == 8, CANTS_INVALID_PARAMETER, "A generic time synchronisation frame did not have 8 bytes");
  4654.  
  4655.     ptsTimeSynchronisation->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4656.  
  4657.     // The timestamp is always 8 bytes
  4658.     for (tUINT32 iByteIndex = 0U; iByteIndex < 8; ++iByteIndex)
  4659.     {
  4660.         ((tUINT8*)&ptsTimeSynchronisation->iTime)[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  4661.     }
  4662.  
  4663.     // Convert the time to the native endianness
  4664.     teFUNC_STATUS teSetEndianStatus = funcCANTS_LittleEndianToNativeEndianness(&ptsTimeSynchronisation->iTime);
  4665.     EH_ASSERT(teSetEndianStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to translate from little endian to native endianness");
  4666.  
  4667.     return BT_SUCCESS;
  4668.  
  4669. CANTS_INVALID_PARAMETER:
  4670. CANTS_TRANSLATE_ERROR:
  4671.     return BT_FAIL;
  4672. }
  4673.  
  4674. /** TODO: Add exception CANTS_TRANSLATE_ERROR to EA
  4675.  * Translates a Generic frame to a Set Block Request frame.
  4676.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4677.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4678.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4679.  * @param ptsSetBlockRequest: tsCANTS_FRAME_SET_BLOCK_REQUEST*: The set block request frame
  4680.  * @re-entrant:
  4681.  */
  4682. #ifndef UNIT_TEST
  4683. static
  4684. #endif /* UNIT_TEST */
  4685.  teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_REQUEST* ptsSetBlockRequest)
  4686. {
  4687.     // There must be at least one byte to specify the address
  4688.     EH_ASSERT(ptsGenericFrame->iDataLength > 0, CANTS_INVALID_PARAMETER, "A generic set block request had a data length of 0");
  4689.  
  4690.     ptsSetBlockRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4691.     ptsSetBlockRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4692.  
  4693.     // 0x3F gets the last 6 bits which is the number of blocks
  4694.     ptsSetBlockRequest->iNumberOfBlocks = (ptsGenericFrame->tsIdentifiers.iCommand & 0x3F);
  4695.  
  4696.     // Get the address
  4697.     tUINT64 iAddressLittleEndian = 0U;
  4698.  
  4699.     // Copy the address bytes into the address variable keeping in mind that it's stored as little endian
  4700.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4701.     {
  4702.         iAddressLittleEndian |= (((tUINT64)ptsGenericFrame->acData[iByteIndex]) << (8 * iByteIndex));
  4703.     }
  4704.  
  4705.     // Assign the address but then flip it to native endianness
  4706.     ptsSetBlockRequest->iStartAddress = iAddressLittleEndian;
  4707.     teFUNC_STATUS teFlipEndianStatus = funcCANTS_LittleEndianToNativeEndianness(&ptsSetBlockRequest->iStartAddress);
  4708.     EH_ASSERT(teFlipEndianStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to flip address to native endianness");
  4709.  
  4710.     ptsSetBlockRequest->teAddressSize = (teCANTS_ADDRESS_SIZE)ptsGenericFrame->iDataLength;
  4711.  
  4712.     return BT_SUCCESS;
  4713.  
  4714. CANTS_INVALID_PARAMETER:
  4715. CANTS_TRANSLATE_ERROR:
  4716.     return BT_FAIL;
  4717. }
  4718.  
  4719. /** TODO: Remove exception CANTS_INVALID_PARAMETER from EA
  4720.  * Translates a Generic frame to a Set Block Acknowledgement frame.
  4721.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4722.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4723.  * @param ptsSetBlockAcknoledgement: tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT*: The set block
  4724.  * acknowledgement frame
  4725.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4726.  * @re-entrant:
  4727.  */
  4728. #ifndef UNIT_TEST
  4729. static
  4730. #endif /* UNIT_TEST */
  4731.  teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockAcknowledgement(tsCANTS_FRAME_SET_BLOCK_ACKNOWLEDGEMENT* ptsSetBlockAcknoledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4732. {
  4733.     ptsSetBlockAcknoledgement->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4734.     ptsSetBlockAcknoledgement->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4735.  
  4736.     // 0x7F are the last 7 bits which need is a copy of the set block request command
  4737.     ptsSetBlockAcknoledgement->iCommand = (ptsGenericFrame->tsIdentifiers.iCommand & 0x7F);
  4738.  
  4739.     if ((ptsGenericFrame->tsIdentifiers.iCommand >> 7) == CANTS_FRAME_SUBTYPE_SET_BLOCK_POSITIVE_ACKNOWLEDGEMENT)
  4740.     {
  4741.         ptsSetBlockAcknoledgement->teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
  4742.         ptsSetBlockAcknoledgement->iDataLength = ptsGenericFrame->iDataLength;
  4743.  
  4744.         for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4745.         {
  4746.             ptsSetBlockAcknoledgement->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  4747.         }
  4748.     }
  4749.     else
  4750.     {
  4751.         ptsSetBlockAcknoledgement->teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
  4752.  
  4753.         // A negative acknowledgement contains no data
  4754.         ptsSetBlockAcknoledgement->iDataLength = 0U;
  4755.     }
  4756.  
  4757.     return BT_SUCCESS;
  4758. }
  4759.  
  4760. /**
  4761.  * Translates a Generic frame to a Set Block Transfer frame.
  4762.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4763.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4764.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4765.  * @param ptsSetBlockTransferFrame: tsCANTS_FRAME_SET_BLOCK_TRANSFER*: The set block transfer frame
  4766.  * @re-entrant:
  4767.  */
  4768. #ifndef UNIT_TEST
  4769. static
  4770. #endif /* UNIT_TEST */
  4771.  teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockTransfer(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_TRANSFER* ptsSetBlockTransferFrame)
  4772. {
  4773.     EH_ASSERT(ptsGenericFrame->iDataLength > 0U, CANTS_INVALID_PARAMETER, "A set block transfer contained 0 bytes");
  4774.  
  4775.     ptsSetBlockTransferFrame->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4776.     ptsSetBlockTransferFrame->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4777.  
  4778.     // 0x3F is the last 6 bits which is the block sequence
  4779.     ptsSetBlockTransferFrame->iSequence = (ptsGenericFrame->tsIdentifiers.iCommand & 0x3F);
  4780.  
  4781.     // Copy the block data
  4782.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4783.     {
  4784.         ptsSetBlockTransferFrame->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  4785.     }
  4786.  
  4787.     ptsSetBlockTransferFrame->iDataLength = ptsGenericFrame->iDataLength;
  4788.  
  4789.     return BT_SUCCESS;
  4790.  
  4791. CANTS_INVALID_PARAMETER:
  4792.     return BT_FAIL;
  4793. }
  4794.  
  4795. /**
  4796.  * Translates a Generic frame to a Set Block Abort frame.
  4797.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4798.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4799.  * @param ptsSetBlockAbort: tsCANTS_FRAME_SET_BLOCK_ABORT*: The set block abort frame
  4800.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4801.  * @re-entrant:
  4802.  */
  4803. #ifndef UNIT_TEST
  4804. static
  4805. #endif /* UNIT_TEST */
  4806.  teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockAbort(tsCANTS_FRAME_SET_BLOCK_ABORT* ptsSetBlockAbort, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4807. {
  4808.     ptsSetBlockAbort->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4809.     ptsSetBlockAbort->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4810.  
  4811.     return BT_SUCCESS;
  4812. }
  4813.  
  4814. /**
  4815.  * Translates a Generic frame to a Set Block Status Request frame.
  4816.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4817.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4818.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4819.  * @param ptsSetBlockStatusRequest: tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST*: The set block status
  4820.  * request frame
  4821.  * @re-entrant:
  4822.  */
  4823. #ifndef UNIT_TEST
  4824. static
  4825. #endif /* UNIT_TEST */
  4826.  teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockStatusRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REQUEST* ptsSetBlockStatusRequest)
  4827. {
  4828.     ptsSetBlockStatusRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4829.     ptsSetBlockStatusRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4830.  
  4831.     return BT_SUCCESS;
  4832. }
  4833.  
  4834. /**
  4835.  * Translates a Generic frame to a Set Block Status Report frame.
  4836.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4837.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4838.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4839.  * @param ptsSetBlockStatusReport: tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT*: The set block status report
  4840.  * frame
  4841.  * @re-entrant:
  4842.  */
  4843. #ifndef UNIT_TEST
  4844. static
  4845. #endif /* UNIT_TEST */
  4846.  teFUNC_STATUS CANTS_TranslateFrameGenericToSetBlockStatusReport(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_SET_BLOCK_STATUS_REPORT* ptsSetBlockStatusReport)
  4847. {
  4848.     // The status report needs at least one byte
  4849.     EH_ASSERT(ptsGenericFrame->iDataLength > 0, CANTS_INVALID_PARAMETER, "A set block status report contained 0 bytes");
  4850.  
  4851.     ptsSetBlockStatusReport->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4852.     ptsSetBlockStatusReport->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4853.  
  4854.     // All are assumed zero except the ones actually given in the data
  4855.     ptsSetBlockStatusReport->iBlocksReceived = 0U;
  4856.  
  4857.     // Copy the bitfield
  4858.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4859.     {
  4860.         ((tUINT8*)&ptsSetBlockStatusReport->iBlocksReceived)[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  4861.     }
  4862.  
  4863.     // 0x40 is the 'is complete' bit
  4864.     ptsSetBlockStatusReport->bComplete = (tBOOL)((ptsGenericFrame->tsIdentifiers.iCommand & 0x40) >> 6);
  4865.  
  4866.     return BT_SUCCESS;
  4867.  
  4868. CANTS_INVALID_PARAMETER:
  4869.     return BT_FAIL;
  4870. }
  4871.  
  4872. /** TODO: Add exception CANTS_TRANSLATE_ERROR to EA
  4873.  * Translates a Generic frame to a Get Block Request frame.
  4874.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4875.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4876.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4877.  * @param ptsGetBlockRequest: tsCANTS_FRAME_GET_BLOCK_REQUEST*: The get block request frame
  4878.  * @re-entrant:
  4879.  */
  4880. #ifndef UNIT_TEST
  4881. static
  4882. #endif /* UNIT_TEST */
  4883.  teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockRequest(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_REQUEST* ptsGetBlockRequest)
  4884. {
  4885.     // Ensure there's at least 1 byte for the start address
  4886.     EH_ASSERT(ptsGenericFrame->iDataLength > 0U, CANTS_INVALID_PARAMETER, "A get block request had 0 data bytes");
  4887.  
  4888.     ptsGetBlockRequest->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4889.     ptsGetBlockRequest->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4890.  
  4891.     // 0x3F is the last six bits which the number of blocks
  4892.     ptsGetBlockRequest->iNumberOfBlocks = (ptsGenericFrame->tsIdentifiers.iCommand & 0x3F);
  4893.  
  4894.     ptsGetBlockRequest->teAddressSize = (teCANTS_ADDRESS_SIZE)ptsGenericFrame->iDataLength;
  4895.  
  4896.     // Assign the address as zero to begin with
  4897.     ptsGetBlockRequest->iStartAddress = 0U;
  4898.  
  4899.     // Copy the bytes keeping in mind it's little endian
  4900.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4901.     {
  4902.         ptsGetBlockRequest->iStartAddress |= (((tUINT64)ptsGenericFrame->acData[iByteIndex]) << (8 * iByteIndex));
  4903.     }
  4904.  
  4905.     // Flip the endianness to native
  4906.     teFUNC_STATUS teFlipEndianStatus = funcCANTS_LittleEndianToNativeEndianness(&(ptsGetBlockRequest->iStartAddress));
  4907.     EH_ASSERT(teFlipEndianStatus == BT_SUCCESS, CANTS_TRANSLATE_ERROR, "Failed to flip get block request address endianness");
  4908.  
  4909.     return BT_SUCCESS;
  4910.  
  4911. CANTS_INVALID_PARAMETER:
  4912. CANTS_TRANSLATE_ERROR:
  4913.     return BT_FAIL;
  4914. }
  4915.  
  4916. /**
  4917.  * Translates a Generic frame to a Get Block Acknowledgement frame.
  4918.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4919.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4920.  * @param ptsGetBlockAcknowledgement: tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT*: The get block
  4921.  * acknowledgement frame
  4922.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4923.  * @re-entrant:
  4924.  */
  4925. #ifndef UNIT_TEST
  4926. static
  4927. #endif /* UNIT_TEST */
  4928.  teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockAcknowledgement(tsCANTS_FRAME_GET_BLOCK_ACKNOWLEDGEMENT* ptsGetBlockAcknowledgement, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4929. {
  4930.     ptsGetBlockAcknowledgement->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4931.     ptsGetBlockAcknowledgement->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4932.  
  4933.     // If the get block acknowledgement was positive
  4934.     if ((ptsGenericFrame->tsIdentifiers.iCommand >> 7) == CANTS_FRAME_SUBTYPE_GET_BLOCK_POSITIVE_ACKNOWLEDGEMENT)
  4935.     {
  4936.         ptsGetBlockAcknowledgement->teAcknowledgement = CANTS_POSITIVE_ACKNOWLEDGEMENT;
  4937.  
  4938.         // Copy the acknowledgement response
  4939.         for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4940.         {
  4941.             ptsGetBlockAcknowledgement->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  4942.         }
  4943.  
  4944.         ptsGetBlockAcknowledgement->iDataLength = ptsGenericFrame->iDataLength;
  4945.     }
  4946.     else
  4947.     {
  4948.         ptsGetBlockAcknowledgement->teAcknowledgement = CANTS_NEGATIVE_ACKNOWLEDGEMENT;
  4949.  
  4950.         // Negative acknowledgements have zero bytes
  4951.         ptsGetBlockAcknowledgement->iDataLength = 0U;
  4952.     }
  4953.  
  4954.     return BT_SUCCESS;
  4955. }
  4956.  
  4957. /**
  4958.  * Translates a Generic frame to a Get Block Start frame.
  4959.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4960.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4961.  * @param ptsGetBlockStart: tsCANTS_FRAME_GET_BLOCK_START*: The get block start frame
  4962.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4963.  * @re-entrant:
  4964.  */
  4965. #ifndef UNIT_TEST
  4966. static
  4967. #endif /* UNIT_TEST */
  4968.  teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockStart(tsCANTS_FRAME_GET_BLOCK_START* ptsGetBlockStart, tsCANTS_FRAME_GENERIC* ptsGenericFrame)
  4969. {
  4970.     // Ensure there's at least 1 byte for the bitmap
  4971.     EH_ASSERT(ptsGenericFrame->iDataLength > 0U, CANTS_INVALID_PARAMETER, "Get block start frame had 0 bytes");
  4972.  
  4973.     ptsGetBlockStart->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  4974.     ptsGetBlockStart->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  4975.  
  4976.     ptsGetBlockStart->iBlocksToGet = 0U;
  4977.  
  4978.     // Copy the bitmap of blocks to send
  4979.     for (tUINT32 iByteIndex = 0U; iByteIndex < ptsGenericFrame->iDataLength; ++iByteIndex)
  4980.     {
  4981.         ((tUINT8*)&ptsGetBlockStart->iBlocksToGet)[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  4982.     }
  4983.  
  4984.     return BT_SUCCESS;
  4985.  
  4986. CANTS_INVALID_PARAMETER:
  4987.     return BT_FAIL;
  4988. }
  4989.  
  4990. /**
  4991.  * Translates a Generic frame to a Get Block Transfer frame.
  4992.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  4993.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  4994.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  4995.  * @param ptsGetBlockTransfer: tsCANTS_FRAME_GET_BLOCK_TRANSFER*: The get block transfer frame
  4996.  * @re-entrant:
  4997.  */
  4998. #ifndef UNIT_TEST
  4999. static
  5000. #endif /* UNIT_TEST */
  5001.  teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockTransfer(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_TRANSFER* ptsGetBlockTransfer)
  5002. {
  5003.     // The standard says all get block transfers need to be 8 bytes
  5004.     EH_ASSERT(ptsGenericFrame->iDataLength == 8, CANTS_INVALID_PARAMETER, "Get block transfer did not contain 8 bytes");
  5005.  
  5006.     ptsGetBlockTransfer->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  5007.     ptsGetBlockTransfer->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  5008.  
  5009.     // 0x3F is the last 6 bits which is the block sequence
  5010.     ptsGetBlockTransfer->iSequence = (ptsGenericFrame->tsIdentifiers.iCommand & 0x3F);
  5011.  
  5012.     // Copy the transfer data
  5013.     for (tUINT32 iByteIndex = 0U; iByteIndex < 8; ++iByteIndex)
  5014.     {
  5015.         ptsGetBlockTransfer->acData[iByteIndex] = ptsGenericFrame->acData[iByteIndex];
  5016.     }
  5017.  
  5018.     return BT_SUCCESS;
  5019.  
  5020. CANTS_INVALID_PARAMETER:
  5021.     return BT_FAIL;
  5022. }
  5023.  
  5024. /**
  5025.  * Translates a Generic frame to a Get Block Abort frame.
  5026.  * @returns BT_SUCCESS if there is no exception, otherwise BT_FAIL.
  5027.  * @throws CANTS_INVALID_PARAMETER if an invalid generic frame was provided.
  5028.  * @param ptsGenericFrame: tsCANTS_FRAME_GENERIC*: The generic frame
  5029.  * @param ptsGetBlockAbort: tsCANTS_FRAME_GET_BLOCK_ABORT*: The get block abort frame
  5030.  * @re-entrant:
  5031.  */
  5032. #ifndef UNIT_TEST
  5033. static
  5034. #endif /* UNIT_TEST */
  5035.  teFUNC_STATUS CANTS_TranslateFrameGenericToGetBlockAbort(tsCANTS_FRAME_GENERIC* ptsGenericFrame, tsCANTS_FRAME_GET_BLOCK_ABORT* ptsGetBlockAbort)
  5036. {
  5037.     ptsGetBlockAbort->iToAddress = ptsGenericFrame->tsIdentifiers.iToAddress;
  5038.     ptsGetBlockAbort->iFromAddress = ptsGenericFrame->tsIdentifiers.iFromAddress;
  5039.  
  5040.     return BT_SUCCESS;
  5041. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement