/**
 ****************************************************************************************
 *
 * @file common.c
 *
 * @brief Common FTDF functions
 *
 * Copyright (c) 2016, Dialog Semiconductor
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************************
 */

#include <string.h>
#include <stdlib.h>

#include <ftdf.h>
#include "internal.h"
#include "regmap.h"
#include "black_orca.h"

#if dg_configCOEX_ENABLE_CONFIG
#include "hw_coex.h"
#endif
typedef struct
{
    void   *addr;
    uint8_t size;
    void (* getFunc)(void);
    void (* setFunc)(void);
} PIBAttributeDef;

typedef struct
{
    PIBAttributeDef attributeDefs[ FTDF_NR_OF_PIB_ATTRIBUTES + 1 ];
} PIBAttributeTable;

struct FTDF_Pib                  FTDF_pib __attribute__((section(".retention")));

#ifndef FTDF_LITE
const FTDF_ChannelNumber         page0Channels[ FTDF_NR_OF_CHANNELS ] =
{ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
const FTDF_ChannelDescriptor     channelDescriptors[ 1 ] = { { 0, 16, (FTDF_ChannelNumber *) page0Channels } };
const FTDF_ChannelDescriptorList channelsSupported = { 1, (FTDF_ChannelDescriptor *) channelDescriptors };
#endif

const PIBAttributeTable          pibAttributeTable =
{
    .attributeDefs[ FTDF_PIB_EXTENDED_ADDRESS ].addr                       = &FTDF_pib.extAddress,
    .attributeDefs[ FTDF_PIB_EXTENDED_ADDRESS ].size                       = sizeof(FTDF_pib.extAddress),
    .attributeDefs[ FTDF_PIB_EXTENDED_ADDRESS ].getFunc                    = FTDF_getExtAddress,
    .attributeDefs[ FTDF_PIB_EXTENDED_ADDRESS ].setFunc                    = FTDF_setExtAddress,
    .attributeDefs[ FTDF_PIB_ACK_WAIT_DURATION ].addr                      = &FTDF_pib.ackWaitDuration,
    .attributeDefs[ FTDF_PIB_ACK_WAIT_DURATION ].size                      = 0,
    .attributeDefs[ FTDF_PIB_ACK_WAIT_DURATION ].getFunc                   = FTDF_getAckWaitDuration,
    .attributeDefs[ FTDF_PIB_ACK_WAIT_DURATION ].setFunc                   = NULL,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_ASSOCIATION_PAN_COORD ].addr                  = &FTDF_pib.associatedPANCoord,
    .attributeDefs[ FTDF_PIB_ASSOCIATION_PAN_COORD ].size                  = sizeof(FTDF_pib.associatedPANCoord),
    .attributeDefs[ FTDF_PIB_ASSOCIATION_PAN_COORD ].getFunc               = NULL,
    .attributeDefs[ FTDF_PIB_ASSOCIATION_PAN_COORD ].setFunc               = NULL,
    .attributeDefs[ FTDF_PIB_ASSOCIATION_PERMIT ].addr                     = &FTDF_pib.associationPermit,
    .attributeDefs[ FTDF_PIB_ASSOCIATION_PERMIT ].size                     = sizeof(FTDF_pib.associationPermit),
    .attributeDefs[ FTDF_PIB_ASSOCIATION_PERMIT ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_ASSOCIATION_PERMIT ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_AUTO_REQUEST ].addr                           = &FTDF_pib.autoRequest,
    .attributeDefs[ FTDF_PIB_AUTO_REQUEST ].size                           = sizeof(FTDF_pib.autoRequest),
    .attributeDefs[ FTDF_PIB_AUTO_REQUEST ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_AUTO_REQUEST ].setFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_BATT_LIFE_EXT ].addr                          = &FTDF_pib.battLifeExt,
    .attributeDefs[ FTDF_PIB_BATT_LIFE_EXT ].size                          = sizeof(FTDF_pib.battLifeExt),
    .attributeDefs[ FTDF_PIB_BATT_LIFE_EXT ].getFunc                       = NULL,
    .attributeDefs[ FTDF_PIB_BATT_LIFE_EXT ].setFunc                       = NULL,
    .attributeDefs[ FTDF_PIB_BATT_LIFE_EXT_PERIODS ].addr                  = &FTDF_pib.battLifeExtPeriods,
    .attributeDefs[ FTDF_PIB_BATT_LIFE_EXT_PERIODS ].size                  = sizeof(FTDF_pib.battLifeExtPeriods),
    .attributeDefs[ FTDF_PIB_BATT_LIFE_EXT_PERIODS ].getFunc               = NULL,
    .attributeDefs[ FTDF_PIB_BATT_LIFE_EXT_PERIODS ].setFunc               = NULL,
    .attributeDefs[ FTDF_PIB_BEACON_PAYLOAD ].addr                         = &FTDF_pib.beaconPayload,
    .attributeDefs[ FTDF_PIB_BEACON_PAYLOAD ].size                         = sizeof(FTDF_pib.beaconPayload),
    .attributeDefs[ FTDF_PIB_BEACON_PAYLOAD ].getFunc                      = NULL,
    .attributeDefs[ FTDF_PIB_BEACON_PAYLOAD ].setFunc                      = NULL,
    .attributeDefs[ FTDF_PIB_BEACON_PAYLOAD_LENGTH ].addr                  = &FTDF_pib.beaconPayloadLength,
    .attributeDefs[ FTDF_PIB_BEACON_PAYLOAD_LENGTH ].size                  = sizeof(FTDF_pib.beaconPayloadLength),
    .attributeDefs[ FTDF_PIB_BEACON_PAYLOAD_LENGTH ].getFunc               = NULL,
    .attributeDefs[ FTDF_PIB_BEACON_PAYLOAD_LENGTH ].setFunc               = NULL,
    .attributeDefs[ FTDF_PIB_BEACON_ORDER ].addr                           = &FTDF_pib.beaconOrder,
    .attributeDefs[ FTDF_PIB_BEACON_ORDER ].size                           = 0,
    .attributeDefs[ FTDF_PIB_BEACON_ORDER ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_BEACON_ORDER ].setFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_BEACON_TX_TIME ].addr                         = &FTDF_pib.beaconTxTime,
    .attributeDefs[ FTDF_PIB_BEACON_TX_TIME ].size                         = sizeof(FTDF_pib.beaconTxTime),
    .attributeDefs[ FTDF_PIB_BEACON_TX_TIME ].getFunc                      = NULL,
    .attributeDefs[ FTDF_PIB_BEACON_TX_TIME ].setFunc                      = NULL,
    .attributeDefs[ FTDF_PIB_BSN ].addr                                    = &FTDF_pib.BSN,
    .attributeDefs[ FTDF_PIB_BSN ].size                                    = sizeof(FTDF_pib.BSN),
    .attributeDefs[ FTDF_PIB_BSN ].getFunc                                 = NULL,
    .attributeDefs[ FTDF_PIB_BSN ].setFunc                                 = NULL,
    .attributeDefs[ FTDF_PIB_COORD_EXTENDED_ADDRESS ].addr                 = &FTDF_pib.coordExtAddress,
    .attributeDefs[ FTDF_PIB_COORD_EXTENDED_ADDRESS ].size                 = sizeof(FTDF_pib.coordExtAddress),
    .attributeDefs[ FTDF_PIB_COORD_EXTENDED_ADDRESS ].getFunc              = NULL,
    .attributeDefs[ FTDF_PIB_COORD_EXTENDED_ADDRESS ].setFunc              = NULL,
    .attributeDefs[ FTDF_PIB_COORD_SHORT_ADDRESS ].addr                    = &FTDF_pib.coordShortAddress,
    .attributeDefs[ FTDF_PIB_COORD_SHORT_ADDRESS ].size                    = sizeof(FTDF_pib.coordShortAddress),
    .attributeDefs[ FTDF_PIB_COORD_SHORT_ADDRESS ].getFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_COORD_SHORT_ADDRESS ].setFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_DSN ].addr                                    = &FTDF_pib.DSN,
    .attributeDefs[ FTDF_PIB_DSN ].size                                    = sizeof(FTDF_pib.DSN),
    .attributeDefs[ FTDF_PIB_DSN ].getFunc                                 = NULL,
    .attributeDefs[ FTDF_PIB_DSN ].setFunc                                 = NULL,
    .attributeDefs[ FTDF_PIB_GTS_PERMIT ].addr                             = &FTDF_pib.GTSPermit,
    .attributeDefs[ FTDF_PIB_GTS_PERMIT ].size                             = 0,
    .attributeDefs[ FTDF_PIB_GTS_PERMIT ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_GTS_PERMIT ].setFunc                          = NULL,
#endif /* !FTDF_LITE */
    .attributeDefs[ FTDF_PIB_MAX_BE ].addr                                 = &FTDF_pib.maxBE,
    .attributeDefs[ FTDF_PIB_MAX_BE ].size                                 = sizeof(FTDF_pib.maxBE),
    .attributeDefs[ FTDF_PIB_MAX_BE ].getFunc                              = NULL,
    .attributeDefs[ FTDF_PIB_MAX_BE ].setFunc                              = FTDF_setMaxBE,
    .attributeDefs[ FTDF_PIB_MAX_CSMA_BACKOFFS ].addr                      = &FTDF_pib.maxCSMABackoffs,
    .attributeDefs[ FTDF_PIB_MAX_CSMA_BACKOFFS ].size                      = sizeof(FTDF_pib.maxCSMABackoffs),
    .attributeDefs[ FTDF_PIB_MAX_CSMA_BACKOFFS ].getFunc                   = NULL,
    .attributeDefs[ FTDF_PIB_MAX_CSMA_BACKOFFS ].setFunc                   = FTDF_setMaxCSMABackoffs,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_TOTAL_WAIT_TIME ].addr              = &FTDF_pib.maxFrameTotalWaitTime,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_TOTAL_WAIT_TIME ].size              = sizeof(FTDF_pib.maxFrameTotalWaitTime),
    .attributeDefs[ FTDF_PIB_MAX_FRAME_TOTAL_WAIT_TIME ].getFunc           = FTDF_getMaxFrameTotalWaitTime,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_TOTAL_WAIT_TIME ].setFunc           = FTDF_setMaxFrameTotalWaitTime,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_RETRIES ].addr                      = &FTDF_pib.maxFrameRetries,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_RETRIES ].size                      = sizeof(FTDF_pib.maxFrameRetries),
    .attributeDefs[ FTDF_PIB_MAX_FRAME_RETRIES ].getFunc                   = NULL,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_RETRIES ].setFunc                   = NULL,
    .attributeDefs[ FTDF_PIB_MIN_BE ].addr                                 = &FTDF_pib.minBE,
    .attributeDefs[ FTDF_PIB_MIN_BE ].size                                 = sizeof(FTDF_pib.minBE),
    .attributeDefs[ FTDF_PIB_MIN_BE ].getFunc                              = NULL,
    .attributeDefs[ FTDF_PIB_MIN_BE ].setFunc                              = FTDF_setMinBE,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_LIFS_PERIOD ].addr                            = &FTDF_pib.LIFSPeriod,
    .attributeDefs[ FTDF_PIB_LIFS_PERIOD ].size                            = 0,
    .attributeDefs[ FTDF_PIB_LIFS_PERIOD ].getFunc                         = NULL,
    .attributeDefs[ FTDF_PIB_LIFS_PERIOD ].setFunc                         = NULL,
    .attributeDefs[ FTDF_PIB_SIFS_PERIOD ].addr                            = &FTDF_pib.SIFSPeriod,
    .attributeDefs[ FTDF_PIB_SIFS_PERIOD ].size                            = 0,
    .attributeDefs[ FTDF_PIB_SIFS_PERIOD ].getFunc                         = NULL,
    .attributeDefs[ FTDF_PIB_SIFS_PERIOD ].setFunc                         = NULL,
#endif
    .attributeDefs[ FTDF_PIB_PAN_ID ].addr                                 = &FTDF_pib.PANId,
    .attributeDefs[ FTDF_PIB_PAN_ID ].size                                 = sizeof(FTDF_pib.PANId),
    .attributeDefs[ FTDF_PIB_PAN_ID ].getFunc                              = FTDF_getPANId,
    .attributeDefs[ FTDF_PIB_PAN_ID ].setFunc                              = FTDF_setPANId,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_PROMISCUOUS_MODE ].addr                       = &FTDF_pib.promiscuousMode,
    .attributeDefs[ FTDF_PIB_PROMISCUOUS_MODE ].size                       = sizeof(FTDF_pib.promiscuousMode),
    .attributeDefs[ FTDF_PIB_PROMISCUOUS_MODE ].getFunc                    = NULL,
    .attributeDefs[ FTDF_PIB_PROMISCUOUS_MODE ].setFunc                    = NULL,
    .attributeDefs[ FTDF_PIB_RESPONSE_WAIT_TIME ].addr                     = &FTDF_pib.responseWaitTime,
    .attributeDefs[ FTDF_PIB_RESPONSE_WAIT_TIME ].size                     = sizeof(FTDF_pib.responseWaitTime),
    .attributeDefs[ FTDF_PIB_RESPONSE_WAIT_TIME ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_RESPONSE_WAIT_TIME ].setFunc                  = NULL,
#endif /* !FTDF_LITE */
    .attributeDefs[ FTDF_PIB_RX_ON_WHEN_IDLE ].addr                        = &FTDF_pib.rxOnWhenIdle,
    .attributeDefs[ FTDF_PIB_RX_ON_WHEN_IDLE ].size                        = sizeof(FTDF_pib.rxOnWhenIdle),
    .attributeDefs[ FTDF_PIB_RX_ON_WHEN_IDLE ].getFunc                     = FTDF_getRxOnWhenIdle,
    .attributeDefs[ FTDF_PIB_RX_ON_WHEN_IDLE ].setFunc                     = FTDF_setRxOnWhenIdle,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_SECURITY_ENABLED ].addr                       = &FTDF_pib.securityEnabled,
    .attributeDefs[ FTDF_PIB_SECURITY_ENABLED ].size                       = sizeof(FTDF_pib.securityEnabled),
    .attributeDefs[ FTDF_PIB_SECURITY_ENABLED ].getFunc                    = NULL,
    .attributeDefs[ FTDF_PIB_SECURITY_ENABLED ].setFunc                    = NULL,
#endif /* !FTDF_LITE */
    .attributeDefs[ FTDF_PIB_SHORT_ADDRESS ].addr                          = &FTDF_pib.shortAddress,
    .attributeDefs[ FTDF_PIB_SHORT_ADDRESS ].size                          = sizeof(FTDF_pib.shortAddress),
    .attributeDefs[ FTDF_PIB_SHORT_ADDRESS ].getFunc                       = NULL,
    .attributeDefs[ FTDF_PIB_SHORT_ADDRESS ].setFunc                       = FTDF_setShortAddress,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_SUPERFRAME_ORDER ].addr                       = &FTDF_pib.superframeOrder,
    .attributeDefs[ FTDF_PIB_SUPERFRAME_ORDER ].size                       = 0,
    .attributeDefs[ FTDF_PIB_SUPERFRAME_ORDER ].getFunc                    = NULL,
    .attributeDefs[ FTDF_PIB_SUPERFRAME_ORDER ].setFunc                    = NULL,
    .attributeDefs[ FTDF_PIB_SYNC_SYMBOL_OFFSET ].addr                     = &FTDF_pib.syncSymbolOffset,
    .attributeDefs[ FTDF_PIB_SYNC_SYMBOL_OFFSET ].size                     = 0,
    .attributeDefs[ FTDF_PIB_SYNC_SYMBOL_OFFSET ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_SYNC_SYMBOL_OFFSET ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_TIMESTAMP_SUPPORTED ].addr                    = &FTDF_pib.timestampSupported,
    .attributeDefs[ FTDF_PIB_TIMESTAMP_SUPPORTED ].size                    = 0,
    .attributeDefs[ FTDF_PIB_TIMESTAMP_SUPPORTED ].getFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_TIMESTAMP_SUPPORTED ].setFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_TRANSACTION_PERSISTENCE_TIME ].addr           = &FTDF_pib.transactionPersistenceTime,
    .attributeDefs[ FTDF_PIB_TRANSACTION_PERSISTENCE_TIME ].size           =
    sizeof(FTDF_pib.transactionPersistenceTime),
    .attributeDefs[ FTDF_PIB_TRANSACTION_PERSISTENCE_TIME ].getFunc        = NULL,
    .attributeDefs[ FTDF_PIB_TRANSACTION_PERSISTENCE_TIME ].setFunc        = NULL,
    .attributeDefs[ FTDF_PIB_ENH_ACK_WAIT_DURATION ].addr                  = &FTDF_pib.enhAckWaitDuration,
    .attributeDefs[ FTDF_PIB_ENH_ACK_WAIT_DURATION ].size                  = sizeof(FTDF_pib.enhAckWaitDuration),
    .attributeDefs[ FTDF_PIB_ENH_ACK_WAIT_DURATION ].getFunc               = FTDF_getEnhAckWaitDuration,
    .attributeDefs[ FTDF_PIB_ENH_ACK_WAIT_DURATION ].setFunc               = FTDF_setEnhAckWaitDuration,
    .attributeDefs[ FTDF_PIB_IMPLICIT_BROADCAST ].addr                     = &FTDF_pib.implicitBroadcast,
    .attributeDefs[ FTDF_PIB_IMPLICIT_BROADCAST ].size                     = sizeof(FTDF_pib.implicitBroadcast),
    .attributeDefs[ FTDF_PIB_IMPLICIT_BROADCAST ].getFunc                  = FTDF_getImplicitBroadcast,
    .attributeDefs[ FTDF_PIB_IMPLICIT_BROADCAST ].setFunc                  = FTDF_setImplicitBroadcast,
    .attributeDefs[ FTDF_PIB_SIMPLE_ADDRESS ].addr                         = &FTDF_pib.simpleAddress,
    .attributeDefs[ FTDF_PIB_SIMPLE_ADDRESS ].size                         = sizeof(FTDF_pib.simpleAddress),
    .attributeDefs[ FTDF_PIB_SIMPLE_ADDRESS ].getFunc                      = NULL,
    .attributeDefs[ FTDF_PIB_SIMPLE_ADDRESS ].setFunc                      = FTDF_setSimpleAddress,
    .attributeDefs[ FTDF_PIB_DISCONNECT_TIME ].addr                        = &FTDF_pib.disconnectTime,
    .attributeDefs[ FTDF_PIB_DISCONNECT_TIME ].size                        = sizeof(FTDF_pib.disconnectTime),
    .attributeDefs[ FTDF_PIB_DISCONNECT_TIME ].getFunc                     = NULL,
    .attributeDefs[ FTDF_PIB_DISCONNECT_TIME ].setFunc                     = NULL,
    .attributeDefs[ FTDF_PIB_JOIN_PRIORITY ].addr                          = &FTDF_pib.joinPriority,
    .attributeDefs[ FTDF_PIB_JOIN_PRIORITY ].size                          = sizeof(FTDF_pib.joinPriority),
    .attributeDefs[ FTDF_PIB_JOIN_PRIORITY ].getFunc                       = NULL,
    .attributeDefs[ FTDF_PIB_JOIN_PRIORITY ].setFunc                       = NULL,
    .attributeDefs[ FTDF_PIB_ASN ].addr                                    = &FTDF_pib.ASN,
    .attributeDefs[ FTDF_PIB_ASN ].size                                    = sizeof(FTDF_pib.ASN),
    .attributeDefs[ FTDF_PIB_ASN ].getFunc                                 = NULL,
    .attributeDefs[ FTDF_PIB_ASN ].setFunc                                 = NULL,
    .attributeDefs[ FTDF_PIB_NO_HL_BUFFERS ].addr                          = &FTDF_pib.noHLBuffers,
    .attributeDefs[ FTDF_PIB_NO_HL_BUFFERS ].size                          = sizeof(FTDF_pib.noHLBuffers),
    .attributeDefs[ FTDF_PIB_NO_HL_BUFFERS ].getFunc                       = NULL,
    .attributeDefs[ FTDF_PIB_NO_HL_BUFFERS ].setFunc                       = NULL,
    .attributeDefs[ FTDF_PIB_SLOTFRAME_TABLE ].addr                        = &FTDF_pib.slotframeTable,
    .attributeDefs[ FTDF_PIB_SLOTFRAME_TABLE ].size                        = 0,
    .attributeDefs[ FTDF_PIB_SLOTFRAME_TABLE ].getFunc                     = NULL,
    .attributeDefs[ FTDF_PIB_SLOTFRAME_TABLE ].setFunc                     = NULL,
    .attributeDefs[ FTDF_PIB_LINK_TABLE ].addr                             = &FTDF_pib.linkTable,
    .attributeDefs[ FTDF_PIB_LINK_TABLE ].size                             = 0,
    .attributeDefs[ FTDF_PIB_LINK_TABLE ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_LINK_TABLE ].setFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_TIMESLOT_TEMPLATE ].addr                      = &FTDF_pib.timeslotTemplate,
    .attributeDefs[ FTDF_PIB_TIMESLOT_TEMPLATE ].size                      = sizeof(FTDF_pib.timeslotTemplate),
    .attributeDefs[ FTDF_PIB_TIMESLOT_TEMPLATE ].getFunc                   = NULL,
#ifdef FTDF_NO_TSCH
    .attributeDefs[ FTDF_PIB_TIMESLOT_TEMPLATE ].setFunc                   = NULL,
#else
    .attributeDefs[ FTDF_PIB_TIMESLOT_TEMPLATE ].setFunc                   = FTDF_setTimeslotTemplate,
#endif /* FTDF_NO_TSCH */
    .attributeDefs[ FTDF_PIB_HOPPINGSEQUENCE_ID ].addr                     = &FTDF_pib.HoppingSequenceId,
    .attributeDefs[ FTDF_PIB_HOPPINGSEQUENCE_ID ].size                     = sizeof(FTDF_pib.HoppingSequenceId),
    .attributeDefs[ FTDF_PIB_HOPPINGSEQUENCE_ID ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_HOPPINGSEQUENCE_ID ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_CHANNEL_PAGE ].addr                           = &FTDF_pib.channelPage,
    .attributeDefs[ FTDF_PIB_CHANNEL_PAGE ].size                           = sizeof(FTDF_pib.channelPage),
    .attributeDefs[ FTDF_PIB_CHANNEL_PAGE ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_CHANNEL_PAGE ].setFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_NUMBER_OF_CHANNELS ].addr                     = &FTDF_pib.numberOfChannels,
    .attributeDefs[ FTDF_PIB_NUMBER_OF_CHANNELS ].size                     = sizeof(FTDF_pib.numberOfChannels),
    .attributeDefs[ FTDF_PIB_NUMBER_OF_CHANNELS ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_NUMBER_OF_CHANNELS ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_PHY_CONFIGURATION ].addr                      = &FTDF_pib.phyConfiguration,
    .attributeDefs[ FTDF_PIB_PHY_CONFIGURATION ].size                      = sizeof(FTDF_pib.phyConfiguration),
    .attributeDefs[ FTDF_PIB_PHY_CONFIGURATION ].getFunc                   = NULL,
    .attributeDefs[ FTDF_PIB_PHY_CONFIGURATION ].setFunc                   = NULL,
    .attributeDefs[ FTDF_PIB_EXTENTED_BITMAP ].addr                        = &FTDF_pib.extendedBitmap,
    .attributeDefs[ FTDF_PIB_EXTENTED_BITMAP ].size                        = sizeof(FTDF_pib.extendedBitmap),
    .attributeDefs[ FTDF_PIB_EXTENTED_BITMAP ].getFunc                     = NULL,
    .attributeDefs[ FTDF_PIB_EXTENTED_BITMAP ].setFunc                     = NULL,
    .attributeDefs[ FTDF_PIB_HOPPING_SEQUENCE_LENGTH ].addr                = &FTDF_pib.hoppingSequenceLength,
    .attributeDefs[ FTDF_PIB_HOPPING_SEQUENCE_LENGTH ].size                = sizeof(FTDF_pib.hoppingSequenceLength),
    .attributeDefs[ FTDF_PIB_HOPPING_SEQUENCE_LENGTH ].getFunc             = NULL,
    .attributeDefs[ FTDF_PIB_HOPPING_SEQUENCE_LENGTH ].setFunc             = NULL,
    .attributeDefs[ FTDF_PIB_HOPPING_SEQUENCE_LIST ].addr                  = FTDF_pib.hoppingSequenceList,
    .attributeDefs[ FTDF_PIB_HOPPING_SEQUENCE_LIST ].size                  = sizeof(FTDF_pib.hoppingSequenceList),
    .attributeDefs[ FTDF_PIB_HOPPING_SEQUENCE_LIST ].getFunc               = NULL,
    .attributeDefs[ FTDF_PIB_HOPPING_SEQUENCE_LIST ].setFunc               = NULL,
    .attributeDefs[ FTDF_PIB_CURRENT_HOP ].addr                            = &FTDF_pib.currentHop,
    .attributeDefs[ FTDF_PIB_CURRENT_HOP ].size                            = sizeof(FTDF_pib.currentHop),
    .attributeDefs[ FTDF_PIB_CURRENT_HOP ].getFunc                         = NULL,
    .attributeDefs[ FTDF_PIB_CURRENT_HOP ].setFunc                         = NULL,
    .attributeDefs[ FTDF_PIB_DWELL_TIME ].addr                             = &FTDF_pib.dwellTime,
    .attributeDefs[ FTDF_PIB_DWELL_TIME ].size                             = sizeof(FTDF_pib.dwellTime),
    .attributeDefs[ FTDF_PIB_DWELL_TIME ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_DWELL_TIME ].setFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_CSL_PERIOD ].addr                             = &FTDF_pib.CSLPeriod,
    .attributeDefs[ FTDF_PIB_CSL_PERIOD ].size                             = sizeof(FTDF_pib.CSLPeriod),
    .attributeDefs[ FTDF_PIB_CSL_PERIOD ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_CSL_PERIOD ].setFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_CSL_MAX_PERIOD ].addr                         = &FTDF_pib.CSLMaxPeriod,
    .attributeDefs[ FTDF_PIB_CSL_MAX_PERIOD ].size                         = sizeof(FTDF_pib.CSLMaxPeriod),
    .attributeDefs[ FTDF_PIB_CSL_MAX_PERIOD ].getFunc                      = NULL,
    .attributeDefs[ FTDF_PIB_CSL_MAX_PERIOD ].setFunc                      = NULL,
    .attributeDefs[ FTDF_PIB_CSL_CHANNEL_MASK ].addr                       = &FTDF_pib.CSLChannelMask,
    .attributeDefs[ FTDF_PIB_CSL_CHANNEL_MASK ].size                       = sizeof(FTDF_pib.CSLChannelMask),
    .attributeDefs[ FTDF_PIB_CSL_CHANNEL_MASK ].getFunc                    = NULL,
    .attributeDefs[ FTDF_PIB_CSL_CHANNEL_MASK ].setFunc                    = NULL,
    .attributeDefs[ FTDF_PIB_CSL_FRAME_PENDING_WAIT_T ].addr               = &FTDF_pib.CSLFramePendingWaitT,
    .attributeDefs[ FTDF_PIB_CSL_FRAME_PENDING_WAIT_T ].size               = sizeof(FTDF_pib.CSLFramePendingWaitT),
