Initial Commit
[apps/agl-service-unicens.git] / ucs2-lib / src / ucs_alm.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 API locking manager.
25  *
26  * \cond UCS_INTERNAL_DOC
27  * \addtogroup G_ALM
28  * @{
29  */
30
31 /*------------------------------------------------------------------------------------------------*/
32 /* Includes                                                                                       */
33 /*------------------------------------------------------------------------------------------------*/
34 #include "ucs_alm.h"
35 #include "ucs_misc.h"
36
37 /*------------------------------------------------------------------------------------------------*/
38 /* Internal constant                                                                              */
39 /*------------------------------------------------------------------------------------------------*/
40 /*! \brief Interval for garbage collection */
41 static const uint16_t ALM_GARBAGE_COLLECTOR_INTERVAL = 2600U;   /* parasoft-suppress  MISRA2004-8_7 "Value shall be part of the module, not part of a function." */
42
43 /*------------------------------------------------------------------------------------------------*/
44 /* Internal prototypes                                                                            */
45 /*------------------------------------------------------------------------------------------------*/
46 static void Alm_HandleInternalErrors(void *self, void *error_code_ptr);
47 static void Alm_GarbageCollector(void *self);
48 static bool Alm_CheckRegisteredApi(void *current_alm_ptr, void *alm_inst_ptr);
49 static void Alm_StartTimeout(CApiLockingManager *self);
50 static void Alm_ClearTimeout(CApiLockingManager *self);
51 static bool Alm_SearchLockedApi(void *current_alm_ptr, void *alm_inst_ptr);
52 static void Alm_ResetRegisteredApis(CApiLockingManager *self);
53 static bool Alm_ResetApi(void *current_alm_ptr, void *alm_inst_ptr);
54
55 /*------------------------------------------------------------------------------------------------*/
56 /* Implementation of class CApiLockingManager                                                     */
57 /*------------------------------------------------------------------------------------------------*/
58 /*! \brief  Constructor of the API locking manager class.
59  *  \param  self        Instance pointer
60  *  \param  tm_ptr      Reference to timer management instance
61  *  \param  eh_ptr      Reference to event handler instance
62  *  \param  ucs_user_ptr User reference that needs to be passed in every callback function
63  */
64 void Alm_Ctor(CApiLockingManager *self,
65               CTimerManagement *tm_ptr,
66               CEventHandler *eh_ptr,
67               void * ucs_user_ptr)
68 {
69     MISC_MEM_SET(self, 0, sizeof(*self));
70     T_Ctor(&self->garbage_collector);
71     self->tm_ptr = tm_ptr;
72     self->eh_ptr = eh_ptr;
73     self->ucs_user_ptr = ucs_user_ptr;
74
75     /* Observe internal errors and events */
76     Mobs_Ctor(&self->internal_error_obs, self, EH_M_TERMINATION_EVENTS, &Alm_HandleInternalErrors);
77     Eh_AddObsrvInternalEvent(self->eh_ptr, &self->internal_error_obs);
78 }
79
80 /*! \brief  Handles internal errors and events
81  *  \param  self            Instance pointer
82  *  \param  error_code_ptr  Reference to reported error code
83  */
84 static void Alm_HandleInternalErrors(void *self, void *error_code_ptr)
85 {
86     CApiLockingManager *self_ = (CApiLockingManager *)self;
87     MISC_UNUSED(error_code_ptr);
88
89     Tm_ClearTimer(self_->tm_ptr, &self_->garbage_collector);    /* Clear timeout */
90     Alm_ResetRegisteredApis(self_);                             /* Reset all registered APIs */
91 }
92
93 /*! \brief  Checks for API locking timeouts. This method is the callback function of timer 
94  *          \c garbage_collector.
95  *  \param  self    Instance pointer
96  */
97 static void Alm_GarbageCollector(void *self)
98 {
99     CApiLockingManager *self_ = (CApiLockingManager *)self;
100     (void)Dl_Foreach(&self_->api_list, &Alm_CheckRegisteredApi, self_);
101 }
102
103 /*! \brief  This method is used by Alm_GarbageCollector() to process each registered API.
104  *  \param  current_alm_ptr     Reference to the current API
105  *  \param  alm_inst_ptr        Instance of the API locking manager
106  *  \return \c false to process all registered APIs
107  */
108 static bool Alm_CheckRegisteredApi(void *current_alm_ptr, void *alm_inst_ptr)
109 {
110     CApiLockingManager *self = (CApiLockingManager *)alm_inst_ptr;
111     CApiLocking *alm_ptr_ = (CApiLocking *)current_alm_ptr;
112     MISC_UNUSED(self);
113
114     if(alm_ptr_->timeout_mask != 0U)
115     {
116         Alm_ModuleMask_t tmp_mask = 1U;
117         while(alm_ptr_->timeout_mask != 0U)
118         {
119             if(tmp_mask == (tmp_mask & alm_ptr_->timeout_mask))
120             {
121                 Ssub_Notify(&alm_ptr_->subject, &tmp_mask, false);
122                 alm_ptr_->method_mask &= ~tmp_mask;
123                 alm_ptr_->timeout_mask &= ~tmp_mask;
124             }
125             tmp_mask <<= 1;
126         }
127         Alm_ClearTimeout(self);
128     }
129     if(alm_ptr_->method_mask != 0U)
130     {
131         alm_ptr_->timeout_mask = alm_ptr_->method_mask;
132     }
133     return false;
134 }
135
136 /*! \brief  Registers a new API locking object.
137  *  \param  self    Instance pointer
138  *  \param  al_ptr  Reference to the API to register
139  */
140 void Alm_RegisterApi(CApiLockingManager *self, CApiLocking *al_ptr)
141 {
142     Dl_InsertTail(&self->api_list, &al_ptr->node);
143     Dln_SetData(&al_ptr->node, al_ptr);
144     al_ptr->alm_ptr = self;
145 }
146
147 /*! \brief  Starts the garbage collecting timer.
148  *  \param  self    Instance pointer
149  */
150 static void Alm_StartTimeout(CApiLockingManager *self)
151 {
152     if(T_IsTimerInUse(&self->garbage_collector) == false)
153     {
154         Tm_SetTimer(self->tm_ptr,
155                     &self->garbage_collector,
156                     &Alm_GarbageCollector,
157                     self,
158                     ALM_GARBAGE_COLLECTOR_INTERVAL,
159                     ALM_GARBAGE_COLLECTOR_INTERVAL);
160     }
161 }
162
163 /*! \brief  Clears the garbage collecting timer. The timer is clear if no API locking flag is 
164  *          currently pending.
165  *  \param  self    Instance pointer
166  */
167 static void Alm_ClearTimeout(CApiLockingManager *self)
168 {
169     if(Dl_Foreach(&self->api_list, &Alm_SearchLockedApi, self) == NULL)
170     {
171         Tm_ClearTimer(self->tm_ptr, &self->garbage_collector);
172     }
173 }
174
175 /*! \brief  Used by Alm_ClearTimeout() to check if at least one registered API is locked.
176  *  \param  current_alm_ptr     Reference to the current API locking object
177  *  \param  alm_inst_ptr        Instance of the API locking manager
178  *  \return \c true if a locked API was found, otherwise \c false
179  */
180 static bool Alm_SearchLockedApi(void *current_alm_ptr, void *alm_inst_ptr)
181 {
182     CApiLocking *alm_ptr_ = (CApiLocking *)current_alm_ptr;
183     bool ret_val = false;
184     MISC_UNUSED(alm_inst_ptr);
185
186     if(alm_ptr_->method_mask != 0U)
187     {
188         ret_val = true;
189     }
190     return ret_val;
191 }
192
193 /*! \brief  Resets all registered APIs. Called if an internal error has been occurred.
194  *  \param  self    Instance pointer
195  */
196 static void Alm_ResetRegisteredApis(CApiLockingManager *self)
197 {
198     (void)Dl_Foreach(&self->api_list, &Alm_ResetApi, self);
199 }
200
201 /*! \brief  Used by Alm_ResetRegisteredApis() to reset all registered APIs.
202  *  \param  current_alm_ptr     Reference to the current API locking object
203  *  \param  alm_inst_ptr        Instance of the API locking manager
204  *  \return \c false (process all registered APIs)
205  */
206 static bool Alm_ResetApi(void *current_alm_ptr, void *alm_inst_ptr)
207 {
208     CApiLocking *alm_ptr_ = (CApiLocking *)current_alm_ptr;
209     MISC_UNUSED(alm_inst_ptr);
210
211     alm_ptr_->method_mask = 0U;
212     alm_ptr_->timeout_mask = 0U;
213
214     return false;
215 }
216
217 /*------------------------------------------------------------------------------------------------*/
218 /* Implementation of class CApiLocking                                                            */
219 /*------------------------------------------------------------------------------------------------*/
220 /*! \brief  Constructor of the API locking class.
221  *  \param  self            Instance pointer
222  *  \param  obs_ptr         Observer to signal locked API methods
223  *  \param  ucs_user_ptr     User reference that needs to be passed in every callback function
224  */
225 void Al_Ctor(CApiLocking *self, CSingleObserver *obs_ptr, void * ucs_user_ptr)
226 {
227     MISC_MEM_SET(self, 0, sizeof(*self));
228     self->ucs_user_ptr = ucs_user_ptr;
229     Dln_Ctor(&self->node, NULL);
230     if(obs_ptr != NULL)
231     {
232         Ssub_Ctor(&self->subject, self->ucs_user_ptr);
233         (void)Ssub_AddObserver(&self->subject, obs_ptr);
234     }
235 }
236
237 /*! \brief  Locks the given API method.
238  *  \param  self    Instance pointer
239  *  \param  method  Bitmask of method to lock
240  *  \return \c true if the API has been locked successfully
241  *  \return \c false if the API was already locked
242  */
243 bool Al_Lock(CApiLocking *self, Alm_ModuleMask_t method)
244 {
245     bool ret_val = false;
246     if((self->method_mask & method) == 0U)
247     {
248         ret_val = true;
249         self->method_mask |= method;
250         self->timeout_mask &= ~method;
251         Alm_StartTimeout(self->alm_ptr);
252     }
253     return ret_val;
254 }
255
256 /*! \brief  Releases the lock of the given API method.
257  *  \param  self    Instance pointer
258  *  \param  method  Bitmask of method to lock
259  */
260 void Al_Release(CApiLocking *self, Alm_ModuleMask_t method)
261 {
262     self->method_mask &= ~method;
263     self->timeout_mask &= ~method;
264     Alm_ClearTimeout(self->alm_ptr);
265 }
266
267 /*!
268  * @}
269  * \endcond
270  */
271
272 /*------------------------------------------------------------------------------------------------*/
273 /* End of file                                                                                    */
274 /*------------------------------------------------------------------------------------------------*/
275