/*
 * 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 3 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 Internal header file of Application Message Classes
 *
 * \cond MNS_INTERNAL_DOC
 * \addtogroup G_AMSMSG
 * @{
 */

#ifndef MNS_AMSMESSAGE_H
#define MNS_AMSMESSAGE_H

/*------------------------------------------------------------------------------------------------*/
/* Includes                                                                                       */
/*------------------------------------------------------------------------------------------------*/
#include "mns_ams_pb.h"
#include "mns_message.h"
#include "mns_dl.h"

#ifdef __cplusplus
extern "C"
{
#endif

/*------------------------------------------------------------------------------------------------*/
/* Internal constants                                                                             */
/*------------------------------------------------------------------------------------------------*/
#define AMSG_TX_OBJECT_SZ   (sizeof(Amsg_IntMsgTx_t))
#define AMSG_RX_OBJECT_SZ   (sizeof(Amsg_IntMsgRx_t))

/*------------------------------------------------------------------------------------------------*/
/* Internal types                                                                                 */
/*------------------------------------------------------------------------------------------------*/
/*! \brief Internal transmission result of an application message */
typedef enum Amsg_TxIntStatus_
{
    AMSG_TX_INTRES_NONE     = 0x00U,  /*!< \brief   The internal transmission is not applicable. */
    AMSG_TX_INTRES_SUCCESS  = 0x01U,  /*!< \brief   The internal transmission succeeded. */
    AMSG_TX_INTRES_ERRBUF   = 0x02U   /*!< \brief   The internal transmission failed. */

} Amsg_TxIntStatus_t;

/*! \brief  Assignable function which is invoked as soon as an application message is received 
 *          completely and available in the Rx message queue
 *  \param  self            The instance (optional)
 *  \param  msg_ptr         Reference to the received message
 */
typedef void (*Amsg_RxCompleteCb_t)(void* self, Mns_AmsRx_Msg_t* msg_ptr);

/*! \brief  Callback function type which is fired as soon as an AMS transmission was finished 
 *  \param  self            The instance (optional)
 *  \param  msg_ptr         Reference to the related message object
 *  \param  result          Transmission result
 *  \param  info            Detailed INIC transmission result
 */
typedef void (*Amsg_TxCompleteCb_t)(void* self, Mns_AmsTx_Msg_t* msg_ptr, Mns_AmsTx_Result_t result, Mns_AmsTx_Info_t info);

/*! \brief  Single instance API callback function type which is fired as soon as an AMS transmission was finished 
 *  \param  msg_ptr         Reference to the related message object
 *  \param  result          Transmission result
 *  \param  info            Detailed INIC transmission result
 */
typedef void (*Amsg_TxCompleteSiaCb_t)(Mns_AmsTx_Msg_t* msg_ptr, Mns_AmsTx_Result_t result, Mns_AmsTx_Info_t info);

/*! \brief  Callback function which is invoked to free a Tx message object to the owning pool 
 *  \param  owner_ptr       The owning pool of the message object
 *  \param  msg_ptr         Reference to the related message object
 */
typedef void (*Amsg_TxFreedCb_t)(void *owner_ptr, Mns_AmsTx_Msg_t* msg_ptr);

/*! \brief Keeps callback functions to an external memory management for Rx payload  */
typedef struct Ams_MemAllocator_
{
    void *inst_ptr;                    /*!< \brief The instance of the (external) memory management */
    Mns_Ams_AllocMemCb_t alloc_fptr;   /*!< \brief This function is invoked to allocate Rx user payload */
    Mns_Ams_FreeMemCb_t  free_fptr;    /*!< \brief This function is invoked to free Rx user payload */

} Ams_MemAllocator_t;

/*------------------------------------------------------------------------------------------------*/
/* Class                                                                                          */
/*------------------------------------------------------------------------------------------------*/
/*! \brief Internal Tx message structure */
typedef struct Amsg_IntMsgTx_
{
    Mns_AmsTx_Msg_t     pb_msg;                 /*!< \brief Public message struct must be the first member */
    void               *info_ptr;               /*!< \brief Custom object information required by memory management */

    void               *free_inst_ptr;          /*!< \brief Reference which is passed to free_ptr */
    Amsg_TxFreedCb_t    free_fptr;              /*!< \brief Callback function which is called to free the object */

    uint8_t            *memory_ptr;             /*!< \brief Reference to payload provided by memory management */
    void               *memory_info_ptr;        /*!< \brief Custom payload information required by memory management */
    uint16_t            memory_sz;              /*!< \brief Size of the payload that is provided by memory management */

    uint16_t            next_segment_cnt;       /*!< \brief Specifies the next segment count. '0xFF' means size prefixed */
    uint8_t             follower_id;            /*!< \brief Identifier of segmented messages and corresponding telegrams  */
    Mns_MsgTxStatus_t   temp_result;            /*!< \brief Stores the temporary result that is notified when then transmission
                                                 *          has completed 
                                                 */
    uint16_t            backup_dest_address;    /*!< \brief Backup of replaced target address. */
    Amsg_TxIntStatus_t  internal_status;        /*!< \brief Stores the internal transmission status */
    bool                ignore_wrong_target;    /*!< \brief Forces the message to report transmission result "success", although 
                                                 *          the INIC has reported transmission error "wrong target"
                                                 */
    CDlNode             node;                   /*!< \brief Node required for message pool */

    Amsg_TxCompleteSiaCb_t complete_sia_fptr;   /*!< \brief Single instance API Callback function which is invoked
                                                 *          after transmission completed
                                                 */
    Amsg_TxCompleteCb_t    complete_fptr;       /*!< \brief Callback function which is invoked after transmission
                                                 *          completed 
                                                 */
    void                  *complete_inst_ptr;   /*!< \brief Instance pointer which is required to invoke complete_fptr */

} Amsg_IntMsgTx_t;

/*! \brief Internal Rx message structure */
typedef struct Amsg_IntMsgRx_
{
    Mns_AmsRx_Msg_t     pb_msg;                 /*!< \brief Public message structure must be the first member */
    void               *info_ptr;               /*!< \brief Custom object information required by memory management */

    uint8_t            *memory_ptr;             /*!< \brief Reference to payload provided by memory management */
    void               *memory_info_ptr;        /*!< \brief Custom payload information required by memory management */
    uint16_t            memory_sz;              /*!< \brief The size of the allocated user payload in bytes */

    CDlNode             node;                   /*!< \brief Node required for message pool */
 
    uint8_t             exp_tel_cnt;            /*!< \brief The expected TelCnt used for segmented transfer */
    bool                gc_marker;              /*!< \brief Identifies message objects that were already
                                                 *          marked by the garbage collector. 
                                                 */
} Amsg_IntMsgRx_t;

/*------------------------------------------------------------------------------------------------*/
/* Class methods                                                                                  */
/*------------------------------------------------------------------------------------------------*/
/* Tx */
extern void Amsg_TxCtor(Mns_AmsTx_Msg_t *self, void *info_ptr, Amsg_TxFreedCb_t free_fptr, void *free_inst_ptr);
extern void Amsg_TxSetInternalPayload(Mns_AmsTx_Msg_t *self, uint8_t *mem_ptr, uint16_t mem_size, void *mem_info_ptr);
extern void Amsg_TxReuse(Mns_AmsTx_Msg_t *self);
extern void Amsg_TxSetCompleteCallback(Mns_AmsTx_Msg_t *self, Amsg_TxCompleteSiaCb_t compl_sia_fptr, 
                                Amsg_TxCompleteCb_t compl_fptr, void* compl_inst_ptr);
extern void Amsg_TxNotifyComplete(Mns_AmsTx_Msg_t *self, Mns_AmsTx_Result_t result, Mns_AmsTx_Info_t info);
extern void Amsg_TxFreeUnused(Mns_AmsTx_Msg_t *self);
extern void Amsg_TxUpdateInternalResult(Mns_AmsTx_Msg_t *self, Amsg_TxIntStatus_t result);
extern void Amsg_TxUpdateResult(Mns_AmsTx_Msg_t *self, Mns_MsgTxStatus_t result);
extern Mns_AmsTx_Result_t Amsg_TxGetResultCode(Mns_AmsTx_Msg_t *self);
extern Mns_AmsTx_Info_t Amsg_TxGetResultInfo(Mns_AmsTx_Msg_t *self);
extern uint16_t Amsg_TxGetNextSegmCnt(Mns_AmsTx_Msg_t *self);
extern void Amsg_TxIncrementNextSegmCnt(Mns_AmsTx_Msg_t *self);
extern uint8_t Amsg_TxGetFollowerId(Mns_AmsTx_Msg_t *self);
extern void Amsg_TxSetFollowerId(Mns_AmsTx_Msg_t *self, uint8_t id);
extern void Amsg_TxReplaceDestinationAddr(Mns_AmsTx_Msg_t *self, uint16_t new_destination);
extern void Amsg_TxRemoveFromQueue(Mns_AmsTx_Msg_t *self, CDlList *list_ptr);
extern void Amsg_TxEnqueue(Mns_AmsTx_Msg_t* self, CDlList* list_ptr);
extern Mns_AmsTx_Msg_t* Amsg_TxPeek(CDlList* list_ptr);
extern Mns_AmsTx_Msg_t* Amsg_TxDequeue(CDlList* list_ptr);

/* Rx */
extern void Amsg_RxCtor(Mns_AmsRx_Msg_t *self, void *info_ptr);
extern void Amsg_RxBuildFromTx(Mns_AmsRx_Msg_t *self, Mns_AmsTx_Msg_t *tx_ptr, uint16_t source_address);
extern void Amsg_RxHandleSetup(Mns_AmsRx_Msg_t *self);
extern void Amsg_RxHandleSetMemory(Mns_AmsRx_Msg_t *self, uint8_t *mem_ptr, uint16_t mem_size, void *info_ptr);
extern bool Amsg_RxHandleIsIdentical(Mns_AmsRx_Msg_t *self, Msg_MostTel_t *tel_ptr);
extern void Amsg_RxCopySignatureFromTel(Mns_AmsRx_Msg_t *self, Msg_MostTel_t* src_ptr);
extern void Amsg_RxCopySignatureToTel(Mns_AmsRx_Msg_t *self, Msg_MostTel_t* target_ptr);
extern void Amsg_RxCopyToPayload(Mns_AmsRx_Msg_t *self, uint8_t data[], uint8_t data_sz);
extern bool Amsg_RxAppendPayload(Mns_AmsRx_Msg_t *self, Msg_MostTel_t* src_ptr);
extern bool Amsg_RxHasExternalPayload(Mns_AmsRx_Msg_t *self);
extern void Amsg_RxEnqueue(Mns_AmsRx_Msg_t* self, CDlList* list_ptr);
extern void Amsg_RxSetGcMarker(Mns_AmsRx_Msg_t* self, bool value);
extern bool Amsg_RxGetGcMarker(Mns_AmsRx_Msg_t* self);
extern uint8_t Amsg_RxGetExpTelCnt(Mns_AmsRx_Msg_t* self);
/* Rx helpers */
extern Mns_AmsRx_Msg_t* Amsg_RxPeek(CDlList* list_ptr);
extern Mns_AmsRx_Msg_t* Amsg_RxDequeue(CDlList* list_ptr);

#ifdef __cplusplus
}               /* extern "C" */
#endif

#endif          /* MNS_AMSMESSAGE_H */

/*!
 * @}
 * \endcond
 */

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