#ifdef FTDF_NO_CSL
    .attributeDefs[ FTDF_PIB_CSL_FRAME_PENDING_WAIT_T ].getFunc            = NULL,
    .attributeDefs[ FTDF_PIB_CSL_FRAME_PENDING_WAIT_T ].setFunc            = NULL,
#else
    .attributeDefs[ FTDF_PIB_CSL_FRAME_PENDING_WAIT_T ].getFunc            = FTDF_getCslFramePendingWaitT,
    .attributeDefs[ FTDF_PIB_CSL_FRAME_PENDING_WAIT_T ].setFunc            = FTDF_setCslFramePendingWaitT,
#endif /* FTDF_NO_CSL */
    .attributeDefs[ FTDF_PIB_LOW_ENERGY_SUPERFRAME_SUPPORTED ].addr        = &FTDF_pib.lowEnergySuperframeSupported,
    .attributeDefs[ FTDF_PIB_LOW_ENERGY_SUPERFRAME_SUPPORTED ].size        =
    sizeof(FTDF_pib.lowEnergySuperframeSupported),
    .attributeDefs[ FTDF_PIB_LOW_ENERGY_SUPERFRAME_SUPPORTED ].getFunc     = NULL,
    .attributeDefs[ FTDF_PIB_LOW_ENERGY_SUPERFRAME_SUPPORTED ].setFunc     = NULL,
    .attributeDefs[ FTDF_PIB_LOW_ENERGY_SUPERFRAME_SYNC_INTERVAL ].addr    = &FTDF_pib.lowEnergySuperframeSyncInterval,
    .attributeDefs[ FTDF_PIB_LOW_ENERGY_SUPERFRAME_SYNC_INTERVAL ].size    =
    sizeof(FTDF_pib.lowEnergySuperframeSyncInterval),
    .attributeDefs[ FTDF_PIB_LOW_ENERGY_SUPERFRAME_SYNC_INTERVAL ].getFunc = NULL,
    .attributeDefs[ FTDF_PIB_LOW_ENERGY_SUPERFRAME_SYNC_INTERVAL ].setFunc = NULL,
#endif /* !FTDF_LITE */
    .attributeDefs[ FTDF_PIB_PERFORMANCE_METRICS ].addr                    = &FTDF_pib.performanceMetrics,
    .attributeDefs[ FTDF_PIB_PERFORMANCE_METRICS ].size                    = sizeof(FTDF_pib.performanceMetrics),
    .attributeDefs[ FTDF_PIB_PERFORMANCE_METRICS ].getFunc                 = FTDF_getLmacPmData,
    .attributeDefs[ FTDF_PIB_PERFORMANCE_METRICS ].setFunc                 = NULL,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_USE_ENHANCED_BEACON ].addr                    = &FTDF_pib.useEnhancedBecaon,
    .attributeDefs[ FTDF_PIB_USE_ENHANCED_BEACON ].size                    = sizeof(FTDF_pib.useEnhancedBecaon),
    .attributeDefs[ FTDF_PIB_USE_ENHANCED_BEACON ].getFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_USE_ENHANCED_BEACON ].setFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_EB_IE_LIST ].addr                             = &FTDF_pib.EBIEList,
    .attributeDefs[ FTDF_PIB_EB_IE_LIST ].size                             = sizeof(FTDF_pib.EBIEList),
    .attributeDefs[ FTDF_PIB_EB_IE_LIST ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_EB_IE_LIST ].setFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_EB_FILTERING_ENABLED ].addr                   = &FTDF_pib.EBFilteringEnabled,
    .attributeDefs[ FTDF_PIB_EB_FILTERING_ENABLED ].size                   = sizeof(FTDF_pib.EBFilteringEnabled),
    .attributeDefs[ FTDF_PIB_EB_FILTERING_ENABLED ].getFunc                = NULL,
    .attributeDefs[ FTDF_PIB_EB_FILTERING_ENABLED ].setFunc                = NULL,
    .attributeDefs[ FTDF_PIB_EBSN ].addr                                   = &FTDF_pib.EBSN,
    .attributeDefs[ FTDF_PIB_EBSN ].size                                   = sizeof(FTDF_pib.EBSN),
    .attributeDefs[ FTDF_PIB_EBSN ].getFunc                                = NULL,
    .attributeDefs[ FTDF_PIB_EBSN ].setFunc                                = NULL,
    .attributeDefs[ FTDF_PIB_EB_AUTO_SA ].addr                             = &FTDF_pib.EBAutoSA,
    .attributeDefs[ FTDF_PIB_EB_AUTO_SA ].size                             = sizeof(FTDF_pib.EBAutoSA),
    .attributeDefs[ FTDF_PIB_EB_AUTO_SA ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_EB_AUTO_SA ].setFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_EACK_IE_LIST ].addr                           = &FTDF_pib.EAckIEList,
    .attributeDefs[ FTDF_PIB_EACK_IE_LIST ].size                           = sizeof(FTDF_pib.EAckIEList),
    .attributeDefs[ FTDF_PIB_EACK_IE_LIST ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_EACK_IE_LIST ].setFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_KEY_TABLE ].addr                              = &FTDF_pib.keyTable,
    .attributeDefs[ FTDF_PIB_KEY_TABLE ].size                              = sizeof(FTDF_pib.keyTable),
    .attributeDefs[ FTDF_PIB_KEY_TABLE ].getFunc                           = NULL,
    .attributeDefs[ FTDF_PIB_KEY_TABLE ].setFunc                           = NULL,
    .attributeDefs[ FTDF_PIB_DEVICE_TABLE ].addr                           = &FTDF_pib.deviceTable,
    .attributeDefs[ FTDF_PIB_DEVICE_TABLE ].size                           = sizeof(FTDF_pib.deviceTable),
    .attributeDefs[ FTDF_PIB_DEVICE_TABLE ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_DEVICE_TABLE ].setFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_SECURITY_LEVEL_TABLE ].addr                   = &FTDF_pib.securityLevelTable,
    .attributeDefs[ FTDF_PIB_SECURITY_LEVEL_TABLE ].size                   = sizeof(FTDF_pib.securityLevelTable),
    .attributeDefs[ FTDF_PIB_SECURITY_LEVEL_TABLE ].getFunc                = NULL,
    .attributeDefs[ FTDF_PIB_SECURITY_LEVEL_TABLE ].setFunc                = NULL,
    .attributeDefs[ FTDF_PIB_FRAME_COUNTER ].addr                          = &FTDF_pib.frameCounter,
    .attributeDefs[ FTDF_PIB_FRAME_COUNTER ].size                          = sizeof(FTDF_pib.frameCounter),
    .attributeDefs[ FTDF_PIB_FRAME_COUNTER ].getFunc                       = NULL,
    .attributeDefs[ FTDF_PIB_FRAME_COUNTER ].setFunc                       = NULL,
    .attributeDefs[ FTDF_PIB_MT_DATA_SECURITY_LEVEL ].addr                 = &FTDF_pib.mtDataSecurityLevel,
    .attributeDefs[ FTDF_PIB_MT_DATA_SECURITY_LEVEL ].size                 =
    sizeof(FTDF_pib.mtDataSecurityLevel),
    .attributeDefs[ FTDF_PIB_MT_DATA_SECURITY_LEVEL ].getFunc              = NULL,
    .attributeDefs[ FTDF_PIB_MT_DATA_SECURITY_LEVEL ].setFunc              = NULL,
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_ID_MODE ].addr                    = &FTDF_pib.mtDataKeyIdMode,
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_ID_MODE ].size                    = sizeof(FTDF_pib.mtDataKeyIdMode),
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_ID_MODE ].getFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_ID_MODE ].setFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_SOURCE ].addr                     = &FTDF_pib.mtDataKeySource,
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_SOURCE ].size                     = sizeof(FTDF_pib.mtDataKeySource),
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_SOURCE ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_SOURCE ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_INDEX ].addr                      = &FTDF_pib.mtDataKeyIndex,
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_INDEX ].size                      = sizeof(FTDF_pib.mtDataKeyIndex),
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_INDEX ].getFunc                   = NULL,
    .attributeDefs[ FTDF_PIB_MT_DATA_KEY_INDEX ].setFunc                   = NULL,
    .attributeDefs[ FTDF_PIB_DEFAULT_KEY_SOURCE ].addr                     = &FTDF_pib.defaultKeySource,
    .attributeDefs[ FTDF_PIB_DEFAULT_KEY_SOURCE ].size                     = sizeof(FTDF_pib.defaultKeySource),
    .attributeDefs[ FTDF_PIB_DEFAULT_KEY_SOURCE ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_DEFAULT_KEY_SOURCE ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_PAN_COORD_EXTENDED_ADDRESS ].addr             = &FTDF_pib.PANCoordExtAddress,
    .attributeDefs[ FTDF_PIB_PAN_COORD_EXTENDED_ADDRESS ].size             = sizeof(FTDF_pib.PANCoordExtAddress),
    .attributeDefs[ FTDF_PIB_PAN_COORD_EXTENDED_ADDRESS ].getFunc          = NULL,
    .attributeDefs[ FTDF_PIB_PAN_COORD_EXTENDED_ADDRESS ].setFunc          = NULL,
    .attributeDefs[ FTDF_PIB_PAN_COORD_SHORT_ADDRESS ].addr                = &FTDF_pib.PANCoordShortAddress,
    .attributeDefs[ FTDF_PIB_PAN_COORD_SHORT_ADDRESS ].size                = sizeof(FTDF_pib.PANCoordShortAddress),
    .attributeDefs[ FTDF_PIB_PAN_COORD_SHORT_ADDRESS ].getFunc             = NULL,
    .attributeDefs[ FTDF_PIB_PAN_COORD_SHORT_ADDRESS ].setFunc             = NULL,
    .attributeDefs[ FTDF_PIB_FRAME_COUNTER_MODE ].addr                     = &FTDF_pib.frameCounterMode,
    .attributeDefs[ FTDF_PIB_FRAME_COUNTER_MODE ].size                     = sizeof(FTDF_pib.frameCounterMode),
    .attributeDefs[ FTDF_PIB_FRAME_COUNTER_MODE ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_FRAME_COUNTER_MODE ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_CSL_SYNC_TX_MARGIN ].addr                     = &FTDF_pib.CSLSyncTxMargin,
    .attributeDefs[ FTDF_PIB_CSL_SYNC_TX_MARGIN ].size                     = sizeof(FTDF_pib.CSLSyncTxMargin),
    .attributeDefs[ FTDF_PIB_CSL_SYNC_TX_MARGIN ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_CSL_SYNC_TX_MARGIN ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_CSL_MAX_AGE_REMOTE_INFO ].addr                = &FTDF_pib.CSLMaxAgeRemoteInfo,
    .attributeDefs[ FTDF_PIB_CSL_MAX_AGE_REMOTE_INFO ].size                = sizeof(FTDF_pib.CSLMaxAgeRemoteInfo),
    .attributeDefs[ FTDF_PIB_CSL_MAX_AGE_REMOTE_INFO ].getFunc             = NULL,
    .attributeDefs[ FTDF_PIB_CSL_MAX_AGE_REMOTE_INFO ].setFunc             = NULL,
    .attributeDefs[ FTDF_PIB_TSCH_ENABLED ].addr                           = &FTDF_pib.tschEnabled,
    .attributeDefs[ FTDF_PIB_TSCH_ENABLED ].size                           = 0,
    .attributeDefs[ FTDF_PIB_TSCH_ENABLED ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_TSCH_ENABLED ].setFunc                        = NULL,
#ifdef FTDF_NO_CSL
    .attributeDefs[ FTDF_PIB_LE_ENABLED ].addr                             = &FTDF_pib.leEnabled,
    .attributeDefs[ FTDF_PIB_LE_ENABLED ].size                             = 0,
    .attributeDefs[ FTDF_PIB_LE_ENABLED ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_LE_ENABLED ].setFunc                          = NULL,
#else
    .attributeDefs[ FTDF_PIB_LE_ENABLED ].addr                             = &FTDF_pib.leEnabled,
    .attributeDefs[ FTDF_PIB_LE_ENABLED ].size                             = sizeof(FTDF_pib.leEnabled),
    .attributeDefs[ FTDF_PIB_LE_ENABLED ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_LE_ENABLED ].setFunc                          = FTDF_setLeEnabled,
#endif /* FTDF_NO_CSL */
#endif /* !FTDF_LITE */
    .attributeDefs[ FTDF_PIB_CURRENT_CHANNEL ].addr                        = &FTDF_pib.currentChannel,
    .attributeDefs[ FTDF_PIB_CURRENT_CHANNEL ].size                        = sizeof(FTDF_pib.currentChannel),
    .attributeDefs[ FTDF_PIB_CURRENT_CHANNEL ].getFunc                     = FTDF_getCurrentChannel,
    .attributeDefs[ FTDF_PIB_CURRENT_CHANNEL ].setFunc                     = FTDF_setCurrentChannel,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_CHANNELS_SUPPORTED ].addr                     = (void *) &channelsSupported,
    .attributeDefs[ FTDF_PIB_CHANNELS_SUPPORTED ].size                     = 0,
    .attributeDefs[ FTDF_PIB_CHANNELS_SUPPORTED ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_CHANNELS_SUPPORTED ].setFunc                  = NULL,
#endif /* !FTDF_LITE */
    .attributeDefs[ FTDF_PIB_TX_POWER_TOLERANCE ].addr                     = &FTDF_pib.TXPowerTolerance,
    .attributeDefs[ FTDF_PIB_TX_POWER_TOLERANCE ].size                     = sizeof(FTDF_pib.TXPowerTolerance),
    .attributeDefs[ FTDF_PIB_TX_POWER_TOLERANCE ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_TX_POWER_TOLERANCE ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_TX_POWER ].addr                               = &FTDF_pib.TXPower,
    .attributeDefs[ FTDF_PIB_TX_POWER ].size                               = sizeof(FTDF_pib.TXPower),
    .attributeDefs[ FTDF_PIB_TX_POWER ].getFunc                            = NULL,
    .attributeDefs[ FTDF_PIB_TX_POWER ].setFunc                            = NULL,
    .attributeDefs[ FTDF_PIB_CCA_MODE ].addr                               = &FTDF_pib.CCAMode,
    .attributeDefs[ FTDF_PIB_CCA_MODE ].size                               = sizeof(FTDF_pib.CCAMode),
    .attributeDefs[ FTDF_PIB_CCA_MODE ].getFunc                            = NULL,
    .attributeDefs[ FTDF_PIB_CCA_MODE ].setFunc                            = NULL,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_CURRENT_PAGE ].addr                           = &FTDF_pib.currentPage,
    .attributeDefs[ FTDF_PIB_CURRENT_PAGE ].size                           = 0,
    .attributeDefs[ FTDF_PIB_CURRENT_PAGE ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_CURRENT_PAGE ].setFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_DURATION ].addr                     = &FTDF_pib.maxFrameDuration,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_DURATION ].size                     = 0,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_DURATION ].getFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_MAX_FRAME_DURATION ].setFunc                  = NULL,
    .attributeDefs[ FTDF_PIB_SHR_DURATION ].addr                           = &FTDF_pib.SHRDuration,
    .attributeDefs[ FTDF_PIB_SHR_DURATION ].size                           = 0,
    .attributeDefs[ FTDF_PIB_SHR_DURATION ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_SHR_DURATION ].setFunc                        = NULL,
#endif /* !FTDF_LITE */
    .attributeDefs[ FTDF_PIB_TRAFFIC_COUNTERS ].addr                       = &FTDF_pib.trafficCounters,
    .attributeDefs[ FTDF_PIB_TRAFFIC_COUNTERS ].size                       = 0,
    .attributeDefs[ FTDF_PIB_TRAFFIC_COUNTERS ].getFunc                    = FTDF_getLmacTrafficCounters,
    .attributeDefs[ FTDF_PIB_TRAFFIC_COUNTERS ].setFunc                    = NULL,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_LE_CAPABLE ].addr                             = &FTDF_pib.LECapable,
    .attributeDefs[ FTDF_PIB_LE_CAPABLE ].size                             = 0,
    .attributeDefs[ FTDF_PIB_LE_CAPABLE ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_LE_CAPABLE ].setFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_LL_CAPABLE ].addr                             = &FTDF_pib.LLCapable,
    .attributeDefs[ FTDF_PIB_LL_CAPABLE ].size                             = 0,
    .attributeDefs[ FTDF_PIB_LL_CAPABLE ].getFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_LL_CAPABLE ].setFunc                          = NULL,
    .attributeDefs[ FTDF_PIB_DSME_CAPABLE ].addr                           = &FTDF_pib.DSMECapable,
    .attributeDefs[ FTDF_PIB_DSME_CAPABLE ].size                           = 0,
    .attributeDefs[ FTDF_PIB_DSME_CAPABLE ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_DSME_CAPABLE ].setFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_RFID_CAPABLE ].addr                           = &FTDF_pib.RFIDCapable,
    .attributeDefs[ FTDF_PIB_RFID_CAPABLE ].size                           = 0,
    .attributeDefs[ FTDF_PIB_RFID_CAPABLE ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_RFID_CAPABLE ].setFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_AMCA_CAPABLE ].addr                           = &FTDF_pib.AMCACapable,
    .attributeDefs[ FTDF_PIB_AMCA_CAPABLE ].size                           = 0,
    .attributeDefs[ FTDF_PIB_AMCA_CAPABLE ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_AMCA_CAPABLE ].setFunc                        = NULL,
#endif /* !FTDF_LITE */
    .attributeDefs[ FTDF_PIB_METRICS_CAPABLE ].addr                        = &FTDF_pib.metricsCapable,
    .attributeDefs[ FTDF_PIB_METRICS_CAPABLE ].size                        = 0,
    .attributeDefs[ FTDF_PIB_METRICS_CAPABLE ].getFunc                     = NULL,
    .attributeDefs[ FTDF_PIB_METRICS_CAPABLE ].setFunc                     = NULL,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_RANGING_SUPPORTED ].addr                      = &FTDF_pib.rangingSupported,
    .attributeDefs[ FTDF_PIB_RANGING_SUPPORTED ].size                      = 0,
    .attributeDefs[ FTDF_PIB_RANGING_SUPPORTED ].getFunc                   = NULL,
    .attributeDefs[ FTDF_PIB_RANGING_SUPPORTED ].setFunc                   = NULL,
#endif /* !FTDF_LITE */
    .attributeDefs[ FTDF_PIB_KEEP_PHY_ENABLED ].addr                       = &FTDF_pib.keepPhyEnabled,
    .attributeDefs[ FTDF_PIB_KEEP_PHY_ENABLED ].size                       = sizeof(FTDF_pib.keepPhyEnabled),
    .attributeDefs[ FTDF_PIB_KEEP_PHY_ENABLED ].getFunc                    = FTDF_getKeepPhyEnabled,
    .attributeDefs[ FTDF_PIB_KEEP_PHY_ENABLED ].setFunc                    = FTDF_setKeepPhyEnabled,
    .attributeDefs[ FTDF_PIB_METRICS_ENABLED ].addr                        = &FTDF_pib.metricsEnabled,
    .attributeDefs[ FTDF_PIB_METRICS_ENABLED ].size                        = sizeof(FTDF_pib.metricsEnabled),
    .attributeDefs[ FTDF_PIB_METRICS_ENABLED ].getFunc                     = NULL,
    .attributeDefs[ FTDF_PIB_METRICS_ENABLED ].setFunc                     = NULL,
#ifndef FTDF_LITE
    .attributeDefs[ FTDF_PIB_BEACON_AUTO_RESPOND ].addr                    = &FTDF_pib.beaconAutoRespond,
    .attributeDefs[ FTDF_PIB_BEACON_AUTO_RESPOND ].size                    = sizeof(FTDF_pib.beaconAutoRespond),
    .attributeDefs[ FTDF_PIB_BEACON_AUTO_RESPOND ].getFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_BEACON_AUTO_RESPOND ].setFunc                 = NULL,
    .attributeDefs[ FTDF_PIB_TSCH_CAPABLE ].addr                           = &FTDF_pib.tschCapable,
    .attributeDefs[ FTDF_PIB_TSCH_CAPABLE ].size                           = 0,
    .attributeDefs[ FTDF_PIB_TSCH_CAPABLE ].getFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_TSCH_CAPABLE ].setFunc                        = NULL,
    .attributeDefs[ FTDF_PIB_TS_SYNC_CORRECT_THRESHOLD ].addr              = &FTDF_pib.tsSyncCorrectThreshold,
    .attributeDefs[ FTDF_PIB_TS_SYNC_CORRECT_THRESHOLD ].size              = sizeof(FTDF_pib.tsSyncCorrectThreshold),
    .attributeDefs[ FTDF_PIB_TS_SYNC_CORRECT_THRESHOLD ].getFunc           = NULL,
    .attributeDefs[ FTDF_PIB_TS_SYNC_CORRECT_THRESHOLD ].setFunc           = NULL
#endif /* !FTDF_LITE */
};

