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