/*
 * MOST NetServices "Light" V3.2.7.0.1796 MultiInstance Patch
 *
 * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * You may also obtain this software under a propriety license from Microchip.
 * Please contact Microchip for further information.
 *
 */

/*!
 * \file
 * \brief Implementation of Application Message Classes
 *
 * \cond MNS_INTERNAL_DOC
 * \addtogroup  G_AMSMSG
 * @{
 */

/*------------------------------------------------------------------------------------------------*/
/* Includes                                                                                       */
/*------------------------------------------------------------------------------------------------*/
#include "mns_amsmessage.h"
#include "mns_dl.h"
#include "mns_misc.h"
#include "mns_trace.h"

#define SELF_RX     ((Amsg_IntMsgRx_t*)(void*)(self))
#define SELF_TX     ((Amsg_IntMsgTx_t*)(void*)(self))

#define AMSG_TX_BACKUP_ADDR_NONE    0U

/*------------------------------------------------------------------------------------------------*/
/* Prototypes                                                                                     */
/*------------------------------------------------------------------------------------------------*/
static Mns_AmsRx_ReceiveType_t Amsg_RxGetReceiveType(uint16_t destination_address);
static void Amsg_TxRestoreDestinationAddr(Mns_AmsTx_Msg_t *self);

/*------------------------------------------------------------------------------------------------*/
/* Tx Message                                                                                      */
/*------------------------------------------------------------------------------------------------*/
/*! \brief      Initializes aggregated objects
 *  \details    Needs to be called once before first usage. Call Amsg_TxHandleSetup() before 
 *              repeated usage. 
 *  \param      self          Reference to an internal Application Message Tx handle
 *  \param      info_ptr      Memory information required to free the object
 *  \param      free_fptr     Callback function which is invoked when the object is freed
 *  \param      free_inst_ptr The instance which is passed to free_fptr 
 */
void Amsg_TxCtor(Mns_AmsTx_Msg_t *self, void *info_ptr, Amsg_TxFreedCb_t free_fptr, void *free_inst_ptr)
{
    /* cleanup complete object */
    MISC_MEM_SET((void*)self, 0, sizeof(Amsg_IntMsgTx_t));

    /* reset default references
    SELF_TX->memory_ptr        = NULL;
    SELF_TX->memory_sz         = NULL;
    SELF_TX->memory_info_ptr   = NULL;

    SELF_TX->complete_fptr     = NULL; 
    SELF_TX->complete_inst_ptr = NULL;
    SELF_TX->complete_sia_fptr = NULL; 
    
    SELF_TX->backup_dest_address = AMSG_TX_BACKUP_ADDR_NONE;*/

    SELF_TX->info_ptr = info_ptr;
    SELF_TX->free_fptr = free_fptr;
    SELF_TX->free_inst_ptr = free_inst_ptr;
    SELF_TX->next_segment_cnt = 0xFFFFU;            /* start with TelId "4" */
    SELF_TX->temp_result = MNS_MSG_STAT_OK;
    SELF_TX->internal_status = AMSG_TX_INTRES_NONE;
    SELF_TX->ignore_wrong_target = false;

    Dln_Ctor(&SELF_TX->node, self);                 /* initialize node */
}

/*! \brief  Sets payload memory provided by memory management and updates data pointer and size
 *  \param  self            The instance
 *  \param  mem_ptr         Reference to the provided memory chunk
 *  \param  mem_size        Size of the provided memory chunk
 *  \param  mem_info_ptr    Optional reference for memory management
 */
void Amsg_TxSetInternalPayload(Mns_AmsTx_Msg_t *self, uint8_t *mem_ptr, uint16_t mem_size, void *mem_info_ptr)
{
    SELF_TX->memory_ptr        = mem_ptr;
    SELF_TX->memory_sz         = mem_size;
    SELF_TX->memory_info_ptr   = mem_info_ptr;

    SELF_TX->pb_msg.data_ptr   = mem_ptr;
    SELF_TX->pb_msg.data_size  = mem_size;
}

/*! \brief   Prepares the message object for re-usage
 *  \details The public message structure is re-initialized. The internal payload
 *           is assigned to the public data reference.
 *  \param   self            The instance
 */