FTDF_Boolean        FTDF_transparentMode                              __attribute__((section(".retention")));
FTDF_Bitmap32       FTDF_transparentModeOptions                       __attribute__((section(".retention")));
#if FTDF_DBG_BUS_ENABLE
FTDF_DbgMode        FTDF_dbgMode                                      __attribute__((section(".retention")));
#endif
#ifndef FTDF_LITE
FTDF_Buffer         FTDF_reqBuffers[ FTDF_NR_OF_REQ_BUFFERS ]         __attribute__((section(".retention")));
FTDF_Queue          FTDF_reqQueue                                     __attribute__((section(".retention")));
FTDF_Queue          FTDF_freeQueue                                    __attribute__((section(".retention")));
FTDF_Pending        FTDF_txPendingList[ FTDF_NR_OF_REQ_BUFFERS ]      __attribute__((section(".retention")));
FTDF_PendingTL      FTDF_txPendingTimerList[ FTDF_NR_OF_REQ_BUFFERS ] __attribute__((section(".retention")));
FTDF_PendingTL     *FTDF_txPendingTimerHead                           __attribute__((section(".retention")));
FTDF_Time           FTDF_txPendingTimerLT                             __attribute__((section(".retention")));
FTDF_Time           FTDF_txPendingTimerTime                           __attribute__((section(".retention")));
#endif /* !FTDF_LITE */
#ifndef FTDF_PHY_API
FTDF_MsgBuffer     *FTDF_reqCurrent                                   __attribute__((section(".retention")));
#endif
FTDF_Size           FTDF_nrOfRetries                                  __attribute__((section(".retention")));
#ifndef FTDF_LITE
FTDF_Boolean        FTDF_isPANCoordinator                             __attribute__((section(".retention")));
FTDF_Time           FTDF_startCslSampleTime                           __attribute__((section(".retention")));
FTDF_RxAddressAdmin FTDF_rxa[ FTDF_NR_OF_RX_ADDRS ]                   __attribute__((section(".retention")));
#endif /* !FTDF_LITE */
FTDF_Boolean        FTDF_txInProgress                                 __attribute__((section(".retention")));
#ifndef FTDF_LITE
#ifndef FTDF_NO_CSL
FTDF_PeerCslTiming  FTDF_peerCslTiming[ FTDF_NR_OF_CSL_PEERS ]        __attribute__((section(".retention")));
FTDF_Boolean        FTDF_oldLeEnabled                                 __attribute__((section(".retention")));
FTDF_Time           FTDF_rzTime                                       __attribute__((section(".retention")));
FTDF_ShortAddress   FTDF_sendFramePending                             __attribute__((section(".retention")));
#endif /* FTDF_NO_CSL */
#endif /* !FTDF_LITE */
uint32_t            FTDF_curTime[ 2 ]                                 __attribute__((section(".retention")));
FTDF_LmacCounters   FTDF_lmacCounters                                 __attribute__((section(".retention")));
FTDF_FrameHeader    FTDF_fh;
#ifndef FTDF_LITE
FTDF_SecurityHeader FTDF_sh;
FTDF_AssocAdmin     FTDF_aa;
#endif /* !FTDF_LITE */

#if dg_configCOEX_ENABLE_CONFIG
/* Packet traffic information used when FTDF is in RX enable. */
static FTDF_PTI  FTDF_RxPti __attribute__((section(".retention")));
#endif
static void sendConfirm(FTDF_Status status,
                        FTDF_MsgId  msgId);

void FTDF_reset(int setDefaultPIB)
{
    if (setDefaultPIB)
    {
        // Reset PIB values to their default values
        memset(&FTDF_pib, 0, sizeof(FTDF_pib));

        FTDF_pib.extAddress                        = FTDF_GET_EXT_ADDRESS();
        FTDF_pib.ackWaitDuration                   = 0x36;
#ifndef FTDF_LITE
        FTDF_pib.autoRequest                       = FTDF_TRUE;
        FTDF_pib.beaconOrder                       = 15;
        FTDF_pib.DSN                               = FTDF_pib.extAddress & 0xff;
        FTDF_pib.BSN                               = FTDF_pib.extAddress & 0xff;
        FTDF_pib.EBSN                              = FTDF_pib.extAddress & 0xff;
        FTDF_pib.coordShortAddress                 = 0xffff;
#endif /* !FTDF_LITE */
        FTDF_pib.maxBE                             = 5;
        FTDF_pib.maxCSMABackoffs                   = 4;
        FTDF_pib.maxFrameTotalWaitTime             = 1026; // see asic_vol v40.100.2.30 PR2540
        FTDF_pib.maxFrameRetries                   = 3;
        FTDF_pib.minBE                             = 3;
#ifndef FTDF_LITE
        FTDF_pib.LIFSPeriod                        = 40;
        FTDF_pib.SIFSPeriod                        = 12;
#endif /* !FTDF_LITE */
        FTDF_pib.PANId                             = 0xffff;
#ifndef FTDF_LITE
        FTDF_pib.responseWaitTime                  = 32;
#endif /* !FTDF_LITE */
        FTDF_pib.shortAddress                      = 0xffff;
#ifndef FTDF_LITE
        FTDF_pib.superframeOrder                   = 15;
        FTDF_pib.timestampSupported                = FTDF_TRUE;
        FTDF_pib.transactionPersistenceTime        = 0x1f4;
        FTDF_pib.enhAckWaitDuration                = 0x360;
        FTDF_pib.EBAutoSA                          = FTDF_AUTO_FULL;
#endif /* !FTDF_LITE */
        FTDF_pib.currentChannel                    = 11;
        FTDF_pib.CCAMode                           = FTDF_CCA_MODE_1;
#ifndef FTDF_LITE
        FTDF_pib.maxFrameDuration                  = FTDF_TBD;
        FTDF_pib.SHRDuration                       = FTDF_TBD;
        FTDF_pib.frameCounterMode                  = 4;
#endif /* !FTDF_LITE */
        FTDF_pib.metricsCapable                    = FTDF_TRUE;
#ifndef FTDF_LITE
        FTDF_pib.beaconAutoRespond                 = FTDF_TRUE;
#endif /* !FTDF_LITE */
        FTDF_pib.performanceMetrics.counterOctets  = 4; // 32 bit counters
#ifndef FTDF_LITE
        FTDF_pib.joinPriority                      = 1;
        FTDF_pib.slotframeTable.slotframeEntries   = FTDF_slotframeTable;
        FTDF_pib.linkTable.linkEntries             = FTDF_linkTable;
        FTDF_pib.timeslotTemplate.tsCCAOffset      = 1800;
        FTDF_pib.timeslotTemplate.tsCCA            = 128;
        FTDF_pib.timeslotTemplate.tsTxOffset       = 2120;
        FTDF_pib.timeslotTemplate.tsRxOffset       = 1020;
        FTDF_pib.timeslotTemplate.tsRxAckDelay     = 800;
        FTDF_pib.timeslotTemplate.tsTxAckDelay     = 1000;
        FTDF_pib.timeslotTemplate.tsRxWait         = 2200;
        FTDF_pib.timeslotTemplate.tsAckWait        = 400;
        FTDF_pib.timeslotTemplate.tsRxTx           = 192;
        FTDF_pib.timeslotTemplate.tsMaxAck         = 2400;
        FTDF_pib.timeslotTemplate.tsMaxTs          = 4256;
        FTDF_pib.timeslotTemplate.tsTimeslotLength = 10000;
        FTDF_pib.tsSyncCorrectThreshold            = 220;
        FTDF_pib.hoppingSequenceLength             = 16;
#ifdef FTDF_NO_CSL
        FTDF_pib.LECapable                         = FTDF_FALSE;
#else
        FTDF_pib.LECapable                         = FTDF_TRUE;
#endif /* FTDF_NO_CSL */
#ifdef FTDF_NO_TSCH
        FTDF_pib.tschCapable                       = FTDF_FALSE;
#else
        FTDF_pib.tschCapable                       = FTDF_TRUE;
#endif /* FTDF_NO_TSCH */

        int n;

        for (n = 0; n < FTDF_MAX_HOPPING_SEQUENCE_LENGTH; n++)
        {
            FTDF_pib.hoppingSequenceList[ n ] = n + 11;
        }

#endif /* !FTDF_LITE */

        FTDF_transparentMode  = FTDF_FALSE;
#ifndef FTDF_LITE
        FTDF_isPANCoordinator = FTDF_FALSE;
#endif /* !FTDF_LITE */
        FTDF_lmacCounters.fcsErrorCnt = 0;
        FTDF_lmacCounters.txStdAckCnt = 0;
        FTDF_lmacCounters.rxStdAckCnt = 0;

#ifndef FTDF_LITE
        memset(FTDF_pib.defaultKeySource, 0xff, 8);
#endif /* !FTDF_LITE */
    }

    FTDF_initQueues();

    volatile uint32_t *lmacReset = FTDF_GET_REG_ADDR(ON_OFF_REGMAP_LMACRESET);
    *lmacReset = MSK_R_FTDF_ON_OFF_REGMAP_LMACRESET;

    volatile uint32_t *controlStatus = FTDF_GET_REG_ADDR(ON_OFF_REGMAP_LMAC_CONTROL_STATUS);
    uint32_t           wait          = 0;

    while ((*controlStatus & MSK_F_FTDF_ON_OFF_REGMAP_LMACREADY4SLEEP) == 0)
    {
        wait++;
    }

    volatile uint32_t *wakeupTimerEnableStatus = FTDF_GET_FIELD_ADDR(ON_OFF_REGMAP_WAKEUPTIMERENABLESTATUS);

    FTDF_SET_FIELD(ALWAYS_ON_REGMAP_WAKEUPTIMERENABLE, 0);

    while (*wakeupTimerEnableStatus & MSK_F_FTDF_ON_OFF_REGMAP_WAKEUPTIMERENABLESTATUS)
    { }

    FTDF_SET_FIELD(ALWAYS_ON_REGMAP_WAKEUPTIMERENABLE, 1);

    while ((*wakeupTimerEnableStatus & MSK_F_FTDF_ON_OFF_REGMAP_WAKEUPTIMERENABLESTATUS) == 0)
    { }

#ifndef FTDF_LITE
    int n;

#ifndef FTDF_NO_CSL

    for (n = 0; n < FTDF_NR_OF_CSL_PEERS; n++)
    {
        FTDF_peerCslTiming[ n ].addr = 0xffff;
    }

    FTDF_oldLeEnabled     = FTDF_FALSE;
    FTDF_wakeUpEnableLe   = FTDF_FALSE;
    FTDF_sendFramePending = 0xfffe;
#endif /* FTDF_NO_CSL */
#endif /* !FTDF_LITE */
    FTDF_txInProgress     = FTDF_FALSE;

    FTDF_initCurTime64();
#ifndef FTDF_NO_TSCH
    FTDF_initTschRetries();
    FTDF_initBackoff();
#endif /* FTDF_NO_TSCH */

#ifndef FTDF_LITE

    for (n = 0; n < FTDF_NR_OF_RX_ADDRS; n++)
    {
        FTDF_rxa[ n ].addrMode  = FTDF_NO_ADDRESS;
        FTDF_rxa[ n ].dsnValid  = FTDF_FALSE;
        FTDF_rxa[ n ].bsnValid  = FTDF_FALSE;
        FTDF_rxa[ n ].ebsnValid = FTDF_FALSE;
    }

#ifndef FTDF_NO_TSCH

    for (n = 0; n < FTDF_NR_OF_NEIGHBORS; n++)
    {
        FTDF_neighborTable[ n ].dstAddr = 0xffff;
    }

#endif /* FTDF_NO_TSCH */
#endif /* !FTDF_LITE */
    FTDF_initLmac();

#ifndef FTDF_NO_CSL
    FTDF_rzTime = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);
#endif /* FTDF_NO_CSL */
#if dg_configCOEX_ENABLE_CONFIG
    FTDF_RxPti = 0;
#endif
}

#ifndef FTDF_PHY_API
void FTDF_processResetRequest(FTDF_ResetRequest *resetRequest)
{

    FTDF_reset(resetRequest->setDefaultPIB);
    FTDF_ResetConfirm *resetConfirm = (FTDF_ResetConfirm *) FTDF_GET_MSG_BUFFER(sizeof(FTDF_ResetConfirm));

    resetConfirm->msgId  = FTDF_RESET_CONFIRM;
    resetConfirm->status = FTDF_SUCCESS;

    FTDF_REL_MSG_BUFFER((FTDF_MsgBuffer *) resetRequest);

    FTDF_RCV_MSG((FTDF_MsgBuffer *) resetConfirm);
}
#endif /* FTDF_PHY_API */

void FTDF_initLmac(void)
{
    FTDF_PIBAttribute PIBAttribute;

    for (PIBAttribute = 1; PIBAttribute <= FTDF_NR_OF_PIB_ATTRIBUTES; PIBAttribute++)
    {
        if (pibAttributeTable.attributeDefs[ PIBAttribute ].setFunc != NULL)
        {
            pibAttributeTable.attributeDefs[ PIBAttribute ].setFunc();
        }
    }

    if (FTDF_transparentMode == FTDF_TRUE)
    {
        FTDF_enableTransparentMode(FTDF_TRUE, FTDF_transparentModeOptions);
    }

#ifndef FTDF_LITE

    if (FTDF_isPANCoordinator)
    {
        FTDF_SET_FIELD(ON_OFF_REGMAP_ISPANCOORDINATOR, 1);
    }

#endif /* !FTDF_LITE */
    FTDF_SET_FIELD(ON_OFF_REGMAP_CCAIDLEWAIT, 192);

    volatile uint32_t *txFlagClear = FTDF_GET_FIELD_ADDR(ON_OFF_REGMAP_TX_FLAG_CLEAR);
    *txFlagClear = MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_CLEAR;

    volatile uint32_t *phyParams = FTDF_GET_REG_ADDR(ON_OFF_REGMAP_PHY_PARAMETERS_2);
    *phyParams = (FTDF_PHYTXSTARTUP << OFF_F_FTDF_ON_OFF_REGMAP_PHYTXSTARTUP) |
                 (FTDF_PHYTXLATENCY << OFF_F_FTDF_ON_OFF_REGMAP_PHYTXLATENCY) |
                 (FTDF_PHYTXFINISH << OFF_F_FTDF_ON_OFF_REGMAP_PHYTXFINISH) |
                 (FTDF_PHYTRXWAIT << OFF_F_FTDF_ON_OFF_REGMAP_PHYTRXWAIT);

    phyParams = FTDF_GET_REG_ADDR(ON_OFF_REGMAP_PHY_PARAMETERS_3);
    *phyParams = (FTDF_PHYRXSTARTUP << OFF_F_FTDF_ON_OFF_REGMAP_PHYRXSTARTUP) |
                 (FTDF_PHYRXLATENCY << OFF_F_FTDF_ON_OFF_REGMAP_PHYRXLATENCY) |
                 (FTDF_PHYENABLE << OFF_F_FTDF_ON_OFF_REGMAP_PHYENABLE);

    volatile uint32_t *ftdfCm = FTDF_GET_REG_ADDR(ON_OFF_REGMAP_FTDF_CM);
    *ftdfCm = FTDF_MSK_TX_CE | FTDF_MSK_RX_CE | FTDF_MSK_SYMBOL_TMR_CE;

    volatile uint32_t *rxMask = FTDF_GET_REG_ADDR(ON_OFF_REGMAP_RX_MASK);
    *rxMask = MSK_R_FTDF_ON_OFF_REGMAP_RX_MASK;

    volatile uint32_t *lmacMask = FTDF_GET_REG_ADDR(ON_OFF_REGMAP_LMAC_MASK);
    *lmacMask = MSK_F_FTDF_ON_OFF_REGMAP_RXTIMEREXPIRED_M;

    volatile uint32_t *lmacCtrlMask = FTDF_GET_REG_ADDR(ON_OFF_REGMAP_LMAC_CONTROL_MASK);
    *lmacCtrlMask = MSK_F_FTDF_ON_OFF_REGMAP_SYMBOLTIMETHR_M |
                    MSK_F_FTDF_ON_OFF_REGMAP_SYMBOLTIME2THR_M |
                    MSK_F_FTDF_ON_OFF_REGMAP_SYNCTIMESTAMP_M;

    volatile uint32_t *txFlagClearM;
    txFlagClearM   = FTDF_GET_FIELD_ADDR_INDEXED(ON_OFF_REGMAP_TX_FLAG_CLEAR_M, FTDF_TX_DATA_BUFFER);
    *txFlagClearM |= MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_CLEAR_M;
    txFlagClearM   = FTDF_GET_FIELD_ADDR_INDEXED(ON_OFF_REGMAP_TX_FLAG_CLEAR_M, FTDF_TX_WAKEUP_BUFFER);
    *txFlagClearM |= MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_CLEAR_M;
}

#ifdef FTDF_PHY_API
FTDF_PIBAttributeValue *FTDF_getValue(FTDF_PIBAttribute PIBAttribute)
{

    if (PIBAttribute <= FTDF_NR_OF_PIB_ATTRIBUTES &&
        pibAttributeTable.attributeDefs[ PIBAttribute ].addr != NULL)
    {
        // Update PIB attribute with current LMAC status if a getFunc is defined
        if (pibAttributeTable.attributeDefs[ PIBAttribute ].getFunc != NULL)
        {
            pibAttributeTable.attributeDefs[ PIBAttribute ].getFunc();
        }

        return pibAttributeTable.attributeDefs[ PIBAttribute ].addr;
    }

    return NULL;
}

FTDF_Status FTDF_setValue(FTDF_PIBAttribute PIBAttribute, const FTDF_PIBAttributeValue *PIBAttributeValue)
{
    if (PIBAttribute <= FTDF_NR_OF_PIB_ATTRIBUTES &&
        pibAttributeTable.attributeDefs[ PIBAttribute ].addr != NULL)
    {
        if (pibAttributeTable.attributeDefs[ PIBAttribute ].size != 0)
        {
            memcpy(pibAttributeTable.attributeDefs[ PIBAttribute ].addr,
                   PIBAttributeValue,
                   pibAttributeTable.attributeDefs[ PIBAttribute ].size);

            // Update LMAC with new PIB attribute value if a setFunc is defined
            if (pibAttributeTable.attributeDefs[ PIBAttribute ].setFunc != NULL)
            {
                pibAttributeTable.attributeDefs[ PIBAttribute ].setFunc();
            }

            return FTDF_SUCCESS;

        }
        else
        {
            return FTDF_READ_ONLY;
        }
    }

    return FTDF_UNSUPPORTED_ATTRIBUTE;
}

#else /* FTDF_PHY_API */
void FTDF_processGetRequest(FTDF_GetRequest *getRequest)
{
    FTDF_GetConfirm  *getConfirm   = (FTDF_GetConfirm *) FTDF_GET_MSG_BUFFER(sizeof(FTDF_GetConfirm));
    FTDF_PIBAttribute PIBAttribute = getRequest->PIBAttribute;

    getConfirm->msgId        = FTDF_GET_CONFIRM;
    getConfirm->PIBAttribute = PIBAttribute;

    if (PIBAttribute <= FTDF_NR_OF_PIB_ATTRIBUTES &&
        pibAttributeTable.attributeDefs[ PIBAttribute ].addr != NULL)
    {
        // Update PIB attribute with current LMAC status if a getFunc is defined
        if (pibAttributeTable.attributeDefs[ PIBAttribute ].getFunc != NULL)
        {
            pibAttributeTable.attributeDefs[ PIBAttribute ].getFunc();
        }

        getConfirm->status            = FTDF_SUCCESS;
        getConfirm->PIBAttributeValue = pibAttributeTable.attributeDefs[ PIBAttribute ].addr;
    }
    else
    {
        getConfirm->status = FTDF_UNSUPPORTED_ATTRIBUTE;
    }

    FTDF_REL_MSG_BUFFER((FTDF_MsgBuffer *) getRequest);

    FTDF_RCV_MSG((FTDF_MsgBuffer *) getConfirm);
}

void FTDF_processSetRequest(FTDF_SetRequest *setRequest)
{
    FTDF_SetConfirm  *setConfirm   = (FTDF_SetConfirm *) FTDF_GET_MSG_BUFFER(sizeof(FTDF_SetConfirm));
    FTDF_PIBAttribute PIBAttribute = setRequest->PIBAttribute;

    setConfirm->msgId        = FTDF_SET_CONFIRM;
    setConfirm->PIBAttribute = PIBAttribute;

    if (PIBAttribute <= FTDF_NR_OF_PIB_ATTRIBUTES &&
        pibAttributeTable.attributeDefs[ PIBAttribute ].addr != NULL)
    {
        if (pibAttributeTable.attributeDefs[ PIBAttribute ].size != 0)
        {
            setConfirm->status = FTDF_SUCCESS;
            memcpy(pibAttributeTable.attributeDefs[ PIBAttribute ].addr,
                   setRequest->PIBAttributeValue,
                   pibAttributeTable.attributeDefs[ PIBAttribute ].size);

            // Update LMAC with new PIB attribute value if a setFunc is defined
            if (pibAttributeTable.attributeDefs[ PIBAttribute ].setFunc != NULL)
            {
                pibAttributeTable.attributeDefs[ PIBAttribute ].setFunc();
            }
        }
        else
        {
            setConfirm->status = FTDF_READ_ONLY;
        }
    }
    else
    {
        setConfirm->status = FTDF_UNSUPPORTED_ATTRIBUTE;
    }

    FTDF_REL_MSG_BUFFER((FTDF_MsgBuffer *) setRequest);

    FTDF_RCV_MSG((FTDF_MsgBuffer *) setConfirm);
}


void FTDF_sendCommStatusIndication(FTDF_MsgBuffer     *request,
                                   FTDF_Status         status,
                                   FTDF_PANId          PANId,
                                   FTDF_AddressMode    srcAddrMode,
                                   FTDF_Address        srcAddr,
                                   FTDF_AddressMode    dstAddrMode,
                                   FTDF_Address        dstAddr,
                                   FTDF_SecurityLevel  securityLevel,
                                   FTDF_KeyIdMode      keyIdMode,
                                   FTDF_Octet         *keySource,
                                   FTDF_KeyIndex       keyIndex)
{
    FTDF_CommStatusIndication *commStatus =
        (FTDF_CommStatusIndication *) FTDF_GET_MSG_BUFFER(sizeof(FTDF_CommStatusIndication));

    commStatus->msgId         = FTDF_COMM_STATUS_INDICATION;
    commStatus->PANId         = PANId;
    commStatus->srcAddrMode   = srcAddrMode;
    commStatus->srcAddr       = srcAddr;
    commStatus->dstAddrMode   = dstAddrMode;
    commStatus->dstAddr       = dstAddr;
    commStatus->status        = status;
    commStatus->securityLevel = securityLevel;
    commStatus->keyIdMode     = keyIdMode;
    commStatus->keyIndex      = keyIndex;

    uint8_t n;

    if (securityLevel != 0)
    {
        if (keyIdMode == 0x2)
        {
            for (n = 0; n < 4; n++)
            {
                commStatus->keySource[ n ] = keySource[ n ];
            }
        }
        else if (keyIdMode == 0x3)
        {
            for (n = 0; n < 8; n++)
            {
                commStatus->keySource[ n ] = keySource[ n ];
            }
        }
    }

#ifndef FTDF_LITE

    if (request &&
        (request->msgId == FTDF_ORPHAN_RESPONSE ||
         request->msgId == FTDF_ASSOCIATE_RESPONSE))
    {
        if (FTDF_reqCurrent == request)
        {
            FTDF_reqCurrent = NULL;
        }

        FTDF_REL_MSG_BUFFER(request);
        FTDF_RCV_MSG((FTDF_MsgBuffer *) commStatus);

        FTDF_processNextRequest();
        return;
    }

#endif /* !FTDF_LITE */
    FTDF_RCV_MSG((FTDF_MsgBuffer *) commStatus);
}
#endif /* FTDF_PHY_API */

