summaryrefslogtreecommitdiffstats
path: root/mnsl
diff options
context:
space:
mode:
authorChristian Gromm <christian.gromm@microchip.com>2016-12-08 13:51:04 +0100
committerChristian Gromm <christian.gromm@microchip.com>2016-12-08 13:51:04 +0100
commit8c5f2324d7aa61669324aec1a0ad091fe1379489 (patch)
tree29cbdcdbe3657e1400d596ec3d560a2573d80817 /mnsl
parente89ba11bd9111f02a940f227cf979f1947e975ac (diff)
src: unicens: import sources
This patch adds the source tree of the NetworkManager v3.0.4. Additionally, it provides the needed configuration scripts. Change-Id: I23778b51423b51a4f87741957e0fb208bceb79b3 Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Diffstat (limited to 'mnsl')
-rw-r--r--mnsl/mns_alm.c277
-rw-r--r--mnsl/mns_alm.h113
-rw-r--r--mnsl/mns_ams.c665
-rw-r--r--mnsl/mns_ams.h163
-rw-r--r--mnsl/mns_ams_pb.h262
-rw-r--r--mnsl/mns_amsmessage.c656
-rw-r--r--mnsl/mns_amsmessage.h217
-rw-r--r--mnsl/mns_amspool.c336
-rw-r--r--mnsl/mns_amspool.h100
-rw-r--r--mnsl/mns_base.c70
-rw-r--r--mnsl/mns_base.h93
-rw-r--r--mnsl/mns_cfg.h67
-rw-r--r--mnsl/mns_dl.c392
-rw-r--r--mnsl/mns_dl.h132
-rw-r--r--mnsl/mns_eh.c155
-rw-r--r--mnsl/mns_eh.h130
-rw-r--r--mnsl/mns_eh_pb.h68
-rw-r--r--mnsl/mns_encoder.c254
-rw-r--r--mnsl/mns_encoder.h118
-rw-r--r--mnsl/mns_lld_pb.h221
-rw-r--r--mnsl/mns_lldpool.c101
-rw-r--r--mnsl/mns_lldpool.h112
-rw-r--r--mnsl/mns_memory.h112
-rw-r--r--mnsl/mns_memory_pb.h72
-rw-r--r--mnsl/mns_message.c331
-rw-r--r--mnsl/mns_message.h238
-rw-r--r--mnsl/mns_message_pb.h121
-rw-r--r--mnsl/mns_misc.c82
-rw-r--r--mnsl/mns_misc.h157
-rw-r--r--mnsl/mns_obs.c453
-rw-r--r--mnsl/mns_obs.h196
-rw-r--r--mnsl/mns_pmchannel.c311
-rw-r--r--mnsl/mns_pmchannel.h179
-rw-r--r--mnsl/mns_pmcmd.c157
-rw-r--r--mnsl/mns_pmcmd.h92
-rw-r--r--mnsl/mns_pmfifo.c1368
-rw-r--r--mnsl/mns_pmfifo.h232
-rw-r--r--mnsl/mns_pmfifos.c447
-rw-r--r--mnsl/mns_pmfifos.h131
-rw-r--r--mnsl/mns_pmp.c352
-rw-r--r--mnsl/mns_pmp.h211
-rw-r--r--mnsl/mns_pool.c127
-rw-r--r--mnsl/mns_pool.h82
-rw-r--r--mnsl/mns_ret.h115
-rw-r--r--mnsl/mns_scheduler.c259
-rw-r--r--mnsl/mns_scheduler.h148
-rw-r--r--mnsl/mns_segmentation.c555
-rw-r--r--mnsl/mns_segmentation.h146
-rw-r--r--mnsl/mns_telqueue.c119
-rw-r--r--mnsl/mns_telqueue.h93
-rw-r--r--mnsl/mns_timer.c454
-rw-r--r--mnsl/mns_timer.h146
-rw-r--r--mnsl/mns_trace.h87
-rw-r--r--mnsl/mns_transceiver.c292
-rw-r--r--mnsl/mns_transceiver.h135
-rw-r--r--mnsl/mns_types_cfg.h70
-rw-r--r--mnsl/mnsl.c435
-rw-r--r--mnsl/mnsl.h195
58 files changed, 13402 insertions, 0 deletions
diff --git a/mnsl/mns_alm.c b/mnsl/mns_alm.c
new file mode 100644
index 0000000..5c5e76d
--- /dev/null
+++ b/mnsl/mns_alm.c
@@ -0,0 +1,277 @@
+/*
+ * 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 Implementation of the API locking manager.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_ALM
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_alm.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal constant */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Interval for garbage collection */
+static const uint16_t ALM_GARBAGE_COLLECTOR_INTERVAL = 2600U; /* parasoft-suppress MISRA2004-8_7 "Value shall be part of the module, not part of a function." */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Alm_HandleInternalErrors(void *self, void *error_code_ptr);
+static void Alm_GarbageCollector(void *self);
+static bool Alm_CheckRegisteredApi(void *current_alm_ptr, void *alm_inst_ptr);
+static void Alm_StartTimeout(CApiLockingManager *self);
+static void Alm_ClearTimeout(CApiLockingManager *self);
+static bool Alm_SearchLockedApi(void *current_alm_ptr, void *alm_inst_ptr);
+static void Alm_ResetRegisteredApis(CApiLockingManager *self);
+static bool Alm_ResetApi(void *current_alm_ptr, void *alm_inst_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CApiLockingManager */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the API locking manager class.
+ * \param self Instance pointer
+ * \param tm_ptr Reference to timer management instance
+ * \param eh_ptr Reference to event handler instance
+ * \param mns_inst_id MOST NetServices instance ID
+ */
+void Alm_Ctor(CApiLockingManager *self,
+ CTimerManagement *tm_ptr,
+ CEventHandler *eh_ptr,
+ uint8_t mns_inst_id)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ T_Ctor(&self->garbage_collector);
+ self->tm_ptr = tm_ptr;
+ self->eh_ptr = eh_ptr;
+ self->mns_inst_id = mns_inst_id;
+
+ /* Observe internal errors and events */
+ Mobs_Ctor(&self->internal_error_obs, self, EH_M_TERMINATION_EVENTS, &Alm_HandleInternalErrors);
+ Eh_AddObsrvInternalEvent(self->eh_ptr, &self->internal_error_obs);
+}
+
+/*! \brief Handles internal errors and events
+ * \param self Instance pointer
+ * \param error_code_ptr Reference to reported error code
+ */
+static void Alm_HandleInternalErrors(void *self, void *error_code_ptr)
+{
+ CApiLockingManager *self_ = (CApiLockingManager *)self;
+ MISC_UNUSED(error_code_ptr);
+
+ Tm_ClearTimer(self_->tm_ptr, &self_->garbage_collector); /* Clear timeout */
+ Alm_ResetRegisteredApis(self_); /* Reset all registered APIs */
+}
+
+/*! \brief Checks for API locking timeouts. This method is the callback function of timer
+ * \c garbage_collector.
+ * \param self Instance pointer
+ */
+static void Alm_GarbageCollector(void *self)
+{
+ CApiLockingManager *self_ = (CApiLockingManager *)self;
+ (void)Dl_Foreach(&self_->api_list, &Alm_CheckRegisteredApi, self_);
+}
+
+/*! \brief This method is used by Alm_GarbageCollector() to process each registered API.
+ * \param current_alm_ptr Reference to the current API
+ * \param alm_inst_ptr Instance of the API locking manager
+ * \return \c false to process all registered APIs
+ */
+static bool Alm_CheckRegisteredApi(void *current_alm_ptr, void *alm_inst_ptr)
+{
+ CApiLockingManager *self = (CApiLockingManager *)alm_inst_ptr;
+ CApiLocking *alm_ptr_ = (CApiLocking *)current_alm_ptr;
+ MISC_UNUSED(self);
+
+ if(alm_ptr_->timeout_mask != 0U)
+ {
+ Alm_ModuleMask_t tmp_mask = 1U;
+ while(alm_ptr_->timeout_mask != 0U)
+ {
+ if(tmp_mask == (tmp_mask & alm_ptr_->timeout_mask))
+ {
+ Ssub_Notify(&alm_ptr_->subject, &tmp_mask, false);
+ alm_ptr_->method_mask &= ~tmp_mask;
+ alm_ptr_->timeout_mask &= ~tmp_mask;
+ }
+ tmp_mask <<= 1;
+ }
+ Alm_ClearTimeout(self);
+ }
+ if(alm_ptr_->method_mask != 0U)
+ {
+ alm_ptr_->timeout_mask = alm_ptr_->method_mask;
+ }
+ return false;
+}
+
+/*! \brief Registers a new API locking object.
+ * \param self Instance pointer
+ * \param al_ptr Reference to the API to register
+ */
+void Alm_RegisterApi(CApiLockingManager *self, CApiLocking *al_ptr)
+{
+ Dl_InsertTail(&self->api_list, &al_ptr->node);
+ Dln_SetData(&al_ptr->node, al_ptr);
+ al_ptr->alm_ptr = self;
+}
+
+/*! \brief Starts the garbage collecting timer.
+ * \param self Instance pointer
+ */
+static void Alm_StartTimeout(CApiLockingManager *self)
+{
+ if(T_IsTimerInUse(&self->garbage_collector) == false)
+ {
+ Tm_SetTimer(self->tm_ptr,
+ &self->garbage_collector,
+ &Alm_GarbageCollector,
+ self,
+ ALM_GARBAGE_COLLECTOR_INTERVAL,
+ ALM_GARBAGE_COLLECTOR_INTERVAL);
+ }
+}
+
+/*! \brief Clears the garbage collecting timer. The timer is clear if no API locking flag is
+ * currently pending.
+ * \param self Instance pointer
+ */
+static void Alm_ClearTimeout(CApiLockingManager *self)
+{
+ if(NULL == Dl_Foreach(&self->api_list, &Alm_SearchLockedApi, self))
+ {
+ Tm_ClearTimer(self->tm_ptr, &self->garbage_collector);
+ }
+}
+
+/*! \brief Used by Alm_ClearTimeout() to check if at least one registered API is locked.
+ * \param current_alm_ptr Reference to the current API locking object
+ * \param alm_inst_ptr Instance of the API locking manager
+ * \return \c true if a locked API was found, otherwise \c false
+ */
+static bool Alm_SearchLockedApi(void *current_alm_ptr, void *alm_inst_ptr)
+{
+ CApiLocking *alm_ptr_ = (CApiLocking *)current_alm_ptr;
+ bool ret_val = false;
+ MISC_UNUSED(alm_inst_ptr);
+
+ if(alm_ptr_->method_mask != 0U)
+ {
+ ret_val = true;
+ }
+ return ret_val;
+}
+
+/*! \brief Resets all registered APIs. Called if an internal error has been occurred.
+ * \param self Instance pointer
+ */
+static void Alm_ResetRegisteredApis(CApiLockingManager *self)
+{
+ (void)Dl_Foreach(&self->api_list, &Alm_ResetApi, self);
+}
+
+/*! \brief Used by Alm_ResetRegisteredApis() to reset all registered APIs.
+ * \param current_alm_ptr Reference to the current API locking object
+ * \param alm_inst_ptr Instance of the API locking manager
+ * \return \c false (process all registered APIs)
+ */
+static bool Alm_ResetApi(void *current_alm_ptr, void *alm_inst_ptr)
+{
+ CApiLocking *alm_ptr_ = (CApiLocking *)current_alm_ptr;
+ MISC_UNUSED(alm_inst_ptr);
+
+ alm_ptr_->method_mask = 0U;
+ alm_ptr_->timeout_mask = 0U;
+
+ return false;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CApiLocking */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the API locking class.
+ * \param self Instance pointer
+ * \param obs_ptr Observer to signal locked API methods
+ * \param mns_inst_id MOST NetServices instance ID
+ */
+void Al_Ctor(CApiLocking *self, CSingleObserver *obs_ptr, uint8_t mns_inst_id)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ self->mns_inst_id = mns_inst_id;
+ Dln_Ctor(&self->node, NULL);
+ if(obs_ptr != NULL)
+ {
+ Ssub_Ctor(&self->subject, self->mns_inst_id);
+ (void)Ssub_AddObserver(&self->subject, obs_ptr);
+ }
+}
+
+/*! \brief Locks the given API method.
+ * \param self Instance pointer
+ * \param method Bitmask of method to lock
+ * \return \c true if the API has been locked successfully
+ * \return \c false if the API was already locked
+ */
+bool Al_Lock(CApiLocking *self, Alm_ModuleMask_t method)
+{
+ bool ret_val = false;
+ if((self->method_mask & method) == 0U)
+ {
+ ret_val = true;
+ self->method_mask |= method;
+ self->timeout_mask &= ~method;
+ Alm_StartTimeout(self->alm_ptr);
+ }
+ return ret_val;
+}
+
+/*! \brief Releases the lock of the given API method.
+ * \param self Instance pointer
+ * \param method Bitmask of method to lock
+ */
+void Al_Release(CApiLocking *self, Alm_ModuleMask_t method)
+{
+ self->method_mask &= ~method;
+ self->timeout_mask &= ~method;
+ Alm_ClearTimeout(self->alm_ptr);
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_alm.h b/mnsl/mns_alm.h
new file mode 100644
index 0000000..92e3e46
--- /dev/null
+++ b/mnsl/mns_alm.h
@@ -0,0 +1,113 @@
+/*
+ * 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 the API locking module.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_ALM
+ * @{
+ */
+
+#ifndef MNS_ALM_H
+#define MNS_ALM_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+#include "mns_eh.h"
+#include "mns_timer.h"
+#include "mns_obs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Type definitions */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Bitmask used to store locked API methods */
+typedef uint32_t Alm_ModuleMask_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class structure of the API locking manager */
+typedef struct CApiLockingManager_
+{
+ CTimerManagement *tm_ptr; /*!< \brief Reference to timer management instance */
+ CEventHandler *eh_ptr; /*!< \brief Reference to event handler instance */
+ CTimer garbage_collector; /*!< \brief Timer for garbage collection */
+ CDlList api_list; /*!< \brief List of registered APIs */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+ CMaskedObserver internal_error_obs; /*!< \brief Error observer to handle internal errors and
+ events */
+
+} CApiLockingManager;
+
+/*! \brief Class structure of the API locking */
+typedef struct CApiLocking_
+{
+ CDlNode node; /*!< \brief Node of the doubly linked (API-) list */
+ CApiLockingManager *alm_ptr; /*!< \brief Reference to CApiLockingManager instance */
+ Alm_ModuleMask_t method_mask; /*!< \brief Bitmask which holds locked API methods */
+ Alm_ModuleMask_t timeout_mask; /*!< \brief Bitmask to report timeouts */
+ CSingleSubject subject; /*!< \brief Subject to update registered observer */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+
+} CApiLocking;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CApiLockingManager */
+/*------------------------------------------------------------------------------------------------*/
+extern void Alm_Ctor(CApiLockingManager *self,
+ CTimerManagement *tm_ptr,
+ CEventHandler *eh_ptr,
+ uint8_t mns_inst_id);
+extern void Alm_RegisterApi(CApiLockingManager *self, CApiLocking *al_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CApiLocking */
+/*------------------------------------------------------------------------------------------------*/
+extern void Al_Ctor(CApiLocking *self, CSingleObserver *obs_ptr, uint8_t mns_inst_id);
+extern bool Al_Lock(CApiLocking *self, Alm_ModuleMask_t method);
+extern void Al_Release(CApiLocking *self, Alm_ModuleMask_t method);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_ALM_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_ams.c b/mnsl/mns_ams.c
new file mode 100644
index 0000000..338047b
--- /dev/null
+++ b/mnsl/mns_ams.c
@@ -0,0 +1,665 @@
+/*
+ * 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 Implementation of Application Message Service
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_AMSC
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_ams.h"
+#include "mns_amsmessage.h"
+#include "mns_dl.h"
+#include "mns_misc.h"
+#include "mns_pmp.h"
+#include "mns_encoder.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal constants */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Priority of the Application Message Service */
+static const uint8_t AMS_SRV_PRIO = 253U; /* parasoft-suppress MISRA2004-8_7 "configuration property" */
+/*! \brief Event which triggers the Rx service */
+static const Srv_Event_t AMS_EV_RX_SERVICE = 1U;
+/*! \brief Event which triggers the Tx service */
+static const Srv_Event_t AMS_EV_TX_SERVICE = 2U;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Ams_Cleanup(CAms *self);
+static void Ams_Service(void *self);
+static void Ams_OnEhEvent(void *self, void *error_code_ptr);
+
+static void Ams_TxService(CAms *self);
+static void Ams_TxOnStatus(void *self, Msg_MostTel_t *tel_ptr, Mns_MsgTxStatus_t status);
+static uint8_t Ams_TxGetNextFollowerId(CAms *self);
+
+static void Ams_RxOnTelComplete(CAms *self, Msg_MostTel_t *tel_ptr);
+static void Ams_RxReleaseTel(CAms *self, Msg_MostTel_t *tel_ptr);
+static void Ams_RxProcessWaitingQ(CAms *self);
+static void Ams_RxOnSegError(void *self, Msg_MostTel_t *tel_ptr, Segm_Error_t error);
+static void Ams_RxOnFreedMsg(void *self, void *data_ptr);
+static void Ams_RxFlush(CAms *self);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Initialization Methods */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of class CAms
+ * \param self The instance
+ * \param base_ptr Reference to base services
+ * \param mcm_trcv_ptr Reference to the MCM transceiver
+ * \param rcm_trcv_ptr Reference to the RCM transceiver
+ * \param pool_ptr Reference to the pool for application message handles
+ * \param rx_def_payload_sz Default memory size that is allocated when receiving segmented messages
+ * without size prefix
+ */
+void Ams_Ctor(CAms *self, CBase *base_ptr, CTransceiver *mcm_trcv_ptr, CTransceiver *rcm_trcv_ptr,
+ CAmsMsgPool *pool_ptr, uint16_t rx_def_payload_sz)
+{
+ MISC_UNUSED(rcm_trcv_ptr);
+ MISC_MEM_SET((void *)self, 0, sizeof(*self)); /* reset members to "0" */
+ self->trcv_mcm_ptr = mcm_trcv_ptr;
+ self->trcv_rcm_ptr = rcm_trcv_ptr;
+ self->base_ptr = base_ptr;
+ self->pool_ptr = pool_ptr;
+
+ self->tx.default_llrbc = AMS_LLRBC_DEFAULT; /* set initial retries */
+ self->tx.next_follower_id = 1U; /* set initial follower id */
+ /* init pools */
+ Obs_Ctor(&self->rx.message_freed_observer, self, &Ams_RxOnFreedMsg);
+ Amsp_AssignRxFreedObs(self->pool_ptr, &self->rx.message_freed_observer);
+ Telq_Ctor(&self->rx.waiting_queue, self->base_ptr->mns_inst_id); /* init Rx waiting queue */
+
+ Dl_Ctor(&self->tx.queue, self->base_ptr->mns_inst_id);
+
+ Srv_Ctor(&self->service, AMS_SRV_PRIO, self, &Ams_Service); /* register service */
+ (void)Scd_AddService(&self->base_ptr->scd, &self->service);
+
+ Segm_Ctor(&self->segmentation, self->base_ptr, self->pool_ptr, rx_def_payload_sz);
+ Segm_AssignRxErrorHandler(&self->segmentation, &Ams_RxOnSegError, self);
+
+ if (self->trcv_mcm_ptr != NULL)
+ {
+ Trcv_RxAssignReceiver(self->trcv_mcm_ptr, &Ams_RxOnMcmTelComplete, self);
+ }
+ if (self->trcv_rcm_ptr != NULL)
+ {
+ Trcv_RxAssignReceiver(self->trcv_rcm_ptr, &Ams_RxOnRcmTelComplete, self);
+ }
+
+ Mobs_Ctor(&self->unsync_result_observer, self, EH_M_TERMINATION_EVENTS, &Ams_OnEhEvent); /* register error observer */
+ Eh_AddObsrvInternalEvent(&self->base_ptr->eh, &self->unsync_result_observer);
+}
+
+/*! \brief Sets the default retry values used for Application Messages
+ * \param self The instance
+ * \param llrbc The default low level retry block count
+ */
+void Ams_TxSetDefaultRetries(CAms* self, uint8_t llrbc)
+{
+ self->tx.default_llrbc = llrbc;
+}
+
+/*! \brief Assigns a function of another class to receive application messages
+ * \param self The instance
+ * \param cb_fptr Callback function
+ * \param inst_ptr The instance of the receiver class
+ */
+void Ams_RxAssignReceiver(CAms *self, Amsg_RxCompleteCb_t cb_fptr, void *inst_ptr)
+{
+ self->rx.complete_fptr = cb_fptr;
+ self->rx.complete_inst_ptr = inst_ptr;
+}
+
+/*! \brief Assigns an observer which is invoked if a Tx application message is freed.
+ * \details The observer is only notified a previous allocation of a Tx object has failed.
+ * 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 Ams_TxAssignMsgFreedObs(CAms *self, CObserver *observer_ptr)
+{
+ Amsp_AssignTxFreedObs(self->pool_ptr, observer_ptr);
+}
+
+/*! \brief Assigns a callback function that selects FIFO routing for a Tx message.
+ * \details If no callback function is assigned, then all Tx messages are routed to RCM FIFO.
+ * \param self The instance
+ * \param cb_fptr The callback function
+ */
+void Ams_TxAssignTrcvSelector(CAms *self, Ams_TxIsRcmMsgCb_t cb_fptr)
+{
+ self->tx.is_rcm_fptr = cb_fptr;
+}
+
+/*! \brief Performs a cleanup of the Tx message queue and notifies
+ * the transmission error MNS_AMSTX_RES_NOT_AVAILABLE.
+ * \param self The instance
+ */
+static void Ams_Cleanup(CAms *self)
+{
+ Mns_AmsTx_Msg_t *tx_ptr = NULL;
+ TR_INFO((self->base_ptr->mns_inst_id, "[AMS]", "Starting AMS Cleanup", 0U));
+ /* cleanup Tx queue */
+ for (tx_ptr = Amsg_TxDequeue(&self->tx.queue); tx_ptr != NULL; tx_ptr = Amsg_TxDequeue(&self->tx.queue))
+ {
+ /* just just notify completion, the object is automatically freed to the pool */
+ Amsg_TxNotifyComplete(tx_ptr, MNS_AMSTX_RES_ERR_NOT_AVAILABLE, MNS_AMSTX_I_ERR_UNSYNCED);
+ }
+
+ Segm_Cleanup(&self->segmentation); /* cleanup Rx */
+ Ams_RxFlush(self);
+ Amsp_Cleanup(self->pool_ptr); /* final cleanup of pool */
+ TR_INFO((self->base_ptr->mns_inst_id, "[AMS]", "Finished AMS Cleanup", 0U));
+}
+
+/*! \brief Callback function which is invoked by the event handler
+ * on any termination event.
+ * \param self The instance
+ * \param error_code_ptr Reference to the error code
+ */
+static void Ams_OnEhEvent(void *self, void *error_code_ptr)
+{
+ CAms *self_ = (CAms*)self;
+ MISC_UNUSED(error_code_ptr);
+ Ams_Cleanup(self_);
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Service */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief The AMS service function
+ * \param self The instance
+ */
+static void Ams_Service(void *self)
+{
+ CAms *self_ = (CAms*)self;
+ Srv_Event_t event_mask;
+ Srv_GetEvent(&self_->service, &event_mask);
+
+ if (AMS_EV_TX_SERVICE == (event_mask & AMS_EV_TX_SERVICE)) /* Is event pending? */
+ {
+ Srv_ClearEvent(&self_->service, AMS_EV_TX_SERVICE);
+ Ams_TxService(self_);
+ }
+
+ if (AMS_EV_RX_SERVICE == (event_mask & AMS_EV_RX_SERVICE)) /* Is event pending? */
+ {
+ Srv_ClearEvent(&self_->service, AMS_EV_RX_SERVICE);
+ Ams_RxProcessWaitingQ(self_);
+ }
+}
+
+/*! \brief Allocates and transmits MCMs for the dedicated Application Messages
+ * \param self The instance
+ */
+static void Ams_TxService(CAms *self)
+{
+ CDlNode *node1_ptr;
+ /* run as long as messages are available in Tx queue */
+ for (node1_ptr = Dl_PeekHead(&self->tx.queue); node1_ptr != NULL; node1_ptr = Dl_PeekHead(&self->tx.queue))
+ {
+ Msg_MostTel_t *tel_ptr = NULL;
+ CTransceiver *trcv_ptr = self->trcv_mcm_ptr;
+ Mns_AmsTx_Msg_t *tx_ptr = (Mns_AmsTx_Msg_t*)Dln_GetData(node1_ptr);
+
+ if (self->tx.is_rcm_fptr != NULL)
+ {
+ if (self->tx.is_rcm_fptr(tx_ptr) != false)
+ {
+ trcv_ptr = self->trcv_rcm_ptr;
+ }
+ }
+ /* allocate telegram object with 2 bytes for TelId 4 */
+ tel_ptr = Trcv_TxAllocateMsg(trcv_ptr, 2U); /* remaining message payload is attached as external memory */
+
+ if (tel_ptr != NULL) /* transmit message if telegram object is available */
+ {
+ bool done;
+ CDlNode *node2_ptr = Dl_PopHead(&self->tx.queue); /* get application message from queue */
+
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[AMS]", (node1_ptr == node2_ptr));
+ tx_ptr = (Mns_AmsTx_Msg_t*)Dln_GetData(node2_ptr);
+ done = Segm_TxBuildSegment(&self->segmentation, tx_ptr, tel_ptr); /* run segmentation */
+ Trcv_TxSendMsgExt(trcv_ptr, tel_ptr, &Ams_TxOnStatus, self); /* transmit telegram */
+ TR_INFO((self->base_ptr->mns_inst_id, "[AMS]", "Ams_TxService(tel_ptr=0x%p)", 1U, tel_ptr));
+
+ if (done == false)
+ {
+ Dl_InsertHead(&self->tx.queue, node2_ptr);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* AMS Tx handles */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Retrieves a message Tx handle
+ * \details The payload provided is limited the supported size of the memory management.
+ * The application may also attach own payload to a message object. Therefore,
+ * Ams_TxGetMsg() shall be called with size "0".
+ * \param self The instance
+ * \param size Payload size in bytes or "0" to use application provided payload.
+ * The payload provided by MNS is limited to a size of 45 bytes.
+ * Valid values: 0..45.
+ * \return A Tx message object or \c NULL if no message object is available.
+ */
+Mns_AmsTx_Msg_t * Ams_TxGetMsg(CAms *self, uint16_t size)
+{
+ Mns_AmsTx_Msg_t * msg_ptr = Amsp_AllocTxObj(self->pool_ptr, size);
+
+ if (msg_ptr != NULL)
+ {
+ msg_ptr->destination_address = AMS_ADDR_RSVD_RANGE; /* set invalid address to prevent internal transmission*/
+ msg_ptr->llrbc = self->tx.default_llrbc;
+ }
+
+ return msg_ptr;
+}
+
+/*! \brief Frees an unused or completed Tx message to the pool
+ * \param self The instance
+ * \param msg_ptr Reference to the related message object
+ */
+void Ams_TxFreeUnusedMsg(CAms *self, Mns_AmsTx_Msg_t *msg_ptr)
+{
+ MISC_UNUSED(self);
+ Amsg_TxFreeUnused(msg_ptr); /* the object is automatically freed to the pool */
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* AMS Transmission */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Transmits a MOST Application Message
+ * \details After the transmission completed the function will call one callback function. Therefore
+ * the caller is able to assign one of two different callback function. The difference between
+ * the callback function is that tx_complete_sia_fptr does no provide a self pointer whether
+ * tx_complete_fptr and tx_complete_inst_ptr allow to invoke a class method.
+ * \param self The instance
+ * \param msg_ptr Reference to the related message object
+ * \param tx_complete_sia_fptr Single instance API callback function which is invoked as soon as
+ * the transmission was finished.
+ * \param tx_complete_fptr Multi instance callback function which is invoked as soon as
+ * the transmission was finished.
+ * \param tx_complete_inst_ptr Instance pointer which is referred when tx_complete_fptr is invoked.
+ * \return Possible return values are
+ * - \c MNS_RET_SUCCESS if the transmission was started successfully
+ * - \c MNS_RET_ERR_PARAM if the transmission was refused due to an invalid parameter
+ */
+Mns_Return_t Ams_TxSendMsg(CAms *self, Mns_AmsTx_Msg_t *msg_ptr, Amsg_TxCompleteSiaCb_t tx_complete_sia_fptr,
+ Amsg_TxCompleteCb_t tx_complete_fptr, void* tx_complete_inst_ptr)
+{
+ Mns_Return_t ret_val = MNS_RET_ERR_PARAM;
+
+ TR_INFO((self->base_ptr->mns_inst_id, "[AMS]", "Called Ams_TxSendMsg(0x%p)", 1U, msg_ptr));
+
+ if (Ams_TxIsValidMessage(msg_ptr)) /* prevent application messages to loc. INIC */
+ { /* do not set both callback pointers */
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[AMS]", (((tx_complete_sia_fptr != NULL) && (tx_complete_fptr != NULL)) == false))
+ Amsg_TxSetCompleteCallback(msg_ptr, tx_complete_sia_fptr, tx_complete_fptr, tx_complete_inst_ptr);
+ Ams_TxSendMsgDirect(self, msg_ptr);
+ ret_val = MNS_RET_SUCCESS;
+ }
+
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[AMS]", (ret_val == MNS_RET_SUCCESS));
+
+ return ret_val;
+}
+
+/*! \brief Transmits a MOST Application Message without attributes check
+ * \details This method shall be only be used by AMD and AMS internally
+ * \param self The instance
+ * \param msg_ptr Reference to the related message object
+ */
+void Ams_TxSendMsgDirect(CAms *self, Mns_AmsTx_Msg_t *msg_ptr)
+{
+ TR_INFO((self->base_ptr->mns_inst_id, "[AMS]", "Called Ams_TxSendMsg(0x%p)", 1U, msg_ptr));
+
+ if (msg_ptr->data_size > SEGM_MAX_SIZE_TEL) /* set follower id to be used for all segments */
+ {
+ Amsg_TxSetFollowerId(msg_ptr, Ams_TxGetNextFollowerId(self));
+ }
+
+ Amsg_TxEnqueue(msg_ptr, &self->tx.queue); /* schedule transmission */
+ Srv_SetEvent(&self->service, AMS_EV_TX_SERVICE);
+}
+
+/*! \brief Callback function which is invoked as soon as MCM transmission
+ * was finished in PMS.
+ * \param self The instance
+ * \param tel_ptr Reference to the telegram
+ * \param status Transmission status
+ */
+static void Ams_TxOnStatus(void *self, Msg_MostTel_t *tel_ptr, Mns_MsgTxStatus_t status)
+{
+ CAms *self_ = (CAms*)self;
+ Mns_AmsTx_Msg_t* msg_ptr = (Mns_AmsTx_Msg_t*)tel_ptr->info_ptr;
+
+ TR_INFO((self_->base_ptr->mns_inst_id, "[AMS]", "Ams_TxOnStatus(tel_ptr=0x%p, %d)", 2U, tel_ptr, status));
+
+ if (msg_ptr != NULL) /* MOST Telegram has AMS parent? */
+ {
+ Amsg_TxUpdateResult(msg_ptr, status);
+
+ if ((0U == tel_ptr->tel.tel_id) || (3U == tel_ptr->tel.tel_id)) /* is finished? */
+ { /* just just notify completion, the object is */
+ Amsg_TxNotifyComplete(msg_ptr, Amsg_TxGetResultCode(msg_ptr), Amsg_TxGetResultInfo(msg_ptr)); /* automatically freed to the pool */
+ }
+ else if (status != MNS_MSG_STAT_OK) /* check transmission needs termination before transmission end */
+ {
+ TR_ASSERT(self_->base_ptr->mns_inst_id, "[AMS]", (Amsg_TxGetFollowerId(msg_ptr) != 0U));
+
+ if (((uint8_t)Amsg_TxGetNextSegmCnt(msg_ptr) == (uint8_t)(tel_ptr->tel.tel_cnt + 1U)) /* is last transmitted segment */
+ || ((Amsg_TxGetNextSegmCnt(msg_ptr) == 0U) && (4U == tel_ptr->tel.tel_id))) /* or TelId 4 and the first segment is pending */
+ {
+ Amsg_TxRemoveFromQueue(msg_ptr, &self_->tx.queue);
+ Amsg_TxNotifyComplete(msg_ptr, Amsg_TxGetResultCode(msg_ptr), Amsg_TxGetResultInfo(msg_ptr)); /* just just notify completion, the object is */
+ } /* automatically freed to the pool */
+ }
+ }
+ Trcv_TxReleaseMsg(tel_ptr); /* release message object to pool */
+
+ if ((Dl_GetSize(&self_->tx.queue) > 0U) && (status != MNS_MSG_STAT_ERROR_SYNC)) /* Application Messages are available for Tx */
+ {
+ Srv_SetEvent(&self_->service, AMS_EV_TX_SERVICE);
+ }
+}
+
+/*! \brief Checks if the destination address of the Tx message is valid and payload is consistent
+ * \param msg_ptr Reference to the Tx message object
+ * \return Returns \c true if the destination is correct, otherwise \c false.
+ */
+bool Ams_TxIsValidMessage(Mns_AmsTx_Msg_t *msg_ptr)
+{
+ bool ret = false;
+
+ if (msg_ptr != NULL)
+ {
+ if ((msg_ptr->destination_address == MNS_ADDR_INTERNAL)
+ ||(msg_ptr->destination_address > AMS_ADDR_RSVD_RANGE)) /* is not reserved address? */
+ {
+ if (((msg_ptr->destination_address & 0xFF00U) != 0x0300U)/* is single-cast? */
+ || (msg_ptr->data_size <= SEGM_MAX_SIZE_TEL)) /* or not segmented */
+ {
+ if (!((msg_ptr->data_size > 0U) && (msg_ptr->data_ptr == NULL)))
+ {
+ ret = true;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*! \brief Retrieves the next follower id to use for segmented transfer
+ * \param self The instance
+ * \return The follower id
+ */
+static uint8_t Ams_TxGetNextFollowerId(CAms *self)
+{
+ uint8_t ret;
+ ret = self->tx.next_follower_id;
+ self->tx.next_follower_id++;
+
+ if (self->tx.next_follower_id == 0U) /* skip zero since it means */
+ { /* "no follower" */
+ self->tx.next_follower_id = 1U;
+ }
+
+ return ret;
+}
+
+/*! \brief Retrieves the number of messages that are queued for transmission
+ * \param self The instance
+ * \return The number of messages in the Tx queue
+ */
+uint16_t Ams_TxGetMsgCnt(CAms *self)
+{
+ return Dl_GetSize(&self->tx.queue);
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* AMS Reception */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Rx callback function that can be assigned to the MCM transceiver
+ * \details The associated transceiver reference will be stored in the telegrams \c info_ptr.
+ * Later on the telegram must be released via Ams_RxReleaseTel().
+ * \param self The instance
+ * \param tel_ptr Reference to the Rx telegram object
+ */
+void Ams_RxOnMcmTelComplete(void *self, Msg_MostTel_t *tel_ptr)
+{
+ CAms *self_ = (CAms*)self;
+ TR_ASSERT(self_->base_ptr->mns_inst_id, "[AMS]", (tel_ptr->info_ptr == NULL));
+ tel_ptr->info_ptr = self_->trcv_mcm_ptr;
+ Ams_RxOnTelComplete(self_, tel_ptr);
+}
+
+/*! \brief Rx callback function that can be assigned to the RCM transceiver
+ * \details The associated transceiver reference will be stored in the telegrams \c info_ptr.
+ * Later on the telegram must be released via Ams_RxReleaseTel().
+ * \param self The instance
+ * \param tel_ptr Reference to the Rx telegram object
+ */
+void Ams_RxOnRcmTelComplete(void *self, Msg_MostTel_t *tel_ptr)
+{
+ CAms *self_ = (CAms*)self;
+ TR_ASSERT(self_->base_ptr->mns_inst_id, "[AMS]", (tel_ptr->info_ptr == NULL));
+ tel_ptr->info_ptr = self_->trcv_rcm_ptr;
+ Ams_RxOnTelComplete(self_, tel_ptr);
+}
+
+/*! \brief Releases an Rx telegram to the associated transceiver
+ * \details The associated transceiver reference is stored in the telegrams \c info_ptr
+ * \param self The instance
+ * \param tel_ptr Reference to the Rx telegram object
+ */
+static void Ams_RxReleaseTel(CAms *self, Msg_MostTel_t *tel_ptr)
+{
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[AMS]", ((tel_ptr != NULL) && (tel_ptr->info_ptr != NULL)));
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[AMS]", ((tel_ptr->info_ptr == self->trcv_mcm_ptr)||(tel_ptr->info_ptr == self->trcv_rcm_ptr)));
+
+ if (tel_ptr->info_ptr != NULL)
+ {
+ Trcv_RxReleaseMsg((CTransceiver*)tel_ptr->info_ptr, tel_ptr);
+ }
+
+ MISC_UNUSED(self);
+}
+
+/*! \brief Internal callback function which is invoked as soon as the transceiver
+ * reference is stored to the telegrams info_ptr.
+ * \param self The instance
+ * \param tel_ptr Reference to the Rx telegram object
+ */
+static void Ams_RxOnTelComplete(CAms *self, Msg_MostTel_t *tel_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = NULL;
+
+ TR_INFO((self->base_ptr->mns_inst_id, "[AMS]", "Ams_RxOnComplete(0x%p)", 1U, tel_ptr));
+
+ if (self->rx.complete_fptr == NULL)
+ {
+ /* no processing required, tel_ptr shall be freed */
+ msg_ptr = NULL;
+ }
+ else if (Telq_GetSize(&self->rx.waiting_queue) > 0U) /* asynchronous Rx is running */
+ { /* queue Rx telegram for later processing */
+ Telq_Enqueue(&self->rx.waiting_queue, tel_ptr);
+ tel_ptr = NULL; /* do not free Rx telegram */
+ msg_ptr = NULL;
+ }
+ else
+ {
+ Segm_Result_t result; /* synchronous processing is possible now */
+ msg_ptr = Segm_RxExecuteSegmentation(&self->segmentation, tel_ptr, &result);
+
+ if (result == SEGM_RES_RETRY)
+ {
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[AMS]", (msg_ptr == NULL));
+ Telq_Enqueue(&self->rx.waiting_queue, tel_ptr);
+ tel_ptr = NULL; /* do not free Rx telegram */
+ }
+ }
+
+ if (msg_ptr != NULL)
+ {
+ self->rx.complete_fptr(self->rx.complete_inst_ptr, (Mns_AmsRx_Msg_t*)(void*)msg_ptr);
+ }
+
+ if (tel_ptr != NULL)
+ {
+ Ams_RxReleaseTel(self, tel_ptr); /* free Rx telegram */
+ }
+}
+
+/*! \brief Processes all telegrams in waiting queue
+ * \details Stops if allocation of Rx messages fails
+ * \param self The instance
+ */
+static void Ams_RxProcessWaitingQ(CAms *self)
+{
+ Msg_MostTel_t *tel_ptr;
+ Mns_AmsRx_Msg_t *msg_ptr = NULL;
+
+ for (tel_ptr = Telq_Peek(&self->rx.waiting_queue); tel_ptr != NULL; tel_ptr = Telq_Peek(&self->rx.waiting_queue))
+ {
+ Segm_Result_t result;
+ msg_ptr = Segm_RxExecuteSegmentation(&self->segmentation, tel_ptr, &result);
+
+ if (result == SEGM_RES_OK) /* segmentation process succeeded */
+ {
+ (void)Telq_Dequeue(&self->rx.waiting_queue); /* remove telegram from waitingQ */
+ Ams_RxReleaseTel(self, tel_ptr); /* free telegram */
+ tel_ptr = NULL; /* parasoft-suppress MISRA2004-13_6 "variable is not used as a counter" */
+
+ if (msg_ptr != NULL)
+ {
+ self->rx.complete_fptr(self->rx.complete_inst_ptr, (Mns_AmsRx_Msg_t*)(void*)msg_ptr);
+ }
+ }
+ else
+ {
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[AMS]", (msg_ptr == NULL));
+ break; /* wait until further Rx messages can be allocated - abort loop */
+ }
+ }
+}
+
+/*! \brief Callback function which is invoked by segmentation process to notify a segmentation error
+ * \param self The instance
+ * \param tel_ptr The related Rx telegram which caused the segmentation error
+ * \param error The segmentation error number
+ */
+static void Ams_RxOnSegError(void *self, Msg_MostTel_t *tel_ptr, Segm_Error_t error)
+{
+ const uint8_t ERR_SZ = 2U;
+ CAms *self_ = (CAms*)self;
+ Msg_MostTel_t* error_tel_ptr = NULL;
+
+ TR_ERROR((self_->base_ptr->mns_inst_id, "[AMS]", "Ams_RxOnComplete(0x%p, %d)", 2U, tel_ptr, error));
+
+ if (tel_ptr->source_addr != MSG_ADDR_INIC)
+ { /* only generate segmentation errors */
+ error_tel_ptr = Trcv_TxAllocateMsg(self_->trcv_mcm_ptr, ERR_SZ); /* for messages which are NOT locally routed by the INIC */
+ }
+
+ if (error_tel_ptr != NULL)
+ {
+ error_tel_ptr->destination_addr = tel_ptr->source_addr;
+ error_tel_ptr->id = tel_ptr->id;
+ error_tel_ptr->id.op_type = MNS_OP_ERROR;
+ error_tel_ptr->tel.tel_data_ptr[0] = 0x0CU;
+ error_tel_ptr->tel.tel_data_ptr[1] = (uint8_t)error;
+ error_tel_ptr->opts.llrbc = 0U;
+
+ Trcv_TxSendMsg(self_->trcv_mcm_ptr, error_tel_ptr); /* just fire the message */
+ }
+}
+
+/*! \brief Callback function that is invoked if application Rx messages are available again
+ * \param self The instance
+ * \param data_ptr Unused parameter of observer callback
+ */
+static void Ams_RxOnFreedMsg(void *self, void *data_ptr)
+{
+ CAms *self_ = (CAms*) self;
+ Srv_SetEvent(&self_->service, AMS_EV_RX_SERVICE);
+ MISC_UNUSED(data_ptr);
+}
+
+/*! \brief Removes and frees a message from the Rx queue
+ * \details The application must not access the passed
+ * message any more.
+ * \param self The instance
+ * \param msg_ptr Reference to the message, or \c NULL for the front-most
+ * message in the Rx queue.
+ */
+void Ams_RxFreeMsg(CAms *self, Mns_AmsRx_Msg_t *msg_ptr)
+{
+ TR_INFO((self->base_ptr->mns_inst_id, "[AMS]", "Ams_RxFreeMsg(msg_ptr=0x%p)", 1U, msg_ptr));
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[AMS]", (msg_ptr != NULL));
+
+ if (msg_ptr != NULL)
+ {
+ Amsp_FreeRxPayload(self->pool_ptr, msg_ptr); /* free external payload */
+ Amsp_FreeRxObj(self->pool_ptr, msg_ptr); /* return message to Rx pool */
+ }
+}
+
+/*! \brief Removes all messages located in Rx queues
+ * \param self The instance
+ */
+static void Ams_RxFlush(CAms *self)
+{
+ Msg_MostTel_t *tel_ptr;
+
+ for (tel_ptr = Telq_Dequeue(&self->rx.waiting_queue); tel_ptr != NULL; tel_ptr = Telq_Dequeue(&self->rx.waiting_queue))
+ {
+ Ams_RxReleaseTel(self, tel_ptr);
+ }
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_ams.h b/mnsl/mns_ams.h
new file mode 100644
index 0000000..fb291c1
--- /dev/null
+++ b/mnsl/mns_ams.h
@@ -0,0 +1,163 @@
+/*
+ * 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 Service
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_AMSC
+ * @{
+ */
+
+#ifndef MNS_AMS_H
+#define MNS_AMS_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_ams_pb.h"
+#include "mns_amsmessage.h"
+#include "mns_amspool.h"
+#include "mns_pool.h"
+#include "mns_transceiver.h"
+#include "mns_pmchannel.h"
+#include "mns_ret.h"
+#include "mns_segmentation.h"
+#include "mns_message.h"
+#include "mns_telqueue.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal constants */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Defines the default LLR number for Application Messages */
+#define AMS_LLRBC_DEFAULT (MSG_LLRBC_DEFAULT)
+/*! \brief Defines the maximum LLR number for Application Messages */
+#define AMS_LLRBC_MAX (MSG_LLRBC_MAX)
+/*! \brief Default memory size that is allocated when receiving segmented messages
+ * without size prefix */
+#define AMS_RX_DEF_SIZE_PAYLOAD 400U
+/*! \brief Maximum destination address which is reserved for internal transmission */
+#define AMS_ADDR_RSVD_RANGE 0x000FU
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Callback function type to request FIFO routing for a Tx message.
+ * \param msg_ptr Reference to a Tx message object
+ * \return Returns \c true if a Tx message shall be routed to RCM FIFO, otherwise returns \c false.
+ */
+typedef bool (*Ams_TxIsRcmMsgCb_t)(Mns_AmsTx_Msg_t *msg_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class */
+/*------------------------------------------------------------------------------------------------*/
+
+/*! \brief Application Message Service Class
+ * \details Allows transmission and reception of MOST Application Messages
+ */
+typedef struct CAms_
+{
+ CService service; /*!< \brief Service object */
+ CSegmentation segmentation; /*!< \brief Segmentation object */
+ CMaskedObserver unsync_result_observer; /*!< \brief Observes un-sync result */
+
+ CBase *base_ptr; /*!< \brief Reference to basic services */
+ CAmsMsgPool *pool_ptr; /*!< \brief Pool providing Rx and Tx objects/payload */
+ CTransceiver *trcv_mcm_ptr; /*!< \brief Reference to MCM transceiver */
+ CTransceiver *trcv_rcm_ptr; /*!< \brief Reference to RCM transceiver */
+
+ struct Ams_tx_
+ {
+ CDlList queue; /*!< \brief Input queue of Tx Application Messages */
+ uint8_t default_llrbc; /*!< \brief Default LowLevelRetryBlockCount. Valid values: 0..100 */
+ Ams_TxIsRcmMsgCb_t is_rcm_fptr; /*!< \brief Assignable callback function to request the correct transceiver */
+ uint8_t next_follower_id; /*!< \brief The follower id for the next segmented
+ * message
+ */
+ } tx;
+
+ struct Ams_rx_
+ {
+ CObserver message_freed_observer; /*!< \brief Observes message freed event */
+
+ Amsg_RxCompleteCb_t complete_fptr; /*!< \brief Callback function which is invoked on
+ * message reception
+ */
+ void *complete_inst_ptr; /*!< \brief Instance which is notified on
+ * message reception
+ */
+ CTelQueue waiting_queue; /*!< \brief Queue of unprocessed single telegrams */
+
+ } rx;
+
+} CAms;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Initialization Methods */
+/*------------------------------------------------------------------------------------------------*/
+extern void Ams_Ctor(CAms *self, CBase *base_ptr, CTransceiver *mcm_trcv_ptr, CTransceiver *rcm_trcv_ptr,
+ CAmsMsgPool *pool_ptr, uint16_t rx_def_payload_sz);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Public methods / Tx */
+/*------------------------------------------------------------------------------------------------*/
+extern void Ams_TxSetDefaultRetries(CAms *self, uint8_t llrbc);
+extern void Ams_TxAssignMsgFreedObs(CAms *self, CObserver *observer_ptr);
+extern void Ams_TxAssignTrcvSelector(CAms *self, Ams_TxIsRcmMsgCb_t cb_fptr);
+extern Mns_AmsTx_Msg_t* Ams_TxGetMsg(CAms *self, uint16_t size);
+extern void Ams_TxFreeUnusedMsg(CAms *self, Mns_AmsTx_Msg_t *msg_ptr);
+extern uint16_t Ams_TxGetMsgCnt(CAms *self);
+extern bool Ams_TxIsValidMessage(Mns_AmsTx_Msg_t *msg_ptr);
+extern void Ams_TxSendMsgDirect(CAms *self, Mns_AmsTx_Msg_t *msg_ptr);
+extern Mns_Return_t Ams_TxSendMsg(CAms *self, Mns_AmsTx_Msg_t *msg_ptr, Amsg_TxCompleteSiaCb_t tx_complete_sia_fptr,
+ Amsg_TxCompleteCb_t tx_complete_fptr, void* tx_complete_inst_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Public methods / Rx */
+/*------------------------------------------------------------------------------------------------*/
+extern void Ams_RxAssignReceiver(CAms *self, Amsg_RxCompleteCb_t cb_fptr, void *inst_ptr);
+extern void Ams_RxFreeMsg(CAms *self, Mns_AmsRx_Msg_t *msg_ptr);
+extern void Ams_RxOnMcmTelComplete(void *self, Msg_MostTel_t *tel_ptr);
+extern void Ams_RxOnRcmTelComplete(void *self, Msg_MostTel_t *tel_ptr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* MNS_AMS_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_ams_pb.h b/mnsl/mns_ams_pb.h
new file mode 100644
index 0000000..a559c94
--- /dev/null
+++ b/mnsl/mns_ams_pb.h
@@ -0,0 +1,262 @@
+/*
+ * 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 Public header file of Application Message Service
+ */
+/*!
+ * \addtogroup G_MNS_AMS_TYPES
+ * @{
+ */
+
+#ifndef MNS_AMS_PB_H
+#define MNS_AMS_PB_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+#include "mns_message_pb.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*! \brief Defines which address type was used by the transmitter of a message. */
+typedef enum Mns_AmsRx_ReceiveType_
+{
+ MNS_AMSRX_RCT_SINGLECAST = 0U, /*!< \brief Message was transmitted as singlecast */
+ MNS_AMSRX_RCT_GROUPCAST = 1U, /*!< \brief Message was transmitted as groupcast */
+ MNS_AMSRX_RCT_BROADCAST = 2U /*!< \brief Message was transmitted as broadcast */
+
+} Mns_AmsRx_ReceiveType_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Application message Tx type */
+typedef struct Mns_AmsTx_Msg_
+{
+ uint16_t destination_address; /*!< \brief Destination address. Find some predefined addresses \ref G_MNS_AMS "here". */
+ uint8_t fblock_id; /*!< \brief Function block ID (MOST FBlockID). */
+ uint8_t instance_id; /*!< \brief Instance ID (MOST InstID). */
+ uint16_t function_id; /*!< \brief Function ID (MOST FktID). */
+ Mns_OpType_t op_type; /*!< \brief Operation type (MOST OpType). */
+ uint8_t llrbc; /*!< \brief Specifies the "Low-Level Retry Block Count" (LLRBC)
+ * \details Valid values: 0..100. Default value: configurable via \ref Mns_AmsTx_InitData_t "default_llrbc"
+ * of the initialization structure \ref Mns_AmsTx_InitData_t.
+ * \mns_ic_inic{ See also <i>INIC API User's Guide</i>, section \ref SEC_OS81118_19. }
+ */
+ uint8_t *data_ptr; /*!< \brief Payload data */
+ uint16_t data_size; /*!< \brief The size of payload data in bytes */
+ void *custom_info_ptr; /*!< \brief Customer specific reference
+ * \details The application is allowed to use this attribute to assign an
+ * own reference to the message object. The reference is initialized
+ * by MOST NetServices with \c NULL and will not alter until the
+ * transmission has finished.
+ */
+} Mns_AmsTx_Msg_t;
+
+/*! \brief Application message Rx type */
+typedef struct Mns_AmsRx_Msg_
+{
+ uint16_t source_address; /*!< \brief Source address */
+ uint8_t fblock_id; /*!< \brief Function block ID (MOST FBlockID). */
+ uint8_t instance_id; /*!< \brief Instance ID (MOST InstID). */
+ uint16_t function_id; /*!< \brief Function ID (MOST FktID). */
+ Mns_OpType_t op_type; /*!< \brief Operation type (MOST OpType). */
+ uint8_t *data_ptr; /*!< \brief Reference to payload */
+ uint16_t data_size; /*!< \brief Payload size in bytes */
+ void *custom_info_ptr; /*!< \brief Customer specific reference */
+ Mns_AmsRx_ReceiveType_t receive_type; /*!< \brief Defines which address type was used by the transmitter of this message */
+
+} Mns_AmsRx_Msg_t;
+
+/*! \brief Transmission result of an application message */
+typedef enum Mns_AmsTx_Result_
+{
+ MNS_AMSTX_RES_SUCCESS = 0x00U,/*!< \brief The transmission succeeded. */
+
+ MNS_AMSTX_RES_ERR_RETRIES_EXP = 0x01U,/*!< \brief The transmission including all retries have failed.
+ * \details The following issues may have caused the failure:
+ * - message corruption
+ * - transmission timeouts
+ * - full receive buffers of the destination device
+ * - full receive buffers of the local device if the
+ * destination was the own address, own group or broadcast
+ * address
+ * .
+ */
+ MNS_AMSTX_RES_ERR_INVALID_TGT = 0x02U,/*!< \brief The transmission failed because the specified destination
+ * address is not found or not valid.
+ * \details The following issues may have caused the failure:
+ * - device with the given destination address is not found
+ * - destination address is reserved (for future use)
+ * - destination address is 0xFFFF (un-initialized logical
+ * node address is not supported)
+ * .
+ */
+ MNS_AMSTX_RES_ERR_NOT_AVAILABLE = 0x03U,/*!< \brief The transmission failed since the network or the INIC
+ * is not available.
+ */
+ MNS_AMSTX_RES_ERR_BUF_INTERNAL = 0xFEU,/*!< \brief The transmission failed because the allocation of an Rx message object failed.
+ * The Rx message object is required to receive the message via the own Rx message queue.
+ * \details This is possible in the following cases:
+ * - A message is transmitted to the own node address and the allocation
+ * of an Rx message object failed.
+ * - The network transmission to the own group address or broadcast address
+ * succeeded but the allocation of an Rx message object failed. The application
+ * has to decide whether to retransmit the message to the own address again.
+ */
+ MNS_AMSTX_RES_ERR_UNEXPECTED = 0xFFU /*!< \brief The transmission failed due to an unexpected error.
+ * The cause of this failure may be an invalid INIC configuration,
+ * or an INIC to MOST NetServices incompatibility issue.
+ */
+} Mns_AmsTx_Result_t;
+
+
+/*! \brief Detailed INIC transmission information which might be useful for debugging purposes. */
+typedef enum Mns_AmsTx_Info_
+{
+ MNS_AMSTX_I_SUCCESS = 0x00U, /*!< \brief The transmission succeeded.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_SUCCESS.
+ */
+ MNS_AMSTX_I_ERR_CFG_NORECEIVER = 0x01U, /*!< \brief The transmission failed because the MOST network is not accessible for
+ * MCM in the current attach state or for ICM in general.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_UNEXPECTED.
+ */
+ MNS_AMSTX_I_ERR_BF = 0x08U, /*!< \brief The transmission failed because the receivers buffer is full.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_RETRIES_EXP.
+ */
+ MNS_AMSTX_I_ERR_CRC = 0x09U, /*!< \brief The transmission failed because of a failed CRC.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_RETRIES_EXP.
+ */
+ MNS_AMSTX_I_ERR_ID = 0x0AU, /*!< \brief The transmission failed because of corrupted identifiers.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_RETRIES_EXP.
+ */
+ MNS_AMSTX_I_ERR_ACK = 0x0BU, /*!< \brief The transmission failed because of corrupted PACK or CACK.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_RETRIES_EXP.
+ */
+ MNS_AMSTX_I_ERR_TIMEOUT = 0x0CU, /*!< \brief The transmission failed because of a transmission timeout.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_RETRIES_EXP.
+ */
+ MNS_AMSTX_I_ERR_FATAL_WT = 0x10U, /*!< \brief The transmission failed because of destination is not available.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_INVALID_TGT.
+ */
+ MNS_AMSTX_I_ERR_FATAL_OA = 0x11U, /*!< \brief The transmission failed because of the destination is the own node address.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_INVALID_TGT.
+ */
+ MNS_AMSTX_I_ERR_UNAVAIL_TRANS = 0x18U, /*!< \brief The transmission canceled during the transition from network interface state
+ * "available" to "not available".
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_NOT_AVAILABLE.
+ */
+ MNS_AMSTX_I_ERR_UNAVAIL_OFF = 0x19U, /*!< \brief The transmission failed because the network interface state is "not available".
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_NOT_AVAILABLE.
+ */
+ MNS_AMSTX_I_ERR_UNKNOWN = 0xFEU, /*!< \brief The transmission failed because of an unknown INIC error code.
+ * \details The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_UNEXPECTED.
+ * Please check if the MNS version is compatible with the applied INIC firmware version.
+ */
+ MNS_AMSTX_I_ERR_UNSYNCED = 0xFFU /*!< \brief The transmission failed because the communication between the EHC (MOST NetServices)
+ * and the INIC is lost.
+ * \details The reason can be a communication error between the EHC and the INIC or that
+ * the application has called Mns_Stop().\n
+ * The corresponding transmission result is \ref MNS_AMSTX_RES_ERR_NOT_AVAILABLE.
+ */
+} Mns_AmsTx_Info_t;
+
+
+/*! \brief Defines the usage of a requested memory chunk */
+typedef enum Mns_Ams_MemUsage_
+{
+ MNS_AMS_RX_OBJECT, /*!< \brief Memory is required to allocate an Rx message object */
+ MNS_AMS_RX_PAYLOAD, /*!< \brief Memory is required to allocate Rx message payload */
+ MNS_AMS_TX_OBJECT, /*!< \brief Memory is required to allocate a Tx message object */
+ MNS_AMS_TX_PAYLOAD /*!< \brief Memory is required to allocate Tx message payload */
+
+} Mns_Ams_MemUsage_t;
+
+/*! \brief Callback function type that is invoked to allocate external payload for a segmented Rx message
+ * \param inst_ptr Reference to the (external) memory management
+ * \param mem_size Reference to the required memory size in bytes. Valid values: 0..65535.
+ * \param type Declares how the memory is used by the MOST NetServices
+ * \param custom_info_pptr Reference which is related to the memory chunk and can be set by
+ * the application.
+ * \return Pointer to the provided memory chunk. The application has to guarantee that the memory size
+ * is equal or greater than \c mem_size. The application has to return \c NULL if it is not able
+ * to allocate the required memory at this moment.
+ */
+typedef void* (*Mns_Ams_AllocMemCb_t)(void *inst_ptr, uint16_t mem_size, Mns_Ams_MemUsage_t type, void** custom_info_pptr);
+
+/*! \brief Callback function type that is invoked to free external payload for a segmented Rx message
+ * \param inst_ptr Reference to the (external) memory management
+ * \param mem_ptr Reference to the external payload memory
+ * \param type Declares how the memory is used by the MOST NetServices
+ * \param custom_info_ptr Reference to memory related information which was set by the application
+ * during memory allocation
+ */
+typedef void (*Mns_Ams_FreeMemCb_t)(void *inst_ptr, void *mem_ptr, Mns_Ams_MemUsage_t type, void* custom_info_ptr);
+
+/*! \brief Type of a callback function that is invoked by the MOST NetServices as soon as a
+ * message transmission was finished
+ * \details The callback function notifies the result of a completed transmission. If
+ * the message has external payload, the application must decide whether
+ * to re-use or to free the external payload.
+ * \param msg_ptr Reference to the related Tx message object. When the callback function returns
+ * the reference is no longer valid.
+ * \param result The transmission result.
+ * \param info Detailed INIC transmission result, which might be helpful for debug purposes.
+ */
+typedef void (*Mns_AmsTx_CompleteCb_t)(Mns_AmsTx_Msg_t* msg_ptr, Mns_AmsTx_Result_t result, Mns_AmsTx_Info_t info);
+
+/*!
+ * @}
+ * \addtogroup G_MNS_AMS
+ * @{
+ */
+
+/*! \brief Type of a callback function that is invoked by MOST NetServices to notify that
+ * a Tx application message object is available again while a previous
+ * allocation using Mns_AmsTx_AllocMsg() has failed.
+ */
+typedef void (*Mns_AmsTx_MsgFreedCb_t)(void);
+
+/*! \brief Callback function type that is invoked if the MOST NetServices has received a message
+ * completely and appended to the Rx message queue.
+ */
+typedef void (*Mns_AmsRx_MsgReceivedCb_t)(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ifndef MNS_AMS_PB_H */
+
+/*! @} */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_amsmessage.c b/mnsl/mns_amsmessage.c
new file mode 100644
index 0000000..11ba985
--- /dev/null
+++ b/mnsl/mns_amsmessage.c
@@ -0,0 +1,656 @@
+/*
+ * 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 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 */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_amsmessage.h b/mnsl/mns_amsmessage.h
new file mode 100644
index 0000000..b1faa65
--- /dev/null
+++ b/mnsl/mns_amsmessage.h
@@ -0,0 +1,217 @@
+/*
+ * 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 */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_amspool.c b/mnsl/mns_amspool.c
new file mode 100644
index 0000000..3ce89ae
--- /dev/null
+++ b/mnsl/mns_amspool.c
@@ -0,0 +1,336 @@
+/*
+ * 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 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 */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_amspool.h b/mnsl/mns_amspool.h
new file mode 100644
index 0000000..387dc9b
--- /dev/null
+++ b/mnsl/mns_amspool.h
@@ -0,0 +1,100 @@
+/*
+ * 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 Pools
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_AMSPOOL
+ * @{
+ */
+
+#ifndef MNS_AMSPOOL_H
+#define MNS_AMSPOOL_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_ams_pb.h"
+#include "mns_amsmessage.h"
+#include "mns_obs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Classes */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class members of AMS Pool */
+typedef struct CAmsMsgPool_
+{
+ Ams_MemAllocator_t *allocator_ptr; /*!< \brief Interface to memory allocator */
+ Mns_AmsRx_Msg_t *rx_rsvd_msg_ptr; /*!< \brief Pre-allocated Rx message or NULL if no
+ * reserved message is available */
+ Mns_AmsRx_Msg_t *rx_rsvd_msg_ref; /*!< \brief Stores the reference of the reserved message
+ * to identify it and restore the
+ * \c rx_rsvd_msg_ptr. */
+ CSubject tx_freed_subject; /*!< \brief Allows to observe freed Tx message event */
+ CSubject rx_freed_subject; /*!< \brief Allows to observe freed Rx message event */
+ bool tx_notify_freed; /*!< \brief Is \c true when to notify the next Tx freed object */
+ bool rx_notify_freed; /*!< \brief Is \c true when to notify the next Rx freed object */
+ bool terminated; /*!< \brief Is \c true if a cleanup was done. Helps to release the
+ * pre-allocated message after the first cleanup attempt. */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+
+} CAmsMsgPool;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class methods */
+/*------------------------------------------------------------------------------------------------*/
+extern void Amsp_Ctor(CAmsMsgPool *self, Ams_MemAllocator_t *mem_allocator_ptr, uint8_t mns_inst_id);
+extern void Amsp_Cleanup(CAmsMsgPool *self);
+/* Tx */
+extern void Amsp_AssignTxFreedObs(CAmsMsgPool *self, CObserver *observer_ptr);
+extern Mns_AmsTx_Msg_t* Amsp_AllocTxObj(CAmsMsgPool *self, uint16_t payload_sz);
+/* Rx */
+extern void Amsp_AssignRxFreedObs(CAmsMsgPool *self, CObserver *observer_ptr);
+extern Mns_AmsRx_Msg_t* Amsp_AllocRxObj(CAmsMsgPool *self, uint16_t payload_sz);
+extern Mns_AmsRx_Msg_t* Amsp_AllocRxRsvd(CAmsMsgPool *self);
+extern bool Amsp_AllocRxPayload(CAmsMsgPool *self, uint16_t payload_sz, Mns_AmsRx_Msg_t* msg_ptr);
+extern void Amsp_FreeRxObj(CAmsMsgPool *self, Mns_AmsRx_Msg_t* msg_ptr);
+extern void Amsp_FreeRxPayload(CAmsMsgPool *self, Mns_AmsRx_Msg_t* msg_ptr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* MNS_AMSPOOL_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_base.c b/mnsl/mns_base.c
new file mode 100644
index 0000000..542e485
--- /dev/null
+++ b/mnsl/mns_base.c
@@ -0,0 +1,70 @@
+/*
+ * 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 Implementation of the Base class.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_BASE
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_base.h"
+#include "mns_misc.h"
+#include "mns_message.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CBase */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the Base class.
+ * \param self Instance pointer
+ * \param init_ptr Reference to the initialization data
+ */
+void Base_Ctor(CBase *self, Base_InitData_t *init_ptr)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ /* Save MOST NetServices instance ID */
+ self->mns_inst_id = init_ptr->mns_inst_id;
+ /* Create the scheduler instance */
+ Scd_Ctor(&self->scd, &init_ptr->scd);
+ /* Create the timer management instance */
+ Tm_Ctor(&self->tm, &self->scd, &init_ptr->tm);
+ /* Create the event handler instance */
+ Eh_Ctor(&self->eh, self->mns_inst_id);
+ /* Create the API locking manager instance */
+ Alm_Ctor(&self->alm, &self->tm, &self->eh, self->mns_inst_id);
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_base.h b/mnsl/mns_base.h
new file mode 100644
index 0000000..132243d
--- /dev/null
+++ b/mnsl/mns_base.h
@@ -0,0 +1,93 @@
+/*
+ * 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 the Base class.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_BASE
+ * @{
+ */
+
+#ifndef MNS_BASE_H
+#define MNS_BASE_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+#include "mns_timer.h"
+#include "mns_scheduler.h"
+#include "mns_trace.h"
+#include "mns_eh.h"
+#include "mns_alm.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Initialization structure of the Base class. */
+typedef struct Base_InitData_
+{
+ Scd_InitData_t scd; /*!< \brief Initialization data of the scheduler */
+ Tm_InitData_t tm; /*!< \brief Initialization data of the timer management */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+
+} Base_InitData_t;
+
+/*! \brief Class structure of the Base class. */
+typedef struct CBase_
+{
+ CScheduler scd; /*!< \brief Scheduler instance */
+ CTimerManagement tm; /*!< \brief Timer management instance */
+ CEventHandler eh; /*!< \brief Event handler instance */
+ CApiLockingManager alm; /*!< \brief API locking manager instance */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+
+} CBase;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes */
+/*------------------------------------------------------------------------------------------------*/
+void Base_Ctor(CBase *self, Base_InitData_t *init_ptr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_BASE_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_cfg.h b/mnsl/mns_cfg.h
new file mode 100644
index 0000000..dcf6e2b
--- /dev/null
+++ b/mnsl/mns_cfg.h
@@ -0,0 +1,67 @@
+/*
+ * 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 Configuration header file of MOST NetServices Light
+ */
+
+#ifndef MNSL_CFG_H
+#define MNSL_CFG_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* File only needed for other includes. */
+#include "mns_types_cfg.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Message Pool */
+/*------------------------------------------------------------------------------------------------*/
+/* Sets the number of pre-allocated Rx messages which are shared by all FIFOs. Default value: 35*/
+/* #define MNSL_CHANNEL_POOL_SIZE_RX 35 */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Tracing & Debugging */
+/*------------------------------------------------------------------------------------------------*/
+/* Define the following macros to map info and error trace output to user defined functions.
+ * The purpose of these functions is debugging. It is not recommended to define these functions
+ * in a production system.
+ */
+#define MNS_TR_ERROR My_TraceError
+// #define MNS_TR_INFO My_TraceInfo
+
+extern void My_TraceError(uint8_t mns_inst_id, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...);
+extern void My_TraceInfo(uint8_t mns_inst_id, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNSL_CFG_H */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
diff --git a/mnsl/mns_dl.c b/mnsl/mns_dl.c
new file mode 100644
index 0000000..7a7a322
--- /dev/null
+++ b/mnsl/mns_dl.c
@@ -0,0 +1,392 @@
+/*
+ * 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 Implementation of the doubly linked list.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_DL
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_dl.h"
+#include "mns_trace.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CDlList */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the doubly linked list class.
+ * \param self Instance pointer
+ * \param mns_inst_id MOST NetServices instance ID
+ */
+void Dl_Ctor(CDlList *self, uint8_t mns_inst_id)
+{
+ self->head = NULL;
+ self->tail = NULL;
+ self->size = 0U;
+ self->mns_inst_id = mns_inst_id;
+}
+
+/*! \brief Inserts a new node after an arbitrary node.
+ * \param self Instance pointer
+ * \param node Reference of the initial node
+ * \param new_node Reference of the new node are to be inserted
+ */
+void Dl_InsertAfter(CDlList *self, CDlNode *node, CDlNode *new_node)
+{
+ TR_ASSERT(self->mns_inst_id, "[DL]", (self->size <= 0xFFFFU));
+ new_node->prev = node;
+ new_node->next = node->next;
+ if(node->next == NULL) /* Is initial node last node in list? */
+ {
+ self->tail = new_node; /* Set new node as tail of list */
+ }
+ else
+ {
+ node->next->prev = new_node; /* Adjust follower node */
+ }
+ node->next = new_node; /* Adjust parent node */
+ new_node->in_use = true; /* Signals that node is part of a list */
+ self->size++; /* Increment number of nodes */
+}
+
+/*! \brief Inserts a new node before an arbitrary node.
+ * \param self Instance pointer
+ * \param node Reference of the initial node
+ * \param new_node Reference of the new node are to be inserted
+ */
+void Dl_InsertBefore(CDlList *self, CDlNode *node, CDlNode *new_node)
+{
+ TR_ASSERT(self->mns_inst_id, "[DL]", (self->size <= 0xFFFFU));
+ new_node->prev = node->prev;
+ new_node->next = node;
+ if(node->prev == NULL) /* Is initial node first node in list? */
+ {
+ self->head = new_node; /* Set new node as head of list */
+ }
+ else
+ {
+ node->prev->next = new_node; /* Adjust parent node */
+ }
+ node->prev = new_node; /* Adjust follower node */
+ new_node->in_use = true; /* Signals that node is part of a list */
+ self->size++; /* Increment number of nodes */
+}
+
+/*! \brief Sets the new node as head of a doubly linked list.
+ * \param self Instance pointer
+ * \param new_node Reference of the new node are to be placed as head of the list
+ */
+void Dl_InsertHead(CDlList *self, CDlNode *new_node)
+{
+ if(self->head == NULL) /* Is list empty? */
+ {
+ TR_ASSERT(self->mns_inst_id, "[DL]", (self->size <= 0xFFFFU));
+ self->head = new_node;
+ self->tail = new_node;
+ new_node->prev = NULL;
+ new_node->next = NULL;
+ new_node->in_use = true; /* Signals that node is part of a list */
+ self->size++; /* Increment number of nodes */
+ }
+ else
+ {
+ Dl_InsertBefore(self, self->head, new_node);
+ }
+}
+
+/*! \brief Inserts the new node at the end of a doubly linked list.
+ * \param self Instance pointer
+ * \param new_node Reference of the new node are to be placed at the end of the list
+ */
+void Dl_InsertTail(CDlList *self, CDlNode *new_node)
+{
+ if(self->tail == NULL) /* Is list empty? */
+ {
+ Dl_InsertHead(self, new_node);
+ }
+ else
+ {
+ Dl_InsertAfter(self, self->tail, new_node);
+ }
+}
+
+/*! \brief Removes an arbitrary node from a doubly linked list.
+ * \param self Instance pointer
+ * \param node Reference of the node are to be removed from the list
+ * \return \c DL_OK: No error
+ * \return \c DL_UNKNOWN_NODE: Given node is not part of this list
+ */
+Dl_Ret_t Dl_Remove(CDlList *self, CDlNode *node)
+{
+ Dl_Ret_t ret_val = DL_UNKNOWN_NODE;
+
+ if(Dl_IsNodeInList(self, node) != false) /* Is node part of list? */
+ {
+ TR_ASSERT(self->mns_inst_id, "[DL]", (self->size > 0U));
+ if(node->prev == NULL) /* First node in list? */
+ {
+ self->head = node->next; /* Replace head node with next node in list */
+ }
+ else /* -> Not first node in list */
+ {
+ node->prev->next = node->next; /* Set next pointer of previous node to next node */
+ }
+ if(node->next == NULL) /* Last node in list? */
+ {
+ self->tail = node->prev; /* Replace tail node with previous node in list */
+ }
+ else /* -> Not last node in list */
+ {
+ node->next->prev = node->prev; /* Set previous ptr of next node to previous node */
+ }
+ node->prev = NULL;
+ node->next = NULL;
+ node->in_use = false; /* Signals that node is not part of a list */
+ ret_val = DL_OK;
+ self->size--; /* Decrement number of nodes */
+ }
+
+ return ret_val;
+}
+
+/*! \brief Removes the first node in a doubly linked list.
+ * \param self Instance pointer
+ * \return The reference of the removed head node or \c NULL if the list is empty.
+ */
+CDlNode * Dl_PopHead(CDlList *self)
+{
+ CDlNode *node = self->head;
+
+ if(NULL != node) /* Is list not empty? */
+ {
+ TR_ASSERT(self->mns_inst_id, "[DL]", (self->size > 0U));
+ self->head = node->next; /* Replace head node with next node in list */
+ if(node->next == NULL) /* Last node in list? */
+ {
+ self->tail = NULL; /* Replace tail node and set list's tail pointer
+ * to NULL
+ */
+ }
+ else /* -> Not last node in list */
+ {
+ node->next->prev = NULL; /* Set previous pointer of next node to NULL */
+ }
+ node->prev = NULL;
+ node->next = NULL;
+ node->in_use = false; /* Signals that node is not part of a list */
+ self->size--; /* Decrement number of nodes */
+ }
+
+ return node;
+}
+
+/*! \brief Removes the last node in a doubly linked list.
+ * \param self Instance pointer
+ * \return The reference of the removed tail node or \c NULL if the list is empty.
+ */
+CDlNode * Dl_PopTail(CDlList *self)
+{
+ CDlNode *node = self->tail;
+
+ if(NULL != node) /* Is list not empty? */
+ {
+ TR_ASSERT(self->mns_inst_id, "[DL]", (self->size > 0U));
+ if(node->prev == NULL) /* First node in list? */
+ {
+ self->head = NULL; /* Replace head node and set list's head pointer
+ * to NULL
+ */
+ }
+ else /* -> Not first node in list */
+ {
+ node->prev->next = NULL; /* Set next pointer of previous node to NULL */
+ }
+ self->tail = node->prev; /* Replace tail node with previous node in list */
+ node->prev = NULL;
+ node->next = NULL;
+ node->in_use = false; /* Signals that node is not part of a list */
+ self->size--; /* Decrement number of nodes */
+ }
+
+ return node;
+}
+
+/*! \brief Returns the reference of the first node in a doubly linked list.
+ * \param self Instance pointer
+ * \return The reference of the head node or \c NULL if the list is empty.
+ */
+CDlNode * Dl_PeekHead(CDlList *self)
+{
+ return self->head;
+}
+
+/*! \brief Returns the reference of the last node in a doubly linked list.
+ * \param self Instance pointer
+ * \return The reference of the tail node or NULL if the list is empty.
+ */
+CDlNode * Dl_PeekTail(CDlList *self)
+{
+ return self->tail;
+}
+
+/*! \brief Calls the given function for each node in the doubly linked list. If the func_ptr
+ * returns true the loop is stopped and the current node will be returned.
+ * \param self Instance pointer
+ * \param func_ptr Reference of the callback function which is called for each node
+ * \param user_data_ptr Reference of optional user data given to func_ptr
+ * \return Returns the current node or \c NULL if the whole list is processed.
+ */
+CDlNode * Dl_Foreach(CDlList *self, Dl_ForeachFunc_t func_ptr, void *user_data_ptr)
+{
+ CDlNode *ret_val = NULL;
+ CDlNode *node = self->head;
+
+ while(NULL != node) /* End of list reached? */
+ {
+ if(func_ptr(node->data_ptr, user_data_ptr) != false) /* Data found? */
+ {
+ ret_val = node;
+ break;
+ }
+ node = node->next;
+ }
+ return ret_val;
+}
+
+/*! \brief Checks if a node is part of the given doubly linked list.
+ * \param self Instance pointer
+ * \param node Reference of the searched node
+ * \return \c true: Node is part of the given list
+ * \return \c false: Node is not part of the given list
+ */
+bool Dl_IsNodeInList(CDlList *self, const CDlNode *node)
+{
+ bool ret_val = false;
+ CDlNode *current_node = self->head;
+
+ while(NULL != current_node) /* End of list reached? */
+ {
+ if(current_node == node) /* Is current node the searched one */
+ {
+ ret_val = true;
+ break;
+ }
+ current_node = current_node->next;
+ }
+ return ret_val;
+}
+
+/*! \brief Appends one doubly linked list to another doubly linked list.
+ * \param self Instance pointer
+ * \param list_ptr Reference to the doubly linked list
+ */
+void Dl_AppendList(CDlList *self, CDlList *list_ptr)
+{
+ TR_ASSERT(self->mns_inst_id, "[DL]", (list_ptr != NULL));
+ if(list_ptr->head != NULL)
+ {
+ if(self->tail == NULL) /* Is list empty? */
+ {
+ self->head = list_ptr->head;
+ self->tail = list_ptr->tail;
+ self->size = list_ptr->size;
+ }
+ else
+ {
+ list_ptr->head->prev = self->tail;
+ self->tail->next = list_ptr->head;
+ self->tail = list_ptr->tail;
+ self->size += list_ptr->size;
+ }
+ list_ptr->head = NULL;
+ list_ptr->tail = NULL;
+ list_ptr->size = 0U;
+ }
+}
+
+/*! \brief Interface function to retrieve the list size.
+ * \param self Instance pointer
+ * \return Size of the list
+ */
+uint16_t Dl_GetSize(CDlList *self)
+{
+ return self->size;
+}
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CDlNode */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of doubly linked list nodes.
+ * \param self Instance pointer
+ * \param data_ptr Optional reference to data
+ */
+void Dln_Ctor(CDlNode *self, void *data_ptr)
+{
+ self->next = NULL;
+ self->prev = NULL;
+ self->in_use = false;
+ self->data_ptr = data_ptr;
+}
+
+/*! \brief Interface function to set the data pointer of the given node.
+ * \param self Instance pointer
+ * \param data_ptr Reference of the new data
+ */
+void Dln_SetData(CDlNode *self, void *data_ptr)
+{
+ self->data_ptr = data_ptr;
+}
+
+/*! \brief Interface function to request the data pointer of the given node.
+ * \param self Instance pointer
+ */
+void * Dln_GetData(CDlNode *self)
+{
+ return self->data_ptr;
+}
+
+/*! \brief Checks if a node is part of a doubly linked list.
+ * \param self Instance pointer of the searched node
+ * \return \c true: Node is part of a list
+ * \return \c false: Node is not part of a list
+ */
+bool Dln_IsNodePartOfAList(CDlNode *self)
+{
+ return self->in_use;
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_dl.h b/mnsl/mns_dl.h
new file mode 100644
index 0000000..96e89e3
--- /dev/null
+++ b/mnsl/mns_dl.h
@@ -0,0 +1,132 @@
+/*
+ * 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 the doubly linked list.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_DL
+ * @{
+ */
+
+#ifndef MNS_DL_H
+#define MNS_DL_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_types_cfg.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Type definitions */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Callback signature used by foreach-function
+ * \param d_ptr Reference to the data of the current node
+ * \param up_ptr Reference to the user data
+ * \return true: Stop the for-each-loop
+ * \return false: Continue the for-each-loop
+ */
+typedef bool(*Dl_ForeachFunc_t)(void *d_ptr, void *ud_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Enumerators */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Standard return values of the list module. */
+typedef enum Dl_Ret_
+{
+ DL_OK, /*!< \brief No error */
+ DL_UNKNOWN_NODE, /*!< \brief Unknown node */
+ DL_STOPPED /*!< \brief Search process stopped */
+
+} Dl_Ret_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class structure of doubly linked list node. */
+typedef struct DlNode_
+{
+ struct DlNode_ *prev; /*!< \brief Reference to previous node in list */
+ struct DlNode_ *next; /*!< \brief Reference to next node in list */
+ void *data_ptr; /*!< \brief Reference to optional data */
+ bool in_use; /*!< \brief Flag which signals that the node is in use */
+
+} CDlNode;
+
+/*! \brief Class structure of the doubly linked list. */
+typedef struct CDlList_
+{
+ struct DlNode_ *head; /*!< \brief Reference to head of the list */
+ struct DlNode_ *tail; /*!< \brief Reference to tail of the list */
+ uint16_t size; /*!< \brief Number of nodes in the list */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+
+} CDlList;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CDlList */
+/*------------------------------------------------------------------------------------------------*/
+extern void Dl_Ctor(CDlList *self, uint8_t mns_inst_id);
+extern void Dl_InsertAfter(CDlList *self, CDlNode *node, CDlNode *new_node);
+extern void Dl_InsertBefore(CDlList *self, CDlNode *node, CDlNode *new_node);
+extern void Dl_InsertHead(CDlList *self, CDlNode *new_node);
+extern void Dl_InsertTail(CDlList *self, CDlNode *new_node);
+extern Dl_Ret_t Dl_Remove(CDlList *self, CDlNode *node);
+extern CDlNode * Dl_PopHead(CDlList *self);
+extern CDlNode * Dl_PopTail(CDlList *self);
+extern CDlNode * Dl_PeekHead(CDlList *self);
+extern CDlNode * Dl_PeekTail(CDlList *self);
+extern CDlNode * Dl_Foreach(CDlList *self, Dl_ForeachFunc_t func_ptr, void *user_data_ptr);
+extern bool Dl_IsNodeInList(CDlList *self, const CDlNode *node);
+extern void Dl_AppendList(CDlList *self, CDlList *list_ptr);
+extern uint16_t Dl_GetSize(CDlList *self);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CDlNode */
+/*------------------------------------------------------------------------------------------------*/
+extern void Dln_Ctor(CDlNode *self, void *data_ptr);
+extern void Dln_SetData(CDlNode *self, void *data_ptr);
+extern void * Dln_GetData(CDlNode *self);
+extern bool Dln_IsNodePartOfAList(CDlNode *self);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_DL_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_eh.c b/mnsl/mns_eh.c
new file mode 100644
index 0000000..36e0168
--- /dev/null
+++ b/mnsl/mns_eh.c
@@ -0,0 +1,155 @@
+/*
+ * 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 Implementation of the event handler.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_EH
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_eh.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static bool Eh_EncodeEvent(uint32_t event_code, Mns_Error_t *public_error_code_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CEventHandler */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the event handler class.
+ * \param self Instance pointer
+ * \param mns_inst_id MOST NetServices instance ID
+ */
+void Eh_Ctor(CEventHandler *self, uint8_t mns_inst_id)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ /* Save MOST NetServices instance ID */
+ self->mns_inst_id = mns_inst_id;
+ /* Initialize subject for internal events */
+ Sub_Ctor(&self->internal_event_subject, self->mns_inst_id);
+ /* Initialize subject for public error reporting */
+ Ssub_Ctor(&self->public_error_subject, self->mns_inst_id);
+}
+
+/*! \brief Adds an observer which reports public errors
+ * \param self Instance pointer
+ * \param obs_ptr Reference to an observer
+ */
+void Eh_AddObsrvPublicError(CEventHandler *self, CSingleObserver *obs_ptr)
+{
+ (void)Ssub_AddObserver(&self->public_error_subject, obs_ptr);
+}
+
+/*! \brief Removes an observer registered by Eh_AddObsrvPublicError().
+ * \param self Instance pointer
+ */
+void Eh_DelObsrvPublicError(CEventHandler *self)
+{
+ Ssub_RemoveObserver(&self->public_error_subject);
+}
+
+/*! \brief Reports an event to the event handler.
+ * \param self Instance pointer
+ * \param event_code Event code to report
+ */
+void Eh_ReportEvent(CEventHandler *self, uint32_t event_code)
+{
+ Mns_Error_t public_error_code;
+ /* Check if event code exists */
+ if((event_code & EH_M_ALL_EVENTS) != 0U)
+ {
+ /* Encode internal event code */
+ bool result = Eh_EncodeEvent(event_code, &public_error_code);
+ /* Notify all registered observers */
+ Msub_Notify(&self->internal_event_subject, &event_code, event_code);
+ /* Report error to application? */
+ if(result != false)
+ {
+ Ssub_Notify(&self->public_error_subject, &public_error_code, false);
+ }
+ }
+}
+
+/*! \brief Encodes an internal event code. Some internal event codes are mapped to public
+ * error codes.
+ * \param event_code Internal event code to report
+ * \param public_error_code_ptr Returned public error code
+ * \return true if error must be reported to the application, otherwise false
+ */
+static bool Eh_EncodeEvent(uint32_t event_code, Mns_Error_t *public_error_code_ptr)
+{
+ bool ret_val = true;
+
+ /* Translate internal event code into public error code */
+ switch(event_code)
+ {
+ case EH_E_BIST_FAILED:
+ *public_error_code_ptr = MNS_GEN_ERR_INIC;
+ break;
+ case EH_E_UNSYNC_COMPLETE:
+ case EH_E_UNSYNC_FAILED:
+ *public_error_code_ptr = MNS_GEN_ERR_COMMUNICATION;
+ break;
+ default:
+ ret_val = false; /* Do not report this event to application. */
+ break;
+ }
+
+ return ret_val;
+}
+
+/*! \brief Registers an observer on the given event code.
+ * \param self Instance pointer
+ * \param obs_ptr Reference to the masked-observer object
+ */
+void Eh_AddObsrvInternalEvent(CEventHandler *self, CMaskedObserver *obs_ptr)
+{
+ (void)Sub_AddObserver(&self->internal_event_subject, &obs_ptr->parent);
+}
+
+/*! \brief Unregisters the given observer from the given event code.
+ * \param self Instance pointer
+ * \param obs_ptr Reference to the masked-observer object
+ */
+void Eh_DelObsrvInternalEvent(CEventHandler *self, CMaskedObserver *obs_ptr)
+{
+ (void)Sub_RemoveObserver(&self->internal_event_subject, &obs_ptr->parent);
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_eh.h b/mnsl/mns_eh.h
new file mode 100644
index 0000000..2186a2f
--- /dev/null
+++ b/mnsl/mns_eh.h
@@ -0,0 +1,130 @@
+/*
+ * 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 the event handler.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_EH
+ * @{
+ */
+
+#ifndef MNS_EH_H
+#define MNS_EH_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_eh_pb.h"
+#include "mns_obs.h"
+#include "mns_trace.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Definitions */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief A control FIFO synchronization is lost. When this event occurs the PMS still waits
+ * until all FIFOs are unsynchronized. So this event is no termination event.
+ */
+#define EH_E_SYNC_LOST 0x0001U
+/*! \brief INIC Build-In-Self-Test failed
+ */
+#define EH_E_BIST_FAILED 0x0002U
+/*! \brief Notifies completed un-synchronization of Port Message FIFOs
+ */
+#define EH_E_UNSYNC_COMPLETE 0x0004U
+/*! \brief Notifies that the Port Message Channel was not able to un-synchronize its FIFOs
+ * within a definite time
+ */
+#define EH_E_UNSYNC_FAILED 0x0008U
+/*! \brief MOST NetServices initialization succeeded
+ */
+#define EH_E_INIT_SUCCEEDED 0x0010U
+/*! \brief MOST NetServices initialization failed
+ */
+#define EH_E_INIT_FAILED 0x0020U
+
+/*! \brief Mask including all events that lead to the termination of the MNS
+ */
+#define EH_M_TERMINATION_EVENTS (EH_E_UNSYNC_COMPLETE | EH_E_UNSYNC_FAILED | \
+ EH_E_BIST_FAILED | EH_E_INIT_FAILED)
+
+/*! \brief Bitmask to identify all internal event codes
+ */
+#define EH_M_ALL_EVENTS (EH_M_TERMINATION_EVENTS | EH_E_INIT_SUCCEEDED | EH_E_SYNC_LOST)
+
+/*------------------------------------------------------------------------------------------------*/
+/* Type definitions */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Function signature used for callback functions which notifies the event handler
+ * observers.
+ * \param self Instance pointer
+ * \param event_code Reported event code
+ */
+typedef void (*Ehobs_UpdateCb_t)(void *self, uint32_t event_code);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class structure of the event handler. */
+typedef struct CEventHandler_
+{
+ /*! \brief Subject used for internal events */
+ CSubject internal_event_subject;
+ /*! \brief Single subject to report error to application */
+ CSingleSubject public_error_subject;
+ /*! \brief MOST NetServices instance ID */
+ uint8_t mns_inst_id;
+
+} CEventHandler;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CEventHandler */
+/*------------------------------------------------------------------------------------------------*/
+extern void Eh_Ctor(CEventHandler *self, uint8_t mns_inst_id);
+extern void Eh_AddObsrvPublicError(CEventHandler *self, CSingleObserver *obs_ptr);
+extern void Eh_DelObsrvPublicError(CEventHandler *self);
+extern void Eh_ReportEvent(CEventHandler *self, uint32_t event_code);
+extern void Eh_AddObsrvInternalEvent(CEventHandler *self, CMaskedObserver *obs_ptr);
+extern void Eh_DelObsrvInternalEvent(CEventHandler *self, CMaskedObserver *obs_ptr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_EH_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_eh_pb.h b/mnsl/mns_eh_pb.h
new file mode 100644
index 0000000..422ae15
--- /dev/null
+++ b/mnsl/mns_eh_pb.h
@@ -0,0 +1,68 @@
+/*
+ * 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 Public header file of the event handler.
+ */
+/*!
+ * \addtogroup G_MNS_INIT_AND_SRV_TYPES
+ * @{
+ */
+
+#ifndef MNS_EH_PB_H
+#define MNS_EH_PB_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Enumerations */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief MOST NetServices general error codes */
+typedef enum Mns_Error_
+{
+ MNS_GEN_ERR_COMMUNICATION = 1, /*!< \brief Fatal communication error between EHC and INIC */
+ MNS_GEN_ERR_INIC = 2 /*!< \brief INIC internal error */
+
+} Mns_Error_t;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_EH_PB_H */
+
+/*! @} */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_encoder.c b/mnsl/mns_encoder.c
new file mode 100644
index 0000000..5153e64
--- /dev/null
+++ b/mnsl/mns_encoder.c
@@ -0,0 +1,254 @@
+/*
+ * 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 Implementation of message encoder
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_ENCODER
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_encoder.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Constants */
+/*------------------------------------------------------------------------------------------------*/
+#define ENC_LLR_TIME_DEFAULT 11U /*! \brief Default LLR time required to transmit valid messages
+ * with ContentType 0x81
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Enc_Encode_00(Msg_MostTel_t *tel_ptr, uint8_t header[]);
+static void Enc_Decode_00(Msg_MostTel_t *tel_ptr, uint8_t header[]);
+
+static void Enc_Encode_80(Msg_MostTel_t *tel_ptr, uint8_t header[]);
+static void Enc_Decode_80(Msg_MostTel_t *tel_ptr, uint8_t header[]);
+
+static void Enc_Encode_81(Msg_MostTel_t *tel_ptr, uint8_t header[]);
+static void Enc_Decode_81(Msg_MostTel_t *tel_ptr, uint8_t header[]);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Retrieves the interface of a specific encoder
+ * \details Creates all encoder interfaces as singletons
+ * \param type Specifies the type of encoder to retrieve
+ * \return The desired interface to the specified encoder
+ */
+IEncoder *Enc_GetEncoder(Enc_MsgContent_t type)
+{
+ static IEncoder enc_content_00 = {ENC_CONTENT_00, 8U, 12U, &Enc_Encode_00, &Enc_Decode_00};
+ static IEncoder enc_content_80 = {ENC_CONTENT_80, 6U, 11U, &Enc_Encode_80, &Enc_Decode_80};
+ static IEncoder enc_content_81 = {ENC_CONTENT_81, 6U, 13U, &Enc_Encode_81, &Enc_Decode_81};
+ IEncoder *encoder_ptr = NULL;
+
+ switch (type)
+ {
+ case ENC_CONTENT_00:
+ encoder_ptr = &enc_content_00;
+ break;
+ case ENC_CONTENT_80:
+ encoder_ptr = &enc_content_80;
+ break;
+ case ENC_CONTENT_81:
+ encoder_ptr = &enc_content_81;
+ break;
+ default:
+ encoder_ptr = NULL;
+ break;
+ }
+
+ return encoder_ptr;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Content type "00" */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Encodes a message telegram to the "ContentType 0x00" MOST message header
+ * \param tel_ptr Reference to the Msg_MostTel_t structure
+ * \param header The header buffer
+ */
+static void Enc_Encode_00(Msg_MostTel_t *tel_ptr, uint8_t header[])
+{
+ header[0] = MISC_HB(tel_ptr->source_addr);
+ header[1] = MISC_LB(tel_ptr->source_addr);
+ header[2] = MISC_HB(tel_ptr->destination_addr);
+ header[3] = MISC_LB(tel_ptr->destination_addr);
+
+ header[4] = tel_ptr->id.fblock_id;
+ header[5] = tel_ptr->id.instance_id;
+
+ header[6] = MISC_HB(tel_ptr->id.function_id);
+ header[7] = MISC_LB(tel_ptr->id.function_id);
+
+ header[8] = (uint8_t)(tel_ptr->tel.tel_id << 4) | (uint8_t)((uint8_t)tel_ptr->id.op_type & 0xFU);
+ header[9] = tel_ptr->opts.llrbc;
+
+ header[10] = tel_ptr->tel.tel_cnt;
+ header[11] = tel_ptr->tel.tel_len;
+}
+
+/*! \brief Decodes a "ContentType 0x00" MOST message header to a message telegram structure
+ * \param tel_ptr Reference to the Msg_MostTel_t structure
+ * \param header The header buffer
+ */
+static void Enc_Decode_00(Msg_MostTel_t *tel_ptr, uint8_t header[])
+{
+ tel_ptr->source_addr = (uint16_t)((uint16_t)header[0] << 8) | (uint16_t)header[1];
+ tel_ptr->destination_addr = (uint16_t)((uint16_t)header[2] << 8) | (uint16_t)header[3];
+
+ tel_ptr->id.fblock_id = header[4];
+ tel_ptr->id.instance_id = header[5];
+
+ tel_ptr->id.function_id = (uint16_t)((uint16_t)header[6] << 8) | (uint16_t)header[7];
+
+ tel_ptr->tel.tel_id = header[8] >> 4; /* high nibble: TelId */
+ tel_ptr->id.op_type = (Mns_OpType_t)(header[8] & 0x0FU); /* low nibble: OPType */
+
+ tel_ptr->opts.llrbc = header[9];
+ tel_ptr->tel.tel_cnt = header[10];
+ tel_ptr->tel.tel_len = header[11];
+
+ tel_ptr->tel.tel_data_ptr = &header[12];
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Content type "0x80" */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Encodes a message telegram to the "ContentType 0x80" MOST message header
+ * \param tel_ptr Reference to the Msg_MostTel_t structure
+ * \param header The header buffer
+ */
+static void Enc_Encode_80(Msg_MostTel_t *tel_ptr, uint8_t header[])
+{ /* high nibble: TelId low nibble: OPType */
+ header[0] = (uint8_t)(tel_ptr->tel.tel_id << 4) | (uint8_t)((uint8_t)tel_ptr->id.op_type & 0xFU);
+ header[1] = tel_ptr->tel.tel_cnt;
+ header[2] = tel_ptr->tel.tel_len;
+
+ header[3] = MISC_HB(tel_ptr->id.function_id);
+ header[4] = MISC_LB(tel_ptr->id.function_id);
+
+ header[5] = MISC_HB(tel_ptr->source_addr);
+ header[6] = MISC_LB(tel_ptr->source_addr);
+
+ header[7] = MISC_HB(tel_ptr->destination_addr);
+ header[8] = MISC_LB(tel_ptr->destination_addr);
+
+ header[9] = tel_ptr->id.fblock_id;
+ header[10] = tel_ptr->id.instance_id;
+}
+
+/*! \brief Decodes a "ContentType 0x80" MOST message header to a message telegram structure
+ * \param tel_ptr Reference to the Msg_MostTel_t structure
+ * \param header The header buffer
+ */
+static void Enc_Decode_80(Msg_MostTel_t *tel_ptr, uint8_t header[])
+{
+ tel_ptr->tel.tel_id = header[0] >> 4; /* high nibble: TelId */
+ tel_ptr->id.op_type = (Mns_OpType_t)(header[0] & 0x0FU); /* low nibble: OPType */
+
+ tel_ptr->tel.tel_cnt = header[1];
+ tel_ptr->tel.tel_len = header[2];
+
+ tel_ptr->id.function_id = (uint16_t)((uint16_t)header[3] << 8) | (uint16_t)header[4];
+
+ tel_ptr->source_addr = (uint16_t)((uint16_t)header[5] << 8) | (uint16_t)header[6];
+ tel_ptr->destination_addr = (uint16_t)((uint16_t)header[7] << 8) | (uint16_t)header[8];
+
+ tel_ptr->id.fblock_id = header[9];
+ tel_ptr->id.instance_id = header[10];
+
+ tel_ptr->tel.tel_data_ptr = &header[11];
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Content type "0x81" */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Encodes a message telegram to the "ContentType 0x81" MOST message header
+ * \param tel_ptr Reference to the Msg_MostTel_t structure
+ * \param header The header buffer
+ */
+static void Enc_Encode_81(Msg_MostTel_t *tel_ptr, uint8_t header[])
+{
+ header[0] = tel_ptr->opts.llrbc;
+ header[1] = ENC_LLR_TIME_DEFAULT;
+ /* high nibble: TelId low nibble: OPType */
+ header[2] = (uint8_t)(tel_ptr->tel.tel_id << 4) | (uint8_t)((uint8_t)tel_ptr->id.op_type & 0xFU);
+ header[3] = tel_ptr->tel.tel_cnt;
+ header[4] = tel_ptr->tel.tel_len;
+
+ header[5] = MISC_HB(tel_ptr->id.function_id);
+ header[6] = MISC_LB(tel_ptr->id.function_id);
+
+ header[7] = MISC_HB(tel_ptr->source_addr);
+ header[8] = MISC_LB(tel_ptr->source_addr);
+
+ header[9] = MISC_HB(tel_ptr->destination_addr);
+ header[10] = MISC_LB(tel_ptr->destination_addr);
+
+ header[11] = tel_ptr->id.fblock_id;
+ header[12] = tel_ptr->id.instance_id;
+}
+
+/*! \brief Decodes a "ContentType 0x81" MOST message header to a message telegram structure
+ * \param tel_ptr Reference to the Msg_MostTel_t structure
+ * \param header The header buffer
+ */
+static void Enc_Decode_81(Msg_MostTel_t *tel_ptr, uint8_t header[])
+{
+ tel_ptr->opts.llrbc = header[0];
+
+ tel_ptr->tel.tel_id = header[2] >> 4; /* high nibble: TelId */
+ tel_ptr->id.op_type = (Mns_OpType_t)(header[2] & 0x0FU); /* low nibble: OPType */
+
+ tel_ptr->tel.tel_cnt = header[3];
+ tel_ptr->tel.tel_len = header[4];
+
+ tel_ptr->id.function_id = (uint16_t)((uint16_t)header[5] << 8) | (uint16_t)header[6];
+
+ tel_ptr->source_addr = (uint16_t)((uint16_t)header[7] << 8) | (uint16_t)header[8];
+ tel_ptr->destination_addr = (uint16_t)((uint16_t)header[9] << 8) | (uint16_t)header[10];
+
+ tel_ptr->id.fblock_id = header[11];
+ tel_ptr->id.instance_id = header[12];
+
+ tel_ptr->tel.tel_data_ptr = &header[13];
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_encoder.h b/mnsl/mns_encoder.h
new file mode 100644
index 0000000..439a622
--- /dev/null
+++ b/mnsl/mns_encoder.h
@@ -0,0 +1,118 @@
+/*
+ * 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 Declaration of message encoder
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_ENCODER
+ * @{
+ */
+
+#ifndef MNS_ENCODER_H
+#define MNS_ENCODER_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_message.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Defines */
+/*------------------------------------------------------------------------------------------------*/
+#define ENC_MAX_SIZE_CONTENT 16U /*!< \brief Maximum content size in bytes, quadlet aligned */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Retrieves the size of a MOST message header
+ * \return The size of the MOST message header in bytes.
+ */
+typedef uint8_t (*Enc_GetSize_t)(void);
+
+/*! \brief Retrieves the content type of a MOST message header
+ * \return The content type of the MOST message header in bytes.
+ */
+typedef uint8_t (*Enc_GetContType_t)(void);
+
+/*! \brief Encodes a message telegram to the MOST message header
+ * \param tel_ptr Reference to the Msg_MostTel_t structure
+ * \param header The header buffer
+ */
+typedef void (*Enc_Encode_t)(Msg_MostTel_t *tel_ptr, uint8_t header[]);
+
+/*! \brief Decodes a MOST message header to a message telegram structure
+ * \param tel_ptr Reference to the Msg_MostTel_t structure
+ * \param header The header buffer
+ */
+typedef void (*Enc_Decode_t)(Msg_MostTel_t *tel_ptr, uint8_t header[]);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Identifier for a MOST Message Content */
+typedef enum Enc_MsgContent_
+{
+ ENC_CONTENT_00 = 0x00, /*!< \brief Content Type "0x00": Uncompressed, excluding retry values */
+ ENC_CONTENT_80 = 0x80, /*!< \brief Content Type "0x80": Compressed, excluding retry values */
+ ENC_CONTENT_81 = 0x81 /*!< \brief Content Type "0x81": Compressed, including retry values */
+
+} Enc_MsgContent_t;
+
+/*! \brief Interface for message encoder */
+typedef struct IEncoder_
+{
+ Enc_MsgContent_t content_type; /*!< \brief Retrieves the content type of the MOST message header */
+ uint8_t pm_hdr_sz; /*!< \brief Retrieves the size of the Port Message header */
+ uint8_t msg_hdr_sz; /*!< \brief Retrieves the size of the MOST message header */
+ Enc_Encode_t encode_fptr; /*!< \brief Function required to encode a MOST message header */
+ Enc_Decode_t decode_fptr; /*!< \brief Function required to decode a MOST message header */
+
+} IEncoder;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Function prototypes */
+/*------------------------------------------------------------------------------------------------*/
+extern IEncoder *Enc_GetEncoder(Enc_MsgContent_t type);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_ENCODER_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_lld_pb.h b/mnsl/mns_lld_pb.h
new file mode 100644
index 0000000..d1a087b
--- /dev/null
+++ b/mnsl/mns_lld_pb.h
@@ -0,0 +1,221 @@
+/*
+ * 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 Declaration of the low-level driver interface
+ * \defgroup G_LLD Low-Level Driver
+ * \brief API functions to be used by the low-level driver.
+ * \details The MOST NetServices provides a certain set of functions which are only dedicated to the low-level driver.
+ * The low-level driver \em API is a set of functions which shall be used by the low-level driver.
+ * The low-level driver \em callbacks is a set of function that shall be implemented by the low-level driver.
+ * The low-level driver \em callbacks shall be assigned to the MOST NetServices initialization structure.
+ * During initialization MOST NetServices invokes the callback \ref Mns_Lld_Callbacks_t "start_fptr" and
+ * passes the low-level driver \em API as pointer to \ref Mns_Lld_Api_t.
+ * \mns_ic_started{ See also Getting Started with \ref P_UM_STARTED_LLD. }
+ * \mns_ic_examples{ See also <i>Examples</i>, section \ref P_UM_EXAMPLE_LLD_01, \ref P_UM_EXAMPLE_LLD_02 and \ref P_UM_EXAMPLE_LLD_03. }
+ * \ingroup G_MNS_API
+ * \defgroup G_LLD_TYPES Referred Types
+ * \brief Referred types used by the low-level driver interface
+ * \ingroup G_LLD
+ * \defgroup G_LLD_API Low-Level Driver API
+ * \brief Function pointers to be used by the low-level driver
+ * \ingroup G_LLD
+ */
+
+#ifndef MNS_LLD_PB_H
+#define MNS_LLD_PB_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_types_cfg.h"
+#include "mns_memory_pb.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*!
+ * \addtogroup G_LLD_TYPES
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Tx message object providing the raw port message byte stream */
+typedef struct Mns_Lld_TxMsg_
+{
+ struct Mns_Lld_TxMsg_ *custom_next_msg_ptr;/*!< \brief Shall be used by the LLD implementation to queue messages for
+ * asynchronous transmission
+ * \details MOST NetServices will set this value to \c NULL since only
+ * single messages are forwarded to the LLD. Within the transmit function
+ * it is recommended that the LLD queues the message for asynchronous
+ * transmission. Despite a driver's transmit function might signal busy for
+ * a short term MOST NetServices might forward multiple messages for
+ * transmission. If a driver works asynchronously (interrupt driven) it
+ * can easily use this pointer build a queue of waiting messages.
+ * Nonetheless, it is important that \ref Mns_Lld_Api_t::tx_release_fptr
+ * "tx_release_fptr" is invoked for every message separately. The Interface
+ * between MOST NetServices and the LLD does only support single messages.
+ */
+ Mns_Mem_Buffer_t *memory_ptr; /*!< \brief Points to the data buffer */
+
+} Mns_Lld_TxMsg_t;
+
+/*! \brief Rx message object pointing to the raw port message byte stream. */
+typedef struct Mns_Lld_RxMsg_
+{
+ uint8_t* data_ptr; /*!< \brief Points to a MOST NetServices allocated memory chunk. */
+ uint16_t data_size; /*!< \brief Size of the memory chunk in bytes. Valid values: 6..72. */
+
+} Mns_Lld_RxMsg_t;
+
+/*!
+ * @}
+ * \addtogroup G_LLD_API
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Low-level driver API */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Allocates an Rx message object
+ * \param inst_ptr Reference to internal MOST NetServices handler
+ * \param buffer_size The size in bytes of the received Rx message.
+ * Valid values: 6..72.
+ * \return The Rx message object or \c NULL if no message object is available. In the latter
+ * case the low-level driver can wait until Mns_Lld_RxMsgAvailableCb_t() is invoked.
+ * The low-level driver is allowed to pre-allocate Rx messages with the maximum size
+ * of 72 bytes. After writing received data into Mns_Lld_RxMsg_t::data_ptr the
+ * low-level driver must set Mns_Lld_RxMsg_t::data_size to the actual message size.
+ * \warning
+ * The function will also return \c NULL if the requested \c buffer_size exceeds the valid range.
+ * In such a case the MOST NetServices cannot guarantee that Mns_Lld_RxMsgAvailableCb_t() is
+ * called as expected. Received messages exceeding the valid range must be discarded by the LLD.
+ */
+typedef Mns_Lld_RxMsg_t* (*Mns_Lld_RxAllocateCb_t)(void *inst_ptr, uint16_t buffer_size);
+
+/*! \brief Frees an unused Rx message object
+ * \param inst_ptr Reference to internal MOST NetServices handler
+ * \param msg_ptr Reference to the unused Rx message object
+ */
+typedef void (*Mns_Lld_RxFreeUnusedCb_t)(void *inst_ptr, Mns_Lld_RxMsg_t *msg_ptr);
+
+/*! \brief Pass an Rx message to MOST NetServices
+ * \param inst_ptr Reference to internal MOST NetServices handler
+ * \param msg_ptr Reference to the Rx message object containing the received
+ * message.
+ */
+typedef void (*Mns_Lld_RxReceiveCb_t)(void *inst_ptr, Mns_Lld_RxMsg_t *msg_ptr);
+
+/*! \brief Notifies that the LLD no longer needs to access the Tx message object
+ * \param inst_ptr Reference to internal MOST NetServices handler
+ * \param msg_ptr Reference to the Tx message object which is no longer accessed
+ * by the low-level driver
+ */
+typedef void (*Mns_Lld_TxReleaseCb_t)(void *inst_ptr, Mns_Lld_TxMsg_t *msg_ptr);
+
+/*! \brief Initialization required for one communication channel (control or packet)
+ */
+typedef struct Mns_Lld_Api_
+{
+ Mns_Lld_RxAllocateCb_t rx_allocate_fptr; /*!< \brief Allocates an Rx message object */
+ Mns_Lld_RxFreeUnusedCb_t rx_free_unused_fptr; /*!< \brief Frees an unused Rx message object */
+ Mns_Lld_RxReceiveCb_t rx_receive_fptr; /*!< \brief Pass an Rx message to MOST NetServices */
+ Mns_Lld_TxReleaseCb_t tx_release_fptr; /*!< \brief Notifies that the LLD no longer needs to access the Tx message object */
+
+} Mns_Lld_Api_t;
+
+/*!
+ * @}
+ * \addtogroup G_LLD
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* LLD interface functions */
+/*------------------------------------------------------------------------------------------------*/
+
+/*! \brief Notifies the LLD to start transmitting and receiving messages
+ * \param api_ptr Reference to MOST NetServices LLD interface
+ * \param ns_ptr Reference to internal MOST NetServices handler
+ */
+typedef void (*Mns_Lld_StartCb_t)(Mns_Lld_Api_t* api_ptr, void *ns_ptr, void *inst_ptr);
+
+/*! \brief Notifies the LLD to stop/abort transmitting and receiving messages
+ * \details As soon as this function is called the low-level driver is not allowed
+ * to call any MOST NetServices function.
+ */
+typedef void (*Mns_Lld_StopCb_t)(void *inst_ptr);
+
+/*! \brief Notifies the LLD to reset the INIC
+ * \details If this function is called the low-level driver is responsible to
+ * perform an INIC hardware reset.
+ */
+typedef void (*Mns_Lld_ResetInicCb_t)(void *inst_ptr);
+
+/*! \brief Callback function which is invoked as soon as port message objects are available again.
+ * \details By implementing this callback function the low-level driver can avoid polling for
+ * Rx message objects. The low-level driver should wait for the function call as soon
+ * as Mns_Lld_RxAllocateCb_t() returns NULL. Only then it shall call those functions again.
+ */
+typedef void (*Mns_Lld_RxMsgAvailableCb_t)(void *inst_ptr);
+
+/*! \brief Callback function which is invoked to transmit a single message to the INIC
+ * \param msg_ptr Reference to a single Tx message.
+ */
+typedef void (*Mns_Lld_TxTransmitCb_t)(Mns_Lld_TxMsg_t *msg_ptr, void *inst_ptr);
+
+/*!
+ * @}
+ * \addtogroup G_LLD_TYPES
+ * @{
+ */
+
+/*! \brief Set of functions implemented by the low-level driver
+ */
+typedef struct Mns_Lld_Callbacks_
+{
+ Mns_Lld_StartCb_t start_fptr; /*!< \brief Callback function to initialize the low-level driver and
+ * start the transmission and reception of messages */
+ Mns_Lld_StopCb_t stop_fptr; /*!< \brief Callback function to stop/abort the transmission and reception of messages */
+ Mns_Lld_RxMsgAvailableCb_t rx_available_fptr; /*!< \brief Callback function which is invoked as soon as Rx message objects are available again */
+ Mns_Lld_TxTransmitCb_t tx_transmit_fptr; /*!< \brief Callback function to transmit one or multiple messages to the INIC */
+
+} Mns_Lld_Callbacks_t;
+
+/*! @} */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_LLD_PB_H */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_lldpool.c b/mnsl/mns_lldpool.c
new file mode 100644
index 0000000..ae9f33d
--- /dev/null
+++ b/mnsl/mns_lldpool.c
@@ -0,0 +1,101 @@
+/*
+ * 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 Implementation of LLD Message Pool
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PMF
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_lldpool.h"
+#include "mns_misc.h"
+#include "mns_trace.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Returns an unused LLD Tx message object back to the pool
+ * \param self The instance
+ * \param owner_ptr Assigns messages to the respective FIFO
+ * \param mns_inst_id MOST NetServices instance ID
+ */
+void Lldp_Ctor(CLldPool *self, void *owner_ptr, uint8_t mns_inst_id)
+{
+ uint8_t cnt;
+ MISC_MEM_SET(self, 0, sizeof(*self));
+
+ Dl_Ctor(&self->list, mns_inst_id);
+
+ for (cnt = 0U; cnt < LLDP_NUM_HANDLES; cnt++) /* setup LLD Tx handles */
+ {
+ TR_ASSERT(mns_inst_id, "[FIFO]", (NULL == self->messages[cnt].msg_ptr));
+ Dln_Ctor(&self->messages[cnt].node, &self->messages[cnt]);
+ self->messages[cnt].owner_ptr = owner_ptr;
+ Dl_InsertTail(&self->list, &self->messages[cnt].node);
+ }
+}
+
+/*! \brief Returns an unused LLD Tx message object back to the pool
+ * \param self The instance
+ * \param msg_ptr The unused LLD Tx message object
+ */
+void Lldp_ReturnTxToPool(CLldPool *self, Lld_IntTxMsg_t *msg_ptr)
+{
+ Dl_InsertTail(&self->list, &msg_ptr->node);
+}
+
+/*! \brief Allocates an unused LLD Tx message object from the pool
+ * \param self The instance
+ * \return An internal LLD Tx message object or \c NULL if no message object is
+ * available.
+ */
+Lld_IntTxMsg_t* Lldp_GetTxFromPool(CLldPool *self)
+{
+ CDlNode *node_ptr = NULL;
+ Lld_IntTxMsg_t *handle_ptr = NULL;
+
+ node_ptr = Dl_PopHead(&self->list);
+
+ if (node_ptr != NULL)
+ {
+ handle_ptr = (Lld_IntTxMsg_t*)Dln_GetData(node_ptr);
+ }
+
+ return handle_ptr;
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_lldpool.h b/mnsl/mns_lldpool.h
new file mode 100644
index 0000000..fdf4419
--- /dev/null
+++ b/mnsl/mns_lldpool.h
@@ -0,0 +1,112 @@
+/*
+ * 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 LLD Message Pool
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PMF
+ * @{
+ */
+
+#ifndef MNS_LLDPOOL_H
+#define MNS_LLDPOOL_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+#include "mns_base.h"
+#include "mns_lld_pb.h"
+#include "mns_message.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macros */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Number of LLD Tx handles dedicated to each FIFO */
+#define LLDP_NUM_HANDLES 5U
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Internal LLD Tx message */
+typedef struct Lld_IntTxMsg_
+{
+ Mns_Lld_TxMsg_t lld_msg; /*!< \brief Contains the public LLD Tx message
+ * \details This attribute needs to be the first one in this structure
+ */
+ CDlNode node; /*!< \brief Node required for queuing */
+ CMessage *msg_ptr; /*!< \brief Reference to the associated common message object, or
+ * \c NULL if the object is a command */
+ void *owner_ptr; /*!< \brief Points to the FIFO which owns the message object
+ * or NULL if the object is a command */
+
+} Lld_IntTxMsg_t;
+
+/*! \brief Internal LLD Rx message */
+typedef struct Lld_IntRxMsg_
+{
+ Mns_Lld_RxMsg_t lld_msg; /*!< \brief Contains the public LLD Rx message
+ * \details This attribute needs to be the first one in this structure
+ */
+ CMessage *msg_ptr; /*!< \brief Reference to the associated common message object*/
+
+} Lld_IntRxMsg_t;
+
+/*! \brief The class CLldPool*/
+typedef struct CLldPool_
+{
+ CDlList list; /*!< \brief Points to the first available message in Tx pool */
+ Lld_IntTxMsg_t messages[LLDP_NUM_HANDLES];/*!< \brief Available messages in Tx pool */
+
+} CLldPool;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Function prototypes */
+/*------------------------------------------------------------------------------------------------*/
+extern void Lldp_Ctor(CLldPool *self, void *owner_ptr, uint8_t mns_inst_id);
+extern void Lldp_ReturnTxToPool(CLldPool *self, Lld_IntTxMsg_t *msg_ptr);
+extern Lld_IntTxMsg_t* Lldp_GetTxFromPool(CLldPool *self);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* MNS_LLDPOOL_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_memory.h b/mnsl/mns_memory.h
new file mode 100644
index 0000000..5b80bf1
--- /dev/null
+++ b/mnsl/mns_memory.h
@@ -0,0 +1,112 @@
+/*
+ * 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 Declaration of internal memory buffer
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_MEMORY
+ * @{
+ */
+
+#ifndef MNS_MEMORY_H
+#define MNS_MEMORY_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_memory_pb.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* IAllocator Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Callback function which frees memory
+ * \param allocator Reference to the Mem_Allocator_t object
+ * \param mem_ptr Reference to memory chunk
+ * \param mem_info_ptr Customer specific information needed to free
+ * the related memory chunk
+ */
+typedef void (*Mem_Free_t)(void *allocator, void* mem_ptr, void* mem_info_ptr);
+
+/*! \brief Callback function which allocated memory
+ * \param allocator Reference to the Mem_Allocator_t object
+ * \param size Size of the demanded memory chunk
+ * \param mem_info_ptr Customer specific information needed to free
+ * the related memory chunk
+ * \return Reference to a memory chunk with a minimum size of \c size.
+ * Otherwise NULL.
+ */
+typedef void* (*Mem_Allocate_t)(void *allocator, uint16_t size, void** mem_info_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Interface IAllocator */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Interface which is needed to be implemented by a memory allocator */
+typedef struct IAllocator_
+{
+ void* base; /*!< Reference to the base class */
+ Mem_Allocate_t allocate_fptr; /*!< Callback function required to allocate memory */
+ Mem_Free_t free_fptr; /*!< Callback function required to free memory */
+
+} IAllocator;
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Memory buffer */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Memory chunk comprising non public fields */
+typedef struct Mem_IntBuffer_
+{
+ Mns_Mem_Buffer_t public_buffer; /*!< \brief Public attributes of memory buffer
+ * \details This has to be the first member in this
+ * struct
+ */
+ IAllocator *allocator_ptr; /*!< \brief Reference to the allocator which is
+ * required to free the memory chunk
+ */
+ void *mem_info_ptr; /*!< \brief Customer specific information needed to
+ * free the related memory chunk
+ */
+} Mem_IntBuffer_t;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_MEMORY_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_memory_pb.h b/mnsl/mns_memory_pb.h
new file mode 100644
index 0000000..2165e73
--- /dev/null
+++ b/mnsl/mns_memory_pb.h
@@ -0,0 +1,72 @@
+/*
+ * 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 Declaration of memory buffer and memory allocator
+ */
+/*!
+ * \addtogroup G_LLD_TYPES
+ * @{
+ */
+
+#ifndef MNS_MEMORY_PB_H
+#define MNS_MEMORY_PB_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_types_cfg.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Memory buffer */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Memory chunk representing a message or part of a message. */
+typedef struct Mns_Mem_Buffer_
+{
+ struct Mns_Mem_Buffer_ *next_buffer_ptr; /*!< \brief Points to an additional memory buffer
+ * that belongs to the same message.
+ */
+ uint8_t *data_ptr; /*!< \brief Points to the data buffer */
+ uint16_t data_size; /*!< \brief Size of the data buffer */
+ uint16_t total_size; /*!< \brief Reserved for future use. Size of this and all concatenated data buffers */
+
+} Mns_Mem_Buffer_t;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_MEMORY_PB_H */
+
+/*! @} */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_message.c b/mnsl/mns_message.c
new file mode 100644
index 0000000..33a0673
--- /dev/null
+++ b/mnsl/mns_message.c
@@ -0,0 +1,331 @@
+/*
+ * 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 Implementation of class message
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_MESSAGE
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_message.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal constants */
+/*------------------------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of common MOST message class
+ * \param self The instance
+ */
+void Msg_Ctor(CMessage *self)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+
+ Dln_Ctor(&self->node, self);
+
+ self->rsvd_memory.allocator_ptr = NULL;
+ self->rsvd_memory.mem_info_ptr = NULL;
+ self->rsvd_memory.public_buffer.next_buffer_ptr = NULL;
+ self->rsvd_memory.public_buffer.data_ptr = &self->rsvd_buffer[0];
+ self->rsvd_memory.public_buffer.data_size = MSG_SIZE_RSVD_BUFFER;
+ self->rsvd_memory.public_buffer.total_size = MSG_SIZE_RSVD_BUFFER;
+
+ self->start_ptr = &self->rsvd_buffer[0];
+ self->pb_msg.tel.tel_data_ptr = &self->rsvd_buffer[0];
+/* self->pb_msg.tel.tel_id = 0U;
+ self->pb_msg.tel.tel_cnt = 0U;
+ self->pb_msg.tel.tel_len = 0U; */
+
+ self->pb_msg.opts.llrbc = MSG_LLRBC_DEFAULT;
+
+/* self->header_rsvd_sz = 0U;
+ self->header_curr_idx = 0U;
+ self->header_curr_sz = 0U;
+ self->ref_ptr = NULL; */
+}
+
+/*! \brief Prepares the message for re-usage
+ * \details In future this function has to take care that external memory
+ * has to be reinitialize properly.
+ * \param self The instance
+ */
+void Msg_Cleanup(CMessage *self)
+{
+ void *handle = self->lld_handle_ptr; /* restore associated LLD message object */
+ void *pool_ptr = self->pool_ptr; /* restore associated pool reference */
+
+ Msg_Ctor(self); /* simply call constructor now */
+
+ self->lld_handle_ptr = handle;
+ self->pool_ptr = pool_ptr;
+}
+
+/*! \brief Adds external message payload to the message
+ * \details The internally reserved message payload is no longer in in use.
+ * \param self The instance
+ * \param payload_ptr Pointer to externally allocated payload
+ * \param payload_sz Size of externally allocated payload
+ * \param mem_info_ptr Reference to additional memory information
+ */
+void Msg_SetExtPayload(CMessage *self, uint8_t *payload_ptr, uint8_t payload_sz, void* mem_info_ptr)
+{
+ self->pb_msg.tel.tel_data_ptr = payload_ptr;
+ self->pb_msg.tel.tel_len = payload_sz;
+
+ self->ext_memory.allocator_ptr = NULL;
+ self->ext_memory.mem_info_ptr = mem_info_ptr;
+ self->ext_memory.public_buffer.data_ptr = payload_ptr;
+ self->ext_memory.public_buffer.data_size = payload_sz;
+ self->ext_memory.public_buffer.total_size = payload_sz;
+ self->ext_memory.public_buffer.next_buffer_ptr = NULL;
+}
+
+/*! \brief Initially defines a header space in front of the data body
+ * \details Ensure that \c start_ptr is assigned correctly before calling
+ * this functions.
+ * \param self The instance
+ * \param header_sz Size of the header
+ */
+void Msg_ReserveHeader(CMessage *self, uint8_t header_sz)
+{
+ /* self->start_ptr stays */
+ self->header_rsvd_sz = header_sz;
+ self->header_curr_idx = header_sz;
+ self->header_curr_sz = 0U;
+
+ self->pb_msg.tel.tel_data_ptr = &self->start_ptr[header_sz];
+}
+
+/*! \brief Adds a defined header space in front of the current header
+ * \param self The instance
+ * \param header_sz Size of the header
+ */
+void Msg_PullHeader(CMessage *self, uint8_t header_sz)
+{
+/* MNS_ASSERT(header_sz <= self->curr_header_sz); */
+
+/* self->pb_msg.tel.tel_data_ptr = &self->rsvd_buffer[MSG_SIZE_RSVD_HEADER];*/
+ self->header_curr_idx -= header_sz;
+ self->header_curr_sz += header_sz;
+}
+
+/*! \brief Undoes a message header of a defined size
+ * \param self The instance
+ * \param header_sz Size of the header
+ */
+void Msg_PushHeader(CMessage *self, uint8_t header_sz)
+{
+ self->header_curr_idx += header_sz;
+ self->header_curr_sz -= header_sz;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class Properties (get/set) */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Retrieves the reference to the containing MOST Telegrams structure
+ * \param self The instance
+ * \return Pointer to the internal MOST Telegram structure
+ */
+Msg_MostTel_t* Msg_GetMostTel(CMessage *self)
+{
+ return &self->pb_msg;
+}
+
+/*! \brief Retrieves the start of the current message header
+ * \param self The instance
+ * \return Pointer to the current header start
+ */
+uint8_t* Msg_GetHeader(CMessage *self)
+{
+ return &(self->rsvd_buffer[self->header_curr_idx]);
+}
+
+/*! \brief Retrieves the size of the current message header
+ * \param self The instance
+ * \return Size of the current header in bytes
+ */
+uint8_t Msg_GetHeaderSize(CMessage * self)
+{
+ return (self->header_curr_sz);
+}
+
+/*! \brief Retrieves the message buffer as memory structure
+ * \param self The instance
+ * \return Reference to the message memory structure
+ */
+Mns_Mem_Buffer_t* Msg_GetMemTx(CMessage *self)
+{
+ self->rsvd_memory.public_buffer.data_ptr = &(self->rsvd_buffer[self->header_curr_idx]);
+
+ if (self->ext_memory.public_buffer.data_size == 0U)
+ {
+ self->rsvd_memory.public_buffer.next_buffer_ptr = NULL;
+ self->rsvd_memory.public_buffer.data_size = (uint16_t)self->header_curr_sz + (uint16_t)self->pb_msg.tel.tel_len;
+ self->rsvd_memory.public_buffer.total_size = (uint16_t)self->header_curr_sz + (uint16_t)self->pb_msg.tel.tel_len;
+ }
+ else
+ {
+ self->rsvd_memory.public_buffer.next_buffer_ptr = &self->ext_memory.public_buffer;
+ self->rsvd_memory.public_buffer.data_size = (uint16_t)self->header_curr_sz; /* only header is enclosed */
+ self->rsvd_memory.public_buffer.total_size = self->rsvd_memory.public_buffer.data_size
+ + self->ext_memory.public_buffer.data_size;
+ }
+
+ return &self->rsvd_memory.public_buffer;
+}
+
+/*! \brief Assigns a message status handler which is called as soon as the message is processed
+ * \param self The instance
+ * \param callback_fptr Reference to the status callback function
+ * \param inst_ptr The instance which implements the status callback
+ */
+void Msg_SetTxStatusHandler(CMessage *self, Msg_TxStatusCb_t callback_fptr, void *inst_ptr)
+{
+ self->tx_status_inst = inst_ptr;
+ self->tx_status_fptr = callback_fptr;
+}
+
+/*! \brief Marks the message as occupied by the LLD
+ * \param self The instance
+ * \param active Set to \c true if the message is occupied by the LLD, otherwise \c false.
+ */
+void Msg_SetTxActive(CMessage *self, bool active)
+{
+ self->tx_active = active;
+}
+
+/*! \brief Checks if the message as occupied by the LLD
+ * \param self The instance
+ * \return Returns \c true if the message is occupied by the LLD, otherwise \c false.
+ */
+bool Msg_IsTxActive(CMessage *self)
+{
+ return self->tx_active;
+}
+
+/*! \brief Marks the message as bypass message
+ * \param self The instance
+ * \param bypass Set to \c true if the message is supposed to be a bypass message, otherwise \c false.
+ */
+void Msg_SetTxBypass(CMessage *self, bool bypass)
+{
+ self->tx_bypass = bypass;
+}
+
+/*! \brief Checks if the message is marked as bypass message
+ * \param self The instance
+ * \return Returns \c true if the message is marked as bypass message, otherwise \c false.
+ */
+bool Msg_IsTxBypass(CMessage *self)
+{
+ return self->tx_bypass;
+}
+
+/*! \brief Fires a status notification for the message object
+ * \param self The instance
+ * \param status The transmission status
+ */
+void Msg_NotifyTxStatus(CMessage *self, Mns_MsgTxStatus_t status)
+{
+ if (self->tx_status_fptr != NULL)
+ {
+ self->tx_status_fptr(self->tx_status_inst, &self->pb_msg, status);
+ }
+}
+
+/*! \brief Assigns a low-level driver message
+ * \param self The instance
+ * \param handle The reference to a low-level driver message object (Tx or Rx)
+ */
+void Msg_SetLldHandle(CMessage *self, void *handle)
+{
+ self->lld_handle_ptr = handle;
+}
+
+/*! \brief Retrieves the reference to a low-level driver message
+ * \param self The instance
+ * \return The reference to a low-level driver message object or \c NULL
+ * if no message is assigned.
+ */
+void *Msg_GetLldHandle(CMessage *self)
+{
+ return self->lld_handle_ptr;
+}
+
+/*! \brief Assigns a reference for the owning pool
+ * \param self The instance
+ * \param pool_ptr The reference to the owning pool
+ */
+void Msg_SetPoolReference(CMessage *self, void *pool_ptr)
+{
+ self->pool_ptr = pool_ptr;
+}
+
+/*! \brief Retrieves a reference for the owning pool
+ * \param self The instance
+ * \return The reference to the owning pool or \c NULL
+ * if no pool is assigned.
+ */
+void *Msg_GetPoolReference(CMessage *self)
+{
+ return self->pool_ptr;
+}
+
+/*! \brief Retrieves the reference to the internal node member
+ * \param self The instance
+ * \return The reference the internal list node
+ */
+CDlNode *Msg_GetNode(CMessage *self)
+{
+ return &self->node;
+}
+
+/*! \brief Performs checks on length payload length
+ * \param self The instance
+ * \return Returns \c true if the verification succeeded. Otherwise \c false.
+ */
+bool Msg_VerifyContent(CMessage *self)
+{
+ bool success = (self->pb_msg.tel.tel_len <= MSG_MAX_SIZE_PAYLOAD) ? true : false;
+
+ return success;
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_message.h b/mnsl/mns_message.h
new file mode 100644
index 0000000..69d82ea
--- /dev/null
+++ b/mnsl/mns_message.h
@@ -0,0 +1,238 @@
+/*
+ * 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 Declaration of class message
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_MESSAGE
+ * @{
+ */
+
+#ifndef MNS_MESSAGE_H
+#define MNS_MESSAGE_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_memory.h"
+#include "mns_dl.h"
+#include "mns_message_pb.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Common macros */
+/*------------------------------------------------------------------------------------------------*/
+#define MSG_ADDR_INVALID 0U /*!< \brief The (source) address the INIC uses to declare an invalid source address.
+ * \details Invalid source addresses can be:
+ * - invalid messages from MOST: source_address = [0x0000..0x000F]
+ * - invalid messages from EHC: source_address != [0x0002, 0x0003]
+ * .
+ */
+#define MSG_ADDR_INIC 1U /*!< \brief The address of the local INIC */
+#define MSG_ADDR_EHC_CFG 2U /*!< \brief The address of the EHC configuration interface (ICM and RCM FIFO) */
+#define MSG_ADDR_EHC_APP 3U /*!< \brief The address of the EHC application interface (MCM FIFO) */
+
+#define MSG_LLRBC_DEFAULT 10U /*!< \brief The default LowLevelRetry BlockCount */
+#define MSG_LLRBC_MAX 100U/*!< \brief The maximum LowLevelRetry BlockCount */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief MOST message id "FBlockID.InstID.FktID.OPType" */
+typedef struct Msg_MsgId_
+{
+ uint8_t fblock_id; /*!< \brief FBlockID */
+ uint8_t instance_id; /*!< \brief InstID */
+ uint16_t function_id; /*!< \brief FktID */
+ Mns_OpType_t op_type; /*!< \brief Operation type */
+
+} Msg_MsgId_t;
+
+/*! \brief Retry options */
+typedef struct Msg_TxOptions_
+{
+ uint8_t llrbc; /*!< \brief Low-level retry block count performed by the INIC.
+ * \details The LLRBC are applicable for MCMs. ICMs don't care.
+ * Values exceeding the maximum value are be corrected
+ * by the INIC silently to the maximum value.
+ * Valid range: 0..100
+ */
+ uint8_t cancel_id; /*!< \brief Either "0" or label for a group of dependent telegrams.
+ * \details The value determines the required action if the transmission
+ * has failed.
+ * Valid range:
+ * - 0: Only the failed telegram will is removed from the FIFO.
+ * - 1..255: All telegrams with the same cancel_id as a failed telegram
+ * will be removed from the FIFO queue.
+ */
+
+} Msg_TxOptions_t;
+
+/*! \brief Most telegram data */
+typedef struct Msg_TelData_
+{
+ uint8_t tel_id; /*!< \brief Telegram id which indicates the telegram as part of
+ * segmented message or as single transfer. */
+ uint8_t tel_len; /*!< \brief The telegram length.
+ * I.e. the number of telegram bytes starting at address
+ * which is referred in \c tel_data_ptr. The INIC will add
+ * \em one in case of \"tel_id = 1..3\".
+ */
+ uint8_t tel_cnt; /*!< \brief The message count indexing the telegram within a segmented
+ * message.
+ * The respective tel_cnt is moved by the INIC to \"DATA[0]\"
+ * in case of \"tel_id = 1..3\". Otherwise it is ignored.
+ */
+ uint8_t *tel_data_ptr; /*!< \brief Points to telegram data. */
+
+} Msg_TelData_t;
+
+/*! \brief Common MOST message */
+typedef struct Msg_MostTel_
+{
+ uint16_t destination_addr; /*!< \brief MOST destination address */
+ uint16_t source_addr; /*!< \brief MOST source address */
+
+ Msg_MsgId_t id; /*!< \brief MOST message id "FBlockID.InstID.FktID.OPType" */
+ Msg_TxOptions_t opts; /*!< \brief Message transmission options */
+ Msg_TelData_t tel; /*!< \brief MOST telegram data */
+ void *info_ptr; /*!< \brief Possible reference to additional data */
+
+} Msg_MostTel_t;
+
+/* necessary forward declaration */
+struct CMessage_;
+/*! \brief Common message class which provides MOST style message addressing */
+typedef struct CMessage_ CMessage;
+
+/*! \brief Assignable function which is invoked as soon as transmission
+ * of the message object is finished.
+ * \param self The instance
+ * \param msg_ptr Reference to the message object
+ * \param status Transmission status
+ */
+typedef void (*Msg_TxStatusCb_t)(void *self, Msg_MostTel_t *tel_ptr, Mns_MsgTxStatus_t status);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macros */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Size in bytes of reserved message header */
+#define MSG_SIZE_RSVD_HEADER 24U
+/*! \brief Size in bytes of message payload */
+#define MSG_MAX_SIZE_PAYLOAD 45U
+/*! \brief Size in bytes of pre-allocated message buffer
+ * \details Size = 24(header) + 45(payload) + 3(stuffing) = 72 */
+#define MSG_SIZE_RSVD_BUFFER 72U
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class CMessage */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class CMessage
+ * \details Common internal message class which embeds the public message attributes
+ */
+struct CMessage_
+{
+ Msg_MostTel_t pb_msg; /*!< \brief Public part which defines the MOST telegram
+ * structure. This attribute must be the first
+ * element inside the message structure.
+ */
+ uint8_t rsvd_buffer[MSG_SIZE_RSVD_BUFFER]; /*!< \brief Reserved memory space */
+ Mem_IntBuffer_t rsvd_memory; /*!< \brief Reserved memory which is needed at least for the
+ * Port message header (24 bytes) */
+ Mem_IntBuffer_t ext_memory; /*!< \brief Possible user memory */
+
+ uint8_t *start_ptr; /*!< \brief Points to the start of the message buffer */
+ uint8_t header_curr_idx; /*!< \brief Index of the end of the current header */
+ uint8_t header_curr_sz; /*!< \brief Current size of header in bytes */
+ uint8_t header_rsvd_sz; /*!< \brief Reserved size of header in bytes */
+
+ void *pool_ptr; /*!< \brief Point to the pool the message is allocated from and released to */
+ void *lld_handle_ptr; /*!< \brief Possible reference to another message object */
+ CDlNode node; /*!< \brief Node for usage in a doubly linked list */
+
+ Msg_TxStatusCb_t tx_status_fptr; /*!< \brief Pointer to Tx status callback */
+ void *tx_status_inst; /*!< \brief Reference to instance which needs Tx status notification */
+
+ bool tx_active; /*!< \brief Is \c true if the object is occupied by the LLD, otherwise \c false */
+ bool tx_bypass; /*!< \brief Is \c true if a message was queued as bypass message */
+};
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Methods */
+/*------------------------------------------------------------------------------------------------*/
+extern void Msg_Ctor(CMessage *self);
+extern void Msg_Cleanup(CMessage *self);
+
+extern void Msg_ReserveHeader(CMessage *self, uint8_t header_sz);
+extern void Msg_PullHeader(CMessage *self, uint8_t header_sz);
+extern void Msg_PushHeader(CMessage *self, uint8_t header_sz);
+
+extern void Msg_NotifyTxStatus(CMessage *self, Mns_MsgTxStatus_t status);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Properties */
+/*------------------------------------------------------------------------------------------------*/
+extern Msg_MostTel_t* Msg_GetMostTel(CMessage *self);
+
+extern uint8_t* Msg_GetHeader(CMessage *self);
+extern uint8_t Msg_GetHeaderSize(CMessage *self);
+extern Mns_Mem_Buffer_t* Msg_GetMemTx(CMessage *self);
+
+extern void Msg_SetLldHandle(CMessage *self, void *handle);
+extern void *Msg_GetLldHandle(CMessage *self);
+extern void Msg_SetPoolReference(CMessage *self, void *pool_ptr);
+extern void *Msg_GetPoolReference(CMessage *self);
+
+extern CDlNode *Msg_GetNode(CMessage *self);
+
+extern void Msg_SetTxStatusHandler(CMessage *self, Msg_TxStatusCb_t callback_fptr, void *inst_ptr);
+extern void Msg_SetExtPayload(CMessage *self, uint8_t *payload_ptr, uint8_t payload_sz, void* mem_info_ptr);
+extern void Msg_SetTxActive(CMessage *self, bool active);
+extern bool Msg_IsTxActive(CMessage *self);
+extern void Msg_SetTxBypass(CMessage *self, bool bypass);
+extern bool Msg_IsTxBypass(CMessage *self);
+
+extern bool Msg_VerifyContent(CMessage *self);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_MESSAGE_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_message_pb.h b/mnsl/mns_message_pb.h
new file mode 100644
index 0000000..8656519
--- /dev/null
+++ b/mnsl/mns_message_pb.h
@@ -0,0 +1,121 @@
+/*
+ * 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 Declaration of public message types
+ */
+
+#ifndef MNS_MESSAGE_PB_H
+#define MNS_MESSAGE_PB_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*!
+ * \addtogroup G_MNS_AMS
+ * @{
+ */
+/*------------------------------------------------------------------------------------------------*/
+/* Defines */
+/*------------------------------------------------------------------------------------------------*/
+#define MNS_ADDR_INTERNAL 0x0000U /*!< \brief Internal transmission destination address
+ * \details Can be used for internal message transmission
+ * to avoid possible race conditions during
+ * recalculation of the own node address.
+ */
+#define MNS_ADDR_BROADCAST_BLOCKING 0x03C8U /*!< \brief Blocking broadcast destination address */
+#define MNS_ADDR_BROADCAST_UNBLOCKING 0x03FFU /*!< \brief Unblocking broadcast destination address */
+#define MNS_ADDR_DEBUG 0x0FF0U /*!< \brief Optional debug destination address */
+/*! @} */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Message transmission status for internal/debug use
+ * \ingroup G_MNS_MISC_RET_RES
+ */
+typedef enum Mns_MsgTxStatus_
+{
+ MNS_MSG_STAT_OK = 0x00U, /*!< \brief Transmission succeeded */
+ MNS_MSG_STAT_ERROR_CFG_NO_RCVR = 0x01U, /*!< \brief No internal receiver exists */
+ MNS_MSG_STAT_ERROR_BF = 0x08U, /*!< \brief Buffer full */
+ MNS_MSG_STAT_ERROR_CRC = 0x09U, /*!< \brief CRC */
+ MNS_MSG_STAT_ERROR_ID = 0x0AU, /*!< \brief Corrupted identifiers */
+ MNS_MSG_STAT_ERROR_ACK = 0x0BU, /*!< \brief Corrupted PACK or CACK */
+ MNS_MSG_STAT_ERROR_TIMEOUT = 0x0CU, /*!< \brief TX timeout */
+ MNS_MSG_STAT_ERROR_FATAL_WT = 0x10U, /*!< \brief Wrong target */
+ MNS_MSG_STAT_ERROR_FATAL_OA = 0x11U, /*!< \brief Own node address */
+ MNS_MSG_STAT_ERROR_NA_TRANS = 0x18U, /*!< \brief Control channel was switched off and
+ * a pending transmission was canceled */
+ MNS_MSG_STAT_ERROR_NA_OFF = 0x19U, /*!< \brief Control channel not available */
+ MNS_MSG_STAT_ERROR_UNKNOWN = 0xFEU, /*!< \brief Unknown error status */
+ MNS_MSG_STAT_ERROR_SYNC = 0xFFU /*!< \brief Internal error which is notified if
+ * communication link with INIC is lost
+ */
+} Mns_MsgTxStatus_t;
+
+/*! \brief Operation Types
+ * \ingroup G_MNS_AMS_TYPES
+ */
+typedef enum Mns_OpType_
+{
+ MNS_OP_SET = 0x0, /*!< \brief Operation Set (Property) */
+ MNS_OP_GET = 0x1, /*!< \brief Operation Get (Property) */
+ MNS_OP_SETGET = 0x2, /*!< \brief Operation SetGet (Property) */
+ MNS_OP_INC = 0x3, /*!< \brief Operation Increment (Property) */
+ MNS_OP_DEC = 0x4, /*!< \brief Operation Decrement (Property) */
+ MNS_OP_STATUS = 0xC, /*!< \brief Operation Status (Property) */
+
+ MNS_OP_START = 0x0, /*!< \brief Operation Start (Method) */
+ MNS_OP_ABORT = 0x1, /*!< \brief Operation Abort (Method) */
+ MNS_OP_STARTRESULT = 0x2, /*!< \brief Operation StartResult (Method) */
+ MNS_OP_PROCESSING = 0xB, /*!< \brief Operation Processing (Method) */
+ MNS_OP_RESULT = 0xC, /*!< \brief Operation Result (Method) */
+
+ MNS_OP_STARTACK = 0x8, /*!< \brief Operation StartAck (Method) */
+ MNS_OP_ABORTACK = 0x7, /*!< \brief Operation AbortAck (Method) */
+ MNS_OP_STARTRESULTACK = 0x6, /*!< \brief Operation StartResultAck (Method) */
+ MNS_OP_PROCESSINGACK = 0xA, /*!< \brief Operation ProcessingAck (Method) */
+ MNS_OP_RESULTACK = 0xD, /*!< \brief Operation ResultAck (Method) */
+
+ MNS_OP_GETINTERFACE = 0x5, /*!< \brief Operation GetInterface (Property/Method) */
+ MNS_OP_INTERFACE = 0xE, /*!< \brief Operation Interface (Property/Method) */
+ MNS_OP_ERROR = 0xF, /*!< \brief Operation Error (Property/Method) */
+ MNS_OP_ERRORACK = 0x9 /*!< \brief Operation ErrorAck (Property/Method) */
+
+} Mns_OpType_t;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_MESSAGE_PB_H */
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_misc.c b/mnsl/mns_misc.c
new file mode 100644
index 0000000..c020c11
--- /dev/null
+++ b/mnsl/mns_misc.c
@@ -0,0 +1,82 @@
+/*
+ * 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 Implementation of the library module which contains miscellaneous helper functions.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_MISC
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief MOST NetServices internal memset-function.
+ * \param dst_ptr Pointer to the block of memory to fill
+ * \param value Value to be set
+ * \param size Number of bytes to be set to the value
+ */
+void Misc_MemSet(void *dst_ptr, int32_t value, uint32_t size)
+{
+ uint8_t *dst_ptr_ = (uint8_t *)dst_ptr;
+ uint32_t i;
+
+ for(i=0U; i<size; i++)
+ {
+ dst_ptr_[i] = (uint8_t)value; /* parasoft-suppress MISRA2004-17_4 "void pointer required for memset-function signature (stdlib)" */
+ }
+}
+
+/*! \brief MOST NetServices internal memcpy-function.
+ * \param dst_ptr Pointer to the destination array where the content is to be copied
+ * \param src_ptr Pointer to the source of data to be copied
+ * \param size Number of bytes to copy
+ */
+void Misc_MemCpy(void *dst_ptr, void *src_ptr, uint32_t size)
+{
+ uint8_t *dst_ptr_ = (uint8_t *)dst_ptr;
+ uint8_t *src_ptr_ = (uint8_t *)src_ptr;
+ uint32_t i;
+
+ for(i=0U; i<size; i++)
+ {
+ dst_ptr_[i] = src_ptr_[i]; /* parasoft-suppress MISRA2004-17_4 "void pointers required for memcpy-function signature (stdlib)" */
+ }
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_misc.h b/mnsl/mns_misc.h
new file mode 100644
index 0000000..76d005f
--- /dev/null
+++ b/mnsl/mns_misc.h
@@ -0,0 +1,157 @@
+/*
+ * 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 the library module which contains miscellaneous helper functions.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_MISC
+ * @{
+ */
+
+#ifndef MNS_MISC_H
+#define MNS_MISC_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Standard library functions */
+/*------------------------------------------------------------------------------------------------*/
+/* parasoft suppress item MISRA2004-19_7 reason "function-like macros allowed for stdlib and helper functions" */
+
+/*! \def MISC_MEM_SET
+ * \brief Macro to encapsulate memset function
+ * \details By defining the macro MNS_MEM_SET the application is able to specify its own memset
+ * function. If the macro is not defined MOST NetServices internal memset function
+ * Misc_MemSet() is used.
+ * \param dest Pointer to the block of memory to fill
+ * \param value Value to be set
+ * \param size Number of bytes to be set to the value.
+ */
+#ifdef MNS_MEM_SET
+#define MISC_MEM_SET(dest, value, size) (MNS_MEM_SET((dest), (value), (size)))
+#else
+#define MISC_MEM_SET(dest, value, size) (Misc_MemSet((dest), (value), (size)))
+#endif
+
+/*! \def MISC_MEM_CPY
+ * \brief Macro to encapsulate memcpy function
+ * \details By defining the macro MNS_MEM_CPY the application is able to specify its own memcpy
+ * function. If the macro is not defined MOST NetServices internal memcpy function
+ * Misc_MemCpy() is used.
+ * \param dest Pointer to the destination array where the content is to be copied
+ * \param src Pointer to the source of data to be copied
+ * \param size Number of bytes to copy
+ */
+#ifdef MNS_MEM_CPY
+#define MISC_MEM_CPY(dest, src, size) (MNS_MEM_CPY((dest), (src), (size)))
+#else
+#define MISC_MEM_CPY(dest, src, size) (Misc_MemCpy((dest), (src), (size)))
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Helper Macros */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Macro to avoid compiler warning "Unused Parameter" */
+#define MISC_UNUSED(p) ((p) = (p))
+
+/*! \brief High Byte of 16-bit value */
+#define MISC_HB(value) ((uint8_t)((uint16_t)(value) >> 8))
+
+/*! \brief Low Byte of 16-bit value */
+#define MISC_LB(value) ((uint8_t)((uint16_t)(value) & (uint16_t)0xFF))
+
+/*! \brief Big-Endian to target 16 bit */
+#define MISC_DECODE_WORD(w_ptr, msb_ptr) (*(w_ptr) = \
+ (uint16_t)((uint16_t)((uint16_t)(msb_ptr)[0] << 8) | (uint16_t)(msb_ptr)[1]))
+
+/*! \brief Big-Endian to target 32 bit */
+#define MISC_DECODE_DWORD(dw_ptr, msb_ptr) (*(dw_ptr) = \
+ (uint32_t)((uint32_t)((uint32_t)(msb_ptr)[0] << 24) | \
+ (uint32_t)((uint32_t)(msb_ptr)[1] << 16) | \
+ (uint32_t)((uint32_t)(msb_ptr)[2] << 8) | (uint32_t)(msb_ptr)[3]))
+
+/*! \brief Checks if a value is inside a certain range */
+#define MISC_IS_VALUE_IN_RANGE(val, min, max) ((((val) >= (min)) && ((val) <= (max))) ? true : false)
+
+/*! \brief Checks if the given size is a multiple of 4. If not, the given size is corrected
+ * by that macro.
+ */
+#define MISC_QUADLET_ALGINED_SIZE(size) (((((size)+4U)-1U)/4U)*4U)
+
+/* parasoft unsuppress item MISRA2004-19_7 reason "function-like macros allowed for stdlib and helper functions" */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes */
+/*------------------------------------------------------------------------------------------------*/
+extern void Misc_MemSet(void *dst_ptr, int32_t value, uint32_t size);
+extern void Misc_MemCpy(void *dst_ptr, void *src_ptr, uint32_t size);
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*!
+ * \def MNS_MEM_SET
+ * \brief Customer assignment of memset function
+ * \details By defining the macro MNS_MEM_SET the application is able to specify its own memset
+ * function to be used by the MOST NetServices. If the macro is not set the MOST
+ * NetServices will use byte wise write operations.
+ * \ingroup G_MNS_MISC
+ */
+#ifndef MNS_MEM_SET
+#define MNS_MEM_SET
+#endif
+
+/*!
+ * \def MNS_MEM_CPY
+ * \brief Customer assignment of memcpy function
+ * \details By defining the macro MNS_MEM_CPY the application is able to specify its own memcpy
+ * function to be used by the MOST NetServices. If the macro is not set the MOST
+ * NetServices will use byte wise copy operations.
+ * \ingroup G_MNS_MISC
+ */
+#ifndef MNS_MEM_CPY
+#define MNS_MEM_CPY
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_MISC_H */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_obs.c b/mnsl/mns_obs.c
new file mode 100644
index 0000000..7183fb2
--- /dev/null
+++ b/mnsl/mns_obs.c
@@ -0,0 +1,453 @@
+/*
+ * 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 Implementation of the observer library module. The module consists of the two classes
+ * CSubject and CObserver.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_OBS
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_obs.h"
+#include "mns_misc.h"
+#include "mns_trace.h"
+
+#include <assert.h> //TKU
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal Prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Sub_UpdateList(CSubject *self);
+static bool Sub_CheckObserver(void *current_obs_ptr, void *subject_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CSubject */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the subject class. Initializes a subject which distributes its data to
+ * a list of observers.
+ * \param self Instance pointer
+ * \param mns_inst_id MOST NetServices instance ID
+ */
+void Sub_Ctor(CSubject *self, uint8_t mns_inst_id)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ self->mns_inst_id = mns_inst_id;
+ Dl_Ctor(&self->list, self->mns_inst_id);
+ Dl_Ctor(&self->add_list, self->mns_inst_id);
+}
+
+/*! \brief Adds an observer to a subjects list.
+ * \param self Instance pointer
+ * \param obs_ptr Pointer to observer instance
+ * \return \c SUB_OK: No error
+ * \return \c SUB_ALREADY_ADDED: Observer is already added
+ * \return \c SUB_UNKNOWN_OBSERVER: Given observer is not valid
+ */
+Sub_Ret_t Sub_AddObserver(CSubject *self, CObserver *obs_ptr)
+{
+ Sub_Ret_t ret_val;
+ if(obs_ptr == NULL)
+ {
+ ret_val = SUB_UNKNOWN_OBSERVER;
+ }
+ else if(obs_ptr->valid != false)
+ {
+ ret_val = SUB_ALREADY_ADDED;
+ }
+ else if((self->notify != false) &&
+ (false == Dl_IsNodeInList(&self->list, &obs_ptr->node)) &&
+ (false == Dl_IsNodeInList(&self->add_list, &obs_ptr->node)))
+ {
+ TR_ASSERT(self->mns_inst_id, "[OBS]", (self->num_observers < 0xFFU));
+ Dl_InsertTail(&self->add_list, &obs_ptr->node);
+ obs_ptr->valid = true;
+ self->changed = true;
+ ret_val = SUB_DELAYED;
+ }
+ else if((self->notify == false) && (false == Dl_IsNodeInList(&self->list, &obs_ptr->node)))
+ {
+ TR_ASSERT(self->mns_inst_id, "[OBS]", (self->num_observers < 0xFFU));
+ ret_val = SUB_OK;
+ Dl_InsertTail(&self->list, &obs_ptr->node);
+ obs_ptr->valid = true;
+ self->num_observers++;
+ }
+ else
+ {
+ ret_val = SUB_UNKNOWN_OBSERVER;
+ }
+ return ret_val;
+}
+
+/*! \brief Removes an observer from a subjects list.
+ * \param self Instance pointer
+ * \param obs_ptr Pointer to observer instance
+ * \return \c SUB_OK: No error
+ * \return \c SUB_UNKNOWN_OBSERVER: Unknown observer is given
+ * \return \c SUB_UNKNOWN_OBSERVER: Given observer is not valid
+ */
+Sub_Ret_t Sub_RemoveObserver(CSubject *self, CObserver *obs_ptr)
+{
+ Sub_Ret_t ret_val;
+ if(obs_ptr == NULL)
+ {
+ ret_val = SUB_UNKNOWN_OBSERVER;
+ }
+ else if(obs_ptr->valid == false)
+ {
+ ret_val = SUB_UNKNOWN_OBSERVER;
+ }
+ else if((self->notify != false) &&
+ (Dl_IsNodeInList(&self->list, &obs_ptr->node) != false))
+ {
+ TR_ASSERT(self->mns_inst_id, "[OBS]", (self->num_observers > 0U));
+ obs_ptr->valid = false;
+ self->changed = true;
+ self->num_observers--;
+ ret_val = SUB_DELAYED;
+ }
+ else if((self->notify == false) &&
+ (DL_OK == Dl_Remove(&self->list, &obs_ptr->node)))
+ {
+ TR_ASSERT(self->mns_inst_id, "[OBS]", (self->num_observers > 0U));
+ self->num_observers--;
+ ret_val = SUB_OK;
+ }
+ else
+ {
+ ret_val = SUB_UNKNOWN_OBSERVER;
+ }
+ return ret_val;
+}
+
+/*! \brief Notifies all registered observers of a subject.
+ * \param self Instance pointer
+ * \param data_ptr Reference to value to distribute (optional)
+ */
+void Sub_Notify(CSubject *self, void *data_ptr)
+{
+ if(NULL != self)
+ {
+ CDlNode *n_tmp = self->list.head;
+ self->notify = true;
+ self->changed = false;
+ while(NULL != n_tmp)
+ {
+ CObserver *o_tmp = (CObserver *)n_tmp->data_ptr;
+ if((NULL != o_tmp->update_fptr) && (o_tmp->valid != false))
+ {
+ (o_tmp->update_fptr)(o_tmp->inst_ptr, data_ptr);
+ }
+ n_tmp = n_tmp->next;
+ }
+ if(self->changed != false)
+ {
+ Sub_UpdateList(self);
+ }
+ self->notify = false;
+ }
+}
+
+/*! \brief Updates the list of observers. Delayed remove- and add-operations are processed.
+ * \param self Instance pointer
+ */
+static void Sub_UpdateList(CSubject *self)
+{
+ (void)Dl_Foreach(&self->list, &Sub_CheckObserver, self);
+ Dl_AppendList(&self->list, &self->add_list);
+}
+
+/*! \brief Checks if the given observer is still valid. If the observer is invalid it will be
+ * removed from the list. This function is used by the foreach loop in Sub_UpdateList().
+ * \param current_obs_ptr Reference to the current observer object
+ * \param subject_ptr Reference to the subject object
+ * \return Returns always \c false. Force to process the whole list.
+ */
+static bool Sub_CheckObserver(void *current_obs_ptr, void *subject_ptr)
+{
+ CObserver *current_obs_ptr_ = (CObserver *)current_obs_ptr;
+ CSubject *subject_ptr_ = (CSubject *)subject_ptr;
+
+ if(false == current_obs_ptr_->valid)
+ {
+ (void)Dl_Remove(&subject_ptr_->list, &current_obs_ptr_->node);
+ }
+ return false;
+}
+
+/*! \brief Returns the number of registered observers of a subject.
+ * \param self Instance pointer
+ * \return The number of registered observers
+ */
+uint8_t Sub_GetNumObservers(CSubject *self)
+{
+ return self->num_observers;
+}
+
+/*! \brief Switches all observers of the source-subject to the target-subject.
+ * \param sub_target Target subject
+ * \param sub_source Source subject
+ * \return \c SUB_OK: No error
+ * \return \c SUB_INVALID_OPERATION: Target and source must be different objects
+ */
+Sub_Ret_t Sub_SwitchObservers(CSubject *sub_target, CSubject *sub_source)
+{
+ Sub_Ret_t ret_val;
+
+ if(sub_target == sub_source)
+ {
+ ret_val = SUB_INVALID_OPERATION;
+ }
+ else
+ {
+ Dl_AppendList(&sub_target->list, &sub_source->list);
+ sub_target->num_observers += sub_source->num_observers;
+ sub_source->num_observers = 0U;
+ ret_val = SUB_OK;
+ }
+ return ret_val;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CObserver */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the observer class. Initializes an observer which is notified
+ * by a corresponding subject.
+ * \param self Instance pointer
+ * \param inst_ptr Instance pointer used by update_fptr()
+ * \param update_fptr Callback function to update the observer
+ */
+void Obs_Ctor(CObserver *self, void *inst_ptr, Obs_UpdateCb_t update_fptr)
+{
+ assert(NULL != inst_ptr);
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ self->inst_ptr = inst_ptr;
+ self->update_fptr = update_fptr;
+ Dln_Ctor(&self->node, self);
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CSingleSubject */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the single-subject class. Initializes a single-subject which distributes
+ * its data to the registered single-observer.
+ * \param self Instance pointer
+ * \param mns_inst_id MOST NetServices instance ID
+ */
+void Ssub_Ctor(CSingleSubject *self, uint8_t mns_inst_id)
+{
+ self->observer_ptr = NULL;
+ self->mns_inst_id = mns_inst_id;
+}
+
+/*! \brief Adds a single-observer to a single-subject.
+ * \param self Instance pointer
+ * \param obs_ptr Pointer to single-observer instance
+ * \return \c SSUB_OK: No error
+ * \return \c SSUB_ALREADY_ADDED: Observer is already added
+ * \return \c SSUB_UNKNOWN_OBSERVER: Given observer is not valid
+ */
+Ssub_Ret_t Ssub_AddObserver(CSingleSubject *self, CSingleObserver *obs_ptr)
+{
+ Ssub_Ret_t ret_val;
+ if(obs_ptr == NULL)
+ {
+ ret_val = SSUB_UNKNOWN_OBSERVER;
+ }
+ else if(self->observer_ptr != obs_ptr)
+ {
+#ifdef MNS_TR_INFO
+ if(self->observer_ptr != NULL)
+ {
+ TR_INFO((self->mns_inst_id, "[SSUB]", "Observer callback has been overwritten", 0U));
+ }
+#endif
+ ret_val = SSUB_OK;
+ self->observer_ptr = obs_ptr;
+ }
+ else
+ {
+ ret_val = SSUB_ALREADY_ADDED;
+ }
+
+ return ret_val;
+}
+
+/*! \brief Removes an single-observer from a single-subject.
+ * \param self Instance pointer
+ */
+void Ssub_RemoveObserver(CSingleSubject *self)
+{
+ self->observer_ptr = NULL;
+}
+
+/*! \brief Notifies the registered single-observer of the given single-subject.
+ * \param self Instance pointer
+ * \param data_ptr Reference to value to distribute (optional)
+ * \param auto_remove If true the observer will be removed
+ */
+void Ssub_Notify(CSingleSubject *self, void *data_ptr, bool auto_remove)
+{
+ void *inst_ptr = NULL;
+ Obs_UpdateCb_t update_fptr = NULL;
+ if(self->observer_ptr != NULL)
+ {
+ inst_ptr = self->observer_ptr->inst_ptr;
+ update_fptr = self->observer_ptr->update_fptr;
+ if(auto_remove != false)
+ {
+ self->observer_ptr = NULL;
+ }
+ }
+ if(update_fptr != NULL)
+ {
+ update_fptr(inst_ptr, data_ptr);
+ }
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CSingleObserver */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the single-observer class. Initializes an single-observer which is
+ * notified by a corresponding single-subject.
+ * \param self Instance pointer
+ * \param inst_ptr Instance pointer used by update_fptr()
+ * \param update_fptr Callback function to update the observer
+ */
+void Sobs_Ctor(CSingleObserver *self, void *inst_ptr, Sobs_UpdateCb_t update_fptr)
+{
+ self->inst_ptr = inst_ptr;
+ self->update_fptr = update_fptr;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CMaskedObserver */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the masked-observer class. Initializes an observer which is notified
+ * by a corresponding subject.
+ * \param self Instance pointer
+ * \param inst_ptr Instance pointer used by update_fptr()
+ * \param notification_mask Notification bitmask
+ * \param update_fptr Callback function to update the observer
+ */
+void Mobs_Ctor(CMaskedObserver *self,
+ void *inst_ptr,
+ uint32_t notification_mask,
+ Obs_UpdateCb_t update_fptr)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ Obs_Ctor(&self->parent, inst_ptr, update_fptr);
+ self->notification_mask = notification_mask;
+}
+
+/*! \brief Sets the notification mask of a masked-observer.
+ * \param self Instance pointer
+ * \param mask Bitmask to set
+ */
+void Mobs_SetNotificationMask(CMaskedObserver *self, uint32_t mask)
+{
+ self->notification_mask = mask;
+}
+
+/*! \brief Retrieves the notification mask of a masked-observer.
+ * \param self Instance pointer
+ * \return Returns the current notification bitmask of the given observer
+ */
+uint32_t Mobs_GetNotificationMask(CMaskedObserver *self)
+{
+ return self->notification_mask;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Additional methods of class CSubject used in combination with CMaskedObserver */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Adds an masked-observer to a masked-subjects list.
+ * \param self Instance pointer
+ * \param obs_ptr Pointer to observer instance
+ * \return \c SUB_OK: No error
+ * \return \c SUB_ALREADY_ADDED: Observer is already added
+ * \return \c SUB_UNKNOWN_OBSERVER: Given observer is not valid
+ */
+Sub_Ret_t Msub_AddObserver(CSubject *self, CMaskedObserver *obs_ptr)
+{
+ return Sub_AddObserver(self, &obs_ptr->parent);
+}
+
+/*! \brief Removes an masked-observer from a subjects list.
+ * \param self Instance pointer
+ * \param obs_ptr Pointer to observer instance
+ * \return \c SUB_OK: No error
+ * \return \c SUB_UNKNOWN_OBSERVER: Unknown observer is given
+ * \return \c SUB_UNKNOWN_OBSERVER: Given observer is not valid
+ */
+Sub_Ret_t Msub_RemoveObserver(CSubject *self, CMaskedObserver *obs_ptr)
+{
+ return Sub_RemoveObserver(self, &obs_ptr->parent);
+}
+
+/*! \brief Notifies all registered masked-observers of a masked-subject.
+ * \param self Instance pointer
+ * \param data_ptr Reference to value to distribute (optional)
+ * \param notification_mask Bitmask indicates notified observers
+ */
+void Msub_Notify(CSubject *self, void *data_ptr, uint32_t notification_mask)
+{
+ if(NULL != self)
+ {
+ CDlNode *n_tmp = self->list.head;
+ self->notify = true;
+ self->changed = false;
+ while(NULL != n_tmp)
+ {
+ CMaskedObserver *o_tmp = (CMaskedObserver *)n_tmp->data_ptr;
+ if( (NULL != o_tmp->parent.update_fptr) &&
+ (o_tmp->parent.valid != false) &&
+ ((o_tmp->notification_mask & notification_mask) != 0U) )
+ {
+ (o_tmp->parent.update_fptr)(o_tmp->parent.inst_ptr, data_ptr);
+ }
+ n_tmp = n_tmp->next;
+ }
+ if(self->changed != false)
+ {
+ Sub_UpdateList(self);
+ }
+ self->notify = false;
+ }
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_obs.h b/mnsl/mns_obs.h
new file mode 100644
index 0000000..088c6c8
--- /dev/null
+++ b/mnsl/mns_obs.h
@@ -0,0 +1,196 @@
+/*
+ * 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 the observer library module. The module consists of the two
+ * classes CSubject and CObserver.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_OBS
+ * @{
+ */
+
+#ifndef MNS_OBS_H
+#define MNS_OBS_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_types_cfg.h"
+#include "mns_dl.h"
+#include "mns_ret.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Type definitions */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Function signature used for callback functions which notifies the observers.
+ * \param self Instance pointer
+ * \param data_ptr Reference to optional data
+ */
+typedef void (*Obs_UpdateCb_t)(void *self, void *data_ptr);
+
+/*! \brief Function signature used for callback functions which notifies the single-observers.
+ * \param self Instance pointer
+ * \param data_ptr Reference to optional data
+ */
+typedef void (*Sobs_UpdateCb_t)(void *self, void *data_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Enumerators */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Standard return values of the subject class. */
+typedef enum Sub_Ret_
+{
+ SUB_OK, /*!< \brief No error */
+ SUB_DELAYED, /*!< \brief Operation is queued since notification is still active */
+ SUB_ALREADY_ADDED, /*!< \brief Observer already added */
+ SUB_UNKNOWN_OBSERVER, /*!< \brief Unknown observer */
+ SUB_INVALID_OPERATION /*!< \brief Invalid operation */
+
+} Sub_Ret_t;
+
+/*! \brief Standard return values of the single-subject class. */
+typedef enum Ssub_Ret_
+{
+ SSUB_OK, /*!< \brief No error */
+ SSUB_ALREADY_ADDED, /*!< \brief Observer already added */
+ SSUB_UNKNOWN_OBSERVER /*!< \brief Unknown observer */
+
+} Ssub_Ret_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class structure of observers which are notified by subjects. */
+typedef struct CObserver_
+{
+ CDlNode node; /*!< \brief Node element to be able to add observer to list */
+ void *inst_ptr; /*!< \brief Reference to instance used by update_fptr() */
+ Obs_UpdateCb_t update_fptr; /*!< \brief Callback function to update the observer */
+ bool valid; /*!< \brief Used for queued remove operation */
+
+} CObserver;
+
+/*! \brief Class structure of subjects. */
+typedef struct CSubject_
+{
+ CDlList list; /*!< \brief Doubly linked list to manage observers */
+ CDlList add_list; /*!< \brief List to manage delayed add operations */
+ uint8_t num_observers; /*!< \brief Number of added observers */
+ bool notify; /*!< \brief Signals that the notification is in progress */
+ bool changed; /*!< \brief Signals that an add- or a remove-operation
+ has been queued */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+
+} CSubject;
+
+/*! \brief Class structure of a single-observer which is notified by a single-subject. */
+typedef struct CSingleObserver_
+{
+ void *inst_ptr; /*!< \brief Reference to instance used by update_fptr() */
+ Obs_UpdateCb_t update_fptr; /*!< \brief Callback function to update the observer */
+
+} CSingleObserver;
+
+/*! \brief Class structure of a single-subject. */
+typedef struct CSingleSubject_
+{
+ CSingleObserver *observer_ptr; /*!< \brief Reference to the assigned single-observer */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+
+} CSingleSubject;
+
+/*! \brief Class structure of masked observers which are notified by subjects. */
+typedef struct CMaskedObserver_
+{
+ CObserver parent; /*!< \brief Parent class instance */
+ uint32_t notification_mask; /*!< \brief Notification bitmask */
+
+} CMaskedObserver;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CSubject */
+/*------------------------------------------------------------------------------------------------*/
+extern void Sub_Ctor(CSubject *self, uint8_t mns_inst_id);
+extern Sub_Ret_t Sub_AddObserver(CSubject *self, CObserver *obs_ptr);
+extern Sub_Ret_t Sub_RemoveObserver(CSubject *self, CObserver *obs_ptr);
+extern void Sub_Notify(CSubject *self, void *data_ptr);
+extern uint8_t Sub_GetNumObservers(CSubject *self);
+extern Sub_Ret_t Sub_SwitchObservers(CSubject *sub_target, CSubject *sub_source);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CObserver */
+/*------------------------------------------------------------------------------------------------*/
+extern void Obs_Ctor(CObserver *self, void *inst_ptr, Obs_UpdateCb_t update_fptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CSingleSubject */
+/*------------------------------------------------------------------------------------------------*/
+extern void Ssub_Ctor(CSingleSubject *self, uint8_t mns_inst_id);
+extern Ssub_Ret_t Ssub_AddObserver(CSingleSubject *self, CSingleObserver *obs_ptr);
+extern void Ssub_RemoveObserver(CSingleSubject *self);
+extern void Ssub_Notify(CSingleSubject *self, void *data_ptr, bool auto_remove);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CSingleObserver */
+/*------------------------------------------------------------------------------------------------*/
+extern void Sobs_Ctor(CSingleObserver *self, void *inst_ptr, Sobs_UpdateCb_t update_fptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CMaskedObserver */
+/*------------------------------------------------------------------------------------------------*/
+extern void Mobs_Ctor(CMaskedObserver *self,
+ void *inst_ptr,
+ uint32_t notification_mask,
+ Obs_UpdateCb_t update_fptr);
+extern void Mobs_SetNotificationMask(CMaskedObserver *self, uint32_t mask);
+extern uint32_t Mobs_GetNotificationMask(CMaskedObserver *self);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Additional prototypes of class CSubject used in combination with CMaskedObserver */
+/*------------------------------------------------------------------------------------------------*/
+extern Sub_Ret_t Msub_AddObserver(CSubject *self, CMaskedObserver *obs_ptr);
+extern Sub_Ret_t Msub_RemoveObserver(CSubject *self, CMaskedObserver *obs_ptr);
+extern void Msub_Notify(CSubject *self, void *data_ptr, uint32_t notification_mask);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_OBS_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmchannel.c b/mnsl/mns_pmchannel.c
new file mode 100644
index 0000000..e98a2b2
--- /dev/null
+++ b/mnsl/mns_pmchannel.c
@@ -0,0 +1,311 @@
+/*
+ * 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 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 */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmchannel.h b/mnsl/mns_pmchannel.h
new file mode 100644
index 0000000..8b069ad
--- /dev/null
+++ b/mnsl/mns_pmchannel.h
@@ -0,0 +1,179 @@
+/*
+ * 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 Port Message Channel
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PMC
+ * @{
+ */
+
+#ifndef MNS_PMCHANNEL_H
+#define MNS_PMCHANNEL_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+#include "mns_lld_pb.h"
+#include "mns_lldpool.h"
+#include "mns_pool.h"
+#include "mns_base.h"
+#include "mns_message.h"
+#include "mns_pmp.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macros */
+/*------------------------------------------------------------------------------------------------*/
+#define PMCH_POOL_SIZE_RX_MIN 10U /*!< \brief Minimal size of Rx pool which is shared by all FIFOs */
+#define PMCH_POOL_SIZE_RX_OPT 35U /*!< \brief Optimal size of Rx pool which is shared by all FIFOs */
+
+#define PMCH_MCM_CREDITS_OPT 21U /*!< \brief Optimal number of credits configured for MCM FIFO */
+#define PMCH_MCM_THRESHOLD_OPT 8U /*!< \brief Optimal threshold configured for MCM FIFO */
+
+#define PMCH_FIFO_CREDITS_OPT 5U /*!< \brief Optimal number of credits configured for conventional FIFOs */
+#define PMCH_FIFO_THRESHOLD_OPT 4U /*!< \brief Optimal threshold configured for conventional FIFO */
+
+#define PMCH_FIFO_CREDITS_MIN 3U /*!< \brief Minimal number of credits configured for conventional FIFOs */
+#define PMCH_FIFO_THRESHOLD_MIN 2U /*!< \brief Minimal threshold configured for conventional FIFO */
+
+/* required rules */
+#if defined(MNS_FOOTPRINT_TINY) && defined(MNSL_CHANNEL_POOL_SIZE_RX)
+# error Forbidden combination of macros MNS_FOOTPRINT_TINY and MNSL_CHANNEL_POOL_SIZE_RX
+#endif
+
+#ifdef MNSL_CHANNEL_POOL_SIZE_RX
+# if (MNSL_CHANNEL_POOL_SIZE_RX < PMCH_POOL_SIZE_RX_MIN)
+# error MNSL_CHANNEL_POOL_SIZE_RX must be at least 10
+# endif
+#endif
+
+/*! \def MNSL_CHANNEL_POOL_SIZE_RX
+ * \brief MNSL configuration that defines the number of pre-allocated Rx messages which are shared by all FIFOs.
+ * Valid values: 35...65535. Default value: 35.
+ *
+ * \def PMCH_POOL_SIZE_RX
+ * \brief Defines the number of pre-allocated Rx messages which are shared by all FIFOs.
+ */
+#ifdef MNS_FOOTPRINT_TINY
+# define PMCH_POOL_SIZE_RX (PMCH_POOL_SIZE_RX_MIN)
+# define PMCH_MCM_CREDITS (PMCH_FIFO_CREDITS_MIN)
+# define PMCH_FIFO_CREDITS (PMCH_FIFO_CREDITS_MIN)
+# define PMCH_MCM_THRESHOLD (PMCH_FIFO_THRESHOLD_MIN)
+# define PMCH_FIFO_THRESHOLD (PMCH_FIFO_THRESHOLD_MIN)
+# define MNSL_CHANNEL_POOL_SIZE_RX (PMCH_POOL_SIZE_RX_MIN)
+#elif defined MNSL_CHANNEL_POOL_SIZE_RX
+# define PMCH_POOL_SIZE_RX ((uint16_t)MNSL_CHANNEL_POOL_SIZE_RX)
+# define PMCH_MCM_CREDITS (PMCH_FIFO_CREDITS_MIN)
+# define PMCH_FIFO_CREDITS (PMCH_FIFO_CREDITS_MIN)
+# define PMCH_MCM_THRESHOLD (PMCH_FIFO_THRESHOLD_MIN)
+# define PMCH_FIFO_THRESHOLD (PMCH_FIFO_THRESHOLD_MIN)
+#else
+# define PMCH_POOL_SIZE_RX (PMCH_POOL_SIZE_RX_OPT)
+# define PMCH_MCM_CREDITS (PMCH_MCM_CREDITS_OPT)
+# define PMCH_FIFO_CREDITS (PMCH_FIFO_CREDITS_OPT)
+# define PMCH_MCM_THRESHOLD (PMCH_MCM_THRESHOLD_OPT)
+# define PMCH_FIFO_THRESHOLD (PMCH_FIFO_THRESHOLD_OPT)
+# define MNSL_CHANNEL_POOL_SIZE_RX (PMCH_POOL_SIZE_RX_OPT)
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+typedef void (*Pmch_OnRxMsg_t)(void *fifo_ptr, CMessage *msg_ptr);
+typedef void (*Pmch_OnTxRelease_t)(void *fifo_ptr, Mns_Lld_TxMsg_t *handle_ptr);
+
+/*! \brief Initialization structure of the Base Module. */
+typedef struct Pmch_InitData_
+{
+ uint8_t mns_inst_id; /*!< \brief Initialization data of the Trace Module */
+ Mns_Lld_Callbacks_t lld_iface; /*!< \brief LLD callback functions */
+ Pmch_OnTxRelease_t tx_release_fptr; /*!< \brief Callback which releases a FIFO dedicated LLD buffer */
+
+} Pmch_InitData_t;
+
+/*! \brief Combination of callback and instance for a receiving FIFO */
+typedef struct Pmch_Receiver_
+{
+ Pmch_OnRxMsg_t rx_fptr; /*!< \brief Reference to an Rx callback function */
+ void *inst_ptr; /*!< \brief Reference to the instance which shall be
+ * passed to the callback function */
+} Pmch_Receiver_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class attributes */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Structure of a PMS object */
+typedef struct CPmChannel_
+{
+ Pmch_InitData_t init_data; /*!< \brief Copy of initialization data */
+
+ Lld_IntRxMsg_t lld_rx_msgs[PMCH_POOL_SIZE_RX]; /*!< \brief Pre-allocated LLD Rx message objects */
+ CMessage rx_msgs[PMCH_POOL_SIZE_RX]; /*!< \brief Pre-allocated Rx message objects */
+ CPool rx_msgs_pool; /*!< \brief Pre-allocated Rx message pool */
+ bool rx_trigger_available; /*!< \brief Triggers LLD callback function if a buffer
+ * is available again.
+ */
+ bool lld_active; /*!< \brief Determines whether the LLD is running */
+ Mns_Lld_Api_t mns_iface; /*!< \brief PMS function pointers */
+
+ Pmch_Receiver_t receivers[PMP_MAX_NUM_FIFOS]; /*!< \brief Registered FIFOs for Rx */
+
+ void *inst_ptr; /*< TKU: tag for LLD */
+
+} CPmChannel;
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class methods */
+/*------------------------------------------------------------------------------------------------*/
+/* component creation */
+extern void Pmch_Ctor(CPmChannel *self, const Pmch_InitData_t *init_ptr, void *inst_ptr);
+extern void Pmch_Initialize(CPmChannel *self);
+extern void Pmch_Uninitialize(CPmChannel *self);
+extern void Pmch_RegisterReceiver(CPmChannel *self, Pmp_FifoId_t fifo_id, Pmch_OnRxMsg_t rx_fptr, void *inst_ptr);
+extern void Pmch_Transmit(CPmChannel *self, Mns_Lld_TxMsg_t *msg_ptr);
+extern void Pmch_ReturnRxToPool(void *self, CMessage *msg_ptr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* MNS_PMCHANNEL_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmcmd.c b/mnsl/mns_pmcmd.c
new file mode 100644
index 0000000..21d8913
--- /dev/null
+++ b/mnsl/mns_pmcmd.c
@@ -0,0 +1,157 @@
+/*
+ * 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 Implementation of class CPmCommand
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PM_CMD
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_pmcmd.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of CPmCommand class
+ * \param self The instance
+ * \param fifo The dedicated FIFO
+ * \param type The port message type
+ */
+void Pmcmd_Ctor(CPmCommand *self, Pmp_FifoId_t fifo, Pmp_MsgType_t type)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self)); /* setup attributes */
+ self->memory.data_ptr = &self->data[0];
+ self->tx_obj.lld_msg.memory_ptr = &self->memory;
+ self->tx_obj.msg_ptr = NULL; /* label message as command by setting */
+ self->tx_obj.owner_ptr = NULL; /* msg_ptr and owner_ptr to NULL */
+ self->trigger = false;
+
+ Pmp_SetPmhl(self->data, 3U); /* PMHL is always "3" for control/status messages */
+ Pmp_SetFph(self->data, fifo, type);
+}
+
+/*! \brief Retrieves reference to the LLD Tx message object required to call Pmch_Transmit()
+ * \param self The instance
+ * \return Returns a reference to the LLD Tx message object
+ */
+Mns_Lld_TxMsg_t* Pmcmd_GetLldTxObject(CPmCommand *self)
+{
+ return (Mns_Lld_TxMsg_t*)(void*)self;
+}
+
+/*! \brief Sets the content of a command/status message
+ * \param self The instance
+ * \param sid The sequence id
+ * \param ext_type The ExtType type
+ * \param ext_code The ExtType code
+ * \param add_data_ptr Additional payload data
+ * \param add_data_sz The size of additional payload data, valid values: 0..4
+ */
+void Pmcmd_SetContent(CPmCommand *self, uint8_t sid, uint8_t ext_type, uint8_t ext_code, uint8_t add_data_ptr[], uint8_t add_data_sz)
+{
+ if ((add_data_ptr != NULL) && (add_data_sz != 0U))
+ {
+ MISC_MEM_CPY(&self->data[6U], add_data_ptr, (size_t)add_data_sz);
+ }
+
+ self->memory.data_size = 6U + (uint16_t)add_data_sz;
+ self->memory.total_size = 6U + (uint16_t)add_data_sz;
+
+ Pmp_SetPml(self->data, 4U + add_data_sz);
+ Pmp_SetSid(self->data, sid);
+ Pmp_SetExtType(self->data, ext_type, ext_code);
+}
+
+/*! \brief Updates the content of a command/status message
+ * \details The length and the content of the payload is not modified.
+ * It is important to call Pmcmd_SetContent() before.
+ * \param self The instance
+ * \param sid The sequence id
+ * \param ext_type The ExtType type
+ * \param ext_code The ExtType code
+ */
+void Pmcmd_UpdateContent(CPmCommand *self, uint8_t sid, uint8_t ext_type, uint8_t ext_code)
+{
+ Pmp_SetSid(self->data, sid);
+ Pmp_SetExtType(self->data, ext_type, ext_code);
+}
+
+/*! \brief Reserves the command object if it is available
+ * \param self The instance
+ * \return \c true if the command object is available, \c false
+ * if the command object is (still) in usage
+ */
+bool Pmcmd_Reserve(CPmCommand *self)
+{
+ bool succ = false;
+
+ if (self->reserved == false)
+ {
+ self->reserved = true;
+ succ = true;
+ }
+ return succ;
+}
+
+/*! \brief Releases the command object after usage
+ * \param self The instance
+ */
+void Pmcmd_Release(CPmCommand *self)
+{
+ self->reserved = false;
+}
+
+/*! \brief Sets or resets the trigger attribute
+ * \param self The instance
+ * \param trigger The trigger value
+ */
+void Pmcmd_SetTrigger(CPmCommand *self, bool trigger)
+{
+ self->trigger = trigger;
+}
+
+/*! \brief Returns the trigger value
+ * \param self The instance
+ * \return Returns \c true if the trigger attribute is set, otherwise \c false.
+ */
+bool Pmcmd_IsTriggered(CPmCommand *self)
+{
+ return self->trigger;
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmcmd.h b/mnsl/mns_pmcmd.h
new file mode 100644
index 0000000..5905beb
--- /dev/null
+++ b/mnsl/mns_pmcmd.h
@@ -0,0 +1,92 @@
+/*
+ * 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 Declaration of class CPmCommand
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PM_CMD
+ * @{
+ */
+
+#ifndef MNS_PMCMD_H
+#define MNS_PMCMD_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_types_cfg.h"
+#include "mns_memory.h"
+#include "mns_lldpool.h"
+#include "mns_pmp.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class CPmCommand */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class CPmCommand */
+typedef struct CPmCommand_
+{
+ Lld_IntTxMsg_t tx_obj; /*!< \brief Required LLD Tx structure, must be first attribute */
+ uint8_t data[10]; /*!< \brief Reserved memory space */
+ Mns_Mem_Buffer_t memory; /*!< \brief Public memory structure */
+ bool reserved; /*!< \brief \c true if the command is in use, otherwise \c false. */
+ bool trigger; /*!< \brief \c true if the command is triggered, otherwise \c false. */
+
+} CPmCommand;
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Methods */
+/*------------------------------------------------------------------------------------------------*/
+extern void Pmcmd_Ctor(CPmCommand *self, Pmp_FifoId_t fifo, Pmp_MsgType_t type);
+extern Mns_Lld_TxMsg_t* Pmcmd_GetLldTxObject(CPmCommand *self);
+extern bool Pmcmd_Reserve(CPmCommand *self);
+extern void Pmcmd_Release(CPmCommand *self);
+extern void Pmcmd_SetContent(CPmCommand *self, uint8_t sid, uint8_t ext_type,
+ uint8_t ext_code, uint8_t add_data_ptr[], uint8_t add_data_sz);
+extern void Pmcmd_UpdateContent(CPmCommand *self, uint8_t sid, uint8_t ext_type, uint8_t ext_code);
+extern void Pmcmd_SetTrigger(CPmCommand *self, bool trigger);
+extern bool Pmcmd_IsTriggered(CPmCommand *self);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_PMCMD_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmfifo.c b/mnsl/mns_pmfifo.c
new file mode 100644
index 0000000..a1cafbf
--- /dev/null
+++ b/mnsl/mns_pmfifo.c
@@ -0,0 +1,1368 @@
+/*
+ * 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 Implementation of Port Message FIFO
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PMF
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_pmfifo.h"
+#include "mns_pmp.h"
+#include "mns_pmcmd.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal macros */
+/*------------------------------------------------------------------------------------------------*/
+/*------------------------------------------------------------------------------------------------*/
+/* Internal Constants */
+/*------------------------------------------------------------------------------------------------*/
+static const uint8_t FIFO_SRV_PRIO = 252U; /* parasoft-suppress MISRA2004-8_7 "configuration property" */
+static const Srv_Event_t FIFO_SE_RX_SERVICE = 1U; /*!< \brief Event which triggers the Rx service */
+static const Srv_Event_t FIFO_SE_TX_SERVICE = 2U; /*!< \brief Event which triggers the Rx service */
+static const Srv_Event_t FIFO_SE_TX_APPLY_STATUS = 4U; /*!< \brief Event which triggers to apply the current INIC status */
+static const Srv_Event_t FIFO_SE_ALL = 7U; /* parasoft-suppress MISRA2004-8_7 "configuration property" */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Fifo_InitCounters(CPmFifo *self, uint8_t tx_sid_complete, uint8_t tx_credits);
+static void Fifo_Service(void *self);
+
+static void Fifo_RxService(CPmFifo *self);
+static void Fifo_RxCheckStatusTrigger(CPmFifo *self);
+static void Fifo_RxGetCredit(CPmFifo *self);
+static void Fifo_RxReleaseCredit(CPmFifo *self);
+static bool Fifo_RxProcessData(CPmFifo *self, CMessage *msg_ptr);
+static void Fifo_RxProcessStatus(CPmFifo *self, CMessage *msg_ptr);
+static void Fifo_RxProcessCommand(CPmFifo *self, CMessage *msg_ptr);
+static void Fifo_RxProcessSyncStatus(CPmFifo *self, uint8_t sid, uint8_t type, uint8_t code, uint8_t *header_ptr);
+static uint8_t Fifo_RxCheckFailureCode(CPmFifo *self, uint8_t failure_code);
+static void Fifo_OnRx(void *self, CMessage *msg_ptr);
+
+static void Fifo_TxService(CPmFifo *self);
+static void Fifo_TxProcessData(CPmFifo *self);
+static void Fifo_TxProcessStatus(CPmFifo *self);
+static void Fifo_TxProcessCommand(CPmFifo *self);
+
+static void Fifo_TxEnqueueBypassMsg(CPmFifo *self, CDlList *q_ptr, CMessage *msg_ptr);
+static bool Fifo_FindFirstRegularMsg(void *d_ptr, void *ud_ptr);
+
+static void Fifo_TxExecuteCancel(CPmFifo *self, uint8_t failure_sid, uint8_t failure_code);
+static void Fifo_TxExecuteCancelAll(CPmFifo *self, uint8_t failure_sid, uint8_t failure_code);
+static void Fifo_TxFinishedCancelAll(CPmFifo *self);
+static uint8_t Fifo_TxPendingGetFollowerId(CPmFifo *self);
+static void Fifo_TxCancelFollowers(CPmFifo *self, uint8_t follower_id, Mns_MsgTxStatus_t status);
+
+static bool Fifo_TxHasAccessPending(CPmFifo *self);
+static void Fifo_TxRestorePending(CPmFifo *self);
+
+static void Fifo_TxOnWatchdogTimer(void *self);
+static void Fifo_TxStartWatchdog(CPmFifo *self);
+
+static uint8_t Fifo_TxGetValidAcknowledges(CPmFifo *self, uint8_t sid);
+static bool Fifo_TxNotifyStatus(CPmFifo *self, uint8_t sid, Mns_MsgTxStatus_t status);
+static void Fifo_TxApplyCurrentStatus(CPmFifo *self);
+static void Fifo_TxUpdateCurrentStatus(CPmFifo *self, uint8_t sid, uint8_t type, uint8_t code);
+static bool Fifo_TxIsIncomingSidValid(CPmFifo *self, uint8_t sid);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of message FIFO
+ * \param self The instance
+ * \param init_ptr Reference to initialization data
+ * \param config_ptr Reference to configuration
+ */
+void Fifo_Ctor(CPmFifo *self, const Fifo_InitData_t *init_ptr, const Fifo_Config_t *config_ptr)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+
+ self->init = *init_ptr;
+ self->config = *config_ptr;
+
+ self->sync_state = FIFO_S_UNSYNCED_INIT; /* initialize members */
+ Sub_Ctor(&self->sync_state_subject, self->init.base_ptr->mns_inst_id);
+
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_Ctor(): state: %u", 1U, self->sync_state));
+
+ Srv_Ctor(&self->service, FIFO_SRV_PRIO, self, &Fifo_Service); /* registration of service */
+ (void)Scd_AddService(&self->init.base_ptr->scd, &self->service);
+
+ T_Ctor(&self->wd.timer); /* setup watchdog */
+ self->wd.timer_value = self->config.tx_wd_timer_value;
+ Pmcmd_Ctor(&self->wd.wd_cmd, self->config.fifo_id, PMP_MSG_TYPE_CMD);
+ Pmcmd_SetContent(&self->wd.wd_cmd, 0U, PMP_CMD_TYPE_REQ_STATUS, PMP_CMD_CODE_REQ_STATUS, NULL, 0U);
+
+ /* init Rx part */
+ Dl_Ctor(&self->rx.queue, self->init.base_ptr->mns_inst_id);
+ self->rx.encoder_ptr = self->init.rx_encoder_ptr;
+ self->rx.on_complete_fptr = self->init.rx_cb_fptr;
+ self->rx.on_complete_inst = self->init.rx_cb_inst;
+
+ self->rx.ack_threshold = self->config.rx_threshold;
+
+ if (self->config.rx_threshold > self->config.rx_credits)/* configuration error - use single acknowledge */
+ {
+ self->rx.ack_threshold = 1U;
+ TR_FAILED_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]");
+ }
+
+ self->rx.wait_processing = false;
+ Pmcmd_Ctor(&self->rx.status, self->config.fifo_id, PMP_MSG_TYPE_STATUS);
+ Pmcmd_SetContent(&self->rx.status, 0U, PMP_STATUS_TYPE_FLOW, PMP_STATUS_CODE_SUCCESS, NULL, 0U);
+
+ /* init Tx part */
+ Dl_Ctor(&self->tx.waiting_queue, self->init.base_ptr->mns_inst_id);
+ Dl_Ctor(&self->tx.pending_q, self->init.base_ptr->mns_inst_id);
+
+ Pmcmd_Ctor(&self->tx.cancel_cmd, self->config.fifo_id, PMP_MSG_TYPE_CMD);
+ Pmcmd_SetContent(&self->tx.cancel_cmd, 0U, PMP_CMD_TYPE_MSG_ACTION, PMP_CMD_CODE_ACTION_CANCEL, NULL, 0U);
+
+ Fifo_InitCounters(self, 0U, 0U); /* values are incremented on each sync attempt */
+ self->tx.encoder_ptr = init_ptr->tx_encoder_ptr;
+
+ /* FIFO synchronization command */
+ self->sync_cnt = 0xFFU;
+ self->sync_params[0] = config_ptr->rx_credits;
+ self->sync_params[1] = config_ptr->rx_busy_allowed;
+ self->sync_params[2] = config_ptr->rx_ack_timeout;
+ self->sync_params[3] = config_ptr->tx_wd_timeout;
+ Pmcmd_Ctor(&self->tx.sync_cmd, self->config.fifo_id, PMP_MSG_TYPE_CMD);
+ Pmcmd_SetContent(&self->tx.sync_cmd, 0U, PMP_CMD_TYPE_SYNCHRONIZATION, PMP_CMD_CODE_SYNC, self->sync_params, 4U);
+
+ /* default PM header for Tx */
+ self->tx.pm_header.pml = 6U;
+ self->tx.pm_header.pmhl = self->tx.encoder_ptr->pm_hdr_sz - 3U;
+ Pmh_SetFph(&self->tx.pm_header, self->config.fifo_id, PMP_MSG_TYPE_DATA);
+ self->tx.pm_header.sid = 0U;
+ self->tx.pm_header.ext_type = (uint8_t)self->tx.encoder_ptr->content_type;
+
+ Lldp_Ctor(&self->tx.lld_pool, self, self->init.base_ptr->mns_inst_id);
+
+ Pmch_RegisterReceiver(self->init.channel_ptr, self->config.fifo_id, &Fifo_OnRx, self);
+}
+
+/*! \brief Initializes flow control and related counters
+ * \param self The instance
+ * \param tx_sid_complete Reference to initialization data
+ * \param tx_credits Number of credits for Tx
+ */
+static void Fifo_InitCounters(CPmFifo *self, uint8_t tx_sid_complete, uint8_t tx_credits)
+{
+ self->rx.busy_num = 0U;
+ self->rx.expected_sid = tx_sid_complete + 1U;
+ self->rx.ack_last_ok_sid = tx_sid_complete;
+
+ self->tx.credits = tx_credits;
+ self->tx.sid_next_to_use = tx_sid_complete +1U;
+ self->tx.sid_last_completed = tx_sid_complete;
+
+ self->tx.failure_status = 0U;
+ self->tx.failure_sid = 0U;
+
+ self->tx.current_sid = tx_sid_complete;
+ self->tx.current_type = PMP_STATUS_TYPE_FLOW;
+ self->tx.current_code = (uint8_t)PMP_STATUS_CODE_SUCCESS;
+}
+
+/*! \brief Adds an observer of synchronization state changes
+ * \param self The instance
+ * \param obs_ptr The observer. The notification result type is \ref Pmp_FifoId_t.
+ */
+void Fifo_AddStateObserver(CPmFifo *self, CObserver *obs_ptr)
+{
+ (void)Sub_AddObserver(&self->sync_state_subject, obs_ptr);
+}
+
+/*! \brief Removes an observer of synchronization state changes
+ * \param self The instance
+ * \param obs_ptr The observer.
+ */
+void Fifo_RemoveStateObserver(CPmFifo *self, CObserver *obs_ptr)
+{
+ (void)Sub_RemoveObserver(&self->sync_state_subject, obs_ptr);
+}
+
+/*! \brief Stops execution of a FIFO and notifies sync lost if necessary
+ * \param self The instance
+ * \param new_state The new synchronization state
+ * \param allow_notification Set to \c false in order to avoid recursion
+ */
+void Fifo_Stop(CPmFifo *self, Fifo_SyncState_t new_state, bool allow_notification)
+{
+ bool notify = false;
+
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_Stop(): FIFO: %u, state: %u, new_state: %u", 3U, self->config.fifo_id, self->sync_state, new_state));
+
+ if (self->sync_state != new_state)
+ {
+ notify = true;
+ }
+
+ self->sync_state = new_state;
+ self->tx.credits = 0U;
+
+ if (self->wd.timer_value != 0U)
+ {
+ Tm_ClearTimer(&self->init.base_ptr->tm, &self->wd.timer);
+ }
+
+ if ((notify != false) && (allow_notification != false))
+ {
+ Sub_Notify(&self->sync_state_subject, &self->config.fifo_id);
+ }
+}
+
+/*! \brief Releases all external references
+ * \details It is important to call Fifo_Stop() prior to this functions. The low-level driver
+ * must be stopped as well to avoid concurrent access to message objects.
+ * \param self The instance
+ */
+void Fifo_Cleanup(CPmFifo *self)
+{
+ CMessage *msg_ptr = NULL;
+ CDlNode *node_ptr = NULL;
+
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (self->sync_state == FIFO_S_UNSYNCED_INIT));
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_Cleanup(): FIFO: %u", 1U, self->config.fifo_id));
+
+ /* cleanup pending queue */
+ for (node_ptr = Dl_PopHead(&self->tx.pending_q); node_ptr != NULL; node_ptr = Dl_PopHead(&self->tx.pending_q))
+ {
+ msg_ptr = (CMessage*)Dln_GetData(node_ptr);
+
+ Msg_NotifyTxStatus(msg_ptr, MNS_MSG_STAT_ERROR_SYNC);
+ Lldp_ReturnTxToPool(&self->tx.lld_pool, (Lld_IntTxMsg_t*)Msg_GetLldHandle(msg_ptr));
+ Msg_SetLldHandle(msg_ptr, NULL); /* remove link to LLD message object */
+ }
+
+ /* cleanup waiting queue */
+ for (node_ptr = Dl_PopHead(&self->tx.waiting_queue); node_ptr != NULL; node_ptr = Dl_PopHead(&self->tx.waiting_queue))
+ {
+ msg_ptr = (CMessage*)Dln_GetData(node_ptr);
+
+ Msg_NotifyTxStatus(msg_ptr, MNS_MSG_STAT_ERROR_SYNC);
+ }
+
+ /* cleanup Rx queue */
+ for (node_ptr = Dl_PopHead(&self->rx.queue); node_ptr != NULL; node_ptr = Dl_PopHead(&self->rx.queue))
+ {
+ msg_ptr = (CMessage*)Dln_GetData(node_ptr);
+
+ Pmch_ReturnRxToPool(self->init.channel_ptr, msg_ptr);
+ }
+
+ Srv_ClearEvent(&self->service, FIFO_SE_ALL);
+}
+
+
+/*! \brief Service function of FIFO
+ * \details The processing order of Rx followed by Tx is important for Fifo_RxProcessCommand()
+ * \param self The instance
+ */
+static void Fifo_Service(void *self)
+{
+ CPmFifo *self_ = (CPmFifo*)self;
+ Srv_Event_t event_mask;
+
+ Srv_GetEvent(&self_->service, &event_mask);
+
+ if(FIFO_SE_RX_SERVICE == (event_mask & FIFO_SE_RX_SERVICE)) /* Is event pending? */
+ {
+ Srv_ClearEvent(&self_->service, FIFO_SE_RX_SERVICE);
+ Fifo_RxService(self_);
+ }
+
+ if(FIFO_SE_TX_APPLY_STATUS == (event_mask & FIFO_SE_TX_APPLY_STATUS))
+ {
+ Srv_ClearEvent(&self_->service, FIFO_SE_TX_APPLY_STATUS);
+ Fifo_TxApplyCurrentStatus(self_);
+ }
+
+ if(FIFO_SE_TX_SERVICE == (event_mask & FIFO_SE_TX_SERVICE)) /* Is event pending? */
+ {
+ Srv_ClearEvent(&self_->service, FIFO_SE_TX_SERVICE);
+ Fifo_TxService(self_);
+ }
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Tx Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Enqueues a message for transmission
+ * \param self The instance
+ * \param msg_ptr The Tx message object
+ * \param bypass Use \c true if the message shall bypass all other messages
+ * in the FIFO. Otherwise \c false.
+ */
+void Fifo_Tx(CPmFifo *self, CMessage *msg_ptr, bool bypass)
+{
+ uint8_t *msg_hdr_ptr = NULL;
+
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (msg_ptr != NULL));
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_Tx(): FIFO: %u, msg_ptr: 0x%p, FuncId: 0x%X, queued Tx message", 3U, self->config.fifo_id, msg_ptr, msg_ptr->pb_msg.id.function_id));
+
+ Msg_PullHeader(msg_ptr, self->tx.encoder_ptr->msg_hdr_sz);
+ msg_hdr_ptr = Msg_GetHeader(msg_ptr);
+ self->tx.encoder_ptr->encode_fptr(Msg_GetMostTel(msg_ptr), msg_hdr_ptr);
+
+ if (bypass == false)
+ {
+ Dl_InsertTail(&self->tx.waiting_queue, Msg_GetNode(msg_ptr)); /* enqueue message for asynchronous transmission */
+ }
+ else
+ {
+ Fifo_TxEnqueueBypassMsg(self, &self->tx.waiting_queue, msg_ptr); /* queue before first non-bypass message */
+ }
+
+ Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
+}
+
+/*! \brief Enqueues a bypass message between the last bypass and the first regular message in a queue
+ * \param self The instance
+ * \param q_ptr The message queue
+ * \param msg_ptr The Tx message object
+ */
+static void Fifo_TxEnqueueBypassMsg(CPmFifo *self, CDlList *q_ptr, CMessage *msg_ptr)
+{
+ CDlNode *node_ptr = Dl_Foreach(q_ptr, &Fifo_FindFirstRegularMsg, NULL); /* find first "non-bypass" message */
+ Msg_SetTxBypass(msg_ptr, true); /* mark new message as bypass message */
+
+ if (node_ptr == NULL) /* no message or only bypass messages found */
+ {
+ Dl_InsertTail(&self->tx.waiting_queue, Msg_GetNode(msg_ptr)); /* enqueue message to tail */
+ }
+ else /* first "non-bypass" message is found */
+ { /* insert the bypass message before the first regular message found */
+ Dl_InsertBefore(&self->tx.waiting_queue, node_ptr, Msg_GetNode(msg_ptr));
+ }
+}
+
+/*! \brief Required as "for-each" function to find the first "regular message"
+ * \param d_ptr Points to a message object in the queue
+ * \param ud_ptr Unused data reference, always \c NULL
+ * \return Returns \c true if a regular (non-bypass) message is found.
+ */
+static bool Fifo_FindFirstRegularMsg(void *d_ptr, void *ud_ptr)
+{
+ bool ret = true;
+ MISC_UNUSED(ud_ptr);
+
+ if (Msg_IsTxBypass((CMessage*)d_ptr))
+ {
+ ret = false;
+ }
+
+ return ret;
+}
+
+/*! \brief Processing of data, status and command messages
+ * \param self The instance
+ */
+static void Fifo_TxService(CPmFifo *self)
+{
+ Fifo_TxProcessCommand(self);
+ Fifo_TxProcessStatus(self);
+ Fifo_TxProcessData(self);
+}
+
+/*! \brief Processing of status messages
+ * \param self The instance
+ */
+static void Fifo_TxProcessStatus(CPmFifo *self)
+{
+ if (Pmcmd_IsTriggered(&self->rx.status) != false)
+ {
+ if (Pmcmd_Reserve(&self->rx.status) != false)
+ {
+ Pmcmd_SetTrigger(&self->rx.status, false);
+ self->rx.ack_last_ok_sid = (self->rx.expected_sid - self->rx.busy_num) - 1U;
+ self->rx.wait_processing = false;
+
+ if (self->rx.busy_num == 0U) /* currently no processing of data messages active */
+ { /* notify the latest with SUCCESS */
+ Pmcmd_UpdateContent(&self->rx.status, self->rx.expected_sid - 1U, PMP_STATUS_TYPE_FLOW, PMP_STATUS_CODE_SUCCESS);
+ }
+ else /* message processing is active */
+ { /* notify code busy according to remaining credits */
+ Pmcmd_UpdateContent(&self->rx.status, self->rx.expected_sid - self->rx.busy_num, PMP_STATUS_TYPE_FLOW, PMP_STATUS_CODE_BUSY);
+ }
+
+ Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->rx.status));
+ }
+ }
+}
+
+/*! \brief Processing of queued data messages
+ * \param self The instance
+ */
+static void Fifo_TxProcessData(CPmFifo *self)
+{
+ /* process all queued messages as long as credits are available,
+ * process all queued messages if FIFO is not synced
+ */
+ while ((self->tx.cancel_all_running == false) && (self->tx.credits > 0U))
+ {
+ CMessage *msg_ptr = NULL;
+ CDlNode *node_ptr = NULL;
+ uint8_t *msg_hdr_ptr = NULL;
+ Lld_IntTxMsg_t *lld_tx_ptr = NULL;
+
+ node_ptr = Dl_PopHead(&self->tx.waiting_queue); /* get message node */
+ if (NULL == node_ptr)
+ {
+ msg_ptr = NULL; /* stop processing - no further messages in queue */
+ break;
+ }
+
+ msg_ptr = (CMessage*)Dln_GetData(node_ptr); /* get message object */
+
+ if (self->sync_state != FIFO_S_SYNCED)
+ {
+ Msg_NotifyTxStatus(msg_ptr, MNS_MSG_STAT_ERROR_SYNC); /* notify sync error while not synced */
+ }
+ else
+ {
+ lld_tx_ptr = Lldp_GetTxFromPool(&self->tx.lld_pool);
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (msg_ptr != NULL));
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (lld_tx_ptr != NULL));
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxProcessData(): FIFO: %u, msg_ptr: 0x%p, FuncId: 0x%X, SID: 0x%02X, queued Tx message", 4U, self->config.fifo_id, msg_ptr, msg_ptr->pb_msg.id.function_id, self->tx.sid_next_to_use));
+
+ Msg_SetLldHandle(msg_ptr, lld_tx_ptr); /* link message objects */
+ lld_tx_ptr->msg_ptr = msg_ptr;
+
+ Msg_PullHeader(msg_ptr, self->tx.encoder_ptr->pm_hdr_sz); /* get PM header pointer */
+ msg_hdr_ptr = Msg_GetHeader(msg_ptr);
+
+ {
+ uint8_t tel_length = Msg_GetMostTel(msg_ptr)->tel.tel_len;
+ self->tx.pm_header.pml = (Msg_GetHeaderSize(msg_ptr) + tel_length) - 2U;
+ }
+
+ self->tx.pm_header.sid = self->tx.sid_next_to_use; /* assign SeqID */
+ self->tx.sid_next_to_use++;
+
+ Pmh_BuildHeader(&self->tx.pm_header, msg_hdr_ptr); /* build PM header */
+ lld_tx_ptr->lld_msg.memory_ptr = Msg_GetMemTx(msg_ptr);
+
+ Msg_SetTxActive(msg_ptr, true);
+ Dl_InsertTail(&self->tx.pending_q, Msg_GetNode(msg_ptr));
+
+ Pmch_Transmit(self->init.channel_ptr, (Mns_Lld_TxMsg_t*)(void*)lld_tx_ptr);
+
+ self->tx.credits--;
+ }
+ }
+}
+
+/*! \brief Processing of status messages
+ * \param self The instance
+ */
+static void Fifo_TxProcessCommand(CPmFifo *self)
+{
+ if (Pmcmd_IsTriggered(&self->tx.sync_cmd) != false)
+ {
+ if (Pmcmd_Reserve(&self->tx.sync_cmd) != false)
+ {
+ Pmcmd_SetTrigger(&self->tx.sync_cmd, false);
+
+ if (self->sync_state == FIFO_S_SYNCING)
+ {
+ self->sync_cnt++;
+ Pmcmd_SetContent(&self->tx.sync_cmd, self->sync_cnt, PMP_CMD_TYPE_SYNCHRONIZATION, PMP_CMD_CODE_SYNC, self->sync_params, 4U);
+ Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->tx.sync_cmd));
+ }
+ else if (self->sync_state == FIFO_S_UNSYNCING)
+ {
+ Pmcmd_SetContent(&self->tx.sync_cmd, 0U, PMP_CMD_TYPE_SYNCHRONIZATION, PMP_CMD_CODE_UNSYNC, NULL, 0U);
+ Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->tx.sync_cmd));
+ }
+ else
+ {
+ Pmcmd_Release(&self->tx.sync_cmd);
+ TR_FAILED_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]");
+ }
+ }
+ else
+ {
+ TR_FAILED_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]");
+ }
+ }
+}
+
+/*! \brief Releases a LLD Tx message object
+ * \param self The instance
+ * \param handle_ptr The unused LLD Tx message object
+ * \details If Fifo_TxApplyStatus() is waiting for a message object
+ * being released
+ */
+void Fifo_TxOnRelease(void *self, Mns_Lld_TxMsg_t *handle_ptr)
+{
+ CPmFifo *self_ = (CPmFifo*)self;
+ Lld_IntTxMsg_t *tx_ptr = (Lld_IntTxMsg_t*)(void*)handle_ptr;
+
+ if (tx_ptr->msg_ptr != NULL)
+ {
+ Msg_SetTxActive(tx_ptr->msg_ptr, false);
+ }
+ else
+ {
+ TR_FAILED_ASSERT(self_->init.base_ptr->mns_inst_id, "[FIFO]");
+ }
+
+ if (self_->tx.status_waiting_release != false)
+ {
+ self_->tx.status_waiting_release = false;
+ Srv_SetEvent(&self_->service, (FIFO_SE_TX_APPLY_STATUS | FIFO_SE_TX_SERVICE));
+ }
+}
+
+/*! \brief Triggers a command CANCEL_ALL and stops further Tx processing
+ * \details CANCEL_ALL shall be called only, if the front-most pending message
+ * has followers (is segmented, i.e. \c cancel_id > 0). Use command CANCEL
+ * if the front-most message has no followers (\c cancel_id == NULL).
+ * \param self The instance
+ * \param failure_sid The failure sid
+ * \param failure_code The failure code reported by the INIC
+ */
+static void Fifo_TxExecuteCancelAll(CPmFifo *self, uint8_t failure_sid, uint8_t failure_code)
+{
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxExecuteCancelAll(): FIFO: %u, SID: %u, Code: %u", 3U, self->config.fifo_id, failure_sid, failure_code));
+
+ if (Pmcmd_Reserve(&self->tx.cancel_cmd) != false) /* prepare cancel command */
+ {
+ Pmcmd_UpdateContent(&self->tx.cancel_cmd, self->tx.current_sid,
+ PMP_CMD_TYPE_MSG_ACTION, PMP_CMD_CODE_ACTION_CANCEL_ALL);
+ Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->tx.cancel_cmd));
+ }
+ else
+ {
+ TR_FAILED_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]"); /* Unable to reserve cancel command */
+ }
+
+ self->tx.cancel_all_running = true;
+ self->tx.failure_sid = failure_sid;
+ self->tx.failure_status = failure_code;
+}
+
+/*! \brief Shall be called if the command CANCEL_ALL was processed completely
+ * \param self The instance
+ * \details Since the CANCEL_ALL is used to cancel the front-most message and
+ * all of its followers (same cancel_id)
+
+ for mid-level retries, the canceled messages
+ * are moved from the processing_q to the waiting_q again. The MLR timer is
+ * started. As soon as the timer elapses, Tx processing is continued again.
+ * If the front-most message has a follower id, all pending messages are
+ * moved to the waiting queue and all messages with the same follower id
+ * are notified as failed.
+ */
+static void Fifo_TxFinishedCancelAll(CPmFifo *self)
+{
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxFinishedCancelAll(): FIFO: %u, FailureStatus: %u,", 2U, self->config.fifo_id, self->tx.failure_status));
+
+ if (self->tx.failure_status != 0U) /* avoid multiple execution of the same CANCELED status */
+ { /* and all of its followers */
+ uint8_t follower_id = Fifo_TxPendingGetFollowerId(self);
+ Fifo_TxRestorePending(self); /* move remaining messages to waiting_q */
+ Fifo_TxCancelFollowers(self, follower_id, (Mns_MsgTxStatus_t)self->tx.failure_status);
+ /* notify front-most and message and all of its followers */
+ self->tx.cancel_all_running = false; /* continue with Tx processing */
+ self->tx.failure_sid = 0U;
+ self->tx.failure_status = 0U;
+ Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
+ }
+}
+
+/*! \brief Triggers a command CANCEL while Tx processing continues
+ * \param self The instance
+ * \param failure_sid The failure sid
+ * \param failure_code The failure code reported by the INIC
+ */
+static void Fifo_TxExecuteCancel(CPmFifo *self, uint8_t failure_sid, uint8_t failure_code)
+{
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxExecuteCancel(): FIFO: %u, SID: %u, Code: %u", 3U, self->config.fifo_id, failure_sid, failure_code));
+
+ if (Pmcmd_Reserve(&self->tx.cancel_cmd) != false)
+ {
+ Pmcmd_UpdateContent(&self->tx.cancel_cmd, self->tx.current_sid,
+ PMP_CMD_TYPE_MSG_ACTION, PMP_CMD_CODE_ACTION_CANCEL);
+ Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->tx.cancel_cmd));
+ }
+ else
+ {
+ TR_FAILED_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]"); /* Unable to reserve cancel command */
+ }
+
+ self->tx.cancel_all_running = false;
+ self->tx.failure_sid = failure_sid;
+ self->tx.failure_status = failure_code;
+}
+
+/*! \brief Checks if the LLD has released all messages in the pending_q
+ * \param self The instance
+ * \return Returns \c true if all messages are released by the LLD, otherwise \c false.
+ */
+static bool Fifo_TxHasAccessPending(CPmFifo *self)
+{
+ bool ret = true;
+ CDlNode *node_ptr = Dl_PeekTail(&self->tx.pending_q); /* if the tail is not active, then all */
+ /* pending message are not active */
+ if (node_ptr != NULL)
+ {
+ CMessage *msg_ptr = (CMessage*)Dln_GetData(node_ptr);
+
+ if (Msg_IsTxActive(msg_ptr) != false)
+ {
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxHasAccessPending(): FIFO: %u, msg_ptr: 0x%p, still in use", 2U, self->config.fifo_id, msg_ptr));
+ self->tx.status_waiting_release = true;
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+/*! \brief Moves all pending messages to the waiting_q
+ * \details All messages from pending_q will be moved to the waiting_g and
+ * all consumed credits are restored. The message objects are restored
+ * to the queue in the same order as they have been forwarded to the LLD.
+ * This method is typically called to restore the waiting_q in the correct
+ * order before notifying a
+ * \param self The instance
+ */
+static void Fifo_TxRestorePending(CPmFifo *self)
+{
+ /* take tail from pending_q to the head of waiting_q */
+ CMessage *msg_ptr = NULL;
+ CDlNode *node_ptr = NULL;
+
+ /* cleanup pending queue */
+ for (node_ptr = Dl_PopTail(&self->tx.pending_q); node_ptr != NULL; node_ptr = Dl_PopTail(&self->tx.pending_q))
+ {
+ msg_ptr = (CMessage*)Dln_GetData(node_ptr);
+
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxRestorePending(): FIFO: %u, msg_ptr: 0x%p", 2U, self->config.fifo_id, msg_ptr));
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (Msg_IsTxActive(msg_ptr) == false));
+
+ self->tx.sid_last_completed++;
+ self->tx.credits++;
+ Lldp_ReturnTxToPool(&self->tx.lld_pool, (Lld_IntTxMsg_t*)Msg_GetLldHandle(msg_ptr));
+ Msg_SetLldHandle(msg_ptr, NULL); /* remove link to LLD message object */
+ Msg_PushHeader(msg_ptr, self->tx.encoder_ptr->pm_hdr_sz); /* set index to position of message header */
+ Dl_InsertHead(&self->tx.waiting_queue, node_ptr); /* enqueue message to waiting_q */
+ }
+}
+
+/*! \brief Retrieves the follower id of the front-most pending message
+ * \param self The instance
+ * \return Returns the follower id of the front-most pending message.
+ */
+static uint8_t Fifo_TxPendingGetFollowerId(CPmFifo *self)
+{
+ CDlNode *node_ptr;
+ CMessage *tx_ptr;
+ uint8_t ret = 0U;
+
+ node_ptr = Dl_PeekHead(&self->tx.pending_q);
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (node_ptr != NULL));
+
+ if (node_ptr != NULL)
+ {
+ tx_ptr = (CMessage*)Dln_GetData(node_ptr);
+ ret = tx_ptr->pb_msg.opts.cancel_id;
+ }
+
+ return ret;
+}
+
+/*! \brief Aborts the transmission of all messages in the waiting_q with a given follower id
+ * \param self The instance
+ * \param follower_id The follower id a message needs to have to be canceled
+ * \param status The transmission status that shall be notified
+ */
+static void Fifo_TxCancelFollowers(CPmFifo *self, uint8_t follower_id, Mns_MsgTxStatus_t status)
+{
+ CDlNode *node_ptr;
+ CDlList temp_queue;
+
+ Dl_Ctor(&temp_queue, self->init.base_ptr->mns_inst_id);
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxCancelFollowers(): FIFO: %u: FollowerId: %u", 2U, self->config.fifo_id, follower_id));
+
+ for (node_ptr = Dl_PopHead(&self->tx.waiting_queue); node_ptr != NULL; node_ptr = Dl_PopHead(&self->tx.waiting_queue))
+ {
+ CMessage *tx_ptr = (CMessage*)Dln_GetData(node_ptr);
+
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (Msg_GetLldHandle(tx_ptr) == NULL));
+
+ if (tx_ptr->pb_msg.opts.cancel_id == follower_id)
+ {
+ Msg_NotifyTxStatus(tx_ptr, status); /* notify failed transmission of message and all followers */
+ }
+ else
+ {
+ Dl_InsertTail(&temp_queue, node_ptr); /* add to temporary queue and keep order of messages */
+ }
+ }
+
+ if (Dl_GetSize(&temp_queue) > 0U) /* restore temp_queue to waiting_q */
+ {
+ Dl_AppendList(&self->tx.waiting_queue, &temp_queue);/* temp_queue will be empty now */
+ }
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Tx Message Processing */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Retrieves the number of (implicit) acknowledges that are related to one SID
+ * \param self The instance
+ * \param sid The sequence ID
+ * \return The number of implicit acknowledges that are related to the SID
+ */
+static uint8_t Fifo_TxGetValidAcknowledges(CPmFifo *self, uint8_t sid)
+{
+ uint8_t diff_s = (uint8_t)(sid - self->tx.sid_last_completed); /* number of implicit acknowledged data */
+ uint8_t diff_b = (uint8_t)(self->tx.sid_next_to_use - self->tx.sid_last_completed); /* number of "sent but un-acknowledged data" + 1 */
+
+ if (diff_b <= diff_s) /* check valid acknowledges */
+ {
+ diff_s = 0U;
+ }
+
+ return diff_s;
+}
+
+
+/*! \brief Checks id an incoming SID of a status message is valid.
+ * \param self The instance
+ * \param sid The sequence ID
+ * \return Returns \c true if the SID is valid, otherwise \c false.
+ */
+static bool Fifo_TxIsIncomingSidValid(CPmFifo *self, uint8_t sid)
+{
+ bool ret = false;
+ uint8_t diff_s = (uint8_t)(sid - self->tx.sid_last_completed); /* number of implicit acknowledged data */
+ uint8_t diff_b = (uint8_t)(self->tx.sid_next_to_use - self->tx.sid_last_completed); /* number of "sent but un-acknowledged data" + 1 */
+ uint8_t diff_p = (uint8_t)(self->tx.current_sid - self->tx.sid_last_completed); /* pending/known acknowledges */
+
+ if (diff_b > diff_s) /* check if SID fits in valid range */
+ {
+ if (diff_s >= diff_p) /* avoid overwriting with smaller values */
+ {
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
+/*! \brief Implicitly notifies transmission status to calling classes
+ * \param self The instance
+ * \param sid The sequence ID until the status shall be notified
+ * \param status The status which is notified
+ * \return Returns \c true if all desired messages had been notified,
+ * otherwise \c false.
+ */
+static bool Fifo_TxNotifyStatus(CPmFifo *self, uint8_t sid, Mns_MsgTxStatus_t status)
+{
+ bool ret = true;
+ uint8_t acks = Fifo_TxGetValidAcknowledges(self, sid);
+
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxNotifyStatus(): FIFO: %u, calculated_acks: %u", 2U, self->config.fifo_id, acks));
+
+ while (acks > 0U)
+ {
+ CDlNode *node_ptr = Dl_PopHead(&self->tx.pending_q);
+
+ if (node_ptr != NULL)
+ {
+ CMessage *tx_ptr = (CMessage*)node_ptr->data_ptr;
+
+ if (!Msg_IsTxActive(tx_ptr))
+ {
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (tx_ptr != NULL));
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxNotifyStatus(): FIFO: %u, FuncId: 0x%X, notified status: %u", 3U, self->config.fifo_id, tx_ptr->pb_msg.id.function_id, status));
+ Msg_NotifyTxStatus(tx_ptr, status);
+ Lldp_ReturnTxToPool(&self->tx.lld_pool, (Lld_IntTxMsg_t*)Msg_GetLldHandle(tx_ptr));
+ Msg_SetLldHandle(tx_ptr, NULL); /* remove link to LLD message object */
+
+ self->tx.credits++; /* increment credits */
+ self->tx.sid_last_completed++; /* update last acknowledge SID */
+ }
+ else
+ {
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxNotifyStatus(): FIFO: %u, LLD objects still occupied", 1U, self->config.fifo_id));
+ Dl_InsertHead(&self->tx.pending_q, node_ptr);
+ self->tx.status_waiting_release = true;
+ ret = false;
+ break;
+ }
+ }
+ else
+ {
+ TR_FAILED_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]"); /* not yet handled */
+ /* trigger sync again */
+ }
+
+ acks--;
+ }
+
+ return ret;
+}
+
+/*! \brief Updates the current Tx status with the content of a received FIFO status
+ * \param self The instance
+ * \param sid The sequence id of the FIFO status
+ * \param type The type of the FIFO status. Valid types are only:
+ * - PMP_STATUS_TYPE_FLOW
+ * - PMP_STATUS_TYPE_FAILURE
+ * \param code The code of the FIFO status
+ */
+static void Fifo_TxUpdateCurrentStatus(CPmFifo *self, uint8_t sid, uint8_t type, uint8_t code)
+{
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (type == (uint8_t)PMP_STATUS_TYPE_FAILURE) || (type == (uint8_t)PMP_STATUS_TYPE_FLOW));
+ if (Fifo_TxIsIncomingSidValid(self, sid)) /* is new or updating status */
+ {
+ self->tx.current_sid = sid; /* update current status */
+ self->tx.current_type = (Pmp_StatusType_t)type;
+ self->tx.current_code = code;
+ }
+ else
+ {
+ TR_ERROR((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxUpdateCurrentStatus(): FIFO: %u, sid: %u, type: %u, code: %u, INVALID SID", 4U, self->config.fifo_id, sid, type, code));
+ }
+}
+
+/*! \brief Analyses the current Tx status, tries to notify statuses to the transmitter and triggers
+ * retry/cancel actions.
+ * \param self The instance
+ */
+static void Fifo_TxApplyCurrentStatus(CPmFifo *self)
+{
+ if ((self->tx.cancel_all_running == false) && (self->tx.failure_status != 0U)) /* Command(CANCEL) is pending */
+ {
+ if (Fifo_TxGetValidAcknowledges(self, self->tx.current_sid) > 1U) /* ?>=1? "single cancel" is valid and implicit */
+ {
+ if (Fifo_TxNotifyStatus(self, self->tx.failure_sid, (Mns_MsgTxStatus_t)self->tx.failure_status))
+ {
+ self->tx.failure_status = 0U; /* implicit canceled stops retries */
+ self->tx.failure_sid = 0U;
+ }
+ }
+ }
+
+ if ((self->tx.current_type == PMP_STATUS_TYPE_FAILURE) && (self->tx.status_waiting_release == false))
+ {
+ if (self->tx.cancel_all_running == false)
+ {
+ if (Fifo_TxNotifyStatus(self, self->tx.current_sid - 1U, MNS_MSG_STAT_OK) != false)
+ {
+ /* important: failed message now is front-most message in the tx.pending_q, */
+ /* any implicit acknowledge was done before */
+ if (self->tx.failure_status == 0U) /* failure not yet handled - avoid multiple calls */
+ {
+ if (Fifo_TxPendingGetFollowerId(self) == 0U)
+ {
+ Fifo_TxExecuteCancel(self, self->tx.current_sid, self->tx.current_code); /* execute simple cancel */
+ }
+ else
+ {
+ Fifo_TxExecuteCancelAll(self, self->tx.current_sid, self->tx.current_code); /* execute cancel all */
+ /* self->tx.cancel_all_running now is 'true' and Tx is stopped */
+ }
+ }
+ }
+ }
+ }
+
+ if ((self->tx.current_type == PMP_STATUS_TYPE_FLOW) && (self->tx.status_waiting_release == false))
+ {
+ if ((uint8_t)PMP_STATUS_CODE_SUCCESS == self->tx.current_code) /* acknowledge pending messages */
+ {
+ /* no further retries possible */
+ (void)Fifo_TxNotifyStatus(self, self->tx.current_sid, MNS_MSG_STAT_OK);
+ }
+ else if ((uint8_t)PMP_STATUS_CODE_CANCELED == self->tx.current_code)
+ {
+ if (self->tx.cancel_all_running != false)
+ {
+ /* wait until the last SID is notified */
+ if (self->tx.current_sid == (uint8_t)(self->tx.sid_next_to_use - (uint8_t)1U))
+ {
+ /* cancel done if none of pending messages is active */
+ if (Fifo_TxHasAccessPending(self) != false)
+ {
+ Fifo_TxFinishedCancelAll(self);
+ }
+ }
+ }
+ else if (Fifo_TxNotifyStatus(self, self->tx.current_sid, (Mns_MsgTxStatus_t)self->tx.failure_status))
+ {
+ self->tx.failure_status = 0U;
+ self->tx.failure_sid = 0U;
+ }
+ }
+ else
+ {
+ if (Fifo_TxNotifyStatus(self, self->tx.current_sid - 1U, MNS_MSG_STAT_OK)) /* just implicitly acknowledge preceding message */
+ {
+ if ((uint8_t)PMP_STATUS_CODE_NACK == self->tx.current_code)
+ {
+ Fifo_Stop(self, FIFO_S_UNSYNCED_INIT, true);
+ TR_FAILED_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]");
+ }
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Rx Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Receives a message on the respective FIFO
+ * \param self The instance
+ * \param msg_ptr Reference to the Rx message
+ */
+static void Fifo_OnRx(void *self, CMessage *msg_ptr)
+{
+ CPmFifo *self_ = (CPmFifo*)self;
+ Dl_InsertTail(&self_->rx.queue, Msg_GetNode(msg_ptr)); /* enqueue in rx_queue */
+ Srv_SetEvent(&self_->service, (FIFO_SE_RX_SERVICE | FIFO_SE_TX_APPLY_STATUS | FIFO_SE_TX_SERVICE));
+}
+
+/*! \brief Processes the Rx queue completely and triggers possible Tx events
+ * \param self The instance
+ */
+static void Fifo_RxService(CPmFifo *self)
+{
+ while (false == self->rx.wait_processing) /* process all Rx messages if possible */
+ {
+ CMessage *msg_ptr;
+ uint8_t *header_ptr;
+ Pmp_MsgType_t type;
+ bool ok;
+
+ bool free_msg = true; /* default: free every status or command message */
+ CDlNode *node_ptr = Dl_PopHead(&self->rx.queue);
+
+ if (NULL == node_ptr)
+ {
+ msg_ptr = NULL; /* stop processing - no further messages in queue */
+ break;
+ }
+
+ msg_ptr = (CMessage*)node_ptr->data_ptr;
+ header_ptr = Msg_GetHeader(msg_ptr);
+ type = Pmp_GetMsgType(header_ptr);
+ ok = Pmp_VerifyHeader(header_ptr, MSG_SIZE_RSVD_BUFFER);
+
+ if (ok != false)
+ {
+ switch (type)
+ {
+ case PMP_MSG_TYPE_CMD:
+ Fifo_RxProcessCommand(self, msg_ptr);
+ break;
+ case PMP_MSG_TYPE_STATUS:
+ Fifo_RxProcessStatus(self, msg_ptr);
+ break;
+ case PMP_MSG_TYPE_DATA:
+ free_msg = Fifo_RxProcessData(self, msg_ptr); /* important: message can be freed */
+ break; /* synchronously */
+ default:
+ TR_FAILED_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]"); /* unknown FIFO message type */
+ break;
+ }
+ }
+ else
+ {
+ TR_FAILED_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]"); /* invalid message header */
+ }
+
+ if (free_msg != false)
+ {
+ Pmch_ReturnRxToPool(self->init.channel_ptr, msg_ptr);
+ }
+ }
+}
+
+/*! \brief Evaluates the trigger condition to transmit a Rx status
+ * \details Needs to be called before and after processing Rx data messages
+ * \param self The instance
+ */
+static void Fifo_RxCheckStatusTrigger(CPmFifo *self)
+{
+ /* calculate the number of credits the INIC has consumed */
+ /* if less messages are processing, the freed can be acknowledged */
+ uint8_t consumed_inic_credits = (self->rx.expected_sid - self->rx.ack_last_ok_sid) - 1U;
+ uint8_t possible_acks = consumed_inic_credits - self->rx.busy_num;
+
+ if ((consumed_inic_credits >= self->rx.ack_threshold) && (possible_acks > 0U))
+ {
+ if (Pmcmd_IsTriggered(&self->rx.status) == false)
+ {
+ Pmcmd_SetTrigger(&self->rx.status, true); /* INIC might run out of credits */
+ Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
+ }
+ }
+}
+
+/*! \brief This function shall be called before processing a valid FIFO data message
+ * \param self The instance
+ */
+static void Fifo_RxGetCredit(CPmFifo *self)
+{
+ self->rx.busy_num++;
+ Fifo_RxCheckStatusTrigger(self);
+}
+
+/*! \brief This function shall be called after processing a valid FIFO data message
+ * \details It is important to call this function after the message object is freed,
+ * so that the flow control can be updated.
+ * \param self The instance
+ */
+static void Fifo_RxReleaseCredit(CPmFifo *self)
+{
+ self->rx.busy_num--;
+ Fifo_RxCheckStatusTrigger(self);
+}
+
+/*! \brief Releases a FIFO data message which was received and forwarded by the FIFO
+ * \details The function returns the message to the channel's Rx message pool and
+ * has to update the number of credits (processing handles).
+ * A FIFO data message is initially allocated from the channel's Rx message pool.
+ * When processing the handle the determined FIFO need to calculate the amount of
+ * credits. When freeing the message the handle needs to be returned to the channel's
+ * Rx pool again and the FIFO needs to refresh the status and credits calculation.
+ * Therefore the message has to be freed to the respective FIFO again.
+ * \param self The instance
+ * \param msg_ptr The Rx data message
+ */
+void Fifo_RxReleaseMsg(CPmFifo *self, CMessage *msg_ptr)
+{
+ Pmch_ReturnRxToPool(self->init.channel_ptr, msg_ptr);
+ Fifo_RxReleaseCredit(self);
+}
+
+/*! \brief Processes an Rx data message
+ * \param self The instance
+ * \param msg_ptr The Rx data message
+ * \return \c true if the message object is no longer needed.
+ * Otherwise \c false.
+ */
+static bool Fifo_RxProcessData(CPmFifo *self, CMessage *msg_ptr)
+{
+ bool free_msg = true;
+ uint8_t content_header_sz = 0U;
+ uint8_t sid = 0U;
+ uint8_t *header_ptr = Msg_GetHeader(msg_ptr);
+ sid = Pmp_GetSid(header_ptr);
+
+ if (self->sync_state != FIFO_S_SYNCED)
+ { /* discard Rx messages while FIFO is not synced */
+ TR_ERROR((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_RxProcessData(): FIFO: %u, state: %u, discards Rx message with SID=0x%02X while not synced (warning)", 3U, self->config.fifo_id, self->sync_state, sid));
+ }
+ else if (sid == self->rx.expected_sid) /* check if SID is ok */
+ {
+ uint8_t pm_header_sz = Pmp_GetPmhl(header_ptr) + 3U;
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (pm_header_sz == self->rx.encoder_ptr->pm_hdr_sz));
+
+ self->rx.expected_sid++; /* update SID */
+ content_header_sz = self->rx.encoder_ptr->msg_hdr_sz;
+
+ /* parasoft suppress item MISRA2004-17_4 reason "necessary offset usage" */
+ self->rx.encoder_ptr->decode_fptr(Msg_GetMostTel(msg_ptr), &(header_ptr[pm_header_sz]));
+ /* parasoft unsuppress item MISRA2004-17_4 reason "necessary offset usage" */
+
+ Msg_ReserveHeader(msg_ptr, content_header_sz + pm_header_sz);
+ Msg_PullHeader(msg_ptr, content_header_sz + pm_header_sz);
+
+ if (Msg_VerifyContent(msg_ptr))
+ {
+ if (self->rx.on_complete_fptr != NULL)
+ {
+ (void)Fifo_RxGetCredit(self);
+ free_msg = false; /* callback is responsible to free the message */
+ self->rx.on_complete_fptr(self->rx.on_complete_inst, msg_ptr);
+ /* Fifo_RxReleaseCredit() is called when message is freed */
+ }
+ }
+ }
+ else
+ {
+ TR_ERROR((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_RxProcessData(): FIFO: %u, state: %u, discards Rx message with unexpected SID=0x%02X (warning)", 3U, self->config.fifo_id, self->sync_state, sid));
+ }
+
+ return free_msg;
+}
+
+/*! \brief Processes an Rx status message
+ * \param self The instance
+ * \param msg_ptr The Rx status message
+ */
+static void Fifo_RxProcessStatus(CPmFifo *self, CMessage *msg_ptr)
+{
+ CPmh pm_header;
+ uint8_t current_sid;
+ uint8_t current_type;
+ uint8_t current_code;
+ uint8_t *header_ptr = Msg_GetHeader(msg_ptr);
+
+ Pmh_DecodeHeader(&pm_header, header_ptr);
+ current_sid = pm_header.sid;
+ current_type = (uint8_t)Pmh_GetExtStatusType(&pm_header);
+ current_code = (uint8_t)Pmh_GetExtStatusCode(&pm_header);
+
+ self->wd.request_started = false; /* status finishes a wd request */
+
+ switch ((Pmp_StatusType_t)current_type)
+ {
+ case PMP_STATUS_TYPE_FAILURE:
+ Fifo_TxUpdateCurrentStatus(self, current_sid, current_type, Fifo_RxCheckFailureCode(self, current_code)); /* just update status type FAILURE */
+ break;
+ case PMP_STATUS_TYPE_FLOW:
+ Fifo_TxUpdateCurrentStatus(self, current_sid, current_type, current_code); /* just update status type FLOW (codes: BUSY, NACK, SUCCESS, CANCELED) */
+ break;
+ case PMP_STATUS_TYPE_SYNCED:
+ Fifo_RxProcessSyncStatus(self, current_sid, current_type, current_code, header_ptr);
+ break;
+ case PMP_STATUS_TYPE_UNSYNCED_BSY:
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_RxProcessStatus(): FIFO: %u, state: %u, received UNSYNCED_BSY", 2U, self->config.fifo_id, self->sync_state));
+ if (self->sync_state != FIFO_S_SYNCING)
+ {
+ Fifo_Stop(self, FIFO_S_UNSYNCED_BUSY, true);
+ }
+ break;
+ case PMP_STATUS_TYPE_UNSYNCED_RDY:
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_RxProcessStatus(): FIFO: %u, state: %u, received UNSYNCED_RDY", 2U, self->config.fifo_id, self->sync_state));
+ if (self->sync_state == FIFO_S_SYNCING)
+ {
+ if (current_code == (uint8_t)PMP_UNSYNC_R_COMMAND)
+ {
+ Fifo_Synchronize(self); /* retry synchronization */
+ }
+ }
+ else
+ {
+ Fifo_Stop(self, FIFO_S_UNSYNCED_READY, true);
+ }
+ break;
+ default:
+ /* ignore status */
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_RxProcessStatus(): FIFO: %u, state: %u, received UNKNOWN TYPE: %u", 3U, self->config.fifo_id, self->sync_state, current_type));
+ break;
+ }
+}
+
+/*! \brief Checks failure_code and sets invalid code to MNS_MSG_STAT_ERROR_UNKNOWN
+ * \param self The instance
+ * \param failure_code The INIC failure code
+ * \return Returns the checked failure code
+ */
+static uint8_t Fifo_RxCheckFailureCode(CPmFifo *self, uint8_t failure_code)
+{
+ uint8_t ret;
+ MISC_UNUSED(self);
+
+ switch (failure_code)
+ {
+ case (uint8_t)MNS_MSG_STAT_ERROR_CFG_NO_RCVR:
+ case (uint8_t)MNS_MSG_STAT_ERROR_BF:
+ case (uint8_t)MNS_MSG_STAT_ERROR_CRC:
+ case (uint8_t)MNS_MSG_STAT_ERROR_ID:
+ case (uint8_t)MNS_MSG_STAT_ERROR_ACK:
+ case (uint8_t)MNS_MSG_STAT_ERROR_TIMEOUT:
+ case (uint8_t)MNS_MSG_STAT_ERROR_FATAL_WT:
+ case (uint8_t)MNS_MSG_STAT_ERROR_FATAL_OA:
+ case (uint8_t)MNS_MSG_STAT_ERROR_NA_TRANS:
+ case (uint8_t)MNS_MSG_STAT_ERROR_NA_OFF:
+ ret = failure_code;
+ break;
+ default:
+ ret = (uint8_t)MNS_MSG_STAT_ERROR_UNKNOWN;
+ break;
+ }
+
+ return ret;
+}
+
+/*! \brief Processes an Rx command message
+ * \param self The instance
+ * \param msg_ptr The Rx command message
+ */
+static void Fifo_RxProcessCommand(CPmFifo *self, CMessage *msg_ptr)
+{
+ MISC_UNUSED(msg_ptr);
+ /* be aware that PMHL might vary */
+ Pmcmd_SetTrigger(&self->rx.status, true); /* just trigger latest Rx status now */
+}
+
+/*! \brief Processes a status SYNCED from the INIC
+ * \param self The instance
+ * \param sid The sid of the sync status
+ * \param type The type of the sync status
+ * \param code The code of the sync status
+ * \param header_ptr Pointer to the raw port message
+ * \return The current synchronization state
+ */
+static void Fifo_RxProcessSyncStatus(CPmFifo *self, uint8_t sid, uint8_t type, uint8_t code, uint8_t *header_ptr)
+{
+ bool check = false;
+ uint8_t tx_credits = 0U;
+
+ TR_ASSERT(self->init.base_ptr->mns_inst_id, "[FIFO]", (type==(uint8_t)PMP_STATUS_TYPE_SYNCED));
+ MISC_UNUSED(type);
+ MISC_UNUSED(code);
+
+ if (Pmp_GetDataSize(header_ptr) == 4U)
+ {
+ tx_credits = Pmp_GetData(header_ptr, 0U) & (uint8_t)PMP_CREDITS_MASK;
+
+ if ((tx_credits >= PMP_CREDITS_MIN) &&
+ (Pmp_GetData(header_ptr, 1U) == self->sync_params[1]) &&
+ (Pmp_GetData(header_ptr, 2U) == self->sync_params[2]) &&
+ (Pmp_GetData(header_ptr, 3U) == self->sync_params[3]) &&
+ (sid == (self->sync_cnt)))
+ {
+ check = true; /* the sync status parameters are correct */
+ }
+ }
+
+ if ((check != false) && (self->sync_state == FIFO_S_SYNCING))
+ {
+ Fifo_InitCounters(self, sid, tx_credits); /* values are incremented on each sync attempt */
+ self->sync_state = FIFO_S_SYNCED; /* sync status shall have 4 bytes message body */
+ self->rx.wait_processing = false;
+ Fifo_TxStartWatchdog(self);
+ Sub_Notify(&self->sync_state_subject, &self->config.fifo_id);
+ }
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Synchronization */
+/*------------------------------------------------------------------------------------------------*/
+
+/*! \brief Synchronizes the FIFO
+ * \param self The instance
+ */
+void Fifo_Synchronize(CPmFifo *self)
+{
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_Synchronize(): FIFO: %u, state: %u", 2U, self->config.fifo_id, self->sync_state));
+ self->sync_state = FIFO_S_SYNCING;
+ Pmcmd_SetTrigger(&self->tx.sync_cmd, true);
+ Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
+}
+
+/*! \brief Un-synchronizes the FIFO
+ * \param self The instance
+ */
+void Fifo_Unsynchronize(CPmFifo *self)
+{
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_Unsynchronize(): FIFO: %u, state: %u", 2U, self->config.fifo_id, self->sync_state));
+ if ( (self->sync_state == FIFO_S_SYNCING) || (self->sync_state == FIFO_S_SYNCED) )
+ {
+ self->sync_state = FIFO_S_UNSYNCING;
+ Pmcmd_SetTrigger(&self->tx.sync_cmd, true);
+ Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
+ }
+}
+
+/*! \brief Retrieves the current synchronization state
+ * \param self The instance
+ * \return The current synchronization state
+ */
+Fifo_SyncState_t Fifo_GetState(CPmFifo *self)
+{
+ return self->sync_state;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Watchdog */
+/*------------------------------------------------------------------------------------------------*/
+
+/*! \brief Starts the watchdog handling
+ * \param self The instance
+ */
+static void Fifo_TxStartWatchdog(CPmFifo *self)
+{
+ self->wd.request_started = false;
+
+ TR_INFO((self->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxStartWatchdog(): fifo_id: %u, timeout: %u", 2U, self->config.fifo_id, self->wd.timer_value));
+
+ if (self->wd.timer_value != 0U)
+ {
+ Tm_SetTimer(&self->init.base_ptr->tm, &self->wd.timer, &Fifo_TxOnWatchdogTimer,
+ self,
+ self->wd.timer_value,
+ self->wd.timer_value
+ );
+ }
+}
+
+/*! \brief Callback function which is invoked if the watchdog timer expires
+ * \param self The instance
+ */
+static void Fifo_TxOnWatchdogTimer(void *self)
+{
+ CPmFifo *self_ = (CPmFifo*)self;
+
+ TR_INFO((self_->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxOnWatchdogTimer(): FIFO: %u, state: %u", 2U, self_->config.fifo_id, self_->sync_state));
+
+ if (self_->wd.request_started == false)
+ {
+ if (Pmcmd_Reserve(&self_->wd.wd_cmd) != false)
+ {
+ self_->wd.request_started = true; /* indicate that a status is expected */
+ Pmcmd_UpdateContent(&self_->wd.wd_cmd, self_->tx.sid_next_to_use - 1U, PMP_CMD_TYPE_REQ_STATUS, PMP_CMD_CODE_REQ_STATUS);
+ Pmch_Transmit(self_->init.channel_ptr, Pmcmd_GetLldTxObject(&self_->wd.wd_cmd));
+ }
+ else
+ {
+ TR_ERROR((self_->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxOnWatchdogTimer(): Unable to reserve watchdog command ", 0U));
+ Fifo_Stop(self_, FIFO_S_UNSYNCED_INIT, true);
+ }
+ }
+ else /* status not received in time - notify communication error */
+ {
+ TR_ERROR((self_->init.base_ptr->mns_inst_id, "[FIFO]", "Fifo_TxOnWatchdogTimer(): Missing response on status request", 0U));
+ Fifo_Stop(self_, FIFO_S_UNSYNCED_INIT, true);
+ }
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmfifo.h b/mnsl/mns_pmfifo.h
new file mode 100644
index 0000000..3c9962f
--- /dev/null
+++ b/mnsl/mns_pmfifo.h
@@ -0,0 +1,232 @@
+/*
+ * 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 Port Message FIFO
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PMF
+ * @{
+ */
+
+#ifndef MNS_PMFIFO_H
+#define MNS_PMFIFO_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+#include "mns_base.h"
+#include "mns_lld_pb.h"
+#include "mns_message.h"
+#include "mns_encoder.h"
+#include "mns_pmp.h"
+#include "mns_lldpool.h"
+#include "mns_pmchannel.h"
+#include "mns_pmcmd.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macros */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Number of LLD Tx handles dedicated to each FIFO */
+#define FIFO_TX_HANDLES 5U
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Callback function which is invoked when receiving an Rx message
+ * \param self The Instance (of the host)
+ * \param msg_ptr The Rx message
+ */
+typedef void (*Fifo_OnRxMsg_t)(void *self, CMessage *msg_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Initialization structure of class Port Message FIFO */
+typedef struct Fifo_InitData_
+{
+ CBase *base_ptr; /*!< \brief Reference to base module */
+ CPmChannel *channel_ptr; /*!< \brief Points to channel object which is needed to communicate with
+ * the driver */
+ IEncoder *tx_encoder_ptr; /*!< \brief Encoder for Tx messages */
+ IEncoder *rx_encoder_ptr; /*!< \brief Encoder for Rx messages */
+ Fifo_OnRxMsg_t rx_cb_fptr; /*!< \brief Callback function invoked for Rx */
+ void *rx_cb_inst; /*!< \brief Instance which is referred when invoking rx_cb_fptr */
+
+} Fifo_InitData_t;
+
+/*! \brief Initialization structure of class Port Message FIFO */
+typedef struct Fifo_Config_
+{
+ Pmp_FifoId_t fifo_id; /*!< \brief Identifier of message FIFO.
+ * \details It is required that the fifo_id has the same value as
+ * specified in PMP.
+ */
+ uint8_t rx_credits; /*!< \brief Number of Rx credits, i.e. reserved Rx messages */
+ uint8_t rx_threshold; /*!< \brief Number of Rx credits which are acknowledged in a single status.
+ * \details The value needs to be smaller or equal than \c rx_credits.
+ * Valid values are:
+ * - 0,1: Single message acknowledge
+ * - 2..rx_credits: Implicit acknowledge is triggered after
+ * the specified number of messages.
+ */
+ uint8_t tx_wd_timeout; /*!< \brief Idle timeout in x100ms. Formerly known as watchdog timeout */
+ uint16_t tx_wd_timer_value; /*!< \brief Timer value used to trigger the watchdog in ms */
+ uint8_t rx_ack_timeout; /*!< \brief Rx status timeout in x100ms. */
+ uint8_t rx_busy_allowed; /*!< \brief Number of allowed RxStatus busy responds. 0..14, or 0xF (infinite) */
+
+} Fifo_Config_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief The synchronization status */
+typedef enum Fifo_SyncState_
+{
+ FIFO_S_UNSYNCED_INIT,
+ FIFO_S_SYNCING,
+ FIFO_S_UNSYNCED_BUSY,
+ FIFO_S_UNSYNCED_READY,
+ FIFO_S_SYNCED,
+ FIFO_S_UNSYNCING
+
+} Fifo_SyncState_t;
+
+/*! \brief The class CPmFifo*/
+typedef struct CPmFifo_
+{
+ Fifo_InitData_t init; /*!< \brief Initialization data */
+ Fifo_Config_t config; /*!< \brief Configuration data */
+
+ CService service; /*!< \brief Service object */
+ Fifo_SyncState_t sync_state; /*!< \brief Synchronization state of the FIFO */
+ CSubject sync_state_subject; /*!< \brief Notification of changed synchronization state */
+ uint8_t sync_params[4]; /*!< \brief Synchronization parameters */
+ uint8_t sync_cnt; /*!< \brief Counts the number of synchronization attempts */
+
+ struct CPmFifo_wd_
+ {
+ CTimer timer; /*!< \brief The timer object */
+ CPmCommand wd_cmd; /*!< \brief The watchdog command message */
+ uint16_t timer_value; /*!< \brief The internal timer value used by PMC to trigger the watchdog */
+ bool request_started; /*!< \brief Is used to check if the INIC responds with a status before the
+ * next Cmd.REQUEST_STATUS is triggered.
+ */
+ } wd;
+
+ struct CPmFifo_rx_
+ {
+ CDlList queue; /*!< \brief Message queue containing all incoming messages */
+
+ IEncoder *encoder_ptr; /*!< \brief Encoder for Rx messages */
+ Fifo_OnRxMsg_t on_complete_fptr; /*!< \brief Callback function invoked for Rx */
+ void *on_complete_inst; /*!< \brief Instance which is referred when invoking rx_cb_fptr */
+
+ uint8_t ack_threshold; /*!< \brief Number of unacknowledged Rx credits */
+ uint8_t ack_last_ok_sid; /*!< \brief Latest SID which was acknowledged with "success" */
+ uint8_t expected_sid; /*!< \brief The next expected Rx message SeqId */
+ uint8_t busy_num; /*!< \brief The number of currently processing data messages */
+
+ bool wait_processing; /*!< \brief If set: Wait until transmission of e.g. NACK has finished
+ * before continuing with further Rx message processing.
+ * The flag is used if a status must be sent explicitly.
+ */
+ CPmCommand status; /*!< \brief Rx status channel control */
+
+ } rx;
+
+ struct CPmFifo_tx_
+ {
+ CDlList waiting_queue; /*!< \brief Queue containing all outgoing messages */
+ CDlList pending_q; /*!< \brief Queue containing all messages waiting for Tx status */
+ IEncoder *encoder_ptr; /*!< \brief Encoder for Tx messages */
+ uint8_t credits; /*!< \brief Remaining Tx credits */
+
+ CLldPool lld_pool; /*!< \brief Pool of LLD Tx messages, used for data messages */
+
+ CPmh pm_header; /*!< \brief Temporary header which is used to build the FIFO data messages*/
+ CPmCommand cancel_cmd; /*!< \brief Tx cancel command message */
+ CPmCommand sync_cmd; /*!< \brief Sync command message */
+
+ uint8_t sid_next_to_use; /*!< \brief SID that shall be used for the next transmission */
+ uint8_t sid_last_completed; /*!< \brief Latest SID that was acknowledged by the INIC */
+ uint8_t current_sid; /*!< \brief Tracks the latest valid FIFO status SID received from the INIC */
+ Pmp_StatusType_t current_type; /*!< \brief Tracks the latest valid FIFO status type received from the INIC */
+ uint8_t current_code; /*!< \brief Tracks the latest valid FIFO status code received from the INIC */
+
+ bool status_waiting_release; /*!< \brief Is \c true if status notification wasn't completed due to messages
+ * which are not yet released by the LLD.
+ */
+ bool cancel_all_running; /*!< \brief Is \c true during pending command CANCEL_ALL. This command is required
+ * if the front-most message is segmented which requires to discard all
+ * belonging segments (same \c cancel_id) after the CANCEL_ALL was completed.
+ */
+ uint8_t failure_status; /*!< \brief Stores the Tx status until the message is canceled */
+ uint8_t failure_sid; /*!< \brief Stores the SID of the last cancelled data message */
+ } tx;
+
+} CPmFifo;
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Function Prototypes */
+/*------------------------------------------------------------------------------------------------*/
+extern void Fifo_Ctor(CPmFifo *self, const Fifo_InitData_t *init_ptr, const Fifo_Config_t *config_ptr);
+extern void Fifo_Stop(CPmFifo *self, Fifo_SyncState_t new_state, bool allow_notification);
+extern void Fifo_Cleanup(CPmFifo *self);
+
+extern void Fifo_Synchronize(CPmFifo *self);
+extern void Fifo_Unsynchronize(CPmFifo *self);
+extern Fifo_SyncState_t Fifo_GetState(CPmFifo *self);
+extern void Fifo_AddStateObserver(CPmFifo *self, CObserver *obs_ptr);
+extern void Fifo_RemoveStateObserver(CPmFifo *self, CObserver *obs_ptr);
+
+/* Rx interface */
+extern void Fifo_RxReleaseMsg(CPmFifo *self, CMessage *msg_ptr);
+
+/* Tx interface */
+extern void Fifo_Tx(CPmFifo *self, CMessage *msg_ptr, bool bypass);
+extern void Fifo_TxOnRelease(void *self, Mns_Lld_TxMsg_t *handle_ptr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* MNS_PMFIFO_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmfifos.c b/mnsl/mns_pmfifos.c
new file mode 100644
index 0000000..e82b837
--- /dev/null
+++ b/mnsl/mns_pmfifos.c
@@ -0,0 +1,447 @@
+/*
+ * 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 Implementation of class CPmFifos
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PMFIFOS
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_pmfifos.h"
+#include "mns_misc.h"
+#include "mns_trace.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal Constants */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief The initialization value of sync_count. It is incremented for each sync or un-sync attempt. */
+static const uint8_t FIFOS_SYNC_CNT_INITIAL = 0xFFU;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal typedefs */
+/*------------------------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Fifos_Cleanup(CPmFifos *self);
+static void Fifos_OnSyncTimeout(void *self);
+static void Fifos_OnUnsyncTimeout(void *self);
+static void Fifos_OnFifoEvent(void *self, void *fifo_id_ptr);
+
+static void Fifos_HandleFifoStateChange(CPmFifos *self, Pmp_FifoId_t fifo_id);
+static bool Fifos_AreAllFifosInState(CPmFifos *self, Fifo_SyncState_t target_state);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of class CPmFifos
+ * \param self The instance
+ * \param base_ptr Reference to basic services
+ * \param channel_ptr Reference to the port message channel
+ * \param icm_fifo_ptr Reference to ICM FIFO, or NULL.
+ * \param mcm_fifo_ptr Reference to MCM FIFO, or NULL.
+ * \param rcm_fifo_ptr Reference to RCM FIFO, or NULL.
+ * \details At least one FIFO (MCM or ICM) must be provided.
+ */
+void Fifos_Ctor(CPmFifos *self, CBase *base_ptr, CPmChannel *channel_ptr, CPmFifo *icm_fifo_ptr, CPmFifo *mcm_fifo_ptr, CPmFifo *rcm_fifo_ptr)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+
+ self->base_ptr = base_ptr;
+ self->channel_ptr = channel_ptr;
+ self->state = FIFOS_S_UNSYNCED;
+
+ self->unsync_initial = false;
+ Fifos_ConfigureSyncParams(self, FIFOS_SYNC_RETRIES, FIFOS_SYNC_TIMEOUT);
+
+ self->fifos[PMP_FIFO_ID_ICM] = icm_fifo_ptr;
+ self->fifos[PMP_FIFO_ID_RCM] = rcm_fifo_ptr;
+ self->fifos[PMP_FIFO_ID_MCM] = mcm_fifo_ptr;
+
+ T_Ctor(&self->init_timer);
+ Sub_Ctor(&self->event_subject, self->base_ptr->mns_inst_id);
+ Obs_Ctor(&self->obs_icm, self, &Fifos_OnFifoEvent);
+ Obs_Ctor(&self->obs_rcm, self, &Fifos_OnFifoEvent);
+ Obs_Ctor(&self->obs_mcm, self, &Fifos_OnFifoEvent);
+
+ Pmcmd_Ctor(&self->cmd, PMP_FIFO_ID_ALL, PMP_MSG_TYPE_CMD);
+
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[FIFOS]", (!((icm_fifo_ptr == NULL) && (mcm_fifo_ptr == NULL))));
+
+ if (icm_fifo_ptr != NULL)
+ {
+ Fifo_AddStateObserver(icm_fifo_ptr, &self->obs_icm);
+ }
+
+ if (rcm_fifo_ptr != NULL)
+ {
+ Fifo_AddStateObserver(rcm_fifo_ptr, &self->obs_rcm);
+ }
+
+ if (mcm_fifo_ptr != NULL)
+ {
+ Fifo_AddStateObserver(mcm_fifo_ptr, &self->obs_mcm);
+ }
+
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_Ctor(): FIFOS created, state %d", 1U, self->state));
+}
+
+/*! \brief Adds an observer of synchronization events
+ * \param self The instance
+ * \param obs_ptr The observer. The notification result type is Fifos_Event_t.
+ */
+void Fifos_AddEventObserver(CPmFifos *self, CObserver *obs_ptr)
+{
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[FIFOS]", (obs_ptr != 0));
+ (void)Sub_AddObserver(&self->event_subject, obs_ptr);
+}
+
+/*! \brief Removes an observer of synchronization events
+ * \param self The instance
+ * \param obs_ptr The observer.
+ */
+void Fifos_RemoveEventObserver(CPmFifos *self, CObserver *obs_ptr)
+{
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[FIFOS]", (obs_ptr != 0));
+ (void)Sub_RemoveObserver(&self->event_subject, obs_ptr);
+}
+
+/*! \brief Forces all FIFOs to state UNSYNCED without waiting for INIC responses and
+ * without throwing events
+ * \details Stops the LLD interface and releases all pending message resources.
+ * This function shall be called if the MNS requires a un-normal termination
+ * which is not detected by port message protocol.
+ * \param self The instance
+ */
+void Fifos_ForceTermination(CPmFifos *self)
+{
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_ForceTermination(): Termination started, state: %d", 1U, self->state));
+ Fifos_Cleanup(self);
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_ForceTermination(): Termination done, state: %d", 1U, self->state));
+}
+
+/*! \brief Configures retries and timeout for synchronize or un-synchronize
+ * operation
+ * \details This method shall be called before starting a synchronization or un-synchronization
+ * or after it has finished. The current counter of synchronization attempts is reset.
+ * \param self The instance
+ * \param retries The number of retries until event FIFOS_EV_SYNC_FAILED or
+ * FIFOS_EV_UNSYNC_FAILED will be notified
+ * \param timeout The timeout in milliseconds when the retry is performed
+ */
+void Fifos_ConfigureSyncParams(CPmFifos *self, uint8_t retries, uint16_t timeout)
+{
+ self->cmd_retries = retries;
+ self->cmd_timeout = timeout;
+ self->sync_cnt = FIFOS_SYNC_CNT_INITIAL;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Synchronization */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Initializes all port message FIFOs
+ * \details Possible results of the operation are the following events which are fired
+ * asynchronously. Refer also Fifos_AddEventObserver() and \ref Fifos_Event_t.
+ * - \ref FIFOS_EV_SYNC_ESTABLISHED
+ * - \ref FIFOS_EV_SYNC_FAILED
+ * \param self The instance
+ * \param reset_cnt If \c true resets the synchronization counter. In this case an automatic
+ * retries will be done after the first synchronization timeout.
+ * \param force_sync If \c true the method will also trigger the synchronization of already
+ * synced \ref CPmFifo objects.
+ */
+void Fifos_Synchronize(CPmFifos *self, bool reset_cnt, bool force_sync)
+{
+ uint8_t cnt;
+ self->state = FIFOS_S_SYNCING;
+ self->unsync_initial = false;
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_Synchronize(): Synchronization started, state: %d", 1U, self->state));
+
+ if (reset_cnt)
+ {
+ self->sync_cnt = FIFOS_SYNC_CNT_INITIAL;
+ }
+
+ self->sync_cnt++;
+ Pmch_Initialize(self->channel_ptr); /* Start LLD if not already done */
+
+ for (cnt = 0U; cnt < PMP_MAX_NUM_FIFOS; cnt++)
+ {
+ if (self->fifos[cnt] != NULL)
+ {
+ if (force_sync || (Fifo_GetState(self->fifos[cnt]) != FIFO_S_SYNCED))
+ {
+ Fifo_Synchronize(self->fifos[cnt]);
+ }
+ }
+ }
+
+ Tm_SetTimer(&self->base_ptr->tm, &self->init_timer,
+ &Fifos_OnSyncTimeout, self,
+ self->cmd_timeout, 0U);
+}
+
+/*! \brief Un-initializes all port message FIFOs
+ * \details Possible results of the operation are the following events which are fired
+ * asynchronously. Refer also Fifos_AddEventObserver() and \ref Fifos_Event_t.
+ * - \ref FIFOS_EV_UNSYNC_COMPLETE
+ * - \ref FIFOS_EV_UNSYNC_FAILED
+ * \param self The instance
+ * \param reset_cnt If \c true resets the synchronization counter. In this case an automatic
+ * retries will be done after the first synchronization timeout.
+ * \param initial If the un-synchronization shall be executed prior to a initial synchronization
+ * it is recommended to set the argument to \c true. After notifying the event
+ * FIFOS_EV_UNSYNC_COMPLETE the LLD interface will not be stopped. The subsequent
+ * call of Fifos_Synchronize() will not start the LLD interface un-necessarily.
+ * To trigger a final un-synchronization \c initial shall be set to \c false.
+ * I.e., FIFOS_EV_UNSYNC_COMPLETE stops the LLD interface.
+ */
+void Fifos_Unsynchronize(CPmFifos *self, bool reset_cnt, bool initial)
+{
+ self->state = FIFOS_S_UNSYNCING;
+ self->unsync_initial = initial;
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_Unsynchronize(): Un-synchronization started, state: %d", 1U, self->state));
+
+ if (reset_cnt)
+ {
+ self->sync_cnt = FIFOS_SYNC_CNT_INITIAL;
+ }
+
+ self->sync_cnt++;
+ Pmch_Initialize(self->channel_ptr); /* Start LLD if not already done */
+
+ if (Pmcmd_Reserve(&self->cmd))
+ {
+ Pmcmd_SetContent(&self->cmd, 0xFFU, PMP_CMD_TYPE_SYNCHRONIZATION, PMP_CMD_CODE_UNSYNC, NULL, 0U);
+
+ Pmch_Transmit(self->channel_ptr, Pmcmd_GetLldTxObject(&self->cmd));
+ }
+
+ Tm_SetTimer(&self->base_ptr->tm, &self->init_timer,
+ &Fifos_OnUnsyncTimeout, self,
+ self->cmd_timeout, 0U);
+}
+
+/*! \brief Handles the synchronization timeout
+ * \param self The instance
+ */
+static void Fifos_OnSyncTimeout(void *self)
+{
+ CPmFifos *self_ = (CPmFifos*)self;
+ Fifos_Event_t the_event = FIFOS_EV_SYNC_FAILED;
+
+ self_->state = FIFOS_S_UNSYNCED;
+
+ TR_INFO((self_->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_OnSyncTimeout(): state: %d", 1U, self_->state));
+
+ if (self_->sync_cnt < self_->cmd_retries)
+ {
+ Fifos_Synchronize(self_, false, false); /* retry synchronization after first timeout */
+ }
+ else
+ {
+ Fifos_Cleanup(self_);
+ Sub_Notify(&self_->event_subject, &the_event);
+ }
+}
+
+/*! \brief Handles the un-synchronization timeout
+ * \param self The instance
+ */
+static void Fifos_OnUnsyncTimeout(void *self)
+{
+ CPmFifos *self_ = (CPmFifos*)self;
+ Fifos_Event_t the_event = FIFOS_EV_UNSYNC_FAILED;
+
+ self_->state = FIFOS_S_UNSYNCED;
+ TR_INFO((self_->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_OnUnsyncTimeout(): state: %d", 1U, self_->state));
+
+ if (self_->sync_cnt < self_->cmd_retries)
+ {
+ Fifos_Unsynchronize(self_, false, self_->unsync_initial); /* retry synchronization after first timeout */
+ }
+ else
+ {
+ self_->unsync_initial = false; /* un-sync timeout will lead to termination - stop LLD */
+ Fifos_Cleanup(self_);
+ Sub_Notify(&self_->event_subject, &the_event);
+}
+}
+
+/*! \brief Performs a cleanup of the Port Message Channel and the dedicated FIFOs
+ * \details Releases all message objects which are currently in use.
+ * \param self The instance
+ */
+static void Fifos_Cleanup(CPmFifos *self)
+{
+ uint8_t count;
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_Cleanup(): Channel cleanup started", 0U));
+
+ if (self->unsync_initial == false)
+ {
+ Pmch_Uninitialize(self->channel_ptr);
+ }
+
+ for (count = 0U; count < PMP_MAX_NUM_FIFOS; count++) /* stop & cleanup all FIFOs */
+ {
+ if (self->fifos[count] != NULL)
+ { /* stop and avoid recursion */
+ Fifo_Stop(self->fifos[count], FIFO_S_UNSYNCED_INIT, false);
+ Fifo_Cleanup(self->fifos[count]);
+ }
+ }
+
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_Cleanup(): Channel cleanup completed", 0U));
+
+ /* notify external event after message objects were released */
+ self->state = FIFOS_S_UNSYNCED;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* FIFO observation */
+/*------------------------------------------------------------------------------------------------*/
+
+/*! \brief Notifies an event to the host class
+ * \param self The instance
+ * \param fifo_id_ptr Specific event identifier, pointer to "fifo_id"
+ */
+static void Fifos_OnFifoEvent(void *self, void *fifo_id_ptr)
+{
+ CPmFifos *self_ = (CPmFifos*)self;
+ Fifos_HandleFifoStateChange(self_, *((Pmp_FifoId_t*)fifo_id_ptr));
+}
+
+/*! \brief Executes transition to new synchronization states
+ * \param self The instance
+ * \param fifo_id The FIFO identifier
+ */
+static void Fifos_HandleFifoStateChange(CPmFifos *self, Pmp_FifoId_t fifo_id)
+{
+ Fifos_Event_t the_event;
+
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_HandleFifoStateChange(): FIFOs state: %d, FIFO: %d, FIFO State: %d", 3U,
+ self->state, fifo_id, Fifo_GetState(self->fifos[fifo_id])));
+
+ switch (self->state)
+ {
+ case FIFOS_S_SYNCING:
+ if (Fifos_AreAllFifosInState(self, FIFO_S_SYNCED))
+ {
+ self->state = FIFOS_S_SYNCED; /* now the complete channel is synced */
+ Tm_ClearTimer(&self->base_ptr->tm, &self->init_timer);
+ Fifos_ConfigureSyncParams(self, FIFOS_UNSYNC_RETRIES, FIFOS_UNSYNC_TIMEOUT);
+ the_event = FIFOS_EV_SYNC_ESTABLISHED;
+ Sub_Notify(&self->event_subject, &the_event);
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_HandleFifoStateChange(): Synchronization of Port Message channel completed", 0U));
+ }
+ break;
+
+ case FIFOS_S_UNSYNCING:
+ if (Fifos_AreAllFifosInState(self, FIFO_S_UNSYNCED_READY))
+ {
+ Fifos_Cleanup(self);
+ self->state = FIFOS_S_UNSYNCED; /* now the complete channel is un-synced */
+ Tm_ClearTimer(&self->base_ptr->tm, &self->init_timer);
+ the_event = FIFOS_EV_UNSYNC_COMPLETE;
+ Sub_Notify(&self->event_subject, &the_event);
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_HandleFifoStateChange(): Un-synchronization of Port Message channel completed", 0U));
+ }
+ break;
+
+ case FIFOS_S_SYNCED:
+ if (!Fifos_AreAllFifosInState(self, FIFO_S_SYNCED))
+ {
+ self->state = FIFOS_S_UNSYNCING; /* set state to 'unsyncing' and wait until all FIFOs are unsynced */
+ self->sync_cnt = 0U; /* pretend having triggered an un-sync which starts the timer */
+ Tm_SetTimer(&self->base_ptr->tm, &self->init_timer,
+ &Fifos_OnUnsyncTimeout, self,
+ FIFOS_UNSYNC_TIMEOUT, 0U);
+ the_event = FIFOS_EV_SYNC_LOST;
+ Sub_Notify(&self->event_subject, &the_event);
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_HandleFifoStateChange(): Lost synchronization of Port Message channel", 0U));
+ }
+ if (Fifos_AreAllFifosInState(self, FIFO_S_UNSYNCED_READY))
+ {
+ Fifos_Cleanup(self);
+ self->state = FIFOS_S_UNSYNCED; /* the complete channel suddenly goes unsynced_complete */
+ Tm_ClearTimer(&self->base_ptr->tm, &self->init_timer);
+ the_event = FIFOS_EV_UNSYNC_COMPLETE;
+ Sub_Notify(&self->event_subject, &the_event);
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_HandleFifoStateChange(): Sudden un-synchronization of Port Message channel completed", 0U));
+ }
+ break;
+
+ case FIFOS_S_UNSYNCED:
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_HandleFifoStateChange(): Unexpected FIFO event in state unsynced", 0U));
+ break;
+
+ default:
+ TR_INFO((self->base_ptr->mns_inst_id, "[FIFOS]", "Fifos_HandleFifoStateChange(): Unexpected FIFOs state", 0U));
+ break;
+ }
+
+ MISC_UNUSED(fifo_id);
+}
+
+/*! \brief Helper function that evaluates if all configured FIFOs are in a given state
+ * \param self The instance
+ * \param target_state The required state that is evaluated for all FIFOs
+ * \return \c true if all FIFOs are in the given \c target_state, otherwise \c false.
+ */
+static bool Fifos_AreAllFifosInState(CPmFifos *self, Fifo_SyncState_t target_state)
+{
+ bool ret = true;
+ uint8_t cnt;
+
+ for (cnt = 0U; cnt < PMP_MAX_NUM_FIFOS; cnt++)
+ {
+ if (self->fifos[cnt] != NULL)
+ {
+ Fifo_SyncState_t state = Fifo_GetState(self->fifos[cnt]);
+
+ if (state != target_state)
+ {
+ ret = false;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmfifos.h b/mnsl/mns_pmfifos.h
new file mode 100644
index 0000000..814b057
--- /dev/null
+++ b/mnsl/mns_pmfifos.h
@@ -0,0 +1,131 @@
+/*
+ * 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 class CPmFifos
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PMFIFOS
+ * @{
+ */
+
+#ifndef MNS_PMFIFOS_H
+#define MNS_PMFIFOS_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+#include "mns_base.h"
+#include "mns_pmfifo.h"
+#include "mns_pmchannel.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macros */
+/*------------------------------------------------------------------------------------------------*/
+#define FIFOS_SYNC_TIMEOUT 50U /*!< \brief Synchronization timeout in milliseconds */
+#define FIFOS_SYNC_RETRIES 40U /*!< \brief Maximum number of synchronization retries after timeout */
+#define FIFOS_UNSYNC_TIMEOUT 200U /*!< \brief Un-synchronization timeout in milliseconds */
+#define FIFOS_UNSYNC_RETRIES 0U /*!< \brief Un-synchronization retries */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief The synchronization status of all FIFOs */
+typedef enum Fifos_SyncState_
+{
+ FIFOS_S_UNSYNCED, /*!< \brief Not all FIFOs are synchronized */
+ FIFOS_S_SYNCING, /*!< \brief FIFOs synchronization has started */
+ FIFOS_S_SYNCED, /*!< \brief All FIFOs are synchronized */
+ FIFOS_S_UNSYNCING /*!< \brief FIFOs un-synchronization has started */
+
+} Fifos_SyncState_t;
+
+/*! \brief PMS Events */
+typedef enum Fifos_Event_
+{
+ FIFOS_EV_SYNC_LOST = 0, /*!< \brief Synchronization of at least one FIFO is lost */
+ FIFOS_EV_SYNC_ESTABLISHED = 1, /*!< \brief Synchronization of all FIFOs is established */
+ FIFOS_EV_SYNC_FAILED = 2, /*!< \brief The initial synchronization of FIFOs failed */
+ FIFOS_EV_UNSYNC_COMPLETE = 3, /*!< \brief Un-synchronization of all FIFOs has succeeded */
+ FIFOS_EV_UNSYNC_FAILED = 4 /*!< \brief Un-synchronization of all FIFOs has failed */
+
+} Fifos_Event_t;
+
+/*! \brief The class CPmFifos*/
+typedef struct CPmFifos_
+{
+ CBase *base_ptr; /*!< \brief Reference to base object */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+ CPmChannel *channel_ptr; /*!< \brief MOST NetServices instance ID */
+
+ CPmFifo *fifos[PMP_MAX_NUM_FIFOS]; /*!< \brief Reference to assigned FIFOs */
+
+ CObserver obs_icm; /*!< \brief Observes ICM synchronization state */
+ CObserver obs_rcm; /*!< \brief Observes ICM synchronization state */
+ CObserver obs_mcm; /*!< \brief Observes MCM synchronization state */
+ CPmCommand cmd; /*!< \brief The UNSYNC command message */
+ Fifos_SyncState_t state; /*!< \brief The Overall synchronization state */
+ uint8_t sync_cnt; /*!< \brief The current count of synchronization command */
+
+ uint8_t cmd_retries; /*!< \brief The number of sync/un-sync retries */
+ uint16_t cmd_timeout; /*!< \brief The the timeout to retry sync/un-sync */
+ bool unsync_initial; /*!< \brief Specifies if un-sync complete shall un-initialize the channel */
+
+ CSubject event_subject; /*!< \brief Subject to report synchronization result */
+ CTimer init_timer; /*!< \brief Timer elapses on synchronization timeout */
+
+} CPmFifos;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Function prototypes */
+/*------------------------------------------------------------------------------------------------*/
+extern void Fifos_Ctor(CPmFifos *self, CBase *base_ptr, CPmChannel *channel_ptr, CPmFifo *icm_fifo_ptr, CPmFifo *mcm_fifo_ptr, CPmFifo *rcm_fifo_ptr);
+extern void Fifos_AddEventObserver(CPmFifos *self, CObserver *obs_ptr);
+extern void Fifos_RemoveEventObserver(CPmFifos *self, CObserver *obs_ptr);
+extern void Fifos_Synchronize(CPmFifos *self, bool reset_cnt, bool force_sync);
+extern void Fifos_Unsynchronize(CPmFifos *self, bool reset_cnt, bool initial);
+extern void Fifos_ForceTermination(CPmFifos *self);
+extern void Fifos_ConfigureSyncParams(CPmFifos *self, uint8_t retries, uint16_t timeout/*, bool uninit_on_fail*/);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* MNS_PMFIFOS_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmp.c b/mnsl/mns_pmp.c
new file mode 100644
index 0000000..765982d
--- /dev/null
+++ b/mnsl/mns_pmp.c
@@ -0,0 +1,352 @@
+/*
+ * 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 Implementation of Port Message Protocol
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PMH
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_pmp.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* PMP Indexes */
+/*------------------------------------------------------------------------------------------------*/
+#define PMP_IDX_PML_H 0U
+#define PMP_IDX_PML_L 1U
+#define PMP_IDX_PMHL 2U
+#define PMP_IDX_FPH 3U
+#define PMP_IDX_SID 4U
+#define PMP_IDX_EXT_TYPE 5U
+
+/*------------------------------------------------------------------------------------------------*/
+/* Masks and shifts for bit fields */
+/*------------------------------------------------------------------------------------------------*/
+#define PMP_PMHL_MASK 0x1FU /* 0b00011111 */
+#define PMP_VERSION_MASK 0xE0U /* 0b11100000 */
+#define PMP_VERSION 0x40U /* Version: "2" */
+#define PMP_FPH_TYPE_POS 1U
+#define PMP_FPH_TYPE_MASK 0x06U /* 0b00000110 */
+#define PMP_FPH_ID_POS 3U
+#define PMP_FPH_ID_MASK 0x38U /* 0b00111000 */
+#define PMP_FPH_DIR_RX 0x01U /* RX: "1" */
+#define PMP_FPH_DIR_MASK 0x01U /* 0b00000001 */
+#define PMP_EXT_TYPE_POS 5U
+#define PMP_EXT_TYPE_MASK 0xE0U /* 0b11100000 */
+#define PMP_EXT_CODE_MASK 0x1FU /* 0b00011111 */
+
+/*------------------------------------------------------------------------------------------------*/
+/* PMP Verification */
+/*------------------------------------------------------------------------------------------------*/
+#define PMP_PML_MAX_SIZE_CTRL 69U
+#define PMP_PMHL_MIN_SIZE 3U
+#define PMP_PMHL_MAX_SIZE 5U
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macro like functions */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Sets the port message length within a given message header
+ * \param header The message header
+ * \param length The port message length
+ */
+void Pmp_SetPml(uint8_t header[], uint8_t length)
+{
+ header[PMP_IDX_PML_H] = 0U;
+ header[PMP_IDX_PML_L] = length;
+}
+
+/*! \brief Sets the port message header length within a given message header
+ * \param header The message header
+ * \param length The port message header length. Valid values: 3..5.
+ * Invalid values will set the PMHL to \c 0.
+ */
+void Pmp_SetPmhl(uint8_t header[], uint8_t length)
+{
+ if ((length < PMP_PMHL_MIN_SIZE) || (length > PMP_PMHL_MAX_SIZE))
+ {
+ length = 0U;
+ }
+
+ header[PMP_IDX_PMHL] = length | PMP_VERSION;
+}
+
+/*! \brief Sets the FIFO protocol header within a given message header
+ * \param header The message header
+ * \param id The FIFO id
+ * \param type The port message type
+ */
+void Pmp_SetFph(uint8_t header[], Pmp_FifoId_t id, Pmp_MsgType_t type)
+{
+ header[PMP_IDX_FPH] = (uint8_t)((uint8_t)type << PMP_FPH_TYPE_POS) | (uint8_t)((uint8_t)id << PMP_FPH_ID_POS) | (uint8_t)PMP_DIR_TX;
+}
+
+/*! \brief Sets the field ExtType within a given message header
+ * \param header The message header
+ * \param type The command or status type
+ * \param code The command or status code
+ */
+void Pmp_SetExtType(uint8_t header[], uint8_t type, uint8_t code)
+{
+ header[PMP_IDX_EXT_TYPE] = (uint8_t)((type << PMP_EXT_TYPE_POS) & PMP_EXT_TYPE_MASK) | (uint8_t)(code & PMP_EXT_CODE_MASK);
+}
+
+/*! \brief Sets the sequence id within a given message header
+ * \param header The message header
+ * \param sid The sequence id
+ */
+void Pmp_SetSid(uint8_t header[], uint8_t sid)
+{
+ header[PMP_IDX_SID] = sid;
+}
+
+/*! \brief Retrieves the port message length of a given port message buffer
+ * \param header Data buffer containing the port message.
+ * The required size of this buffer is 6 bytes.
+ * \return The port message length in bytes or 0 if the PML is greater than 255.
+ */
+uint8_t Pmp_GetPml(uint8_t header[])
+{
+ uint8_t pml;
+ if (header[PMP_IDX_PML_H] != 0U)
+ {
+ pml = 0U;
+ }
+ else
+ {
+ pml = header[PMP_IDX_PML_L];
+ }
+
+ return pml;
+}
+
+/*! \brief Retrieves the port message header length of a given port message buffer
+ * \param header Data buffer containing the port message.
+ * The required size of this buffer is 6 bytes.
+ * \return The port message header length in bytes
+ */
+uint8_t Pmp_GetPmhl(uint8_t header[])
+{
+ return ((uint8_t)(header[PMP_IDX_PMHL] & (uint8_t)PMP_PMHL_MASK));
+}
+
+/*! \brief Retrieves the FIFO number of a given port message buffer
+ * \param header Data buffer containing the port message.
+ * The required size of this buffer is 6 bytes.
+ * \return The FIFO number
+ */
+Pmp_FifoId_t Pmp_GetFifoId(uint8_t header[])
+{
+ return (Pmp_FifoId_t)(((uint8_t)PMP_FPH_ID_MASK & (header)[PMP_IDX_FPH]) >> PMP_FPH_ID_POS);
+}
+
+/*! \brief Retrieves the FIFO Type of a given port message buffer
+ * \param header Data buffer containing the port message.
+ * The required size of this buffer is 6 bytes.
+ * \return The FIFO type
+ */
+Pmp_MsgType_t Pmp_GetMsgType(uint8_t header[])
+{
+ return ((Pmp_MsgType_t)((PMP_FPH_TYPE_MASK & (header)[PMP_IDX_FPH]) >> PMP_FPH_TYPE_POS));
+}
+
+/*! \brief Retrieves the SequenceID of a given port message buffer
+ * \param header Data buffer containing the port message.
+ * The required size of this buffer is 6 bytes.
+ * \return The SequenceID
+ */
+uint8_t Pmp_GetSid(uint8_t header[])
+{
+ return ((header)[PMP_IDX_SID]);
+}
+
+/*! \brief Retrieves payload data of a port message
+ * \param header Data buffer containing the port message.
+ * The required size of this buffer is 6 bytes.
+ * \param index The index of the payload byte starting with '0'
+ * \return The content of a payload data byte
+ */
+uint8_t Pmp_GetData(uint8_t header[], uint8_t index)
+{
+ return header[Pmp_GetPmhl(header) + 3U + index];
+}
+
+/*! \brief Retrieves the payload size of the port message
+ * \param header Data buffer containing the port message.
+ * The required size of this buffer is 6 bytes.
+ * \details The function Pmp_VerifyHeader() must be called before
+ * to verify that the port message fields are consistent.
+ * \return The payload size of a port message
+ */
+uint8_t Pmp_GetDataSize(uint8_t header[])
+{
+ return Pmp_GetPml(header) - (Pmp_GetPmhl(header) + 1U);
+}
+
+/*! \brief Checks if header length fields are set to valid values
+ * \param header Data buffer containing the port message.
+ * The required size of this buffer is 6 bytes.
+ * \param buf_len Length of the complete port message in bytes
+ * \return Returns \c true if the header was checked successfully,
+ * otherwise \c false.
+ */
+bool Pmp_VerifyHeader(uint8_t header[], uint8_t buf_len)
+{
+ uint8_t pml = Pmp_GetPml(header);
+ uint8_t pmhl = Pmp_GetPmhl(header);
+ bool ok = true;
+
+ ok = ((pmhl >= 3U)&&(pmhl <= 5U)) ? ok : false;
+ ok = ((header[PMP_IDX_PMHL] & PMP_VERSION_MASK) == PMP_VERSION) ? ok : false;
+ ok = (pml >= (pmhl + 1U)) ? ok : false;
+ ok = ((pml + 2U) <= buf_len) ? ok : false;
+ ok = (pml <= PMP_PML_MAX_SIZE_CTRL) ? ok : false;
+ ok = ((header[PMP_IDX_FPH] & PMP_FPH_DIR_MASK) == PMP_FPH_DIR_RX) ? ok : false;
+
+ return ok;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Creates a Port Message Header instance
+ * \param self The instance
+ */
+void Pmh_Ctor(CPmh *self)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+}
+
+/*! \brief Inserts a port message header of the specified size into a given buffer
+ * \param self Header content to be written to the buffer (source)
+ * \param data Data buffer the header shall be written to (target)
+ */
+void Pmh_BuildHeader(CPmh *self, uint8_t data[])
+{
+ uint8_t cnt;
+
+ data[PMP_IDX_PML_H] = 0U;
+ data[PMP_IDX_PML_L] = (uint8_t)self->pml;
+ data[PMP_IDX_PMHL] = (uint8_t)PMP_VERSION | self->pmhl;
+ data[PMP_IDX_FPH] = (uint8_t)PMP_DIR_TX | ((uint8_t)((self->fifo_id) << PMP_FPH_ID_POS)) |
+ ((uint8_t)((self->msg_type) << PMP_FPH_TYPE_POS));
+
+ data[PMP_IDX_SID] = self->sid;
+ data[PMP_IDX_EXT_TYPE]= self->ext_type;
+
+ for (cnt=3U; cnt < self->pmhl; cnt++)
+ {
+ data[3U + cnt] = 0U; /* add stuffing bytes */
+ }
+}
+
+/*! \brief Decodes a given data buffer into a provided port message header structure
+ * \param self Header content structure (target)
+ * \param data Data buffer containing the port message with a minimum size
+ * of 6 bytes (source)
+ */
+void Pmh_DecodeHeader(CPmh *self, uint8_t data[])
+{
+ self->pml = Pmp_GetPml(data);
+ self->pmhl = data[PMP_IDX_PMHL] & PMP_PMHL_MASK; /* ignore version */
+
+ self->fifo_id = Pmp_GetFifoId(data);
+ self->msg_type = Pmp_GetMsgType(data);
+ self->sid = data[PMP_IDX_SID];
+ self->ext_type = data[PMP_IDX_EXT_TYPE];
+}
+
+/*! \brief Setter function for FIFO protocol header which contains several subfields
+ * \details The "retransmitted" flag is currently not supported (always Tx)
+ * \param self Reference to the PM content structure that shall be modified
+ * \param fifo_id Id of the PM FIFO
+ * \param msg_type PM type
+ */
+void Pmh_SetFph(CPmh *self, Pmp_FifoId_t fifo_id, Pmp_MsgType_t msg_type)
+{
+ self->msg_type = msg_type;
+ self->fifo_id = fifo_id;
+}
+
+/*! \brief Retrieves the ExtType StatusType
+ * \param self The instance
+ * \return Returns The Status Type
+ */
+Pmp_StatusType_t Pmh_GetExtStatusType(CPmh *self)
+{
+ return ((Pmp_StatusType_t)((uint8_t)(PMP_EXT_TYPE_MASK & self->ext_type) >> PMP_EXT_TYPE_POS));
+}
+
+/*! \brief Retrieves the ExtType StatusCode
+ * \param self The instance
+ * \return Returns The Status Code
+ */
+Pmp_CommandCode_t Pmh_GetExtCommandCode(CPmh *self)
+{
+ return ((Pmp_CommandCode_t)(uint8_t)(PMP_EXT_CODE_MASK & self->ext_type));
+}
+
+/*! \brief Retrieves the ExtType StatusType
+ * \param self The instance
+ * \return Returns The Status Type
+ */
+Pmp_CommandType_t Pmh_GetExtCommandType(CPmh *self)
+{
+ return ((Pmp_CommandType_t)((uint8_t)(PMP_EXT_TYPE_MASK & self->ext_type) >> PMP_EXT_TYPE_POS));
+}
+
+/*! \brief Retrieves the ExtType StatusCode
+ * \param self The instance
+ * \return Returns The Status Code
+ */
+Pmp_StatusCode_t Pmh_GetExtStatusCode(CPmh *self)
+{
+ return ((Pmp_StatusCode_t)(uint8_t)(PMP_EXT_CODE_MASK & self->ext_type));
+}
+
+/*! \brief Sets the ExtType field by passing the values for type and code
+ * \details The function is applicable for status and command
+ * \param self The Instance
+ * \param type The status or command type
+ * \param code The status or command code
+ */
+void Pmh_SetExtType(CPmh *self, uint8_t type, uint8_t code)
+{
+ self->ext_type = (uint8_t)((type << PMP_EXT_TYPE_POS) & PMP_EXT_TYPE_MASK) | (uint8_t)(code & PMP_EXT_CODE_MASK);
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pmp.h b/mnsl/mns_pmp.h
new file mode 100644
index 0000000..96b22b0
--- /dev/null
+++ b/mnsl/mns_pmp.h
@@ -0,0 +1,211 @@
+/*
+ * 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 Port Message Protocol
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_PMH
+ * @{
+ */
+
+#ifndef MNS_PMP_H
+#define MNS_PMP_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macros */
+/*------------------------------------------------------------------------------------------------*/
+#define PMP_PM_MAX_SIZE_HEADER 8U /*!< \brief Maximum size of a port message header */
+#define PMP_PM_MIN_SIZE_HEADER 6U /*!< \brief Minimum size of a port message header */
+#define PMP_MAX_NUM_FIFOS 7U /*!< \brief Maximum number if FIFOs an an array
+ * \details Means "3" if FIFO "0" and "2" is used
+ */
+#define PMP_CREDITS_MASK 0x3FU /*!< \brief Valid bits for credits: 5..0 */
+#define PMP_CREDITS_MIN 1U /*!< \brief Minimum value for credits: 1 */
+#define PMP_CREDITS_MAX 63U /*!< \brief Maximum value for credits: 63 */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+
+/*! \brief Specifies the FIFO */
+typedef enum Pmp_FifoId_
+{
+ PMP_FIFO_ID_MCM = 0U, /*!< \brief FIFO dedicated to MOST Control Messages (MCM) */
+ /* PMP_FIFO_ID_MDP = 1U, < (reserved identifier) */
+ PMP_FIFO_ID_ICM = 2U, /*!< \brief FIFO dedicated to INIC Control Messages (ICM) */
+ PMP_FIFO_ID_ALL = 3U, /*!< \brief All FIFOs (ICM, MCM) */
+ /* PMP_FIFO_ID_MEP = 4U < (reserved identifier) */
+ /* PMP_FIFO_ID_IOCM = 5U < (reserved identifier) */
+ PMP_FIFO_ID_RCM = 6U /*!< \brief FIFO dedicated to Remote Control Messages (RCM) */
+ /* PMP_FIFO_ID_RSVD = 7U < (reserved identifier) */
+
+} Pmp_FifoId_t;
+
+/*! \brief Specifies the messages type */
+typedef enum Pmp_MsgType_
+{
+ PMP_MSG_TYPE_CMD = 0U, /*!< \brief FIFO command message */
+ PMP_MSG_TYPE_STATUS = 1U, /*!< \brief FIFO status message */
+ PMP_MSG_TYPE_DATA = 2U /*!< \brief FIFO data message */
+
+} Pmp_MsgType_t;
+
+/*! \brief Specifies the direction of the Port Message */
+typedef enum Pmp_Direction_
+{
+ PMP_DIR_TX = 0, /*!< \brief Direction Tx (EHC -> INIC) */
+ PMP_DIR_RX = 1 /*!< \brief Direction Rx (INIC -> EHC) */
+
+} Pmp_Direction_t;
+
+/*! \brief Specifies FIFO status types */
+typedef enum Pmp_StatusType_
+{
+ PMP_STATUS_TYPE_FAILURE = 0U, /*!< \brief PMP status type "failure" */
+ PMP_STATUS_TYPE_FLOW = 1U, /*!< \brief PMP status type "flow" */
+ PMP_STATUS_TYPE_SYNCED = 4U, /*!< \brief PMP status type "synced" */
+ PMP_STATUS_TYPE_UNSYNCED_BSY = 5U, /*!< \brief PMP status type "unsynced_busy" */
+ PMP_STATUS_TYPE_UNSYNCED_RDY = 6U /*!< \brief PMP status type "unsynced_ready" */
+
+} Pmp_StatusType_t;
+
+/*! \brief Specifies FIFO status codes */
+typedef enum Pmp_StatusCode_
+{
+ PMP_STATUS_CODE_BUSY = 0U, /*!< \brief PMP status code "busy" */
+ PMP_STATUS_CODE_SUCCESS = 1U, /*!< \brief PMP status code "success" */
+ PMP_STATUS_CODE_CANCELED = 3U, /*!< \brief PMP status code "canceled" */
+ PMP_STATUS_CODE_NACK = 8U /*!< \brief PMP status code "not_acknowledge" */
+
+} Pmp_StatusCode_t;
+
+/*! \brief Specifies FIFO status codes */
+typedef enum Pmp_UnsyncReason_
+{
+ PMP_UNSYNC_R_STARTUP = 1U, /*!< \brief PMP status code, UnsyncReason "INIC Startup" */
+ PMP_UNSYNC_R_REINIT = 2U, /*!< \brief PMP status code, UnsyncReason "Re-init of another FIFO" */
+ PMP_UNSYNC_R_COMMAND = 3U, /*!< \brief PMP status code, UnsyncReason "By sync or un-sync command" */
+ PMP_UNSYNC_R_ACK_TIMEOUT = 4U, /*!< \brief PMP status code, UnsyncReason "Missing EHC Rx acknowledge" */
+ PMP_UNSYNC_R_WD_TIMEOUT = 5U, /*!< \brief PMP status code, UnsyncReason "Missing EHC status request" */
+ PMP_UNSYNC_R_TX_TIMEOUT = 6U /*!< \brief PMP status code, UnsyncReason "Missing EHC read, or blocked communication" */
+
+} Pmp_UnsyncReason_t;
+
+/*! \brief Specifies FIFO command types */
+typedef enum Pmp_CommandType_
+{
+ PMP_CMD_TYPE_REQ_STATUS = 0U, /*!< \brief PMP command type "request_status" */
+ PMP_CMD_TYPE_MSG_ACTION = 1U, /*!< \brief PMP command type "message_action" */
+ /* PMP_CMD_TYPE_TRIGGER_NAOMDP = 2U, < (reserved identifier) */
+ PMP_CMD_TYPE_SYNCHRONIZATION = 4U /*!< \brief PMP command type "synchronization" */
+
+} Pmp_CommandType_t;
+
+/*! \brief Specifies FIFO command codes */
+typedef enum Pmp_CommandCode_
+{
+ PMP_CMD_CODE_REQ_STATUS = 0U, /*!< \brief PMP command code "request_status" */
+ /* PMP_CMD_CODE_TRIGGER_NAOMDP = 0U, < (reserved identifier)*/
+ PMP_CMD_CODE_ACTION_RETRY = 1U, /*!< \brief PMP command type "request_status" */
+ PMP_CMD_CODE_ACTION_CANCEL = 2U, /*!< \brief PMP command type "request_status" */
+ PMP_CMD_CODE_ACTION_CANCEL_ALL = 3U, /*!< \brief PMP command type "request_status" */
+ PMP_CMD_CODE_UNSYNC = 10U, /*!< \brief PMP command type "request_status" */
+ PMP_CMD_CODE_SYNC = 21U /*!< \brief PMP command type "request_status" */
+
+} Pmp_CommandCode_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Header buffer operations */
+/*------------------------------------------------------------------------------------------------*/
+extern void Pmp_SetPml(uint8_t header[], uint8_t length);
+extern void Pmp_SetPmhl(uint8_t header[], uint8_t length);
+extern void Pmp_SetFph(uint8_t header[], Pmp_FifoId_t id, Pmp_MsgType_t type);
+extern void Pmp_SetExtType(uint8_t header[], uint8_t type, uint8_t code);
+extern void Pmp_SetSid(uint8_t header[], uint8_t sid);
+
+extern uint8_t Pmp_GetPml(uint8_t header[]);
+extern uint8_t Pmp_GetPmhl(uint8_t header[]);
+extern Pmp_FifoId_t Pmp_GetFifoId(uint8_t header[]);
+extern Pmp_MsgType_t Pmp_GetMsgType(uint8_t header[]);
+extern uint8_t Pmp_GetSid(uint8_t header[]);
+extern uint8_t Pmp_GetDataSize(uint8_t header[]);
+extern uint8_t Pmp_GetData(uint8_t header[], uint8_t index);
+extern bool Pmp_VerifyHeader(uint8_t header[], uint8_t buf_len);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class CPmh */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Defines the content of a Port Message Header
+ * \details The current structure does not support "direction" and "retransmitted" flag.
+ */
+typedef struct CPmh_
+{
+ uint8_t pml; /*!< \brief Port Message length */
+ uint8_t pmhl; /*!< \brief Port Message Header length */
+ Pmp_MsgType_t msg_type; /*!< \brief Port Message type */
+ Pmp_FifoId_t fifo_id; /*!< \brief FIFO identifier */
+ uint8_t sid; /*!< \brief The SequenceId */
+ uint8_t ext_type; /*!< \brief status or content type */
+
+} CPmh;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Function Prototypes */
+/*------------------------------------------------------------------------------------------------*/
+extern void Pmh_Ctor(CPmh *self);
+extern void Pmh_BuildHeader(CPmh *self, uint8_t data[]);
+extern void Pmh_DecodeHeader(CPmh *self, uint8_t data[]);
+extern void Pmh_SetFph(CPmh *self, Pmp_FifoId_t fifo_id, Pmp_MsgType_t msg_type);
+extern Pmp_StatusType_t Pmh_GetExtStatusType(CPmh *self);
+extern Pmp_StatusCode_t Pmh_GetExtStatusCode(CPmh *self);
+extern Pmp_CommandCode_t Pmh_GetExtCommandCode(CPmh *self);
+extern Pmp_CommandType_t Pmh_GetExtCommandType(CPmh *self);
+extern void Pmh_SetExtType(CPmh *self, uint8_t type, uint8_t code);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* MNS_PMP_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_pool.c b/mnsl/mns_pool.c
new file mode 100644
index 0000000..870efd3
--- /dev/null
+++ b/mnsl/mns_pool.c
@@ -0,0 +1,127 @@
+/*
+ * 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 Implementation of message pool class
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_POOL
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_pool.h"
+#include "mns_misc.h"
+#include "mns_trace.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal constants */
+/*------------------------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of message pool class
+ * \param self The instance
+ * \param messages Reference to an array of message objects
+ * \param size Number of message objects the \c messages array is comprising.
+ * \param mns_inst_id MOST NetServices instance ID
+ */
+void Pool_Ctor(CPool *self, CMessage messages[], uint16_t size, uint8_t mns_inst_id)
+{
+ uint16_t index;
+
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ self->mns_inst_id = mns_inst_id;
+ self->initial_size = size;
+ self->messages = messages;
+
+ Dl_Ctor(&self->message_list, self->mns_inst_id);
+
+ for (index = 0U; index < size; index++)
+ {
+ Msg_Ctor(&messages[index]);
+ Msg_SetPoolReference(&messages[index], self);
+ Dl_InsertTail(&self->message_list, Msg_GetNode(&messages[index]));
+ }
+}
+
+/*! \brief Retrieves a message object from the pool
+ * \param self The instance
+ * \return Reference to the CMessage structure if a message is available.
+ * Otherwise \c NULL.
+ */
+CMessage* Pool_GetMsg(CPool *self)
+{
+ CMessage *msg = NULL;
+ CDlNode *node = Dl_PopHead(&self->message_list);
+
+ if (node != NULL)
+ {
+ msg = (CMessage*)node->data_ptr;
+ }
+
+ return msg;
+}
+
+/*! \brief Returns a message object to the pool pre-assigned pool
+ * \param msg_ptr Reference to the message object which needs
+ * to be returned to the pool.
+ */
+void Pool_ReturnMsg(CMessage *msg_ptr)
+{
+ CPool *pool_ptr = (CPool*)Msg_GetPoolReference(msg_ptr);
+
+ if (pool_ptr != NULL)
+ {
+ TR_ASSERT(pool_ptr->mns_inst_id, "[POOL]", (Pool_GetCurrentSize(pool_ptr) < pool_ptr->initial_size));
+ Dl_InsertTail(&pool_ptr->message_list, Msg_GetNode(msg_ptr));
+ }
+ else
+ {
+ TR_ERROR((pool_ptr->mns_inst_id, "[POOL]", "Pool_ReturnMsg(): released msg_ptr=0x%p without pool reference", 1U, msg_ptr));
+ }
+}
+
+/*! \brief Retrieves the current number of available message objects in the pool
+ * \param self The instance
+ * \return The current number of available message objects in the pool
+ */
+uint16_t Pool_GetCurrentSize(CPool *self)
+{
+ uint16_t list_size = Dl_GetSize(&self->message_list);
+
+ return list_size;
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
diff --git a/mnsl/mns_pool.h b/mnsl/mns_pool.h
new file mode 100644
index 0000000..c9b6edd
--- /dev/null
+++ b/mnsl/mns_pool.h
@@ -0,0 +1,82 @@
+/*
+ * 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 Declaration of message pool class
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_POOL
+ * @{
+ */
+#ifndef MNS_POOL_H
+#define MNS_POOL_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_message.h"
+#include "mns_dl.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/*------------------------------------------------------------------------------------------------*/
+/* Class CPool */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class CMessage
+ * \details Common internal message class which embeds a list of MOST telegrams
+ */
+typedef struct CPool_
+{
+ uint16_t initial_size; /*! \brief The size of a provided message array */
+ CMessage *messages; /*! \brief Reference to a message array provided by another module */
+ CDlList message_list; /*! \brief Doubly linked list required providing available messages */
+ uint8_t mns_inst_id; /*! \brief MOST NetServices instance ID */
+
+} CPool;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Methods */
+/*------------------------------------------------------------------------------------------------*/
+extern void Pool_Ctor(CPool *self, CMessage messages[], uint16_t size, uint8_t mns_inst_id);
+extern CMessage* Pool_GetMsg(CPool *self);
+extern void Pool_ReturnMsg(CMessage *msg_ptr);
+extern uint16_t Pool_GetCurrentSize(CPool *self);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_POOL_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_ret.h b/mnsl/mns_ret.h
new file mode 100644
index 0000000..50305bf
--- /dev/null
+++ b/mnsl/mns_ret.h
@@ -0,0 +1,115 @@
+/*
+ * 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 This header file contains standard return values used by MOST NetServices functions
+ * and methods.
+ * \addtogroup G_MNS_MISC_RET_RES
+ * @{
+ */
+
+#ifndef MNS_RET_H
+#define MNS_RET_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Enumerations */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Standard return codes used for synchronous response */
+typedef enum Mns_Return_
+{
+ MNS_RET_SUCCESS = 0x00, /*!< \brief Operation successfully completed */
+ MNS_RET_ERR_PARAM = 0x01, /*!< \brief At least one parameter exceeds its
+ admissible range */
+ MNS_RET_ERR_BUFFER_OVERFLOW = 0x02, /*!< \brief Buffer overflow or service busy */
+ MNS_RET_ERR_NOT_AVAILABLE = 0x03, /*!< \brief Functionality not available */
+ MNS_RET_ERR_NOT_SUPPORTED = 0x04, /*!< \brief This function is not supported by this
+ derivative of INIC / physical layer / MOST
+ speed */
+ MNS_RET_ERR_INVALID_SHADOW = 0x05, /*!< \brief The requested information is not yet
+ available */
+ MNS_RET_ERR_ALREADY_SET = 0x06, /*!< \brief The value to be set is already set. The
+ application can therefore be aware that no
+ message will be send to INIC and no
+ callback will be called */
+ MNS_RET_ERR_API_LOCKED = 0x07, /*!< \brief INIC performs already requested function. */
+ MNS_RET_ERR_NOT_INITIALIZED = 0x08 /*!< \brief MOST NetServices is not initialized */
+
+} Mns_Return_t;
+
+/*! \brief Result codes used for asynchronous response */
+typedef enum Mns_Result_
+{
+ MNS_RES_SUCCESS = 0x00, /*!< \brief Operation successfully completed */
+ MNS_RES_ERR_MOST_STANDARD = 0x01, /*!< \brief MOST standard error occurred */
+ MNS_RES_ERR_BUSY = 0x02, /*!< \brief Function currently busy */
+ MNS_RES_ERR_PROCESSING = 0x03, /*!< \brief Processing error occurred */
+ MNS_RES_ERR_CONFIGURATION = 0x04, /*!< \brief Configuration error occurred */
+ MNS_RES_ERR_SYSTEM = 0x05, /*!< \brief System error occurred */
+ MNS_RES_ERR_TIMEOUT = 0x06, /*!< \brief Timeout occurred */
+ MNS_RES_ERR_TRANSMISSION = 0x07 /*!< \brief Transmission error occurred */
+
+} Mns_Result_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Standard result structure which provides fields for detailed status and
+ * error information
+ * \details \mns_ic_started{ The \ref P_UM_SYNC_AND_ASYNC_RESULTS section in \c Getting \c Started will provide you with more detailed information concerning the info pointer and the error code. }
+ */
+typedef struct Mns_StdResult_
+{
+ Mns_Result_t code; /*!< \brief Result/Error code */
+ uint8_t *info_ptr; /*!< \brief INIC error data */
+ uint8_t info_size; /*!< \brief Size of the INIC error data in bytes */
+
+} Mns_StdResult_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Function signature used for MOST NetServices standard result callbacks
+ * \param result Result of the callback
+ */
+typedef void (*Mns_StdResultCb_t)(Mns_StdResult_t result);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_RET_H */
+
+/*!
+ * @}
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_scheduler.c b/mnsl/mns_scheduler.c
new file mode 100644
index 0000000..1fc5273
--- /dev/null
+++ b/mnsl/mns_scheduler.c
@@ -0,0 +1,259 @@
+/*
+ * 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 Implementation of the scheduler module. The module consists of the two classes
+ * CScheduler and CService.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_SCHEDULER
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_scheduler.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Constants */
+/*------------------------------------------------------------------------------------------------*/
+const Srv_Event_t SRV_EMPTY_EVENT_MASK = (Srv_Event_t)0x00000000; /*!< \brief Empty event mask */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static bool Scd_SearchSlot(void *current_prio_ptr, void *new_prio_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CScheduler */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the scheduler class.
+ * \param self Instance pointer
+ * \param init_ptr Reference to the initialization data
+ */
+void Scd_Ctor(CScheduler *self, Scd_InitData_t *init_ptr)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ self->mns_inst_id = init_ptr->mns_inst_id;
+ Dl_Ctor(&self->srv_list, self->mns_inst_id);
+ Ssub_Ctor(&self->service_request_subject, self->mns_inst_id);
+ (void)Ssub_AddObserver(&self->service_request_subject,
+ init_ptr->service_request_obs_ptr);
+ self->scd_srv_is_running = false;
+}
+
+/*! \brief Add the given service to the scheduler. All services are arranged in priority order.
+ * A service with a higher priority will execute before a service with a lower priority.
+ * \param self Instance pointer
+ * \param srv_ptr Reference of the service which shall be added
+ * \return SCD_OK: Service added
+ * \return SCD_SRV_ALREADY_LISTED: Services already listed
+ */
+Scd_Ret_t Scd_AddService(CScheduler *self, CService *srv_ptr)
+{
+ Scd_Ret_t ret_val;
+
+ /* Check that service is not already part of scheduler */
+ if(false == Dl_IsNodeInList(&self->srv_list, &srv_ptr->list_node))
+ {
+ /* Search slot where the service must be inserted depending on the priority value. */
+ CDlNode *result_ptr = Dl_Foreach(&self->srv_list, &Scd_SearchSlot, &srv_ptr->priority);
+
+ if(NULL != result_ptr) /* Slot found? */
+ {
+ Dl_InsertBefore(&self->srv_list, result_ptr, &srv_ptr->list_node);
+ }
+ else /* No slot found -> Insert as last node */
+ {
+ Dl_InsertTail(&self->srv_list, &srv_ptr->list_node);
+ }
+ /* Create back link service -> scheduler */
+ srv_ptr->scd_ptr = self;
+ Dln_SetData(&srv_ptr->list_node, &srv_ptr->priority);
+ ret_val = SCD_OK;
+ }
+ else /* Service is already part of schedulers list */
+ {
+ ret_val = SCD_SRV_ALREADY_LISTED;
+ }
+
+ return ret_val;
+}
+
+/*! \brief Remove the given service from the schedulers list.
+ * \param self Instance pointer
+ * \param srv_ptr Reference of the service which shall be removed
+ * \return SCD_OK: Service removed
+ * \return SCD_UNKNOWN_SRV: Unknown service can not be removed
+ */
+Scd_Ret_t Scd_RemoveService(CScheduler *self, CService *srv_ptr)
+{
+ Scd_Ret_t ret_val = SCD_OK;
+
+ /* Error occurred? */
+ if(DL_UNKNOWN_NODE == Dl_Remove(&self->srv_list, &srv_ptr->list_node))
+ {
+ ret_val = SCD_UNKNOWN_SRV;
+ }
+
+ return ret_val;
+}
+
+/*! \brief Service function of the scheduler module.
+ * \param self Instance pointer
+ */
+void Scd_Service(CScheduler *self)
+{
+ CService *current_srv_ptr = (CService *)(void*)self->srv_list.head;
+
+ /* Scheduler service is running. Important for event handling */
+ self->scd_srv_is_running = true;
+
+ while(NULL != current_srv_ptr) /* Process registered services */
+ {
+ if(NULL != current_srv_ptr->service_fptr)
+ {
+ /* Are events pending for the current service */
+ if(SRV_EMPTY_EVENT_MASK != current_srv_ptr->event_mask)
+ {
+ /* Execute service callback function */
+ current_srv_ptr->service_fptr(current_srv_ptr->instance_ptr);
+ /* Was the current service removed from the schedulers list? */
+ if((current_srv_ptr->list_node.prev == NULL) && (current_srv_ptr->list_node.next == NULL))
+ {
+ break; /* Abort scheduler service */
+ }
+ }
+ }
+ current_srv_ptr = (CService *)(void*)current_srv_ptr->list_node.next;
+ }
+ /* Scheduler services finished */
+ self->scd_srv_is_running = false;
+}
+
+/*! \brief Searches for pending events.
+ * \param self Instance pointer
+ * \return true: At least one event is active
+ * \return false: No event is pending
+ */
+bool Scd_AreEventsPending(CScheduler *self)
+{
+ bool ret_val = false;
+ CService *current_srv_ptr = (CService *)(void*)self->srv_list.head;
+
+ while(NULL != current_srv_ptr)
+ {
+ if(SRV_EMPTY_EVENT_MASK != current_srv_ptr->event_mask)
+ {
+ ret_val = true;
+ break;
+ }
+ current_srv_ptr = (CService *)(void*)current_srv_ptr->list_node.next;
+ }
+
+ return ret_val;
+}
+
+/*! \brief Searches the slot where the new service has to be inserted. The position depends on
+ * the given priority. If a the priority of the new service is higher than the priority
+ * of the current service \c true is returned which stops the search.
+ * \param current_prio_ptr Current service which is analyzed
+ * \param new_prio_ptr Priority of the new service
+ * \return false: The priority of the current service is greater than the new priority
+ * \return true: The priority of the current service is less than or equal to the new priority
+ */
+static bool Scd_SearchSlot(void *current_prio_ptr, void *new_prio_ptr)
+{
+ uint8_t current_prio_ptr_ = *((uint8_t *)current_prio_ptr);
+ uint8_t new_prio_ = *((uint8_t*)new_prio_ptr);
+ bool ret_val = false;
+
+ if(current_prio_ptr_ <= new_prio_)
+ {
+ ret_val = true;
+ }
+
+ return ret_val;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CService */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Parameter constructor of the service class.
+ * \param self Instance pointer
+ * \param instance_ptr Reference to object which contains the corresponding service
+ * \param priority Priority of the service
+ * \param service_fptr Service callback
+ */
+void Srv_Ctor(CService *self, uint8_t priority, void *instance_ptr, Srv_Cb_t service_fptr)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ Dln_Ctor(&self->list_node, NULL);
+ self->priority = priority;
+ self->instance_ptr = instance_ptr;
+ self->service_fptr = service_fptr;
+}
+
+/*! \brief Sets events for the given service according to the given event mask.
+ * \param self Instance pointer
+ * \param event_mask Mask of the events to be set
+ */
+void Srv_SetEvent(CService *self, Srv_Event_t event_mask)
+{
+ self->event_mask |= event_mask;
+ if(false == self->scd_ptr->scd_srv_is_running)
+ {
+ Ssub_Notify(&self->scd_ptr->service_request_subject, NULL, false);
+ }
+}
+
+/*! \brief The function returns the current state of all event bits of the service.
+ * \param self Instance pointer
+ * \param event_mask_ptr Reference to the memory of the returned event mask
+ */
+void Srv_GetEvent(CService *self, Srv_Event_t *event_mask_ptr)
+{
+ *event_mask_ptr = self->event_mask;
+}
+
+/*! \brief Clears events for the given service according to the given event mask.
+ * \param self Instance pointer
+ * \param event_mask Mask of the events to be clear
+ */
+void Srv_ClearEvent(CService *self, Srv_Event_t event_mask)
+{
+ self->event_mask &= ~event_mask;
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_scheduler.h b/mnsl/mns_scheduler.h
new file mode 100644
index 0000000..624d0ad
--- /dev/null
+++ b/mnsl/mns_scheduler.h
@@ -0,0 +1,148 @@
+/*
+ * 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 the scheduler module. The module consists of the two classes
+ * CScheduler and CService.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_SCHEDULER
+ * @{
+ */
+
+#ifndef MNS_SCHEDULER_H
+#define MNS_SCHEDULER_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+#include "mns_dl.h"
+#include "mns_obs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Type definitions */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Function signature used for MNS request callback function */
+typedef void (*Scd_MnsServiceRequest_t)(void);
+/*! \brief Function signature used for service callback functions
+ * \param self Instance pointer
+ */
+typedef void (*Srv_Cb_t)(void *self);
+/*! \brief Data type of event masks */
+typedef uint32_t Srv_Event_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Definitions */
+/*------------------------------------------------------------------------------------------------*/
+extern const Srv_Event_t SRV_EMPTY_EVENT_MASK; /*!< \brief Empty event mask */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Enumerators */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Standard return values of scheduler module. */
+typedef enum Scd_Ret_
+{
+ SCD_OK, /*!< \brief No error */
+ SCD_UNKNOWN_SRV, /*!< \brief Service is unknown */
+ SCD_SRV_ALREADY_LISTED /*!< \brief Service is already part of the schedulers list */
+
+} Scd_Ret_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Initialization structure of the scheduler module. */
+typedef struct Scd_InitData_
+{
+ /*! \brief Observer to request a MNS service call */
+ CSingleObserver *service_request_obs_ptr;
+ /*! \brief MOST NetServices instance ID */
+ uint8_t mns_inst_id;
+
+} Scd_InitData_t;
+
+/*! \brief Class structure of the scheduler. */
+typedef struct CScheduler_
+{
+ /*! \brief Subject to request a MNS service call */
+ CSingleSubject service_request_subject;
+ /*! \brief Service list of the scheduler */
+ CDlList srv_list;
+ /*! \brief Indicates if the scheduler services is running */
+ bool scd_srv_is_running;
+ /*! \brief MOST NetServices instance ID */
+ uint8_t mns_inst_id;
+
+} CScheduler;
+
+/*! \brief Class structure of services used by the scheduler. */
+typedef struct CService_
+{
+ CDlNode list_node; /*!< \brief Administration area for the linked list */
+ CScheduler *scd_ptr; /*!< \brief Back link to scheduler */
+ void *instance_ptr; /*!< \brief Reference of instance passed to service_fptr() */
+ Srv_Cb_t service_fptr; /*!< \brief Reference of the service callback function */
+ Srv_Event_t event_mask; /*!< \brief Event mask of the service */
+ uint8_t priority; /*!< \brief Priority of the service */
+
+} CService;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CScheduler */
+/*------------------------------------------------------------------------------------------------*/
+extern void Scd_Ctor(CScheduler *self, Scd_InitData_t *init_ptr);
+extern void Scd_Service(CScheduler *self);
+extern Scd_Ret_t Scd_AddService(CScheduler *self, CService *srv_ptr);
+extern Scd_Ret_t Scd_RemoveService(CScheduler *self, CService *srv_ptr);
+extern bool Scd_AreEventsPending(CScheduler *self);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CService */
+/*------------------------------------------------------------------------------------------------*/
+extern void Srv_Ctor(CService *self, uint8_t priority, void *instance_ptr, Srv_Cb_t service_fptr);
+extern void Srv_SetEvent(CService *self, Srv_Event_t event_mask);
+extern void Srv_GetEvent(CService *self, Srv_Event_t *event_mask_ptr);
+extern void Srv_ClearEvent(CService *self, Srv_Event_t event_mask);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_SCHEDULER_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_segmentation.c b/mnsl/mns_segmentation.c
new file mode 100644
index 0000000..7bfa2ff
--- /dev/null
+++ b/mnsl/mns_segmentation.c
@@ -0,0 +1,555 @@
+/*
+ * 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 Implementation of AMS Segmentation Class
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_AMSSEGM
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_segmentation.h"
+#include "mns_ams.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal constants */
+/*------------------------------------------------------------------------------------------------*/
+ /*!\brief Timeout for garbage collector */
+static const uint16_t SEGM_GC_TIMEOUT = 5000U; /* parasoft-suppress MISRA2004-8_7 "intended usage as configuration parameter" */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal typedefs */
+/*------------------------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static Mns_AmsRx_Msg_t *Segm_RxRetrieveProcessingHandle(CSegmentation *self, Msg_MostTel_t *tel_ptr);
+static void Segm_RxStoreProcessingHandle(CSegmentation *self, Mns_AmsRx_Msg_t *msg_ptr);
+static bool Segm_RxSearchProcessingHandle(void *current_data, void *search_data);
+static bool Segm_RxGcSetLabel(void *current_data, void *search_data);
+static Mns_AmsRx_Msg_t* Segm_RxProcessTelId0(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr);
+static void Segm_RxProcessTelId1(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr);
+static void Segm_RxProcessTelId2(CSegmentation *self, Msg_MostTel_t *tel_ptr);
+static Mns_AmsRx_Msg_t* Segm_RxProcessTelId3(CSegmentation *self, Msg_MostTel_t *tel_ptr);
+static void Segm_RxProcessTelId4(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Initialization methods */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of class CSegmentation
+ * \param self The instance
+ * \param base_ptr Reference to base services
+ * \param pool_ptr Reference to the (Rx) message pool
+ * \param rx_def_payload_sz Default memory size that is allocated when receiving segmented messages
+ * without size prefix
+ */
+void Segm_Ctor(CSegmentation *self, CBase *base_ptr, CAmsMsgPool *pool_ptr, uint16_t rx_def_payload_sz)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ self->base_ptr = base_ptr; /* initialize members */
+ self->pool_ptr = pool_ptr;
+
+ self->rx_default_payload_sz = rx_def_payload_sz;
+
+ Dl_Ctor(&self->processing_list, self->base_ptr->mns_inst_id);
+ T_Ctor(&self->gc_timer);
+ Tm_SetTimer(&self->base_ptr->tm, /* start garbage collector timer */
+ &self->gc_timer,
+ &Segm_RxGcScanProcessingHandles,
+ self,
+ SEGM_GC_TIMEOUT,
+ SEGM_GC_TIMEOUT
+ );
+}
+
+/*! \brief Constructor of class CSegmentation
+ * \param self The instance
+ * \param error_fptr Reference to segmentation error callback function
+ * \param error_inst Reference to segmentation error instance
+ */
+void Segm_AssignRxErrorHandler(CSegmentation *self, Segm_OnError_t error_fptr, void *error_inst)
+{
+ self->error_fptr = error_fptr;
+ self->error_inst = error_inst;
+}
+
+/*! \brief Performs cleanup of pending messages
+ * \param self The instance
+ */
+void Segm_Cleanup(CSegmentation *self)
+{
+ CDlNode *node_ptr = NULL;
+ /* cleanup Tx queue */
+ for (node_ptr = Dl_PopHead(&self->processing_list); node_ptr != NULL; node_ptr = Dl_PopHead(&self->processing_list))
+ {
+ Mns_AmsRx_Msg_t *rx_ptr = (Mns_AmsRx_Msg_t*)Dln_GetData(node_ptr);
+
+ Amsp_FreeRxPayload(self->pool_ptr, rx_ptr);
+ Amsp_FreeRxObj(self->pool_ptr, rx_ptr);
+ }
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Tx segmentation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Builds next MOST telegram according to given Application Messages
+ * \param self The instance
+ * \param msg_ptr Reference to the Application Message Tx handle
+ * \param tel_ptr Reference to the MOST Telegram handle
+ * \return Returns \c True if segmentation was completed for the Application Message. Otherwise \c false.
+ */
+bool Segm_TxBuildSegment(CSegmentation *self, Mns_AmsTx_Msg_t* msg_ptr, Msg_MostTel_t *tel_ptr)
+{
+ bool finished = false;
+ MISC_UNUSED(self);
+
+ tel_ptr->destination_addr = msg_ptr->destination_address;
+ tel_ptr->id.fblock_id = msg_ptr->fblock_id;
+ tel_ptr->id.instance_id = msg_ptr->instance_id;
+ tel_ptr->id.function_id = msg_ptr->function_id;
+ tel_ptr->id.op_type = msg_ptr->op_type;
+ tel_ptr->opts.llrbc = msg_ptr->llrbc;
+ tel_ptr->info_ptr = msg_ptr; /* info_ptr must carry the reference to AMS Tx message object */
+ tel_ptr->opts.cancel_id = Amsg_TxGetFollowerId(msg_ptr);
+
+ if (msg_ptr->data_size <= SEGM_MAX_SIZE_TEL) /* is single transfer? */
+ {
+ Msg_SetExtPayload((CMessage*)(void*)tel_ptr, msg_ptr->data_ptr, (uint8_t)msg_ptr->data_size, NULL);
+ finished = true;
+ }
+ else /* is segmented transfer? */
+ {
+ uint16_t next_segm_cnt = Amsg_TxGetNextSegmCnt(msg_ptr);
+
+ if (next_segm_cnt == 0xFFFFU) /* first segment: size prefixed segmented message TelId = "4" */
+ {
+ tel_ptr->tel.tel_id = 4U;
+ tel_ptr->tel.tel_data_ptr[0] = MISC_HB(msg_ptr->data_size);
+ tel_ptr->tel.tel_data_ptr[1] = MISC_LB(msg_ptr->data_size);
+ tel_ptr->tel.tel_len = 2U;
+ }
+ else /* further segments: TelId = "1,2,3" */
+ {
+ uint16_t index = next_segm_cnt * ((uint16_t)SEGM_MAX_SIZE_TEL - 1U);
+ uint16_t remaining_sz = msg_ptr->data_size - index;
+ uint8_t tel_sz = SEGM_MAX_SIZE_TEL - 1U;
+
+ if (remaining_sz < SEGM_MAX_SIZE_TEL)
+ {
+ tel_ptr->tel.tel_id = 3U; /* is last segment */
+ tel_sz = (uint8_t)remaining_sz;
+ finished = true;
+ }
+ else
+ {
+ if (0U == index)
+ {
+ tel_ptr->tel.tel_id = 1U; /* is first segment */
+ }
+ else
+ {
+ tel_ptr->tel.tel_id = 2U; /* is subsequent segment */
+ }
+ }
+
+ tel_ptr->tel.tel_cnt = (uint8_t)next_segm_cnt;
+ Msg_SetExtPayload((CMessage*)(void*)tel_ptr, &msg_ptr->data_ptr[index], tel_sz, NULL);
+ }
+
+ Amsg_TxIncrementNextSegmCnt(msg_ptr);
+ }
+
+ return finished;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Rx pools */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Retrieves a processing Rx Application message object to a corresponding MOST telegram
+ * \param self The instance
+ * \param tel_ptr Reference to the MOST telegram
+ * \return The reference to the corresponding Rx Application Message or \c NULL if no appropriate
+ * Rx Application Message is available.
+ */
+static Mns_AmsRx_Msg_t* Segm_RxRetrieveProcessingHandle(CSegmentation *self, Msg_MostTel_t *tel_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = NULL;
+ CDlNode *result_node_ptr = Dl_Foreach(&self->processing_list, &Segm_RxSearchProcessingHandle, tel_ptr);
+
+ if (result_node_ptr != NULL)
+ {
+ Dl_Ret_t ret = Dl_Remove(&self->processing_list, result_node_ptr);
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[SEGM]", (ret == DL_OK));
+ msg_ptr = (Mns_AmsRx_Msg_t*)Dln_GetData(result_node_ptr);
+ MISC_UNUSED(ret);
+ }
+
+ return msg_ptr;
+}
+
+/*! \brief Stores a processing Rx Application message object into a dedicated list
+ * \param self The instance
+ * \param msg_ptr Reference to the Rx Application Message
+ */
+static void Segm_RxStoreProcessingHandle(CSegmentation *self, Mns_AmsRx_Msg_t *msg_ptr)
+{
+ Amsg_RxSetGcMarker(msg_ptr, false);
+ Amsg_RxEnqueue(msg_ptr, &self->processing_list); /* insert at tail, since garbage collector starts at head */
+}
+
+/*! \brief Performs garbage collection of outdated message objects
+ * \param self The instance
+ */
+void Segm_RxGcScanProcessingHandles(void *self)
+{
+ CSegmentation *self_ = (CSegmentation*)self;
+ /* first remove outdated messages */
+ CDlNode *node_ptr = Dl_PeekHead(&self_->processing_list); /* get first candidate from head */
+
+ while (node_ptr != NULL)
+ {
+ Mns_AmsRx_Msg_t *msg_ptr = (Mns_AmsRx_Msg_t*)Dln_GetData(node_ptr);
+
+ if (Amsg_RxGetGcMarker(msg_ptr) != false)
+ {
+ Msg_MostTel_t tel;
+
+ Amsg_RxCopySignatureToTel(msg_ptr, &tel);
+ self_->error_fptr(self_->error_inst, &tel, SEGM_ERR_5);
+
+ (void)Dl_Remove(&self_->processing_list, node_ptr);
+
+ Amsp_FreeRxPayload(self_->pool_ptr, msg_ptr);
+ Amsp_FreeRxObj(self_->pool_ptr, msg_ptr);
+
+ node_ptr = Dl_PeekHead(&self_->processing_list); /* get next candidate from head */
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ (void)Dl_Foreach(&self_->processing_list, &Segm_RxGcSetLabel, NULL); /* set label of all remaining messages */
+}
+
+/*! \brief Sets garbage collector flags for all list members
+ * \param current_data The Application message object present in list
+ * \param search_data unused (\c NULL)
+ * \return Returns always false in order to handle all list members */
+static bool Segm_RxGcSetLabel(void *current_data, void *search_data)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = (Mns_AmsRx_Msg_t*)current_data;
+ Amsg_RxSetGcMarker(msg_ptr, true);
+ MISC_UNUSED(search_data);
+ return false;
+}
+
+/*! \brief Search routine to identify message objects with the same signature
+ * than a given MOST telegram
+ * \param current_data The Application message object present in list
+ * \param search_data The MOST Telegram object
+ * \return Returns \c true if both handles have the same functional signature,
+ * otherwise \c false. */
+static bool Segm_RxSearchProcessingHandle(void *current_data, void *search_data)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = (Mns_AmsRx_Msg_t*)current_data;
+ Msg_MostTel_t *tel_ptr = (Msg_MostTel_t*)search_data;
+
+ return Amsg_RxHandleIsIdentical(msg_ptr, tel_ptr);
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Rx segmentation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Processes segmentation for a received MOST telegram
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \param result_ptr The result of the segmentation process
+ * \return The completed Rx Application Message or \c NULL if segmentation process is still
+ * ongoing.
+ */
+Mns_AmsRx_Msg_t* Segm_RxExecuteSegmentation(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = NULL;
+ *result_ptr = SEGM_RES_OK;
+
+ switch (tel_ptr->tel.tel_id) /* parasoft-suppress MISRA2004-15_3 "ignore unexpected TelIds" */
+ {
+ case 0U:
+ msg_ptr = Segm_RxProcessTelId0(self, tel_ptr, result_ptr);
+ break;
+ case 1U:
+ Segm_RxProcessTelId1(self, tel_ptr, result_ptr);
+ break;
+ case 2U:
+ Segm_RxProcessTelId2(self, tel_ptr);
+ break;
+ case 3U:
+ msg_ptr = Segm_RxProcessTelId3(self, tel_ptr);
+ break;
+ case 4U:
+ Segm_RxProcessTelId4(self, tel_ptr, result_ptr);
+ break;
+ default:
+ break;
+ }
+
+ return msg_ptr; /* return completed message */
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="0"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \param result_ptr Result of segmentation process
+ * \return The completed Rx Application Message or \c NULL if segmentation process
+ * does not finish successfully.
+ */
+static Mns_AmsRx_Msg_t* Segm_RxProcessTelId0(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxRetrieveProcessingHandle(self, tel_ptr);
+ *result_ptr = SEGM_RES_OK;
+
+ if (msg_ptr != NULL) /* treat error: segmentation process is ongoing */
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_7);
+ Amsp_FreeRxPayload(self->pool_ptr, msg_ptr);/* free assigned user payload and throw segmentation error */
+ Amsp_FreeRxObj(self->pool_ptr, msg_ptr);
+ msg_ptr = NULL;
+ }
+ /* try to allocate handle, memory is NetServices provided (payload <= 45 bytes) */
+ msg_ptr = Amsp_AllocRxObj(self->pool_ptr, (uint16_t)tel_ptr->tel.tel_len);
+
+ if (msg_ptr == NULL)
+ {
+ msg_ptr = Amsp_AllocRxRsvd(self->pool_ptr);
+ }
+
+ if (msg_ptr != NULL) /* handle available: setup Rx Application Message */
+ {
+ Amsg_RxCopySignatureFromTel(msg_ptr, tel_ptr);
+
+ if (tel_ptr->tel.tel_len > 0U)
+ { /* copy payload to message */
+ Amsg_RxCopyToPayload(msg_ptr, tel_ptr->tel.tel_data_ptr, tel_ptr->tel.tel_len);
+ }
+ else
+ { /* set payload length to zero */
+ msg_ptr->data_ptr = NULL;
+ msg_ptr->data_size = 0U;
+ }
+ }
+ else
+ {
+ *result_ptr = SEGM_RES_RETRY; /* retry when next Rx object is released */
+ }
+
+ return msg_ptr;
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="1"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \param result_ptr Result of segmentation process
+ */
+static void Segm_RxProcessTelId1(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr)
+{
+ *result_ptr = SEGM_RES_OK;
+
+ if (tel_ptr->tel.tel_cnt != 0U) /* handle incorrect tel_cnt */
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_3);
+ }
+ else /* tel_cnt is correct -> continue segmentation */
+ {
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxRetrieveProcessingHandle(self, tel_ptr);
+ bool is_size_prefixed = false;
+
+ if (msg_ptr != NULL) /* has previous message */
+ {
+ if ((Amsg_RxGetExpTelCnt(msg_ptr) != 0U) || (msg_ptr->data_size > 0U))
+ { /* error: previous message already contains segments */
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_7);
+ Amsp_FreeRxPayload(self->pool_ptr, msg_ptr);
+ Amsg_RxHandleSetup(msg_ptr); /* initialize message for re-use */
+ }
+ else /* message and payload had been allocated by TelId '4' */
+ {
+ is_size_prefixed = true;
+ }
+ }
+ else /* allocate message object if pre-allocation was not initiated by TelId "4" */
+ {
+ msg_ptr = Amsp_AllocRxObj(self->pool_ptr, 0U);
+ }
+
+ if (msg_ptr != NULL) /* now allocate payload */
+ {
+ if (is_size_prefixed == false)
+ {
+ Amsg_RxCopySignatureFromTel(msg_ptr, tel_ptr); /* save signature and try to allocate */
+ (void)Amsp_AllocRxPayload(self->pool_ptr, self->rx_default_payload_sz, msg_ptr);
+ }
+
+ if (!Amsg_RxHasExternalPayload(msg_ptr)) /* allocation of payload failed */
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_2);
+ Amsp_FreeRxObj(self->pool_ptr, msg_ptr);
+ msg_ptr = NULL;
+ }
+ else /* allocation of payload succeeded */
+ {
+ (void)Amsg_RxAppendPayload(msg_ptr, tel_ptr);
+ Segm_RxStoreProcessingHandle(self, msg_ptr);
+ msg_ptr = NULL;
+ }
+ }
+ else /* no message object allocated */
+ { /* send segmentation error */
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_4);
+ }
+ }
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="2"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ */
+static void Segm_RxProcessTelId2(CSegmentation *self, Msg_MostTel_t *tel_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxProcessTelId3(self, tel_ptr); /* pretend having TelId '2' but store the */
+ /* assembled message again */
+ if (msg_ptr != NULL)
+ {
+ Segm_RxStoreProcessingHandle(self, msg_ptr);
+ }
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="3"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \return The assembled Rx Application Message or \c NULL if segmentation process
+ * did not process successfully.
+ */
+static Mns_AmsRx_Msg_t* Segm_RxProcessTelId3(CSegmentation *self, Msg_MostTel_t *tel_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxRetrieveProcessingHandle(self, tel_ptr);
+
+ if (msg_ptr == NULL) /* is first segment missing */
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_1);
+ }
+ else
+ {
+ uint8_t exp_tel_cnt = Amsg_RxGetExpTelCnt(msg_ptr);
+
+ if ((exp_tel_cnt == 0U) && (msg_ptr->data_size == 0U))
+ { /* error: did not receive first segment */
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_1);
+ Segm_RxStoreProcessingHandle(self, msg_ptr);
+ msg_ptr = NULL;
+ }
+ else if (exp_tel_cnt != tel_ptr->tel.tel_cnt)
+ { /* has wrong TelCnt */
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_3);
+ Segm_RxStoreProcessingHandle(self, msg_ptr);
+ msg_ptr = NULL;
+ }
+
+ if (msg_ptr != NULL)
+ {
+ bool succ = Amsg_RxAppendPayload(msg_ptr, tel_ptr);
+
+ if (succ == false)
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_2);
+ Amsp_FreeRxPayload(self->pool_ptr, msg_ptr);
+ Amsp_FreeRxObj(self->pool_ptr, msg_ptr);
+ msg_ptr = NULL;
+ }
+ }
+ }
+
+ return msg_ptr;
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="4"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \param result_ptr Result of segmentation process
+ */
+static void Segm_RxProcessTelId4(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr)
+{
+ *result_ptr = SEGM_RES_OK;
+
+ if (tel_ptr->tel.tel_len >= 2U) /* telegrams has necessary length */
+ {
+ uint16_t msg_size;
+ MISC_DECODE_WORD(&msg_size, tel_ptr->tel.tel_data_ptr);
+
+ if (msg_size > SEGM_MAX_SIZE_TEL) /* application message has correct size */
+ {
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxRetrieveProcessingHandle(self, tel_ptr);
+
+ if (msg_ptr != NULL) /* treat error: segmentation process is ongoing */
+ {
+ Amsp_FreeRxPayload(self->pool_ptr, msg_ptr);
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_7);
+ Amsg_RxHandleSetup(msg_ptr); /* initialize message for re-use */
+ }
+ else
+ { /* try to allocate handle, memory is NetServices provided (payload <= 45 bytes) */
+ msg_ptr = Amsp_AllocRxObj(self->pool_ptr, 0U);
+ }
+
+ if (msg_ptr != NULL) /* allocation succeeded: decode length and allocate payload */
+ {
+ Amsg_RxCopySignatureFromTel(msg_ptr, tel_ptr);
+ (void)Amsp_AllocRxPayload(self->pool_ptr, msg_size, msg_ptr);
+ Segm_RxStoreProcessingHandle(self, msg_ptr);/* store handle and don't care if payload was allocated or not */
+ msg_ptr = NULL; /* segmentation error 2 is treated by TelId 1 */
+ }
+ else
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_4);
+ }
+ }
+ }
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_segmentation.h b/mnsl/mns_segmentation.h
new file mode 100644
index 0000000..1295be3
--- /dev/null
+++ b/mnsl/mns_segmentation.h
@@ -0,0 +1,146 @@
+/*
+ * 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 AMS Segmentation Class
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_AMSSEGM
+ * @{
+ */
+
+#ifndef MNS_SEGMENTATION_H
+#define MNS_SEGMENTATION_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_message.h"
+#include "mns_amsmessage.h"
+#include "mns_amspool.h"
+#include "mns_base.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macros */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Defines the maximum payload size of a single transfer in bytes */
+#define SEGM_MAX_SIZE_TEL 45U
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Collection of possible segmentation errors */
+typedef enum Segm_Error_
+{
+ SEGM_ERR_1 = 1, /*!< \brief The first segment is missing. */
+
+ SEGM_ERR_2 = 2, /*!< \brief The device is not able to receive a message of this size.
+ * MNS specific: The allocation of user provided payload failed.
+ */
+ SEGM_ERR_3 = 3, /*!< \brief Unexpected segment number. */
+
+ SEGM_ERR_4 = 4, /*!< \brief Too many unfinished segmentation messages were pending. */
+
+ SEGM_ERR_5 = 5, /*!< \brief A timeout occurred while waiting for the next segment. */
+
+ SEGM_ERR_6 = 6, /*!< \brief The Device is not capable to handle segmented messages.
+ * MNS specific: The application did not assign the payload allocation
+ * function in Mns_Ams_InitData_t prior calling Mns_Init().
+ */
+ SEGM_ERR_7 = 7 /*!< \brief Segmented message has not been finished before the arrival of
+ * another message with the identical FBlockID, InstID, FktID, and
+ * OPType sent by the same node.
+ */
+} Segm_Error_t;
+
+/*! \brief Segmentation result */
+typedef enum Segm_Result_
+{
+ SEGM_RES_OK, /*!< \brief Telegram was processed */
+ SEGM_RES_RETRY /*!< \brief Telegram shall be processed again as soon as messages are freed to the Rx pool */
+
+} Segm_Result_t;
+
+/*! \brief Callback function to notify that a segmentation error has occurred
+ * \param self The instance
+ * \param tel_ptr The affected telegram
+ * \param error The segmentation error code (1..7)
+ */
+typedef void (*Segm_OnError_t)(void *self, Msg_MostTel_t *tel_ptr, Segm_Error_t error);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief AMS Segmentation Class
+ * \details Performs Tx and Rx Segmentation
+ */
+typedef struct CSegmentation_
+{
+ CBase *base_ptr; /*!< \brief Reference to base services */
+ CAmsMsgPool *pool_ptr; /*!< \brief Reference to object/payload pool */
+
+ Segm_OnError_t error_fptr; /*!< \brief Callback function to notify segmentation errors */
+ void *error_inst; /*!< \brief Instance which is notified on segmentation errors */
+
+ CDlList processing_list; /*!< \brief Segmented and un-finished Rx messages */
+ CTimer gc_timer; /*!< \brief Timer to trigger the garbage collector */
+ uint16_t rx_default_payload_sz; /*!< \brief Payload size that shall be allocated if size-prefixes
+ * segmentation message is missing */
+
+} CSegmentation;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Initialization Methods */
+/*------------------------------------------------------------------------------------------------*/
+extern void Segm_Ctor(CSegmentation *self, CBase *base_ptr, CAmsMsgPool *pool_ptr, uint16_t rx_def_payload_sz);
+extern void Segm_AssignRxErrorHandler(CSegmentation *self, Segm_OnError_t error_fptr, void *error_inst);
+extern void Segm_Cleanup(CSegmentation *self);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Public method prototypes */
+/*------------------------------------------------------------------------------------------------*/
+extern bool Segm_TxBuildSegment(CSegmentation *self, Mns_AmsTx_Msg_t *msg_ptr, Msg_MostTel_t *tel_ptr);
+extern Mns_AmsRx_Msg_t* Segm_RxExecuteSegmentation(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr);
+extern void Segm_RxGcScanProcessingHandles(void *self);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* MNS_SEGMENTATION_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_telqueue.c b/mnsl/mns_telqueue.c
new file mode 100644
index 0000000..c250507
--- /dev/null
+++ b/mnsl/mns_telqueue.c
@@ -0,0 +1,119 @@
+/*
+ * 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 Implementation of class CTelQueue
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_MSG_QUEUE
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_telqueue.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal constants */
+/*------------------------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of class CTelQueue
+ * \param self The instance
+ * \param mns_inst_id MOST NetServices instance id
+ */
+void Telq_Ctor(CTelQueue *self, uint8_t mns_inst_id)
+{
+ self->mns_inst_id = mns_inst_id;
+ Dl_Ctor(&self->list, self->mns_inst_id);
+}
+
+/*! \brief Retrieves the head object of the telegram queue
+ * \param self The instance
+ * \return Reference to the telegram if a telegram object is available.
+ * Otherwise \c NULL.
+ */
+Msg_MostTel_t* Telq_Dequeue(CTelQueue *self)
+{
+ Msg_MostTel_t *tel_ptr = NULL;
+ CDlNode *node_ptr = Dl_PopHead(&self->list);
+
+ if (node_ptr != NULL)
+ {
+ tel_ptr = (Msg_MostTel_t*)Dln_GetData(node_ptr);
+ }
+
+ return tel_ptr;
+}
+
+/*! \brief Retrieves a reference to the head object
+ * without removing it from the telegram queue
+ * \param self The instance
+ * \return Reference to the telegram if a telegram object is available.
+ * Otherwise \c NULL.
+ */
+Msg_MostTel_t* Telq_Peek(CTelQueue *self)
+{
+ Msg_MostTel_t *tel_ptr = NULL;
+ CDlNode *node_ptr = Dl_PeekHead(&self->list);
+
+ if (node_ptr != NULL)
+ {
+ tel_ptr = (Msg_MostTel_t*)Dln_GetData(node_ptr);
+ }
+
+ return tel_ptr;
+}
+
+/*! \brief Adds a telegram to the tail of the queue
+ * \param self The instance
+ * \param tel_ptr Reference to the telegram
+ */
+void Telq_Enqueue(CTelQueue *self, Msg_MostTel_t *tel_ptr)
+{
+ Dl_InsertTail(&self->list, Msg_GetNode((CMessage*)(void*)tel_ptr));
+}
+
+/*! \brief Retrieves the current number of objects in the telegram queue
+ * \param self The instance
+ * \return The current number of available telegram objects in the pool
+ */
+uint8_t Telq_GetSize(CTelQueue *self)
+{
+ return (uint8_t)Dl_GetSize(&self->list);
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_telqueue.h b/mnsl/mns_telqueue.h
new file mode 100644
index 0000000..2a86387
--- /dev/null
+++ b/mnsl/mns_telqueue.h
@@ -0,0 +1,93 @@
+/*
+ * 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 Declaration of class CTelQueue
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_MSG_QUEUE
+ * @{
+ */
+
+#ifndef MNS_MSGQUEUE_H
+#define MNS_MSGQUEUE_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_message.h"
+#include "mns_dl.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macros */
+/*------------------------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class CTelQueue */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class CTelQueue
+ * \details Internal class to queue MOST telegrams
+ */
+typedef struct CTelQueue_
+{
+ CDlList list; /*! \brief Doubly linked list */
+ uint8_t mns_inst_id; /*! \brief MOST NetServices instance ID */
+
+} CTelQueue;
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Methods */
+/*------------------------------------------------------------------------------------------------*/
+extern void Telq_Ctor(CTelQueue *self, uint8_t mns_inst_id);
+extern Msg_MostTel_t* Telq_Dequeue(CTelQueue *self);
+extern Msg_MostTel_t* Telq_Peek(CTelQueue *self);
+extern void Telq_Enqueue(CTelQueue *self, Msg_MostTel_t *tel_ptr);
+extern uint8_t Telq_GetSize(CTelQueue *self);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_MSGQUEUE_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_timer.c b/mnsl/mns_timer.c
new file mode 100644
index 0000000..c28d32b
--- /dev/null
+++ b/mnsl/mns_timer.c
@@ -0,0 +1,454 @@
+/*
+ * 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 Implementation of the timer management module.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_TIMER
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_timer.h"
+#include "mns_misc.h"
+#include "mns_trace.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Service parameters */
+/*------------------------------------------------------------------------------------------------*/
+/*! Priority of the TM service used by scheduler */
+static const uint8_t TM_SRV_PRIO = 255U; /* parasoft-suppress MISRA2004-8_7 "Value shall be part of the module, not part of a function." */
+/*! Main event for the TM service */
+static const Srv_Event_t TM_EVENT_UPDATE_TIMERS = 1U;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Tm_Service(void *self);
+static void Tm_UpdateTimers(CTimerManagement *self);
+static bool Tm_HandleElapsedTimer(CTimerManagement *self);
+static bool Tm_UpdateTimersAdd(void *c_timer_ptr, void *n_timer_ptr);
+static void Tm_SetTimerInternal(CTimerManagement *self,
+ CTimer *timer_ptr,
+ Tm_Handler_t handler_fptr,
+ void *args_ptr,
+ uint16_t elapse,
+ uint16_t period);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CTimerManagement */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the timer management class.
+ * \param self Instance pointer
+ * \param scd Scheduler instance
+ * \param init_ptr Reference to the initialization data
+ */
+void Tm_Ctor(CTimerManagement *self, CScheduler *scd, const Tm_InitData_t *init_ptr)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ self->mns_inst_id = init_ptr->mns_inst_id;
+ /* Initialize subjects and add observers */
+ Ssub_Ctor(&self->get_tick_count_subject, self->mns_inst_id);
+ (void)Ssub_AddObserver(&self->get_tick_count_subject,
+ init_ptr->get_tick_count_obs_ptr);
+ if(init_ptr->set_application_timer_obs_ptr != NULL)
+ {
+ self->delayed_tm_service_enabled = true;
+ Ssub_Ctor(&self->set_application_timer_subject, self->mns_inst_id);
+ (void)Ssub_AddObserver(&self->set_application_timer_subject,
+ init_ptr->set_application_timer_obs_ptr);
+ }
+ /* Initialize timer management service */
+ Srv_Ctor(&self->tm_srv, TM_SRV_PRIO, self, &Tm_Service);
+ /* Add timer management service to scheduler */
+ (void)Scd_AddService(scd, &self->tm_srv);
+}
+
+/*! \brief Service function of the timer management.
+ * \param self Instance pointer
+ */
+static void Tm_Service(void *self)
+{
+ CTimerManagement *self_ = (CTimerManagement *)self;
+ Srv_Event_t event_mask;
+
+ Srv_GetEvent(&self_->tm_srv, &event_mask);
+
+ if(TM_EVENT_UPDATE_TIMERS == (event_mask & TM_EVENT_UPDATE_TIMERS)) /* Is event pending? */
+ {
+ Srv_ClearEvent(&self_->tm_srv, TM_EVENT_UPDATE_TIMERS);
+ Tm_UpdateTimers(self_);
+ }
+}
+
+/*! \brief If event TM_EVENT_UPDATE_TIMERS is set this function is called. Handles the update
+ * of the timer list. If a timer has expired the corresponding callback function is
+ * executed. If the expired timer is a periodic timer, the timer will be set again.
+ * \param self Instance pointer
+ */
+static void Tm_UpdateTimers(CTimerManagement *self)
+{
+ uint16_t current_tick_count;
+ Ssub_Notify(&self->get_tick_count_subject, &current_tick_count, false);
+
+ if(self->timer_list.head != NULL) /* At least one timer is running? */
+ {
+ bool continue_loop = true;
+ /* Calculate time difference between the current and the last TM service run */
+ uint16_t tick_count_diff = (uint16_t)(current_tick_count - self->last_tick_count);
+ /* Save current tick count for next service run */
+ self->last_tick_count = current_tick_count;
+
+ /* Loop while timer list is not empty */
+ while((self->timer_list.head != NULL) && (continue_loop!= false))
+ {
+ /* Is not first timer in list elapsed yet? */
+ if(tick_count_diff <= ((CTimer *)self->timer_list.head->data_ptr)->delta)
+ {
+ /* Update delta of first timer in list */
+ ((CTimer *)self->timer_list.head->data_ptr)->delta -= tick_count_diff;
+ tick_count_diff = 0U;
+ }
+ else /* At least first timer in list elapsed */
+ {
+ /* Update tick count difference for next timer in list */
+ tick_count_diff -= ((CTimer *)self->timer_list.head->data_ptr)->delta;
+ /* First timer elapsed */
+ ((CTimer *)self->timer_list.head->data_ptr)->delta = 0U;
+ }
+
+ /* First timer in list elapsed? */
+ if(0U == ((CTimer *)self->timer_list.head->data_ptr)->delta)
+ {
+ /* Handle elapsed timer */
+ continue_loop = Tm_HandleElapsedTimer(self);
+ }
+ else /* No elapsed timer in list. */
+ {
+ /* First timer in list updated! Set trigger to inform application (see
+ Tm_CheckForNextService()) and stop TM service. */
+ self->set_service_timer = true;
+ continue_loop = false;
+ }
+ }
+ }
+}
+
+/*! \brief This function is called if the first timer in list is elapsed. The timer handler
+ * callback function is invoked. If the timer is a periodic timer it is wound up again.
+ * \param self Instance pointer
+ * \return \c true if the next timer must be check.
+ * \return \c false if the wound up timer (periodic timer) is new head of timer list
+ */
+static bool Tm_HandleElapsedTimer(CTimerManagement *self)
+{
+ bool ret_val = true;
+
+ CDlNode *node = self->timer_list.head;
+ /* Reset flag to be able to check if timer object has changed within handler
+ callback function */
+ ((CTimer *)node->data_ptr)->changed = false;
+ /* Call timer handler callback function */
+ ((CTimer *)node->data_ptr)->handler_fptr(((CTimer *)node->data_ptr)->args_ptr);
+
+ /* Timer object hasn't changed within handler callback function? */
+ if(false == ((CTimer *)node->data_ptr)->changed)
+ {
+ /* Remove current timer from list */
+ (void)Dl_Remove(&self->timer_list, node);
+ /* Mark timer as unused */
+ ((CTimer *)node->data_ptr)->in_use = false;
+ /* Is current timer a periodic timer? */
+ if(((CTimer *)node->data_ptr)->period > 0U)
+ {
+ /* Reload current timer */
+ Tm_SetTimerInternal(self,
+ ((CTimer *)node->data_ptr),
+ ((CTimer *)node->data_ptr)->handler_fptr,
+ ((CTimer *)node->data_ptr)->args_ptr,
+ ((CTimer *)node->data_ptr)->period,
+ ((CTimer *)node->data_ptr)->period);
+
+ if(node == self->timer_list.head) /* Is current timer new head of list? */
+ {
+ /* Set trigger to inform application (see Tm_CheckForNextService()) and
+ stop TM service. */
+ self->set_service_timer = true;
+ ret_val = false;
+ }
+ }
+ }
+
+ return ret_val;
+}
+
+/*! \brief Calls an application callback function to inform the application that the MNS must be
+ * serviced not later than the passed time period. If the timer list is empty a possible
+ * running application timer will be stopped. This function is called at the end of
+ * Mns_Service().
+ * \param self Instance pointer
+ */
+void Tm_CheckForNextService(CTimerManagement *self)
+{
+ if(self->delayed_tm_service_enabled != false)
+ {
+ uint16_t current_tick_count;
+ Ssub_Notify(&self->get_tick_count_subject, &current_tick_count, false);
+ /* Has head of timer list changed? */
+ if(self->set_service_timer != false)
+ {
+ uint16_t new_time;
+ uint16_t diff = current_tick_count - self->last_tick_count;
+ self->set_service_timer = false;
+ /* Timer expired since last TM service? */
+ if(diff >= ((CTimer *)self->timer_list.head->data_ptr)->delta)
+ {
+ new_time = 1U; /* Return minimum value */
+ }
+ else
+ {
+ /* Calculate new timeout */
+ new_time = (uint16_t)(((CTimer *)self->timer_list.head->data_ptr)->delta - diff);
+ }
+ /* Inform the application that the MNS must be serviced not later than the passed
+ time period. */
+ Ssub_Notify(&self->set_application_timer_subject, &new_time, false);
+ }
+ }
+ else
+ {
+ Tm_TriggerService(self); /* Application timer not implemented -> Retrigger TM */
+ }
+}
+
+/*! \brief Helper function to set the TM service event.
+ * \details This function is used by the application to trigger a service call of the Timer
+ * Management if the application timer has expired.
+ * \param self Instance pointer
+ */
+void Tm_TriggerService(CTimerManagement *self)
+{
+ if(self->timer_list.head != NULL) /* At least one timer is running? */
+ {
+ Srv_SetEvent(&self->tm_srv, TM_EVENT_UPDATE_TIMERS);
+ }
+}
+
+/*! \brief Helper function to stop the TM service.
+ * \param self Instance pointer
+ */
+void Tm_StopService(CTimerManagement *self)
+{
+ uint16_t new_time = 0U;
+
+ /* Clear probable running application timer */
+ Ssub_Notify(&self->set_application_timer_subject, &new_time, false);
+
+ /* Reset the service timer. Not necessary ? */
+ self->set_service_timer = false;
+
+ /* Clear the timer head queue to prevent any event to be set */
+ self->timer_list.head = NULL;
+}
+
+/*! \brief Creates a new timer. The timer expires at the specified elapse time and then after
+ * every specified period. When the timer expires the specified callback function is
+ * called.
+ * \param self Instance pointer
+ * \param timer_ptr Reference to the timer object
+ * \param handler_fptr Callback function which is called when the timer expires
+ * \param args_ptr Reference to an optional parameter which is passed to the specified
+ * callback function
+ * \param elapse The elapse value before the timer expires for the first time, in
+ * milliseconds
+ * \param period The period of the timer, in milliseconds. If this parameter is zero, the
+ * timer is signaled once. If the parameter is greater than zero, the timer
+ * is periodic.
+ */
+void Tm_SetTimer(CTimerManagement *self,
+ CTimer *timer_ptr,
+ Tm_Handler_t handler_fptr,
+ void *args_ptr,
+ uint16_t elapse,
+ uint16_t period)
+{
+ (void)Tm_ClearTimer(self, timer_ptr); /* Clear timer if running */
+ /* Call the internal method to set the new timer (-> does not trigger TM service!) */
+ Tm_SetTimerInternal(self, timer_ptr, handler_fptr, args_ptr, elapse, period);
+ Tm_TriggerService(self); /* New timer added -> trigger timer list update */
+}
+
+/*! \brief This function contains the internal part when adding a new timer. The function is
+ * called within Tm_SetTimer() and within Tm_UpdateTimers().
+ * \param self Instance pointer
+ * \param timer_ptr Reference to the timer object
+ * \param handler_fptr Callback function which is called when the timer expires
+ * \param args_ptr Reference to an optional parameter which is passed to the specified
+ * callback function
+ * \param elapse The elapse value before the timer expires for the first time, in
+ * milliseconds
+ * \param period The period of the timer, in milliseconds. If this parameter is zero, the
+ * timer is signaled once. If the parameter is greater than zero, the timer
+ * is periodic.
+ */
+static void Tm_SetTimerInternal(CTimerManagement *self,
+ CTimer *timer_ptr,
+ Tm_Handler_t handler_fptr,
+ void *args_ptr,
+ uint16_t elapse,
+ uint16_t period)
+{
+ uint16_t current_tick_count;
+ Ssub_Notify(&self->get_tick_count_subject, &current_tick_count, false);
+
+ /* Save timer specific values */
+ timer_ptr->changed = true; /* Flag is needed by Tm_UpdateTimers() */
+ timer_ptr->in_use = true;
+ timer_ptr->handler_fptr = handler_fptr;
+ timer_ptr->args_ptr = args_ptr;
+ timer_ptr->elapse = elapse;
+ timer_ptr->period = period;
+ timer_ptr->delta = elapse;
+
+ /* Create back link to be able to point from node to timer object */
+ timer_ptr->node.data_ptr = (void *)timer_ptr;
+
+ if(NULL == self->timer_list.head) /* Is timer list empty? */
+ {
+ Dl_InsertHead(&self->timer_list, &timer_ptr->node); /* Add first timer to list */
+ /* Save current tick count */
+ Ssub_Notify(&self->get_tick_count_subject, &self->last_tick_count, false);
+ }
+ else /* Timer list is not empty */
+ {
+ CDlNode *result_ptr = NULL;
+
+ /* Set delta value in relation to last saved tick count (last TM service) */
+ timer_ptr->delta += (uint16_t)(current_tick_count - self->last_tick_count);
+
+ /* Search slot where new timer must be inserted. Update delta of new timer
+ and delta of the following timer in the list. */
+ result_ptr = Dl_Foreach(&self->timer_list, &Tm_UpdateTimersAdd, (void *)timer_ptr);
+
+ if(NULL != result_ptr) /* Slot found? */
+ {
+ /* Insert new timer at found position */
+ Dl_InsertBefore(&self->timer_list, result_ptr, &timer_ptr->node);
+ }
+ else /* No slot found -> Insert as last node */
+ {
+ /* Add new timer to end of list */
+ Dl_InsertTail(&self->timer_list, &timer_ptr->node);
+ }
+ }
+}
+
+/*! \brief Removes the specified timer from the timer list.
+ * \param self Instance pointer
+ * \param timer_ptr Reference to the timer object
+ * \attention Make sure that for a timer object Tm_SetTimer() is called before Tm_ClearTimer()
+ * is called!
+ */
+void Tm_ClearTimer(CTimerManagement *self, CTimer *timer_ptr)
+{
+ if(timer_ptr->in_use != false) /* Is timer currently in use? */
+ {
+ timer_ptr->changed = true; /* Flag is needed by Tm_UpdateTimers() */
+
+ if(NULL != timer_ptr->node.next) /* Has deleted timer a follower? */
+ {
+ /* Adjust delta of following timer */
+ ((CTimer *)timer_ptr->node.next->data_ptr)->delta += timer_ptr->delta;
+ }
+
+ (void)Dl_Remove(&self->timer_list, &timer_ptr->node);
+ timer_ptr->in_use = false;
+
+ Tm_TriggerService(self); /* Timer removed -> trigger timer list update */
+ }
+}
+
+/*! \brief Used by Tm_SetTimer() to find the slot where the new timer must be inserted.
+ * \param c_timer_ptr Reference to current timer processed by foreach loop
+ * \param n_timer_ptr Reference to new timer
+ * \return \c true: Slot found, stop foreach loop
+ * \return \c false: Slot not found, continue foreach loop
+ */
+static bool Tm_UpdateTimersAdd(void *c_timer_ptr, void *n_timer_ptr)
+{
+ CTimer *current_timer_ptr = (CTimer *)c_timer_ptr;
+ CTimer *new_timer_ptr = (CTimer *)n_timer_ptr;
+ bool ret_val;
+
+ /* Is current timer lesser than new timer? */
+ if(current_timer_ptr->delta <= new_timer_ptr->delta)
+ {
+ /* Update delta of new timer and continue foreach loop */
+ new_timer_ptr->delta -= current_timer_ptr->delta;
+ ret_val = false;
+ }
+ else /* Slot found! */
+ {
+ /* Correct delta of current timer and stop foreach loop */
+ current_timer_ptr->delta -= new_timer_ptr->delta;
+ ret_val = true;
+ }
+
+ return ret_val;
+}
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CTimer */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of the Timer class.
+ * \param self Instance pointer
+ */
+void T_Ctor(CTimer *self)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+}
+
+/*! \brief Returns the status of the given timer.
+ * \param self Instance pointer
+ * \return \c true if the timer is currently in use
+ * \return \c false if the timer is not currently in use
+ */
+bool T_IsTimerInUse(CTimer *self)
+{
+ return self->in_use;
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_timer.h b/mnsl/mns_timer.h
new file mode 100644
index 0000000..9e5c02a
--- /dev/null
+++ b/mnsl/mns_timer.h
@@ -0,0 +1,146 @@
+/*
+ * 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 the timer management module.
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_TIMER
+ * @{
+ */
+
+#ifndef MNS_TIMER_H
+#define MNS_TIMER_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_cfg.h"
+#include "mns_dl.h"
+#include "mns_scheduler.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Function signature used for timer handler
+ * \param args Void pointer to optional data
+ */
+typedef void (*Tm_Handler_t)(void *args);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Structures */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Initialization structure of the timer management module. */
+typedef struct Tm_InitData_
+{
+ /*! \brief Observer used to request current tick count value */
+ CSingleObserver *get_tick_count_obs_ptr;
+ /*! \brief Observer used to start application timer for delayed TM service calls */
+ CSingleObserver *set_application_timer_obs_ptr;
+ /*! \brief MOST NetServices instance ID */
+ uint8_t mns_inst_id;
+
+} Tm_InitData_t;
+
+/*! \brief Class structure of the a timer object. */
+typedef struct CTimer_
+{
+ /*! \brief Node of the doubly linked (timer-) list */
+ CDlNode node;
+ /*! \brief Handler function which is invoked when the timer expires */
+ Tm_Handler_t handler_fptr;
+ /*! \brief Reference to optional parameter */
+ void *args_ptr;
+ /*! \brief The Timeout value before the timer expires for the first time, in milliseconds */
+ uint16_t elapse;
+ /*! \brief The period of the timer, in milliseconds */
+ uint16_t period;
+ /*! \brief Delta time related to next timer in list */
+ uint16_t delta;
+ /*! \brief Flag which signals that the timer is in use */
+ bool in_use;
+ /*! \brief Flag to check if timer object has changed within timer handler callback function */
+ bool changed;
+
+} CTimer;
+
+/*! \brief Class structure of the timer management */
+typedef struct CTimerManagement_
+{
+ /*! \brief Doubly linked list to manage the active timers */
+ CDlList timer_list;
+ /*! \brief Subject to request current tick count */
+ CSingleSubject get_tick_count_subject;
+ /*! \brief Subject to start the application timer which triggers a MNS service call */
+ CSingleSubject set_application_timer_subject;
+ /*! \brief Service instance to add the timer management to the scheduler */
+ CService tm_srv;
+ /*! \brief Last tick count value (saved at TM service) */
+ uint16_t last_tick_count;
+ /*! \brief Signals that the application timer callbacks are used */
+ bool delayed_tm_service_enabled;
+ /*! \brief Indicates that the application timer must be started */
+ bool set_service_timer;
+ /*! \brief MOST NetServices instance ID */
+ uint8_t mns_inst_id;
+
+} CTimerManagement;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CTimerManagement */
+/*------------------------------------------------------------------------------------------------*/
+extern void Tm_Ctor(CTimerManagement *self, CScheduler *scd, const Tm_InitData_t *init_ptr);
+extern void Tm_SetTimer(CTimerManagement *self, CTimer *timer_ptr, Tm_Handler_t handler_fptr,
+ void *args_ptr, uint16_t elapse, uint16_t period);
+extern void Tm_ClearTimer(CTimerManagement *self, CTimer *timer_ptr);
+extern void Tm_CheckForNextService(CTimerManagement *self);
+extern void Tm_TriggerService(CTimerManagement *self);
+extern void Tm_StopService(CTimerManagement *self);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes of class CTimer */
+/*------------------------------------------------------------------------------------------------*/
+extern void T_Ctor(CTimer *self);
+extern bool T_IsTimerInUse(CTimer *self);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_TIMER_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_trace.h b/mnsl/mns_trace.h
new file mode 100644
index 0000000..7ef4758
--- /dev/null
+++ b/mnsl/mns_trace.h
@@ -0,0 +1,87 @@
+/*
+ * 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 the trace interface
+ */
+
+#ifndef MNSL_TRACE_H
+#define MNSL_TRACE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Unit and entry ids */
+/*------------------------------------------------------------------------------------------------*/
+#define TR_MNSL_ASSERT "ASSERT failed in line %d"
+#define TR_MNSL_INIC_RESULT_ID_1 "INIC error data:"
+#define TR_MNSL_INIC_RESULT_ID_2 "--> Data[%u]: 0x%02X"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal macros */
+/*------------------------------------------------------------------------------------------------*/
+
+/* parasoft suppress MISRA2004-19_7 MISRA2004-19_4 reason "function-like macros are allowed for tracing" */
+#ifdef MNS_TR_ERROR
+# define TR_ERROR(args) MNS_TR_ERROR args;
+# define TR_FAILED_ASSERT(mns_inst_id, unit) TR_ERROR(((mns_inst_id), (unit), TR_MNSL_ASSERT, 1U, __LINE__))
+# define TR_ASSERT(mns_inst_id, unit, expr) if (!(expr)) {TR_FAILED_ASSERT((mns_inst_id), (unit));}
+# define TR_ERROR_INIC_RESULT(mns_inst_id, unit, info_ptr, info_size) \
+ { \
+ uint8_t i; \
+ TR_ERROR(((mns_inst_id), (unit), TR_MNSL_INIC_RESULT_ID_1, 0U)); \
+ for(i=0U; i<info_size; i++) \
+ { \
+ TR_ERROR(((mns_inst_id), (unit), TR_MNSL_INIC_RESULT_ID_2, 2U, i, info_ptr[i])) \
+ } \
+ }
+#else
+# define MNS_TR_ERROR
+# define TR_ERROR(args)
+# define TR_FAILED_ASSERT(mns_inst_id, unit)
+# define TR_ASSERT(mns_inst_id, unit, expr)
+# define TR_ERROR_INIC_RESULT(mns_inst_id, unit, info_ptr, info_size)
+#endif
+
+#ifdef MNS_TR_INFO
+# define TR_INFO(args) MNS_TR_INFO args;
+#else
+# define MNS_TR_INFO
+# define TR_INFO(args)
+#endif
+/* parasoft unsuppress item MISRA2004-19_7 item MISRA2004-19_4 reason "function-like macros are allowed for tracing" */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNSL_TRACE_H */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_transceiver.c b/mnsl/mns_transceiver.c
new file mode 100644
index 0000000..ed5e3af
--- /dev/null
+++ b/mnsl/mns_transceiver.c
@@ -0,0 +1,292 @@
+/*
+ * 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 Implementation of class CTransceiver
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_TRCV
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_transceiver.h"
+#include "mns_misc.h"
+#include "mns_pmp.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Trcv_OnTxStatusInternal(void *self, Msg_MostTel_t *tel_ptr, Mns_MsgTxStatus_t status);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of class CTransceiver
+ * \param self The instance
+ * \param fifo_ptr Reference to the dedicated port message FIFO
+ * \param def_src_addr Source address that is preset in Tx message object
+ * \param mns_inst_id MOST NetServices instance ID
+ * \param trace_id ID specifies FIFO in traces if multiple transceivers are running
+ */
+void Trcv_Ctor(CTransceiver *self, CPmFifo *fifo_ptr, uint16_t def_src_addr, uint8_t mns_inst_id, uint8_t trace_id)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ self->fifo_ptr = fifo_ptr;
+ self->tx_def_src = def_src_addr;
+ self->mns_inst_id = mns_inst_id;
+ self->own_id = trace_id;
+ Pool_Ctor(&self->tx_msg_pool, self->tx_msgs, TRCV_SIZE_TX_POOL, mns_inst_id);
+ TR_ASSERT(self->mns_inst_id, "[TRCV]", (fifo_ptr != NULL));
+}
+
+/*! \brief Assigns a function of another class to receive messages
+ * \details The assigned function is responsible to call Trcv_RxReleaseMsg() it has finished to process it
+ * \param self The instance
+ * \param callback_fptr Callback function
+ * \param inst_ptr The instance of the receiver class
+ */
+void Trcv_RxAssignReceiver(CTransceiver *self, Trcv_RxCompleteCb_t callback_fptr, void *inst_ptr)
+{
+ self->rx_complete_fptr = callback_fptr;
+ self->rx_complete_inst = inst_ptr;
+}
+
+/*! \brief Assigns a function of another class to filter Rx messages
+ * \details The assigned function is responsible to discard or pass Rx messages
+ * \param self The instance
+ * \param callback_fptr Callback function
+ * \param inst_ptr The instance of the filter class
+ */
+void Trcv_RxAssignFilter(CTransceiver *self, Trcv_RxFilterCb_t callback_fptr, void *inst_ptr)
+{
+ self->rx_filter_fptr = callback_fptr;
+ self->rx_filter_inst = inst_ptr;
+}
+
+/*! \brief Releases an Rx message which was received by the assigned receiver
+ * \param self The instance
+ * \param tel_ptr Reference to the received message
+ */
+void Trcv_RxReleaseMsg(CTransceiver *self, Msg_MostTel_t *tel_ptr)
+{
+ CMessage *msg_ptr = (CMessage*)(void*)tel_ptr;
+ bool check_ok = !Dln_IsNodePartOfAList(Msg_GetNode(msg_ptr)); /* message object shall not be part of a list */
+ /* because it was provided in an earlier step */
+ TR_ASSERT(self->mns_inst_id, "[TRCV]", check_ok);
+ if (check_ok)
+ {
+ Fifo_RxReleaseMsg(self->fifo_ptr, msg_ptr);
+ }
+}
+
+/*! \brief Retrieves a message object from the pool
+ * \param self The instance
+ * \param size Size of the message in bytes. Valid range: 0..45.
+ * \return Reference to the Msg_MostTel_t structure if a message is available.
+ * Otherwise \c NULL.
+ */
+extern Msg_MostTel_t* Trcv_TxAllocateMsg(CTransceiver *self, uint8_t size)
+{
+ const uint8_t TRCV_CTRL_MAX_SIZE = 45U; /* replace by PMS constant in future */
+ CMessage *handle = NULL;
+ Msg_MostTel_t *tel_ptr = NULL;
+
+ if (size <= TRCV_CTRL_MAX_SIZE)
+ {
+ handle = Pool_GetMsg(&self->tx_msg_pool);
+
+ if (handle != NULL)
+ {
+ Msg_Cleanup(handle); /* reset headers and fields */
+ Msg_ReserveHeader(handle, PMP_PM_MAX_SIZE_HEADER + ENC_MAX_SIZE_CONTENT);
+ tel_ptr = Msg_GetMostTel(handle); /* return public struct of the message object */
+ tel_ptr->tel.tel_id = 0U;
+ tel_ptr->tel.tel_len = size;
+ tel_ptr->tel.tel_cnt = 0U;
+ tel_ptr->source_addr = self->tx_def_src;
+ }
+ }
+
+ return tel_ptr;
+}
+
+/*! \brief Returns a message object to the transceiver pool a message was allocated from
+ * \param tel_ptr Reference to the message object which needs to be returned.
+ */
+void Trcv_TxReleaseMsg(Msg_MostTel_t *tel_ptr)
+{
+ CMessage* msg_ptr = (CMessage*)(void*)tel_ptr; /* avoid MISRA-C warning by converting to "void*" */
+ bool check_ok = !Dln_IsNodePartOfAList(Msg_GetNode(msg_ptr)); /* message object shall not be part of a list */
+ TR_ASSERT(0U, "[TRCV]", check_ok); /* because it was provided in an earlier step */
+
+ if (check_ok)
+ {
+ Pool_ReturnMsg(msg_ptr);
+ }
+}
+
+/*! \brief Prepares a message object for re-transmission
+ * \param tel_ptr Reference to the Tx message object which needs
+ * to be reused.
+ */
+void Trcv_TxReuseMsg(Msg_MostTel_t *tel_ptr)
+{
+ CMessage* msg_ptr = (CMessage*)(void*)tel_ptr;
+ TR_ASSERT(0U, "[TRCV]", (!Dln_IsNodePartOfAList(Msg_GetNode(msg_ptr)))); /* message object shall not be part of a list */
+ /* because it was provided in an earlier step */
+ Msg_Cleanup(msg_ptr); /* reset headers and fields */
+ Msg_ReserveHeader(msg_ptr, PMP_PM_MAX_SIZE_HEADER + ENC_MAX_SIZE_CONTENT);
+}
+
+/*! \brief Transmits a given message object to the INIC
+ * \details After completed transmission the message object is released automatically
+ * \param self The instance
+ * \param tel_ptr Reference to the message object
+ */
+void Trcv_TxSendMsg(CTransceiver *self, Msg_MostTel_t *tel_ptr)
+{
+ CMessage *msg_ptr;
+
+ TR_ASSERT(self->mns_inst_id, "[TRCV]", (tel_ptr != NULL));
+ msg_ptr = (CMessage*)(void*)tel_ptr;
+
+ TR_INFO((self->mns_inst_id, "[TRCV]", "Trcv_TxSendMsg(): FIFO: %u, MSG(tgt:0x%04X, id:%02X.%01X.%04X.%01X)", 6U, self->own_id, tel_ptr->destination_addr, tel_ptr->id.fblock_id, tel_ptr->id.instance_id, tel_ptr->id.function_id, tel_ptr->id.op_type));
+ Msg_SetTxStatusHandler(msg_ptr, &Trcv_OnTxStatusInternal, self); /* just release the message */
+ Fifo_Tx(self->fifo_ptr, msg_ptr, false);
+}
+
+/*! \brief Transmits a given message object to the INIC with a dedicated result callback
+ * \param self The instance
+ * \param tel_ptr Reference to the message object
+ * \param callback_fptr Callback function which is invoked after message transmission has finished.
+ * Must be \c NULL to avoid that a callback function is invoked. In this case
+ * the message object is freed internally. Hence, the message object must
+ * not provide external payload.
+ * \param inst_ptr Reference to the instance which is invoked with callback_fptr. Has to be \c
+ * NULL if callback_fptr is \c NULL.
+ * \note The provided callback function is responsible to free the message object by calling
+ * Trcv_TxReleaseMsg() or to reuse the message object by calling Trcv_TxReuseMsg() before
+ * passing it to one of the transmit functions again.
+ */
+void Trcv_TxSendMsgExt(CTransceiver *self, Msg_MostTel_t *tel_ptr, Msg_TxStatusCb_t callback_fptr, void *inst_ptr)
+{
+ CMessage *msg_ptr;
+
+ TR_ASSERT(self->mns_inst_id, "[TRCV]", (tel_ptr != NULL));
+ msg_ptr = (CMessage*)(void*)tel_ptr;
+
+ if (callback_fptr == NULL)
+ {
+ TR_ASSERT(self->mns_inst_id, "[TRCV]", (inst_ptr == NULL));
+ callback_fptr = &Trcv_OnTxStatusInternal;
+ inst_ptr = self;
+ }
+
+ TR_INFO((self->mns_inst_id, "[TRCV]", "Trcv_TxSendMsgExt(): FIFO: %u, MSG(tgt:0x%04X, id:%02X.%01X.%04X.%01X)", 6U, self->own_id, tel_ptr->destination_addr, tel_ptr->id.fblock_id, tel_ptr->id.instance_id, tel_ptr->id.function_id, tel_ptr->id.op_type));
+ Msg_SetTxStatusHandler(msg_ptr, callback_fptr, inst_ptr);
+ Fifo_Tx(self->fifo_ptr, msg_ptr, false);
+}
+
+/*! \brief Transmits a given message object to the INIC bypassing all other messages in the FIFO
+ * \param self The instance
+ * \param tel_ptr Reference to the message object
+ * \param callback_fptr Callback function which is invoked after message transmission has finished.
+ * Must be \c NULL to avoid that a callback function is invoked. In this case
+ * the message object is freed internally. Hence, the message object must
+ * not provide external payload.
+ * \param inst_ptr Reference to the instance which is invoked
+ * \note The provided callback function is responsible to free the message object by calling
+ * Trcv_TxReleaseMsg() or to reuse the message object by calling Trcv_TxReuseMsg() before
+ * passing it to one of the transmit functions again.
+ */
+void Trcv_TxSendMsgBypass(CTransceiver *self, Msg_MostTel_t *tel_ptr, Msg_TxStatusCb_t callback_fptr, void *inst_ptr)
+{
+ CMessage *msg_ptr;
+
+ TR_ASSERT(self->mns_inst_id, "[TRCV]", (tel_ptr != NULL));
+ msg_ptr = (CMessage*)(void*)tel_ptr;
+
+ if (callback_fptr == NULL)
+ {
+ TR_ASSERT(self->mns_inst_id, "[TRCV]", (inst_ptr == NULL));
+ callback_fptr = &Trcv_OnTxStatusInternal;
+ inst_ptr = self;
+ }
+
+ Msg_SetTxStatusHandler(msg_ptr, callback_fptr, inst_ptr);
+ Fifo_Tx(self->fifo_ptr, msg_ptr, true);
+}
+
+/*! \brief Callback function which is invoked instead of an external callback
+ * as soon as channel transmission was finished in PMS.
+ * \param self The instance
+ * \param tel_ptr Reference to the message object
+ * \param status Transmission status
+ */
+static void Trcv_OnTxStatusInternal(void *self, Msg_MostTel_t *tel_ptr, Mns_MsgTxStatus_t status)
+{
+ Trcv_TxReleaseMsg(tel_ptr);
+ MISC_UNUSED(self);
+ MISC_UNUSED(status);
+}
+
+/*! \brief Internal callback function which is intended to be
+ * invoked by the port message channel on completed reception.
+ * \param self The instance
+ * \param tel_ptr Reference to the message object
+ */
+void Trcv_RxOnMsgComplete(void *self, CMessage *tel_ptr)
+{
+ CTransceiver *self_ = (CTransceiver*)self;
+ bool discard = false;
+
+ TR_INFO((self_->mns_inst_id, "[TRCV]", "Trcv_RxOnMsgComplete(): FIFO: %u, MSG(src:0x%04X, id:%02X.%01X.%04X.%01X)", 6U, self_->own_id, tel_ptr->pb_msg.source_addr, tel_ptr->pb_msg.id.fblock_id, tel_ptr->pb_msg.id.instance_id, tel_ptr->pb_msg.id.function_id, tel_ptr->pb_msg.id.op_type));
+ if (self_->rx_filter_fptr != NULL)
+ {
+ discard = self_->rx_filter_fptr(self_->rx_filter_inst, Msg_GetMostTel(tel_ptr));
+ }
+
+ if ((self_->rx_complete_fptr != NULL) && (discard == false))
+ {
+ /* the assigned Rx function is responsible to release the message */
+ self_->rx_complete_fptr(self_->rx_complete_inst, Msg_GetMostTel(tel_ptr));
+ }
+ else
+ {
+ Fifo_RxReleaseMsg(self_->fifo_ptr, tel_ptr);
+ }
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_transceiver.h b/mnsl/mns_transceiver.h
new file mode 100644
index 0000000..b1701c5
--- /dev/null
+++ b/mnsl/mns_transceiver.h
@@ -0,0 +1,135 @@
+/*
+ * 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 Declaration of class CTransceiver
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_TRCV
+ * @{
+ */
+
+#ifndef MNS_TRANSCEIVER_H
+#define MNS_TRANSCEIVER_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_message.h"
+#include "mns_pool.h"
+#include "mns_pmfifo.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Assignable callback function which is invoked for message reception
+ * \param self The instance
+ * \param tel_ptr Reference to the message object
+ */
+typedef void (*Trcv_RxCompleteCb_t)(void *self, Msg_MostTel_t *tel_ptr);
+
+/*! \brief Assignable callback function which is invoked to filter Rx messages
+ * \details Filtering is a synchronous operation. Hence, it is not possible to keep a message
+ * object for delayed processing. The invoked function has to decide whether a
+ * message shall be discarded and freed to the Rx pool. Therefore, it has to return
+ * \c true. By returning \ false, the message will be received in the usual way.
+ * \param self The instance
+ * \param tel_ptr Reference to the message object
+ * \return Returns \c true to discard the message and free it to the pool (no-pass). Otherwise, returns
+ * \c false (pass).
+ */
+typedef bool (*Trcv_RxFilterCb_t)(void *self, Msg_MostTel_t *tel_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Macros */
+/*------------------------------------------------------------------------------------------------*/
+#define TRCV_SIZE_TX_POOL 100U /*!< \brief Number of messages in the message pool */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Class CTransceiver */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Class CTransceiver
+ * \details Provides MOST message objects and communication methods to further classes
+ */
+typedef struct CTransceiver_
+{
+ CMessage tx_msgs[TRCV_SIZE_TX_POOL];/*!< \brief Messages in message pool */
+ CPool tx_msg_pool; /*!< \brief The message pool */
+ uint16_t tx_def_src; /*!< \brief Default source address for Tx message object */
+ uint8_t mns_inst_id; /*!< \brief MOST NetServices instance ID */
+ uint8_t own_id; /*!< \brief ID of the transceiver required for tracing */
+ CPmFifo *fifo_ptr; /*!< \brief Reference to dedicated port message FIFO */
+
+ Trcv_RxCompleteCb_t rx_complete_fptr; /*!< \brief Callback function which is invoked on
+ * message reception
+ */
+ void *rx_complete_inst; /*!< \brief Instance which is notified on
+ * message reception
+ */
+ Trcv_RxFilterCb_t rx_filter_fptr; /*!< \brief Callback function which is invoked
+ * to filter Rx messages
+ */
+ void *rx_filter_inst; /*!< \brief Instance which is notified to
+ * filter Rx messages
+ */
+} CTransceiver;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Methods */
+/*------------------------------------------------------------------------------------------------*/
+/* Constructor */
+extern void Trcv_Ctor(CTransceiver *self, CPmFifo *fifo_ptr, uint16_t def_src_addr, uint8_t mns_inst_id, uint8_t trace_id);
+/* Tx */
+extern Msg_MostTel_t* Trcv_TxAllocateMsg(CTransceiver *self, uint8_t size);
+extern void Trcv_TxSendMsg(CTransceiver *self, Msg_MostTel_t *tel_ptr);
+extern void Trcv_TxSendMsgExt(CTransceiver *self, Msg_MostTel_t *tel_ptr, Msg_TxStatusCb_t callback_fptr, void *inst_ptr);
+extern void Trcv_TxSendMsgBypass(CTransceiver *self, Msg_MostTel_t *tel_ptr, Msg_TxStatusCb_t callback_fptr, void *inst_ptr);
+extern void Trcv_TxReleaseMsg(Msg_MostTel_t *tel_ptr);
+extern void Trcv_TxReuseMsg(Msg_MostTel_t *tel_ptr);
+/* Rx */
+extern void Trcv_RxAssignReceiver(CTransceiver *self, Trcv_RxCompleteCb_t callback_fptr, void *inst_ptr);
+extern void Trcv_RxAssignFilter(CTransceiver *self, Trcv_RxFilterCb_t callback_fptr, void *inst_ptr);
+extern void Trcv_RxReleaseMsg(CTransceiver *self, Msg_MostTel_t *tel_ptr);
+extern void Trcv_RxOnMsgComplete(void *self, CMessage *tel_ptr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_TRANSCEIVER_H */
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mns_types_cfg.h b/mnsl/mns_types_cfg.h
new file mode 100644
index 0000000..32ce84e
--- /dev/null
+++ b/mnsl/mns_types_cfg.h
@@ -0,0 +1,70 @@
+/*
+ * 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 MOST NetServices data types.
+ */
+
+#ifndef MNS_TYPES_H
+#define MNS_TYPES_H
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Data Types */
+/*------------------------------------------------------------------------------------------------*/
+/* Definition of standard integer typed, typically defined in <stdint.h> */
+/* typedef signed char int8_t; */
+/* typedef short int16_t; */
+/* typedef int int32_t; */
+/* typedef unsigned char uint8_t; */
+/* typedef unsigned short uint16_t; */
+/* typedef unsigned int uint32_t; */
+
+/* Definition of size_t, typically defined in <stddef.h> */
+/* typedef uint32_t size_t; */
+
+/* Definition of character type */
+ typedef char char_t;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNS_TYPES_H */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+
diff --git a/mnsl/mnsl.c b/mnsl/mnsl.c
new file mode 100644
index 0000000..2b59746
--- /dev/null
+++ b/mnsl/mnsl.c
@@ -0,0 +1,435 @@
+/*
+ * 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.
+ *
+ */
+
+/* parasoft suppress item * reason "not part of MOST NetServices delivery" */
+
+/*!
+ * \file
+ * \brief Implementation of MOST NetServices Light
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_types_cfg.h"
+#include "mnsl.h"
+#include "mns_base.h"
+#include "mns_misc.h"
+#include "mns_pmchannel.h"
+#include "mns_ams.h"
+#include "mns_transceiver.h"
+#include "mns_pmfifos.h"
+
+#include <assert.h> //TKU
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Mnsl_OnPmsEvent(void *self, void *event_code);
+static void Mnsl_OnServiceRequest(void *self, void *data_ptr);
+static void Mnsl_OnGetTickCount(void *self, void *tick_count_value_ptr);
+static void Mnsl_OnSetApplicationTimer(void *self, void *new_time_value_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation of class CMnsl */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Assigns default values to a provided MNSL init structure
+ * \param init_ptr Reference to MNSL init structure.
+ * \param enable_watchdog Set to \c true for normal use. Set to \c false to disable the watchdog
+ * supervision for debugging purpose only.
+ */
+extern void Mnsl_SetDefaultConfig(Mnsl_InitData_t *init_ptr, bool enable_watchdog)
+{
+ MISC_MEM_SET(init_ptr, 0, sizeof(Mnsl_InitData_t));
+
+ init_ptr->pms.active_fifos = MNSL_FIFOS_MCM_ICM;
+ init_ptr->pms.compressed = false;
+
+ init_ptr->pms.icm_config.fifo_id = PMP_FIFO_ID_ICM;
+ init_ptr->pms.icm_config.tx_wd_timeout = 0U;
+ init_ptr->pms.icm_config.tx_wd_timer_value = 0U;
+ init_ptr->pms.icm_config.rx_ack_timeout = 10U;
+ init_ptr->pms.icm_config.rx_busy_allowed = 0xFU;
+ init_ptr->pms.icm_config.rx_credits = PMCH_FIFO_CREDITS;
+ init_ptr->pms.icm_config.rx_threshold = PMCH_FIFO_THRESHOLD;
+
+ init_ptr->pms.rcm_config.fifo_id = PMP_FIFO_ID_RCM;
+ init_ptr->pms.rcm_config.tx_wd_timeout = 10U; /* watchdog timeout: 1s */
+ init_ptr->pms.rcm_config.tx_wd_timer_value = 600U; /* watchdog trigger every 600 ms */
+ init_ptr->pms.rcm_config.rx_ack_timeout = 10U;
+ init_ptr->pms.rcm_config.rx_busy_allowed = 0xFU;
+ init_ptr->pms.rcm_config.rx_credits = PMCH_FIFO_CREDITS;
+ init_ptr->pms.rcm_config.rx_threshold = PMCH_FIFO_THRESHOLD;
+
+ init_ptr->pms.mcm_config.fifo_id = PMP_FIFO_ID_MCM;
+ init_ptr->pms.mcm_config.tx_wd_timeout = 10U; /* watchdog timeout: 1s */
+ init_ptr->pms.mcm_config.tx_wd_timer_value = 600U; /* watchdog trigger every 600 ms */
+ init_ptr->pms.mcm_config.rx_ack_timeout = 10U;
+ init_ptr->pms.mcm_config.rx_busy_allowed = 0xFU;
+ init_ptr->pms.mcm_config.rx_credits = PMCH_MCM_CREDITS;
+ init_ptr->pms.mcm_config.rx_threshold = PMCH_MCM_THRESHOLD;
+
+ if (enable_watchdog == false)
+ {
+ init_ptr->pms.icm_config.rx_ack_timeout = 0U; /* acknowledge timeout: 0 -> infinite */
+ init_ptr->pms.rcm_config.tx_wd_timeout = 0U; /* watchdog timeout: 0 -> infinite */
+ init_ptr->pms.rcm_config.tx_wd_timer_value = 0U;/* watchdog timer: 0 -> no timer */
+ init_ptr->pms.rcm_config.rx_ack_timeout = 0U; /* acknowledge timeout: 0 -> infinite */
+ init_ptr->pms.mcm_config.tx_wd_timeout = 0U; /* watchdog timeout: 0 -> infinite */
+ init_ptr->pms.mcm_config.tx_wd_timer_value = 0U;/* watchdog timer: 0 -> no timer */
+ init_ptr->pms.mcm_config.rx_ack_timeout = 0U; /* acknowledge timeout: 0 -> infinite */
+ }
+}
+
+/*! \brief Initialize MNS Light class
+ * \param init_ptr Reference to the MNSL init structure.
+ * The memory of the init structure can be freed after the function returns.
+ */
+void Mnsl_Init(CMnsl *mnsl, Mnsl_InitData_t *init_ptr, void *inst_ptr)
+{
+ assert(NULL != mnsl);
+ CSingleObserver *srv_request_obs_ptr = NULL;
+ CSingleObserver *app_timer_obs_ptr = NULL;
+ Base_InitData_t base_init_data;
+ Pmch_InitData_t pmch_init_data;
+ CPmFifo *icm_ptr = NULL;
+ CPmFifo *rcm_ptr = NULL;
+ CPmFifo *mcm_ptr = NULL;
+ CTransceiver *trcv_mcm_ptr = NULL;
+ CTransceiver *trcv_rcm_ptr = NULL;
+
+ MISC_MEM_SET(mnsl, 0, sizeof(mnsl));
+ MISC_MEM_SET(&base_init_data, 0, sizeof(base_init_data));
+
+ mnsl->inst_ptr = inst_ptr; //TKU
+ mnsl->inst_id = 1U;
+ mnsl->get_tick_count_fptr = init_ptr->general.get_tickcount_fptr;
+ mnsl->srv_request_fptr = init_ptr->general.request_service_fptr;
+ mnsl->set_app_timer_fptr = init_ptr->general.set_app_timer_fptr;
+
+ if(mnsl->srv_request_fptr != NULL)
+ {
+ Sobs_Ctor(&mnsl->srv_request_obs, mnsl, &Mnsl_OnServiceRequest);
+ srv_request_obs_ptr = &mnsl->srv_request_obs;
+ }
+ if (mnsl->set_app_timer_fptr != NULL)
+ {
+ Sobs_Ctor(&mnsl->set_app_timer_obs, mnsl, &Mnsl_OnSetApplicationTimer);
+ app_timer_obs_ptr = &mnsl->set_app_timer_obs;
+ }
+
+ base_init_data.mns_inst_id = 1U;
+ base_init_data.tm.mns_inst_id = 1U;
+ base_init_data.scd.mns_inst_id = 1U;
+
+ Sobs_Ctor(&mnsl->get_tick_count_obs, mnsl, &Mnsl_OnGetTickCount);
+ base_init_data.tm.get_tick_count_obs_ptr = &mnsl->get_tick_count_obs;
+ base_init_data.scd.service_request_obs_ptr = srv_request_obs_ptr;
+ base_init_data.tm.set_application_timer_obs_ptr = app_timer_obs_ptr;
+
+ Base_Ctor(&mnsl->base, &base_init_data);
+
+ /* Initialize port message service */
+ pmch_init_data.mns_inst_id = 1U;
+ pmch_init_data.tx_release_fptr = &Fifo_TxOnRelease;
+ pmch_init_data.lld_iface = init_ptr->lld;
+ Pmch_Ctor(&mnsl->pm_channel, &pmch_init_data, inst_ptr);
+
+ if((init_ptr->pms.active_fifos & MNSL_FIFOS_ICM) == MNSL_FIFOS_ICM)
+ {
+ Fifo_InitData_t icm_init;
+
+ icm_init.base_ptr = &mnsl->base;
+ icm_init.channel_ptr = &mnsl->pm_channel;
+ icm_init.rx_cb_fptr = &Trcv_RxOnMsgComplete;
+ icm_init.rx_cb_inst = &mnsl->icm_transceiver;
+
+ if (init_ptr->pms.compressed)
+ {
+ icm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_80);
+ icm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_80);
+ }
+ else
+ {
+ icm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
+ icm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
+ }
+
+ Fifo_Ctor(&mnsl->icm_fifo, &icm_init, &init_ptr->pms.icm_config);
+ Trcv_Ctor(&mnsl->icm_transceiver, &mnsl->icm_fifo, MSG_ADDR_EHC_CFG, base_init_data.mns_inst_id, PMP_FIFO_ID_ICM);/* initialize ICM transceiver and set link to PMS instance */
+
+ icm_ptr = &mnsl->icm_fifo;
+ }
+
+ if((init_ptr->pms.active_fifos & MNSL_FIFOS_RCM) == MNSL_FIFOS_RCM)
+ {
+ Fifo_InitData_t rcm_init;
+
+ rcm_init.base_ptr = &mnsl->base;
+ rcm_init.channel_ptr = &mnsl->pm_channel;
+ rcm_init.rx_cb_fptr = &Trcv_RxOnMsgComplete;
+ rcm_init.rx_cb_inst = &mnsl->rcm_transceiver;
+ rcm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
+ rcm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
+ /* Note: RCM compressed data format is not supported */
+
+ Fifo_Ctor(&mnsl->rcm_fifo, &rcm_init, &init_ptr->pms.rcm_config);
+ Trcv_Ctor(&mnsl->rcm_transceiver, &mnsl->rcm_fifo, MSG_ADDR_EHC_CFG, base_init_data.mns_inst_id, PMP_FIFO_ID_RCM);/* initialize ICM transceiver and set link to PMS instance */
+
+ rcm_ptr = &mnsl->rcm_fifo;
+ trcv_rcm_ptr = &mnsl->rcm_transceiver;
+ }
+
+ if((init_ptr->pms.active_fifos & MNSL_FIFOS_MCM) == MNSL_FIFOS_MCM)
+ {
+ Fifo_InitData_t mcm_init;
+
+ mcm_init.base_ptr = &mnsl->base;
+ mcm_init.channel_ptr = &mnsl->pm_channel;
+ mcm_init.rx_cb_fptr = &Trcv_RxOnMsgComplete;
+ mcm_init.rx_cb_inst = &mnsl->mcm_transceiver;
+
+ if (init_ptr->pms.compressed)
+ {
+ mcm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_81);
+ mcm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_80);
+ }
+ else
+ {
+ mcm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
+ mcm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
+ }
+
+ Fifo_Ctor(&mnsl->mcm_fifo, &mcm_init, &init_ptr->pms.mcm_config);
+ Trcv_Ctor(&mnsl->mcm_transceiver, &mnsl->mcm_fifo, MSG_ADDR_EHC_APP, base_init_data.mns_inst_id, PMP_FIFO_ID_MCM);/* initialize ICM transceiver and set link to PMS instance */
+
+ mcm_ptr = &mnsl->mcm_fifo;
+ trcv_mcm_ptr = &mnsl->mcm_transceiver;
+ }
+
+ if ((trcv_mcm_ptr != NULL) || (trcv_rcm_ptr != NULL)) /* initialize AMS if MCM or RCM is active */
+ {
+ mnsl->ams_allocator.alloc_fptr = init_ptr->ams.rx_alloc_mem_fptr;
+ mnsl->ams_allocator.free_fptr = init_ptr->ams.rx_free_mem_fptr;
+ Amsp_Ctor(&mnsl->ams_pool, &mnsl->ams_allocator, mnsl->base.mns_inst_id);
+ Ams_Ctor(&mnsl->ams, &mnsl->base, trcv_mcm_ptr, trcv_rcm_ptr, &mnsl->ams_pool, AMS_RX_DEF_SIZE_PAYLOAD);
+ }
+
+ /* initialize FIFO handler */
+ Fifos_Ctor(&mnsl->fifos, &mnsl->base, &mnsl->pm_channel, icm_ptr, mcm_ptr, rcm_ptr);
+
+ /* register event callback */
+ mnsl->event_fptr = init_ptr->general.event_fptr;
+ Obs_Ctor(&mnsl->pms_observer, mnsl, &Mnsl_OnPmsEvent);
+ Fifos_AddEventObserver(&mnsl->fifos, &mnsl->pms_observer);
+}
+
+/*! \brief Synchronizes the PMS
+ * \details Accordingly MNSL_EVENT_SYNC_COMPLETE or MNSL_EVENT_SYNC_FAILED will be notified.
+ */
+void Mnsl_Synchronize(CMnsl *mnsl)
+{
+ assert(NULL != mnsl);
+ /* initializes the port message service & LLD interface */
+ Fifos_ConfigureSyncParams(&mnsl->fifos, FIFOS_SYNC_RETRIES, FIFOS_SYNC_TIMEOUT);
+ Fifos_Synchronize(&mnsl->fifos, true, true);
+}
+
+/*! \brief Un-synchronizes the PMS
+ * \details Accordingly MNSL_EVENT_UNSYNC_COMPLETE or MNSL_EVENT_UNSYNC_FAILED will be notified.
+ * Calling this function if MNSL is already un-synced will report MNSL_EVENT_UNSYNC_FAILED,
+ * since the low-level driver interface is not active.
+ * \param initial MNSL is able to trigger un-synchronization in advance of the initial
+ * synchronization. In this case, timeouts and retries behave like a synchronization
+ * and on MNSL_EVENT_UNSYNC_COMPLETE the LLD interface will stay running.
+ * I.e. if set to \c true the un-synchronization behaves like MNS initial un-synchronization.
+ * If set to \c false, the un-synchronization behaves like MNS final un-synchronization.
+ */
+void Mnsl_Unsynchronize(CMnsl *mnsl, bool initial)
+{
+ assert(NULL != mnsl);
+ if (initial == false)
+ {
+ Fifos_ConfigureSyncParams(&mnsl->fifos, FIFOS_UNSYNC_RETRIES, FIFOS_UNSYNC_TIMEOUT); /* final sync */
+ }
+ else
+ {
+ Fifos_ConfigureSyncParams(&mnsl->fifos, FIFOS_SYNC_RETRIES, FIFOS_SYNC_TIMEOUT); /* initial sync */
+ }
+
+ Fifos_Unsynchronize(&mnsl->fifos, true, initial);
+}
+
+/*! \brief Handles PMS event and notifies MNSL registered event callback
+ * \param self Reference to instance
+ * \param event_code Event notified by the PMS
+ */
+static void Mnsl_OnPmsEvent(void *self, void *event_code)
+{
+ assert(NULL != self);
+ Fifos_Event_t *code = (Fifos_Event_t*)event_code;
+ CMnsl *mnsl = (CMnsl *)self;
+
+ if (mnsl->event_fptr != NULL)
+ {
+ switch (*code)
+ {
+ case FIFOS_EV_SYNC_LOST:
+ Eh_ReportEvent(&mnsl->base.eh, EH_E_SYNC_LOST); /* event is necessary for AMS cleanup */
+ mnsl->event_fptr(MNSL_EVENT_SYNC_LOST, mnsl->inst_ptr);
+ break;
+ case FIFOS_EV_SYNC_ESTABLISHED:
+ mnsl->event_fptr(MNSL_EVENT_SYNC_COMPLETE, mnsl->inst_ptr);
+ break;
+ case FIFOS_EV_SYNC_FAILED:
+ mnsl->event_fptr(MNSL_EVENT_SYNC_FAILED, mnsl->inst_ptr);
+ break;
+ case FIFOS_EV_UNSYNC_COMPLETE:
+ mnsl->event_fptr(MNSL_EVENT_UNSYNC_COMPLETE, mnsl->inst_ptr);
+ Eh_ReportEvent(&mnsl->base.eh, EH_E_UNSYNC_COMPLETE); /* event is necessary for AMS cleanup */
+ break;
+ case FIFOS_EV_UNSYNC_FAILED:
+ mnsl->event_fptr(MNSL_EVENT_UNSYNC_FAILED, mnsl->inst_ptr);
+ Eh_ReportEvent(&mnsl->base.eh, EH_E_UNSYNC_FAILED); /* event is necessary for AMS cleanup */
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*! \brief Service function of MNS Light
+ */
+void Mnsl_Service(CMnsl *mnsl)
+{
+ assert(NULL != mnsl);
+ bool pending_events;
+
+ TR_INFO((mnsl->inst_id, "[API]", "Mnsl_Service()", 0U));
+ Scd_Service(&mnsl->base.scd); /* Run the scheduler */
+ pending_events = Scd_AreEventsPending(&mnsl->base.scd); /* Check if events are still pending? */
+
+ if (pending_events != false) /* At least one event is pending? */
+ {
+ TR_INFO((mnsl->inst_id, "[API]", "Mnsl_Service(): events still pending", 0U));
+ Mnsl_OnServiceRequest(mnsl, NULL);
+ }
+ else /* No event is pending */
+ {
+ TR_INFO((mnsl->inst_id, "[API]", "Mnsl_Service(): calling Tm_CheckForNextService()", 0U));
+ mnsl->base.scd.scd_srv_is_running = true; /* prevent continuous service requests if no app timer is provided */
+ Tm_CheckForNextService(&mnsl->base.tm); /* If MNS timers are running: What is the next time that the timer management must be */
+ mnsl->base.scd.scd_srv_is_running = false; /* serviced again? */
+ }
+}
+
+/*! \brief Reports that the application provided timer has expired.
+ */
+void Mnsl_ReportTimeout(CMnsl *mnsl)
+{
+ assert(NULL != mnsl);
+ TR_INFO((mnsl->inst_id, "[API]", "Mns_ReportTimeout()", 0U));
+ Tm_TriggerService(&mnsl->base.tm); /* Trigger TM service call */
+}
+
+/*! \brief Callback function which is invoked by the scheduler
+ * \param self Parameter not used with single instance API
+ * \param data_ptr Currently unused
+ */
+static void Mnsl_OnServiceRequest(void *self, void *data_ptr)
+{
+ assert(NULL != self);
+ CMnsl *mnsl = (CMnsl *)self;
+ MISC_UNUSED(data_ptr);
+
+ if (mnsl->srv_request_fptr != NULL)
+ {
+ TR_INFO((mnsl->inst_id, "[API]", "Mnsl_OnServiceRequest(): calling srv_request_fptr()", 0U));
+ mnsl->srv_request_fptr(mnsl->inst_ptr);
+ }
+}
+
+/*! \brief This function is used in combination with the observer \c mns.get_tick_count_obs
+ * which is used to request the current tick count value form the application.
+ * \param self Parameter not used with single instance API
+ * \param tick_count_value_ptr Reference to the requested tick count value. The pointer must
+ * be casted into data type uint16_t.
+ */
+static void Mnsl_OnGetTickCount(void *self, void *tick_count_value_ptr)
+{
+ assert(NULL != self);
+ CMnsl *mnsl = (CMnsl *)self;
+ *((uint16_t *)tick_count_value_ptr) = mnsl->get_tick_count_fptr();
+}
+
+/*! \brief Callback function which is invoked to start the application timer when the MNSL service
+ * is implemented event driven
+ * \param self The instance
+ * \param new_time_value_ptr Reference to the new timer value. The pointer must be casted into
+ * data type uint16_t.
+ */
+static void Mnsl_OnSetApplicationTimer(void *self, void *new_time_value_ptr)
+{
+ CMnsl *self_ = (CMnsl*)self;
+ TR_INFO((mnsl->inst_id, "[API]", "Mnsl_OnSetApplicationTimer(): set_app_timer_fptr(%d)", 1U, *((uint16_t *)new_time_value_ptr)));
+ self_->set_app_timer_fptr(*((uint16_t *)new_time_value_ptr), self_->inst_ptr);
+}
+
+/*! \brief Returns the ICM transceiver object
+ * \return Reference to the ICM transceiver
+ */
+CTransceiver * Mnsl_GetIcmTransceiver(CMnsl *mnsl)
+{
+ return &mnsl->icm_transceiver;
+}
+
+/*! \brief Returns the RCM transceiver object
+ * \return Reference to the RCM transceiver
+ */
+CTransceiver * Mnsl_GetRcmTransceiver(CMnsl *mnsl)
+{
+ return &mnsl->rcm_transceiver;
+}
+
+/*! \brief Returns the MCM transceiver object
+ * \return Reference to the MCM transceiver
+ */
+CTransceiver * Mnsl_GetMcmTransceiver(CMnsl *mnsl)
+{
+ return &mnsl->mcm_transceiver;
+}
+
+/*! \brief Returns the AMS transceiver object
+ * \details It is important not make usage of competing transceivers
+ * AMS, MCM and RCM. Either use AMS exclusively or MCM and RCM.
+ * Important: Do not use AMS in mode \c MNSL_FIFOS_ICM.
+ * \return Reference to the AMS
+ */
+CAms * Mnsl_GetAmsTransceiver(CMnsl *mnsl)
+{
+ return &mnsl->ams;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
diff --git a/mnsl/mnsl.h b/mnsl/mnsl.h
new file mode 100644
index 0000000..7288f50
--- /dev/null
+++ b/mnsl/mnsl.h
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ *
+ */
+
+/* parasoft suppress item * reason "not part of MOST NetServices delivery" */
+
+/*!
+ * \file
+ * \brief Header file of MOST NetServices Light
+ */
+
+#ifndef MNSL_H
+#define MNSL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_transceiver.h"
+#include "mns_ams.h"
+#include "mns_pmfifos.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Definitions */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief MNS Major Version Number */
+#define MNSL_VERSION_MAJOR 3
+/*! \brief MNS Minor Version Number */
+#define MNSL_VERSION_MINOR 2
+/*! \brief MNS Release Version Number */
+#define MNSL_VERSION_RELEASE 7
+/*! \brief MNS Service Release Number */
+#define MNSL_VERSION_SR 0
+/*! \brief MNS Build Number */
+#define MNSL_VERSION_BUILD 1796
+
+/*------------------------------------------------------------------------------------------------*/
+/* Types */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Defines which FIFOs shall be built on the Port Message Channel */
+typedef enum Mnsl_ActiveFifos_
+{
+ MNSL_FIFOS_MCM = 0x01U, /*!< \brief Initialize PM channel with MCM FIFO only */
+ MNSL_FIFOS_ICM = 0x02U, /*!< \brief Initialize PM channel with ICM FIFO only */
+ MNSL_FIFOS_MCM_ICM = 0x03U, /*!< \brief Initialize PM channel with MCM and ICM FIFO */
+ MNSL_FIFOS_RCM = 0x04U, /*!< \brief Initialize PM channel with RCM FIFO only */
+ MNSL_FIFOS_MCM_RCM = 0x05U, /*!< \brief Initialize PM channel with MCM and RCM FIFO */
+ MNSL_FIFOS_ICM_RCM = 0x06U, /*!< \brief Initialize PM channel with ICM and RCM FIFO */
+ MNSL_FIFOS_MCM_ICM_RCM = 0x07U /*!< \brief Initialize PM channel with MCM, ICM and RCM FIFO */
+
+} Mnsl_ActiveFifos_t;
+
+/*! \brief Possible MNSL events */
+typedef enum Mnsl_Event_
+{
+ MNSL_EVENT_SYNC_COMPLETE = 0, /*!< \brief The initial synchronization completed successfully */
+ MNSL_EVENT_SYNC_FAILED = 1, /*!< \brief The initial synchronization failed */
+ MNSL_EVENT_SYNC_LOST = 2, /*!< \brief The synchronization to the INIC was lost irrecoverably */
+ MNSL_EVENT_UNSYNC_COMPLETE = 3, /*!< \brief The un-synchronization was completed successfully */
+ MNSL_EVENT_UNSYNC_FAILED = 4 /*!< \brief The un-synchronization failed */
+
+} Mnsl_Event_t;
+
+typedef uint16_t (*Mnsl_GetTickCountCb_t)(void);
+typedef void (*Mnsl_EventCb_t)(Mnsl_Event_t event_code, void *inst_ptr);
+typedef void (*Mnsl_ServiceRequestCb_t)(void *inst_ptr);
+typedef void (*Mnsl_SetAppTimerCb_t)(uint16_t timeout, void *inst_ptr);
+
+/*! \brief General initialization settings */
+typedef struct Mnsl_General_InitData_
+{
+ Mnsl_EventCb_t event_fptr; /*!< \brief Reports an MNSL event (mandatory callback) */
+ Mnsl_GetTickCountCb_t get_tickcount_fptr; /*!< \brief Requests the current tick count in milliseconds (mandatory callback) */
+ Mnsl_ServiceRequestCb_t request_service_fptr;/*!< \brief Reports that the application shall call Mnsl_Service() (optional callback) */
+ Mnsl_SetAppTimerCb_t set_app_timer_fptr; /*!< \brief Triggers the application to call Mnsl_ReportTimeout() after a specific time (mandatory callback) */
+
+} Mnsl_General_InitData_t;
+
+/*! \brief Port Message Service (PMS) settings */
+typedef struct Mnsl_Pms_InitData_
+{
+ Mnsl_ActiveFifos_t active_fifos; /*!< \brief Defines which FIFOs shall be initialized */
+ Fifo_Config_t icm_config; /*!< \brief Setup of ICM FIFO */
+ Fifo_Config_t mcm_config; /*!< \brief Setup of MCM FIFO */
+ Fifo_Config_t rcm_config; /*!< \brief Setup of RCM FIFO */
+ bool compressed; /*!< \brief Set to \c true in order to use OS81118 Rev.C */
+
+} Mnsl_Pms_InitData_t;
+
+/*! \brief Application Message Service (AMS) settings */
+typedef struct Mnsl_Ams_InitData_
+{
+ Mns_Ams_AllocMemCb_t rx_alloc_mem_fptr; /*!< \brief Required to allocate memory for an AMS Rx message */
+ Mns_Ams_FreeMemCb_t rx_free_mem_fptr; /*!< \brief Required to free memory for an AMS Rx message */
+
+} Mnsl_Ams_InitData_t;
+
+/*! \brief Initialization settings */
+typedef struct Mnsl_InitData_
+{
+ Mnsl_General_InitData_t general; /*!< \brief Basic settings to drive MNSL */
+ Mns_Lld_Callbacks_t lld; /*!< \brief Mandatory callback functions of the driver */
+ Mnsl_Pms_InitData_t pms; /*!< \brief Port Message Service settings */
+ Mnsl_Ams_InitData_t ams; /*!< \brief Application Message Service settings */
+
+} Mnsl_InitData_t;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Helper Macros */
+/*------------------------------------------------------------------------------------------------*/
+#define MNSL_UNUSED(p) ((p) = (p)) /* parasoft-suppress MISRA2004-19_7 "suppress warning" */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal structures */
+/*------------------------------------------------------------------------------------------------*/
+typedef struct CMnsl_
+{
+ uint8_t inst_id;
+ CBase base;
+ CPmChannel pm_channel;
+ CPmFifos fifos;
+ CPmFifo icm_fifo;
+ CPmFifo rcm_fifo;
+ CPmFifo mcm_fifo;
+
+ Mnsl_GetTickCountCb_t get_tick_count_fptr;
+ CSingleObserver get_tick_count_obs;
+
+ Mnsl_ServiceRequestCb_t srv_request_fptr;
+ CSingleObserver srv_request_obs;
+
+ Mnsl_SetAppTimerCb_t set_app_timer_fptr;
+ CSingleObserver set_app_timer_obs;
+
+ CTransceiver icm_transceiver;
+ CTransceiver rcm_transceiver;
+ CTransceiver mcm_transceiver;
+ CAms ams;
+ CAmsMsgPool ams_pool;
+ Ams_MemAllocator_t ams_allocator;
+
+ Mnsl_EventCb_t event_fptr;
+ CObserver pms_observer;
+
+ void *inst_ptr; //TKU: added
+
+} CMnsl;
+
+/*------------------------------------------------------------------------------------------------*/
+/* Prototypes */
+/*------------------------------------------------------------------------------------------------*/
+extern void Mnsl_SetDefaultConfig(Mnsl_InitData_t *init_ptr, bool enable_watchdog);
+extern void Mnsl_Init(CMnsl *mnsl, Mnsl_InitData_t *init_ptr, void *inst_ptr);
+extern void Mnsl_Synchronize(CMnsl *mnsl);
+extern void Mnsl_Unsynchronize(CMnsl *mnsl, bool initial);
+extern void Mnsl_Service(CMnsl *mnsl);
+extern void Mnsl_ReportTimeout(CMnsl *mnsl);
+extern CTransceiver * Mnsl_GetIcmTransceiver(CMnsl *mnsl);
+extern CTransceiver * Mnsl_GetRcmTransceiver(CMnsl *mnsl);
+extern CTransceiver * Mnsl_GetMcmTransceiver(CMnsl *mnsl);
+extern CAms * Mnsl_GetAmsTransceiver(CMnsl *mnsl);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef MNSL_H */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+