wlan_mlme/
probe_sequence.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use rand::seq::SliceRandom;
6use wlan_common::tx_vector::{TxVecIdx, MAX_VALID_IDX, START_IDX};
7
8const NUM_PROBE_SEQUENCE: usize = 8;
9const SEQUENCE_LENGTH: usize = 1 + (MAX_VALID_IDX - START_IDX) as usize;
10
11pub struct ProbeEntry {
12    sequence_idx: usize,
13    probe_idx: usize,
14}
15
16impl Default for ProbeEntry {
17    fn default() -> Self {
18        Self { sequence_idx: NUM_PROBE_SEQUENCE - 1, probe_idx: SEQUENCE_LENGTH - 1 }
19    }
20}
21
22impl ProbeEntry {
23    pub fn cycle_complete(&self) -> bool {
24        self.probe_idx == SEQUENCE_LENGTH - 1
25    }
26}
27
28pub type ProbeTable = [[TxVecIdx; SEQUENCE_LENGTH]; NUM_PROBE_SEQUENCE];
29
30pub struct ProbeSequence {
31    probe_table: ProbeTable,
32}
33
34impl ProbeSequence {
35    pub fn sequential() -> Self {
36        // This unwrap is safe, since START_IDX is const and always a valid TxVecIdx.
37        let default_idx = TxVecIdx::new(START_IDX).unwrap();
38        let mut probe_table = [[default_idx; SEQUENCE_LENGTH]; NUM_PROBE_SEQUENCE];
39        for i in 0..NUM_PROBE_SEQUENCE {
40            for j in START_IDX..=MAX_VALID_IDX {
41                // The unwrap here is safe because the range is exactly the set of valid TxVecIdx.
42                probe_table[i][(j - START_IDX) as usize] = TxVecIdx::new(j).unwrap();
43            }
44        }
45        Self { probe_table }
46    }
47
48    pub fn random_new() -> Self {
49        let mut rng = rand::thread_rng();
50        // This unwrap is safe, since START_IDX is const and always a valid TxVecIdx.
51        let default_idx = TxVecIdx::new(START_IDX).unwrap();
52        let mut probe_table = [[default_idx; SEQUENCE_LENGTH]; NUM_PROBE_SEQUENCE];
53        for i in 0..NUM_PROBE_SEQUENCE {
54            for j in START_IDX..=MAX_VALID_IDX {
55                // This unwrap is safe, since the range we're iterating over is exactly the set of
56                // valid TxVecIdx values as defined by the START_IDX and MAX_VALID_IDX consts.
57                probe_table[i][(j - START_IDX) as usize] = TxVecIdx::new(j).unwrap();
58            }
59            (&mut probe_table[i][..]).shuffle(&mut rng);
60        }
61        Self { probe_table }
62    }
63
64    pub fn next(&self, entry: &mut ProbeEntry) -> TxVecIdx {
65        entry.probe_idx = (entry.probe_idx + 1) % SEQUENCE_LENGTH;
66        if entry.probe_idx == 0 {
67            entry.sequence_idx = (entry.sequence_idx + 1) % NUM_PROBE_SEQUENCE;
68        }
69        self.probe_table[entry.sequence_idx][entry.probe_idx]
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use std::collections::HashSet;
77
78    #[test]
79    fn random_new() {
80        let probe_seq = ProbeSequence::random_new();
81        // Verify that each probe sequence contains all possible TxVecIdx values.
82        for i in 0..NUM_PROBE_SEQUENCE {
83            let seq = &probe_seq.probe_table[i];
84            let mut seen_tx_idx = HashSet::new();
85            for tx_vector_idx in seq {
86                seen_tx_idx.insert(*tx_vector_idx);
87            }
88            assert_eq!(seen_tx_idx.len(), (MAX_VALID_IDX - START_IDX + 1) as usize);
89        }
90    }
91
92    #[test]
93    fn probe_entries() {
94        let probe_seq = ProbeSequence::random_new();
95        let mut entry = ProbeEntry::default();
96        let mut seen_tx_idx = HashSet::new();
97        for _ in 0..SEQUENCE_LENGTH - 1 {
98            seen_tx_idx.insert(probe_seq.next(&mut entry));
99            assert!(!entry.cycle_complete());
100        }
101        // After the last sequence value, we should see the cycle is complete.
102        seen_tx_idx.insert(probe_seq.next(&mut entry));
103        assert!(entry.cycle_complete());
104        assert_eq!(seen_tx_idx.len(), (MAX_VALID_IDX - START_IDX + 1) as usize);
105
106        // Now we should start seeing duplicate values.
107        assert!(seen_tx_idx.contains(&probe_seq.next(&mut entry)));
108        assert!(!entry.cycle_complete());
109    }
110}