/*---------------------------------------------------------------------------*/ void rf1a_cb_tx_ended(rtimer_clock_t *timestamp) { GLOSSY_TX_STOPPED; g.t_tx_stop = *timestamp; if(WITH_SYNC()) { /* store the relay counter of this last transmission */ g.relay_cnt_last_tx = g.header.relay_cnt; if(g.t_ref_updated == 0) { /* t_ref has not been updated yet: update it */ update_t_ref(g.t_tx_start, g.header.relay_cnt); } if((g.relay_cnt_last_tx == g.relay_cnt_last_rx + 1) && (g.n_rx > 0)) { /* this transmission immediately followed a reception: measure T_slot */ add_T_slot_measurement(g.t_tx_start - g.t_rx_start + NS_TO_RTIMER_HF(TAU1)); } } /* increment the transmission counter */ g.n_tx++; if((g.n_tx == GET_N_TX_MAX(g.header.pkt_type)) && (GET_N_TX_MAX(g.header.pkt_type) > 1 || (!IS_INITIATOR()))) { /* we have reached N_tx_max and either N_tx_max > 1 or we are a receiver: * stop Glossy */ glossy_stop(); } else { #if GLOSSY_CONF_RETRANSMISSION_TIMEOUT if((IS_INITIATOR()) && (g.n_rx == 0)) { /* we are the initiator and we still have not received any packet: * schedule the timeout */ schedule_timeout(); } #endif /* GLOSSY_CONF_RETRANSMISSION_TIMEOUT */ } }
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); }
/*---------------------------------------------------------------------------*/ void rf1a_cb_rx_ended(rtimer_clock_t *timestamp, uint8_t *pkt, uint8_t pkt_len) { GLOSSY_RX_STOPPED; /* enable timer overflow / update interrupt (since we are in an interrupt * context here, the timer interrupts will only be handled after this ISR) * Note that the RX/TX switching is constant regardless of the runtime of * this ISR; it is only necessary to write to the TX queue before the * preamble has been sent by the radio module */ rtimer_update_enable(1); LWB_INT_ENABLE; g.t_rx_stop = *timestamp; #if GLOSSY_CONF_COLLECT_STATS g.stats.pkt_cnt_crcok++; #endif /* GLOSSY_CONF_COLLECT_STATS */ /* we have received a packet and the CRC is correct, now check the header */ if((process_glossy_header(pkt, pkt_len, 1) == GLOSSY_SUCCESS)) { /* we received a correct packet, and the header has been stored into * g.header */ uint8_t *payload = pkt + GLOSSY_HEADER_LEN(g.header.pkt_type); /* store the relay counter corresponding to the first reception */ #if GLOSSY_CONF_COLLECT_STATS uint8_t relay_cnt = g.header.relay_cnt; #endif /* GLOSSY_CONF_COLLECT_STATS */ /* increment the relay counter */ g.header.relay_cnt++; if((GET_N_TX_MAX(g.header.pkt_type) == 0) || (g.n_tx < GET_N_TX_MAX(g.header.pkt_type))) { /* if n_tx_max is either unknown or not yet reached, transmit the * packet */ rf1a_write_to_tx_fifo((uint8_t *)&g.header, GLOSSY_HEADER_LEN(g.header.pkt_type), payload, g.payload_len); } else { /* otherwise, stop Glossy */ glossy_stop(); } #if GLOSSY_CONF_COLLECT_STATS /* stats */ if(WITH_RELAY_CNT()) { /* the relay counter is part of the header */ if(g.n_rx == 0) { g.stats.last_flood_relay_cnt = relay_cnt; } /* get the RSSI value */ if(g.n_rx < 3) { g.stats.last_flood_rssi[g.n_rx] = rf1a_get_last_packet_rssi(); g.stats.last_flood_hops[g.n_rx] = g.header.relay_cnt - 1; } } g.stats.last_flood_rssi_sum += rf1a_get_last_packet_rssi(); #endif /* GLOSSY_CONF_COLLECT_STATS */ /* increment the reception counter */ g.n_rx++; GLOSSY_FIRST_RX; if((!IS_INITIATOR()) && (g.n_rx == 1)) { /* we are a receiver and this was our first packet reception: */ /* store the payload for the application */ memcpy((uint8_t *)g.payload, payload, g.payload_len); } if(WITH_SYNC()) { /* store the relay counter of this last reception */ g.relay_cnt_last_rx = g.header.relay_cnt - 1; if(g.t_ref_updated == 0) { /* t_ref has not been updated yet: update it */ update_t_ref(g.t_rx_start - NS_TO_RTIMER_HF(TAU1), g.header.relay_cnt - 1); } if((g.relay_cnt_last_rx == g.relay_cnt_last_tx + 1) && (g.n_tx > 0)) { /* this reception immediately followed a transmission: measure * T_slot */ add_T_slot_measurement(g.t_rx_start - g.t_tx_start - NS_TO_RTIMER_HF(TAU1)); } } /* notify about the successful reception */ DEBUG_PRINT_VERBOSE("Glossy RX completed. Received a %u-byte packet with " "initiator %u.", pkt_len, g.header.initiator_id); } else { #if GLOSSY_CONF_COLLECT_STATS if(!g.stats.already_counted) { g.stats.last_flood_n_rx_fail++; g.stats.already_counted = 1; } #endif /* GLOSSY_CONF_COLLECT_STATS */ /* some fields in the header were not correct: discard it */ rf1a_cb_rx_failed(timestamp); } }
/*---------------------------- Glossy interface -----------------------------*/ void glossy_start(uint16_t initiator_id, uint8_t *payload, uint8_t payload_len, uint8_t n_tx_max, glossy_sync_t sync, glossy_rf_cal_t rf_cal) { GLOSSY_STARTED; DEBUG_PRINT_VERBOSE("Glossy started: in=%u, pl=%u, n=%u, s=%u", initiator_id, payload_len, n_tx_max, sync); /* disable undesired interrupts */ GLOSSY_DISABLE_INTERRUPTS; /* reset the data structure */ g.active = 1; g.payload = payload; g.payload_len = payload_len; g.n_rx = 0; g.n_tx = 0; g.relay_cnt_last_rx = 0; g.relay_cnt_last_tx = 0; g.t_ref_updated = 0; g.T_slot_sum = 0; g.n_T_slot = 0; #if GLOSSY_CONF_COLLECT_STATS g.stats.last_flood_n_rx_started = 0; g.stats.last_flood_n_rx_fail = 0; g.stats.already_counted = 0; g.stats.last_flood_rssi_sum = 0; g.stats.last_flood_rssi_noise = 0; g.stats.last_flood_t_to_rx = 0; g.stats.last_flood_duration = rtimer_now_hf(); if(WITH_RELAY_CNT()) { /* clear last_flood_rssi and last_flood_hops in one memset call */ memset(g.stats.last_flood_rssi, 0, 6); } #endif /* GLOSSY_CONF_COLLECT_STATS */ /* prepare the Glossy header, with the information known so far */ g.header.initiator_id = initiator_id; SET_PKT_TYPE(g.header.pkt_type, sync, n_tx_max); g.header.relay_cnt = 0; /* automatically switch to TX at the end of RX */ rf1a_set_rxoff_mode(RF1A_OFF_MODE_TX); /* automatically switch to RX at the end of TX */ rf1a_set_txoff_mode(RF1A_OFF_MODE_RX); /* do not calibrate automatically */ rf1a_set_calibration_mode(RF1A_CALIBRATION_MODE_MANUAL); /* re-configure patable (config is lost when radio was in sleep mode) */ rf1a_set_tx_power(RF_CONF_TX_POWER); if(rf_cal == GLOSSY_WITH_RF_CAL) { /* if instructed so, perform a manual calibration */ rf1a_manual_calibration(); } rf1a_set_header_len_rx(GLOSSY_HEADER_LEN(g.header.pkt_type)); rf1a_go_to_idle(); if(IS_INITIATOR()) { /* Glossy initiator */ if(GET_SYNC(g.header.pkt_type) == GLOSSY_UNKNOWN_SYNC || (g.payload_len + GLOSSY_HEADER_LEN(g.header.pkt_type) + 1) > RF_CONF_MAX_PKT_LEN) { /* the initiator must know whether there will be synchronization or * not and the packet length may not exceed the max. length */ DEBUG_PRINT_ERROR("invalid parameters, Glossy stopped"); glossy_stop(); } else { /* start the first transmission */ g.t_timeout = rtimer_now_hf() + TIMEOUT_EXTRA_TICKS; rf1a_start_tx(); rf1a_write_to_tx_fifo((uint8_t *)&g.header, GLOSSY_HEADER_LEN(g.header.pkt_type), (uint8_t *)g.payload, g.payload_len); g.relay_cnt_timeout = 0; } } else { /* Glossy receiver */ rf1a_start_rx(); #if GLOSSY_CONF_COLLECT_STATS /* measure the channel noise (but only if waiting for the schedule */ if(sync == GLOSSY_WITH_SYNC) { /* wait after entering RX mode before reading RSSI (see swra114d.pdf) */ __delay_cycles(MCLK_SPEED / 3000); /* wait 0.33 ms */ g.stats.last_flood_rssi_noise = rf1a_get_rssi(); /* RSSI of the noise floor */ } #endif /* GLOSSY_CONF_COLLECT_STATS */ } /* note: RF_RDY bit must be cleared by the radio core before entering LPM * after a transition from idle to RX or TX. Either poll the status of the * radio core (SNOP strobe) or read the GDOx signal assigned to RF_RDY */ while(RF1AIN & BIT0); /* check GDO0 signal (added by rdaforno) */ }