summaryrefslogtreecommitdiffstats
path: root/mnsl/mnsl.c
diff options
context:
space:
mode:
Diffstat (limited to 'mnsl/mnsl.c')
-rw-r--r--mnsl/mnsl.c435
1 files changed, 435 insertions, 0 deletions
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 */
+/*------------------------------------------------------------------------------------------------*/