Initial Commit
[apps/agl-service-unicens.git] / ucs2-lib / src / ucs_scheduler.c
1 /*------------------------------------------------------------------------------------------------*/
2 /* UNICENS V2.1.0-3491                                                                            */
3 /* Copyright (c) 2017 Microchip Technology Germany II GmbH & Co. KG.                              */
4 /*                                                                                                */
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.                                                            */
9 /*                                                                                                */
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.                                                   */
14 /*                                                                                                */
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/>.                          */
17 /*                                                                                                */
18 /* You may also obtain this software under a propriety license from Microchip.                    */
19 /* Please contact Microchip for further information.                                              */
20 /*------------------------------------------------------------------------------------------------*/
21
22 /*!
23  * \file
24  * \brief Implementation of the scheduler module. The module consists of the two classes
25  *        CScheduler and CService.
26  *
27  * \cond UCS_INTERNAL_DOC
28  * \addtogroup G_SCHEDULER
29  * @{
30  */
31
32 /*------------------------------------------------------------------------------------------------*/
33 /* Includes                                                                                       */
34 /*------------------------------------------------------------------------------------------------*/
35 #include "ucs_scheduler.h"
36 #include "ucs_misc.h"
37
38 /*------------------------------------------------------------------------------------------------*/
39 /* Constants                                                                                      */
40 /*------------------------------------------------------------------------------------------------*/
41 const Srv_Event_t SRV_EMPTY_EVENT_MASK = (Srv_Event_t)0x00000000;   /*!< \brief Empty event mask */
42
43 /*------------------------------------------------------------------------------------------------*/
44 /* Internal prototypes                                                                            */
45 /*------------------------------------------------------------------------------------------------*/
46 static bool Scd_SearchSlot(void *current_prio_ptr, void *new_prio_ptr);
47
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
55  */
56 void Scd_Ctor(CScheduler *self, Scd_InitData_t *init_ptr, void * ucs_user_ptr)
57 {
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;
65 }
66
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
73  */
74 Scd_Ret_t Scd_AddService(CScheduler *self, CService *srv_ptr)
75 {
76     Scd_Ret_t ret_val;
77
78     /* Check that service is not already part of scheduler */
79     if(Dl_IsNodeInList(&self->srv_list, &srv_ptr->list_node) == false) 
80     {
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);
83
84         if(result_ptr != NULL)   /* Slot found? */
85         {
86             Dl_InsertBefore(&self->srv_list, result_ptr, &srv_ptr->list_node);
87         }
88         else                    /* No slot found -> Insert as last node */
89         {
90             Dl_InsertTail(&self->srv_list, &srv_ptr->list_node);
91         }
92         /* Create back link service -> scheduler */
93         srv_ptr->scd_ptr = self;
94         Dln_SetData(&srv_ptr->list_node, &srv_ptr->priority);
95         ret_val = SCD_OK;
96     }
97     else    /* Service is already part of schedulers list */
98     {
99         ret_val = SCD_SRV_ALREADY_LISTED;
100     }
101
102     return ret_val;
103 }
104
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
110  */
111 Scd_Ret_t Scd_RemoveService(CScheduler *self, CService *srv_ptr)
112 {
113     Scd_Ret_t ret_val = SCD_OK;
114
115     /* Error occurred? */
116     if(Dl_Remove(&self->srv_list, &srv_ptr->list_node) == DL_UNKNOWN_NODE)
117     {
118         ret_val = SCD_UNKNOWN_SRV;
119     }
120
121     return ret_val;
122 }
123
124 /*! \brief Service function of the scheduler module.
125  *  \param self   Instance pointer
126  */
127 void Scd_Service(CScheduler *self)
128 {
129     CService *current_srv_ptr = (CService *)(void*)self->srv_list.head;
130
131     /* Scheduler service is running. Important for event handling */
132     self->scd_srv_is_running = true;
133
134     while(current_srv_ptr != NULL)   /* Process registered services */
135     {
136         if(current_srv_ptr->service_fptr != NULL)
137         {
138             /* Are events pending for the current service */
139             if(current_srv_ptr->event_mask != SRV_EMPTY_EVENT_MASK)
140             {
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))
145                 {
146                     break;  /* Abort scheduler service */
147                 }
148             }
149         }
150         current_srv_ptr = (CService *)(void*)current_srv_ptr->list_node.next;
151     }
152     /* Scheduler services finished */
153     self->scd_srv_is_running = false;
154 }
155
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
160  */
161 bool Scd_AreEventsPending(CScheduler *self)
162 {
163     bool ret_val = false;
164     CService *current_srv_ptr = (CService *)(void*)self->srv_list.head;
165
166     while(current_srv_ptr != NULL)
167     {
168         if(current_srv_ptr->event_mask != SRV_EMPTY_EVENT_MASK)
169         {
170             ret_val = true;
171             break;
172         }
173         current_srv_ptr = (CService *)(void*)current_srv_ptr->list_node.next;
174     }
175
176     return ret_val;
177 }
178
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
186  */
187 static bool Scd_SearchSlot(void *current_prio_ptr, void *new_prio_ptr)
188 {
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;
192
193     if(current_prio_ptr_ <= new_prio_)
194     {
195         ret_val = true;
196     }
197
198     return ret_val;
199 }
200
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
209  */
210 void Srv_Ctor(CService *self, uint8_t priority, void *instance_ptr, Srv_Cb_t service_fptr)
211 {
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;
217 }
218
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
222  */
223 void Srv_SetEvent(CService *self, Srv_Event_t event_mask)
224 {
225     self->event_mask |= event_mask;
226     if(self->scd_ptr->scd_srv_is_running == false) 
227     {
228         Ssub_Notify(&self->scd_ptr->service_request_subject, NULL, false);
229     }
230 }
231
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
235  */
236 void Srv_GetEvent(CService *self, Srv_Event_t *event_mask_ptr)
237 {
238     *event_mask_ptr = self->event_mask;
239 }
240
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
244  */
245 void Srv_ClearEvent(CService *self, Srv_Event_t event_mask)
246 {
247     self->event_mask &= ~event_mask;
248 }
249
250 /*!
251  * @}
252  * \endcond
253  */
254
255 /*------------------------------------------------------------------------------------------------*/
256 /* End of file                                                                                    */
257 /*------------------------------------------------------------------------------------------------*/
258