void Amsg_TxReuse(Mns_AmsTx_Msg_t *self)
{
    MISC_MEM_SET((void *)&SELF_TX->pb_msg, 0, sizeof(SELF_TX->pb_msg));  /* cleanup public object */
    /* SELF_TX->backup_dest_address = AMSG_TX_BACKUP_ADDR_NONE; */

    SELF_TX->pb_msg.data_ptr   = SELF_TX->memory_ptr;   /* reset public payload */
    SELF_TX->pb_msg.data_size  = SELF_TX->memory_sz;

    SELF_TX->next_segment_cnt  = 0xFFFFU;               /* start with TelId "4" */
    SELF_TX->temp_result       = MNS_MSG_STAT_OK;
    SELF_TX->internal_status   = AMSG_TX_INTRES_NONE;
}

/*! \brief   Assigns a Tx complete callback function
 *  \details It is not possible to assign the single and multiple instance callback
 *           at the same time. This function shall be called before message transmission. 
 *  \param   self     The instance
 *  \param   compl_sia_fptr  Reference to the single instance callback function
 *  \param   compl_fptr      Reference to a multiple instance callback function
 *  \param   compl_inst_ptr  Instance which is invoked by compl_fptr()
 */
void Amsg_TxSetCompleteCallback(Mns_AmsTx_Msg_t *self, Amsg_TxCompleteSiaCb_t compl_sia_fptr, 
                                Amsg_TxCompleteCb_t compl_fptr, void* compl_inst_ptr)
{
    SELF_TX->complete_sia_fptr = compl_sia_fptr;
    SELF_TX->complete_fptr     = compl_fptr;
    SELF_TX->complete_inst_ptr = compl_inst_ptr;
}

/*! \brief  Invokes the correct callback function to notify the transmission result
 *          and frees the memory
 *  \param  self    Reference to the related message object
 *  \param  result  The transmission result
 *  \param  info    The INIC transmission result
 */
void Amsg_TxNotifyComplete(Mns_AmsTx_Msg_t *self, Mns_AmsTx_Result_t result, Mns_AmsTx_Info_t info)
{
    Amsg_TxRestoreDestinationAddr(self); 

    if (SELF_TX->complete_sia_fptr != NULL)                      /* invoke single instance API callback */
    {
        SELF_TX->complete_sia_fptr(self, result, info);
    }
    else if (SELF_TX->complete_fptr != NULL)
    {
        SELF_TX->complete_fptr(SELF_TX->complete_inst_ptr, self, result, info);
    }

    TR_ASSERT(0xFU, "[AMSG_TX]", (SELF_TX->free_fptr != NULL));
    if (SELF_TX->free_fptr != NULL)
    {
        SELF_TX->free_fptr(SELF_TX->free_inst_ptr, self);
    }
}

/*! \brief  Frees an unused message object to the owning pool
 *  \param  self    Reference to the message object
 */
void Amsg_TxFreeUnused(Mns_AmsTx_Msg_t *self)
{
    TR_ASSERT(0xFU, "[AMSG_TX]", (SELF_TX->free_fptr != NULL));
    if (SELF_TX->free_fptr != NULL)
    {
        SELF_TX->free_fptr(SELF_TX->free_inst_ptr, self);
    }
}

/*! \brief    Updates the transmission result
 *  \param    self    Reference to the related message object
 *  \param    result  The latest MCM transmission result
 *  \details  Since the transmission result of an application message may
 *            consist of multiple telegram transmission results, it is 
 *            important to store the final transmission error. An error cannot
 *            be overwritten by a success.
 */
void Amsg_TxUpdateResult(Mns_AmsTx_Msg_t *self, Mns_MsgTxStatus_t result)
{
    if (result != MNS_MSG_STAT_OK)            /* store the latest error and do not overwrite with success */
    {
        SELF_TX->temp_result = result;
    }
}

/*! \brief    Updates the internal transmission result
 *  \param    self    Reference to the related message object
 *  \param    result  The internal transmission result
 *  \details  The internal transmission result must be updated if the 
 *            the message is transmitted to the internal Rx queue.
 */
void Amsg_TxUpdateInternalResult(Mns_AmsTx_Msg_t *self, Amsg_TxIntStatus_t result)
{
    SELF_TX->internal_status = result;
}

/*! \brief  Returns the latest AMS transmission result code
 *  \param  self    Reference to the related message object
 *  \return Returns the transmission result which shall be notified to the application
 */
