/** * Main function of the timer task. This function is in charge of * calling the callbacks associated with the timers. * * This function is run in a high priority task on microkernel builds. * This function is run in a high priority fiber on nanokernel builds. * It implements an infinite loop that waits for any of the semaphores from * g_TimerSem. * When a semaphore is signaled, this function fetches the pointer to the * associated callback in g_TimerDesc, then calls it. * * @param dummy1 not used (required by ZEPHYR API) * @param dummy2 not used (required by ZEPHYR API) * * */ void timer_task(int dummy1, int dummy2) { int32_t timeout = UINT32_MAX; uint32_t now; UNUSED(dummy1); UNUSED(dummy2); while (1) { /* the Timer task shall never stop */ /* Before waiting for next timeout, publish it to warn QUARK cpu */ publish_cpu_timeout(timeout); /* block until g_TimerSem is signaled or until the next timeout expires */ #ifdef CONFIG_MICROKERNEL (void)task_sem_take(g_TimerSem, CONVERT_MS_TO_TICKS(timeout)); #else nano_sem_take(&g_TimerSem, CONVERT_MS_TO_TICKS(timeout)); #endif now = get_uptime_ms(); /* task is unblocked: check for expired timers */ while (g_CurrentTimerHead && is_after_expiration(now, &(g_CurrentTimerHead->desc))) { execute_callback(g_CurrentTimerHead); now = get_uptime_ms(); } /* Compute timeout until the expiration of the next timer */ if (g_CurrentTimerHead != NULL) { /* In micro kernel context, timeout = 0 or timeout < 0 works. * In nano kernel context timeout must be a positive value. */ timeout = g_CurrentTimerHead->desc.expiration - now; if (timeout < 0) panic(E_OS_ERR_OVERFLOW); } else { timeout = UINT32_MAX; } #ifdef __DEBUG_OS_ABSTRACTION_TIMER if (NULL != g_CurrentTimerHead) _log( "\nINFO : timer_task : now = %u, next timer expires at %u, timeout = %u", get_uptime_ms(), g_CurrentTimerHead->desc.expiration, timeout); else _log( "\nINFO : timer_task : now = %u, no next timer, timeout = OS_WAIT_FOREVER", get_uptime_ms()); #endif } /* end while(1) */ }
/** * start the timer. * This service may panic if err parameter is null and: * no timer is available or timer is running . * * Authorized execution levels: task, fiber, ISR * * @param tmr : handler on the timer (value returned by timer_create ). * @param err (out): execution status: */ void timer_start(T_TIMER tmr, uint32_t delay, OS_ERR_TYPE* err) { T_TIMER_LIST_ELT* timer = (T_TIMER_LIST_ELT*) tmr; OS_ERR_TYPE localErr = E_OS_OK; /* if timer is created */ if (NULL != timer) { if(timer->desc.status == E_TIMER_READY) { /* if timer parameter are valid */ if ((NULL != timer->desc.callback) && (0 < delay)) { #ifdef __DEBUG_OS_ABSTRACTION_TIMER _log ("\nINFO : timer_start : starting timer "); #endif /* Update expiration time */ timer->desc.delay = CONVERT_MS_TO_TICKS(delay); timer->desc.expiration = _GET_TICK() + timer->desc.delay; disable_scheduling(); /* add the timer */ add_timer(timer); /* new timer is the next to expire, unblock timer_task to assess the change */ if (g_CurrentTimerHead == timer) { signal_timer_task(); } enable_scheduling(); } else { /* timer is not valid */ localErr = E_OS_ERR; } } else if(timer->desc.status == E_TIMER_RUNNING) { localErr = E_OS_ERR_BUSY; } } else { /* tmr is not a timer from g_TimerPool_elements */ localErr = E_OS_ERR; } error_management(err, localErr); }
/** * Create a timer object. * This service may panic if err parameter is null and: * callback parameter is null, or * no timer is available. * * Authorized execution levels: task, fiber, ISR * * @param callback: pointer to the function to be executed. * @param privData: pointer to data that shall be passed to the callback * @param delay: number of milliseconds between function executions * @param repeat: specifies if the timer shall be re-started after each execution of the callback * @param startup : specifies if the timer shall be start immediately * @param err (out): execution status: * E_OS_OK : callback is programmed * E_OS_ERR: no timer is available, or callback parameter is null * * @return Handler on the timer, NULL if the service fails (e.g. no available * timer or callback is a null pointer). */ T_TIMER timer_create(T_ENTRY_POINT callback, void* privData, uint32_t delay, bool repeat, bool startup, OS_ERR_TYPE* err) { T_TIMER_LIST_ELT* timer = NULL; #ifdef CONFIG_NANOKERNEL /********************** NANO KERNEL SPECIFIC: */ if (delay> 0 && delay < NANO_TICK ) { delay= NANO_TICK; } #endif /* check input parameters */ if ((NULL != callback) && (OS_WAIT_FOREVER != delay)) { /* delay should be set to 0 if startup flag is false * otherwise delay should be a positive value if startup flag is true */ if (((0 < delay) && (true == startup)) || ((0 <= delay) && (false == startup))) { /* find and reserve a timer resource from g_TimerPool_elements */ /* rem: timer points to an element from the global g_TimerPool_elements */ timer = g_TimerPool_alloc(); if (timer != NULL) { /* initialize timer descriptor */ timer->desc.callback = callback; timer->desc.data = privData; timer->desc.delay = CONVERT_MS_TO_TICKS ( delay ); timer->desc.repeat = repeat; timer->desc.status = E_TIMER_READY; /* insert timer in the list of active timers */ if (startup) { timer->desc.expiration = _GET_TICK() + timer->desc.delay; disable_scheduling(); add_timer(timer); if ( g_CurrentTimerHead == timer ) { /* new timer is the next to expire, unblock timer_task to assess the change */ signal_timer_task(); } enable_scheduling(); } #ifdef __DEBUG_OS_ABSTRACTION_TIMER _log ("\nINFO : timer_create : new timer will expire at %u (now = %u ) - addr = 0x%x",timer->desc.expiration,_GET_TICK(), (uint32) timer); #endif error_management (err, E_OS_OK); } else { /* all timers from the pool are already being used */ error_management (err, E_OS_ERR_NO_MEMORY); } } else { /* delay and startup parameter are inconsistent */ error_management (err, E_OS_ERR); } } else { /* callback == NULL or delay == 0 : at least one parameter is invalid */ error_management (err, E_OS_ERR); } return ((T_TIMER) timer); }