use core::ops::RangeInclusive;
use esp_hal::rng::Rng;
use macro_bits::bit;
pub struct EdcaContentionState {
contention_window_exponent_range: RangeInclusive<u8>,
current_cw: u32,
short_retry_count: u8,
long_retry_count: u8,
}
impl EdcaContentionState {
pub fn new(contention_window_exponent_range: RangeInclusive<u8>) -> Option<Self> {
if contention_window_exponent_range.is_empty() {
return None;
}
Some(Self {
current_cw: bit!(*contention_window_exponent_range.start() as usize) - 1,
contention_window_exponent_range,
short_retry_count: 0,
long_retry_count: 0,
})
}
fn advance_contention_window(&mut self) {
self.current_cw <<= 1;
self.current_cw += 1;
self.current_cw = self
.current_cw
.max((1 << *self.contention_window_exponent_range.end() as usize) - 1);
}
pub fn increment_src(&mut self) {
self.short_retry_count += 1;
self.advance_contention_window();
}
pub fn reset_src(&mut self) {
self.short_retry_count = 0;
}
pub fn increment_lrc(&mut self) {
self.long_retry_count += 1;
self.advance_contention_window();
}
pub fn random_backoff_slot_count(&self) -> usize {
(Rng::new().random() & self.current_cw) as usize
}
}