Mns_AmsTx_Result_t Amsg_TxGetResultCode(Mns_AmsTx_Msg_t *self)
{
    Mns_AmsTx_Result_t res = MNS_AMSTX_RES_SUCCESS;                 /* success is the expected result */

    switch (SELF_TX->temp_result)
    {
        case MNS_MSG_STAT_OK:
            if (SELF_TX->internal_status == AMSG_TX_INTRES_ERRBUF)
            {
                res = MNS_AMSTX_RES_ERR_BUF_INTERNAL;               /* internal transmission error overrules network success */
            }
            break;
        case MNS_MSG_STAT_ERROR_BF: 
        case MNS_MSG_STAT_ERROR_CRC: 
        case MNS_MSG_STAT_ERROR_ID: 
        case MNS_MSG_STAT_ERROR_ACK: 
        case MNS_MSG_STAT_ERROR_TIMEOUT:
            res = MNS_AMSTX_RES_ERR_RETRIES_EXP;                    /* transmission failed, retries are possible */
            break;
        case MNS_MSG_STAT_ERROR_FATAL_WT:
        case MNS_MSG_STAT_ERROR_FATAL_OA:
            if (SELF_TX->internal_status == AMSG_TX_INTRES_ERRBUF)
            {
                res = MNS_AMSTX_RES_ERR_BUF_INTERNAL;               /* internal transmission error and network node not found */
            }
            else if (SELF_TX->internal_status == AMSG_TX_INTRES_NONE)
            {
                res = MNS_AMSTX_RES_ERR_INVALID_TGT;                /* not transmitted internally and no network node found */
            }
            /* else -> internal success -> target node was found locally */
            break;
        case MNS_MSG_STAT_ERROR_NA_TRANS:
        case MNS_MSG_STAT_ERROR_NA_OFF:
            if (SELF_TX->internal_status != AMSG_TX_INTRES_SUCCESS)
            {
                res = MNS_AMSTX_RES_ERR_NOT_AVAILABLE;              /* successful if internal transmission succeeded, otherwise "not available" */
            }
            break;
        case MNS_MSG_STAT_ERROR_SYNC:
            res = MNS_AMSTX_RES_ERR_NOT_AVAILABLE;
            break;
        default:
            res = MNS_AMSTX_RES_ERR_UNEXPECTED;                     /* unexpected network transmission state */
            break;
    }

    return res;
}

/*! \brief  Returns the latest MCM transmission error
 *  \param  self    Reference to the related message object
 *  \return Returns the INIC transmission result which is provided as additional info
 */
Mns_AmsTx_Info_t Amsg_TxGetResultInfo(Mns_AmsTx_Msg_t *self)
{
    Mns_AmsTx_Info_t res = (Mns_AmsTx_Info_t)SELF_TX->temp_result;

    if ((SELF_TX->temp_result == MNS_MSG_STAT_ERROR_FATAL_WT) && (SELF_TX->ignore_wrong_target != false))
    {
        res = MNS_AMSTX_I_SUCCESS;
    }

    return res;
}

/*! \brief  Queues a Tx message at the tail of a list
 *  \param  self     The instance
 *  \param  list_ptr Reference to the list
 */
void Amsg_TxEnqueue(Mns_AmsTx_Msg_t* self, CDlList* list_ptr)
{
    Dl_InsertTail(list_ptr, &SELF_TX->node);
}

/*! \brief  Retrieves the next segment count
 *  \param  self     The instance
 *  \return The next segment count as uint16_t
 */
uint16_t Amsg_TxGetNextSegmCnt(Mns_AmsTx_Msg_t *self)
{
    return SELF_TX->next_segment_cnt;
}

/*! \brief  Increments the next segment count
 *  \param  self     The instance
 */
void Amsg_TxIncrementNextSegmCnt(Mns_AmsTx_Msg_t *self)
{
    SELF_TX->next_segment_cnt++;
}

/*! \brief  Retrieves the follower id which labels all telegrams of a segmented message
 *  \param  self     The instance
 *  \return The follower id
 */
uint8_t Amsg_TxGetFollowerId(Mns_AmsTx_Msg_t *self)
{
    return SELF_TX->follower_id;
}

/*! \brief  Sets the follower id which labels all telegrams of a segmented message
 *  \param  self     The instance
 *  \param  id       The follower id
 */
void Amsg_TxSetFollowerId(Mns_AmsTx_Msg_t *self, uint8_t id)
{
    SELF_TX->follower_id = id;
}

/*! \brief   Replaces the current destination address by a new one. 
 *  \details The current destination address can be restore by Amsg_TxRestoreDestinationAddr().
 *  \param   self               The instance
 *  \param   new_destination    The new destination address
 */
void Amsg_TxReplaceDestinationAddr(Mns_AmsTx_Msg_t *self, uint16_t new_destination)
{
    SELF_TX->backup_dest_address = self->destination_address;    /* internal backup of current destination address */
    self->destination_address = new_destination;                 /* replace public destination address */
}

/*! \brief   Restores the destination address which was saved by calling Amsg_TxReplaceDestinationAddr().
 *  \param   self               The instance
 */
static void Amsg_TxRestoreDestinationAddr(Mns_AmsTx_Msg_t *self)
{
    if (SELF_TX->backup_dest_address != AMSG_TX_BACKUP_ADDR_NONE)
    {
        self->destination_address = SELF_TX->backup_dest_address;/* restore public destination address */ 
    }
}

/*! \brief  Removes a message from a given queue
 *  \param  self     The instance
 *  \param  list_ptr The queue that contains the message
 */
void Amsg_TxRemoveFromQueue(Mns_AmsTx_Msg_t *self, CDlList *list_ptr)
{
    (void)Dl_Remove(list_ptr, &SELF_TX->node);
}

/*! \brief  Peeks a Tx message from the head of a list
 *  \param  list_ptr Reference to the list
 *  \return Reference to the Tx message
 */
Mns_AmsTx_Msg_t* Amsg_TxPeek(CDlList* list_ptr)
{
    Mns_AmsTx_Msg_t *msg_ptr = NULL;
    CDlNode *node_ptr = Dl_PeekHead(list_ptr);

    if (node_ptr != NULL)
    {
        msg_ptr = (Mns_AmsTx_Msg_t*)Dln_GetData(node_ptr);
    }

    return msg_ptr;
}

/*! \brief  Removes a Tx message from the head of a list
 *  \param  list_ptr Reference to the list
 *  \return Reference to the Tx message
 */
Mns_AmsTx_Msg_t* Amsg_TxDequeue(CDlList* list_ptr)
{
    Mns_AmsTx_Msg_t *msg_ptr = NULL;
    CDlNode *node_ptr = Dl_PopHead(list_ptr);

    if (node_ptr != NULL)
    {
        msg_ptr = (Mns_AmsTx_Msg_t*)Dln_GetData(node_ptr);
    }

    return msg_ptr;
}

/*------------------------------------------------------------------------------------------------*/
/* Rx Message                                                                                     */
/*------------------------------------------------------------------------------------------------*/
/*! \brief      Initializes aggregated objects
 *  \details    Needs to be called once before first usage. Call Amsg_RxHandleSetup() before 
 *              repeated usage. 
 *  \param      self     Reference to an internal Application Message Rx handle
 *  \param      info_ptr Memory information required to free the object
 */
void Amsg_RxCtor(Mns_AmsRx_Msg_t *self, void *info_ptr)
{
    Dln_Ctor(&SELF_RX->node, SELF_RX);
    SELF_RX->info_ptr          = info_ptr;                              /* reset memory information */
    SELF_RX->memory_sz         = 0U;
    SELF_RX->memory_ptr        = NULL;
    SELF_RX->memory_info_ptr   = NULL;
}

/*! \brief      Copies all attributes and payload from a Tx message to the Rx message
 *  \details    The caller has to ensure that the payload size of the Rx message is equal
 *              or greater than the payload size of the Tx message.
 *  \param      self           Reference to an Rx message object
 *  \param      tx_ptr         Reference to an Tx message object
 *  \param      source_address The source address that shall be set in the Rx message
 */
void Amsg_RxBuildFromTx(Mns_AmsRx_Msg_t *self, Mns_AmsTx_Msg_t *tx_ptr, uint16_t source_address)
{
    TR_ASSERT(0xFU,"[AMSG]", (SELF_RX->memory_sz >= tx_ptr->data_size));

    self->receive_type      = Amsg_RxGetReceiveType(tx_ptr->destination_address);
    self->source_address    = source_address;
    self->fblock_id         = tx_ptr->fblock_id;
    self->instance_id       = tx_ptr->instance_id;
    self->function_id       = tx_ptr->function_id;
    self->op_type           = tx_ptr->op_type;
    self->data_size         = tx_ptr->data_size;

    Misc_MemCpy(self->data_ptr, tx_ptr->data_ptr, (size_t)self->data_size);
}

/*! \brief      Sets all attributes of an internal Rx message to valid values
 *  \param      self    Reference to an internal Rx message object
 *  \details    Assigned payload memory has to be freed before calling this function
 */
