Skip to main content

proto_lab/
ether_simulator.rs

1use std::{
2    collections::BTreeMap,
3    sync::{Arc, Mutex},
4};
5
6use crate::{device::IODriverSimulator, WirelessModemFake};
7
8pub struct EtherSimulator {
9    name: String,
10    devices: Arc<Mutex<Vec<WirelessModemFake>>>,
11    last_broadcasted_device: Option<String>,
12}
13
14impl EtherSimulator {
15    pub fn new(name: &str) -> Self {
16        Self {
17            name: String::from(name),
18            devices: Arc::new(Mutex::new(vec![])),
19            last_broadcasted_device: None,
20        }
21    }
22
23    /// Gets the name of the ether
24    /// ```
25    /// use proto_lab::EtherSimulator;
26    /// let mut ether = EtherSimulator::new("my_ether");
27    /// assert_eq!(ether.get_name(), "my_ether");
28    /// ```
29    pub fn get_name(&self) -> &str {
30        &self.name
31    }
32
33    /// Registers a new device (driver / modem)
34    /// ```
35    /// use proto_lab::EtherSimulator;
36    /// use proto_lab::WirelessModemFake;
37    /// use proto_lab::IODriverSimulator;
38    ///
39    /// let mut ether = EtherSimulator::new("my_ether");
40    /// ether.register_driver(WirelessModemFake::new("my_modem"));
41    /// assert_eq!(ether.get_driver("my_modem").unwrap().get_name(), "my_modem");
42    /// ```
43    pub fn register_driver(&mut self, driver: WirelessModemFake) {
44        let mut devices = self.devices.lock().expect("Fail to get lock on devices");
45        devices.push(WirelessModemFake::clone(&driver));
46    }
47
48    /// Unregisters a device
49    /// ```
50    /// use proto_lab::EtherSimulator;
51    /// use proto_lab::WirelessModemFake;
52    /// use proto_lab::IODriverSimulator;
53    ///
54    /// let mut ether = EtherSimulator::new("my_ether");
55    /// ether.register_driver(WirelessModemFake::new("my_modem"));
56    /// ether.unregister_driver("my_modem");
57    /// assert!(ether.get_driver("my_modem").is_none());
58    /// ```
59    pub fn unregister_driver(&mut self, name: &str) {
60        let mut devices = self.devices.lock().expect("Fail to get lock on devices");
61
62        loop {
63            let mut index_to_remove: Option<_> = None;
64
65            for (i, device) in devices.iter_mut().enumerate() {
66                if device.get_name() == name {
67                    index_to_remove.replace(i);
68                }
69            }
70
71            match index_to_remove {
72                Some(i) => devices.remove(i),
73                None => break,
74            };
75        }
76    }
77
78    /// Gets a registered device
79    /// ```
80    /// use proto_lab::EtherSimulator;
81    /// use proto_lab::WirelessModemFake;
82    /// use proto_lab::IODriverSimulator;
83    ///
84    /// let mut ether = EtherSimulator::new("my_ether");
85    /// assert!(ether.get_driver("my_modem").is_none());
86    /// ether.register_driver(WirelessModemFake::new("my_modem"));
87    /// assert_eq!(ether.get_driver("my_modem").unwrap().get_name(), "my_modem");
88    /// ```
89    pub fn get_driver(&self, name: &str) -> Option<WirelessModemFake> {
90        let devices = self.devices.lock().expect("Fail to get lock on devices");
91
92        for device in devices.iter() {
93            if device.get_name() == name {
94                return Some(WirelessModemFake::clone(&device));
95            }
96        }
97        None
98    }
99
100    /// Gets the broadcasted byte from broadasting devices.
101    /// Simulates data collections within the ether.
102    /// ```
103    /// use proto_lab::EtherSimulator;
104    /// use proto_lab::IODriverSimulator;
105    /// use proto_lab::WirelessModemFake;
106    ///
107    /// let mut ether = EtherSimulator::new("ether");
108    ///
109    /// let modem_1 = WirelessModemFake::new("modem_1");
110    /// let modem_2 = WirelessModemFake::new("modem_2");
111    ///
112    /// ether.register_driver(modem_1.clone());
113    /// ether.register_driver(modem_2.clone());
114    ///
115    /// modem_1.put_to_rx_pin(b'a');
116    /// modem_1.put_to_rx_pin(b'b');
117    ///
118    /// ether.start_tick();
119    /// ether.simulate();
120    /// ether.end_tick();
121    ///
122    /// assert_eq!(modem_2.get_from_tx_pin().expect("No byte"), b'a');
123    ///
124    /// ether.start_tick();
125    /// ether.simulate();
126    /// ether.end_tick();
127    ///
128    /// assert_eq!(modem_2.get_from_tx_pin().expect("No byte"), b'b');
129    /// ```
130    fn get_current_byte(&mut self) -> Option<u8> {
131        let devices = self.devices.lock().expect("Fail to get lock on devices");
132        let mut broadcasted_data: BTreeMap<String, u8> = BTreeMap::new();
133
134        // Collect all broadcasts.
135        for device in devices.iter() {
136            if let Some(byte) = device.get_from_device_network_side() {
137                broadcasted_data
138                    .entry(device.get_name().to_owned())
139                    .and_modify(|el| *el = byte)
140                    .or_insert(byte);
141            }
142        }
143
144        // Deterministic simulation of data collision
145        // In case when multiple devices are broadasting at the same time -
146        // clears out data of device which had broadcast on the previous
147        // iteration of simulation.
148        match self.last_broadcasted_device.take() {
149            None => (),
150            Some(name_of_last_broadcasted) => {
151                if broadcasted_data.len() > 1 {
152                    broadcasted_data.retain(|name, _| *name.clone() != name_of_last_broadcasted);
153                }
154            }
155        }
156
157        for (name, byte) in broadcasted_data.iter() {
158            self.last_broadcasted_device.replace(name.clone());
159            return Some(*byte);
160        }
161
162        self.last_broadcasted_device.take();
163        return None;
164    }
165
166    /// Prepares all the registered devices for starting of simulation during tick.
167    pub fn start_tick(&self) {
168        let devices = self.devices.lock().expect("Fail to get lock on devices");
169        for device in devices.iter() {
170            device.start_tick();
171        }
172    }
173
174    /// Prepares all the registered devices for ending of simulation during tick.
175    pub fn end_tick(&self) {
176        let devices = self.devices.lock().expect("Fail to get lock on devices");
177        for device in devices.iter() {
178            device.end_tick();
179        }
180    }
181
182    /// This operation shall be called only during tick is active.
183    pub fn simulate(&mut self) {
184        let current_byte = self.get_current_byte();
185
186        let devices = self.devices.lock().expect("Fail to get lock on devices");
187
188        if let Some(current_byte) = current_byte {
189            for device in devices.iter() {
190                device.put_to_device_network_side(current_byte);
191            }
192        }
193    }
194
195    /// Clones itself.
196    /// Also makes all internal data shared to be able to use from multiple threads.
197    /// ```
198    /// use proto_lab::EtherSimulator;
199    /// use proto_lab::WirelessModemFake;
200    /// use proto_lab::IODriverSimulator;
201    ///
202    /// let mut ether = EtherSimulator::new("my_ether");
203    /// let ether_clone = ether.clone();
204    ///
205    /// assert_eq!(ether.get_name(), ether_clone.get_name());
206    pub fn clone(&self) -> EtherSimulator {
207        EtherSimulator {
208            name: String::from(&self.name),
209            devices: Arc::clone(&self.devices),
210            last_broadcasted_device: self.last_broadcasted_device.clone(),
211        }
212    }
213}
214
215#[cfg(test)]
216mod test {
217    #[test]
218    fn test_of_collisions() {
219        use super::EtherSimulator;
220        use super::IODriverSimulator;
221        use super::WirelessModemFake;
222
223        let mut ether = EtherSimulator::new("ether");
224
225        let sending_modem_1 = WirelessModemFake::new("modem_1");
226        let sending_modem_2 = WirelessModemFake::new("modem_2");
227        let receiving_modem = WirelessModemFake::new("modem_3");
228
229        ether.register_driver(sending_modem_1.clone());
230        ether.register_driver(sending_modem_2.clone());
231        ether.register_driver(receiving_modem.clone());
232
233        let bytes_from_senging_modem_1 = vec![b'1', b'2', b'3', b'4', b'5'];
234        let bytes_from_sending_modem_2 = vec![b'6', b'7', b'8', b'9', b'0'];
235
236        for b in bytes_from_senging_modem_1.iter() {
237            sending_modem_1.put_to_rx_pin(*b);
238        }
239        for b in bytes_from_sending_modem_2.iter() {
240            sending_modem_2.put_to_rx_pin(*b);
241        }
242
243        let mut received_vec: Vec<u8> = vec![];
244        let expected_vec: Vec<u8> = vec![b'1', b'7', b'3', b'9', b'5'];
245
246        ether.start_tick();
247        ether.simulate();
248        ether.end_tick();
249        while let Some(got_byte) = receiving_modem.get_from_tx_pin() {
250            received_vec.push(got_byte);
251            ether.start_tick();
252            ether.simulate();
253            ether.end_tick();
254        }
255
256        assert_eq!(received_vec, expected_vec);
257    }
258}