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 API locking manager.
26 * \cond UCS_INTERNAL_DOC
31 /*------------------------------------------------------------------------------------------------*/
33 /*------------------------------------------------------------------------------------------------*/
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." */
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);
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
64 void Alm_Ctor(CApiLockingManager *self,
65 CTimerManagement *tm_ptr,
66 CEventHandler *eh_ptr,
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;
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);
80 /*! \brief Handles internal errors and events
81 * \param self Instance pointer
82 * \param error_code_ptr Reference to reported error code
84 static void Alm_HandleInternalErrors(void *self, void *error_code_ptr)
86 CApiLockingManager *self_ = (CApiLockingManager *)self;
87 MISC_UNUSED(error_code_ptr);
89 Tm_ClearTimer(self_->tm_ptr, &self_->garbage_collector); /* Clear timeout */
90 Alm_ResetRegisteredApis(self_); /* Reset all registered APIs */
93 /*! \brief Checks for API locking timeouts. This method is the callback function of timer
94 * \c garbage_collector.
95 * \param self Instance pointer
97 static void Alm_GarbageCollector(void *self)
99 CApiLockingManager *self_ = (CApiLockingManager *)self;
100 (void)Dl_Foreach(&self_->api_list, &Alm_CheckRegisteredApi, self_);
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
108 static bool Alm_CheckRegisteredApi(void *current_alm_ptr, void *alm_inst_ptr)
110 CApiLockingManager *self = (CApiLockingManager *)alm_inst_ptr;
111 CApiLocking *alm_ptr_ = (CApiLocking *)current_alm_ptr;
114 if(alm_ptr_->timeout_mask != 0U)
116 Alm_ModuleMask_t tmp_mask = 1U;
117 while(alm_ptr_->timeout_mask != 0U)
119 if(tmp_mask == (tmp_mask & alm_ptr_->timeout_mask))
121 Ssub_Notify(&alm_ptr_->subject, &tmp_mask, false);
122 alm_ptr_->method_mask &= ~tmp_mask;
123 alm_ptr_->timeout_mask &= ~tmp_mask;
127 Alm_ClearTimeout(self);
129 if(alm_ptr_->method_mask != 0U)
131 alm_ptr_->timeout_mask = alm_ptr_->method_mask;
136 /*! \brief Registers a new API locking object.
137 * \param self Instance pointer
138 * \param al_ptr Reference to the API to register
140 void Alm_RegisterApi(CApiLockingManager *self, CApiLocking *al_ptr)
142 Dl_InsertTail(&self->api_list, &al_ptr->node);
143 Dln_SetData(&al_ptr->node, al_ptr);
144 al_ptr->alm_ptr = self;
147 /*! \brief Starts the garbage collecting timer.
148 * \param self Instance pointer
150 static void Alm_StartTimeout(CApiLockingManager *self)
152 if(T_IsTimerInUse(&self->garbage_collector) == false)
154 Tm_SetTimer(self->tm_ptr,
155 &self->garbage_collector,
156 &Alm_GarbageCollector,
158 ALM_GARBAGE_COLLECTOR_INTERVAL,
159 ALM_GARBAGE_COLLECTOR_INTERVAL);
163 /*! \brief Clears the garbage collecting timer. The timer is clear if no API locking flag is
165 * \param self Instance pointer
167 static void Alm_ClearTimeout(CApiLockingManager *self)
169 if(Dl_Foreach(&self->api_list, &Alm_SearchLockedApi, self) == NULL)
171 Tm_ClearTimer(self->tm_ptr, &self->garbage_collector);
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
180 static bool Alm_SearchLockedApi(void *current_alm_ptr, void *alm_inst_ptr)
182 CApiLocking *alm_ptr_ = (CApiLocking *)current_alm_ptr;
183 bool ret_val = false;
184 MISC_UNUSED(alm_inst_ptr);
186 if(alm_ptr_->method_mask != 0U)
193 /*! \brief Resets all registered APIs. Called if an internal error has been occurred.
194 * \param self Instance pointer
196 static void Alm_ResetRegisteredApis(CApiLockingManager *self)
198 (void)Dl_Foreach(&self->api_list, &Alm_ResetApi, self);
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)
206 static bool Alm_ResetApi(void *current_alm_ptr, void *alm_inst_ptr)
208 CApiLocking *alm_ptr_ = (CApiLocking *)current_alm_ptr;
209 MISC_UNUSED(alm_inst_ptr);
211 alm_ptr_->method_mask = 0U;
212 alm_ptr_->timeout_mask = 0U;
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
225 void Al_Ctor(CApiLocking *self, CSingleObserver *obs_ptr, void * ucs_user_ptr)
227 MISC_MEM_SET(self, 0, sizeof(*self));
228 self->ucs_user_ptr = ucs_user_ptr;
229 Dln_Ctor(&self->node, NULL);
232 Ssub_Ctor(&self->subject, self->ucs_user_ptr);
233 (void)Ssub_AddObserver(&self->subject, obs_ptr);
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
243 bool Al_Lock(CApiLocking *self, Alm_ModuleMask_t method)
245 bool ret_val = false;
246 if((self->method_mask & method) == 0U)
249 self->method_mask |= method;
250 self->timeout_mask &= ~method;
251 Alm_StartTimeout(self->alm_ptr);
256 /*! \brief Releases the lock of the given API method.
257 * \param self Instance pointer
258 * \param method Bitmask of method to lock
260 void Al_Release(CApiLocking *self, Alm_ModuleMask_t method)
262 self->method_mask &= ~method;
263 self->timeout_mask &= ~method;
264 Alm_ClearTimeout(self->alm_ptr);
272 /*------------------------------------------------------------------------------------------------*/
274 /*------------------------------------------------------------------------------------------------*/