#ifndef FTDF_LITE
FTDF_Octet *FTDF_addFrameHeader(FTDF_Octet       *txPtr,
                                FTDF_FrameHeader *frameHeader,
                                FTDF_DataLength   msduLength)
{
    uint8_t          frameVersion;
    uint8_t          longFrameControl = 0x00;
    FTDF_Boolean     panIdCompression = FTDF_FALSE;
    FTDF_Bitmap8     options          = frameHeader->options;
    FTDF_Boolean     secure           = options & FTDF_OPT_SECURITY_ENABLED;
    FTDF_Boolean     framePending     = options & FTDF_OPT_FRAME_PENDING;
    FTDF_Boolean     ackTX            = options & FTDF_OPT_ACK_REQUESTED;
    FTDF_Boolean     panIdPresent     = options & FTDF_OPT_PAN_ID_PRESENT;
    FTDF_Boolean     seqNrSuppressed  = options & FTDF_OPT_SEQ_NR_SUPPRESSED;
    FTDF_Boolean     iesIncluded      = options & FTDF_OPT_IES_PRESENT;
    FTDF_FrameType   frameType        = frameHeader->frameType;
    FTDF_AddressMode dstAddrMode      = frameHeader->dstAddrMode;
    FTDF_AddressMode srcAddrMode      = frameHeader->srcAddrMode;
    FTDF_PANId       dstPANId         = frameHeader->dstPANId;

    if (frameType == FTDF_MULTIPURPOSE_FRAME)
    {
        if (options & (FTDF_OPT_SECURITY_ENABLED | FTDF_OPT_ACK_REQUESTED | FTDF_OPT_PAN_ID_PRESENT |
                       FTDF_OPT_IES_PRESENT | FTDF_OPT_SEQ_NR_SUPPRESSED | FTDF_OPT_FRAME_PENDING))
        {
            longFrameControl = 0x08;
        }

        // Frame control field byte 1
        *txPtr++ = 0x05 | longFrameControl | dstAddrMode << 4 | srcAddrMode << 6;

        if (longFrameControl)
        {
            // Frame control field byte 2
            *txPtr++ =
                (panIdPresent ? 0x01 : 0x00) |
                (secure ? 0x02 : 0x00) |
                (seqNrSuppressed ? 0x04 : 0x00) |
                (framePending ? 0x08 : 0x00) |
                (ackTX ? 0x40 : 0x00) |
                (iesIncluded ? 0x80 : 0x00);
        }
    }
    else
    {
        //        if ( panIdPresent || iesIncluded || seqNrSuppressed || ( options & FTDF_OPT_ENHANCED ) || FTDF_pib.tschEnabled )
        if (panIdPresent || iesIncluded || seqNrSuppressed || (options & FTDF_OPT_ENHANCED))
        {
            frameVersion = 0x02; // 0b10;
        }
        else
        {
            if (secure ||
                msduLength > FTDF_MAX_MAC_SAFE_PAYLOAD_SIZE)
            {
                frameVersion = 0x01; // 0b01;
            }
            else
            {
                frameVersion = 0x00; // 0b00;
            }
        }

        if (frameVersion < 0x02)   //0b10 )
        {
            if (dstAddrMode != FTDF_NO_ADDRESS &&
                srcAddrMode != FTDF_NO_ADDRESS &&
                dstPANId == frameHeader->srcPANId)
            {
                panIdCompression = FTDF_TRUE;
            }
        }
        else
        {
            panIdCompression = panIdPresent;
        }

        // Frame control field byte 1
        *txPtr++ =
            (frameType & 0x7) |
            (secure ? 0x08 : 0x00) |
            (framePending ? 0x10 : 0x00) |
            (ackTX ? 0x20 : 0x00) |
            (panIdCompression ? 0x40 : 0x00);

        // Frame control field byte 2
        *txPtr++ =
            (seqNrSuppressed ? 0x01 : 0x00) |
            (iesIncluded ? 0x02 : 0x00) |
            dstAddrMode << 2 |
            frameVersion << 4 |
            srcAddrMode << 6;
    }

    if (!seqNrSuppressed)
    {
        *txPtr++ = frameHeader->SN;
    }

    FTDF_Boolean addDstPANId = FTDF_FALSE;

    if (frameType == FTDF_MULTIPURPOSE_FRAME)
    {
        if (panIdPresent)
        {
            addDstPANId = FTDF_TRUE;
        }
    }
    else
    {
        if (frameVersion < 0x02)   //0b10 )
        {
            if (dstAddrMode != FTDF_NO_ADDRESS)
            {
                addDstPANId = FTDF_TRUE;
            }
        }
        else
        {
            // See Table 2a "PAN ID Compression" of IEEE 802.15.4-2011 for more details
            if ((srcAddrMode == FTDF_NO_ADDRESS && dstAddrMode == FTDF_NO_ADDRESS && panIdCompression) ||
                (srcAddrMode == FTDF_NO_ADDRESS && dstAddrMode != FTDF_NO_ADDRESS && !panIdCompression) ||
                (srcAddrMode != FTDF_NO_ADDRESS && dstAddrMode != FTDF_NO_ADDRESS && !panIdCompression))
            {
                addDstPANId = FTDF_TRUE;
            }
        }
    }

    if (addDstPANId)
    {
        FTDF_Octet *PANIdPtr = (FTDF_Octet *)&dstPANId;

        *txPtr++ = *PANIdPtr++;
        *txPtr++ = *PANIdPtr;
    }

    FTDF_Address dstAddr = frameHeader->dstAddr;

    if (dstAddrMode == FTDF_SIMPLE_ADDRESS)
    {
        *txPtr++ = dstAddr.simpleAddress;
    }
    else if (dstAddrMode == FTDF_SHORT_ADDRESS)
    {
        FTDF_Octet *shortAddressPtr = (FTDF_Octet *)&dstAddr.shortAddress;

        *txPtr++ = *shortAddressPtr++;
        *txPtr++ = *shortAddressPtr;
    }
    else if (dstAddrMode == FTDF_EXTENDED_ADDRESS)
    {
        FTDF_Octet *extAddressPtr = (FTDF_Octet *)&dstAddr.extAddress;
        int         n;

        for (n = 0; n < 8; n++)
        {
            *txPtr++ = *extAddressPtr++;
        }
    }

    FTDF_Boolean addSrcPANId = FTDF_FALSE;

    if (frameType != FTDF_MULTIPURPOSE_FRAME)
    {
        if (frameVersion < 0x02)  // 0b10 )
        {
            if (srcAddrMode != FTDF_NO_ADDRESS && !panIdCompression)
            {
                addSrcPANId = FTDF_TRUE;
            }
        }
        else
        {
            // See Table 2a "PAN ID Compression" of IEEE 802.15.4-2011 for more details
            if (srcAddrMode != FTDF_NO_ADDRESS && dstAddrMode == FTDF_NO_ADDRESS && !panIdCompression)
            {
                addSrcPANId = FTDF_TRUE;
            }
        }
    }

    if (addSrcPANId)
    {
        FTDF_Octet *PANIdPtr = (FTDF_Octet *)&frameHeader->srcPANId;

        *txPtr++ = *PANIdPtr++;
        *txPtr++ = *PANIdPtr;
    }

    if (srcAddrMode == FTDF_SIMPLE_ADDRESS)
    {
        *txPtr++ = FTDF_pib.simpleAddress;
    }
    else if (srcAddrMode == FTDF_SHORT_ADDRESS)
    {
        FTDF_Octet *shortAddressPtr = (FTDF_Octet *)&FTDF_pib.shortAddress;

        *txPtr++ = *shortAddressPtr++;
        *txPtr++ = *shortAddressPtr;
    }
    else if (srcAddrMode == FTDF_EXTENDED_ADDRESS)
    {
        FTDF_Octet *extAddressPtr = (FTDF_Octet *)&FTDF_pib.extAddress;
        int         n;

        for (n = 0; n < 8; n++)
        {
            *txPtr++ = *extAddressPtr++;
        }
    }

    return txPtr;
}
#endif /* !FTDF_LITE */

FTDF_PTI FTDF_getRxPti(void)
{
#if dg_configCOEX_ENABLE_CONFIG
    FTDF_PTI rx_pti;
    FTDF_criticalVar();
    FTDF_enterCritical();
    rx_pti = FTDF_RxPti;
    FTDF_exitCritical();
    return rx_pti;
#else
    return 0;
#endif
}

void FTDF_setRxPti(FTDF_PTI rx_pti)
{
#if dg_configCOEX_ENABLE_CONFIG
    FTDF_criticalVar();
    FTDF_enterCritical();
    FTDF_RxPti = rx_pti;
    FTDF_exitCritical();
#endif
}

#ifdef FTDF_PHY_API
void FTDF_rxEnable(FTDF_Time rxOnDuration)
{
#if dg_configCOEX_ENABLE_CONFIG
    /* We do not force decision here. It will be automatically made when FTDF begins
     * transaction.
     */
    hw_coex_update_ftdf_pti((hw_coex_pti_t) FTDF_getRxPti(), NULL, false);
#endif
    FTDF_SET_FIELD(ON_OFF_REGMAP_RXENABLE, 0);
    FTDF_SET_FIELD(ON_OFF_REGMAP_RXONDURATION, rxOnDuration);
    FTDF_SET_FIELD(ON_OFF_REGMAP_RXENABLE, 1);
}
#else
void FTDF_processRxEnableRequest(FTDF_RxEnableRequest *rxEnableRequest)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_RXENABLE, 0);
    FTDF_SET_FIELD(ON_OFF_REGMAP_RXONDURATION, rxEnableRequest->rxOnDuration);
    FTDF_SET_FIELD(ON_OFF_REGMAP_RXENABLE, 1);

    FTDF_RxEnableConfirm *rxEnableConfirm =
        (FTDF_RxEnableConfirm *) FTDF_GET_MSG_BUFFER(sizeof(FTDF_RxEnableConfirm));

    rxEnableConfirm->msgId  = FTDF_RX_ENABLE_CONFIRM;
    rxEnableConfirm->status = FTDF_SUCCESS;

    FTDF_REL_MSG_BUFFER((FTDF_MsgBuffer *) rxEnableRequest);
    FTDF_RCV_MSG((FTDF_MsgBuffer *) rxEnableConfirm);
}
#endif /* FTDF_PHY_API */

FTDF_Octet *FTDF_getFrameHeader(FTDF_Octet       *rxBuffer,
                                FTDF_FrameHeader *frameHeader)
{
    FTDF_FrameType   frameType    = *rxBuffer & 0x07;
    uint8_t          frameVersion = 0; // 0b00;
    FTDF_Bitmap8     options      = 0;
    FTDF_AddressMode dstAddrMode;
    FTDF_AddressMode srcAddrMode;
    FTDF_Boolean     panIdCompression = FTDF_FALSE;
    FTDF_Boolean     panIdPresent     = FTDF_FALSE;

    if (frameType == FTDF_MULTIPURPOSE_FRAME)
    {
        dstAddrMode = (*rxBuffer & 0x30) >> 4;
        srcAddrMode = (*rxBuffer & 0xc0) >> 6;

        // Check Long Frame Control
        if (*rxBuffer & 0x08)
        {
            rxBuffer++;

            panIdPresent = *rxBuffer & 0x01;

            if (*rxBuffer & 0x02)
            {
                options |= FTDF_OPT_SECURITY_ENABLED;
            }

            if (*rxBuffer & 0x04)
            {
                options |= FTDF_OPT_SEQ_NR_SUPPRESSED;
            }

            if (*rxBuffer & 0x08)
            {
                options |= FTDF_OPT_FRAME_PENDING;
            }

            if (*rxBuffer & 0x40)
            {
                options |= FTDF_OPT_ACK_REQUESTED;
            }

            if (*rxBuffer & 0x80)
            {
                options |= FTDF_OPT_IES_PRESENT;
            }

            frameVersion              = 0x00; //0b00;

            frameHeader->frameVersion = FTDF_FRAME_VERSION_E;

            rxBuffer++;
        }
        else
        {
            rxBuffer++;
        }
    }
    else
    {
        if (*rxBuffer & 0x08)
        {
            options |= FTDF_OPT_SECURITY_ENABLED;
        }

        if (*rxBuffer & 0x10)
        {
            options |= FTDF_OPT_FRAME_PENDING;
        }

        if (*rxBuffer & 0x20)
        {
            options |= FTDF_OPT_ACK_REQUESTED;
        }

        panIdCompression = *rxBuffer & 0x40;

        rxBuffer++;

        frameVersion = (*rxBuffer & 0x30) >> 4;

        if (frameVersion == 0x02)   //0b10 )
        {
            if (*rxBuffer & 0x01)
            {
                options |= FTDF_OPT_SEQ_NR_SUPPRESSED;
            }

            if (*rxBuffer & 0x02)
            {
                options |= FTDF_OPT_IES_PRESENT;
            }

            frameHeader->frameVersion = FTDF_FRAME_VERSION_E;
        }
        else if (frameVersion == 0x01)   // 0b01 )
        {
            frameHeader->frameVersion = FTDF_FRAME_VERSION_2011;
        }
        else if (frameVersion == 0x00)   //0b00 )
        {
            frameHeader->frameVersion = FTDF_FRAME_VERSION_2003;
        }
        else
        {
            frameHeader->frameVersion = FTDF_FRAME_VERSION_NOT_SUPPORTED;
            return rxBuffer;
        }

        dstAddrMode = (*rxBuffer & 0x0c) >> 2;
        srcAddrMode = (*rxBuffer & 0xc0) >> 6;

        rxBuffer++;
    }

    if ((options & FTDF_OPT_SEQ_NR_SUPPRESSED) == 0)
    {
        frameHeader->SN = *rxBuffer++;
    }

    FTDF_Boolean hasDstPANId = FTDF_FALSE;

    if (frameType == FTDF_MULTIPURPOSE_FRAME)
    {
        hasDstPANId = panIdPresent;
    }
    else
    {
        if (frameVersion < 0x02)   //0b10 )
        {
            if (dstAddrMode != FTDF_NO_ADDRESS)
            {
                hasDstPANId = FTDF_TRUE;
            }
        }
        else
        {
            if ((srcAddrMode == FTDF_NO_ADDRESS && dstAddrMode == FTDF_NO_ADDRESS && panIdCompression) ||
                (srcAddrMode == FTDF_NO_ADDRESS && dstAddrMode != FTDF_NO_ADDRESS && !panIdCompression) ||
                (srcAddrMode != FTDF_NO_ADDRESS && dstAddrMode != FTDF_NO_ADDRESS && !panIdCompression))
            {
                hasDstPANId = FTDF_TRUE;
            }
        }
    }

    if (hasDstPANId)
    {
        FTDF_Octet *PANIdPtr = (FTDF_Octet *) &frameHeader->dstPANId;

        *PANIdPtr++ = *rxBuffer++;
        *PANIdPtr   = *rxBuffer++;
    }

    if (dstAddrMode == FTDF_SIMPLE_ADDRESS)
    {
        frameHeader->dstAddr.simpleAddress = *rxBuffer++;
    }
    else if (dstAddrMode == FTDF_SHORT_ADDRESS)
    {
        FTDF_Octet *shortAddressPtr = (FTDF_Octet *)&frameHeader->dstAddr.shortAddress;

        *shortAddressPtr++ = *rxBuffer++;
        *shortAddressPtr   = *rxBuffer++;
    }
    else if (dstAddrMode == FTDF_EXTENDED_ADDRESS)
    {
        FTDF_Octet *extAddressPtr = (FTDF_Octet *)&frameHeader->dstAddr.extAddress;
        int         n;

        for (n = 0; n < 8; n++)
        {
            *extAddressPtr++ = *rxBuffer++;
        }
    }

    FTDF_Boolean hasSrcPANId = FTDF_FALSE;

    if (frameVersion < 0x02 && frameType != FTDF_MULTIPURPOSE_FRAME)   //0b10
    {
        if (srcAddrMode != FTDF_NO_ADDRESS && !panIdCompression)
        {
            hasSrcPANId = FTDF_TRUE;
        }
    }
    else
    {
        if (srcAddrMode != FTDF_NO_ADDRESS && dstAddrMode == FTDF_NO_ADDRESS && !panIdCompression)
        {
            hasSrcPANId = FTDF_TRUE;
        }
    }

    if (hasSrcPANId)
    {
        FTDF_Octet *PANIdPtr = (FTDF_Octet *) &frameHeader->srcPANId;

        *PANIdPtr++ = *rxBuffer++;
        *PANIdPtr   = *rxBuffer++;
    }
    else
    {
        frameHeader->srcPANId = frameHeader->dstPANId;
    }

    if (srcAddrMode == FTDF_SIMPLE_ADDRESS)
    {
        frameHeader->srcAddr.simpleAddress = *rxBuffer++;
    }
    else if (srcAddrMode == FTDF_SHORT_ADDRESS)
    {
        FTDF_Octet *shortAddressPtr = (FTDF_Octet *)&frameHeader->srcAddr.shortAddress;

        *shortAddressPtr++ = *rxBuffer++;
        *shortAddressPtr   = *rxBuffer++;
    }
    else if (srcAddrMode == FTDF_EXTENDED_ADDRESS)
    {
        FTDF_Octet *extAddressPtr = (FTDF_Octet *)&frameHeader->srcAddr.extAddress;
        int         n;

        for (n = 0; n < 8; n++)
        {
            *extAddressPtr++ = *rxBuffer++;
        }
    }

    frameHeader->frameType   = frameType;
    frameHeader->options     = options;
    frameHeader->dstAddrMode = dstAddrMode;
    frameHeader->srcAddrMode = srcAddrMode;

    return rxBuffer;
}

#ifndef FTDF_LITE
void FTDF_processNextRequest(void)
{
#ifndef FTDF_NO_TSCH

    if (FTDF_pib.tschEnabled)
    {
        FTDF_MsgBuffer *request = FTDF_tschGetPending(FTDF_tschSlotLink->request);

        FTDF_tschSlotLink->request = NULL;

        FTDF_scheduleTsch(request);

        return;
    }

#endif /* FTDF_NO_TSCH */

    while (FTDF_reqCurrent == NULL)
    {
        FTDF_MsgBuffer *request = FTDF_dequeueReqTail(&FTDF_reqQueue);

        if (request)
        {
            FTDF_processRequest(request);
        }
        else
        {
            break;
        }
    }
}
#endif /* !FTDF_LITE */

static void processRxFrame(int readBuf)
{
    static FTDF_PANDescriptor PANDescriptor;
    static FTDF_Address       pendAddrList[ 7 ];

    FTDF_FrameHeader         *frameHeader    = &FTDF_fh;
#ifndef FTDF_LITE
    FTDF_SecurityHeader      *securityHeader = &FTDF_sh;
#endif /* !FTDF_LITE */

    uint8_t                   pendAddrSpec   = 0;

    FTDF_Octet               *rxBuffer       =
        (FTDF_Octet *)(IND_R_FTDF_RX_RAM_RX_FIFO + (intptr_t) readBuf * FTDF_BUFFER_LENGTH);
    FTDF_Octet               *rxPtr          = rxBuffer;
    FTDF_DataLength           frameLen       = *rxPtr++;

    if (FTDF_transparentMode)
    {
        if (FTDF_pib.metricsEnabled)
        {
            FTDF_pib.performanceMetrics.RXSuccessCount++;
        }

        uint32_t           rxMeta1 = *FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_RX_META_1, (intptr_t)readBuf);
        FTDF_LinkQuality   lqi     = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_QUALITY_INDICATOR, readBuf);
        FTDF_Bitmap32      status  = FTDF_TRANSPARENT_RCV_SUCCESSFUL;

        status |= rxMeta1 & MSK_F_FTDF_RETENTION_RAM_CRC16_ERROR ? FTDF_TRANSPARENT_RCV_CRC_ERROR : 0;
        status |= rxMeta1 & MSK_F_FTDF_RETENTION_RAM_RES_FRM_TYPE_ERROR ? FTDF_TRANSPARENT_RCV_RES_FRAMETYPE : 0;
        status |= rxMeta1 & MSK_F_FTDF_RETENTION_RAM_RES_FRM_VERSION_ERROR ? FTDF_TRANSPARENT_RCV_RES_FRAME_VERSION : 0;
        status |= rxMeta1 & MSK_F_FTDF_RETENTION_RAM_DPANID_ERROR ? FTDF_TRANSPARENT_RCV_UNEXP_DST_PAN_ID : 0;
        status |= rxMeta1 & MSK_F_FTDF_RETENTION_RAM_DADDR_ERROR ? FTDF_TRANSPARENT_RCV_UNEXP_DST_ADDR : 0;

#if FTDF_TRANSPARENT_USE_WAIT_FOR_ACK

        if ((FTDF_transparentModeOptions & FTDF_TRANSPARENT_WAIT_FOR_ACK))
        {
            FTDF_getFrameHeader(rxPtr, frameHeader);

            if (frameHeader->frameType == FTDF_ACKNOWLEDGEMENT_FRAME &&
                (status == FTDF_TRANSPARENT_RCV_SUCCESSFUL))
            {

#ifndef FTDF_PHY_API
                volatile uint32_t *txFlagS = FTDF_GET_REG_ADDR_INDEXED(ON_OFF_REGMAP_TX_FLAG_S, FTDF_TX_DATA_BUFFER);

                while (*txFlagS & MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_STAT)
                { }

                // It is required to call FTDF_processTxEvent here because an RX ack generates two events
                // The RX event is raised first, then after an IFS the TX event is raised. However,
                // the FTDF_processNextRequest requires that both events have been handled.
                FTDF_processTxEvent();
#endif /* !FTDF_PHY_API */

                FTDF_SN SN = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_MACSN, FTDF_TX_DATA_BUFFER);

#ifdef FTDF_PHY_API
                FTDF_criticalVar();
                FTDF_enterCritical();

                if (FTDF_txInProgress &&
                    frameHeader->SN == SN)
                {
                    FTDF_exitCritical();
                    return;
                }

                FTDF_exitCritical();
#else

                if (FTDF_reqCurrent &&
                    frameHeader->SN == SN)
                {
                    FTDF_TransparentRequest *transparentRequest = (FTDF_TransparentRequest *) FTDF_reqCurrent;

                    FTDF_criticalVar();
                    FTDF_enterCritical();
                    FTDF_reqCurrent = NULL;
                    FTDF_exitCritical();
                    FTDF_SEND_FRAME_TRANSPARENT_CONFIRM(transparentRequest->handle, FTDF_TRANSPARENT_SEND_SUCCESSFUL);

                    FTDF_REL_MSG_BUFFER((FTDF_MsgBuffer *) transparentRequest);

                    return;
                }

#endif /* FTDF_PHY_API */
            }
        }

#endif /* FTDF_TRANSPARENT_USE_WAIT_FOR_ACK */
        FTDF_RCV_FRAME_TRANSPARENT(frameLen, rxPtr, status, lqi);

        return;
    }

#ifndef FTDF_LITE
    rxPtr = FTDF_getFrameHeader(rxPtr, frameHeader);

    if (frameHeader->frameVersion == FTDF_FRAME_VERSION_NOT_SUPPORTED)
    {
        return;
    }

#if defined(FTDF_NO_CSL) && defined(FTDF_NO_TSCH)
    else if (frameHeader->frameVersion == FTDF_FRAME_VERSION_E ||
             frameHeader->frameType == FTDF_MULTIPURPOSE_FRAME)
    {
        return;
    }

#endif /* FTDF_NO_CSL && FTDF_NO_TSCH */

    FTDF_FrameType frameType = frameHeader->frameType;
    FTDF_Boolean   duplicate = FTDF_FALSE;

    if ((frameHeader->options & FTDF_OPT_SEQ_NR_SUPPRESSED) == 0 &&
        frameHeader->srcAddrMode != FTDF_NO_ADDRESS)
    {
        FTDF_Time    timestamp = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_RX_TIMESTAMP, readBuf);
        FTDF_SNSel   snSel     = FTDF_SN_SEL_DSN;
        FTDF_Boolean drop;

        if ((FTDF_pib.tschEnabled || frameHeader->frameVersion == FTDF_FRAME_VERSION_E) &&
            (frameHeader->options & FTDF_OPT_ACK_REQUESTED))
        {
            drop = FTDF_FALSE;
        }
        else
        {
            drop = FTDF_TRUE;
        }

        if (frameType == FTDF_BEACON_FRAME)
        {
            snSel = frameHeader->frameVersion == FTDF_FRAME_VERSION_E ? FTDF_SN_SEL_EBSN : FTDF_SN_SEL_BSN;
        }

        uint8_t i;

        for (i = 0; i < FTDF_NR_OF_RX_ADDRS; i++)
        {
            // Check if entry is empty or matches
            if (FTDF_rxa[ i ].addrMode == FTDF_NO_ADDRESS ||
                (FTDF_rxa[ i ].addrMode == frameHeader->srcAddrMode &&
                 ((frameHeader->srcAddrMode == FTDF_SHORT_ADDRESS &&
                   frameHeader->srcAddr.shortAddress == FTDF_rxa[ i ].addr.shortAddress) ||
                  (frameHeader->srcAddrMode == FTDF_EXTENDED_ADDRESS &&
                   frameHeader->srcAddr.extAddress == FTDF_rxa[ i ].addr.extAddress))))
            {
                break;
            }
        }

        if (i < FTDF_NR_OF_RX_ADDRS)
        {
            if (FTDF_rxa[ i ].addrMode != FTDF_NO_ADDRESS)
            {
                switch (snSel)
                {
                case FTDF_SN_SEL_DSN:

                    if (FTDF_rxa[ i ].dsnValid == FTDF_TRUE)
                    {
                        if (frameHeader->SN == FTDF_rxa[ i ].dsn)
                        {
                            if (FTDF_pib.metricsEnabled)
                            {
                                FTDF_pib.performanceMetrics.duplicateFrameCount++;
                            }

                            if (drop)
                            {
                                return;
                            }

                            duplicate = FTDF_TRUE;
                        }
                    }
                    else
                    {
                        FTDF_rxa[ i ].dsnValid = FTDF_TRUE;
                    }

                    FTDF_rxa[ i ].dsn = frameHeader->SN;
                    break;

                case FTDF_SN_SEL_BSN:

                    if (FTDF_rxa[ i ].bsnValid == FTDF_TRUE)
                    {
                        if (frameHeader->SN == FTDF_rxa[ i ].bsn)
                        {
                            if (FTDF_pib.metricsEnabled)
                            {
                                FTDF_pib.performanceMetrics.duplicateFrameCount++;
                            }

                            if (drop)
                            {
                                return;
                            }

                            duplicate = FTDF_TRUE;
                        }
                    }
                    else
                    {
                        FTDF_rxa[ i ].bsnValid = FTDF_TRUE;
                    }

                    FTDF_rxa[ i ].bsn = frameHeader->SN;
                    break;

                case FTDF_SN_SEL_EBSN:

                    if (FTDF_rxa[ i ].ebsnValid == FTDF_TRUE)
                    {
                        if (frameHeader->SN == FTDF_rxa[ i ].ebsn)
                        {
                            if (FTDF_pib.metricsEnabled)
                            {
                                FTDF_pib.performanceMetrics.duplicateFrameCount++;
                            }

                            if (drop)
                            {
                                return;
                            }

                            duplicate = FTDF_TRUE;
                        }
                    }
                    else
                    {
                        FTDF_rxa[ i ].ebsnValid = FTDF_TRUE;
                    }

                    FTDF_rxa[ i ].ebsn = frameHeader->SN;
                    break;
                }
            }
            else
            {
                FTDF_rxa[ i ].addrMode = frameHeader->srcAddrMode;
                FTDF_rxa[ i ].addr     = frameHeader->srcAddr;

                switch (snSel)
                {
                case FTDF_SN_SEL_DSN:
                    FTDF_rxa[ i ].dsnValid = FTDF_TRUE;
                    FTDF_rxa[ i ].dsn      = frameHeader->SN;
                    break;

                case FTDF_SN_SEL_BSN:
                    FTDF_rxa[ i ].bsnValid = FTDF_TRUE;
                    FTDF_rxa[ i ].bsn      = frameHeader->SN;
                    break;

                case FTDF_SN_SEL_EBSN:
                    FTDF_rxa[ i ].ebsnValid = FTDF_TRUE;
                    FTDF_rxa[ i ].ebsn      = frameHeader->SN;
                    break;
                }
            }

            FTDF_rxa[ i ].timestamp = timestamp;
        }
        else
        {
            // find oldest entry and overwrite it
            FTDF_Time curTime = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);
            FTDF_Time delta, greatestDelta = 0;
            uint8_t   entry   = 0;

            for (i = 0; i < FTDF_NR_OF_RX_ADDRS; i++)
            {
                delta = curTime - FTDF_rxa[ i ].timestamp;

                if (delta > greatestDelta)
                {
                    greatestDelta = delta;
                    entry         = i;
                }
            }

            FTDF_rxa[ entry ].addrMode = frameHeader->srcAddrMode;
            FTDF_rxa[ entry ].addr     = frameHeader->srcAddr;

            switch (snSel)
            {
            case FTDF_SN_SEL_DSN:
                FTDF_rxa[ entry ].bsnValid  = FTDF_FALSE;
                FTDF_rxa[ entry ].ebsnValid = FTDF_FALSE;
                FTDF_rxa[ entry ].dsnValid  = FTDF_TRUE;
                FTDF_rxa[ entry ].dsn       = frameHeader->SN;
                break;

            case FTDF_SN_SEL_BSN:
                FTDF_rxa[ entry ].dsnValid  = FTDF_FALSE;
                FTDF_rxa[ entry ].ebsnValid = FTDF_FALSE;
                FTDF_rxa[ entry ].bsnValid  = FTDF_TRUE;
                FTDF_rxa[ entry ].bsn       = frameHeader->SN;
                break;

            case FTDF_SN_SEL_EBSN:
                FTDF_rxa[ entry ].dsnValid  = FTDF_FALSE;
                FTDF_rxa[ entry ].bsnValid  = FTDF_FALSE;
                FTDF_rxa[ entry ].ebsnValid = FTDF_TRUE;
                FTDF_rxa[ entry ].ebsn      = frameHeader->SN;
                break;
            }
        }
    }

    if (frameHeader->options & FTDF_OPT_SECURITY_ENABLED)
    {
        rxPtr = FTDF_getSecurityHeader(rxPtr, frameHeader->frameVersion, securityHeader);
    }
    else
    {
        securityHeader->securityLevel = 0;
        securityHeader->keyIdMode     = 0;
    }

    FTDF_IEList *headerIEList  = NULL;
    FTDF_IEList *payloadIEList = NULL;
    int          micLength     = FTDF_getMicLength(securityHeader->securityLevel);

