diff options
Diffstat (limited to 'ucs2-lib/src/ucs_timer.c')
-rw-r--r-- | ucs2-lib/src/ucs_timer.c | 456 |
1 files changed, 0 insertions, 456 deletions
diff --git a/ucs2-lib/src/ucs_timer.c b/ucs2-lib/src/ucs_timer.c deleted file mode 100644 index 6563374..0000000 --- a/ucs2-lib/src/ucs_timer.c +++ /dev/null @@ -1,456 +0,0 @@ -/*------------------------------------------------------------------------------------------------*/ -/* UNICENS V2.1.0-3491 */ -/* Copyright (c) 2017 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 2 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 timer management module. - * - * \cond UCS_INTERNAL_DOC - * \addtogroup G_TIMER - * @{ - */ - -/*------------------------------------------------------------------------------------------------*/ -/* Includes */ -/*------------------------------------------------------------------------------------------------*/ -#include "ucs_timer.h" -#include "ucs_misc.h" -#include "ucs_trace.h" - -/*------------------------------------------------------------------------------------------------*/ -/* Service parameters */ -/*------------------------------------------------------------------------------------------------*/ -/*! Priority of the TM service used by scheduler */ -static const uint8_t TM_SRV_PRIO = 255U; /* parasoft-suppress MISRA2004-8_7 "Value shall be part of the module, not part of a function." */ -/*! Main event for the TM service */ -static const Srv_Event_t TM_EVENT_UPDATE_TIMERS = 1U; - -/*------------------------------------------------------------------------------------------------*/ -/* Internal prototypes */ -/*------------------------------------------------------------------------------------------------*/ -static void Tm_Service(void *self); -static void Tm_UpdateTimers(CTimerManagement *self); -static bool Tm_HandleElapsedTimer(CTimerManagement *self); -static bool Tm_UpdateTimersAdd(void *c_timer_ptr, void *n_timer_ptr); -static void Tm_SetTimerInternal(CTimerManagement *self, - CTimer *timer_ptr, - Tm_Handler_t handler_fptr, - void *args_ptr, - uint16_t elapse, - uint16_t period); - -/*------------------------------------------------------------------------------------------------*/ -/* Implementation of class CTimerManagement */ -/*------------------------------------------------------------------------------------------------*/ -/*! \brief Constructor of the timer management class. - * \param self Instance pointer - * \param scd Scheduler instance - * \param init_ptr Reference to the initialization data - * \param ucs_user_ptr User reference that needs to be passed in every callback function - */ -void Tm_Ctor(CTimerManagement *self, CScheduler *scd, const Tm_InitData_t *init_ptr, void * ucs_user_ptr) -{ - MISC_MEM_SET(self, 0, sizeof(*self)); - self->ucs_user_ptr = ucs_user_ptr; - /* Initialize subjects and add observers */ - Ssub_Ctor(&self->get_tick_count_subject, self->ucs_user_ptr); - (void)Ssub_AddObserver(&self->get_tick_count_subject, - init_ptr->get_tick_count_obs_ptr); - if(init_ptr->set_application_timer_obs_ptr != NULL) - { - self->delayed_tm_service_enabled = true; - Ssub_Ctor(&self->set_application_timer_subject, self->ucs_user_ptr); - (void)Ssub_AddObserver(&self->set_application_timer_subject, - init_ptr->set_application_timer_obs_ptr); - } - /* Initialize timer management service */ - Srv_Ctor(&self->tm_srv, TM_SRV_PRIO, self, &Tm_Service); - /* Add timer management service to scheduler */ - (void)Scd_AddService(scd, &self->tm_srv); -} - -/*! \brief Service function of the timer management. - * \param self Instance pointer - */ -static void Tm_Service(void *self) -{ - CTimerManagement *self_ = (CTimerManagement *)self; - Srv_Event_t event_mask; - - Srv_GetEvent(&self_->tm_srv, &event_mask); - - if(TM_EVENT_UPDATE_TIMERS == (event_mask & TM_EVENT_UPDATE_TIMERS)) /* Is event pending? */ - { - Srv_ClearEvent(&self_->tm_srv, TM_EVENT_UPDATE_TIMERS); - Tm_UpdateTimers(self_); - } -} - -/*! \brief If event TM_EVENT_UPDATE_TIMERS is set this function is called. Handles the update - * of the timer list. If a timer has expired the corresponding callback function is - * executed. If the expired timer is a periodic timer, the timer will be set again. - * \param self Instance pointer - */ -static void Tm_UpdateTimers(CTimerManagement *self) -{ - uint16_t current_tick_count; - Ssub_Notify(&self->get_tick_count_subject, ¤t_tick_count, false); - - if(self->timer_list.head != NULL) /* At least one timer is running? */ - { - bool continue_loop = true; - /* Calculate time difference between the current and the last TM service run */ - uint16_t tick_count_diff = (uint16_t)(current_tick_count - self->last_tick_count); - /* Save current tick count for next service run */ - self->last_tick_count = current_tick_count; - - /* Loop while timer list is not empty */ - while((self->timer_list.head != NULL) && (continue_loop!= false)) - { - /* Is not first timer in list elapsed yet? */ - if(tick_count_diff <= ((CTimer *)self->timer_list.head->data_ptr)->delta) - { - /* Update delta of first timer in list */ - ((CTimer *)self->timer_list.head->data_ptr)->delta -= tick_count_diff; - tick_count_diff = 0U; - } - else /* At least first timer in list elapsed */ - { - /* Update tick count difference for next timer in list */ - tick_count_diff -= ((CTimer *)self->timer_list.head->data_ptr)->delta; - /* First timer elapsed */ - ((CTimer *)self->timer_list.head->data_ptr)->delta = 0U; - } - - /* First timer in list elapsed? */ - if(0U == ((CTimer *)self->timer_list.head->data_ptr)->delta) - { - /* Handle elapsed timer */ - continue_loop = Tm_HandleElapsedTimer(self); - } - else /* No elapsed timer in list. */ - { - /* First timer in list updated! Set trigger to inform application (see - Tm_CheckForNextService()) and stop TM service. */ - self->set_service_timer = true; - continue_loop = false; - } - } - } -} - -/*! \brief This function is called if the first timer in list is elapsed. The timer handler - * callback function is invoked. If the timer is a periodic timer it is wound up again. - * \param self Instance pointer - * \return \c true if the next timer must be check. - * \return \c false if the wound up timer (periodic timer) is new head of timer list - */ -static bool Tm_HandleElapsedTimer(CTimerManagement *self) -{ - bool ret_val = true; - - CDlNode *node = self->timer_list.head; - /* Reset flag to be able to check if timer object has changed within handler - callback function */ - ((CTimer *)node->data_ptr)->changed = false; - /* Call timer handler callback function */ - ((CTimer *)node->data_ptr)->handler_fptr(((CTimer *)node->data_ptr)->args_ptr); - - /* Timer object hasn't changed within handler callback function? */ - if(false == ((CTimer *)node->data_ptr)->changed) - { - /* Remove current timer from list */ - (void)Dl_Remove(&self->timer_list, node); - /* Mark timer as unused */ - ((CTimer *)node->data_ptr)->in_use = false; - /* Is current timer a periodic timer? */ - if(((CTimer *)node->data_ptr)->period > 0U) - { - /* Reload current timer */ - Tm_SetTimerInternal(self, - ((CTimer *)node->data_ptr), - ((CTimer *)node->data_ptr)->handler_fptr, - ((CTimer *)node->data_ptr)->args_ptr, - ((CTimer *)node->data_ptr)->period, - ((CTimer *)node->data_ptr)->period); - - if(node == self->timer_list.head) /* Is current timer new head of list? */ - { - /* Set trigger to inform application (see Tm_CheckForNextService()) and - stop TM service. */ - self->set_service_timer = true; - ret_val = false; - } - } - } - - return ret_val; -} - -/*! \brief Calls an application callback function to inform the application that the UCS must be - * serviced not later than the passed time period. If the timer list is empty a possible - * running application timer will be stopped. This function is called at the end of - * Ucs_Service(). - * \param self Instance pointer - */ -void Tm_CheckForNextService(CTimerManagement *self) -{ - if(self->delayed_tm_service_enabled != false) - { - uint16_t current_tick_count; - Ssub_Notify(&self->get_tick_count_subject, ¤t_tick_count, false); - /* Has head of timer list changed? */ - if(self->set_service_timer != false) - { - uint16_t new_time; - uint16_t diff = current_tick_count - self->last_tick_count; - self->set_service_timer = false; - if (self->timer_list.head != NULL) - { - /* Timer expired since last TM service? */ - if(diff >= ((CTimer *)self->timer_list.head->data_ptr)->delta) - { - new_time = 1U; /* Return minimum value */ - } - else - { - /* Calculate new timeout */ - new_time = (uint16_t)(((CTimer *)self->timer_list.head->data_ptr)->delta - diff); - } - /* Inform the application that the UCS must be serviced not later than the passed - time period. */ - Ssub_Notify(&self->set_application_timer_subject, &new_time, false); - } - } - } - else - { - Tm_TriggerService(self); /* Application timer not implemented -> Retrigger TM */ - } -} - -/*! \brief Helper function to set the TM service event. - * \details This function is used by the application to trigger a service call of the Timer - * Management if the application timer has expired. - * \param self Instance pointer - */ -void Tm_TriggerService(CTimerManagement *self) -{ - if(self->timer_list.head != NULL) /* At least one timer is running? */ - { - Srv_SetEvent(&self->tm_srv, TM_EVENT_UPDATE_TIMERS); - } -} - -/*! \brief Helper function to stop the TM service. - * \param self Instance pointer - */ -void Tm_StopService(CTimerManagement *self) -{ - uint16_t new_time = 0U; - - /* Clear probable running application timer */ - Ssub_Notify(&self->set_application_timer_subject, &new_time, false); - - /* Reset the service timer. Not necessary ? */ - self->set_service_timer = false; - - /* Clear the timer head queue to prevent any event to be set */ - self->timer_list.head = NULL; -} - -/*! \brief Creates a new timer. The timer expires at the specified elapse time and then after - * every specified period. When the timer expires the specified callback function is - * called. - * \param self Instance pointer - * \param timer_ptr Reference to the timer object - * \param handler_fptr Callback function which is called when the timer expires - * \param args_ptr Reference to an optional parameter which is passed to the specified - * callback function - * \param elapse The elapse value before the timer expires for the first time, in - * milliseconds - * \param period The period of the timer, in milliseconds. If this parameter is zero, the - * timer is signaled once. If the parameter is greater than zero, the timer - * is periodic. - */ -void Tm_SetTimer(CTimerManagement *self, - CTimer *timer_ptr, - Tm_Handler_t handler_fptr, - void *args_ptr, - uint16_t elapse, - uint16_t period) -{ - (void)Tm_ClearTimer(self, timer_ptr); /* Clear timer if running */ - /* Call the internal method to set the new timer (-> does not trigger TM service!) */ - Tm_SetTimerInternal(self, timer_ptr, handler_fptr, args_ptr, elapse, period); - Tm_TriggerService(self); /* New timer added -> trigger timer list update */ -} - -/*! \brief This function contains the internal part when adding a new timer. The function is - * called within Tm_SetTimer() and within Tm_UpdateTimers(). - * \param self Instance pointer - * \param timer_ptr Reference to the timer object - * \param handler_fptr Callback function which is called when the timer expires - * \param args_ptr Reference to an optional parameter which is passed to the specified - * callback function - * \param elapse The elapse value before the timer expires for the first time, in - * milliseconds - * \param period The period of the timer, in milliseconds. If this parameter is zero, the - * timer is signaled once. If the parameter is greater than zero, the timer - * is periodic. - */ -static void Tm_SetTimerInternal(CTimerManagement *self, - CTimer *timer_ptr, - Tm_Handler_t handler_fptr, - void *args_ptr, - uint16_t elapse, - uint16_t period) -{ - uint16_t current_tick_count; - Ssub_Notify(&self->get_tick_count_subject, ¤t_tick_count, false); - - /* Save timer specific values */ - timer_ptr->changed = true; /* Flag is needed by Tm_UpdateTimers() */ - timer_ptr->in_use = true; - timer_ptr->handler_fptr = handler_fptr; - timer_ptr->args_ptr = args_ptr; - timer_ptr->elapse = elapse; - timer_ptr->period = period; - timer_ptr->delta = elapse; - - /* Create back link to be able to point from node to timer object */ - timer_ptr->node.data_ptr = (void *)timer_ptr; - - if(self->timer_list.head == NULL) /* Is timer list empty? */ - { - Dl_InsertHead(&self->timer_list, &timer_ptr->node); /* Add first timer to list */ - /* Save current tick count */ - Ssub_Notify(&self->get_tick_count_subject, &self->last_tick_count, false); - } - else /* Timer list is not empty */ - { - CDlNode *result_ptr = NULL; - - /* Set delta value in relation to last saved tick count (last TM service) */ - timer_ptr->delta += (uint16_t)(current_tick_count - self->last_tick_count); - - /* Search slot where new timer must be inserted. Update delta of new timer - and delta of the following timer in the list. */ - result_ptr = Dl_Foreach(&self->timer_list, &Tm_UpdateTimersAdd, (void *)timer_ptr); - - if(result_ptr != NULL) /* Slot found? */ - { - /* Insert new timer at found position */ - Dl_InsertBefore(&self->timer_list, result_ptr, &timer_ptr->node); - } - else /* No slot found -> Insert as last node */ - { - /* Add new timer to end of list */ - Dl_InsertTail(&self->timer_list, &timer_ptr->node); - } - } -} - -/*! \brief Removes the specified timer from the timer list. - * \param self Instance pointer - * \param timer_ptr Reference to the timer object - * \attention Make sure that for a timer object Tm_SetTimer() is called before Tm_ClearTimer() - * is called! - */ -void Tm_ClearTimer(CTimerManagement *self, CTimer *timer_ptr) -{ - if(timer_ptr->in_use != false) /* Is timer currently in use? */ - { - timer_ptr->changed = true; /* Flag is needed by Tm_UpdateTimers() */ - - if(timer_ptr->node.next != NULL) /* Has deleted timer a follower? */ - { - /* Adjust delta of following timer */ - ((CTimer *)timer_ptr->node.next->data_ptr)->delta += timer_ptr->delta; - } - - (void)Dl_Remove(&self->timer_list, &timer_ptr->node); - timer_ptr->in_use = false; - - Tm_TriggerService(self); /* Timer removed -> trigger timer list update */ - } -} - -/*! \brief Used by Tm_SetTimer() to find the slot where the new timer must be inserted. - * \param c_timer_ptr Reference to current timer processed by foreach loop - * \param n_timer_ptr Reference to new timer - * \return \c true: Slot found, stop foreach loop - * \return \c false: Slot not found, continue foreach loop - */ -static bool Tm_UpdateTimersAdd(void *c_timer_ptr, void *n_timer_ptr) -{ - CTimer *current_timer_ptr = (CTimer *)c_timer_ptr; - CTimer *new_timer_ptr = (CTimer *)n_timer_ptr; - bool ret_val; - - /* Is current timer lesser than new timer? */ - if(current_timer_ptr->delta <= new_timer_ptr->delta) - { - /* Update delta of new timer and continue foreach loop */ - new_timer_ptr->delta -= current_timer_ptr->delta; - ret_val = false; - } - else /* Slot found! */ - { - /* Correct delta of current timer and stop foreach loop */ - current_timer_ptr->delta -= new_timer_ptr->delta; - ret_val = true; - } - - return ret_val; -} - - -/*------------------------------------------------------------------------------------------------*/ -/* Implementation of class CTimer */ -/*------------------------------------------------------------------------------------------------*/ -/*! \brief Constructor of the Timer class. - * \param self Instance pointer - */ -void T_Ctor(CTimer *self) -{ - MISC_MEM_SET(self, 0, sizeof(*self)); -} - -/*! \brief Returns the status of the given timer. - * \param self Instance pointer - * \return \c true if the timer is currently in use - * \return \c false if the timer is not currently in use - */ -bool T_IsTimerInUse(CTimer *self) -{ - return self->in_use; -} - -/*! - * @} - * \endcond - */ - -/*------------------------------------------------------------------------------------------------*/ -/* End of file */ -/*------------------------------------------------------------------------------------------------*/ - |