diff options
Diffstat (limited to 'mnsl/mns_scheduler.c')
-rw-r--r-- | mnsl/mns_scheduler.c | 259 |
1 files changed, 259 insertions, 0 deletions
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 */ +/*------------------------------------------------------------------------------------------------*/ + |