#if !defined(FTDF_NO_CSL) || !defined(FTDF_NO_TSCH)

    if (frameHeader->options & FTDF_OPT_IES_PRESENT)
    {
        rxPtr =
            FTDF_getIes(rxPtr, rxBuffer + (frameLen - micLength - FTDF_FCS_LENGTH), &headerIEList, &payloadIEList);
    }

#endif /* !FTDF_NO_CSL || !FTDF_NO_TSCH */

    // Get start of private data (needed to unsecure a frame)
    if (frameType == FTDF_MAC_COMMAND_FRAME)
    {
        frameHeader->commandFrameId = *rxPtr++;
    }
    else if (frameType == FTDF_BEACON_FRAME)
    {
        PANDescriptor.coordAddrMode = frameHeader->srcAddrMode;
        PANDescriptor.coordPANId    = frameHeader->srcPANId;
        PANDescriptor.coordAddr     = frameHeader->srcAddr;
        PANDescriptor.channelNumber = ((FTDF_GET_FIELD(ON_OFF_REGMAP_PHYRXATTR) >> 4) & 0xf) + 11;
        PANDescriptor.channelPage   = 0;
        PANDescriptor.timestamp     = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_RX_TIMESTAMP, readBuf);
        PANDescriptor.linkQuality   = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_QUALITY_INDICATOR, readBuf);

        FTDF_Octet *superframeSpecPtr = (FTDF_Octet *) &PANDescriptor.superframeSpec;
        *superframeSpecPtr++ = *rxPtr++;
        *superframeSpecPtr   = *rxPtr++;

        uint8_t gtsSpec = *rxPtr++;

        PANDescriptor.GTSPermit = (gtsSpec & 0x08) ? FTDF_TRUE : FTDF_FALSE;
        uint8_t gtsDescrCount = gtsSpec & 0x7;

        if (gtsDescrCount != 0)
        {
            // GTS is not supported, so just skip the GTS direction and GTS list fields if present
            rxPtr += (1 + (3 * gtsDescrCount));
        }

        pendAddrSpec = *rxPtr++;
        uint8_t nrOfShortAddrs = pendAddrSpec & 0x07;
        uint8_t nrOfExtAddrs   = (pendAddrSpec & 0x70) >> 4;

        int     n;

        for (n = 0; n < (nrOfShortAddrs + nrOfExtAddrs); n++)
        {
            if (n < nrOfShortAddrs)
            {
                FTDF_Octet *shortAddressPtr = (FTDF_Octet *) &pendAddrList[ n ].shortAddress;
                *shortAddressPtr++ = *rxBuffer++;
                *shortAddressPtr   = *rxBuffer++;
            }
            else
            {
                FTDF_Octet *extAddressPtr = (FTDF_Octet *) &pendAddrList[ n ].extAddress;
                int         m;

                for (m = 0; m < 8; m++)
                {
                    *extAddressPtr++ = *rxBuffer++;
                }
            }
        }
    }
    else if (frameType == FTDF_ACKNOWLEDGEMENT_FRAME &&
             securityHeader->securityLevel != 0)
    {
        if (FTDF_reqCurrent)
        {
            switch (FTDF_reqCurrent->msgId)
            {
            case FTDF_DATA_REQUEST:
            {
                FTDF_DataRequest *dataRequest = (FTDF_DataRequest *) FTDF_reqCurrent;
                frameHeader->srcPANId    = dataRequest->dstPANId;
                frameHeader->srcAddrMode = dataRequest->dstAddrMode;
                frameHeader->srcAddr     = dataRequest->dstAddr;
                break;
            }

            case FTDF_POLL_REQUEST:
            {
                FTDF_PollRequest *pollRequest = (FTDF_PollRequest *) FTDF_reqCurrent;
                frameHeader->srcPANId    = pollRequest->coordPANId;
                frameHeader->srcAddrMode = pollRequest->coordAddrMode;
                frameHeader->srcAddr     = pollRequest->coordAddr;
                break;
            }

            case FTDF_ASSOCIATE_REQUEST:
            {
                FTDF_AssociateRequest *associateRequest = (FTDF_AssociateRequest *) FTDF_reqCurrent;
                frameHeader->srcPANId    = associateRequest->coordPANId;
                frameHeader->srcAddrMode = associateRequest->coordAddrMode;
                frameHeader->srcAddr     = associateRequest->coordAddr;
                break;
            }

            case FTDF_DISASSOCIATE_REQUEST:
            {
                FTDF_DisassociateRequest *disassociateRequest =
                    (FTDF_DisassociateRequest *) FTDF_reqCurrent;
                frameHeader->srcPANId    = disassociateRequest->devicePANId;
                frameHeader->srcAddrMode = disassociateRequest->deviceAddrMode;
                frameHeader->srcAddr     = disassociateRequest->deviceAddress;
                break;
            }

            case FTDF_ASSOCIATE_RESPONSE:
            {
                FTDF_AssociateResponse *associateResponse = (FTDF_AssociateResponse *) FTDF_reqCurrent;
                frameHeader->srcAddrMode        = FTDF_EXTENDED_ADDRESS;
                frameHeader->srcAddr.extAddress = associateResponse->deviceAddress;
                break;
            }
            }
        }
    }

    FTDF_Status status = FTDF_unsecureFrame(rxBuffer, rxPtr, frameHeader, securityHeader);

    if (status != FTDF_SUCCESS)
    {
        if (FTDF_pib.metricsEnabled)
        {
            FTDF_pib.performanceMetrics.securityFailureCount++;
        }

        FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);

        // Since unsecure of acknowledgement frame is always successful,
        // nothing special has to be done to get the address information correct.
        FTDF_sendCommStatusIndication(FTDF_reqCurrent, status,
                                      FTDF_pib.PANId,
                                      frameHeader->srcAddrMode,
                                      frameHeader->srcAddr,
                                      frameHeader->dstAddrMode,
                                      frameHeader->dstAddr,
                                      securityHeader->securityLevel,
                                      securityHeader->keyIdMode,
                                      securityHeader->keySource,
                                      securityHeader->keyIndex);

        if (frameType == FTDF_ACKNOWLEDGEMENT_FRAME && FTDF_reqCurrent)
        {
            sendConfirm(FTDF_NO_ACK,
                        FTDF_reqCurrent->msgId);

            FTDF_processNextRequest();
        }

        return;
    }

    if (FTDF_pib.metricsEnabled && frameType != FTDF_ACKNOWLEDGEMENT_FRAME)
    {
        FTDF_pib.performanceMetrics.RXSuccessCount++;
    }

#ifndef FTDF_NO_TSCH

    if (FTDF_pib.tschEnabled && frameType != FTDF_ACKNOWLEDGEMENT_FRAME)
    {
        FTDF_Time timestamp = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_RX_TIMESTAMP, readBuf);

        FTDF_correctSlotTime(timestamp);
    }

#endif /* FTDF_NO_TSCH */

    switch (frameType)
    {
    case FTDF_ACKNOWLEDGEMENT_FRAME:

        if (FTDF_pib.metricsEnabled)
        {
            if (FTDF_nrOfRetries == 0)
            {
                FTDF_pib.performanceMetrics.TXSuccessCount++;
            }
            else if (FTDF_nrOfRetries == 1)
            {
                FTDF_pib.performanceMetrics.retryCount++;
            }
            else
            {
                FTDF_pib.performanceMetrics.multipleRetryCount++;
            }
        }

        if (frameHeader->frameVersion == FTDF_FRAME_VERSION_E)
        {
            FTDF_pib.trafficCounters.rxEnhAckFrmOkCnt++;
        }

        break;

    case FTDF_BEACON_FRAME:
        FTDF_pib.trafficCounters.rxBeaconFrmOkCnt++;
        break;

    case FTDF_DATA_FRAME:
        FTDF_pib.trafficCounters.rxDataFrmOkCnt++;
        break;

    case FTDF_MAC_COMMAND_FRAME:
        FTDF_pib.trafficCounters.rxCmdFrmOkCnt++;
        break;

    case FTDF_MULTIPURPOSE_FRAME:
        FTDF_pib.trafficCounters.rxMultiPurpFrmOkCnt++;
        break;
    }

    if (frameType == FTDF_ACKNOWLEDGEMENT_FRAME)
    {
        volatile uint32_t *txFlagS = FTDF_GET_REG_ADDR_INDEXED(ON_OFF_REGMAP_TX_FLAG_S, FTDF_TX_DATA_BUFFER);

        while (*txFlagS & MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_STAT)
        { }

        // It is required to call FTDF_processTxEvent here because an RX ack generates two events
        // The RX event is raised first, then after an IFS the TX event is raised. However,
        // the FTDF_processNextRequest requires that both events have been handled.
        FTDF_processTxEvent();

        FTDF_SN SN = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_MACSN, FTDF_TX_DATA_BUFFER);

        if (FTDF_reqCurrent &&
            frameHeader->SN == SN)
        {
#ifndef FTDF_NO_CSL

            if (FTDF_pib.leEnabled == FTDF_TRUE)
            {
                FTDF_Time timestamp = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_RX_TIMESTAMP,
                                                             readBuf);

                FTDF_setPeerCslTiming(headerIEList, timestamp);
            }

#endif /* FTDF_NO_CSL */

#ifndef FTDF_NO_TSCH

            if (FTDF_pib.tschEnabled == FTDF_TRUE)
            {
                FTDF_correctSlotTimeFromAck(headerIEList);

                FTDF_TschRetry *tschRetry = FTDF_getTschRetry(FTDF_getRequestAddress(FTDF_reqCurrent));

                tschRetry->nrOfRetries     = 0;
                FTDF_tschSlotLink->request = NULL;
            }

#endif /* FTDF_NO_TSCH */

            switch (FTDF_reqCurrent->msgId)
            {
            case FTDF_DATA_REQUEST:
            {
                FTDF_Time          timestamp     = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_TXTIMESTAMP,
                                                                          FTDF_TX_DATA_BUFFER);
                FTDF_NumOfBackoffs numOfBackoffs = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_CSMACANRRETRIES,
                                                                          FTDF_TX_DATA_BUFFER);

                FTDF_sendDataConfirm((FTDF_DataRequest *)FTDF_reqCurrent,
                                     FTDF_SUCCESS,
                                     timestamp,
                                     SN,
                                     numOfBackoffs,
                                     payloadIEList);

                break;
            }

            case FTDF_POLL_REQUEST:
            {
                if (!(frameHeader->options & FTDF_OPT_FRAME_PENDING))
                {
                    FTDF_sendPollConfirm((FTDF_PollRequest *)FTDF_reqCurrent, FTDF_NO_DATA);
                }

                break;
            }

            case FTDF_ASSOCIATE_REQUEST:
            {
                FTDF_AssocAdmin *assocAdmin = &FTDF_aa;

                if (assocAdmin->fastA == FTDF_TRUE ||
                    assocAdmin->dataR == FTDF_FALSE)
                {
                    uint32_t timestamp = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);
                    FTDF_SET_FIELD(ON_OFF_REGMAP_SYMBOLTIME2THR,
                                   (timestamp + FTDF_pib.responseWaitTime * FTDF_BASE_SUPERFRAME_DURATION));
                }
                else if (!(frameHeader->options & FTDF_OPT_FRAME_PENDING))
                {
                    FTDF_sendAssociateConfirm((FTDF_AssociateRequest *)FTDF_reqCurrent,
                                              FTDF_NO_DATA,
                                              0xffff);
                }

                break;
            }

            case FTDF_ASSOCIATE_RESPONSE:
            {
                FTDF_AssociateResponse *assocResp = (FTDF_AssociateResponse *)FTDF_reqCurrent;

                FTDF_Address srcAddr, dstAddr;
                srcAddr.extAddress = FTDF_pib.extAddress;
                dstAddr.extAddress = assocResp->deviceAddress;

                FTDF_sendCommStatusIndication(FTDF_reqCurrent, FTDF_SUCCESS,
                                              FTDF_pib.PANId,
                                              FTDF_EXTENDED_ADDRESS,
                                              srcAddr,
                                              FTDF_EXTENDED_ADDRESS,
                                              dstAddr,
                                              assocResp->securityLevel,
                                              assocResp->keyIdMode,
                                              assocResp->keySource,
                                              assocResp->keyIndex);
                break;
            }

            case FTDF_ORPHAN_RESPONSE:
            {
                FTDF_OrphanResponse *orphanResp = (FTDF_OrphanResponse *)FTDF_reqCurrent;

                FTDF_Address srcAddr, dstAddr;
                srcAddr.extAddress = FTDF_pib.extAddress;
                dstAddr.extAddress = orphanResp->orphanAddress;

                FTDF_sendCommStatusIndication(FTDF_reqCurrent, FTDF_SUCCESS,
                                              FTDF_pib.PANId,
                                              FTDF_EXTENDED_ADDRESS,
                                              srcAddr,
                                              FTDF_EXTENDED_ADDRESS,
                                              dstAddr,
                                              orphanResp->securityLevel,
                                              orphanResp->keyIdMode,
                                              orphanResp->keySource,
                                              orphanResp->keyIndex);
                break;
            }

            case FTDF_DISASSOCIATE_REQUEST:
            {
                FTDF_sendDisassociateConfirm((FTDF_DisassociateRequest *)FTDF_reqCurrent, FTDF_SUCCESS);
                break;
            }

            case FTDF_REMOTE_REQUEST:
            {
                FTDF_RemoteRequest *remoteRequest = (FTDF_RemoteRequest *) FTDF_reqCurrent;

                if (remoteRequest->remoteId == FTDF_REMOTE_PAN_ID_CONFLICT_NOTIFICATION)
                {
                    FTDF_sendSyncLossIndication(FTDF_PAN_ID_CONFLICT, securityHeader);
                }

                FTDF_reqCurrent = NULL;

                break;
            }
            }

            if (FTDF_reqCurrent->msgId != FTDF_DATA_REQUEST)
            {
                // for data request the application owns the memory
                FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);
            }

            FTDF_processNextRequest();
        }
        else
        {
            FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);
        }
    }
    else if ((frameHeader->frameVersion == FTDF_FRAME_VERSION_E || FTDF_pib.tschEnabled) &&
             (frameHeader->options & FTDF_OPT_ACK_REQUESTED))
    {
#if !defined(FTDF_NO_CSL) || !defined(FTDF_NO_TSCH)
        static FTDF_FrameHeader afh;
        FTDF_FrameHeader       *ackFrameHeader = &afh;

        ackFrameHeader->frameType = FTDF_ACKNOWLEDGEMENT_FRAME;
        ackFrameHeader->options   =
            (frameHeader->options &
             (FTDF_OPT_SECURITY_ENABLED | FTDF_OPT_SEQ_NR_SUPPRESSED)) | FTDF_OPT_ENHANCED;

        if (FTDF_pib.leEnabled == FTDF_TRUE ||
            FTDF_pib.tschEnabled == FTDF_TRUE ||
            FTDF_pib.EAckIEList.nrOfIEs != 0)
        {
            ackFrameHeader->options |= FTDF_OPT_IES_PRESENT;
        }

        ackFrameHeader->dstAddrMode = FTDF_NO_ADDRESS;
        ackFrameHeader->srcAddrMode = FTDF_NO_ADDRESS;
        ackFrameHeader->SN          = frameHeader->SN;

        FTDF_Octet *txPtr = (FTDF_Octet *) FTDF_GET_REG_ADDR(RETENTION_RAM_TX_FIFO) +
                            (FTDF_BUFFER_LENGTH * FTDF_TX_ACK_BUFFER);

        // Skip PHY header (= MAC length)
        txPtr++;

        txPtr = FTDF_addFrameHeader(txPtr,
                                    ackFrameHeader,
                                    0);

        if (frameHeader->options & FTDF_OPT_SECURITY_ENABLED)
        {
            securityHeader->frameCounter     = FTDF_pib.frameCounter;
            securityHeader->frameCounterMode = FTDF_pib.frameCounterMode;

            txPtr                            = FTDF_addSecurityHeader(txPtr,
                                                                      securityHeader);
        }

#ifndef FTDF_NO_CSL

        if (FTDF_pib.leEnabled == FTDF_TRUE)
        {
            static FTDF_Octet        phaseAndPeriod[ 4 ];
            static FTDF_IEDescriptor cslIE     = { 0x1a, 4, { phaseAndPeriod } };
            static FTDF_IEList       cslIEList = { 1, &cslIE };
            FTDF_Time                curTime   = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);

            FTDF_Time                delta     = curTime -
                                                 (FTDF_startCslSampleTime - FTDF_pib.CSLPeriod * 10);

            *(FTDF_Period *)(phaseAndPeriod + 0) = (FTDF_Period)(delta / 10);
            *(FTDF_Period *)(phaseAndPeriod + 2) = FTDF_pib.CSLPeriod;

            txPtr                                  = FTDF_addIes(txPtr,
                                                                 &cslIEList,
                                                                 &FTDF_pib.EAckIEList,
                                                                 FTDF_FALSE);
        }

#endif /* FTDF_NO_CSL */

#ifndef FTDF_NO_TSCH

        if (FTDF_pib.tschEnabled == FTDF_TRUE)
        {
            FTDF_Time rxTimestamp = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_RX_TIMESTAMP, readBuf);

            txPtr = FTDF_addCorrTimeIE(txPtr, rxTimestamp);
        }

#endif /* FTDF_NO_TSCH */

        if (!FTDF_pib.leEnabled && !FTDF_pib.tschEnabled)
        {
            txPtr = FTDF_addIes(txPtr,
                                NULL,
                                &FTDF_pib.EAckIEList,
                                FTDF_FALSE);
        }

        FTDF_sendAckFrame(frameHeader,
                          securityHeader,
                          txPtr);
#endif /* !FTDF_NO_CSL || !FTDF_NO_TSCH */

        if (duplicate)
        {
            FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);
            return;
        }
    }

    if (frameType == FTDF_DATA_FRAME || frameType == FTDF_MULTIPURPOSE_FRAME)
    {
        FTDF_DataLength payloadLength = frameLen -
                                        (rxPtr - rxBuffer) + 1 - micLength - FTDF_FCS_LENGTH;

        if (FTDF_reqCurrent &&
            FTDF_reqCurrent->msgId == FTDF_POLL_REQUEST)
        {
            FTDF_PollRequest *pollRequest = (FTDF_PollRequest *) FTDF_reqCurrent;

            if (frameHeader->srcAddrMode == pollRequest->coordAddrMode &&
                frameHeader->srcPANId == pollRequest->coordPANId &&
                ((frameHeader->srcAddrMode == FTDF_SHORT_ADDRESS &&
                  frameHeader->srcAddr.shortAddress == pollRequest->coordAddr.shortAddress) ||
                 (frameHeader->srcAddrMode == FTDF_EXTENDED_ADDRESS &&
                  frameHeader->srcAddr.extAddress == pollRequest->coordAddr.extAddress)))
            {
                if (payloadLength == 0)
                {
                    FTDF_sendPollConfirm(pollRequest, FTDF_NO_DATA);
                }
                else
                {
                    FTDF_sendPollConfirm(pollRequest, FTDF_SUCCESS);
                }
            }
        }
        else if (FTDF_reqCurrent &&
                 FTDF_reqCurrent->msgId == FTDF_ASSOCIATE_REQUEST &&
                 payloadLength == 0)
        {
            sendConfirm(FTDF_NO_DATA, FTDF_ASSOCIATE_REQUEST);
        }

        if (payloadLength != 0)
        {
            FTDF_LinkQuality mpduLinkQuality = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_QUALITY_INDICATOR,
                                                                      readBuf);
            FTDF_Time        timestamp       = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_RX_TIMESTAMP,
                                                                      readBuf);

            FTDF_sendDataIndication(frameHeader,
                                    securityHeader,
                                    payloadIEList,
                                    payloadLength,
                                    rxPtr,
                                    mpduLinkQuality,
                                    timestamp);
        }

#ifndef FTDF_NO_CSL
        else if (headerIEList->nrOfIEs == 1 &&
                 headerIEList->IEs[ 0 ].ID == 0x1d)
        {
            FTDF_Period rzTime = *(uint16_t *) headerIEList->IEs[ 0 ].content.raw;

            FTDF_criticalVar();
            FTDF_enterCritical();

            FTDF_Time curTime = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);

            FTDF_rzTime = curTime + (FTDF_Time) rzTime * 10 + 260;  // 260 length of max frame in symbols

            FTDF_Time CSLPeriod = FTDF_pib.CSLPeriod * 10;
            FTDF_Time delta     = FTDF_rzTime - FTDF_startCslSampleTime;

            while (delta < 0x80000000)    // A delta larger than 0x80000000 is assumed a negative delta
            {
                FTDF_startCslSampleTime += CSLPeriod;
                delta                    = FTDF_rzTime - FTDF_startCslSampleTime;
            }

            FTDF_SET_FIELD(ON_OFF_REGMAP_MACCSLSTARTSAMPLETIME, FTDF_startCslSampleTime);

            FTDF_exitCritical();

            FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);
        }

