char glossy_scheduler(struct rtimer *t, void *ptr) { PT_BEGIN(&pt); if (IS_INITIATOR()) { // Glossy initiator. while (1) { printf("[SCHEDULER]: Get Data from queue\n"); // Increment sequence number. glossy_data.seq_no++; // Glossy phase. leds_on(LEDS_GREEN); rtimer_clock_t t_stop = RTIMER_TIME(t) + GLOSSY_DURATION; // Start Glossy. glossy_start((uint8_t *)&glossy_data, DATA_LEN, GLOSSY_INITIATOR, GLOSSY_SYNC, N_TX, APPLICATION_HEADER, t_stop, (rtimer_callback_t)glossy_scheduler, t, ptr); // Store time at which Glossy has started. t_start = RTIMER_TIME(t); // Yield the protothread. It will be resumed when Glossy terminates. PT_YIELD(&pt); // Off phase. leds_off(LEDS_GREEN); // Stop Glossy. glossy_stop(); if (!GLOSSY_IS_BOOTSTRAPPING()) { // Glossy has already successfully bootstrapped. if (!GLOSSY_IS_SYNCED()) { // The reference time was not updated: increment reference time by GLOSSY_PERIOD. set_t_ref_l(GLOSSY_REFERENCE_TIME + GLOSSY_PERIOD); set_t_ref_l_updated(1); } } // Schedule begin of next Glossy phase based on GLOSSY_PERIOD. rtimer_set(t, t_start + GLOSSY_PERIOD, 1, (rtimer_callback_t)glossy_scheduler, ptr); // Estimate the clock skew over the last period. estimate_period_skew(); // Poll the process that prints statistics (will be activated later by Contiki). process_poll(&glossy_print_stats_process); // Yield the protothread. PT_YIELD(&pt); } } else { // Glossy receiver. while (1) { // Glossy phase. leds_on(LEDS_GREEN); rtimer_clock_t t_stop; if (GLOSSY_IS_BOOTSTRAPPING()) { // Glossy is still bootstrapping: // Schedule end of Glossy phase based on GLOSSY_INIT_DURATION. t_stop = RTIMER_TIME(t) + GLOSSY_INIT_DURATION; } else { // Glossy has already successfully bootstrapped: // Schedule end of Glossy phase based on GLOSSY_DURATION. t_stop = RTIMER_TIME(t) + GLOSSY_DURATION; } // Start Glossy. glossy_start((uint8_t *)&glossy_data, DATA_LEN, GLOSSY_RECEIVER, GLOSSY_SYNC, N_TX, APPLICATION_HEADER, t_stop, (rtimer_callback_t)glossy_scheduler, t, ptr); // Yield the protothread. It will be resumed when Glossy terminates. PT_YIELD(&pt); // Off phase. leds_off(LEDS_GREEN); // Stop Glossy. glossy_stop(); if (GLOSSY_IS_BOOTSTRAPPING()) { // Glossy is still bootstrapping. if (!GLOSSY_IS_SYNCED()) { // The reference time was not updated: reset skew_estimated to zero. skew_estimated = 0; } } else { // Glossy has already successfully bootstrapped. if (!GLOSSY_IS_SYNCED()) { // The reference time was not updated: // increment reference time by GLOSSY_PERIOD + period_skew. set_t_ref_l(GLOSSY_REFERENCE_TIME + GLOSSY_PERIOD + period_skew); set_t_ref_l_updated(1); // Increment sync_missed. sync_missed++; } else { // The reference time was not updated: reset sync_missed to zero. sync_missed = 0; } } // Estimate the clock skew over the last period. estimate_period_skew(); if (GLOSSY_IS_BOOTSTRAPPING()) { // Glossy is still bootstrapping. if (skew_estimated == 0) { // The reference time was not updated: // Schedule begin of next Glossy phase based on last begin and GLOSSY_INIT_PERIOD. rtimer_set(t, RTIMER_TIME(t) + GLOSSY_INIT_PERIOD, 1, (rtimer_callback_t)glossy_scheduler, ptr); } else { // The reference time was updated: // Schedule begin of next Glossy phase based on reference time and GLOSSY_INIT_PERIOD. rtimer_set(t, GLOSSY_REFERENCE_TIME + GLOSSY_PERIOD - GLOSSY_INIT_GUARD_TIME, 1, (rtimer_callback_t)glossy_scheduler, ptr); } } else { // Glossy has already successfully bootstrapped: // Schedule begin of next Glossy phase based on reference time and GLOSSY_PERIOD. rtimer_set(t, GLOSSY_REFERENCE_TIME + GLOSSY_PERIOD + period_skew - GLOSSY_GUARD_TIME * (1 + sync_missed), 1, (rtimer_callback_t)glossy_scheduler, ptr); } // Poll the process that prints statistics (will be activated later by Contiki). process_poll(&glossy_print_stats_process); // Yield the protothread. PT_YIELD(&pt); } } PT_END(&pt); }
//-------------------------------------------------------------------------------------------------- static inline void compute_new_sync_state() { if (GLOSSY_IS_SYNCED()) { // Reference time of Glossy is updated. LWB_STATS_SYNC(n_synced)++; if ((lwb_context.sync_state == LWB_SYNC_STATE_QUASI_SYNCED || lwb_context.sync_state == LWB_SYNC_STATE_SYNCED) && (CURRENT_SCHEDULE_INFO().time < OLD_SCHEDULE_INFO().time)) { // 16-bit overflow UI32_SET_HIGH(lwb_context.time, UI32_GET_HIGH(lwb_context.time) + 1); } UI32_SET_LOW(lwb_context.time, CURRENT_SCHEDULE_INFO().time); switch (lwb_context.sync_state) { case LWB_SYNC_STATE_BOOTSTRAP: { lwb_context.sync_state = LWB_SYNC_STATE_QUASI_SYNCED; lwb_context.t_sync_guard = T_GUARD_3; lwb_context.t_last_sync_ref = GLOSSY_T_REF; lwb_context.t_sync_ref = GLOSSY_T_REF; } break; default: { // If Glossy's reference time is updated while in any other states, // we consider LWB is synchronized. lwb_context.sync_state = LWB_SYNC_STATE_SYNCED; lwb_context.t_sync_guard = T_GUARD; lwb_context.t_sync_ref = GLOSSY_T_REF; lwb_estimate_skew(); } break; } } else { // Reference time of Glossy is not updated. LWB_STATS_SYNC(n_sync_missed)++; switch (lwb_context.sync_state) { case LWB_SYNC_STATE_SYNCED: { lwb_context.sync_state = LWB_SYNC_STATE_UNSYNCED_1; lwb_context.t_sync_guard = T_GUARD_1; } break; case LWB_SYNC_STATE_UNSYNCED_1: { lwb_context.sync_state = LWB_SYNC_STATE_UNSYNCED_2; lwb_context.t_sync_guard = T_GUARD_2; } break; case LWB_SYNC_STATE_UNSYNCED_2: { lwb_context.sync_state = LWB_SYNC_STATE_UNSYNCED_3; lwb_context.t_sync_guard = T_GUARD_3; } break; case LWB_SYNC_STATE_UNSYNCED_3: case LWB_SYNC_STATE_QUASI_SYNCED: { // go back to bootstrap lwb_context.sync_state = LWB_SYNC_STATE_BOOTSTRAP; lwb_context.t_sync_guard = T_GUARD_3; lwb_context.skew = 0; } break; default: break; } if (lwb_context.sync_state != LWB_SYNC_STATE_BOOTSTRAP) { // We are not bootstrapping. So, we calculate the new schedule information based on the old one. // set new time based on old time if (OLD_SCHEDULE_INFO().round_period == 1) { CURRENT_SCHEDULE_INFO().time = OLD_SCHEDULE_INFO().time + 1; } else { /// @todo Find why sched_info.round_period - 1 is used CURRENT_SCHEDULE_INFO().time = OLD_SCHEDULE_INFO().time + OLD_SCHEDULE_INFO().round_period; } CURRENT_SCHEDULE_INFO().round_period = OLD_SCHEDULE_INFO().round_period; // compute new reference time // Why "ui16_t_diff % 2" is used is explained under lwb_estimate_skew(). uint16_t ui16_t_diff = CURRENT_SCHEDULE_INFO().time - OLD_SCHEDULE_INFO().time; uint16_t new_t_ref = lwb_context.t_last_sync_ref + ((int32_t)ui16_t_diff * lwb_context.skew / (int32_t)64) + ((uint32_t)RTIMER_SECOND * (ui16_t_diff % 2)); set_t_ref_l(new_t_ref); lwb_context.t_last_sync_ref = new_t_ref; lwb_context.t_sync_ref = new_t_ref; } else { // The new state is bootstrap. We do not calculate things based on old information. } } }