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}