#endif /* FTDF_NO_CSL */
        else
        {
            FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);
        }
    }
    else if (frameType == FTDF_MAC_COMMAND_FRAME)
    {
        FTDF_processCommandFrame(rxPtr, frameHeader, securityHeader, payloadIEList);
    }
    else if (frameType == FTDF_BEACON_FRAME)
    {
        FTDF_Octet *superframeSpecPtr = (FTDF_Octet *)&PANDescriptor.superframeSpec;
        superframeSpecPtr++;

        if (FTDF_isPANCoordinator)
        {
            if (frameHeader->srcPANId == FTDF_pib.PANId && (*superframeSpecPtr & 0x40))
            {
                FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);
                FTDF_sendSyncLossIndication(FTDF_PAN_ID_CONFLICT, securityHeader);
                return;
            }
        }
        else if (FTDF_pib.associatedPANCoord)
        {
            if (frameHeader->srcPANId == FTDF_pib.PANId && (*superframeSpecPtr & 0x40) &&
                ((frameHeader->srcAddrMode == FTDF_SHORT_ADDRESS &&
                  frameHeader->srcAddr.shortAddress != FTDF_pib.coordShortAddress) ||
                 (frameHeader->srcAddrMode == FTDF_EXTENDED_ADDRESS &&
                  frameHeader->srcAddr.extAddress != FTDF_pib.coordExtAddress)))
            {
                FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);
                FTDF_sendPANIdConflictNotification(frameHeader, securityHeader);
                return;
            }
        }

        FTDF_DataLength beaconPayloadLength = frameLen - (rxPtr - rxBuffer) + 1 - micLength - FTDF_FCS_LENGTH;

        if (FTDF_pib.autoRequest == FTDF_FALSE ||
            beaconPayloadLength != 0)
        {
            FTDF_Time timestamp = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_RX_TIMESTAMP,
                                                         readBuf);

            FTDF_BeaconNotifyIndication *beaconNotifyIndication =
                (FTDF_BeaconNotifyIndication *) FTDF_GET_MSG_BUFFER(
                    sizeof(FTDF_BeaconNotifyIndication));

            beaconNotifyIndication->msgId         = FTDF_BEACON_NOTIFY_INDICATION;
            beaconNotifyIndication->BSN           = frameHeader->SN;
            beaconNotifyIndication->PANDescriptor = &PANDescriptor;
            beaconNotifyIndication->pendAddrSpec  = pendAddrSpec;
            beaconNotifyIndication->addrList      = pendAddrList;
            beaconNotifyIndication->sduLength     = beaconPayloadLength;
            beaconNotifyIndication->sdu           = FTDF_GET_DATA_BUFFER(beaconPayloadLength);
            beaconNotifyIndication->EBSN          = frameHeader->SN;
            beaconNotifyIndication->beaconType    =
                frameHeader->frameVersion == FTDF_FRAME_VERSION_E ? FTDF_ENHANCED_BEACON : FTDF_NORMAL_BEACON;
            beaconNotifyIndication->IEList        = payloadIEList;
            beaconNotifyIndication->timestamp     = timestamp;

            memcpy(beaconNotifyIndication->sdu, rxPtr, beaconPayloadLength);

            FTDF_RCV_MSG((FTDF_MsgBuffer *) beaconNotifyIndication);
        }
        else if (FTDF_reqCurrent &&
                 FTDF_reqCurrent->msgId == FTDF_SCAN_REQUEST)
        {
            FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);
            FTDF_addPANdescriptor(&PANDescriptor);
        }
        else
        {
            FTDF_REL_DATA_BUFFER((FTDF_Octet *)payloadIEList);
        }
    }

#ifndef FTDF_NO_TSCH

    if (FTDF_pib.tschEnabled == FTDF_TRUE)
    {
        FTDF_scheduleTsch(NULL);
    }

#endif /* FTDF_NO_TSCH */
#endif /* !FTDF_LITE */
}



void FTDF_processRxEvent(void)
{
    volatile uint32_t *rxEvent = (volatile uint32_t *) IND_R_FTDF_ON_OFF_REGMAP_RX_EVENT;

    if (*rxEvent & MSK_F_FTDF_ON_OFF_REGMAP_RXSOF_E)
    {
#ifdef SIMULATOR
        *rxEvent &= ~MSK_F_FTDF_ON_OFF_REGMAP_RXSOF_E;
#else
        *rxEvent  = MSK_F_FTDF_ON_OFF_REGMAP_RXSOF_E;
#endif
    }

    if (*rxEvent & MSK_F_FTDF_ON_OFF_REGMAP_RXBYTE_E)
    {
#ifdef SIMULATOR
        *rxEvent &= ~MSK_F_FTDF_ON_OFF_REGMAP_RXBYTE_E;
#else
        *rxEvent  = MSK_F_FTDF_ON_OFF_REGMAP_RXBYTE_E;
#endif
    }

    if (*rxEvent & MSK_F_FTDF_ON_OFF_REGMAP_RX_OVERFLOW_E)
    {
        // No API defined to report this error to the higher layer, so just clear it.
#ifdef SIMULATOR
        *rxEvent &= ~MSK_F_FTDF_ON_OFF_REGMAP_RX_OVERFLOW_E;
#else
        *rxEvent  = MSK_F_FTDF_ON_OFF_REGMAP_RX_OVERFLOW_E;
#endif
    }

    if (*rxEvent & MSK_F_FTDF_ON_OFF_REGMAP_RX_BUF_AVAIL_E)
    {
        int readBuf  = FTDF_GET_FIELD(ON_OFF_REGMAP_RX_READ_BUF_PTR);
        int writeBuf = FTDF_GET_FIELD(ON_OFF_REGMAP_RX_WRITE_BUF_PTR);

        while (readBuf != writeBuf)
        {
            processRxFrame(readBuf % 8);
            readBuf = (readBuf + 1) % 16;
        }

        FTDF_SET_FIELD(ON_OFF_REGMAP_RX_READ_BUF_PTR, readBuf);

#ifdef SIMULATOR
        *rxEvent &= ~MSK_F_FTDF_ON_OFF_REGMAP_RX_BUF_AVAIL_E;
#else
        *rxEvent  = MSK_F_FTDF_ON_OFF_REGMAP_RX_BUF_AVAIL_E;
#endif
    }

    volatile uint32_t *lmacEvent = (volatile uint32_t *) IND_R_FTDF_ON_OFF_REGMAP_LMAC_EVENT;

    if (*lmacEvent & MSK_F_FTDF_ON_OFF_REGMAP_EDSCANREADY_E)
    {
#ifdef SIMULATOR
        *lmacEvent &= ~MSK_F_FTDF_ON_OFF_REGMAP_EDSCANREADY_E;
#else
        *lmacEvent  = MSK_F_FTDF_ON_OFF_REGMAP_EDSCANREADY_E;
#endif

#ifndef FTDF_LITE
        FTDF_MsgBuffer *request = FTDF_reqCurrent;

        if (request->msgId == FTDF_SCAN_REQUEST)
        {
            FTDF_scanReady((FTDF_ScanRequest *) request);
        }

#endif /* !FTDF_LITE */
    }

    if (*lmacEvent & MSK_F_FTDF_ON_OFF_REGMAP_RXTIMEREXPIRED_E)
    {
#ifdef SIMULATOR
        *lmacEvent &= ~MSK_F_FTDF_ON_OFF_REGMAP_RXTIMEREXPIRED_E;
#else
        *lmacEvent  = MSK_F_FTDF_ON_OFF_REGMAP_RXTIMEREXPIRED_E;
#endif

#ifndef FTDF_LITE
#ifndef FTDF_NO_TSCH

        if (FTDF_pib.tschEnabled)
        {
            FTDF_scheduleTsch(NULL);
        }
        else
#endif /* FTDF_NO_TSCH */
            if (FTDF_reqCurrent)
            {
                FTDF_MsgId msgId = FTDF_reqCurrent->msgId;

                if (msgId == FTDF_POLL_REQUEST)
                {
                    FTDF_sendPollConfirm((FTDF_PollRequest *)FTDF_reqCurrent, FTDF_NO_DATA);
                }
                else if (msgId == FTDF_SCAN_REQUEST)
                {
                    FTDF_scanReady((FTDF_ScanRequest *) FTDF_reqCurrent);
                }
                else if (msgId == FTDF_ASSOCIATE_REQUEST)
                {
                    FTDF_sendAssociateConfirm((FTDF_AssociateRequest *)FTDF_reqCurrent,
                                              FTDF_NO_DATA,
                                              0xffff);
                }
            }

#endif /* !FTDF_LITE */
    }
}

static void sendConfirm(FTDF_Status status,
                        FTDF_MsgId  msgId)
{
    switch (msgId)
    {
#ifndef FTDF_LITE

    case FTDF_DATA_REQUEST:
    {
        FTDF_DataRequest  *dataRequest   = (FTDF_DataRequest *) FTDF_reqCurrent;

        FTDF_Time          timestamp     = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_TXTIMESTAMP,
                                                                  FTDF_TX_DATA_BUFFER);
        FTDF_SN            SN            = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_MACSN, FTDF_TX_DATA_BUFFER);
        FTDF_NumOfBackoffs numOfBackoffs = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_CSMACANRRETRIES,
                                                                  FTDF_TX_DATA_BUFFER);

        FTDF_sendDataConfirm(dataRequest, status,
                             timestamp,
                             SN,
                             numOfBackoffs,
                             NULL);

        break;
    }

    case FTDF_POLL_REQUEST:

        if (status != FTDF_SUCCESS)
        {
            FTDF_sendPollConfirm((FTDF_PollRequest *)FTDF_reqCurrent, status);
        }

        break;

    case FTDF_ASSOCIATE_REQUEST:

        if (status != FTDF_SUCCESS)
        {
            FTDF_sendAssociateConfirm((FTDF_AssociateRequest *)FTDF_reqCurrent,
                                      status,
                                      0xffff);
        }

        break;

    case FTDF_ASSOCIATE_RESPONSE:

        if (status != FTDF_SUCCESS)
        {
            FTDF_AssociateResponse *assocResp = (FTDF_AssociateResponse *)FTDF_reqCurrent;

            FTDF_Address srcAddr, dstAddr;
            srcAddr.extAddress = FTDF_pib.extAddress;
            dstAddr.extAddress = assocResp->deviceAddress;

            FTDF_sendCommStatusIndication(FTDF_reqCurrent, status,
                                          FTDF_pib.PANId,
                                          FTDF_EXTENDED_ADDRESS,
                                          srcAddr,
                                          FTDF_EXTENDED_ADDRESS,
                                          dstAddr,
                                          assocResp->securityLevel,
                                          assocResp->keyIdMode,
                                          assocResp->keySource,
                                          assocResp->keyIndex);
        }

        break;

    case FTDF_ORPHAN_RESPONSE:

        if (status != FTDF_SUCCESS)
        {
            FTDF_OrphanResponse *orphanResp = (FTDF_OrphanResponse *)FTDF_reqCurrent;

            FTDF_Address srcAddr, dstAddr;
            srcAddr.extAddress = FTDF_pib.extAddress;
            dstAddr.extAddress = orphanResp->orphanAddress;

            FTDF_sendCommStatusIndication(FTDF_reqCurrent, status,
                                          FTDF_pib.PANId,
                                          FTDF_EXTENDED_ADDRESS,
                                          srcAddr,
                                          FTDF_EXTENDED_ADDRESS,
                                          dstAddr,
                                          orphanResp->securityLevel,
                                          orphanResp->keyIdMode,
                                          orphanResp->keySource,
                                          orphanResp->keyIndex);
        }

        break;

    case FTDF_DISASSOCIATE_REQUEST:

        if (status != FTDF_SUCCESS)
        {
            FTDF_sendDisassociateConfirm((FTDF_DisassociateRequest *)FTDF_reqCurrent, status);
        }

        break;

    case FTDF_SCAN_REQUEST:

        if (status != FTDF_SUCCESS)
        {
            FTDF_sendScanConfirm((FTDF_ScanRequest *)FTDF_reqCurrent, status);
        }

        break;

    case FTDF_BEACON_REQUEST:
        FTDF_sendBeaconConfirm((FTDF_BeaconRequest *)FTDF_reqCurrent, status);
        break;

    case FTDF_REMOTE_REQUEST:
        FTDF_reqCurrent = NULL;
        break;
#endif /* !FTDF_LITE */

    case FTDF_TRANSPARENT_REQUEST:
    {
#ifndef FTDF_PHY_API
        FTDF_TransparentRequest *transparentRequest = (FTDF_TransparentRequest *) FTDF_reqCurrent;
#endif
        FTDF_Bitmap32            transparentStatus  = 0;

        switch (status)
        {
        case FTDF_SUCCESS:
            transparentStatus = FTDF_TRANSPARENT_SEND_SUCCESSFUL;
            break;

        case FTDF_CHANNEL_ACCESS_FAILURE:
            transparentStatus = FTDF_TRANSPARENT_CSMACA_FAILURE;
            break;
#if FTDF_TRANSPARENT_WAIT_FOR_ACK

        case FTDF_NO_ACK:
            transparentStatus = FTDF_TRANSPARENT_NO_ACK;
            break;
#endif
        }

        if (FTDF_pib.metricsEnabled)
        {
            FTDF_pib.performanceMetrics.TXSuccessCount++;
        }

#ifdef FTDF_PHY_API
        FTDF_criticalVar();
        FTDF_enterCritical();
        FTDF_txInProgress = FTDF_FALSE;
        FTDF_exitCritical();

        FTDF_SEND_FRAME_TRANSPARENT_CONFIRM(NULL, transparentStatus);
#else

        FTDF_reqCurrent = NULL;

        FTDF_SEND_FRAME_TRANSPARENT_CONFIRM(transparentRequest->handle,
                                            transparentStatus);

        FTDF_REL_MSG_BUFFER((FTDF_MsgBuffer *) transparentRequest);
#ifndef FTDF_LITE
        FTDF_processNextRequest();
#endif /* !FTDF_LITE */

#endif /* FTDF_PHY_API */
        break;
    }
    }
}

void FTDF_processTxEvent(void)
{
    volatile uint32_t *txFlagStatE;
    FTDF_Status        status = FTDF_SUCCESS;

#if dg_configCOEX_ENABLE_CONFIG
    hw_coex_pti_t tx_pti;
    hw_coex_update_ftdf_pti(FTDF_getRxPti(), &tx_pti, true);
#endif

    txFlagStatE = FTDF_GET_FIELD_ADDR_INDEXED(ON_OFF_REGMAP_TX_FLAG_CLEAR_E, FTDF_TX_WAKEUP_BUFFER);

    if (*txFlagStatE & MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_CLEAR_E)
    {
#ifdef SIMULATOR
        *txFlagStatE &= ~MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_CLEAR_E;
#else
        *txFlagStatE  = MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_CLEAR_E;
#endif

        volatile uint32_t *txStatus =
            FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_RETURN_STATUS_1, FTDF_TX_WAKEUP_BUFFER);

        if (*txStatus & MSK_F_FTDF_RETENTION_RAM_CSMACAFAIL)
        {
            if (FTDF_pib.metricsEnabled)
            {
                FTDF_pib.performanceMetrics.TXFailCount++;
            }

            status = FTDF_CHANNEL_ACCESS_FAILURE;
        }
    }

    txFlagStatE = FTDF_GET_FIELD_ADDR_INDEXED(ON_OFF_REGMAP_TX_FLAG_CLEAR_E, FTDF_TX_DATA_BUFFER);

    if (*txFlagStatE & MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_CLEAR_E)
    {
#ifdef SIMULATOR
        *txFlagStatE &= ~MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_CLEAR_E;
#else
        *txFlagStatE  = MSK_F_FTDF_ON_OFF_REGMAP_TX_FLAG_CLEAR_E;
#endif
    }
    else
    {
        return;
    }

#ifndef FTDF_PHY_API
    FTDF_txInProgress = FTDF_FALSE;

    if (FTDF_reqCurrent == NULL)
    {
        return;
    }

#else
    FTDF_criticalVar();
    FTDF_enterCritical();

    if (FTDF_txInProgress == FTDF_FALSE)
    {
        FTDF_exitCritical();
        return;
    }

    FTDF_exitCritical();
#endif

    FTDF_Boolean ackTX = FTDF_GET_FIELD_INDEXED(RETENTION_RAM_ACKREQUEST, FTDF_TX_DATA_BUFFER);

    if (status == FTDF_SUCCESS)
    {
        volatile uint32_t *txMeta    = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_0, FTDF_TX_DATA_BUFFER);
        FTDF_FrameType     frameType =
            (*txMeta & MSK_F_FTDF_RETENTION_RAM_FRAMETYPE) >> OFF_F_FTDF_RETENTION_RAM_FRAMETYPE;

        switch (frameType)
        {
        case FTDF_BEACON_FRAME:
            FTDF_pib.trafficCounters.txBeaconFrmCnt++;
            break;

        case FTDF_DATA_FRAME:
            FTDF_pib.trafficCounters.txDataFrmCnt++;
            break;

        case FTDF_MAC_COMMAND_FRAME:
            FTDF_pib.trafficCounters.txCmdFrmCnt++;
            break;

        case FTDF_MULTIPURPOSE_FRAME:
            FTDF_pib.trafficCounters.txMultiPurpFrmCnt++;
            break;
        }

        volatile uint32_t *txStatus =
            FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_RETURN_STATUS_1, FTDF_TX_DATA_BUFFER);
#ifndef FTDF_LITE
#ifndef FTDF_NO_TSCH
        FTDF_TschRetry *tschRetry = NULL;

        if (FTDF_pib.tschEnabled)
        {
            tschRetry = FTDF_getTschRetry(FTDF_getRequestAddress(FTDF_reqCurrent));
        }

#endif /* FTDF_NO_TSCH */
#endif /* !FTDF_LITE */

        if (*txStatus & MSK_F_FTDF_RETENTION_RAM_ACKFAIL)
        {
#ifndef FTDF_LITE
#ifndef FTDF_NO_TSCH

            if (FTDF_pib.tschEnabled)
            {
                tschRetry->nrOfRetries++;
                FTDF_tschSlotLink->request = NULL;
                status                     = FTDF_scheduleTsch(FTDF_reqCurrent);

                if (status == FTDF_SUCCESS)
                {
                    // If FTDF_reqCurrent is not equal to NULL the retried request will be queued
                    // rather then send again
                    FTDF_reqCurrent = NULL;
                }
            }
            else
#endif /* FTDF_NO_TSCH */
#endif /* !FTDF_LITE */

                if (FTDF_nrOfRetries < FTDF_pib.maxFrameRetries)
                {
                    FTDF_nrOfRetries++;
#ifndef FTDF_LITE
#ifndef FTDF_NO_CSL

                    if (FTDF_pib.leEnabled)
                    {
                        FTDF_setPeerCslTiming(NULL, 0);

                        FTDF_criticalVar();
                        FTDF_enterCritical();

                        FTDF_Time curTime = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);

                        FTDF_txInProgress = FTDF_TRUE;
                        FTDF_SET_FIELD(ON_OFF_REGMAP_MACCSLSTARTSAMPLETIME, curTime + 5);
                        FTDF_SET_FIELD(ON_OFF_REGMAP_MACWUPERIOD, FTDF_pib.CSLMaxPeriod);

                        volatile uint32_t *txFlagSet = FTDF_GET_FIELD_ADDR(ON_OFF_REGMAP_TX_FLAG_SET);
                        *txFlagSet |= ((1 << FTDF_TX_DATA_BUFFER) | (1 << FTDF_TX_WAKEUP_BUFFER));

                        FTDF_exitCritical();
                    }
                    else
#endif /* FTDF_NO_CSL */
#endif /* !FTDF_LITE */
                    {
#if dg_configCOEX_ENABLE_CONFIG
                        hw_coex_update_ftdf_pti(tx_pti, NULL, true);
#endif
                        volatile uint32_t *txFlagSet = FTDF_GET_FIELD_ADDR(ON_OFF_REGMAP_TX_FLAG_SET);
                        *txFlagSet |= (1 << FTDF_TX_DATA_BUFFER);
                    }

                    return;
                }
                else
                {
                    if (FTDF_pib.metricsEnabled)
                    {
                        FTDF_pib.performanceMetrics.TXFailCount++;
                    }

                    status = FTDF_NO_ACK;
                }
        }
        else if (*txStatus & MSK_F_FTDF_RETENTION_RAM_CSMACAFAIL)
        {
#ifndef FTDF_LITE
#ifndef FTDF_NO_TSCH

            if (FTDF_pib.tschEnabled)
            {
                tschRetry->nrOfCcaRetries++;

                if (tschRetry->nrOfCcaRetries < FTDF_pib.maxCSMABackoffs)
                {
                    FTDF_tschSlotLink->request = NULL;
                    status                     = FTDF_scheduleTsch(FTDF_reqCurrent);

                    if (status == FTDF_SUCCESS)
                    {
                        // If FTDF_reqCurrent is not equal to NULL the retried request will be queued
                        // rather then send again
                        FTDF_reqCurrent = NULL;
                    }
                }
                else
                {
                    status = FTDF_CHANNEL_ACCESS_FAILURE;
                }
            }
            else
#endif /* FTDF_NO_TSCH */
#endif /* !FTDF_LITE */
            {
                status = FTDF_CHANNEL_ACCESS_FAILURE;
            }

            if (FTDF_pib.metricsEnabled && status != FTDF_SUCCESS)
            {
                FTDF_pib.performanceMetrics.TXFailCount++;
            }
        }
        else
        {
            if (ackTX == FTDF_FALSE && FTDF_pib.metricsEnabled)
            {
                FTDF_pib.performanceMetrics.TXSuccessCount++;
            }

#ifndef FTDF_LITE
#ifndef FTDF_NO_TSCH

            if (FTDF_pib.tschEnabled)
            {
                tschRetry->nrOfCcaRetries = 0;
            }

#endif /* FTDF_NO_TSCH */
#endif /* !FTDF_LITE */
        }
    }

#ifndef FTDF_PHY_API

    if ((ackTX == FTDF_FALSE || status != FTDF_SUCCESS) && FTDF_reqCurrent)
    {
        sendConfirm(status,
                    FTDF_reqCurrent->msgId);
#ifndef FTDF_LITE
        FTDF_processNextRequest();
#endif /* !FTDF_LITE */
    }

#else

    if (FTDF_txInProgress)
    {
        sendConfirm(status, FTDF_TRANSPARENT_REQUEST);
    }

#endif
}

void FTDF_processSymbolTimerEvent(void)
{
    volatile uint32_t *symbolTimeThrEvent = FTDF_GET_FIELD_ADDR(ON_OFF_REGMAP_SYMBOLTIMETHR_E);

#ifdef FTDF_PHY_API
    volatile uint32_t *lmacReady4sleepEvent = FTDF_GET_FIELD_ADDR(ON_OFF_REGMAP_LMACREADY4SLEEP_D);

    if (*lmacReady4sleepEvent & MSK_F_FTDF_ON_OFF_REGMAP_LMACREADY4SLEEP_D)
    {
        *lmacReady4sleepEvent = MSK_F_FTDF_ON_OFF_REGMAP_LMACREADY4SLEEP_D;

        /* If lmac ready 4 sleep, call respective callback, after disabling the interrupt */
        if (FTDF_GET_FIELD(ON_OFF_REGMAP_LMACREADY4SLEEP) == 1)
        {
            volatile uint32_t *lmacCtrlMask = FTDF_GET_REG_ADDR(ON_OFF_REGMAP_LMAC_CONTROL_MASK);
            *lmacCtrlMask &= ~MSK_F_FTDF_ON_OFF_REGMAP_LMACREADY4SLEEP_M;
            FTDF_LMACREADY4SLEEP_CB(FTDF_TRUE, 0);
        }
    }

#endif

    // sync timestamp event
    if (*symbolTimeThrEvent & MSK_F_FTDF_ON_OFF_REGMAP_SYNCTIMESTAMP_E)
    {
#ifdef SIMULATOR
        *symbolTimeThrEvent &= ~MSK_F_FTDF_ON_OFF_REGMAP_SYNCTIMESTAMP_E;
#else
        *symbolTimeThrEvent  = MSK_F_FTDF_ON_OFF_REGMAP_SYNCTIMESTAMP_E;
#endif

        FTDF_SET_FIELD(ON_OFF_REGMAP_SYNCTIMESTAMPENA, 0);
#ifndef FTDF_LITE
#ifndef FTDF_NO_CSL
        FTDF_oldLeEnabled = FTDF_FALSE;

        if (FTDF_wakeUpEnableLe)
        {
            FTDF_pib.leEnabled  = FTDF_TRUE;
            FTDF_setLeEnabled();
            FTDF_wakeUpEnableLe = FTDF_FALSE;
        }

#endif /* FTDF_NO_CSL */

#ifndef FTDF_NO_TSCH

        if (FTDF_wakeUpEnableTsch)
        {
            FTDF_setTschEnabled();
        }

#endif /* FTDF_NO_TSCH */

        FTDF_restoreTxPendingTimer();
#endif /* !FTDF_LITE */
        FTDF_WAKE_UP_READY();
    }

    // miscellaneous event
    // - Non-TSCH mode: association timer
    // - TSCH mode: next active link timer
    if (*symbolTimeThrEvent & MSK_F_FTDF_ON_OFF_REGMAP_SYMBOLTIME2THR_E)
    {
#ifdef SIMULATOR
        *symbolTimeThrEvent &= ~MSK_F_FTDF_ON_OFF_REGMAP_SYMBOLTIME2THR_E;
#else
        *symbolTimeThrEvent  = MSK_F_FTDF_ON_OFF_REGMAP_SYMBOLTIME2THR_E;
#endif

#ifndef FTDF_LITE
#ifndef FTDF_NO_TSCH

        if (FTDF_pib.tschEnabled)
        {
            FTDF_tschProcessRequest();
        }
        else
#endif /* FTDF_NO_TSCH */
            if (FTDF_reqCurrent &&
                FTDF_reqCurrent->msgId == FTDF_ASSOCIATE_REQUEST)
            {
                FTDF_AssocAdmin *assocAdmin = &FTDF_aa;

                // macResponseWaitTime expired
                assocAdmin->dataR = FTDF_TRUE;

                FTDF_sendAssociateDataRequest();
            }

#endif /* !FTDF_LITE */
    }

    // pending queue symbol timer event
    if (*symbolTimeThrEvent & MSK_F_FTDF_ON_OFF_REGMAP_SYMBOLTIMETHR_E)
    {
#ifdef SIMULATOR
        *symbolTimeThrEvent &= ~MSK_F_FTDF_ON_OFF_REGMAP_SYMBOLTIMETHR_E;
#else
        *symbolTimeThrEvent  = MSK_F_FTDF_ON_OFF_REGMAP_SYMBOLTIMETHR_E;
#endif

#ifndef FTDF_LITE
        FTDF_removeTxPendingTimer(NULL);
#endif /* !FTDF_LITE */
    }
}

