int8_t nrk_wait_until_next_n_periods (uint16_t p) { uint8_t timer; nrk_stack_check (); if (p == 0) p = 1; // Next Period Wakeup Time is Set inside scheduler when a task becomes Runnable nrk_int_disable (); nrk_cur_task_TCB->suspend_flag = 1; nrk_cur_task_TCB->num_periods = p; timer = _nrk_os_timer_get (); //nrk_cur_task_TCB->cpu_remaining=_nrk_prev_timer_val+1; // +2 allows for potential time conflict resolution if (timer < (MAX_SCHED_WAKEUP_TIME - TIME_PAD)) // 254 8bit overflow point - 2 if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) { timer += TIME_PAD; _nrk_prev_timer_val = timer; _nrk_set_next_wakeup (timer); } nrk_int_enable (); _nrk_wait_for_scheduler (); return NRK_OK; }
int8_t nrk_wait (nrk_time_t t) { uint8_t timer; uint16_t nw; nrk_stack_check (); nrk_int_disable (); nrk_cur_task_TCB->suspend_flag = 1; nrk_cur_task_TCB->num_periods = 1; timer = _nrk_os_timer_get (); //printf( "t1 %lu %lu\n",t.secs, t.nano_secs/NANOS_PER_MS); nw = _nrk_time_to_ticks (t); //printf( "t2 %u\n",nw ); nrk_cur_task_TCB->next_wakeup = nw + timer; //printf( "wu %u\n",nrk_cur_task_TCB->next_wakeup ); if (timer < (MAX_SCHED_WAKEUP_TIME - TIME_PAD)) if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) { timer += TIME_PAD; _nrk_prev_timer_val = timer; _nrk_set_next_wakeup (timer); } nrk_int_enable (); _nrk_wait_for_scheduler (); return NRK_OK; }
int8_t nrk_wait_until_next_period () { uint8_t timer; //Abhijeet disabled this... Haww //NVIC_EnableIRQ(TIMER0_IRQn); //NVIC_EnableIRQ(TIMER1_IRQn); //nrk_stack_check (); // Next Period Wakeup Time is Set inside scheduler when a task becomes Runnable nrk_int_disable (); nrk_cur_task_TCB->num_periods = 1; nrk_cur_task_TCB->suspend_flag = 1; timer = _nrk_os_timer_get (); //nrk_cur_task_TCB->cpu_remaining=_nrk_prev_timer_val+1; if (timer < (MAX_SCHED_WAKEUP_TIME - TIME_PAD)) // if(timer<(250-10)) if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) { timer += TIME_PAD; _nrk_prev_timer_val = timer; // pdiener: why is this only set in this special case? _nrk_set_next_wakeup (timer); // pdiener: Set next wakeup to NOW...Ask Madhur and Abhijeet } nrk_int_enable (); _nrk_wait_for_scheduler (); //pc6.printf("should not come here"); return NRK_OK; }
int8_t nrk_wait_until_next_period() { uint8_t timer; nrk_stack_check(); // Next Period Wakeup Time is Set inside scheduler when a task becomes Runnable nrk_int_disable(); nrk_cur_task_TCB->num_periods = 1; nrk_cur_task_TCB->suspend_flag = 1; timer = _nrk_os_timer_get(); //nrk_cur_task_TCB->cpu_remaining=_nrk_prev_timer_val+1; if (timer < (MAX_SCHED_WAKEUP_TIME - TIME_PAD)) if ((timer + TIME_PAD) <= _nrk_get_next_wakeup()) { timer += TIME_PAD; _nrk_prev_timer_val = timer; _nrk_set_next_wakeup(timer); } printf("Task %u finished in %u. \r\n",nrk_cur_task_TCB->task_ID,timer); nrk_int_enable(); _nrk_wait_for_scheduler(); return NRK_OK; }
int8_t nrk_wait_until_next_period () { uint16_t timer; nrk_stack_check (); // Next Period Wakeup Time is Set inside scheduler when a task becomes Runnable // EXCEPT THIS CAUSES A FIRST-TIME-THROUGH BUG nrk_int_disable (); nrk_cur_task_TCB->num_periods = 1; nrk_cur_task_TCB->suspend_flag = 1; nrk_cur_task_TCB->next_wakeup = nrk_cur_task_TCB->next_period; timer = _nrk_os_timer_get (); //nrk_cur_task_TCB->cpu_remaining=_nrk_prev_timer_val+1; if (timer < (MAX_SCHED_WAKEUP_TIME - TIME_PAD)) if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) { timer += TIME_PAD; _nrk_prev_timer_val = timer; _nrk_set_next_wakeup (timer); } nrk_int_enable (); _nrk_wait_for_scheduler (); return NRK_OK; }
int8_t nrk_wait_until_next_period () { uint8_t timer; nrk_stack_check (); // Next Period Wakeup Time is Set inside scheduler when a task becomes Runnable nrk_int_disable (); nrk_cur_task_TCB->num_periods = 1; nrk_cur_task_TCB->suspend_flag = 1; timer = _nrk_os_timer_get (); //nrk_cur_task_TCB->cpu_remaining=_nrk_prev_timer_val+1; if (timer < (MAX_SCHED_WAKEUP_TIME - TIME_PAD)) if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) { timer += TIME_PAD; _nrk_prev_timer_val = timer; // pdiener: why is this only set in this special case? _nrk_set_next_wakeup (timer); // pdiener: Set next wakeup to NOW } nrk_int_enable (); _nrk_wait_for_scheduler (); return NRK_OK; }
void nrk_time_get(nrk_time_t *t) { t->secs=nrk_system_time.secs; t->nano_secs=nrk_system_time.nano_secs; t->nano_secs+=((uint32_t)_nrk_os_timer_get()*(uint32_t)NANOS_PER_TICK); while(t->nano_secs>=(uint32_t)NANOS_PER_SEC) { t->nano_secs-=(uint32_t)NANOS_PER_SEC; t->secs++; } }
int8_t nrk_wait_until_nw() { uint8_t timer; nrk_int_disable(); nrk_cur_task_TCB->suspend_flag = 1; nrk_cur_task_TCB->nw_flag = 1; timer = _nrk_os_timer_get(); if (timer < MAX_SCHED_WAKEUP_TIME - TIME_PAD) if ((timer + TIME_PAD) <= _nrk_get_next_wakeup()) { timer += TIME_PAD; _nrk_prev_timer_val = timer; _nrk_set_next_wakeup(timer); } //else nrk_cur_task_TCB->next_wakeup=ticks+1; nrk_int_enable(); //while(nrk_cur_task_TCB->suspend_flag==1); _nrk_wait_for_scheduler(); return NRK_OK; }
int8_t nrk_set_next_wakeup(nrk_time_t t) { uint8_t timer; uint16_t nw; nrk_int_disable(); timer = _nrk_os_timer_get(); nw = _nrk_time_to_ticks(t); if (nw <= TIME_PAD) return NRK_ERROR; nrk_cur_task_TCB->next_wakeup = nw + timer; /* if(timer<(254-TIME_PAD)) if((timer+TIME_PAD)<=_nrk_get_next_wakeup()) { timer+=TIME_PAD; _nrk_prev_timer_val=timer; _nrk_set_next_wakeup(timer); } */ // nrk_cur_task_TCB->nw_flag=1; nrk_int_enable(); return NRK_OK; }
void nrk_time_get(nrk_time_t *t) { //t->nano_secs=(((uint32_t)_nrk_precision_os_timer_get()%PRECISION_TICKS_PER_TICK)*(uint32_t)NANOS_PER_PRECISION_TICK); #ifdef NRK_SUB_TICK_TIMING t->nano_secs=(((uint32_t)_nrk_precision_os_timer_get())*(uint32_t)NANOS_PER_PRECISION_TICK); #else t->nano_secs=0; #endif t->secs=nrk_system_time.secs; t->nano_secs+=nrk_system_time.nano_secs; t->nano_secs+=((uint32_t)_nrk_os_timer_get()*(uint32_t)NANOS_PER_TICK); while(t->nano_secs>=(uint32_t)NANOS_PER_SEC) { t->nano_secs-=(uint32_t)NANOS_PER_SEC; t->secs++; } }
void inline _nrk_scheduler() { int8_t task_ID; uint16_t next_wake; //uint16_t start_time_stamp; /* _nrk_precision_os_timer_reset(); */ /* nrk_int_disable(); */ // this should be removed... Not needed #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP _nrk_high_speed_timer_reset(); start_time_stamp=_nrk_high_speed_timer_get(); #endif _nrk_set_next_wakeup(MAX_SCHED_WAKEUP_TIME); // Set to huge number which will later get set to min next_wake=60000; // Safety zone starts here.... #ifdef NRK_WATCHDOG nrk_watchdog_reset(); #endif #ifdef NRK_SW_WDT _nrk_sw_wdt_check(); #endif #ifdef NRK_KERNEL_TEST //nrk_kprintf( PSTR("*")); //Check if OS tick was delayed... // if(_nrk_cpu_state!=CPU_SLEEP && _nrk_os_timer_get()!=0) { // nrk_kprintf( PSTR("X" )); //printf( "%u ",_nrk_os_timer_get()); // } //printf( "%u\r\n",_nrk_prev_timer_val); if((_nrk_cpu_state!=CPU_ACTIVE) && (_nrk_os_timer_get()>nrk_max_sleep_wakeup_time)) nrk_max_sleep_wakeup_time=_nrk_os_timer_get(); #endif //while(_nrk_time_trigger>0) //{ nrk_system_time.nano_secs+=((uint32_t)_nrk_prev_timer_val*NANOS_PER_TICK); nrk_system_time.nano_secs-=(nrk_system_time.nano_secs%(uint32_t)NANOS_PER_TICK); #ifdef NRK_STATS_TRACKER if(nrk_cur_task_TCB->task_ID==NRK_IDLE_TASK_ID) { if(_nrk_cpu_state==CPU_SLEEP) _nrk_stats_sleep(_nrk_prev_timer_val); _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); // Add 0 time since the preempted call before set the correct value _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, 0); } else { if(nrk_cur_task_TCB->suspend_flag==1) _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); else _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); } #endif while(nrk_system_time.nano_secs>=NANOS_PER_SEC) { nrk_system_time.nano_secs-=NANOS_PER_SEC; nrk_system_time.secs++; nrk_system_time.nano_secs-=(nrk_system_time.nano_secs%(uint32_t)NANOS_PER_TICK); } // _nrk_time_trigger--; //} if(nrk_cur_task_TCB->suspend_flag==1 && nrk_cur_task_TCB->task_state!=FINISHED) { // nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; if(nrk_cur_task_TCB->event_suspend==RSRC_EVENT_SUSPENDED) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if( nrk_cur_task_TCB->event_suspend>0 && nrk_cur_task_TCB->nw_flag==0) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if( nrk_cur_task_TCB->event_suspend>0 && nrk_cur_task_TCB->nw_flag==1) nrk_cur_task_TCB->task_state = SUSPENDED; else { nrk_cur_task_TCB->task_state = SUSPENDED; nrk_cur_task_TCB->event_suspend=0; nrk_cur_task_TCB->nw_flag=0; } nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); } // nrk_print_readyQ(); // Update cpu used value for ended task // If the task has used its reserve, suspend task // Don't disable IdleTask which is 0 // Don't decrease cpu_remaining if reserve is 0 and hence disabled if(nrk_cur_task_TCB->cpu_reserve!=0 && nrk_cur_task_TCB->task_ID!=NRK_IDLE_TASK_ID) { // Update CASH and cpu_remaining // First use up any available CASH budget uint8_t ticksToAccountFor = _nrk_prev_timer_val; nrk_budget_t *budgetFromCASH = nrk_peek_budget(); while (ticksToAccountFor > 0 && budgetFromCASH) { // We've found some cash budget uint8_t availableCASH = budgetFromCASH->amount_left; nrk_time_t system_time; nrk_time_get(&system_time); // We need to look at the deadline for the cash budget // If it has passed, we can only use the portion that came before the deadline if (nrk_time_compare(&system_time, &budgetFromCASH->expire_time) == 1) { nrk_time_t difference; nrk_time_sub(&difference, system_time, budgetFromCASH->expire_time); uint8_t differenceInTicks = _nrk_time_to_ticks(&difference); // Check if it expired before we got a chance to use it if (differenceInTicks > ticksToAccountFor) { availableCASH = 0; } else { uint8_t usableBudget = ticksToAccountFor - _nrk_time_to_ticks(&difference); // Take the minimum of available vs usable availableCASH = usableBudget < availableCASH ? usableBudget : availableCASH; } // pop it off the queue. Expired now. nrk_get_budget(); } if (availableCASH > ticksToAccountFor) { budgetFromCASH->amount_left -= ticksToAccountFor; ticksToAccountFor = 0; } else { ticksToAccountFor -= availableCASH; // Pop the now empty cash budget off the queue nrk_get_budget(); } budgetFromCASH = budgetFromCASH->Next; } // If we still have ticks to account for, take them off cpu_remaining if (ticksToAccountFor > 0) { nrk_cur_task_TCB->cpu_remaining -= ticksToAccountFor; } // For finished tasks that still have cpu remaining, give it to the CASH queue if (nrk_cur_task_TCB->task_state==FINISHED && nrk_cur_task_TCB->cpu_remaining > 0) { // Add to CASH queue nrk_add_nrk_budget(nrk_cur_task_TCB->absolute_deadline, nrk_cur_task_TCB->cpu_remaining); } else if (nrk_cur_task_TCB->cpu_remaining ==0 ) { // Support for Constant Bandwith Servers if(nrk_cur_task_TCB->task_type == CBS_TASK) { // Recharge budget nrk_cur_task_TCB->cpu_remaining = nrk_cur_task_TCB->cpu_reserve; // Increase the absolute deadline nrk_time_t increase = _nrk_ticks_to_time(nrk_cur_task_TCB->period); nrk_time_add(&nrk_cur_task_TCB->absolute_deadline, nrk_cur_task_TCB->absolute_deadline, increase); // Remove/re-add from ready queue to re-sort based on new absolute deadline nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); nrk_add_to_readyQ(nrk_cur_task_TCB->task_ID); } else { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif nrk_kernel_error_add(NRK_RESERVE_VIOLATED,nrk_cur_task_TCB->task_ID); nrk_cur_task_TCB->task_state = SUSPENDED; nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); } } } // Check I/O nrk_queues to add tasks with remaining cpu back... // Add eligable tasks back to the ready Queue // At the same time find the next earliest wakeup for (task_ID=0; task_ID < NRK_MAX_TASKS; task_ID++) { if(nrk_task_TCB[task_ID].task_ID==-1) continue; nrk_task_TCB[task_ID].suspend_flag=0; if( nrk_task_TCB[task_ID].task_ID!=NRK_IDLE_TASK_ID && nrk_task_TCB[task_ID].task_state!=FINISHED ) { if( nrk_task_TCB[task_ID].next_wakeup >= _nrk_prev_timer_val ) nrk_task_TCB[task_ID].next_wakeup-=_nrk_prev_timer_val; else { nrk_task_TCB[task_ID].next_wakeup=0; } // Do next period book keeping. // next_period needs to be set such that the period is kept consistent even if other // wait until functions are called. if( nrk_task_TCB[task_ID].next_period >= _nrk_prev_timer_val ) nrk_task_TCB[task_ID].next_period-=_nrk_prev_timer_val; else { if(nrk_task_TCB[task_ID].period>_nrk_prev_timer_val) nrk_task_TCB[task_ID].next_period= nrk_task_TCB[task_ID].period-_nrk_prev_timer_val; else nrk_task_TCB[task_ID].next_period= _nrk_prev_timer_val % nrk_task_TCB[task_ID].period; } if(nrk_task_TCB[task_ID].next_period==0) nrk_task_TCB[task_ID].next_period=nrk_task_TCB[task_ID].period; } // Look for Next Task that Might Wakeup to interrupt current task if (nrk_task_TCB[task_ID].task_state == SUSPENDED ) { // printf( "Task: %d nw: %d\n",task_ID,nrk_task_TCB[task_ID].next_wakeup); // If a task needs to become READY, make it ready if (nrk_task_TCB[task_ID].next_wakeup == 0) { // printf( "Adding back %d\n",task_ID ); if(nrk_task_TCB[task_ID].event_suspend>0 && nrk_task_TCB[task_ID].nw_flag==1) nrk_task_TCB[task_ID].active_signal_mask=SIG(nrk_wakeup_signal); //if(nrk_task_TCB[task_ID].event_suspend==0) nrk_task_TCB[task_ID].active_signal_mask=0; nrk_task_TCB[task_ID].event_suspend=0; nrk_task_TCB[task_ID].nw_flag=0; nrk_task_TCB[task_ID].suspend_flag=0; if(nrk_task_TCB[task_ID].num_periods==1) { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; nrk_task_TCB[task_ID].task_state = READY; nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; // If there is no period set, don't wakeup periodically if(nrk_task_TCB[task_ID].period==0) nrk_task_TCB[task_ID].next_wakeup = MAX_SCHED_WAKEUP_TIME; nrk_add_to_readyQ(task_ID); } else { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; //nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; //nrk_task_TCB[task_ID].num_periods--; nrk_task_TCB[task_ID].next_wakeup = (nrk_task_TCB[task_ID].period*(nrk_task_TCB[task_ID].num_periods-1)); nrk_task_TCB[task_ID].next_period = (nrk_task_TCB[task_ID].period*(nrk_task_TCB[task_ID].num_periods-1)); if(nrk_task_TCB[task_ID].period==0) nrk_task_TCB[task_ID].next_wakeup = MAX_SCHED_WAKEUP_TIME; nrk_task_TCB[task_ID].num_periods=1; // printf( "np = %d\r\n",nrk_task_TCB[task_ID].next_wakeup); // nrk_task_TCB[task_ID].num_periods=1; } } if(nrk_task_TCB[task_ID].next_wakeup!=0 && nrk_task_TCB[task_ID].next_wakeup<next_wake ) { // Find closest next_wake task next_wake=nrk_task_TCB[task_ID].next_wakeup; } } } #ifdef NRK_STATS_TRACKER _nrk_stats_task_start(nrk_cur_task_TCB->task_ID); #endif task_ID = nrk_get_high_ready_task_ID(); nrk_high_ready_prio = nrk_task_TCB[task_ID].task_prio; nrk_high_ready_TCB = &nrk_task_TCB[task_ID]; // next_wake should hold next time when a suspended task might get run // task_ID holds the highest priority READY task ID // So nrk_task_TCB[task_ID].cpu_remaining holds the READY task's end time // Now we pick the next wakeup (either the end of the current task, or the possible resume // of a suspended task) if(task_ID!=NRK_IDLE_TASK_ID) { // You are a non-Idle Task if(nrk_task_TCB[task_ID].cpu_reserve!=0 && nrk_task_TCB[task_ID].cpu_remaining<MAX_SCHED_WAKEUP_TIME) { if(next_wake>nrk_task_TCB[task_ID].cpu_remaining) next_wake=nrk_task_TCB[task_ID].cpu_remaining; } else { if(next_wake>MAX_SCHED_WAKEUP_TIME) next_wake=MAX_SCHED_WAKEUP_TIME; } } else { // This is the idle task // Make sure you wake up from the idle task a little earlier // if you would go into deep sleep... // After waking from deep sleep, the next context swap must be at least // NRK_SLEEP_WAKEUP_TIME-1 away to make sure the CPU wakes up in time. #ifndef NRK_NO_POWER_DOWN if(next_wake>NRK_SLEEP_WAKEUP_TIME) { if(next_wake-NRK_SLEEP_WAKEUP_TIME<MAX_SCHED_WAKEUP_TIME) { if(next_wake-NRK_SLEEP_WAKEUP_TIME<NRK_SLEEP_WAKEUP_TIME) { next_wake=NRK_SLEEP_WAKEUP_TIME-1; } else { next_wake=next_wake-NRK_SLEEP_WAKEUP_TIME; } } else if(next_wake>NRK_SLEEP_WAKEUP_TIME+MAX_SCHED_WAKEUP_TIME) { next_wake=MAX_SCHED_WAKEUP_TIME; } else { next_wake=MAX_SCHED_WAKEUP_TIME-NRK_SLEEP_WAKEUP_TIME; } } #endif } /* // Some code to catch the case when the scheduler wakes up // from deep sleep and has to execute again before NRK_SLEEP_WAKEUP_TIME-1 if(_nrk_cpu_state==2 && next_wake<NRK_SLEEP_WAKEUP_TIME-1) { nrk_int_disable(); while(1) { nrk_spin_wait_us(60000); nrk_led_toggle(RED_LED); nrk_spin_wait_us(60000); nrk_led_toggle(GREEN_LED); printf( "crash: %d %d %d\r\n",task_ID,next_wake,_nrk_cpu_state); } }*/ // If we disable power down, we still need to wakeup before the overflow #ifdef NRK_NO_POWER_DOWN if(next_wake>MAX_SCHED_WAKEUP_TIME) next_wake=MAX_SCHED_WAKEUP_TIME; #endif //printf( "nw = %d %d %d\r\n",task_ID,_nrk_cpu_state,next_wake); nrk_cur_task_prio = nrk_high_ready_prio; nrk_cur_task_TCB = nrk_high_ready_TCB; #ifdef NRK_KERNEL_TEST if(nrk_high_ready_TCB==NULL) { nrk_kprintf( PSTR( "KERNEL TEST: BAD TCB!\r\n" )); } #endif //printf( "n %u %u %u %u\r\n",task_ID, _nrk_prev_timer_val, next_wake,_nrk_os_timer_get()); _nrk_prev_timer_val=next_wake; if((_nrk_os_timer_get()+1)>=next_wake) // just bigger then, or equal? { // FIXME: Terrible Terrible... // Need to find out why this is happening... #ifdef NRK_KERNEL_TEST // Ignore if you are the idle task coming from deep sleep if(!(task_ID==NRK_IDLE_TASK_ID && _nrk_cpu_state==CPU_SLEEP)) nrk_kernel_error_add(NRK_WAKEUP_MISSED,task_ID); #endif // This is bad news, but keeps things running // +2 just in case we are on the edge of the last tick next_wake=_nrk_os_timer_get()+2; _nrk_prev_timer_val=next_wake; } if(task_ID!=NRK_IDLE_TASK_ID) _nrk_cpu_state=CPU_ACTIVE; _nrk_set_next_wakeup(next_wake); #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP // Bound Context Swap to 100us nrk_high_speed_timer_wait(start_time_stamp,CONTEXT_SWAP_TIME_BOUND); #endif nrk_stack_pointer_restore(); //nrk_int_enable(); nrk_start_high_ready_task(); }
void _isa_rx (uint8_t slot) { uint8_t n; uint32_t node_mask; volatile uint8_t timeout; #ifdef LED_DEBUG nrk_led_set(1); #endif rf_set_rx (&isa_rfRxInfo, isa_param.channel); // sets rx buffer and channel rf_polling_rx_on (); // Timing for waiting for sfd timeout = _nrk_os_timer_get(); timeout+=4; // 4ms n = 0; //nrk_gpio_set(NRK_DEBUG_3); while ((n = rf_rx_check_sfd()) == 0) { if (_nrk_os_timer_get() > timeout) { //spend too much time on waiting for a pkt's arrival rf_rx_off (); #ifdef LED_DEBUG nrk_led_clr(1); #endif #ifdef RX_DEBUG printf("sfd times out.\n\r"); #endif return; } } //printf("%d\n\r",_nrk_high_speed_timer_get()); // sfd received, start receiving packet and record start time rx_start_time = _nrk_high_speed_timer_get(); // Timing for waiting for finishing packet receiving timeout = _nrk_os_timer_get(); timeout += 5; // 5ms if (n != 0) { n = 0; //printf("Packet on its way\n\r"); while ((n = rf_polling_rx_packet (false,128)) == 0) { //printf("%d\n\r",_nrk_os_timer_get()); if (_nrk_os_timer_get () > timeout) { #ifdef RX_DEBUG printf("packet is too long, times out.\n\r"); #endif // spend too much time on receiving pkt. return; // huge timeout as fail safe } } } rf_rx_off (); if (n == 1) {// successfully received packet isa_rx_data_ready = 1; //potential problem: if repeater or recipient receives noise, the DHDR would be changed. And it is highly possible that the highest bit of DHDR would be set to 0 /*if(isa_node_mode != ISA_GATEWAY) DHDR = isa_rfRxInfo.pPayload[DHDR_INDEX];*/ #ifdef RX_DEBUG printf("Repeater slot = %d, local slot is %d.\n\r", isa_rfRxInfo.pPayload[SLOT_INDEX],global_slot); #endif RX_DEBUG nrk_event_signal(isa_rx_pkt_signal); //_nrk_high_speed_timer_reset(); //nrk_high_speed_timer_wait(0,CPU_PROCESS_TIME); //nrk_gpio_set(NRK_DEBUG_3); node_mask = ((uint32_t) 1) << isa_rfRxInfo.pPayload[SRC_INDEX]; if( !(node_mask & child_list)) return; //FIXME change // ACK required if(DHDR & (1<<7)){ // Transmit ACK packet DHR = configDHR(); isa_ack_buf[DHR_INDEX]= DHR; #ifdef ACK_DEBUG //printf("DHR is %d.\n\r",DHR); #endif isa_ack_tx.pPayload = isa_ack_buf; if (DHDR & (1<<2)){ // recipient , only reply explicit ACK //isa_ack_tx.length = PKT_DATA_START-1; isa_ack_tx.length = 2; } else { //reply ACK with time offsetX offsetX = rx_start_time - slot_start_time; //printf("slot_start_time is %d,rx_start_time is %d.\n\r",slot_start_time,rx_start_time); uint8_t temp1,temp2; temp1 = (offsetX & 0xFF00)>>8; isa_ack_buf[OFFSET_HIGH]=temp1; temp2 = (offsetX & 0x00FF); isa_ack_buf[OFFSET_LOW]=temp2; #ifdef ACK_DEBUG printf("offsetX is %d\n\r", offsetX); #endif //isa_ack_tx.length = PKT_DATA_START + 1; isa_ack_tx.length = 4; } rf_tx_tdma_packet (&isa_ack_tx,slot_start_time,isa_param.tx_guard_time,&tx_start_time); }
/************************************************************************** This function is the same as normal TX, only it waits until the last second to send the duty out with the high speed timer. And by duty, I mean the packet BIATCH... **************************************************************************/ uint8_t rf_tx_tdma_packet(RF_TX_INFO *pRTI, uint16_t slot_start_time, uint16_t tx_guard_time) { uint16_t frameControlField; uint8_t packetLength; uint8_t success; uint8_t spiStatusByte; uint8_t checksum,i; uint8_t timestamp; #ifdef RADIO_PRIORITY_CEILING nrk_sem_pend (radio_sem); #endif timestamp=_nrk_os_timer_get(); // XXX 2 below are hacks... #ifdef CC2420_OSC_OPT FASTSPI_STROBE(CC2420_SXOSCON); nrk_spin_wait_us(OSC_STARTUP_DELAY); #endif FASTSPI_STROBE(CC2420_SFLUSHRX); FASTSPI_STROBE(CC2420_SFLUSHRX); // Wait until the transceiver is idle while (FIFOP_IS_1 || SFD_IS_1); // Turn off global interrupts to avoid interference on the SPI interface DISABLE_GLOBAL_INT(); // Flush the TX FIFO just in case... FASTSPI_STROBE(CC2420_SFLUSHTX); FASTSPI_STROBE(CC2420_SFLUSHTX); checksum=0; for(i=0; i<pRTI->length; i++ ) { // lets do our own payload checksum because we don't trust the CRC checksum+=pRTI->pPayload[i]; } packetLength = pRTI->length + RF_PACKET_OVERHEAD_SIZE + CHECKSUM_OVERHEAD; //nrk_set_led(3); //do { } while(_nrk_get_high_speed_timer()<(tx_guard_time)); // Write the packet to the TX FIFO (the FCS is appended automatically when AUTOCRC is enabled) // These are only the MAC AGNOSTIC parameters... // Slots for example are at a higher layer since they assume TDMA FASTSPI_WRITE_FIFO((uint8_t*)&packetLength, 1); // Packet length frameControlField = pRTI->ackRequest ? RF_FCF_ACK : RF_FCF_NOACK; FASTSPI_WRITE_FIFO((uint8_t*) &frameControlField, 2); // Frame control field FASTSPI_WRITE_FIFO((uint8_t*) &rfSettings.txSeqNumber, 1); // Sequence number FASTSPI_WRITE_FIFO((uint8_t*) &rfSettings.panId, 2); // Dest. PAN ID FASTSPI_WRITE_FIFO((uint8_t*) &pRTI->destAddr, 2); // Dest. address FASTSPI_WRITE_FIFO((uint8_t*) &rfSettings.myAddr, 2); // Source address nrk_high_speed_timer_wait(slot_start_time,tx_guard_time); //nrk_clr_led(3); /* DISABLE_GLOBAL_INT(); nrk_set_led(3); last=0; do { if(last==_nrk_get_high_speed_timer()) { //while(1) //printf( "TX ERROR %d vs %d\r\n",_nrk_get_high_speed_timer(),tx_guard_time ); break; } last=_nrk_get_high_speed_timer(); } while((volatile)last<(tx_guard_time)); ENABLE_GLOBAL_INT(); nrk_clr_led(3); */ /* // Turn on RX if necessary if (!rfSettings.receiveOn) { FASTSPI_STROBE(CC2420_SRXON); } // Wait for the RSSI value to become valid do { FASTSPI_UPD_STATUS(spiStatusByte); } while (!(spiStatusByte & BM(CC2420_RSSI_VALID))); // TX begins after the CCA check has passed do { FASTSPI_STROBE(CC2420_STXONCCA); FASTSPI_UPD_STATUS(spiStatusByte); halWait(100); } while (!(spiStatusByte & BM(CC2420_TX_ACTIVE))); */ if (pRTI->cca == TRUE) { uint8_t cnt; if (!rfSettings.receiveOn) { FASTSPI_STROBE (CC2420_SRXON); } // Wait for the RSSI value to become valid do { FASTSPI_UPD_STATUS (spiStatusByte); } while (!(spiStatusByte & BM (CC2420_RSSI_VALID))); // TX begins after the CCA check has passed cnt = 0; do { FASTSPI_STROBE (CC2420_STXONCCA); FASTSPI_UPD_STATUS (spiStatusByte); cnt++; if (cnt > 100) { ENABLE_GLOBAL_INT (); nrk_sem_post(radio_sem); return FALSE; } halWait (100); } while (!(spiStatusByte & BM (CC2420_TX_ACTIVE))); } else FASTSPI_STROBE (CC2420_STXON); //nrk_gpio_set(DEBUG_0); // Fill in the rest of the packet now FASTSPI_WRITE_FIFO((uint8_t*) pRTI->pPayload, pRTI->length); // Payload FASTSPI_WRITE_FIFO((uint8_t*) &checksum, 1); // Checksum //nrk_spin_wait_us(200); // FASTSPI_STROBE(CC2420_STXON); // Wait for the transmission to begin before exiting (makes sure that this function cannot be called // a second time, and thereby cancelling the first transmission (observe the FIFOP + SFD test above). while (!SFD_IS_1); success = TRUE; // Turn interrupts back on // ENABLE_GLOBAL_INT(); // Wait for the acknowledge to be received, if any /*if (pRTI->ackRequest) { rfSettings.ackReceived = FALSE; // Wait for the SFD to go low again while (SFD_IS_1); // We'll enter RX automatically, so just wait until we can be sure that the ack reception should have finished // The timeout consists of a 12-symbol turnaround time, the ack packet duration, and a small margin halWait((12 * RF_SYMBOL_DURATION) + (RF_ACK_DURATION) + (2 * RF_SYMBOL_DURATION) + 100); // If an acknowledgment has been received (by the FIFOP interrupt), the ackReceived flag should be set success = rfSettings.ackReceived; }*/ // Turn off the receiver if it should not continue to be enabled DISABLE_GLOBAL_INT(); // XXX hack, temp out //if (!rfSettings.receiveOn) { while (SFD_IS_1); /*FASTSPI_STROBE(CC2420_SRFOFF);*/ } // while (SFD_IS_1); while (SFD_IS_1); // wait for packet to finish FASTSPI_STROBE(CC2420_SFLUSHRX); FASTSPI_STROBE(CC2420_SFLUSHRX); FASTSPI_STROBE(CC2420_SFLUSHTX); FASTSPI_STROBE(CC2420_SFLUSHTX); #ifdef CC2420_OSC_OPT FASTSPI_STROBE(CC2420_SXOSCOFF); #endif FASTSPI_STROBE(CC2420_SRFOFF); // shut off radio ENABLE_GLOBAL_INT(); // Increment the sequence number, and return the result rfSettings.txSeqNumber++; // while (SFD_IS_1); #ifdef RADIO_PRIORITY_CEILING nrk_sem_post(radio_sem); #endif return success; }
void inline _nrk_scheduler() { int8_t task_ID; uint16_t next_wake; uint16_t start_time_stamp; _nrk_precision_os_timer_reset(); nrk_int_disable(); // this should be removed... Not needed #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP _nrk_high_speed_timer_reset(); start_time_stamp=_nrk_high_speed_timer_get(); #endif _nrk_set_next_wakeup(MAX_SCHED_WAKEUP_TIME); // Set to huge number which will later get set to min next_wake=60000; // Safety zone starts here.... #ifdef NRK_WATCHDOG nrk_watchdog_reset(); #endif #ifdef NRK_SW_WDT _nrk_sw_wdt_check(); #endif //printf( "last run: %d\n",nrk_cur_task_TCB->task_ID ); //for (task_ID=0; task_ID < NRK_MAX_TASKS; task_ID++) //{ //printf( "%d nw:%lu\n",task_ID,nrk_task_TCB[task_ID].next_wakeup ); //} #ifdef NRK_KERNEL_TEST //nrk_kprintf( PSTR("*")); //Check if OS tick was delayed... // if(_nrk_cpu_state!=CPU_SLEEP && _nrk_os_timer_get()!=0) { // nrk_kprintf( PSTR("X" )); //printf( "%u ",_nrk_os_timer_get()); // } //printf( "%u\r\n",_nrk_prev_timer_val); if((_nrk_cpu_state!=CPU_ACTIVE) && (_nrk_os_timer_get()>nrk_max_sleep_wakeup_time)) nrk_max_sleep_wakeup_time=_nrk_os_timer_get(); #endif //while(_nrk_time_trigger>0) //{ nrk_system_time.nano_secs+=((uint32_t)_nrk_prev_timer_val*NANOS_PER_TICK); nrk_system_time.nano_secs-=(nrk_system_time.nano_secs%(uint32_t)NANOS_PER_TICK); #ifdef NRK_STATS_TRACKER if(nrk_cur_task_TCB->task_ID==NRK_IDLE_TASK_ID) { if(_nrk_cpu_state==CPU_SLEEP) _nrk_stats_sleep(_nrk_prev_timer_val); _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); // Add 0 time since the preempted call before set the correct value _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, 0); } else { if(nrk_cur_task_TCB->suspend_flag==1) _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); else _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); } #endif while(nrk_system_time.nano_secs>=NANOS_PER_SEC) { nrk_system_time.nano_secs-=NANOS_PER_SEC; nrk_system_time.secs++; nrk_system_time.nano_secs-=(nrk_system_time.nano_secs%(uint32_t)NANOS_PER_TICK); } // _nrk_time_trigger--; //} if(nrk_cur_task_TCB->suspend_flag==1 && nrk_cur_task_TCB->task_state!=FINISHED) { // nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; if(nrk_cur_task_TCB->event_suspend==RSRC_EVENT_SUSPENDED) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if( nrk_cur_task_TCB->event_suspend>0 && nrk_cur_task_TCB->nw_flag==0) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if( nrk_cur_task_TCB->event_suspend>0 && nrk_cur_task_TCB->nw_flag==1) nrk_cur_task_TCB->task_state = SUSPENDED; else { nrk_cur_task_TCB->task_state = SUSPENDED; nrk_cur_task_TCB->event_suspend=0; nrk_cur_task_TCB->nw_flag=0; // agr added to fix initial startup scheduling problem if(nrk_cur_task_TCB->next_wakeup==0) { nrk_cur_task_TCB->next_wakeup=nrk_cur_task_TCB->next_period; } } nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); } // nrk_print_readyQ(); // Update cpu used value for ended task // If the task has used its reserve, suspend task // Don't disable IdleTask which is 0 // Don't decrease cpu_remaining if reserve is 0 and hence disabled if(nrk_cur_task_TCB->cpu_reserve!=0 && nrk_cur_task_TCB->task_ID!=NRK_IDLE_TASK_ID && nrk_cur_task_TCB->task_state!=FINISHED ) { if(nrk_cur_task_TCB->cpu_remaining<_nrk_prev_timer_val) { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif nrk_kernel_error_add(NRK_RESERVE_ERROR,nrk_cur_task_TCB->task_ID); nrk_cur_task_TCB->cpu_remaining=0; } else nrk_cur_task_TCB->cpu_remaining-=_nrk_prev_timer_val; task_ID= nrk_cur_task_TCB->task_ID; if (nrk_cur_task_TCB->cpu_remaining ==0 ) { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif nrk_kernel_error_add(NRK_RESERVE_VIOLATED,task_ID); nrk_cur_task_TCB->task_state = SUSPENDED; nrk_rem_from_readyQ(task_ID); } } // Check I/O nrk_queues to add tasks with remaining cpu back... // Add eligable tasks back to the ready Queue // At the same time find the next earliest wakeup for (task_ID=0; task_ID < NRK_MAX_TASKS; task_ID++) { if(nrk_task_TCB[task_ID].task_ID==-1) continue; nrk_task_TCB[task_ID].suspend_flag=0; if( nrk_task_TCB[task_ID].task_ID!=NRK_IDLE_TASK_ID && nrk_task_TCB[task_ID].task_state!=FINISHED ) { if( nrk_task_TCB[task_ID].next_wakeup >= _nrk_prev_timer_val ) nrk_task_TCB[task_ID].next_wakeup-=_nrk_prev_timer_val; else { nrk_task_TCB[task_ID].next_wakeup=0; } // Do next period book keeping. // next_period needs to be set such that the period is kept consistent even if other // wait until functions are called. if( nrk_task_TCB[task_ID].next_period >= _nrk_prev_timer_val ) nrk_task_TCB[task_ID].next_period-=_nrk_prev_timer_val; else { if(nrk_task_TCB[task_ID].period>_nrk_prev_timer_val) nrk_task_TCB[task_ID].next_period= nrk_task_TCB[task_ID].period-_nrk_prev_timer_val; else nrk_task_TCB[task_ID].next_period= _nrk_prev_timer_val % nrk_task_TCB[task_ID].period; } if(nrk_task_TCB[task_ID].next_period==0) nrk_task_TCB[task_ID].next_period=nrk_task_TCB[task_ID].period; } // Look for Next Task that Might Wakeup to interrupt current task if (nrk_task_TCB[task_ID].task_state == SUSPENDED ) { //printf( "Task: %d nw: %d\n",task_ID,nrk_task_TCB[task_ID].next_wakeup); // If a task needs to become READY, make it ready if (nrk_task_TCB[task_ID].next_wakeup == 0) { // printf( "Adding back %d\n",task_ID ); if(nrk_task_TCB[task_ID].event_suspend>0 && nrk_task_TCB[task_ID].nw_flag==1) nrk_task_TCB[task_ID].active_signal_mask=SIG(nrk_wakeup_signal); //if(nrk_task_TCB[task_ID].event_suspend==0) nrk_task_TCB[task_ID].active_signal_mask=0; nrk_task_TCB[task_ID].event_suspend=0; nrk_task_TCB[task_ID].nw_flag=0; nrk_task_TCB[task_ID].suspend_flag=0; if(nrk_task_TCB[task_ID].num_periods==1) { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; nrk_task_TCB[task_ID].task_state = READY; nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; // If there is no period set, don't wakeup periodically if(nrk_task_TCB[task_ID].period==0) nrk_task_TCB[task_ID].next_wakeup = MAX_SCHED_WAKEUP_TIME; nrk_add_to_readyQ(task_ID); } else { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; //nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; //nrk_task_TCB[task_ID].num_periods--; nrk_task_TCB[task_ID].next_wakeup = (nrk_task_TCB[task_ID].period*(nrk_task_TCB[task_ID].num_periods-1)); nrk_task_TCB[task_ID].next_period = (nrk_task_TCB[task_ID].period*(nrk_task_TCB[task_ID].num_periods-1)); if(nrk_task_TCB[task_ID].period==0) nrk_task_TCB[task_ID].next_wakeup = MAX_SCHED_WAKEUP_TIME; nrk_task_TCB[task_ID].num_periods=1; // printf( "np = %d\r\n",nrk_task_TCB[task_ID].next_wakeup); // nrk_task_TCB[task_ID].num_periods=1; } } if(nrk_task_TCB[task_ID].next_wakeup!=0 && nrk_task_TCB[task_ID].next_wakeup<next_wake ) { // Find closest next_wake task next_wake=nrk_task_TCB[task_ID].next_wakeup; } } } #ifdef NRK_STATS_TRACKER _nrk_stats_task_start(nrk_cur_task_TCB->task_ID); #endif task_ID = nrk_get_high_ready_task_ID(); nrk_high_ready_prio = nrk_task_TCB[task_ID].task_prio; nrk_high_ready_TCB = &nrk_task_TCB[task_ID]; // next_wake should hold next time when a suspended task might get run // task_ID holds the highest priority READY task ID // So nrk_task_TCB[task_ID].cpu_remaining holds the READY task's end time // Now we pick the next wakeup (either the end of the current task, or the possible resume // of a suspended task) if(task_ID!=NRK_IDLE_TASK_ID) { // You are a non-Idle Task if(nrk_task_TCB[task_ID].cpu_reserve!=0 && nrk_task_TCB[task_ID].cpu_remaining<MAX_SCHED_WAKEUP_TIME) { if(next_wake>nrk_task_TCB[task_ID].cpu_remaining) next_wake=nrk_task_TCB[task_ID].cpu_remaining; } else { if(next_wake>MAX_SCHED_WAKEUP_TIME) next_wake=MAX_SCHED_WAKEUP_TIME; } } else { // This is the idle task // Make sure you wake up from the idle task a little earlier // if you would go into deep sleep... // After waking from deep sleep, the next context swap must be at least // NRK_SLEEP_WAKEUP_TIME-1 away to make sure the CPU wakes up in time. #ifndef NRK_NO_POWER_DOWN if(next_wake>NRK_SLEEP_WAKEUP_TIME) { if(next_wake-NRK_SLEEP_WAKEUP_TIME<MAX_SCHED_WAKEUP_TIME) { if(next_wake-NRK_SLEEP_WAKEUP_TIME<NRK_SLEEP_WAKEUP_TIME) { next_wake=NRK_SLEEP_WAKEUP_TIME-1; } else { next_wake=next_wake-NRK_SLEEP_WAKEUP_TIME; } } else if(next_wake>NRK_SLEEP_WAKEUP_TIME+MAX_SCHED_WAKEUP_TIME) { next_wake=MAX_SCHED_WAKEUP_TIME; } else { next_wake=MAX_SCHED_WAKEUP_TIME-NRK_SLEEP_WAKEUP_TIME; } } #endif } /* // Some code to catch the case when the scheduler wakes up // from deep sleep and has to execute again before NRK_SLEEP_WAKEUP_TIME-1 if(_nrk_cpu_state==2 && next_wake<NRK_SLEEP_WAKEUP_TIME-1) { nrk_int_disable(); while(1) { nrk_spin_wait_us(60000); nrk_led_toggle(RED_LED); nrk_spin_wait_us(60000); nrk_led_toggle(GREEN_LED); printf( "crash: %d %d %d\r\n",task_ID,next_wake,_nrk_cpu_state); } }*/ // If we disable power down, we still need to wakeup before the overflow #ifdef NRK_NO_POWER_DOWN if(next_wake>MAX_SCHED_WAKEUP_TIME) next_wake=MAX_SCHED_WAKEUP_TIME; #endif //printf( "nw = %d %d %d\r\n",task_ID,_nrk_cpu_state,next_wake); nrk_cur_task_prio = nrk_high_ready_prio; nrk_cur_task_TCB = nrk_high_ready_TCB; #ifdef NRK_KERNEL_TEST if(nrk_high_ready_TCB==NULL) { nrk_kprintf( PSTR( "KERNEL TEST: BAD TCB!\r\n" )); } #endif //printf( "n %u %u %u %u\r\n",task_ID, _nrk_prev_timer_val, next_wake,_nrk_os_timer_get()); _nrk_prev_timer_val=next_wake; // Maybe the signals are triggering this problem? if((_nrk_os_timer_get()+1)>=next_wake) // just bigger then, or equal? { // FIXME: Terrible Terrible... // Need to find out why this is happening... #ifdef NRK_KERNEL_TEST // Ignore if you are the idle task coming from deep sleep if(!(task_ID==NRK_IDLE_TASK_ID && _nrk_cpu_state==CPU_SLEEP)) nrk_kernel_error_add(NRK_WAKEUP_MISSED,task_ID); #endif // This is bad news, but keeps things running // +2 just in case we are on the edge of the last tick next_wake=_nrk_os_timer_get()+2; _nrk_prev_timer_val=next_wake; } if(task_ID!=NRK_IDLE_TASK_ID) _nrk_cpu_state=CPU_ACTIVE; _nrk_set_next_wakeup(next_wake); #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP // Bound Context Swap to 100us nrk_high_speed_timer_wait(start_time_stamp,CONTEXT_SWAP_TIME_BOUND); #endif nrk_stack_pointer_restore(); //nrk_int_enable(); nrk_start_high_ready_task(); }
void inline _nrk_scheduler() { int8_t task_ID; uint16_t next_wake; uint16_t start_time_stamp; nrk_int_disable(); // this should be removed... Not needed #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP _nrk_high_speed_timer_reset(); start_time_stamp = _nrk_high_speed_timer_get(); #endif _nrk_set_next_wakeup(MAX_SCHED_WAKEUP_TIME); // Set to huge number which will later get set to min next_wake = 60000; // Safety zone starts here.... #ifdef NRK_WATCHDOG nrk_watchdog_reset(); #endif #ifdef NRK_KERNEL_TEST if(_nrk_cpu_state && _nrk_os_timer_get()>nrk_max_sleep_wakeup_time) nrk_max_sleep_wakeup_time=_nrk_os_timer_get(); #endif //while(_nrk_time_trigger>0) //{ nrk_system_time.nano_secs += ((uint32_t) _nrk_prev_timer_val * NANOS_PER_TICK); nrk_system_time.nano_secs -= (nrk_system_time.nano_secs % (uint32_t) NANOS_PER_TICK); #ifdef NRK_STATS_TRACKER if(nrk_cur_task_TCB->task_ID==NRK_IDLE_TASK_ID) { if(_nrk_cpu_state==2) _nrk_stats_sleep(_nrk_prev_timer_val); _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); // Add 0 time since the preempted call before set the correct value _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, 0); } else { if(nrk_cur_task_TCB->suspend_flag==1) _nrk_stats_task_suspend(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); else _nrk_stats_task_preempted(nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); } #endif printf("==============================\r\n"); printf("ENTERING SCHEDULER @ %u \r\n", nrk_system_time.nano_secs); printf("!! Interrupted TID %u after %u.\r\n ", nrk_cur_task_TCB->task_ID, _nrk_prev_timer_val); while (nrk_system_time.nano_secs >= NANOS_PER_SEC) { nrk_system_time.nano_secs -= NANOS_PER_SEC; nrk_system_time.secs++; nrk_system_time.nano_secs -= (nrk_system_time.nano_secs % (uint32_t) NANOS_PER_TICK); } // _nrk_time_trigger--; //} if (nrk_cur_task_TCB->suspend_flag == 1 && nrk_cur_task_TCB->task_state != FINISHED) { // nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; if (nrk_cur_task_TCB->event_suspend == RSRC_EVENT_SUSPENDED) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if (nrk_cur_task_TCB->event_suspend > 0 && nrk_cur_task_TCB->nw_flag == 0) nrk_cur_task_TCB->task_state = EVENT_SUSPENDED; else if (nrk_cur_task_TCB->event_suspend > 0 && nrk_cur_task_TCB->nw_flag == 1) nrk_cur_task_TCB->task_state = SUSPENDED; else { nrk_cur_task_TCB->task_state = SUSPENDED; nrk_cur_task_TCB->event_suspend = 0; nrk_cur_task_TCB->nw_flag = 0; } nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID); } // nrk_print_readyQ(); // Update cpu used value for ended task // If the task has used its reserve, suspend task // Don't disable IdleTask which is 0 // Don't decrease cpu_remaining if reserve is 0 and hence disabled if (nrk_cur_task_TCB->cpu_reserve != 0 && nrk_cur_task_TCB->task_ID != NRK_IDLE_TASK_ID && nrk_cur_task_TCB->task_state != FINISHED) { if (nrk_cur_task_TCB->cpu_remaining < _nrk_prev_timer_val) { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif printf("< MISS > Deadline Missed for Task %u\r\n",task_ID); nrk_kernel_error_add(NRK_RESERVE_ERROR, nrk_cur_task_TCB->task_ID); nrk_cur_task_TCB->cpu_remaining = 0; } else nrk_cur_task_TCB->cpu_remaining -= _nrk_prev_timer_val; task_ID = nrk_cur_task_TCB->task_ID; if (nrk_cur_task_TCB->cpu_remaining == 0) { #ifdef NRK_STATS_TRACKER _nrk_stats_add_violation(nrk_cur_task_TCB->task_ID); #endif printf("xxxxxx >> Deadline Violated for Task %u\r\n",task_ID); nrk_kernel_error_add(NRK_RESERVE_VIOLATED, task_ID); nrk_cur_task_TCB->task_state = SUSPENDED; nrk_rem_from_readyQ(task_ID); } } // Check I/O nrk_queues to add tasks with remaining cpu back... // Add eligable tasks back to the ready Queue // At the same time find the next earliest wakeup for (task_ID = 0; task_ID < NRK_MAX_TASKS; task_ID++) { if (nrk_task_TCB[task_ID].task_ID == -1) continue; nrk_task_TCB[task_ID].suspend_flag = 0; if (nrk_task_TCB[task_ID].task_ID != NRK_IDLE_TASK_ID && nrk_task_TCB[task_ID].task_state != FINISHED) { if (nrk_task_TCB[task_ID].next_wakeup >= _nrk_prev_timer_val) nrk_task_TCB[task_ID].next_wakeup -= _nrk_prev_timer_val; else nrk_task_TCB[task_ID].next_wakeup = 0; // Do next period book keeping. // next_period needs to be set such that the period is kept consistent even if other // wait until functions are called. if (nrk_task_TCB[task_ID].next_period >= _nrk_prev_timer_val) nrk_task_TCB[task_ID].next_period -= _nrk_prev_timer_val; else { if (nrk_task_TCB[task_ID].period > _nrk_prev_timer_val) nrk_task_TCB[task_ID].next_period = nrk_task_TCB[task_ID].period - _nrk_prev_timer_val; else nrk_task_TCB[task_ID].next_period = _nrk_prev_timer_val % nrk_task_TCB[task_ID].period; } if (nrk_task_TCB[task_ID].next_period == 0) nrk_task_TCB[task_ID].next_period = nrk_task_TCB[task_ID].period; } // Look for Next Task that Might Wakeup to interrupt current task if (nrk_task_TCB[task_ID].task_state == SUSPENDED) { // printf( "Task: %d nw: %d\n",task_ID,nrk_task_TCB[task_ID].next_wakeup); // If a task needs to become READY, make it ready if (nrk_task_TCB[task_ID].next_wakeup == 0) { // printf( "Adding back %d\n",task_ID ); if (nrk_task_TCB[task_ID].event_suspend > 0 && nrk_task_TCB[task_ID].nw_flag == 1) nrk_task_TCB[task_ID].active_signal_mask =SIG(nrk_wakeup_signal); //if(nrk_task_TCB[task_ID].event_suspend==0) nrk_task_TCB[task_ID].active_signal_mask=0; nrk_task_TCB[task_ID].event_suspend = 0; nrk_task_TCB[task_ID].nw_flag = 0; nrk_task_TCB[task_ID].suspend_flag = 0; if (nrk_task_TCB[task_ID].num_periods == 1) { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; nrk_task_TCB[task_ID].task_state = READY; nrk_task_TCB[task_ID].next_wakeup = nrk_task_TCB[task_ID].next_period; nrk_task_TCB[task_ID].abs_deadline += nrk_task_TCB[task_ID].period; nrk_add_to_readyQ(task_ID); } else { nrk_task_TCB[task_ID].cpu_remaining = nrk_task_TCB[task_ID].cpu_reserve; nrk_task_TCB[task_ID].next_wakeup = (nrk_task_TCB[task_ID].period * (nrk_task_TCB[task_ID].num_periods - 1)); nrk_task_TCB[task_ID].next_period = (nrk_task_TCB[task_ID].period * (nrk_task_TCB[task_ID].num_periods - 1)); nrk_task_TCB[task_ID].num_periods = 1; } } if (nrk_task_TCB[task_ID].next_wakeup != 0 && nrk_task_TCB[task_ID].next_wakeup < next_wake) { // Find closest next_wake task next_wake = nrk_task_TCB[task_ID].next_wakeup; } printf("SQueue Contents :\r\n"); printf( "%u. TID %u, CPU Rem %u, CPU Res %u, Period %u, State %u, NW %u, NP %u, AD %u \r\n", task_ID, nrk_task_TCB[task_ID].task_ID, nrk_task_TCB[task_ID].cpu_remaining, nrk_task_TCB[task_ID].cpu_reserve, nrk_task_TCB[task_ID].period, nrk_task_TCB[task_ID].task_state, nrk_task_TCB[task_ID].next_wakeup, nrk_task_TCB[task_ID].next_period, nrk_task_TCB[task_ID].abs_deadline); } } printf(">>> next_wake is @ %u after loop .\r\n", next_wake); #ifdef NRK_STATS_TRACKER _nrk_stats_task_start(nrk_cur_task_TCB->task_ID); #endif task_ID = nrk_get_high_ready_task_ID(); nrk_high_ready_prio = nrk_task_TCB[task_ID].task_prio; nrk_high_ready_TCB = &nrk_task_TCB[task_ID]; // next_wake should hold next time when a suspended task might get run // task_ID holds the highest priority READY task ID // So nrk_task_TCB[task_ID].cpu_remaining holds the READY task's end time // Now we pick the next wakeup (either the end of the current task, or the possible resume // of a suspended task) if (task_ID != NRK_IDLE_TASK_ID) { // You are a non-Idle Task if (nrk_task_TCB[task_ID].cpu_reserve != 0 && nrk_task_TCB[task_ID].cpu_remaining < MAX_SCHED_WAKEUP_TIME) { if (next_wake > nrk_task_TCB[task_ID].cpu_remaining) next_wake = nrk_task_TCB[task_ID].cpu_remaining; } else { if (next_wake > MAX_SCHED_WAKEUP_TIME) next_wake = MAX_SCHED_WAKEUP_TIME; } } else { // This is the idle task // Make sure you wake up from the idle task a little earlier // if you would go into deep sleep... // After waking from deep sleep, the next context swap must be at least // NRK_SLEEP_WAKEUP_TIME-1 away to make sure the CPU wakes up in time. if (next_wake > NRK_SLEEP_WAKEUP_TIME) { if (next_wake - NRK_SLEEP_WAKEUP_TIME < MAX_SCHED_WAKEUP_TIME) { if (next_wake - NRK_SLEEP_WAKEUP_TIME < NRK_SLEEP_WAKEUP_TIME) { next_wake = NRK_SLEEP_WAKEUP_TIME - 1; } else { next_wake = next_wake - NRK_SLEEP_WAKEUP_TIME; } } else if (next_wake > NRK_SLEEP_WAKEUP_TIME + MAX_SCHED_WAKEUP_TIME) { next_wake = MAX_SCHED_WAKEUP_TIME; } else { next_wake = MAX_SCHED_WAKEUP_TIME - NRK_SLEEP_WAKEUP_TIME; } } } printf(">>> next_wake CHANGED TO REM_TIME,i.e. %u .\r\n", next_wake); /* // Some code to catch the case when the scheduler wakes up // from deep sleep and has to execute again before NRK_SLEEP_WAKEUP_TIME-1 if(_nrk_cpu_state==2 && next_wake<NRK_SLEEP_WAKEUP_TIME-1) { nrk_int_disable(); while(1) { nrk_spin_wait_us(60000); nrk_led_toggle(RED_LED); nrk_spin_wait_us(60000); nrk_led_toggle(GREEN_LED); printf( "crash: %d %d %d\r\n",task_ID,next_wake,_nrk_cpu_state); } }*/ //printf( "nw = %d %d %d\r\n",task_ID,_nrk_cpu_state,next_wake); nrk_cur_task_prio = nrk_high_ready_prio; nrk_cur_task_TCB = nrk_high_ready_TCB; #ifdef NRK_KERNEL_TEST if(nrk_high_ready_TCB==NULL) { nrk_kprintf( PSTR( "KERNEL TEST: BAD TCB!\r\n" )); } #endif _nrk_prev_timer_val = next_wake; if (_nrk_os_timer_get() >= next_wake) // just bigger then, or equal? { // FIXME: Terrible Terrible... // Need to find out why this is happening... #ifdef NRK_KERNEL_TEST // Ignore if you are the idle task coming from deep sleep if(!(task_ID==NRK_IDLE_TASK_ID && _nrk_cpu_state==2)) nrk_kernel_error_add(NRK_WAKEUP_MISSED,task_ID); #endif // This is bad news, but keeps things running // +2 just in case we are on the edge of the last tick next_wake = _nrk_os_timer_get() + 2; _nrk_prev_timer_val = next_wake; } if (task_ID != NRK_IDLE_TASK_ID) _nrk_cpu_state = 0; nrk_queue * printer = _head_node; int j = 0; printf("RQueue Contents :\r\n"); while (printer) { printf( "%u. TID %u, CPU Rem %u, CPU Res %u, Period %u, State %u, NW %u, NP %u, AD %u . \r\n", j, printer->task_ID, nrk_task_TCB[printer->task_ID].cpu_remaining, nrk_task_TCB[printer->task_ID].cpu_reserve, nrk_task_TCB[printer->task_ID].period, nrk_task_TCB[printer->task_ID].task_state, nrk_task_TCB[printer->task_ID].next_wakeup, nrk_task_TCB[printer->task_ID].next_period, nrk_task_TCB[printer->task_ID].abs_deadline); printer = printer->Next; j++; } _nrk_set_next_wakeup(next_wake); printf("Setting TACCR0 to (nw-1) -> %u \r\n", (next_wake - 1)); printf("Starting TID %u \r\n", task_ID); printf("EXITING SCHEDULER\r\n"); printf("==============================\r\n"); _nrk_set_next_wakeup(next_wake); #ifndef NRK_NO_BOUNDED_CONTEXT_SWAP // Bound Context Swap to 100us nrk_high_speed_timer_wait(start_time_stamp, CONTEXT_SWAP_TIME_BOUND); #endif nrk_stack_pointer_restore(); //nrk_int_enable(); nrk_start_high_ready_task(); }