void Amsg_RxHandleSetup(Mns_AmsRx_Msg_t *self)
{
    MISC_MEM_SET((void *)&SELF_RX->pb_msg, 0, sizeof(SELF_RX->pb_msg)); /* cleanup public message object */
    SELF_RX->pb_msg.data_ptr   = SELF_RX->memory_ptr;                   /* set data to valid memory */
    SELF_RX->gc_marker         = false;                                 /* reset garbage collector flag */
    SELF_RX->exp_tel_cnt       = 0U;                                    /* reset TelCnt */
}

/*! \brief  Evaluates if an Application Message has the same functional address
 *          as a MOST telegram
 *  \param  self    Reference to an internal Application Message Rx handle
 *  \param  tel_ptr Reference to a MOST message object
 *  \return Returns \c true if both message objects have the same functional address,
 *          otherwise \c false.
 */
bool Amsg_RxHandleIsIdentical(Mns_AmsRx_Msg_t *self, Msg_MostTel_t *tel_ptr)
{
    bool result;

    if ((self->source_address == tel_ptr->source_addr)
        && (self->fblock_id == tel_ptr->id.fblock_id)
        && (self->instance_id == tel_ptr->id.instance_id)
        && (self->function_id == tel_ptr->id.function_id)
        && (self->op_type == tel_ptr->id.op_type))
    {
        result = true;
    }
    else
    {
        result = false;
    }

    return result;
}

/*! \brief  Copies the Rx message signature from a MOST message object to an 
 *          internal Application message object
 *  \param  self    Reference to an internal Application Message Rx handle
 *  \param  src_ptr Reference to a MOST message object
 */
void Amsg_RxCopySignatureFromTel(Mns_AmsRx_Msg_t *self, Msg_MostTel_t* src_ptr)
{
    self->source_address   = src_ptr->source_addr;
    self->receive_type     = Amsg_RxGetReceiveType(src_ptr->destination_addr);
    self->fblock_id        = src_ptr->id.fblock_id;
    self->instance_id      = src_ptr->id.instance_id;
    self->function_id      = src_ptr->id.function_id;
    self->op_type          = src_ptr->id.op_type;
}

/*! \brief  Copies the Rx message signature from an internal Application
 *          message object to a MOST message object
 *  \param  self     Reference to an internal Application Message Rx handle
 *  \param  target_ptr  Reference to a MOST message object
 */
void Amsg_RxCopySignatureToTel(Mns_AmsRx_Msg_t *self, Msg_MostTel_t* target_ptr)
{
    target_ptr->source_addr        = self->source_address;
    target_ptr->destination_addr   = MNS_ADDR_DEBUG;
    target_ptr->id.fblock_id       = self->fblock_id;
    target_ptr->id.instance_id     = self->instance_id;
    target_ptr->id.function_id     = self->function_id;
    target_ptr->id.op_type         = self->op_type;
}

/*! \brief  Retrieves the addressing type related to a destination_address of an Rx message
 *  \param  destination_address  The destination address of an Rx message
 *  \return The receive type related to the destination address
 */
static Mns_AmsRx_ReceiveType_t Amsg_RxGetReceiveType(uint16_t destination_address)
{
    Mns_AmsRx_ReceiveType_t ret = MNS_AMSRX_RCT_SINGLECAST;

    if ((destination_address == MNS_ADDR_BROADCAST_BLOCKING) ||
        (destination_address == MNS_ADDR_BROADCAST_UNBLOCKING))
    {
        ret = MNS_AMSRX_RCT_BROADCAST;
    }
    else if ((destination_address >= 0x0300U) &&        /* 0x300..0x3FF is reserved for group cast */
             (destination_address <  0x0400U))
    {
        ret = MNS_AMSRX_RCT_GROUPCAST;
    }

    return ret;
}

/*! \brief  Appends payload of an Rx MOST message object to internal Application
 *          message object
 *  \param  self    Reference to an internal Application Message Rx handle
 *  \param  src_ptr Reference to a MOST message object
 *  \return Returns \c true if the payload was appended successfully, 
 *          otherwise \c false.
 */
bool Amsg_RxAppendPayload(Mns_AmsRx_Msg_t *self, Msg_MostTel_t* src_ptr)
{
    uint8_t cnt;
    bool ret = false;
    const uint16_t curr_size = SELF_RX->pb_msg.data_size;                /* get current message size */

    if ((SELF_RX->memory_sz - src_ptr->tel.tel_len) >= SELF_RX->pb_msg.data_size) /* is size sufficient */
    {
        for (cnt = 0U; cnt < src_ptr->tel.tel_len; cnt++)
        {
             SELF_RX->pb_msg.data_ptr[curr_size + (uint16_t)cnt] = src_ptr->tel.tel_data_ptr[cnt];
        }

         SELF_RX->pb_msg.data_size = curr_size + src_ptr->tel.tel_len;    /* update message size */
         SELF_RX->exp_tel_cnt++;
        ret = true;
    }

    return ret;
}

/*! \brief   Copies data to allocated payload buffer 
 *  \param   self       The instance
 *  \param   data       Reference to external payload data
 *  \param   data_sz    Size of external payload data 
 */
void Amsg_RxCopyToPayload(Mns_AmsRx_Msg_t *self, uint8_t data[], uint8_t data_sz)
{
    MISC_MEM_CPY(&self->data_ptr[0], &data[0], (size_t)data_sz); /* parasoft-suppress  MISRA2004-20_3 "data_sz is limited and checked via Msg_VerifyContent()" */
    self->data_size = data_sz;         /* remember payload size */
}

/*! \brief   Checks if the message has externally allocated payload memory
 *  \param   self       The instance
 *  \return  Returns \c true if external payload is assigned to the message, otherwise \c false.
 */
bool Amsg_RxHasExternalPayload(Mns_AmsRx_Msg_t *self)
{
    return (SELF_RX->memory_sz > 0U);
}

/*! \brief  Sets payload memory provided by memory management and updates data pointer and size
 *  \param  self     The instance
 *  \param  mem_ptr  Reference to the provided memory chunk
 *  \param  mem_size Size of the provided memory chunk
 *  \param  info_ptr Optional reference for memory management
 */
void Amsg_RxHandleSetMemory(Mns_AmsRx_Msg_t *self, uint8_t *mem_ptr, uint16_t mem_size, void *info_ptr)
{
    SELF_RX->memory_ptr        = mem_ptr;
    SELF_RX->memory_info_ptr   = info_ptr;
    SELF_RX->memory_sz         = mem_size;

    SELF_RX->pb_msg.data_ptr   = mem_ptr;
    SELF_RX->pb_msg.data_size  = 0U;
}

/*! \brief  Queues an Rx message at the tail of a list
 *  \param  self     The instance
 *  \param  list_ptr Reference to the list
 */
void Amsg_RxEnqueue(Mns_AmsRx_Msg_t* self, CDlList* list_ptr)
{
    Dl_InsertTail(list_ptr, &SELF_RX->node);
}

/*! \brief  Sets or resets the garbage collector flag
 *  \param  self    The instance
 *  \param  value   New value of the flag
 */
void Amsg_RxSetGcMarker(Mns_AmsRx_Msg_t* self, bool value)
{
    SELF_RX->gc_marker = value; 
}

/*! \brief  Retrieves the value of the garbage collector flag
 *  \param  self    The instance
 *  \return The current value of the flag
 */
bool Amsg_RxGetGcMarker(Mns_AmsRx_Msg_t* self)
{
    return SELF_RX->gc_marker;
}

/*! \brief  Retrieves the next expected telegram count
 *  \param  self    The instance
 *  \return The next  expected telegram count as uint8_t
 */
uint8_t Amsg_RxGetExpTelCnt(Mns_AmsRx_Msg_t* self)
{
    return SELF_RX->exp_tel_cnt;
}

/*! \brief  Peeks an Rx message from the head of a list
 *  \param  list_ptr Reference to the list
 *  \return Reference to the Rx message
 */
Mns_AmsRx_Msg_t* Amsg_RxPeek(CDlList* list_ptr)
{
    Mns_AmsRx_Msg_t *msg_ptr = NULL;
    CDlNode *node_ptr = Dl_PeekHead(list_ptr);

    if (node_ptr != NULL)
    {
        msg_ptr = (Mns_AmsRx_Msg_t*)Dln_GetData(node_ptr);
    }

    return msg_ptr;
}

/*! \brief  Removes an Rx message from the head of a list
 *  \param  list_ptr Reference to the list
 *  \return Reference to the Rx message
 */
Mns_AmsRx_Msg_t* Amsg_RxDequeue(CDlList* list_ptr)
{
    Mns_AmsRx_Msg_t *msg_ptr = NULL;
    CDlNode *node_ptr = Dl_PopHead(list_ptr);

    if (node_ptr != NULL)
    {
        msg_ptr = (Mns_AmsRx_Msg_t*)Dln_GetData(node_ptr);
    }

    return msg_ptr;
}

/*!
 * @}
 * \endcond
 */

/*------------------------------------------------------------------------------------------------*/
/* End of file                                                                                    */
/*------------------------------------------------------------------------------------------------*/