#ifndef FTDF_LITE
FTDF_Status FTDF_sendFrame(FTDF_ChannelNumber   channel,
                           FTDF_FrameHeader    *frameHeader,
                           FTDF_SecurityHeader *securityHeader,
                           FTDF_Octet          *txPtr,
                           FTDF_DataLength      payloadSize,
                           FTDF_Octet          *payload)
{
    FTDF_Octet     *txBufPtr       = (FTDF_Octet *) FTDF_GET_REG_ADDR(RETENTION_RAM_TX_FIFO);

    FTDF_DataLength micLength      = FTDF_getMicLength(securityHeader->securityLevel);
    FTDF_DataLength phyPayloadSize = (txPtr - txBufPtr) - 1 + payloadSize + micLength + FTDF_FCS_LENGTH;

    if (phyPayloadSize > (FTDF_BUFFER_LENGTH - 1))
    {
        return FTDF_FRAME_TOO_LONG;
    }

    *txBufPtr = phyPayloadSize;

    FTDF_Octet *privPtr = txPtr;

    int         n;

    for (n = 0; n < payloadSize; n++)
    {
        *txPtr++ = *payload++;
    }

    FTDF_Status status = FTDF_secureFrame(txBufPtr,
                                          privPtr,
                                          frameHeader,
                                          securityHeader);

    if (status != FTDF_SUCCESS)
    {
        return status;
    }

    FTDF_Bitmap8       options   = frameHeader->options;

    volatile uint32_t *metaData0 = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_0, FTDF_TX_DATA_BUFFER);
    volatile uint32_t *metaData1 = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_1, FTDF_TX_DATA_BUFFER);

    uint16_t           phyAttr   = (FTDF_pib.CCAMode & 0x3) | 0x08 | ((channel - 11) & 0x0F) << 4 |
                                   (FTDF_pib.TXPower & 0x03) << 8;

    metaData0  = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_0, FTDF_TX_DATA_BUFFER);
    metaData1  = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_1, FTDF_TX_DATA_BUFFER);

    *metaData0 =
        ((phyPayloadSize << OFF_F_FTDF_RETENTION_RAM_FRAME_LENGTH) & MSK_F_FTDF_RETENTION_RAM_FRAME_LENGTH) |
        ((phyAttr << OFF_F_FTDF_RETENTION_RAM_PHYATTR) & MSK_F_FTDF_RETENTION_RAM_PHYATTR) |
        ((frameHeader->frameType << OFF_F_FTDF_RETENTION_RAM_FRAMETYPE) & MSK_F_FTDF_RETENTION_RAM_FRAMETYPE) |
        MSK_F_FTDF_RETENTION_RAM_CSMACA_ENA |
        ((options & FTDF_OPT_ACK_REQUESTED) ? MSK_F_FTDF_RETENTION_RAM_ACKREQUEST : 0) |
        MSK_F_FTDF_RETENTION_RAM_CRC16_ENA;

    *metaData1 =
        ((frameHeader->SN << OFF_F_FTDF_RETENTION_RAM_MACSN) & MSK_F_FTDF_RETENTION_RAM_MACSN);

    uint32_t phyCsmaCaAttr = (FTDF_pib.CCAMode & 0x3) | ((channel - 11) & 0xf) << 4;
    FTDF_SET_FIELD(ON_OFF_REGMAP_PHYCSMACAATTR, phyCsmaCaAttr);

#ifndef FTDF_NO_CSL

    if (FTDF_pib.leEnabled == FTDF_TRUE)
    {
        if (frameHeader->dstAddrMode != FTDF_SHORT_ADDRESS)
        {
            return FTDF_NO_SHORT_ADDRESS;
        }

        // Clear CSMACA of data frame buffer
        *metaData0 &= ~MSK_F_FTDF_RETENTION_RAM_CSMACA_ENA;

        txPtr       = txBufPtr = ((FTDF_Octet *) FTDF_GET_REG_ADDR(RETENTION_RAM_TX_FIFO)) +
                                 (FTDF_BUFFER_LENGTH * FTDF_TX_WAKEUP_BUFFER);

        *txPtr++                    = 0x0d;
        *txPtr++                    = 0x2d;
        *txPtr++                    = 0x81;
        *txPtr++                    = frameHeader->SN;
        *(FTDF_PANId *) txPtr        = frameHeader->dstPANId;
        txPtr                      += 2;
        *(FTDF_ShortAddress *) txPtr = frameHeader->dstAddr.shortAddress;
        txPtr                      += 2;
        *txPtr++                    = 0x82;
        *txPtr++                    = 0x0e;

        metaData0                   = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_0, FTDF_TX_WAKEUP_BUFFER);
        metaData1                   = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_1, FTDF_TX_WAKEUP_BUFFER);
        volatile uint32_t *txPriority =
            FTDF_GET_REG_ADDR_INDEXED(ON_OFF_REGMAP_TX_PRIORITY, FTDF_TX_WAKEUP_BUFFER);

        *metaData0 =
            ((0x0d << OFF_F_FTDF_RETENTION_RAM_FRAME_LENGTH) & MSK_F_FTDF_RETENTION_RAM_FRAME_LENGTH) |
            ((phyAttr << OFF_F_FTDF_RETENTION_RAM_PHYATTR) & MSK_F_FTDF_RETENTION_RAM_PHYATTR) |
            ((FTDF_MULTIPURPOSE_FRAME << OFF_F_FTDF_RETENTION_RAM_FRAMETYPE) & MSK_F_FTDF_RETENTION_RAM_FRAMETYPE) |
            MSK_F_FTDF_RETENTION_RAM_CSMACA_ENA |
            MSK_F_FTDF_RETENTION_RAM_CRC16_ENA;

        *metaData1 =
            ((frameHeader->SN << OFF_F_FTDF_RETENTION_RAM_MACSN) & MSK_F_FTDF_RETENTION_RAM_MACSN);

        *txPriority = MSK_F_FTDF_ON_OFF_REGMAP_ISWAKEUP;
    }

#endif /* FTDF_NO_CSL */

    volatile uint32_t *txFlagSet = FTDF_GET_FIELD_ADDR(ON_OFF_REGMAP_TX_FLAG_SET);

#ifndef FTDF_NO_CSL

    if (FTDF_pib.leEnabled == FTDF_TRUE)
    {
        FTDF_Time curTime = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);
        FTDF_Time delta   = curTime - FTDF_rzTime;

        if (delta > 0x80000000)
        {
            // Receiving an wakeup frame sequence, delay sending until RZ has passed.
            FTDF_sendFramePending = frameHeader->dstAddr.shortAddress;
        }
        else
        {
            FTDF_Time   wakeupStartTime;
            FTDF_Period wakeupPeriod;

            FTDF_criticalVar();
            FTDF_enterCritical();

            FTDF_getWakeupParams(frameHeader->dstAddr.shortAddress, &wakeupStartTime, &wakeupPeriod);

            FTDF_txInProgress = FTDF_TRUE;
            FTDF_SET_FIELD(ON_OFF_REGMAP_MACCSLSTARTSAMPLETIME, wakeupStartTime);
            FTDF_SET_FIELD(ON_OFF_REGMAP_MACWUPERIOD, wakeupPeriod);

            *txFlagSet |= ((1 << FTDF_TX_DATA_BUFFER) | (1 << FTDF_TX_WAKEUP_BUFFER));

            FTDF_exitCritical();
        }
    }
    else
#endif /* FTDF_NO_CSL */
        if (!FTDF_pib.tschEnabled)
        {
            *txFlagSet |= (1 << FTDF_TX_DATA_BUFFER);
//                SetWord16(P2_SET_DATA_REG, (1 << 3));
//                        SetWord16(P23_MODE_REG, 0x300); // SW trigger - output
//                        for (volatile int k = 0; k < 100; k++) {
//                        }
//                        SetWord16(P23_MODE_REG, 0x000);// SW trigger - high Z


        }

    return FTDF_SUCCESS;
}

#if !defined(FTDF_NO_CSL) || !defined(FTDF_NO_TSCH)
FTDF_Status FTDF_sendAckFrame(FTDF_FrameHeader    *frameHeader,
                              FTDF_SecurityHeader *securityHeader,
                              FTDF_Octet          *txPtr)
{
    FTDF_Octet     *txBufPtr       = ((FTDF_Octet *) FTDF_GET_REG_ADDR(RETENTION_RAM_TX_FIFO)) +
                                     2 * FTDF_BUFFER_LENGTH;
    FTDF_DataLength micLength      = FTDF_getMicLength(securityHeader->securityLevel);
    FTDF_DataLength phyPayloadSize = (txPtr - txBufPtr) - 1 + micLength + FTDF_FCS_LENGTH;

    *txBufPtr = phyPayloadSize;

    FTDF_Status status = FTDF_secureFrame(txBufPtr,
                                          txPtr,
                                          frameHeader,
                                          securityHeader);

    if (status != FTDF_SUCCESS)
    {
        return status;
    }

    volatile uint32_t *metaData0  = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_0, FTDF_TX_ACK_BUFFER);
    volatile uint32_t *metaData1  = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_1, FTDF_TX_ACK_BUFFER);
    volatile uint32_t *txPriority = FTDF_GET_REG_ADDR_INDEXED(ON_OFF_REGMAP_TX_PRIORITY, FTDF_TX_ACK_BUFFER);

    uint16_t           phyAttr    =
        (FTDF_pib.CCAMode & 0x3) | 0x08 | (FTDF_GET_FIELD(ON_OFF_REGMAP_PHYRXATTR) & 0x00f0) |
        (FTDF_pib.TXPower & 0x03) << 8;

    *metaData0 =
        ((phyPayloadSize << OFF_F_FTDF_RETENTION_RAM_FRAME_LENGTH) & MSK_F_FTDF_RETENTION_RAM_FRAME_LENGTH) |
        ((phyAttr << OFF_F_FTDF_RETENTION_RAM_PHYATTR) & MSK_F_FTDF_RETENTION_RAM_PHYATTR) |
        ((FTDF_ACKNOWLEDGEMENT_FRAME << OFF_F_FTDF_RETENTION_RAM_FRAMETYPE) & MSK_F_FTDF_RETENTION_RAM_FRAMETYPE) |
        MSK_F_FTDF_RETENTION_RAM_CRC16_ENA;

    *metaData1 =
        ((frameHeader->SN << OFF_F_FTDF_RETENTION_RAM_MACSN) & MSK_F_FTDF_RETENTION_RAM_MACSN);

    *txPriority = 1;

    volatile uint32_t *txFlagSet = FTDF_GET_FIELD_ADDR(ON_OFF_REGMAP_TX_FLAG_SET);

#ifndef FTDF_NO_TSCH

    if (FTDF_pib.tschEnabled)
    {
        FTDF_criticalVar();
        FTDF_enterCritical();

        FTDF_Period txAckDelayVal = FTDF_GET_FIELD(ON_OFF_REGMAP_MACTSTXACKDELAYVAL);

        if (txAckDelayVal > 20)
        {
            *txFlagSet |= 1 << FTDF_TX_ACK_BUFFER;
        }

        FTDF_exitCritical();
    }
    else
#endif /* FTDF_NO_TSCH */
    {
        *txFlagSet |= 1 << FTDF_TX_ACK_BUFFER;
    }

    FTDF_pib.trafficCounters.txEnhAckFrmCnt++;

    return FTDF_SUCCESS;
}
#endif /* !FTDF_NO_CSL || !FTDF_NO_TSCH */
#endif /* !FTDF_LITE */

void FTDF_sendTransparentFrame(FTDF_DataLength    frameLength,
                               FTDF_Octet        *frame,
                               FTDF_ChannelNumber channel,
                               FTDF_PTI           pti,
                               FTDF_Boolean       cmsaSuppress)
{
    volatile uint32_t *metaData0 = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_0, FTDF_TX_DATA_BUFFER);
    volatile uint32_t *metaData1 = FTDF_GET_REG_ADDR_INDEXED(RETENTION_RAM_TX_META_DATA_1, FTDF_TX_DATA_BUFFER);

#if FTDF_TRANSPARENT_USE_WAIT_FOR_ACK
    FTDF_Boolean useAck = FTDF_FALSE;
    //FTDF_FrameHeader*         frameHeader    = &FTDF_fh;
    FTDF_FrameHeader frameHeader;
    FTDF_SN SN;
#endif
    uint16_t           phyAttr   = (FTDF_pib.CCAMode & 0x3) | 0x08 | ((channel - 11) & 0x0F) << 4 |
                                   (FTDF_pib.TXPower & 0x03) << 8;
#if FTDF_TRANSPARENT_USE_WAIT_FOR_ACK

    if (FTDF_transparentModeOptions & FTDF_TRANSPARENT_WAIT_FOR_ACK)
    {
        FTDF_getFrameHeader(frame, &frameHeader);

        if (frameHeader.options & FTDF_OPT_ACK_REQUESTED)
        {
            useAck = FTDF_TRUE;
        }

        SN = frameHeader.SN;
    }

#endif

    *metaData0 =
        ((frameLength << OFF_F_FTDF_RETENTION_RAM_FRAME_LENGTH) & MSK_F_FTDF_RETENTION_RAM_FRAME_LENGTH) |
        ((phyAttr << OFF_F_FTDF_RETENTION_RAM_PHYATTR) & MSK_F_FTDF_RETENTION_RAM_PHYATTR) |
        (((*frame & 0x7) << OFF_F_FTDF_RETENTION_RAM_FRAMETYPE) & MSK_F_FTDF_RETENTION_RAM_FRAMETYPE) |
        ((cmsaSuppress) ? 0 : MSK_F_FTDF_RETENTION_RAM_CSMACA_ENA) |
#if FTDF_TRANSPARENT_USE_WAIT_FOR_ACK
        ((useAck) ? MSK_F_FTDF_RETENTION_RAM_ACKREQUEST : 0) |
#endif
        ((FTDF_transparentModeOptions &
          FTDF_TRANSPARENT_ENABLE_FCS_GENERATION) ? MSK_F_FTDF_RETENTION_RAM_CRC16_ENA : 0);

#if FTDF_TRANSPARENT_USE_WAIT_FOR_ACK

    if (useAck)
    {
        *metaData1 = ((SN << OFF_F_FTDF_RETENTION_RAM_MACSN) & MSK_F_FTDF_RETENTION_RAM_MACSN);
    }
    else
    {
        *metaData1 = ((0 << OFF_F_FTDF_RETENTION_RAM_MACSN) & MSK_F_FTDF_RETENTION_RAM_MACSN);
    }

#else
    *metaData1 =
        ((0 << OFF_F_FTDF_RETENTION_RAM_MACSN) & MSK_F_FTDF_RETENTION_RAM_MACSN);
#endif

    uint32_t phyCsmaCaAttr = (FTDF_pib.CCAMode & 0x3) | ((channel - 11) & 0xf) << 4;
    FTDF_SET_FIELD(ON_OFF_REGMAP_PHYCSMACAATTR, phyCsmaCaAttr);
#if dg_configCOEX_ENABLE_CONFIG
    hw_coex_update_ftdf_pti((hw_coex_pti_t) pti, NULL, true);
#endif
    volatile uint32_t *txFlagSet = FTDF_GET_FIELD_ADDR(ON_OFF_REGMAP_TX_FLAG_SET);
    *txFlagSet |= (1 << FTDF_TX_DATA_BUFFER);
}

void FTDF_initQueues(void)
{
#ifndef FTDF_LITE
    FTDF_initQueue(&FTDF_freeQueue);
    FTDF_initQueue(&FTDF_reqQueue);

    int n;

    for (n = 0; n < FTDF_NR_OF_REQ_BUFFERS; n++)
    {
        FTDF_queueBufferHead(&FTDF_reqBuffers[ n ], &FTDF_freeQueue);

        FTDF_txPendingList[ n ].addr.extAddress = 0xFFFFFFFFFFFFFFFFLL;
        FTDF_txPendingList[ n ].addrMode        = FTDF_NO_ADDRESS;
        FTDF_txPendingList[ n ].PANId           = 0xFFFF;
        FTDF_initQueue(&FTDF_txPendingList[ n ].queue);

        FTDF_txPendingTimerList[ n ].free = FTDF_TRUE;
        FTDF_txPendingTimerList[ n ].next = NULL;
    }

    FTDF_txPendingTimerHead = FTDF_txPendingTimerList;
    FTDF_txPendingTimerTime = 0;
#endif /* !FTDF_LITE */
#ifndef FTDF_PHY_API
    FTDF_reqCurrent         = NULL;
#endif
}

#ifndef FTDF_LITE
void FTDF_initQueue(FTDF_Queue *queue)
{
    queue->head.next = (FTDF_Buffer *) &queue->tail;
    queue->head.prev = NULL;
    queue->tail.next = NULL;
    queue->tail.prev = (FTDF_Buffer *) &queue->head;
}

void FTDF_queueBufferHead(FTDF_Buffer *buffer, FTDF_Queue *queue)
{
    FTDF_Buffer *next = queue->head.next;

    queue->head.next    = buffer;
    next->header.prev   = buffer;
    buffer->header.next = next;
    buffer->header.prev = (FTDF_Buffer *) &queue->head;
}

FTDF_Buffer *FTDF_dequeueBufferTail(FTDF_Queue *queue)
{
    FTDF_Buffer *buffer = queue->tail.prev;

    if (buffer->header.prev == NULL)
    {
        return NULL;
    }

    queue->tail.prev                 = buffer->header.prev;
    buffer->header.prev->header.next = (FTDF_Buffer *) &queue->tail;

    return buffer;
}

FTDF_Status FTDF_queueReqHead(FTDF_MsgBuffer *request, FTDF_Queue *queue)
{
    FTDF_Buffer *buffer = FTDF_dequeueBufferTail(&FTDF_freeQueue);

    if (buffer == NULL)
    {
        return FTDF_TRANSACTION_OVERFLOW;
    }

    FTDF_Buffer *next = queue->head.next;

    queue->head.next    = buffer;
    next->header.prev   = buffer;
    buffer->header.next = next;
    buffer->header.prev = (FTDF_Buffer *) &queue->head;
    buffer->request     = request;

    return FTDF_SUCCESS;
}

FTDF_MsgBuffer *FTDF_dequeueReqTail(FTDF_Queue *queue)
{
    FTDF_Buffer *buffer = queue->tail.prev;

    if (buffer->header.prev == NULL)
    {
        return NULL;
    }

    queue->tail.prev                 = buffer->header.prev;
    buffer->header.prev->header.next = (FTDF_Buffer *) &queue->tail;

    FTDF_MsgBuffer *request = buffer->request;

    FTDF_queueBufferHead(buffer, &FTDF_freeQueue);

    return request;
}

FTDF_MsgBuffer *FTDF_dequeueByHandle(FTDF_Handle handle, FTDF_Queue *queue)
{
    FTDF_Buffer *buffer = queue->head.next;

    while (buffer->header.next != NULL)
    {
        if (buffer->request &&
            buffer->request->msgId == FTDF_DATA_REQUEST &&
            ((FTDF_DataRequest *) buffer->request)->msduHandle == handle)
        {
            buffer->header.prev->header.next = buffer->header.next;
            buffer->header.next->header.prev = buffer->header.prev;

            FTDF_MsgBuffer *request = buffer->request;

            FTDF_queueBufferHead(buffer, &FTDF_freeQueue);

            return request;
        }

        buffer = buffer->header.next;
    }

    return NULL;
}

FTDF_MsgBuffer *FTDF_dequeueByRequest(FTDF_MsgBuffer *request, FTDF_Queue *queue)
{
    FTDF_Buffer *buffer = queue->head.next;

    while (buffer->header.next != NULL)
    {
        if (buffer->request == request)
        {
            buffer->header.prev->header.next = buffer->header.next;
            buffer->header.next->header.prev = buffer->header.prev;

            FTDF_MsgBuffer *req = buffer->request;

            FTDF_queueBufferHead(buffer, &FTDF_freeQueue);

            return req;
        }

        buffer = buffer->header.next;
    }

    return NULL;
}

FTDF_Boolean FTDF_isQueueEmpty(FTDF_Queue *queue)
{
    if (queue->head.next->header.next == NULL)
    {
        return FTDF_TRUE;
    }
    else
    {
        return FTDF_FALSE;
    }
}

static FTDF_PendingTL *FTDF_findFreePendingTimer(void)
{
    uint8_t i;

    for (i = 0; i < FTDF_NR_OF_REQ_BUFFERS; i++)
    {
        if (FTDF_txPendingTimerList[ i ].free == FTDF_TRUE)
        {
            break;
        }
    }

    return &FTDF_txPendingTimerList[ i ];
}

void FTDF_addTxPendingTimer(FTDF_MsgBuffer *request, uint8_t pendListNr, FTDF_Time delta, void (* func)(
                                FTDF_PendingTL *))
{
    FTDF_criticalVar();
    FTDF_enterCritical();

    FTDF_PendingTL *ptr       = FTDF_txPendingTimerHead;
    FTDF_Time       timestamp = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);

    if (ptr->free == FTDF_FALSE)
    {
        while (ptr)
        {
            ptr->delta -= timestamp - FTDF_txPendingTimerLT;
            ptr         = ptr->next;
        }
    }

    FTDF_txPendingTimerLT = timestamp;
    ptr                   = FTDF_txPendingTimerHead;

    if (ptr->free == FTDF_TRUE)
    {
        ptr->free       = FTDF_FALSE;
        ptr->next       = NULL;
        ptr->request    = request;
        ptr->delta      = delta;
        ptr->pendListNr = pendListNr;
        ptr->func       = func;

        FTDF_SET_FIELD(ON_OFF_REGMAP_SYMBOLTIMETHR, delta + timestamp);
        FTDF_txPendingTimerTime = delta + timestamp;
        FTDF_exitCritical();
        return;
    }

    if (ptr->delta > delta)
    {
        FTDF_txPendingTimerHead             = FTDF_findFreePendingTimer();
        FTDF_txPendingTimerHead->free       = FTDF_FALSE;
        FTDF_txPendingTimerHead->next       = ptr;
        FTDF_txPendingTimerHead->request    = request;
        FTDF_txPendingTimerHead->delta      = delta;
        FTDF_txPendingTimerHead->pendListNr = pendListNr;
        FTDF_txPendingTimerHead->func       = func;

        FTDF_SET_FIELD(ON_OFF_REGMAP_SYMBOLTIMETHR, delta + timestamp);
        FTDF_txPendingTimerTime = delta + timestamp;
        FTDF_exitCritical();
        return;
    }
    else if (ptr->delta == delta)
    {
        delta++;
    }

    FTDF_PendingTL *prev;

    while (ptr->next)
    {
        prev = ptr;
        ptr  = ptr->next;

        if (ptr->delta == delta)
        {
            delta++;
        }

        if (prev->delta < delta && ptr->delta > delta)
        {
            prev->next       = FTDF_findFreePendingTimer();
            prev->next->next = ptr;
            ptr              = prev->next;
            ptr->free        = FTDF_FALSE;
            ptr->request     = request;
            ptr->delta       = delta;
            ptr->pendListNr  = pendListNr;
            ptr->func        = func;

            FTDF_exitCritical();
            return;
        }
    }

    ptr->next       = FTDF_findFreePendingTimer();
    ptr             = ptr->next;
    ptr->free       = FTDF_FALSE;
    ptr->next       = NULL;
    ptr->request    = request;
    ptr->delta      = delta;
    ptr->pendListNr = pendListNr;
    ptr->func       = func;

    FTDF_exitCritical();
}

