/* * 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 . * * You may also obtain this software under a propriety license from Microchip. * Please contact Microchip for further information. * */ /*! * \file * \brief Implementation of Application Message Pool * * \cond MNS_INTERNAL_DOC * \addtogroup G_AMSPOOL * @{ */ /*------------------------------------------------------------------------------------------------*/ /* Includes */ /*------------------------------------------------------------------------------------------------*/ #include "mns_amspool.h" #include "mns_misc.h" #include "mns_trace.h" /*------------------------------------------------------------------------------------------------*/ /* Internal macros */ /*------------------------------------------------------------------------------------------------*/ #define INT_RX(ptr) ((Amsg_IntMsgRx_t*)(void*)(ptr)) /* parasoft-suppress MISRA2004-19_7 "common definition of type cast improves code" */ #define INT_TX(ptr) ((Amsg_IntMsgTx_t*)(void*)(ptr)) /* parasoft-suppress MISRA2004-19_7 "common definition of type cast improves code" */ /*------------------------------------------------------------------------------------------------*/ /* Internal prototypes */ /*------------------------------------------------------------------------------------------------*/ static void Amsp_FreeTxObj(void *self, Mns_AmsTx_Msg_t* msg_ptr); /*------------------------------------------------------------------------------------------------*/ /* Initialization */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Constructor of application message pool class * \param self The instance * \param mem_allocator_ptr Reference to memory allocator * \param mns_inst_id MOST NetServices instance ID */ void Amsp_Ctor(CAmsMsgPool *self, Ams_MemAllocator_t *mem_allocator_ptr, uint8_t mns_inst_id) { self->mns_inst_id = mns_inst_id; self->allocator_ptr = mem_allocator_ptr; self->rx_rsvd_msg_ptr = Amsp_AllocRxObj(self, 45U); self->rx_rsvd_msg_ref = self->rx_rsvd_msg_ptr; self->terminated = false; self->tx_notify_freed = false; self->rx_notify_freed = false; Sub_Ctor(&self->tx_freed_subject, self->mns_inst_id); Sub_Ctor(&self->rx_freed_subject, self->mns_inst_id); TR_ASSERT(self->mns_inst_id, "[AMSP]", (self->rx_rsvd_msg_ptr != NULL)); } /*! \brief Frees pre-allocated message memory * \param self The instance */ void Amsp_Cleanup(CAmsMsgPool *self) { Amsg_IntMsgRx_t *msg_ptr = INT_RX(self->rx_rsvd_msg_ptr); TR_INFO((self->mns_inst_id, "[AMSP]", "Amsp_Cleanup: rx_rsvd_msg_ptr=0x%p", 1U, self->rx_rsvd_msg_ptr)); self->terminated = true; self->tx_notify_freed = false; self->rx_notify_freed = false; if (msg_ptr != NULL) { self->allocator_ptr->free_fptr(self->allocator_ptr->inst_ptr, msg_ptr->memory_ptr, MNS_AMS_RX_PAYLOAD, msg_ptr->memory_info_ptr); self->allocator_ptr->free_fptr(self->allocator_ptr->inst_ptr, msg_ptr, MNS_AMS_RX_OBJECT, msg_ptr->info_ptr); self->rx_rsvd_msg_ref = NULL; self->rx_rsvd_msg_ptr = NULL; } } /*! \brief Assigns an observer which is invoked as soon as memory dedicated to a Tx message is * freed.The data_ptr of the update callback function is not used (always \c NULL). * See \ref Obs_UpdateCb_t. * \param self The instance * \param observer_ptr The observer */ void Amsp_AssignTxFreedObs(CAmsMsgPool *self, CObserver *observer_ptr) { (void)Sub_AddObserver(&self->tx_freed_subject, observer_ptr); } /*! \brief Assigns an observer which is invoked as soon as memory dedicated to a Tx message is * freed.The data_ptr of the update callback function is not used (always \c NULL). * See \ref Obs_UpdateCb_t. * \param self The instance * \param observer_ptr The observer */ void Amsp_AssignRxFreedObs(CAmsMsgPool *self, CObserver *observer_ptr) { (void)Sub_AddObserver(&self->rx_freed_subject, observer_ptr); } /*------------------------------------------------------------------------------------------------*/ /* Tx allocations */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Allocates an internal Tx message object (without payload) * \param self The instance * \param payload_sz The required payload size in bytes * \return Reference to the Tx message object if the allocation succeeds. Otherwise \c NULL. */ Mns_AmsTx_Msg_t* Amsp_AllocTxObj(CAmsMsgPool *self, uint16_t payload_sz) { void *payload_info_ptr = NULL; void *payload_ptr = NULL; void *obj_info_ptr = NULL; Mns_AmsTx_Msg_t *msg_ptr = (Mns_AmsTx_Msg_t*)self->allocator_ptr->alloc_fptr(self->allocator_ptr->inst_ptr, AMSG_TX_OBJECT_SZ, MNS_AMS_TX_OBJECT, &obj_info_ptr); TR_INFO((self->mns_inst_id, "[AMSP]", "Allocating TxObject: msg_ptr=0x%p, size=%d, info_ptr=0x%p", 3U, msg_ptr, AMSG_TX_OBJECT_SZ, obj_info_ptr)); if (msg_ptr != NULL) { if (payload_sz > 0U) { payload_ptr = self->allocator_ptr->alloc_fptr(self->allocator_ptr->inst_ptr, payload_sz, MNS_AMS_TX_PAYLOAD, &payload_info_ptr); TR_INFO((self->mns_inst_id, "[AMSP]", "Allocating TxPayload: msg_ptr=0x%p, mem_ptr=0x%p, size=%d, info_ptr=0x%p", 4U, msg_ptr, payload_ptr, payload_sz, payload_info_ptr)); if (payload_ptr == NULL) { TR_INFO((self->mns_inst_id, "[AMSP]", "Freeing TxObject: msg_ptr=0x%p, info_ptr=0x%p", 2U, msg_ptr, obj_info_ptr)); self->allocator_ptr->free_fptr(self->allocator_ptr->inst_ptr, msg_ptr, MNS_AMS_TX_OBJECT, obj_info_ptr); msg_ptr = NULL; } } } if (msg_ptr != NULL) { Amsg_TxCtor(msg_ptr, obj_info_ptr, &Amsp_FreeTxObj, self); if (payload_ptr != NULL) { Amsg_TxSetInternalPayload(msg_ptr, (uint8_t*)payload_ptr, payload_sz, payload_info_ptr); } } else { self->tx_notify_freed = true; } return msg_ptr; } /*! \brief Frees an internal Tx message object including its payload * \param self The instance * \param msg_ptr Reference to the internal Tx message object */ static void Amsp_FreeTxObj(void *self, Mns_AmsTx_Msg_t* msg_ptr) { CAmsMsgPool *self_ = (CAmsMsgPool*)self; Amsg_IntMsgTx_t *obj_ptr = INT_TX(msg_ptr); if (obj_ptr->memory_ptr != NULL) { TR_INFO((self_->mns_inst_id, "[AMSP]", "Freeing TxPayload: msg_ptr=0x%p, mem_ptr=0x%p, info_ptr=0x%p", 3U, msg_ptr, obj_ptr->memory_ptr, obj_ptr->memory_info_ptr)); self_->allocator_ptr->free_fptr(self_->allocator_ptr->inst_ptr, obj_ptr->memory_ptr, MNS_AMS_TX_PAYLOAD, obj_ptr->memory_info_ptr); Amsg_TxSetInternalPayload(msg_ptr, NULL, 0U, NULL); } TR_INFO((self_->mns_inst_id, "[AMSP]", "Freeing TxObject: msg_ptr=0x%p, info_ptr=0x%p", 2U, msg_ptr, obj_ptr->info_ptr)); self_->allocator_ptr->free_fptr(self_->allocator_ptr->inst_ptr, msg_ptr, MNS_AMS_TX_OBJECT, obj_ptr->info_ptr); if (self_->tx_notify_freed) { Sub_Notify(&self_->tx_freed_subject, NULL); self_->tx_notify_freed = false; } } /*------------------------------------------------------------------------------------------------*/ /* Rx allocations */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Allocates an internal Rx message object (optionally with payload) * \param self The instance * \param payload_sz The required payload size that shall be allocated and assigned to the object. * Value "0" means that no payload memory shall be allocated in the same turn. * \return Reference to the Rx message object if the allocation succeeds. Otherwise \c NULL. */ Mns_AmsRx_Msg_t* Amsp_AllocRxObj(CAmsMsgPool *self, uint16_t payload_sz) { void *info_ptr = NULL; Mns_AmsRx_Msg_t *msg_ptr = (Mns_AmsRx_Msg_t*)self->allocator_ptr->alloc_fptr(self->allocator_ptr->inst_ptr, AMSG_RX_OBJECT_SZ, MNS_AMS_RX_OBJECT, &info_ptr); TR_INFO((self->mns_inst_id, "[AMSP]", "Allocating RxObject: msg_ptr=0x%p, size=%d, info_ptr=0x%p", 3U, msg_ptr, AMSG_RX_OBJECT_SZ, info_ptr)); if (msg_ptr != NULL) { Amsg_RxCtor(msg_ptr, info_ptr); Amsg_RxHandleSetup(msg_ptr); if (payload_sz != 0U) { if (!Amsp_AllocRxPayload(self, payload_sz, msg_ptr)) { Amsp_FreeRxObj(self, msg_ptr); /* payload allocation has failed - release message object */ msg_ptr = NULL; } } } return msg_ptr; } /*! \brief Allocates a reserved Rx message object with payload up to 45 bytes payload * \param self The instance * \return Reference to the Rx message object if the allocation succeeds. Otherwise \c NULL. */ Mns_AmsRx_Msg_t* Amsp_AllocRxRsvd(CAmsMsgPool *self) { Mns_AmsRx_Msg_t *msg_ptr = NULL; if (self->rx_rsvd_msg_ptr != NULL) { msg_ptr = self->rx_rsvd_msg_ptr; self->rx_rsvd_msg_ptr = NULL; Amsg_RxHandleSetup(msg_ptr); TR_INFO((self->mns_inst_id, "[AMSP]", "Retrieving reserved RxObject: msg_ptr=0x%p", 1U, msg_ptr)); } else { self->rx_notify_freed = true; } return msg_ptr; } /*! \brief Allocates payload for an internal Rx message object * \param self The instance * \param payload_sz Payload size in bytes * \param msg_ptr Reference to the internal Rx message object * \return Returns \c true if the allocation succeeds. Otherwise \c NULL. */ bool Amsp_AllocRxPayload(CAmsMsgPool *self, uint16_t payload_sz, Mns_AmsRx_Msg_t* msg_ptr) { bool success = false; void *info_ptr = NULL; void *mem_ptr = self->allocator_ptr->alloc_fptr(self->allocator_ptr->inst_ptr, payload_sz, MNS_AMS_RX_PAYLOAD, &info_ptr); TR_INFO((self->mns_inst_id, "[AMSP]", "Allocating RxPayload: msg_ptr=0x%p, mem_ptr=0x%p, size=%d, info_ptr=0x%p", 4U, msg_ptr, mem_ptr, payload_sz, info_ptr)); TR_ASSERT(self->mns_inst_id, "[AMSP]", (msg_ptr != NULL)); /* message reference is required */ TR_ASSERT(self->mns_inst_id, "[AMSP]", (msg_ptr != self->rx_rsvd_msg_ref)); /* forbidden overwrite of pre-allocated message payload */ if (mem_ptr != NULL) { Amsg_RxHandleSetMemory(msg_ptr, (uint8_t*)mem_ptr, payload_sz, info_ptr); success = true; } return success; } /*! \brief Frees an internal Rx message object * \param self The instance * \param msg_ptr Reference to the internal Rx message object * \details Payload that is assigned to the message object has to be freed * separately by using Amsp_FreeRxPayload(). */ void Amsp_FreeRxObj(CAmsMsgPool *self, Mns_AmsRx_Msg_t* msg_ptr) { if (msg_ptr == self->rx_rsvd_msg_ref) { TR_ASSERT(self->mns_inst_id, "[AMSP]", (self->rx_rsvd_msg_ptr == NULL)); /* before freeing, message shall be reserved */ TR_INFO((self->mns_inst_id, "[AMSP]", "Restoring reserved RxObject: msg_ptr=0x%p", 1U, msg_ptr)); self->rx_rsvd_msg_ptr = self->rx_rsvd_msg_ref; /* restore reserved message */ if (self->terminated != false) { /* also free reserved message if it is freed */ Amsp_Cleanup(self); /* from any queue after Amsp_Cleanup() */ } } else { Amsg_IntMsgRx_t *obj_ptr = INT_RX(msg_ptr); TR_INFO((self->mns_inst_id, "[AMSP]", "Freeing RxObject: msg_ptr=0x%p, info_ptr=0x%p", 2U, msg_ptr, obj_ptr->info_ptr)); self->allocator_ptr->free_fptr(self->allocator_ptr->inst_ptr, msg_ptr, MNS_AMS_RX_OBJECT, obj_ptr->info_ptr); } if (self->rx_notify_freed) { Sub_Notify(&self->rx_freed_subject, NULL); self->rx_notify_freed = false; } } /*! \brief Frees payload that is associated with an internal Rx message object * \param self The instance * \param msg_ptr Reference to the internal Rx message object */ void Amsp_FreeRxPayload(CAmsMsgPool *self, Mns_AmsRx_Msg_t* msg_ptr) { Amsg_IntMsgRx_t *obj_ptr = INT_RX(msg_ptr); if (msg_ptr == self->rx_rsvd_msg_ref) { TR_ASSERT(self->mns_inst_id, "[AMSP]", (self->rx_rsvd_msg_ptr == NULL)); /* release payload before object */ TR_INFO((self->mns_inst_id, "[AMSP]", "Restoring reserved RxPayload: msg_ptr=0x%p", 1U, msg_ptr)); } else if (obj_ptr->memory_ptr != NULL) { TR_INFO((self->mns_inst_id, "[AMSP]", "Freeing RxPayload: msg_ptr=0x%p, mem_ptr=0x%p, info_ptr=0x%p", 3U, msg_ptr, obj_ptr->memory_ptr, obj_ptr->memory_info_ptr)); self->allocator_ptr->free_fptr(self->allocator_ptr->inst_ptr, obj_ptr->memory_ptr, MNS_AMS_RX_PAYLOAD, obj_ptr->memory_info_ptr); Amsg_RxHandleSetMemory(msg_ptr, NULL, 0U, NULL); } } /*! * @} * \endcond */ /*------------------------------------------------------------------------------------------------*/ /* End of file */ /*------------------------------------------------------------------------------------------------*/