diff options
Diffstat (limited to 'mnsl/mnsl.c')
-rw-r--r-- | mnsl/mnsl.c | 435 |
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 */ +/*------------------------------------------------------------------------------------------------*/ |