void FTDF_removeTxPendingTimer(FTDF_MsgBuffer *request)
{
    FTDF_criticalVar();
    FTDF_enterCritical();

    FTDF_PendingTL *ptr       = FTDF_txPendingTimerHead;
    FTDF_Time       timestamp = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);

    if (ptr->free == FTDF_TRUE)
    {
        FTDF_SET_FIELD(ON_OFF_REGMAP_SYMBOLTIMETHR, timestamp - 1);
        FTDF_txPendingTimerTime = timestamp - 1;
        FTDF_exitCritical();
        return;
    }

    while (ptr)
    {
        ptr->delta -= timestamp - FTDF_txPendingTimerLT;
        ptr         = ptr->next;
    }

    FTDF_txPendingTimerLT = timestamp;
    ptr                   = FTDF_txPendingTimerHead;

    if (!request || ptr->request == request)
    {
        if (ptr->next)
        {
            FTDF_PendingTL *temp = ptr;

            if (ptr->next->delta < 75)
            {
                while (temp)
                {
                    temp->delta += 75;
                    temp         = temp->next;
                }
            }

            FTDF_SET_FIELD(ON_OFF_REGMAP_SYMBOLTIMETHR, timestamp + ptr->next->delta);
            FTDF_txPendingTimerTime = timestamp + ptr->next->delta;
            FTDF_txPendingTimerHead = ptr->next;

            ptr->free               = FTDF_TRUE;
            ptr->next               = NULL;
        }
        else
        {
            FTDF_SET_FIELD(ON_OFF_REGMAP_SYMBOLTIMETHR, timestamp - 1);
            FTDF_txPendingTimerTime = timestamp - 1;

            ptr->free = FTDF_TRUE;
            ptr->next = NULL;
        }

        FTDF_exitCritical();

        if (!request)
        {
            if (ptr->func)
            {
                ptr->func(ptr);
            }
        }

        return;
    }

    FTDF_PendingTL *prev = ptr;

    while (ptr->next)
    {
        prev = ptr;
        ptr  = ptr->next;

        if (ptr->request == request)
        {
            prev->next = ptr->next;
            ptr->free  = FTDF_TRUE;
            ptr->next  = NULL;

            FTDF_exitCritical();
            return;
        }
    }

    FTDF_SET_FIELD(ON_OFF_REGMAP_SYMBOLTIMETHR, timestamp - 1);
    FTDF_txPendingTimerTime = timestamp - 1;
    FTDF_exitCritical();
}

void FTDF_restoreTxPendingTimer(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_SYMBOLTIMETHR, FTDF_txPendingTimerTime);
}

FTDF_Boolean FTDF_getTxPendingTimerHead(FTDF_Time *time)
{
    FTDF_PendingTL *ptr = FTDF_txPendingTimerHead;

    if (ptr->free == FTDF_TRUE)
    {
        return FTDF_FALSE;
    }

    *time = FTDF_txPendingTimerTime;
    return FTDF_TRUE;
}

#ifndef FTDF_NO_TSCH
void FTDF_processKeepAliveTimerExp(FTDF_PendingTL *ptr)
{
    FTDF_RemoteRequest *remoteRequest = (FTDF_RemoteRequest *)ptr->request;

    remoteRequest->msgId    = FTDF_REMOTE_REQUEST;
    remoteRequest->remoteId = FTDF_REMOTE_KEEP_ALIVE;
    remoteRequest->dstAddr  = FTDF_neighborTable[ ptr->pendListNr ].dstAddr;

    FTDF_processRemoteRequest(remoteRequest);
}
#endif /* FTDF_NO_TSCH */

void FTDF_sendTransactionExpired(FTDF_PendingTL *ptr)
{
    FTDF_MsgBuffer *req =
        FTDF_dequeueByRequest(ptr->request, &FTDF_txPendingList[ ptr->pendListNr ].queue);

    if (!req)
    {
        return;
    }

    if (FTDF_isQueueEmpty(&FTDF_txPendingList[ ptr->pendListNr ].queue))
    {
#ifndef FTDF_NO_TSCH

        if (FTDF_pib.tschEnabled)
        {
            FTDF_txPendingList[ ptr->pendListNr ].addr.shortAddress = 0xfffe;
        }
        else
#endif /* FTDF_NO_TSCH */
        {
            FTDF_txPendingList[ ptr->pendListNr ].addrMode = FTDF_NO_ADDRESS;
        }
    }

    switch (req->msgId)
    {
    case FTDF_DATA_REQUEST:
    {
        FTDF_DataRequest *dataRequest = (FTDF_DataRequest *)req;

        FTDF_sendDataConfirm(dataRequest, FTDF_TRANSACTION_EXPIRED, 0, 0, 0, NULL);

        break;
    }

    case FTDF_ASSOCIATE_REQUEST:
    {
        FTDF_AssociateRequest *associateRequest = (FTDF_AssociateRequest *)req;

        FTDF_sendAssociateConfirm(associateRequest, FTDF_TRANSACTION_EXPIRED, 0xffff);

        break;
    }

    case FTDF_ASSOCIATE_RESPONSE:
    {
        FTDF_AssociateResponse *assocResp = (FTDF_AssociateResponse *)req;

        FTDF_Address srcAddr, dstAddr;
        srcAddr.extAddress = FTDF_pib.extAddress;
        dstAddr.extAddress = assocResp->deviceAddress;

        FTDF_sendCommStatusIndication(req, FTDF_TRANSACTION_EXPIRED,
                                      FTDF_pib.PANId,
                                      FTDF_EXTENDED_ADDRESS,
                                      srcAddr,
                                      FTDF_EXTENDED_ADDRESS,
                                      dstAddr,
                                      assocResp->securityLevel,
                                      assocResp->keyIdMode,
                                      assocResp->keySource,
                                      assocResp->keyIndex);

        break;
    }

    case FTDF_DISASSOCIATE_REQUEST:
    {
        FTDF_DisassociateRequest *disReq = (FTDF_DisassociateRequest *)req;

        FTDF_sendDisassociateConfirm(disReq, FTDF_TRANSACTION_EXPIRED);

        break;
    }

    case FTDF_BEACON_REQUEST:
    {
        FTDF_BeaconRequest *beaconRequest = (FTDF_BeaconRequest *)req;

        FTDF_sendBeaconConfirm(beaconRequest, FTDF_TRANSACTION_EXPIRED);

        break;
    }
    }
}

#ifndef FTDF_NO_TSCH
void FTDF_resetKeepAliveTimer(FTDF_ShortAddress dstAddr)
{
    uint8_t n;

    for (n = 0; n < FTDF_NR_OF_NEIGHBORS; n++)
    {
        if (FTDF_neighborTable[ n ].dstAddr == dstAddr)
        {
            break;
        }
    }

    if (n == FTDF_NR_OF_NEIGHBORS)
    {
        return;
    }

    FTDF_removeTxPendingTimer((FTDF_MsgBuffer *)&FTDF_neighborTable[ n ].msg);

    FTDF_Time tsTimeslotLength = (FTDF_Time) FTDF_pib.timeslotTemplate.tsTimeslotLength / 16;
    FTDF_Time delta            = tsTimeslotLength * FTDF_neighborTable[ n ].period;

    FTDF_addTxPendingTimer((FTDF_MsgBuffer *)&FTDF_neighborTable[ n ].msg, n, delta, FTDF_processKeepAliveTimerExp);
}
#endif /* FTDF_NO_TSCH */
#endif /* !FTDF_LITE */

void FTDF_enableTransparentMode(FTDF_Boolean  enable,
                                FTDF_Bitmap32 options)
{
#ifndef FTDF_LITE

    if (FTDF_pib.leEnabled == FTDF_TRUE ||
        FTDF_pib.tschEnabled == FTDF_TRUE)
    {
        return;
    }

#endif /* !FTDF_LITE */

    FTDF_transparentMode        = enable;
    FTDF_transparentModeOptions = options;

    if (enable)
    {
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSFRMTYPE,
                       (options & FTDF_TRANSPARENT_PASS_ALL_FRAME_TYPES));
        FTDF_SET_FIELD(ON_OFF_REGMAP_DISRXACKREQUESTCA, (options & FTDF_TRANSPARENT_AUTO_ACK ? 0 : 1));
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSCRCERROR, (options & FTDF_TRANSPARENT_PASS_CRC_ERROR ? 1 : 0));
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSRESFRAMEVERSION,
                       (options & FTDF_TRANSPARENT_PASS_ALL_FRAME_VERSION ? 1 : 0));
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSWRONGDPANID,
                       (options & FTDF_TRANSPARENT_PASS_ALL_PAN_ID ? 1 : 0));
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSWRONGDADDR, (options & FTDF_TRANSPARENT_PASS_ALL_ADDR ? 1 : 0));
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSBEACONWRONGPANID,
                       (options & FTDF_TRANSPARENT_PASS_ALL_BEACON ? 1 : 0));
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSTOPANCOORDINATOR,
                       (options & FTDF_TRANSPARENT_PASS_ALL_NO_DEST_ADDR ? 1 : 0));
    }
    else
    {
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSFRMTYPE, 0);
        FTDF_SET_FIELD(ON_OFF_REGMAP_DISRXACKREQUESTCA, 0);
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSCRCERROR, 0);
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSRESFRAMEVERSION, 0);
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSWRONGDPANID, 0);
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSWRONGDADDR, 0);
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSBEACONWRONGPANID, 0);
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACALWAYSPASSTOPANCOORDINATOR, 0);
    }
}

#if FTDF_DBG_BUS_ENABLE
void FTDF_checkDbgMode(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_DBG_CONTROL, FTDF_dbgMode);

    if (FTDF_dbgMode)
    {
        FTDF_DBG_BUS_GPIO_CONFIG();
    }
}

void FTDF_setDbgMode(FTDF_DbgMode dbgMode)
{
    FTDF_dbgMode = dbgMode;
    FTDF_checkDbgMode();
}
#endif /* FTDF_DBG_BUS_ENABLE */

#ifndef FTDF_LITE
#ifndef FTDF_NO_CSL
void FTDF_setPeerCslTiming(FTDF_IEList *headerIEList, FTDF_Time timeStamp)
{
    if (FTDF_reqCurrent->msgId != FTDF_DATA_REQUEST)
    {
        // Only use the CSL timing of data frame acks
        return;
    }

    FTDF_DataRequest *dataRequest = (FTDF_DataRequest *) FTDF_reqCurrent;
    FTDF_ShortAddress dstAddr     = dataRequest->dstAddr.shortAddress;

    if (dataRequest->dstAddrMode != FTDF_SHORT_ADDRESS ||
        dstAddr == 0xffff)
    {
        return;
    }

    int n;

    // Search for an existing entry
    for (n = 0; n < FTDF_NR_OF_CSL_PEERS; n++)
    {
        if (FTDF_peerCslTiming[ n ].addr == dstAddr)
        {
            break;
        }
    }

    if (headerIEList == NULL)
    {
        if (n < FTDF_NR_OF_CSL_PEERS)
        {
            // Delete entry
            FTDF_peerCslTiming[ n ].addr = 0xffff;
        }

        return;
    }

    int ieNr = 0;

    while (ieNr < headerIEList->nrOfIEs &&
           headerIEList->IEs[ ieNr ].ID != 0x1a)
    {
        ieNr++;
    }

    if (ieNr == headerIEList->nrOfIEs)
    {
        return;
    }

    if (n == FTDF_NR_OF_CSL_PEERS)
    {
        // Search for an empty entry
        for (n = 0; n < FTDF_NR_OF_CSL_PEERS; n++)
        {
            if (FTDF_peerCslTiming[ n ].addr == 0xffff)
            {
                break;
            }
        }
    }

    if (n == FTDF_NR_OF_CSL_PEERS)
    {
        // No free entry, search for the least recently used entry
        FTDF_Time maxDelta = 0;
        int       lru      = 0;

        for (n = 0; n < FTDF_NR_OF_CSL_PEERS; n++)
        {
            FTDF_Time delta = timeStamp - FTDF_peerCslTiming[ n ].time;

            if (delta > maxDelta)
            {
                maxDelta = delta;
                lru      = n;
            }
        }

        n = lru;
    }

    FTDF_Period phase  = (*(FTDF_Period *)(headerIEList->IEs[ 0 ].content.raw + 0));
    FTDF_Period period = (*(FTDF_Period *)(headerIEList->IEs[ 0 ].content.raw + 2));

    FTDF_peerCslTiming[ n ].addr   = dstAddr;
    FTDF_peerCslTiming[ n ].time   = timeStamp - (phase * 10);
    FTDF_peerCslTiming[ n ].period = period;
}

void FTDF_getWakeupParams(FTDF_ShortAddress dstAddr,
                          FTDF_Time        *wakeupStartTime,
                          FTDF_Period      *wakeupPeriod)
{
    int n;

    for (n = 0; n < FTDF_NR_OF_CSL_PEERS; n++)
    {
        if (FTDF_peerCslTiming[ n ].addr == dstAddr)
        {
            break;
        }
    }

    FTDF_Time curTime = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);

    if (dstAddr == 0xffff ||
        n == FTDF_NR_OF_CSL_PEERS)
    {
        *wakeupStartTime = curTime + 5;
        *wakeupPeriod    = FTDF_pib.CSLMaxPeriod;

        return;
    }

    FTDF_Time peerTime   = FTDF_peerCslTiming[ n ].time;
    FTDF_Time peerPeriod = FTDF_peerCslTiming[ n ].period * 10;
    FTDF_Time delta      = curTime - peerTime;

    if (delta > (uint32_t)(FTDF_pib.CSLMaxAgeRemoteInfo * 10))
    {
        *wakeupStartTime = curTime + 5;
        *wakeupPeriod    = FTDF_pib.CSLMaxPeriod;

        return;
    }

    FTDF_Time wStart = peerTime + (((delta / peerPeriod) + 1) * peerPeriod) - FTDF_pib.CSLSyncTxMargin;
    delta = wStart - curTime;

    if (delta < 3 || delta > 0x80000000)    // A delta larger than 0x80000000 is assumed a negative delta
    {
        wStart += peerPeriod;
    }

    *wakeupPeriod    = (FTDF_pib.CSLSyncTxMargin / 10) * 2;
    *wakeupStartTime = wStart;
}

void FTDF_setCslSampleTime(void)
{
    FTDF_Time CSLPeriod = FTDF_pib.CSLPeriod * 10;

    FTDF_criticalVar();
    FTDF_enterCritical();

    FTDF_Time curTime = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);
    FTDF_Time delta   = (curTime - FTDF_startCslSampleTime);

    // A delta larger than 0x80000000 is assumed a negative delta, in this case the sample time does
    // not need to be updated.
    if (delta < 0x80000000)
    {
        if (delta < CSLPeriod)
        {
            FTDF_startCslSampleTime += CSLPeriod;

            if (delta < 3)
            {
                // To avoid to set the CSL sample time to a time stamp in the past set it to a sample period later
                // if the next sample would be within 3 symbols.
                FTDF_startCslSampleTime += CSLPeriod;
            }
        }
        else
        {
            FTDF_startCslSampleTime = FTDF_startCslSampleTime + ((delta / CSLPeriod) + 1) * CSLPeriod;
        }

        FTDF_SET_FIELD(ON_OFF_REGMAP_MACCSLSTARTSAMPLETIME, FTDF_startCslSampleTime);
    }

    FTDF_exitCritical();
}
#endif /* FTDF_NO_CSL */
#endif /* !FTDF_LITE */

FTDF_Time64 FTDF_getCurTime64(void)
{
    FTDF_Time newTime = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);

    if (newTime < FTDF_curTime[ 0 ])
    {
        FTDF_curTime[ 1 ]++;
    }

    FTDF_curTime[ 0 ] = newTime;

    return *(FTDF_Time64 *)FTDF_curTime;
}

void FTDF_initCurTime64(void)
{
    FTDF_curTime[ 0 ] = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);
    FTDF_curTime[ 1 ] = 0;
}

void FTDF_getExtAddress(void)
{
    uint32_t *extAddress = (uint32_t *) &FTDF_pib.extAddress;
    extAddress[ 0 ] = FTDF_GET_FIELD(ON_OFF_REGMAP_AEXTENDEDADDRESS_L);
    extAddress[ 1 ] = FTDF_GET_FIELD(ON_OFF_REGMAP_AEXTENDEDADDRESS_H);
}

void FTDF_setExtAddress(void)
{
    uint32_t *extAddress = (uint32_t *) &FTDF_pib.extAddress;
    FTDF_SET_FIELD(ON_OFF_REGMAP_AEXTENDEDADDRESS_L, extAddress[ 0 ]);
    FTDF_SET_FIELD(ON_OFF_REGMAP_AEXTENDEDADDRESS_H, extAddress[ 1 ]);
}

void FTDF_getAckWaitDuration(void)
{
    FTDF_pib.ackWaitDuration = FTDF_GET_FIELD(ON_OFF_REGMAP_MACACKWAITDURATION);
}

#ifndef FTDF_LITE
void FTDF_getEnhAckWaitDuration(void)
{
    FTDF_pib.enhAckWaitDuration = FTDF_GET_FIELD(ON_OFF_REGMAP_MACENHACKWAITDURATION);
}

void FTDF_setEnhAckWaitDuration(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACENHACKWAITDURATION, FTDF_pib.enhAckWaitDuration);
}

void FTDF_getImplicitBroadcast(void)
{
    FTDF_pib.implicitBroadcast = FTDF_GET_FIELD(ON_OFF_REGMAP_MACIMPLICITBROADCAST);
}

void FTDF_setImplicitBroadcast(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACIMPLICITBROADCAST, FTDF_pib.implicitBroadcast);
}
#endif /* !FTDF_LITE */

void FTDF_setShortAddress(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACSHORTADDRESS, FTDF_pib.shortAddress);
}

#ifndef FTDF_LITE
void FTDF_setSimpleAddress(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACSIMPLEADDRESS, FTDF_pib.simpleAddress);
}
#endif /* !FTDF_LITE */

void FTDF_getRxOnWhenIdle(void)
{
    FTDF_pib.rxOnWhenIdle = FTDF_GET_FIELD(ON_OFF_REGMAP_RXALWAYSON);
}

void FTDF_setRxOnWhenIdle(void)
{
#if dg_configCOEX_ENABLE_CONFIG
    /* We do not force decision here. It will be automatically made when FTDF begins
     * transaction.
     */
    hw_coex_update_ftdf_pti((hw_coex_pti_t) FTDF_getRxPti(), NULL, false);
#endif
    FTDF_SET_FIELD(ON_OFF_REGMAP_RXENABLE, 0);
    FTDF_SET_FIELD(ON_OFF_REGMAP_RXALWAYSON, FTDF_pib.rxOnWhenIdle);
    FTDF_SET_FIELD(ON_OFF_REGMAP_RXENABLE, 1);

}

void FTDF_getPANId(void)
{
    FTDF_pib.PANId = FTDF_GET_FIELD(ON_OFF_REGMAP_MACPANID);
}

void FTDF_setPANId(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACPANID, FTDF_pib.PANId);
}

void FTDF_getCurrentChannel(void)
{
    FTDF_pib.currentChannel = ((FTDF_GET_FIELD(ON_OFF_REGMAP_PHYRXATTR) & 0x00f0) >> 4) + 11;
}

void FTDF_setCurrentChannel(void)
{
    uint32_t phyAckAttr = 0x08 | ((FTDF_pib.currentChannel - 11) & 0xf) << 4 | (FTDF_pib.TXPower & 0x3) << 8;

    FTDF_SET_FIELD(ON_OFF_REGMAP_PHYRXATTR, (((FTDF_pib.currentChannel - 11) & 0xf) << 4));
    FTDF_SET_FIELD(ON_OFF_REGMAP_PHYACKATTR, phyAckAttr);
}

void FTDF_getMaxFrameTotalWaitTime(void)
{
    FTDF_pib.maxFrameTotalWaitTime = FTDF_GET_FIELD(ON_OFF_REGMAP_MACMAXFRAMETOTALWAITTIME);
}

void FTDF_setMaxFrameTotalWaitTime(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACMAXFRAMETOTALWAITTIME, FTDF_pib.maxFrameTotalWaitTime);
}

void FTDF_setMaxCSMABackoffs(void)
{
#ifndef FTDF_LITE

    if (FTDF_pib.leEnabled == FTDF_FALSE && FTDF_pib.tschEnabled == FTDF_FALSE)
#endif /* !FTDF_LITE */
    {
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACMAXCSMABACKOFFS, FTDF_pib.maxCSMABackoffs);
    }
}

void FTDF_setMaxBE(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACMAXBE, FTDF_pib.maxBE);
}

void FTDF_setMinBE(void)
{
#ifndef FTDF_LITE

    if (FTDF_pib.leEnabled == FTDF_FALSE && FTDF_pib.tschEnabled == FTDF_FALSE)
#endif /* !FTDF_LITE */
    {
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACMINBE, FTDF_pib.minBE);
    }
}

#ifndef FTDF_LITE
#ifndef FTDF_NO_CSL
void FTDF_setLeEnabled(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACCSLSAMPLEPERIOD, 66);
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACCSLDATAPERIOD, 66);
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACCSLMARGINRZ, 1);

    if (FTDF_pib.leEnabled)
    {
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACMAXCSMABACKOFFS, 0);
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACMINBE, 0);

        if (FTDF_oldLeEnabled == FTDF_FALSE)
        {
            if (FTDF_wakeUpEnableLe == FTDF_FALSE)
            {
                FTDF_startCslSampleTime = FTDF_GET_FIELD(ON_OFF_REGMAP_SYMBOLTIMESNAPSHOTVAL);
                FTDF_setCslSampleTime();
            }
            else
            {
                FTDF_SET_FIELD(ON_OFF_REGMAP_MACCSLSTARTSAMPLETIME, FTDF_startCslSampleTime);
            }
        }
    }
    else
    {
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACMAXCSMABACKOFFS, FTDF_pib.maxCSMABackoffs);
        FTDF_SET_FIELD(ON_OFF_REGMAP_MACMINBE, FTDF_pib.minBE);
    }

    FTDF_SET_FIELD(ON_OFF_REGMAP_MACLEENABLED, FTDF_pib.leEnabled);

    FTDF_oldLeEnabled = FTDF_pib.leEnabled;
}

void FTDF_getCslFramePendingWaitT(void)
{
    FTDF_pib.CSLFramePendingWaitT = FTDF_GET_FIELD(ON_OFF_REGMAP_MACCSLFRAMEPENDINGWAITT);
}

void FTDF_setCslFramePendingWaitT(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACCSLFRAMEPENDINGWAITT, FTDF_pib.CSLFramePendingWaitT);
}
#endif /* FTDF_NO_CSL */
#endif /* !FTDF_LITE */

void FTDF_getLmacPmData(void)
{
    FTDF_pib.performanceMetrics.FCSErrorCount = FTDF_GET_FIELD(ON_OFF_REGMAP_MACFCSERRORCOUNT) +
                                                FTDF_lmacCounters.fcsErrorCnt;
}

void FTDF_getLmacTrafficCounters(void)
{
    FTDF_pib.trafficCounters.txStdAckFrmCnt   = FTDF_GET_FIELD(ON_OFF_REGMAP_MACTXSTDACKFRMCNT) +
                                                FTDF_lmacCounters.txStdAckCnt;
    FTDF_pib.trafficCounters.rxStdAckFrmOkCnt = FTDF_GET_FIELD(ON_OFF_REGMAP_MACRXSTDACKFRMOKCNT) +
                                                FTDF_lmacCounters.rxStdAckCnt;
}

void FTDF_getKeepPhyEnabled(void)
{
    FTDF_pib.keepPhyEnabled = FTDF_GET_FIELD(ON_OFF_REGMAP_KEEP_PHY_EN);
}

void FTDF_setKeepPhyEnabled(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_KEEP_PHY_EN, FTDF_pib.keepPhyEnabled);
}

#ifndef FTDF_LITE
#ifndef FTDF_NO_TSCH
void FTDF_setTimeslotTemplate(void)
{
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACTSTXACKDELAY, FTDF_pib.timeslotTemplate.tsTxAckDelay);
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACTSRXWAIT, FTDF_pib.timeslotTemplate.tsRxWait);
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACTSRXACKDELAY, FTDF_pib.timeslotTemplate.tsRxAckDelay);
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACTSACKWAIT, FTDF_pib.timeslotTemplate.tsAckWait);
    FTDF_SET_FIELD(ON_OFF_REGMAP_MACTSRXTX, FTDF_pib.timeslotTemplate.tsRxTx -
                   FTDF_PHYTRXWAIT - FTDF_PHYTXSTARTUP - FTDF_PHYTXLATENCY);
}
#endif /* FTDF_NO_TSCH */
#endif /* !FTDF_LITE */
