/* * MOST NetServices "Light" V3.2.7.0.1796 MultiInstance Patch * * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * You may also obtain this software under a propriety license from Microchip. * Please contact Microchip for further information. * */ /* 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 //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 */ /*------------------------------------------------------------------------------------------------*/