/****************************************************************************** * * Copyright (C) 1999-2012 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #include "gki_int.h" #ifndef BT_ERROR_TRACE_0 #define BT_ERROR_TRACE_0(l, m) #endif /* Make sure that this has been defined in target.h */ #ifndef GKI_NUM_TIMERS #error NO TIMERS: Must define at least 1 timer in the system! #endif /* Largest signed positive timer count */ #define GKI_NO_NEW_TMRS_STARTED (0x7fffffffL) /* Marks an unused timer list entry (initial value) */ #define GKI_UNUSED_LIST_ENTRY (0x80000000L) #define GKI_MAX_INT32 (0x7fffffffL) /******************************************************************************* ** ** Function gki_timers_init ** ** Description This internal function is called once at startup to ** initialize all the timer structures. ** ** Returns void ** *******************************************************************************/ void gki_timers_init(void) { uint8_t tt; gki_cb.com.OSTicksTilExp = 0; /* Remaining time (of OSTimeCurTimeout) before next timer expires */ gki_cb.com.OSNumOrigTicks = 0; #if (GKI_DELAY_STOP_SYS_TICK > 0) gki_cb.com.OSTicksTilStop = 0; /* clear inactivity delay timer */ #endif for (tt = 0; tt < GKI_MAX_TASKS; tt++) { gki_cb.com.OSWaitTmr[tt] = 0; #if (GKI_NUM_TIMERS > 0) gki_cb.com.OSTaskTmr0[tt] = 0; gki_cb.com.OSTaskTmr0R[tt] = 0; #endif #if (GKI_NUM_TIMERS > 1) gki_cb.com.OSTaskTmr1[tt] = 0; gki_cb.com.OSTaskTmr1R[tt] = 0; #endif #if (GKI_NUM_TIMERS > 2) gki_cb.com.OSTaskTmr2[tt] = 0; gki_cb.com.OSTaskTmr2R[tt] = 0; #endif #if (GKI_NUM_TIMERS > 3) gki_cb.com.OSTaskTmr3[tt] = 0; gki_cb.com.OSTaskTmr3R[tt] = 0; #endif } for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) { gki_cb.com.timer_queues[tt] = NULL; } gki_cb.com.p_tick_cb = NULL; gki_cb.com.system_tick_running = false; return; } /******************************************************************************* ** ** Function gki_timers_is_timer_running ** ** Description This internal function is called to test if any gki timer ** are running ** ** ** Returns TRUE if at least one time is running in the system, FALSE ** else. ** *******************************************************************************/ bool gki_timers_is_timer_running(void) { uint8_t tt; for (tt = 0; tt < GKI_MAX_TASKS; tt++) { #if (GKI_NUM_TIMERS > 0) if (gki_cb.com.OSTaskTmr0[tt]) { return true; } #endif #if (GKI_NUM_TIMERS > 1) if (gki_cb.com.OSTaskTmr1[tt]) { return true; } #endif #if (GKI_NUM_TIMERS > 2) if (gki_cb.com.OSTaskTmr2[tt]) { return true; } #endif #if (GKI_NUM_TIMERS > 3) if (gki_cb.com.OSTaskTmr3[tt]) { return true; } #endif } return false; } /******************************************************************************* ** ** Function GKI_get_tick_count ** ** Description This function returns the current system ticks ** ** Returns The current number of system ticks ** *******************************************************************************/ uint32_t GKI_get_tick_count(void) { return gki_cb.com.OSTicks; } /******************************************************************************* ** ** Function GKI_ready_to_sleep ** ** Description This function returns the number of system ticks until the ** next timer will expire. It is typically called by a power ** savings manager to find out how long it can have the system ** sleep before it needs to service the next entry. ** ** Parameters: None ** ** Returns Number of ticks til the next timer expires ** Note: The value is a signed value. This value should be ** compared to x > 0, to avoid misinterpreting negative ** tick values. ** *******************************************************************************/ int32_t GKI_ready_to_sleep(void) { return (gki_cb.com.OSTicksTilExp); } /******************************************************************************* ** ** Function GKI_start_timer ** ** Description An application can call this function to start one of ** it's four general purpose timers. Any of the four timers ** can be 1-shot or continuous. If a timer is already running, ** it will be reset to the new parameters. ** ** Parameters tnum - (input) timer number to be started ** (TIMER_0, TIMER_1, TIMER_2, or ** TIMER_3) ** ticks - (input) the number of system ticks til the ** timer expires. ** is_continuous - (input) TRUE if timer restarts ** automatically, else FALSE if it is ** a 'one-shot'. ** ** Returns void ** *******************************************************************************/ void GKI_start_timer(uint8_t tnum, int32_t ticks, bool is_continuous) { int32_t reload; int32_t orig_ticks; uint8_t task_id = GKI_get_taskid(); bool bad_timer = false; if (ticks <= 0) ticks = 1; orig_ticks = ticks; /* save the ticks in case adjustment is necessary */ /* If continuous timer, set reload, else set it to 0 */ if (is_continuous) reload = ticks; else reload = 0; GKI_disable(); if (gki_timers_is_timer_running() == false) { #if (GKI_DELAY_STOP_SYS_TICK > 0) /* if inactivity delay timer is not running, start system tick */ if (gki_cb.com.OSTicksTilStop == 0) { #endif if (gki_cb.com.p_tick_cb) { /* start system tick */ gki_cb.com.system_tick_running = true; (gki_cb.com.p_tick_cb)(true); } #if (GKI_DELAY_STOP_SYS_TICK > 0) } else { /* clear inactivity delay timer */ gki_cb.com.OSTicksTilStop = 0; } #endif } /* Add the time since the last task timer update. ** Note that this works when no timers are active since ** both OSNumOrigTicks and OSTicksTilExp are 0. */ if (GKI_MAX_INT32 - (gki_cb.com.OSNumOrigTicks - gki_cb.com.OSTicksTilExp) > ticks) { ticks += gki_cb.com.OSNumOrigTicks - gki_cb.com.OSTicksTilExp; } else ticks = GKI_MAX_INT32; switch (tnum) { #if (GKI_NUM_TIMERS > 0) case TIMER_0: gki_cb.com.OSTaskTmr0R[task_id] = reload; gki_cb.com.OSTaskTmr0[task_id] = ticks; break; #endif #if (GKI_NUM_TIMERS > 1) case TIMER_1: gki_cb.com.OSTaskTmr1R[task_id] = reload; gki_cb.com.OSTaskTmr1[task_id] = ticks; break; #endif #if (GKI_NUM_TIMERS > 2) case TIMER_2: gki_cb.com.OSTaskTmr2R[task_id] = reload; gki_cb.com.OSTaskTmr2[task_id] = ticks; break; #endif #if (GKI_NUM_TIMERS > 3) case TIMER_3: gki_cb.com.OSTaskTmr3R[task_id] = reload; gki_cb.com.OSTaskTmr3[task_id] = ticks; break; #endif default: bad_timer = true; /* Timer number is bad, so do not use */ } /* Update the expiration timeout if a legitimate timer */ if (!bad_timer) { /* Only update the timeout value if it is less than any other newly started * timers */ gki_adjust_timer_count(orig_ticks); } GKI_enable(); } /******************************************************************************* ** ** Function GKI_stop_timer ** ** Description An application can call this function to stop one of ** it's four general purpose timers. There is no harm in ** stopping a timer that is already stopped. ** ** Parameters tnum - (input) timer number to be started (TIMER_0, ** TIMER_1, TIMER_2, or TIMER_3) ** Returns void ** *******************************************************************************/ void GKI_stop_timer(uint8_t tnum) { uint8_t task_id = GKI_get_taskid(); GKI_disable(); switch (tnum) { #if (GKI_NUM_TIMERS > 0) case TIMER_0: gki_cb.com.OSTaskTmr0R[task_id] = 0; gki_cb.com.OSTaskTmr0[task_id] = 0; break; #endif #if (GKI_NUM_TIMERS > 1) case TIMER_1: gki_cb.com.OSTaskTmr1R[task_id] = 0; gki_cb.com.OSTaskTmr1[task_id] = 0; break; #endif #if (GKI_NUM_TIMERS > 2) case TIMER_2: gki_cb.com.OSTaskTmr2R[task_id] = 0; gki_cb.com.OSTaskTmr2[task_id] = 0; break; #endif #if (GKI_NUM_TIMERS > 3) case TIMER_3: gki_cb.com.OSTaskTmr3R[task_id] = 0; gki_cb.com.OSTaskTmr3[task_id] = 0; break; #endif } if (gki_timers_is_timer_running() == false) { if (gki_cb.com.p_tick_cb) { #if (GKI_DELAY_STOP_SYS_TICK > 0) /* if inactivity delay timer is not running */ if ((gki_cb.com.system_tick_running) && (gki_cb.com.OSTicksTilStop == 0)) { /* set inactivity delay timer */ /* when timer expires, system tick will be stopped */ gki_cb.com.OSTicksTilStop = GKI_DELAY_STOP_SYS_TICK; } #else gki_cb.com.system_tick_running = false; (gki_cb.com.p_tick_cb)(false); /* stop system tick */ #endif } } GKI_enable(); } /******************************************************************************* ** ** Function GKI_timer_update ** ** Description This function is called by an OS to drive the GKI's timers. ** It is typically called at every system tick to ** update the timers for all tasks, and check for timeouts. ** ** Note: It has been designed to also allow for variable tick ** updates so that systems with strict power savings ** requirements can have the update occur at variable ** intervals. ** ** Parameters: ticks_since_last_update - (input) This is the number of ** TICKS that have occurred since the last time ** GKI_timer_update was called. ** ** Returns void ** *******************************************************************************/ void GKI_timer_update(int32_t ticks_since_last_update) { uint8_t task_id; long next_expiration; /* Holds the next soonest expiration time after this update */ /* Increment the number of ticks used for time stamps */ gki_cb.com.OSTicks += ticks_since_last_update; /* If any timers are running in any tasks, decrement the remaining time til * the timer updates need to take place (next expiration occurs) */ gki_cb.com.OSTicksTilExp -= ticks_since_last_update; /* Don't allow timer interrupt nesting */ if (gki_cb.com.timer_nesting) return; gki_cb.com.timer_nesting = 1; #if (GKI_DELAY_STOP_SYS_TICK > 0) /* if inactivity delay timer is set and expired */ if (gki_cb.com.OSTicksTilStop) { if (gki_cb.com.OSTicksTilStop <= (uint32_t)ticks_since_last_update) { if (gki_cb.com.p_tick_cb) { gki_cb.com.system_tick_running = false; (gki_cb.com.p_tick_cb)(false); /* stop system tick */ } gki_cb.com.OSTicksTilStop = 0; /* clear inactivity delay timer */ gki_cb.com.timer_nesting = 0; return; } else gki_cb.com.OSTicksTilStop -= ticks_since_last_update; } #endif /* No need to update the ticks if no timeout has occurred */ if (gki_cb.com.OSTicksTilExp > 0) { gki_cb.com.timer_nesting = 0; return; } GKI_disable(); next_expiration = GKI_NO_NEW_TMRS_STARTED; /* If here then gki_cb.com.OSTicksTilExp <= 0. If negative, then increase gki_cb.com.OSNumOrigTicks to account for the difference so timer updates below are decremented by the full number of ticks. gki_cb.com.OSNumOrigTicks is reset at the bottom of this function so changing this value only affects the timer updates below */ gki_cb.com.OSNumOrigTicks -= gki_cb.com.OSTicksTilExp; /* Check for OS Task Timers */ for (task_id = 0; task_id < GKI_MAX_TASKS; task_id++) { if (gki_cb.com.OSRdyTbl[task_id] == TASK_DEAD) { // task is shutdown do not try to service timers continue; } if (gki_cb.com.OSWaitTmr[task_id] > 0) /* If timer is running */ { gki_cb.com.OSWaitTmr[task_id] -= gki_cb.com.OSNumOrigTicks; if (gki_cb.com.OSWaitTmr[task_id] <= 0) { /* Timer Expired */ gki_cb.com.OSRdyTbl[task_id] = TASK_READY; } } #if (GKI_NUM_TIMERS > 0) /* If any timer is running, decrement */ if (gki_cb.com.OSTaskTmr0[task_id] > 0) { gki_cb.com.OSTaskTmr0[task_id] -= gki_cb.com.OSNumOrigTicks; if (gki_cb.com.OSTaskTmr0[task_id] <= 0) { /* Set Timer 0 Expired event mask and reload timer */ #if (GKI_TIMER_UPDATES_FROM_ISR == TRUE) GKI_isend_event(task_id, TIMER_0_EVT_MASK); #else GKI_send_event(task_id, TIMER_0_EVT_MASK); #endif gki_cb.com.OSTaskTmr0[task_id] = gki_cb.com.OSTaskTmr0R[task_id]; } } /* Check to see if this timer is the next one to expire */ if (gki_cb.com.OSTaskTmr0[task_id] > 0 && gki_cb.com.OSTaskTmr0[task_id] < next_expiration) next_expiration = gki_cb.com.OSTaskTmr0[task_id]; #endif #if (GKI_NUM_TIMERS > 1) /* If any timer is running, decrement */ if (gki_cb.com.OSTaskTmr1[task_id] > 0) { gki_cb.com.OSTaskTmr1[task_id] -= gki_cb.com.OSNumOrigTicks; if (gki_cb.com.OSTaskTmr1[task_id] <= 0) { /* Set Timer 1 Expired event mask and reload timer */ #if (GKI_TIMER_UPDATES_FROM_ISR == TRUE) GKI_isend_event(task_id, TIMER_1_EVT_MASK); #else GKI_send_event(task_id, TIMER_1_EVT_MASK); #endif gki_cb.com.OSTaskTmr1[task_id] = gki_cb.com.OSTaskTmr1R[task_id]; } } /* Check to see if this timer is the next one to expire */ if (gki_cb.com.OSTaskTmr1[task_id] > 0 && gki_cb.com.OSTaskTmr1[task_id] < next_expiration) next_expiration = gki_cb.com.OSTaskTmr1[task_id]; #endif #if (GKI_NUM_TIMERS > 2) /* If any timer is running, decrement */ if (gki_cb.com.OSTaskTmr2[task_id] > 0) { gki_cb.com.OSTaskTmr2[task_id] -= gki_cb.com.OSNumOrigTicks; if (gki_cb.com.OSTaskTmr2[task_id] <= 0) { /* Set Timer 2 Expired event mask and reload timer */ #if (GKI_TIMER_UPDATES_FROM_ISR == TRUE) GKI_isend_event(task_id, TIMER_2_EVT_MASK); #else GKI_send_event(task_id, TIMER_2_EVT_MASK); #endif gki_cb.com.OSTaskTmr2[task_id] = gki_cb.com.OSTaskTmr2R[task_id]; } } /* Check to see if this timer is the next one to expire */ if (gki_cb.com.OSTaskTmr2[task_id] > 0 && gki_cb.com.OSTaskTmr2[task_id] < next_expiration) next_expiration = gki_cb.com.OSTaskTmr2[task_id]; #endif #if (GKI_NUM_TIMERS > 3) /* If any timer is running, decrement */ if (gki_cb.com.OSTaskTmr3[task_id] > 0) { gki_cb.com.OSTaskTmr3[task_id] -= gki_cb.com.OSNumOrigTicks; if (gki_cb.com.OSTaskTmr3[task_id] <= 0) { /* Set Timer 3 Expired event mask and reload timer */ #if (GKI_TIMER_UPDATES_FROM_ISR == TRUE) GKI_isend_event(task_id, TIMER_3_EVT_MASK); #else GKI_send_event(task_id, TIMER_3_EVT_MASK); #endif gki_cb.com.OSTaskTmr3[task_id] = gki_cb.com.OSTaskTmr3R[task_id]; } } /* Check to see if this timer is the next one to expire */ if (gki_cb.com.OSTaskTmr3[task_id] > 0 && gki_cb.com.OSTaskTmr3[task_id] < next_expiration) next_expiration = gki_cb.com.OSTaskTmr3[task_id]; #endif } /* Set the next timer experation value if there is one to start */ if (next_expiration < GKI_NO_NEW_TMRS_STARTED) { gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = next_expiration; } else { gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = 0; } gki_cb.com.timer_nesting = 0; GKI_enable(); return; } /******************************************************************************* ** ** Function GKI_timer_queue_empty ** ** Description This function is called by applications to see whether the ** timer queue is empty ** ** Parameters ** ** Returns bool ** *******************************************************************************/ bool GKI_timer_queue_empty(void) { uint8_t tt; for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) { if (gki_cb.com.timer_queues[tt]) return false; } return true; } /******************************************************************************* ** ** Function GKI_timer_queue_register_callback ** ** Description This function is called by applications to register system ** tick start/stop callback for time queues ** ** ** Parameters p_callback - (input) pointer to the system tick callback ** ** Returns bool ** *******************************************************************************/ void GKI_timer_queue_register_callback(SYSTEM_TICK_CBACK* p_callback) { gki_cb.com.p_tick_cb = p_callback; return; } /******************************************************************************* ** ** Function GKI_init_timer_list ** ** Description This function is called by applications when they ** want to initialize a timer list. ** ** Parameters p_timer_listq - (input) pointer to the timer list queue ** object ** ** Returns void ** *******************************************************************************/ void GKI_init_timer_list(TIMER_LIST_Q* p_timer_listq) { p_timer_listq->p_first = NULL; p_timer_listq->p_last = NULL; p_timer_listq->last_ticks = 0; return; } /******************************************************************************* ** ** Function GKI_init_timer_list_entry ** ** Description This function is called by the applications when they ** want to initialize a timer list entry. This must be ** done prior to first use of the entry. ** ** Parameters p_tle - (input) pointer to a timer list queue entry ** ** Returns void ** *******************************************************************************/ void GKI_init_timer_list_entry(TIMER_LIST_ENT* p_tle) { p_tle->p_next = NULL; p_tle->p_prev = NULL; p_tle->ticks = GKI_UNUSED_LIST_ENTRY; p_tle->in_use = false; } /******************************************************************************* ** ** Function GKI_update_timer_list ** ** Description This function is called by the applications when they ** want to update a timer list. This should be at every ** timer list unit tick, e.g. once per sec, once per minute ** etc. ** ** Parameters p_timer_listq - (input) pointer to the timer list queue ** object ** num_units_since_last_update - (input) number of units since ** the last update (allows for variable unit update) ** ** NOTE: The following timer list update routines should not be used for exact ** time critical purposes. The timer tasks should be used when exact ** timing is needed. ** ** Returns the number of timers that have expired ** *******************************************************************************/ uint16_t GKI_update_timer_list(TIMER_LIST_Q* p_timer_listq, int32_t num_units_since_last_update) { TIMER_LIST_ENT* p_tle; uint16_t num_time_out = 0; int32_t rem_ticks; int32_t temp_ticks; p_tle = p_timer_listq->p_first; /* First, get the guys who have previously timed out */ /* Note that the tick value of the timers should always be '0' */ while ((p_tle) && (p_tle->ticks <= 0)) { num_time_out++; p_tle = p_tle->p_next; } /* Timer entriy tick values are relative to the preceeding entry */ rem_ticks = num_units_since_last_update; /* Now, adjust remaining timer entries */ while ((p_tle != NULL) && (rem_ticks > 0)) { temp_ticks = p_tle->ticks; p_tle->ticks -= rem_ticks; /* See if this timer has just timed out */ if (p_tle->ticks <= 0) { /* We set the number of ticks to '0' so that the legacy code * that assumes a '0' or nonzero value will still work as coded. */ p_tle->ticks = 0; num_time_out++; } rem_ticks -= temp_ticks; /* Decrement the remaining ticks to process */ p_tle = p_tle->p_next; } if (p_timer_listq->last_ticks > 0) { p_timer_listq->last_ticks -= num_units_since_last_update; /* If the last timer has expired set last_ticks to 0 so that other list * update * functions will calculate correctly */ if (p_timer_listq->last_ticks < 0) p_timer_listq->last_ticks = 0; } return (num_time_out); } /******************************************************************************* ** ** Function GKI_get_remaining_ticks ** ** Description This function is called by an application to get remaining ** ticks to expire ** ** Parameters p_timer_listq - (input) pointer to the timer list queue ** object ** p_target_tle - (input) pointer to a timer list queue entry ** ** Returns 0 if timer is not used or timer is not in the list ** remaining ticks if success ** *******************************************************************************/ uint32_t GKI_get_remaining_ticks(TIMER_LIST_Q* p_timer_listq, TIMER_LIST_ENT* p_target_tle) { TIMER_LIST_ENT* p_tle; uint32_t rem_ticks = 0; if (p_target_tle->in_use) { p_tle = p_timer_listq->p_first; /* adding up all of ticks in previous entries */ while ((p_tle) && (p_tle != p_target_tle)) { rem_ticks += p_tle->ticks; p_tle = p_tle->p_next; } /* if found target entry */ if (p_tle == p_target_tle) { rem_ticks += p_tle->ticks; } else { BT_ERROR_TRACE_0(TRACE_LAYER_GKI, "GKI_get_remaining_ticks: No timer entry in the list"); return (0); } } else { BT_ERROR_TRACE_0(TRACE_LAYER_GKI, "GKI_get_remaining_ticks: timer entry is not active"); } return (rem_ticks); } /******************************************************************************* ** ** Function GKI_add_to_timer_list ** ** Description This function is called by an application to add a timer ** entry to a timer list. ** ** Note: A timer value of '0' will effectively insert an ** already expired event. Negative tick values will be ** ignored. ** ** Parameters p_timer_listq - (input) pointer to the timer list queue ** object ** p_tle - (input) pointer to a timer list queue entry ** ** Returns void ** *******************************************************************************/ void GKI_add_to_timer_list(TIMER_LIST_Q* p_timer_listq, TIMER_LIST_ENT* p_tle) { uint32_t nr_ticks_total; uint8_t tt; TIMER_LIST_ENT* p_temp; if (p_tle == NULL || p_timer_listq == NULL) { GKI_TRACE_3("%s: invalid argument %x, %x****************************<<", __func__, p_timer_listq, p_tle); return; } /* Only process valid tick values */ if (p_tle->ticks >= 0) { /* If this entry is the last in the list */ if (p_tle->ticks >= p_timer_listq->last_ticks) { /* If this entry is the only entry in the list */ if (p_timer_listq->p_first == NULL) p_timer_listq->p_first = p_tle; else { /* Insert the entry onto the end of the list */ if (p_timer_listq->p_last != NULL) p_timer_listq->p_last->p_next = p_tle; p_tle->p_prev = p_timer_listq->p_last; } p_tle->p_next = NULL; p_timer_listq->p_last = p_tle; nr_ticks_total = p_tle->ticks; p_tle->ticks -= p_timer_listq->last_ticks; p_timer_listq->last_ticks = nr_ticks_total; } else /* This entry needs to be inserted before the last entry */ { /* Find the entry that the new one needs to be inserted in front of */ p_temp = p_timer_listq->p_first; while (p_tle->ticks > p_temp->ticks) { /* Update the tick value if looking at an unexpired entry */ if (p_temp->ticks > 0) p_tle->ticks -= p_temp->ticks; p_temp = p_temp->p_next; } /* The new entry is the first in the list */ if (p_temp == p_timer_listq->p_first) { p_tle->p_next = p_timer_listq->p_first; p_timer_listq->p_first->p_prev = p_tle; p_timer_listq->p_first = p_tle; } else { p_temp->p_prev->p_next = p_tle; p_tle->p_prev = p_temp->p_prev; p_temp->p_prev = p_tle; p_tle->p_next = p_temp; } p_temp->ticks -= p_tle->ticks; } p_tle->in_use = true; /* if we already add this timer queue to the array */ for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) { if (gki_cb.com.timer_queues[tt] == p_timer_listq) return; } /* add this timer queue to the array */ for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) { if (gki_cb.com.timer_queues[tt] == NULL) break; } if (tt < GKI_MAX_TIMER_QUEUES) { gki_cb.com.timer_queues[tt] = p_timer_listq; } } return; } /******************************************************************************* ** ** Function GKI_remove_from_timer_list ** ** Description This function is called by an application to remove a timer ** entry from a timer list. ** ** Parameters p_timer_listq - (input) pointer to the timer list queue ** object ** p_tle - (input) pointer to a timer list queue entry ** ** Returns void ** *******************************************************************************/ void GKI_remove_from_timer_list(TIMER_LIST_Q* p_timer_listq, TIMER_LIST_ENT* p_tle) { uint8_t tt; /* Verify that the entry is valid */ if (p_tle == NULL || p_tle->in_use == false || p_timer_listq->p_first == NULL) { return; } /* Add the ticks remaining in this timer (if any) to the next guy in the list. ** Note: Expired timers have a tick value of '0'. */ if (p_tle->p_next != NULL) { p_tle->p_next->ticks += p_tle->ticks; } else { p_timer_listq->last_ticks -= p_tle->ticks; } /* Unlink timer from the list. */ if (p_timer_listq->p_first == p_tle) { p_timer_listq->p_first = p_tle->p_next; if (p_timer_listq->p_first != NULL) p_timer_listq->p_first->p_prev = NULL; if (p_timer_listq->p_last == p_tle) p_timer_listq->p_last = NULL; } else { if (p_timer_listq->p_last == p_tle) { p_timer_listq->p_last = p_tle->p_prev; if (p_timer_listq->p_last != NULL) p_timer_listq->p_last->p_next = NULL; } else { if (p_tle->p_next != NULL && p_tle->p_next->p_prev == p_tle) p_tle->p_next->p_prev = p_tle->p_prev; else { /* Error case - chain messed up ?? */ return; } if (p_tle->p_prev != NULL && p_tle->p_prev->p_next == p_tle) p_tle->p_prev->p_next = p_tle->p_next; else { /* Error case - chain messed up ?? */ return; } } } p_tle->p_next = p_tle->p_prev = NULL; p_tle->ticks = GKI_UNUSED_LIST_ENTRY; p_tle->in_use = false; /* if timer queue is empty */ if (p_timer_listq->p_first == NULL && p_timer_listq->p_last == NULL) { for (tt = 0; tt < GKI_MAX_TIMER_QUEUES; tt++) { if (gki_cb.com.timer_queues[tt] == p_timer_listq) { gki_cb.com.timer_queues[tt] = NULL; break; } } } return; } /******************************************************************************* ** ** Function gki_adjust_timer_count ** ** Description This function is called whenever a new timer or GKI_wait ** occurs to adjust (if necessary) the current time til the ** first expiration. This only needs to make an adjustment if ** the new timer (in ticks) is less than the number of ticks ** remaining on the current timer. ** ** Parameters: ticks - (input) number of system ticks of the new timer ** entry ** ** NOTE: This routine MUST be called while interrupts are ** disabled to avoid updates while adjusting the timer ** variables. ** ** Returns void ** *******************************************************************************/ void gki_adjust_timer_count(int32_t ticks) { if (ticks > 0) { /* See if the new timer expires before the current first expiration */ if (gki_cb.com.OSNumOrigTicks == 0 || (ticks < gki_cb.com.OSTicksTilExp && gki_cb.com.OSTicksTilExp > 0)) { gki_cb.com.OSNumOrigTicks = (gki_cb.com.OSNumOrigTicks - gki_cb.com.OSTicksTilExp) + ticks; gki_cb.com.OSTicksTilExp = ticks; } } return; }