1 /*------------------------------------------------------------------------------------------------*/
2 /* UNICENS V2.1.0-3491 */
3 /* Copyright (c) 2017 Microchip Technology Germany II GmbH & Co. KG. */
5 /* This program is free software: you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation, either version 2 of the License, or */
8 /* (at your option) any later version. */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details. */
15 /* You should have received a copy of the GNU General Public License */
16 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* You may also obtain this software under a propriety license from Microchip. */
19 /* Please contact Microchip for further information. */
20 /*------------------------------------------------------------------------------------------------*/
24 * \brief Implementation of the scheduler module. The module consists of the two classes
25 * CScheduler and CService.
27 * \cond UCS_INTERNAL_DOC
28 * \addtogroup G_SCHEDULER
32 /*------------------------------------------------------------------------------------------------*/
34 /*------------------------------------------------------------------------------------------------*/
35 #include "ucs_scheduler.h"
38 /*------------------------------------------------------------------------------------------------*/
40 /*------------------------------------------------------------------------------------------------*/
41 const Srv_Event_t SRV_EMPTY_EVENT_MASK = (Srv_Event_t)0x00000000; /*!< \brief Empty event mask */
43 /*------------------------------------------------------------------------------------------------*/
44 /* Internal prototypes */
45 /*------------------------------------------------------------------------------------------------*/
46 static bool Scd_SearchSlot(void *current_prio_ptr, void *new_prio_ptr);
48 /*------------------------------------------------------------------------------------------------*/
49 /* Implementation of class CScheduler */
50 /*------------------------------------------------------------------------------------------------*/
51 /*! \brief Constructor of the scheduler class.
52 * \param self Instance pointer
53 * \param init_ptr Reference to the initialization data
54 * \param ucs_user_ptr User reference that needs to be passed in every callback function
56 void Scd_Ctor(CScheduler *self, Scd_InitData_t *init_ptr, void * ucs_user_ptr)
58 MISC_MEM_SET(self, 0, sizeof(*self));
59 self->ucs_user_ptr = ucs_user_ptr;
60 Dl_Ctor(&self->srv_list, ucs_user_ptr);
61 Ssub_Ctor(&self->service_request_subject, ucs_user_ptr);
62 (void)Ssub_AddObserver(&self->service_request_subject,
63 init_ptr->service_request_obs_ptr);
64 self->scd_srv_is_running = false;
67 /*! \brief Add the given service to the scheduler. All services are arranged in priority order.
68 * A service with a higher priority will execute before a service with a lower priority.
69 * \param self Instance pointer
70 * \param srv_ptr Reference of the service which shall be added
71 * \return SCD_OK: Service added
72 * \return SCD_SRV_ALREADY_LISTED: Services already listed
74 Scd_Ret_t Scd_AddService(CScheduler *self, CService *srv_ptr)
78 /* Check that service is not already part of scheduler */
79 if(Dl_IsNodeInList(&self->srv_list, &srv_ptr->list_node) == false)
81 /* Search slot where the service must be inserted depending on the priority value. */
82 CDlNode *result_ptr = Dl_Foreach(&self->srv_list, &Scd_SearchSlot, &srv_ptr->priority);
84 if(result_ptr != NULL) /* Slot found? */
86 Dl_InsertBefore(&self->srv_list, result_ptr, &srv_ptr->list_node);
88 else /* No slot found -> Insert as last node */
90 Dl_InsertTail(&self->srv_list, &srv_ptr->list_node);
92 /* Create back link service -> scheduler */
93 srv_ptr->scd_ptr = self;
94 Dln_SetData(&srv_ptr->list_node, &srv_ptr->priority);
97 else /* Service is already part of schedulers list */
99 ret_val = SCD_SRV_ALREADY_LISTED;
105 /*! \brief Remove the given service from the schedulers list.
106 * \param self Instance pointer
107 * \param srv_ptr Reference of the service which shall be removed
108 * \return SCD_OK: Service removed
109 * \return SCD_UNKNOWN_SRV: Unknown service can not be removed
111 Scd_Ret_t Scd_RemoveService(CScheduler *self, CService *srv_ptr)
113 Scd_Ret_t ret_val = SCD_OK;
115 /* Error occurred? */
116 if(Dl_Remove(&self->srv_list, &srv_ptr->list_node) == DL_UNKNOWN_NODE)
118 ret_val = SCD_UNKNOWN_SRV;
124 /*! \brief Service function of the scheduler module.
125 * \param self Instance pointer
127 void Scd_Service(CScheduler *self)
129 CService *current_srv_ptr = (CService *)(void*)self->srv_list.head;
131 /* Scheduler service is running. Important for event handling */
132 self->scd_srv_is_running = true;
134 while(current_srv_ptr != NULL) /* Process registered services */
136 if(current_srv_ptr->service_fptr != NULL)
138 /* Are events pending for the current service */
139 if(current_srv_ptr->event_mask != SRV_EMPTY_EVENT_MASK)
141 /* Execute service callback function */
142 current_srv_ptr->service_fptr(current_srv_ptr->instance_ptr);
143 /* Was the current service removed from the schedulers list? */
144 if((current_srv_ptr->list_node.prev == NULL) && (current_srv_ptr->list_node.next == NULL))
146 break; /* Abort scheduler service */
150 current_srv_ptr = (CService *)(void*)current_srv_ptr->list_node.next;
152 /* Scheduler services finished */
153 self->scd_srv_is_running = false;
156 /*! \brief Searches for pending events.
157 * \param self Instance pointer
158 * \return true: At least one event is active
159 * \return false: No event is pending
161 bool Scd_AreEventsPending(CScheduler *self)
163 bool ret_val = false;
164 CService *current_srv_ptr = (CService *)(void*)self->srv_list.head;
166 while(current_srv_ptr != NULL)
168 if(current_srv_ptr->event_mask != SRV_EMPTY_EVENT_MASK)
173 current_srv_ptr = (CService *)(void*)current_srv_ptr->list_node.next;
179 /*! \brief Searches the slot where the new service has to be inserted. The position depends on
180 * the given priority. If a the priority of the new service is higher than the priority
181 * of the current service \c true is returned which stops the search.
182 * \param current_prio_ptr Current service which is analyzed
183 * \param new_prio_ptr Priority of the new service
184 * \return false: The priority of the current service is greater than the new priority
185 * \return true: The priority of the current service is less than or equal to the new priority
187 static bool Scd_SearchSlot(void *current_prio_ptr, void *new_prio_ptr)
189 uint8_t current_prio_ptr_ = *((uint8_t *)current_prio_ptr);
190 uint8_t new_prio_ = *((uint8_t*)new_prio_ptr);
191 bool ret_val = false;
193 if(current_prio_ptr_ <= new_prio_)
201 /*------------------------------------------------------------------------------------------------*/
202 /* Implementation of class CService */
203 /*------------------------------------------------------------------------------------------------*/
204 /*! \brief Parameter constructor of the service class.
205 * \param self Instance pointer
206 * \param instance_ptr Reference to object which contains the corresponding service
207 * \param priority Priority of the service
208 * \param service_fptr Service callback
210 void Srv_Ctor(CService *self, uint8_t priority, void *instance_ptr, Srv_Cb_t service_fptr)
212 MISC_MEM_SET(self, 0, sizeof(*self));
213 Dln_Ctor(&self->list_node, NULL);
214 self->priority = priority;
215 self->instance_ptr = instance_ptr;
216 self->service_fptr = service_fptr;
219 /*! \brief Sets events for the given service according to the given event mask.
220 * \param self Instance pointer
221 * \param event_mask Mask of the events to be set
223 void Srv_SetEvent(CService *self, Srv_Event_t event_mask)
225 self->event_mask |= event_mask;
226 if(self->scd_ptr->scd_srv_is_running == false)
228 Ssub_Notify(&self->scd_ptr->service_request_subject, NULL, false);
232 /*! \brief The function returns the current state of all event bits of the service.
233 * \param self Instance pointer
234 * \param event_mask_ptr Reference to the memory of the returned event mask
236 void Srv_GetEvent(CService *self, Srv_Event_t *event_mask_ptr)
238 *event_mask_ptr = self->event_mask;
241 /*! \brief Clears events for the given service according to the given event mask.
242 * \param self Instance pointer
243 * \param event_mask Mask of the events to be clear
245 void Srv_ClearEvent(CService *self, Srv_Event_t event_mask)
247 self->event_mask &= ~event_mask;
255 /*------------------------------------------------------------------------------------------------*/
257 /*------------------------------------------------------------------------------------------------*/