/* * 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 Port Message Channel * * \cond MNS_INTERNAL_DOC * \addtogroup G_PMC * @{ */ /*------------------------------------------------------------------------------------------------*/ /* Includes */ /*------------------------------------------------------------------------------------------------*/ #include "mns_pmchannel.h" #include "mns_pmp.h" #include "mns_pmcmd.h" #include "mns_misc.h" /*------------------------------------------------------------------------------------------------*/ /* Internal Constants */ /*------------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------------*/ /* Internal typedefs */ /*------------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------------*/ /* Internal prototypes */ /*------------------------------------------------------------------------------------------------*/ /* LLD related interface functions */ static Mns_Lld_RxMsg_t* Pmch_RxAllocate(void *self, uint16_t buffer_size); static void Pmch_RxUnused(void *self, Mns_Lld_RxMsg_t *msg_ptr); static void Pmch_RxReceive(void *self, Mns_Lld_RxMsg_t *msg_ptr); static void Pmch_TxRelease(void *self, Mns_Lld_TxMsg_t *msg_ptr); /*------------------------------------------------------------------------------------------------*/ /* Implementation */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Constructor of class CPmChannel * \param self The instance * \param init_ptr Reference to initialization data structure * \param inst_ptr TKU: MultiInstance param */ void Pmch_Ctor(CPmChannel *self, const Pmch_InitData_t *init_ptr, void *inst_ptr) { uint16_t cnt; MISC_MEM_SET(self, 0, sizeof(*self)); self->init_data = *init_ptr; self->inst_ptr = inst_ptr; self->lld_active = false; self->mns_iface.rx_allocate_fptr = &Pmch_RxAllocate; self->mns_iface.rx_receive_fptr = &Pmch_RxReceive; self->mns_iface.rx_free_unused_fptr = &Pmch_RxUnused; self->mns_iface.tx_release_fptr = &Pmch_TxRelease; Pool_Ctor(&self->rx_msgs_pool, self->rx_msgs, /* initialize Rx message pool */ PMCH_POOL_SIZE_RX, self->init_data.mns_inst_id); for (cnt = 0U; cnt < PMCH_POOL_SIZE_RX; cnt++) /* and assign LLD Rx handles */ { Msg_SetLldHandle(&self->rx_msgs[cnt], &self->lld_rx_msgs[cnt]); self->lld_rx_msgs[cnt].msg_ptr = &self->rx_msgs[cnt]; } } /*! \brief Registers an Rx callback function dedicated to one FIFO * \param self The instance * \param fifo_id The FIFO identifier * \param rx_fptr The Rx callback function * \param inst_ptr Reference to the instance required to invoke the callback */ void Pmch_RegisterReceiver(CPmChannel *self, Pmp_FifoId_t fifo_id, Pmch_OnRxMsg_t rx_fptr, void *inst_ptr) { TR_ASSERT(self->init_data.mns_inst_id, "[PMCH]", (((uint8_t)fifo_id == (uint8_t)PMP_FIFO_ID_ICM)||((uint8_t)fifo_id == (uint8_t)PMP_FIFO_ID_MCM)||((uint8_t)fifo_id == (uint8_t)PMP_FIFO_ID_RCM))); self->receivers[fifo_id].rx_fptr = rx_fptr; self->receivers[fifo_id].inst_ptr = inst_ptr; } /*! \brief Un-initializes the LLD interface of the channel * \param self The instance */ void Pmch_Initialize(CPmChannel *self) { if (self->lld_active == false) { self->lld_active = true; TR_INFO((self->init_data.mns_inst_id, "[PMCH]", "Pmch_Initialize(): LLD_START()", 0U)); self->init_data.lld_iface.start_fptr(&self->mns_iface, self, self->inst_ptr); } } /*! \brief Un-initializes the LLD interface of the channel * \param self The instance */ extern void Pmch_Uninitialize(CPmChannel *self) { TR_INFO((self->init_data.mns_inst_id, "[PMCH]", "Pmch_Uninitialize(): Channel un-synchronization started", 0U)); if (self->lld_active != false) { self->lld_active = false; TR_INFO((self->init_data.mns_inst_id, "[PMCH]", "Pmch_Uninitialize(): LLD_STOP()", 0U)); self->init_data.lld_iface.stop_fptr(self->inst_ptr); } } /*! \brief Wrapper for LLD transmit * \details This function which shall be used by all internal classes. No class shall * invoke the LLD transmit function directly. Thus, it might be possible * in future to handle transmission failures and retries. * \param self The instance * \param msg_ptr Reference to the public LLD message structure */ void Pmch_Transmit(CPmChannel *self, Mns_Lld_TxMsg_t *msg_ptr) { if (self->lld_active != false) { self->init_data.lld_iface.tx_transmit_fptr(msg_ptr, self->inst_ptr); } else { Pmch_TxRelease(self, msg_ptr); } } /*------------------------------------------------------------------------------------------------*/ /* The exposed low-level driver interface */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Allocates an Rx message object * \param self The instance * \param buffer_size Size of the memory chunk in bytes which is needed to * copy the Rx message. * \return Reference to an allocated Rx message object or \c NULL if no message object is available. */ static Mns_Lld_RxMsg_t* Pmch_RxAllocate(void *self, uint16_t buffer_size) { CMessage *msg_ptr = NULL; Mns_Lld_RxMsg_t *handle = NULL; CPmChannel *self_ = (CPmChannel*)self; if (buffer_size <= MSG_SIZE_RSVD_BUFFER) { msg_ptr = Pool_GetMsg(&self_->rx_msgs_pool); if (msg_ptr != NULL) { Msg_Cleanup(msg_ptr); handle = &((Lld_IntRxMsg_t*)Msg_GetLldHandle(msg_ptr))->lld_msg; TR_ASSERT(self_->init_data.mns_inst_id, "[PMCH]", (handle != NULL)); handle->data_size = buffer_size; handle->data_ptr = Msg_GetHeader(msg_ptr); } else { self_->rx_trigger_available = true; TR_INFO((self_->init_data.mns_inst_id, "[PMCH]", "Pmch_RxAllocate(): Allocation failed, size=%u", 1U, buffer_size)); } } else { self_->rx_trigger_available = true; TR_FAILED_ASSERT(self_->init_data.mns_inst_id, "[PMCH]"); } return handle; } /*! \brief Frees an unused Rx message object * \param self The instance * \param msg_ptr Reference to the unused Rx message object */ static void Pmch_RxUnused(void *self, Mns_Lld_RxMsg_t *msg_ptr) { CPmChannel *self_ = (CPmChannel*)self; CMessage *pb_handle = ((Lld_IntRxMsg_t*)(void*)msg_ptr)->msg_ptr; TR_ASSERT(self_->init_data.mns_inst_id, "[PMCH]", (pb_handle != NULL)); Pmch_ReturnRxToPool(self_, pb_handle); } /*! \brief Pass an Rx message to MOST NetServices * \param self The instance * \param msg_ptr Reference to the Rx message object containing the received * message. */ static void Pmch_RxReceive(void *self, Mns_Lld_RxMsg_t *msg_ptr) { bool found = false; CPmChannel *self_ = (CPmChannel*)self; if (msg_ptr->data_ptr != NULL) { if (msg_ptr->data_size >= PMP_PM_MIN_SIZE_HEADER) /* ignore incomplete messages */ { uint8_t fifo_no = (uint8_t)Pmp_GetFifoId(msg_ptr->data_ptr); /* get channel id (FIFO number) */ if ((fifo_no < PMP_MAX_NUM_FIFOS) && (self_->receivers[fifo_no].inst_ptr != NULL)) { CMessage *handle = ((Lld_IntRxMsg_t*)(void*)msg_ptr)->msg_ptr; /* forward message to the respective FIFO/channel */ self_->receivers[fifo_no].rx_fptr(self_->receivers[fifo_no].inst_ptr, handle); found = true; } else { TR_ERROR((self_->init_data.mns_inst_id, "[PMCH]", "Pmch_RxReceive(): received message for unregistered FIFO no=%u", 1U, fifo_no)); } } else { TR_ERROR((self_->init_data.mns_inst_id, "[PMCH]", "Pmch_RxReceive(): received incomplete message of size=%u", 1U, msg_ptr->data_size)); } } else { TR_ERROR((self_->init_data.mns_inst_id, "[PMCH]", "Pmch_RxReceive(): message data is not valid", 0U)); } if (false == found) { Pmch_RxUnused(self_, msg_ptr); /* Just return message to pool until PMC is implemented */ } } /*! \brief Notifies that the LLD no longer needs to access the Tx message object * \param self The instance * \param msg_ptr Reference to the Tx message object which is no longer accessed * by the low-level driver */ static void Pmch_TxRelease(void *self, Mns_Lld_TxMsg_t *msg_ptr) { CPmChannel *self_ = (CPmChannel*)self; Lld_IntTxMsg_t *tx_ptr = (Lld_IntTxMsg_t*)(void*)msg_ptr; if ((tx_ptr->owner_ptr == NULL) && (tx_ptr->msg_ptr == NULL)) /* tx_ptr is command */ { Pmcmd_Release((CPmCommand*)(void*)tx_ptr); } else if (tx_ptr->owner_ptr != NULL) /* release message to FIFO */ { self_->init_data.tx_release_fptr(tx_ptr->owner_ptr, msg_ptr); } else { TR_FAILED_ASSERT(self_->init_data.mns_inst_id, "[PMCH]"); /* unknown FIFO - invalid message object */ } TR_ASSERT(self_->init_data.mns_inst_id, "[PMCH]", (NULL == msg_ptr->custom_next_msg_ptr)); /* concatenation destroyed by the LLD */ } /*------------------------------------------------------------------------------------------------*/ /* FIFO Related Callback Functions */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Returns an unused Rx message object back to the pool * \param self The instance * \param msg_ptr The unused Rx message object */ void Pmch_ReturnRxToPool(void *self, CMessage *msg_ptr) { CPmChannel *self_ = (CPmChannel*)self; Pool_ReturnMsg(msg_ptr); if (self_->rx_trigger_available == true) { self_->rx_trigger_available = false; if (self_->init_data.lld_iface.rx_available_fptr != NULL) { self_->init_data.lld_iface.rx_available_fptr(self_->inst_ptr); } } } /*! * @} * \endcond */ /*------------------------------------------------------------------------------------------------*/ /* End of file */ /*------------------------------------------------------------------------------------------------*/