?? sos_timer.c
字號:
do{ if ((tt->pid == pid) && (tt->tid == tid)) { list_remove((list_t*)tt); return tt; } tt = (sos_timer_t*)tt->list.l_next; } while ((list_t*)tt != &timer_pool); return NULL;}/** * @brief Remove a timer from the deltaq */static int8_t timer_remove_timer(sos_timer_t *tt){ if((tt->list.l_next == NULL) || (tt->list.l_prev == NULL)) { return -EINVAL; } // if I am not the tail... and I have positive delta if((tt->list.l_next != &deltaq) && (tt->delta > 0 )) { ((sos_timer_t*)(tt->list.l_next))->delta += tt->delta; } list_remove((list_t*)tt); return SOS_OK;}/** * @brief update delta queue * traverse each item in the queue until no more delta left * NOTE: this is executed in interrupt handler, so NO lock necessary */static void timer_update_delta(void){ list_link_t *link; int32_t delta; HAS_CRITICAL_SECTION; ENTER_CRITICAL_SECTION(); delta = outstanding_ticks; outstanding_ticks = 0; LEAVE_CRITICAL_SECTION(); if(list_empty(&deltaq) == true) { return; } DEBUG("update delta = %d\n", delta); for(link = deltaq.l_next; link != (&deltaq); link = link->l_next) { sos_timer_t *h = (sos_timer_t*)link; if(h->delta >= delta) { // if we use all ticks... h->delta -= delta; return; } else { int32_t tmp = h->delta; h->delta -= delta; delta -= tmp; } }}/** * @brief Post the timeout messages *///------------------------------------------------------------------------// TIMER API//------------------------------------------------------------------------//! Assumption - This function is never called from an interrupt contextint8_t ker_timer_init(sos_pid_t pid, uint8_t tid, uint8_t type){ sos_timer_t* tt; tt = find_timer_in_periodic_pool(pid, tid); if (tt != NULL) { tt->type = type; list_insert_tail(&timer_pool, (list_link_t*)tt); return SOS_OK; } //! re-initialize an existing timer by stoping it and updating the type tt = find_timer_block(pid, tid); if (tt != NULL){ ker_timer_stop(pid,tid); tt->type = type; return SOS_OK; } //! Search if pre-initialized timer exists tt = alloc_from_timer_pool(pid, tid); //! Look for pre-allocated timers or try to get dynamic memory if (tt == NULL){ tt = alloc_from_preallocated_timer_pool(pid); if (tt == NULL) tt = (sos_timer_t*)malloc_longterm(sizeof(sos_timer_t), TIMER_PID); //! Init will fail if the system does not have sufficient resources if (tt == NULL) return -ENOMEM; } //! Fill up the data structure and insert into the timer pool tt->pid = pid; tt->tid = tid; tt->type = type; list_insert_tail(&timer_pool, (list_link_t*)tt); return SOS_OK;}int8_t ker_permanent_timer_init(sos_timer_t* tt, sos_pid_t pid, uint8_t tid, uint8_t type){ //! Fill up the data structures and insert into the timer pool tt->pid = pid; tt->tid = tid; tt->type = type; list_insert_tail(&timer_pool, (list_link_t*)tt); return SOS_OK; }int8_t ker_timer_start(sos_pid_t pid, uint8_t tid, int32_t interval){ sos_timer_t* tt; //! Start the timer from the timer pool tt = alloc_from_timer_pool(pid, tid); //! If the timer does not exist, then it is already in use or not initialized if (tt == NULL) { DEBUG_PID(TIMER_PID, "ker_timer_start: tt == NULL\n"); return -EINVAL; } // tt->ticks = PROCESSOR_TICKS(interval); tt->ticks = interval; tt->delta = interval; //DEBUG("timer_start(%d) %d %d %d\n", tt->pid, tt->tid, tt->type, tt->ticks); //! insert into delta queue print_all_timers("timer_start_start"); timer_delta_q_insert(tt, true); print_all_timers("timer_start_end"); ker_log( SOS_LOG_TIMER_START, pid, tid ); return SOS_OK;}//! The implementation of this call can be optimized to include the find with//! the remove. We will do it laterint8_t ker_timer_stop(sos_pid_t pid, uint8_t tid){ sos_timer_t* tt; tt = find_timer_in_periodic_pool(pid, tid); if( tt == NULL ) { //! Find the timer block tt = find_timer_block(pid, tid); if (tt == NULL) { return -EINVAL; } else { //! Remove the timer from the deltaq and any pending messages in the queue timer_remove_timer(tt); } } //timer_remove_timeout_from_scheduler(tt); //! Re-insert timer into the pool list_insert_tail(&timer_pool, (list_link_t*)tt); ker_log( SOS_LOG_TIMER_STOP, pid, tid ); return SOS_OK;}//! Free the first timer block beloning to pid in the timer_poolint8_t ker_timer_release(sos_pid_t pid, uint8_t tid){ sos_timer_t* tt; //! First stop the timer if it is running ker_timer_stop(pid, tid); //! Get the timer block from the pool tt = alloc_from_timer_pool(pid, tid); if (tt == NULL) return -EINVAL; //! Deep free of the timer ker_free(tt); return SOS_OK; }int8_t ker_timer_restart(sos_pid_t pid, uint8_t tid, int32_t interval){ sos_timer_t* tt; tt = find_timer_in_periodic_pool(pid, tid); if (tt == NULL) { //! Locate a running timer or from the timer pool tt = find_timer_block(pid, tid); if (tt != NULL){ timer_remove_timer(tt); //timer_remove_timeout_from_scheduler(tt); } else { tt = alloc_from_timer_pool(pid, tid); } } //! The timer is neither running nor initialized if (tt == NULL) return -EINVAL; /* Special Case restart with existing ticks field */ if( interval <= 0 ) interval = tt->ticks; if(interval < TIMER_MIN_INTERVAL){ /* Need to put the timer back in to the pool as an initialized timer that was never started */ list_insert_tail(&timer_pool, (list_link_t*)tt); return -EPERM; } //! Initialize the data structure tt->ticks = interval; // tt->ticks = PROCESSOR_TICKS(interval); tt->delta = interval; //! Insert into the delta queue timer_delta_q_insert(tt, true); ker_log( SOS_LOG_TIMER_RESTART, pid, tid ); return SOS_OK;}int8_t ker_sys_timer_start(uint8_t tid, int32_t interval, uint8_t type){ sos_pid_t my_id = ker_get_current_pid(); if( (ker_timer_init(my_id, tid, type) != SOS_OK) || (ker_timer_start(my_id, tid, interval) != SOS_OK)) { return ker_mod_panic(my_id); } return SOS_OK; } int8_t ker_sys_timer_restart(uint8_t tid, int32_t interval) { sos_pid_t my_id = ker_get_current_pid(); if( ker_timer_restart(my_id, tid, interval) != SOS_OK ) { return ker_mod_panic(my_id); } return SOS_OK; } int8_t ker_sys_timer_stop(uint8_t tid) { sos_pid_t my_id = ker_get_current_pid(); if( (ker_timer_stop(my_id, tid) != SOS_OK) || (ker_timer_release(my_id, tid) != SOS_OK) ) { return ker_mod_panic(my_id); } return SOS_OK; } // called from schedulerstatic void soft_interrupt( void ){ HAS_CRITICAL_SECTION; timer_update_delta(); while(list_empty(&deltaq) == false) { sos_timer_t *h = (sos_timer_t*)(deltaq.l_next); if(h->delta <= 0) { sos_pid_t pid = h->pid; uint8_t tid = h->tid; uint8_t flag; list_remove_head(&deltaq); if(((h->type) & SLOW_TIMER_MASK) == 0){ flag = SOS_MSG_HIGH_PRIORITY; } else { flag = 0; } if (((h->type) & ONE_SHOT_TIMER_MASK) == 0){ //! periocic timer while(h->delta <= 0) { // make sure it is positive h->delta += h->ticks; } list_insert_tail(&periodic_pool, (list_t*) h); } else { list_insert_tail(&timer_pool, (list_link_t*)h); } sched_dispatch_short_message(pid, TIMER_PID, MSG_TIMER_TIMEOUT, tid, 0, flag); } else { break; } } while(list_empty(&periodic_pool) == false) { list_link_t *link = periodic_pool.l_next; list_remove_head(&periodic_pool); timer_delta_q_insert((sos_timer_t*)link, false); } if(list_empty(&deltaq) == false) { sos_timer_t *h = (sos_timer_t*)(deltaq.l_next); int32_t hw_cnt; ENTER_CRITICAL_SECTION(); hw_cnt = outstanding_ticks - timer_hardware_get_counter(); if( h->delta - hw_cnt > 0) { LEAVE_CRITICAL_SECTION(); timer_set_hw_top(h->delta - hw_cnt, true); } else { LEAVE_CRITICAL_SECTION(); sched_add_interrupt(SCHED_TIMER_INT, soft_interrupt); } } else { ENTER_CRITICAL_SECTION(); timer_set_hw_top(MAX_SLEEP_INTERVAL, false); LEAVE_CRITICAL_SECTION(); }}static void timer_realtime_set_hw_top(uint16_t value){ // compute the time it takes to have next interrupt if(list_empty(&deltaq) == true) { timer_set_hw_top(value, false); } else { uint8_t hw_interval = timer_getInterval(); uint8_t hw_cnt = timer_hardware_get_counter(); if( (hw_interval - hw_cnt) >= value ) { if(list_empty(&deltaq) == true) { timer_set_hw_top(value, false); } else { timer_set_hw_top(value, true); } } }}int8_t timer_realtime_start(uint16_t value, uint16_t interval, timer_callback_t f){ uint8_t i; HAS_CRITICAL_SECTION; ENTER_CRITICAL_SECTION(); if( num_realtime_clock == MAX_REALTIME_CLOCK ) { LEAVE_CRITICAL_SECTION(); return -ENOMEM; } for( i = 0; i < MAX_REALTIME_CLOCK; i++ ) { if( realtime[i].f == NULL ) { timer_realtime_set_hw_top(value); num_realtime_clock++; realtime[i].value = value; realtime[i].interval = interval; realtime[i].f = f; LEAVE_CRITICAL_SECTION(); return SOS_OK; } } LEAVE_CRITICAL_SECTION(); return -ENOMEM;}int8_t timer_realtime_stop(timer_callback_t f){ uint8_t i; HAS_CRITICAL_SECTION; ENTER_CRITICAL_SECTION(); for( i = 0; i < MAX_REALTIME_CLOCK; i++ ) { if( realtime[i].f == f ) { realtime[i].f = NULL; num_realtime_clock--; LEAVE_CRITICAL_SECTION(); return SOS_OK; } } LEAVE_CRITICAL_SECTION(); return -EINVAL;}static uint16_t timer_update_realtime_clock(uint8_t cnt){ uint8_t i; uint16_t min_cnt = 65535; timer_callback_t f[MAX_REALTIME_CLOCK]; // iterate through all realtime clock for( i = 0; i < MAX_REALTIME_CLOCK; i++ ) { f[i] = NULL; if( realtime[i].f != NULL ) { if( realtime[i].value <= cnt ) { f[i] = realtime[i].f; if( realtime[i].interval != 0 ) { realtime[i].value += (realtime[i].interval - cnt); } else { realtime[i].f = NULL; num_realtime_clock--; continue; } } else { realtime[i].value -= cnt; } if( realtime[i].value < min_cnt ) { min_cnt = realtime[i].value; } } } for( i = 0; i < MAX_REALTIME_CLOCK; i++ ) { if( f[i] != NULL ) { (f[i])(); } } return min_cnt;}timer_interrupt(){ uint8_t cnt = timer_getInterval(); outstanding_ticks += cnt; sched_add_interrupt(SCHED_TIMER_INT, soft_interrupt); if( num_realtime_clock > 0 ) { timer_set_hw_interval( timer_update_realtime_clock(cnt) ); }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -