static int update_shortterm(void) { if (shortterm_priority_queue_root.first == NULL) { /* there is no vtimer to schedule, queue is empty */ DEBUG("update_shortterm: shortterm_priority_queue_root.next == NULL - dont know what to do here\n"); return 0; } if (hwtimer_id != -1) { /* there is a running hwtimer for us */ if (hwtimer_next_absolute != shortterm_priority_queue_root.first->priority) { /* the next timer in the vtimer queue is not the next hwtimer */ /* we have to remove the running hwtimer (and schedule a new one) */ hwtimer_remove(hwtimer_id); } else { /* the next vtimer is the next hwtimer, nothing to do */ return 0; } } /* short term part of the next vtimer */ hwtimer_next_absolute = shortterm_priority_queue_root.first->priority; uint32_t next = hwtimer_next_absolute; /* current short term time */ uint32_t now = HWTIMER_TICKS_TO_US(hwtimer_now()); /* make sure the longterm_tick_timer does not get truncated */ if (node_get_timer(shortterm_priority_queue_root.first)->action != vtimer_callback_tick) { /* the next vtimer to schedule is the long term tick */ /* it has a shortterm offset of longterm_tick_start */ next += longterm_tick_start; } if((next - HWTIMER_TICKS_TO_US(VTIMER_THRESHOLD) - now) > MICROSECONDS_PER_TICK ) { DEBUG("truncating next (next - HWTIMER_TICKS_TO_US(VTIMER_THRESHOLD) - now): %lu\n", (next - HWTIMER_TICKS_TO_US(VTIMER_THRESHOLD) - now)); next = now + HWTIMER_TICKS_TO_US(VTIMER_BACKOFF); } DEBUG("update_shortterm: Set hwtimer to %" PRIu32 " (now=%lu)\n", next, HWTIMER_TICKS_TO_US(hwtimer_now())); hwtimer_id = hwtimer_set_absolute(HWTIMER_TICKS(next), vtimer_callback, NULL); return 0; }
static int update_shortterm() { if (hwtimer_id != -1) { if (hwtimer_next_absolute != shortterm_queue_root.next->priority) { hwtimer_remove(hwtimer_id); } else { return 0; } } hwtimer_next_absolute = shortterm_queue_root.next->priority; unsigned int next = hwtimer_next_absolute + longterm_tick_start; unsigned int now = hwtimer_now(); if((next - VTIMER_THRESHOLD - now) > MICROSECONDS_PER_TICK ) { next = now + VTIMER_BACKOFF; } hwtimer_id = hwtimer_set_absolute(next, vtimer_callback, NULL); DEBUG("update_shortterm: Set hwtimer to %lu (now=%lu)\n", hwtimer_next_absolute + longterm_tick_start, hwtimer_now()); return 0; }
/*---------------------------------------------------------------------------*/ int cc1100_send_csmaca(radio_address_t address, protocol_t protocol, int priority, char *payload, radio_packet_length_t payload_len) { uint16_t min_window_size; uint16_t max_window_size; uint16_t difs; uint16_t slottime; switch(priority) { case PRIORITY_ALARM: min_window_size = PRIO_ALARM_MIN_WINDOW_SIZE; max_window_size = PRIO_ALARM_MAX_WINDOW_SIZE; difs = PRIO_ALARM_DIFS; slottime = PRIO_ALARM_SLOTTIME; break; case PRIORITY_WARNING: min_window_size = PRIO_WARN_MIN_WINDOW_SIZE; max_window_size = PRIO_WARN_MAX_WINDOW_SIZE; difs = PRIO_WARN_DIFS; slottime = PRIO_WARN_SLOTTIME; break; default: min_window_size = PRIO_DATA_MIN_WINDOW_SIZE; max_window_size = PRIO_DATA_MAX_WINDOW_SIZE; difs = PRIO_DATA_DIFS; slottime = PRIO_DATA_SLOTTIME; } /* Calculate collisions per second */ if (collision_state == COLLISION_STATE_INITIAL) { vtimer_now(&collision_measurement_start); collision_count = 0; collisions_per_sec = 0; collision_state = COLLISION_STATE_MEASURE; } else if (collision_state == COLLISION_STATE_MEASURE) { timex_t now; vtimer_now(&now); timex_t timespan = timex_sub(now, collision_measurement_start); if (timex_cmp(timespan, timex_set(1, 0)) > 0) { collisions_per_sec = (collision_count * 1000000) / (double) timex_uint64(timespan); if (collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) { timex_t now; vtimer_now(&now); collision_measurement_start = now; collision_state = COLLISION_STATE_KEEP; } else if (collisions_per_sec > 2.2) { timex_t now; vtimer_now(&now); collision_measurement_start = now; collision_state = COLLISION_STATE_KEEP; } else { collision_state = COLLISION_STATE_INITIAL; } } } else if (collision_state == COLLISION_STATE_KEEP) { timex_t now; vtimer_now(&now); timex_t timespan = timex_sub(now, collision_measurement_start); if (timex_cmp(timespan, timex_set(5, 0)) > 0) { collision_state = COLLISION_STATE_INITIAL; } } /* Adjust initial window size according to collision rate */ if (collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) { min_window_size *= 2; } else if (collisions_per_sec > 2.2) { min_window_size *= 4; } uint16_t windowSize = min_window_size; /* Start with window size of PRIO_XXX_MIN_WINDOW_SIZE */ uint16_t backoff = 0; /* Backoff between 1 and windowSize */ uint32_t total; /* Holds the total wait time before send try */ uint32_t cs_timeout; /* Current carrier sense timeout value */ if (protocol == 0) { return RADIO_INVALID_PARAM; /* Not allowed, protocol id must be greater zero */ } cc1100_phy_mutex_lock(); /* Lock radio for exclusive access */ /* Get carrier sense timeout based on overall error rate till now */ send_csmaca_calls++; int fail_percentage = (send_csmaca_calls_cs_timeout * 100) / send_csmaca_calls; if (fail_percentage == 0) { fail_percentage = 1; } cs_timeout = CARRIER_SENSE_TIMEOUT / fail_percentage; if (cs_timeout < CARRIER_SENSE_TIMEOUT_MIN) { cs_timeout = CARRIER_SENSE_TIMEOUT_MIN; } cc1100_cs_init(); /* Initialize carrier sensing */ window: if (backoff != 0) { goto cycle; /* If backoff was 0 */ } windowSize *= 2; /* ...double the current window size */ if (windowSize > max_window_size) { windowSize = max_window_size; /* This is the maximum size allowed */ } backoff = rand() % windowSize; /* ...and choose new backoff */ backoff += (uint16_t) 1; cycle: cs_timeout_flag = 0; /* Carrier sense timeout flag */ cs_hwtimer_id = hwtimer_set(cs_timeout, /* Set hwtimer to set CS timeout flag */ cs_timeout_cb, NULL); while (cc1100_cs_read()) { /* Wait until air is free */ if (cs_timeout_flag) { send_csmaca_calls_cs_timeout++; #ifndef CSMACA_MAC_AGGRESSIVE_MODE cc1100_phy_mutex_unlock(); cc1100_go_after_tx(); /* Go from RX to default mode */ return RADIO_CS_TIMEOUT; /* Return immediately */ #endif #ifdef CSMACA_MAC_AGGRESSIVE_MODE goto send; /* Send anyway */ #endif } } hwtimer_remove(cs_hwtimer_id); /* Remove hwtimer */ cc1100_cs_write_cca(1); /* Air is free now */ cc1100_cs_set_enabled(true); if (cc1100_cs_read()) { goto window; /* GDO0 triggers on rising edge, so */ } /* test once after interrupt is enabled */ if (backoff > 0) { backoff--; /* Decrement backoff counter */ } total = slottime; /* Calculate total wait time */ total *= (uint32_t)backoff; /* Slot vector set */ total += difs; /* ...and standard DIFS wait time */ cs_timeout_flag = 0; /* Carrier sense timeout flag */ cs_hwtimer_id = hwtimer_set(total, /* Set hwtimer to set CS timeout flag */ cs_timeout_cb, NULL); while (!cs_timeout_flag || !cc1100_cs_read_cca()) { /* Wait until timeout is finished */ if (cc1100_cs_read_cca() == 0) { /* Is the air still free? */ hwtimer_remove(cs_hwtimer_id); goto window; /* No. Go back to new wait period. */ } } cc1100_cs_set_enabled(false); #ifdef CSMACA_MAC_AGGRESSIVE_MODE send: #endif int res = cc1100_send(address, protocol, priority, payload, payload_len); if (res < 0) { collision_count++; } return res; }
/*---------------------------------------------------------------------------*/ int cc1100_send_csmaca(radio_address_t address, protocol_t protocol, int priority, char *payload, int payload_len) { uint16_t min_window_size; uint16_t max_window_size; uint16_t difs; uint16_t slottime; switch (priority) { case PRIORITY_ALARM: min_window_size = PRIO_ALARM_MIN_WINDOW_SIZE; max_window_size = PRIO_ALARM_MAX_WINDOW_SIZE; difs = PRIO_ALARM_DIFS; slottime = PRIO_ALARM_SLOTTIME; break; case PRIORITY_WARNING: min_window_size = PRIO_WARN_MIN_WINDOW_SIZE; max_window_size = PRIO_WARN_MAX_WINDOW_SIZE; difs = PRIO_WARN_DIFS; slottime = PRIO_WARN_SLOTTIME; break; default: min_window_size = PRIO_DATA_MIN_WINDOW_SIZE; max_window_size = PRIO_DATA_MAX_WINDOW_SIZE; difs = PRIO_DATA_DIFS; slottime = PRIO_DATA_SLOTTIME; } // Calculate collisions per second if (collision_state == COLLISION_STATE_INITIAL) { timex_t now = vtimer_now(); collision_measurement_start = now.microseconds; collision_count = 0; collisions_per_sec = 0; collision_state = COLLISION_STATE_MEASURE; } else if (collision_state == COLLISION_STATE_MEASURE) { timex_t now = vtimer_now(); uint64_t timespan = now.microseconds - collision_measurement_start; if (timespan > 1000000) { collisions_per_sec = (collision_count * 1000000) / (double) timespan; if (collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) { timex_t now = vtimer_now(); collision_measurement_start = now.microseconds; collision_state = COLLISION_STATE_KEEP; } else if (collisions_per_sec > 2.2) { timex_t now = vtimer_now(); collision_measurement_start = now.microseconds; collision_state = COLLISION_STATE_KEEP; } else { collision_state = COLLISION_STATE_INITIAL; } } } else if (collision_state == COLLISION_STATE_KEEP) { timex_t now = vtimer_now(); uint64_t timespan = now.microseconds - collision_measurement_start; if (timespan > 5000000) { collision_state = COLLISION_STATE_INITIAL; } } // Adjust initial window size according to collision rate if (collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) { min_window_size *= 2; } else if (collisions_per_sec > 2.2) { min_window_size *= 4; } uint16_t windowSize = min_window_size; // Start with window size of PRIO_XXX_MIN_WINDOW_SIZE uint16_t backoff = 0; // Backoff between 1 and windowSize uint32_t total; // Holds the total wait time before send try uint32_t cs_timeout; // Current carrier sense timeout value if (protocol == 0) { return RADIO_INVALID_PARAM; // Not allowed, protocol id must be greater zero } cc1100_phy_mutex_lock(); // Lock radio for exclusive access // Get carrier sense timeout based on overall error rate till now send_csmaca_calls++; int fail_percentage = (send_csmaca_calls_cs_timeout * 100) / send_csmaca_calls; if (fail_percentage == 0) fail_percentage = 1; cs_timeout = CARRIER_SENSE_TIMEOUT / fail_percentage; if (cs_timeout < CARRIER_SENSE_TIMEOUT_MIN) cs_timeout = CARRIER_SENSE_TIMEOUT_MIN; cc1100_cs_init(); // Initialize carrier sensing window: if (backoff != 0) goto cycle; // If backoff was 0 windowSize *= 2; // ...double the current window size if (windowSize > max_window_size) { windowSize = max_window_size; // This is the maximum size allowed } backoff = rand() % windowSize; // ...and choose new backoff if (backoff < 0) backoff *= -1; backoff += (uint16_t) 1; cycle: cs_timeout_flag = 0; // Carrier sense timeout flag cs_hwtimer_id = hwtimer_set(cs_timeout, // Set hwtimer to set CS timeout flag cs_timeout_cb, NULL); while (cc1100_cs_read()) // Wait until air is free { if (cs_timeout_flag) { send_csmaca_calls_cs_timeout++; #ifndef CSMACA_MAC_AGGRESSIVE_MODE cc1100_phy_mutex_unlock(); cc1100_go_after_tx(); // Go from RX to default mode return RADIO_CS_TIMEOUT; // Return immediately #endif #ifdef CSMACA_MAC_AGGRESSIVE_MODE goto send; // Send anyway #endif } } hwtimer_remove(cs_hwtimer_id); // Remove hwtimer cc1100_cs_write_cca(1); // Air is free now cc1100_cs_set_enabled(true); if (cc1100_cs_read()) goto window; // GDO0 triggers on rising edge, so // test once after interrupt is enabled if (backoff > 0) backoff--; // Decrement backoff counter total = slottime; // Calculate total wait time total *= (uint32_t)backoff; // Slot vector set total += difs; // ...and standard DIFS wait time cs_timeout_flag = 0; // Carrier sense timeout flag cs_hwtimer_id = hwtimer_set(total, // Set hwtimer to set CS timeout flag cs_timeout_cb, NULL); while (!cs_timeout_flag || !cc1100_cs_read_cca()) // Wait until timeout is finished { if (cc1100_cs_read_cca() == 0) // Is the air still free? { hwtimer_remove(cs_hwtimer_id); goto window; // No. Go back to new wait period. } } cc1100_cs_set_enabled(false); #ifdef CSMACA_MAC_AGGRESSIVE_MODE send: #endif int res = cc1100_send(address, protocol, priority, payload, payload_len); if (res < 0) { collision_count++; } return res; }