Browse Source

base-station: Restructure radio code.

Mathias Gottschlag 5 years ago
parent
commit
a93ab30bb9

+ 65
- 0
base-station/software/Cargo.lock View File

@@ -31,6 +31,7 @@ dependencies = [
31 31
  "log",
32 32
  "mqtt-protocol",
33 33
  "protocol",
34
+ "rand",
34 35
  "thiserror",
35 36
 ]
36 37
 
@@ -111,6 +112,17 @@ dependencies = [
111 112
  "termcolor",
112 113
 ]
113 114
 
115
+[[package]]
116
+name = "getrandom"
117
+version = "0.1.14"
118
+source = "registry+https://github.com/rust-lang/crates.io-index"
119
+checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
120
+dependencies = [
121
+ "cfg-if",
122
+ "libc",
123
+ "wasi",
124
+]
125
+
114 126
 [[package]]
115 127
 name = "hermit-abi"
116 128
 version = "0.1.11"
@@ -224,6 +236,12 @@ dependencies = [
224 236
  "void",
225 237
 ]
226 238
 
239
+[[package]]
240
+name = "ppv-lite86"
241
+version = "0.2.6"
242
+source = "registry+https://github.com/rust-lang/crates.io-index"
243
+checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
244
+
227 245
 [[package]]
228 246
 name = "proc-macro2"
229 247
 version = "1.0.10"
@@ -256,6 +274,47 @@ dependencies = [
256 274
  "proc-macro2",
257 275
 ]
258 276
 
277
+[[package]]
278
+name = "rand"
279
+version = "0.7.3"
280
+source = "registry+https://github.com/rust-lang/crates.io-index"
281
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
282
+dependencies = [
283
+ "getrandom",
284
+ "libc",
285
+ "rand_chacha",
286
+ "rand_core",
287
+ "rand_hc",
288
+]
289
+
290
+[[package]]
291
+name = "rand_chacha"
292
+version = "0.2.2"
293
+source = "registry+https://github.com/rust-lang/crates.io-index"
294
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
295
+dependencies = [
296
+ "ppv-lite86",
297
+ "rand_core",
298
+]
299
+
300
+[[package]]
301
+name = "rand_core"
302
+version = "0.5.1"
303
+source = "registry+https://github.com/rust-lang/crates.io-index"
304
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
305
+dependencies = [
306
+ "getrandom",
307
+]
308
+
309
+[[package]]
310
+name = "rand_hc"
311
+version = "0.2.0"
312
+source = "registry+https://github.com/rust-lang/crates.io-index"
313
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
314
+dependencies = [
315
+ "rand_core",
316
+]
317
+
259 318
 [[package]]
260 319
 name = "regex"
261 320
 version = "1.3.7"
@@ -409,6 +468,12 @@ version = "1.0.2"
409 468
 source = "registry+https://github.com/rust-lang/crates.io-index"
410 469
 checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
411 470
 
471
+[[package]]
472
+name = "wasi"
473
+version = "0.9.0+wasi-snapshot-preview1"
474
+source = "registry+https://github.com/rust-lang/crates.io-index"
475
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
476
+
412 477
 [[package]]
413 478
 name = "winapi"
414 479
 version = "0.3.8"

+ 1
- 0
base-station/software/Cargo.toml View File

@@ -15,3 +15,4 @@ env_logger = "0.7"
15 15
 log = "0.4"
16 16
 thiserror = "1.0"
17 17
 protocol = { path = "../../common/rust-protocol" }
18
+rand = "0.7.3"

+ 219
- 144
base-station/software/src/radio.rs View File

@@ -4,12 +4,15 @@ use std::thread;
4 4
 use std::thread::sleep;
5 5
 use std::time::{Duration, Instant};
6 6
 
7
-use embedded_nrf24l01::{Configuration, CrcMode, DataRate, NRF24L01};
7
+use embedded_nrf24l01::{Configuration, CrcMode, DataRate, RxMode, NRF24L01};
8 8
 use linux_embedded_hal::spidev::{SpiModeFlags, Spidev, SpidevOptions};
9 9
 use linux_embedded_hal::sysfs_gpio::Direction;
10
+use linux_embedded_hal::sysfs_gpio::Error as GpioError;
10 11
 use linux_embedded_hal::Pin;
11 12
 use log::{error, info};
12 13
 use protocol::{Location, Packet, Value};
14
+use rand::rngs::ThreadRng;
15
+use rand::Rng;
13 16
 
14 17
 use crate::spi::EmbeddedHalSpidev;
15 18
 use crate::Error;
@@ -37,161 +40,225 @@ pub fn start(updates: mpsc::Sender<SensorUpdate>) {
37 40
 }
38 41
 
39 42
 fn radio_thread(updates: &mpsc::Sender<SensorUpdate>) -> Result<(), Error> {
40
-    info!("Initializing radio...");
41
-
42
-    // The NRF module is connected as follows:
43
-    // - CE: PA1
44
-    // - CS: PG8
45
-    // - IRQ: PG9
46
-    // - MOSI: PC0
47
-    // - MISO: PC1
48
-    // - SCK: PC2
49
-
50
-    // Configure SPI.
51
-    let mut spi = Spidev::open("/dev/spidev0.0").unwrap();
52
-    let options = SpidevOptions::new()
53
-        .bits_per_word(8)
54
-        .max_speed_hz(500_000)
55
-        .mode(SpiModeFlags::SPI_MODE_0)
56
-        .build();
57
-    spi.configure(&options).unwrap();
58
-    let spi = EmbeddedHalSpidev::from(spi);
59
-
60
-    // Configure the GPIOs.
61
-    let ce_nr = get_pin_number('A', 1);
62
-    let ce = Pin::new(ce_nr);
63
-    ce.export().unwrap();
64
-    ce.set_direction(Direction::Out).unwrap();
65
-    let cs_nr = get_pin_number('G', 8);
66
-    let cs = Pin::new(cs_nr);
67
-    cs.export().unwrap();
68
-    cs.set_direction(Direction::Out).unwrap();
69
-    let irq_nr = get_pin_number('G', 9);
70
-    let irq = Pin::new(irq_nr);
71
-    irq.export().unwrap();
72
-    irq.set_direction(Direction::In).unwrap();
73
-
74
-    // Initialize the radio module.
75
-    let mut nrf24 = NRF24L01::new(ce, cs, spi)?;
76
-    nrf24.set_frequency(0x32)?;
77
-    nrf24.set_rf(DataRate::R2Mbps, 3)?;
78
-    nrf24.set_crc(Some(CrcMode::OneByte))?;
79
-    nrf24.set_auto_retransmit(250, 3)?;
80
-    nrf24.set_pipes_rx_enable(&[true, false, false, false, false, false])?; // TODO enable pipe 0 once the base station receives messages
81
-    nrf24
82
-        .set_rx_addr(0, &[0xB3, 0xB3, 0xB3, 0xB3, 0x00])
83
-        .unwrap();
84
-    nrf24.flush_rx().unwrap();
85
-    nrf24.flush_tx().unwrap();
86
-    //nrf24.set_auto_ack(&[true; 6]).unwrap();
87
-    info!("auto ack: {:?}", nrf24.get_auto_ack().unwrap());
88
-    nrf24.set_pipes_rx_lengths(&[None; 6]).unwrap();
89
-
90
-    info!("width: {}", nrf24.get_address_width().unwrap());
91
-
92
-    let mut start = Instant::now();
93
-
94
-    // Receive data.
95
-    let mut nrf24 = nrf24.rx().unwrap();
96
-    info!("Starting to receive:");
97
-    loop {
98
-        sleep(Duration::from_millis(1));
99
-        if let Some(pipe) = nrf24.can_read().unwrap() {
100
-            let mut payload = nrf24.read().unwrap();
101
-            info!(
102
-                "packet received on pipe {}: {:x?}, {}",
103
-                pipe,
104
-                payload.as_ref(),
105
-                payload.len()
106
-            );
107
-            if payload.len() != 32 {
108
-                continue;
109
-            }
43
+    let mut radio = Radio::init(updates)?;
44
+    radio.run_loop()?;
45
+    Ok(())
46
+}
110 47
 
111
-            // Get the key of the device.
112
-            let device_id = payload[0];
113
-            let key = match device_id {
114
-                DISPLAY_ID => &DISPLAY_KEY,
115
-                WEATHER_STATION_0_ID => &WEATHER_STATION_0_KEY,
116
-                _ => {
117
-                    info!("packet from unknown device {:02x}", device_id);
118
-                    continue;
119
-                }
120
-            };
48
+struct Radio<'a> {
49
+    rx: Option<RxMode<NRF24L01<GpioError, Pin, Pin, EmbeddedHalSpidev>>>,
50
+    updates: &'a mpsc::Sender<SensorUpdate>,
51
+    rng: ThreadRng,
52
+}
53
+
54
+impl<'a> Radio<'a> {
55
+    fn init(updates: &'a mpsc::Sender<SensorUpdate>) -> Result<Radio<'a>, Error> {
56
+        info!("Initializing radio...");
57
+
58
+        // The NRF module is connected as follows:
59
+        // - CE: PA1
60
+        // - CS: PG8
61
+        // - IRQ: PG9
62
+        // - MOSI: PC0
63
+        // - MISO: PC1
64
+        // - SCK: PC2
65
+
66
+        // Configure SPI.
67
+        let mut spi = Spidev::open("/dev/spidev0.0").unwrap();
68
+        let options = SpidevOptions::new()
69
+            .bits_per_word(8)
70
+            .max_speed_hz(500_000)
71
+            .mode(SpiModeFlags::SPI_MODE_0)
72
+            .build();
73
+        spi.configure(&options).unwrap();
74
+        let spi = EmbeddedHalSpidev::from(spi);
75
+
76
+        // Configure the GPIOs.
77
+        let ce_nr = get_pin_number('A', 1);
78
+        let ce = Pin::new(ce_nr);
79
+        ce.export().unwrap();
80
+        ce.set_direction(Direction::Out).unwrap();
81
+        let cs_nr = get_pin_number('G', 8);
82
+        let cs = Pin::new(cs_nr);
83
+        cs.export().unwrap();
84
+        cs.set_direction(Direction::Out).unwrap();
85
+        let irq_nr = get_pin_number('G', 9);
86
+        let irq = Pin::new(irq_nr);
87
+        irq.export().unwrap();
88
+        irq.set_direction(Direction::In).unwrap();
89
+
90
+        // Initialize the radio module.
91
+        let mut nrf24 = NRF24L01::new(ce, cs, spi)?;
92
+        nrf24.set_frequency(0x32)?;
93
+        nrf24.set_rf(DataRate::R2Mbps, 3)?;
94
+        nrf24.set_crc(Some(CrcMode::OneByte))?;
95
+        nrf24.set_auto_retransmit(250, 3)?;
96
+        nrf24.set_pipes_rx_enable(&[true, false, false, false, false, false])?; // TODO enable pipe 0 once the base station receives messages
97
+        nrf24
98
+            .set_rx_addr(0, &[0xB3, 0xB3, 0xB3, 0xB3, 0x00])
99
+            .unwrap();
100
+        nrf24.flush_rx().unwrap();
101
+        nrf24.flush_tx().unwrap();
102
+        nrf24.set_auto_ack(&[true; 6]).unwrap();
103
+        info!("auto ack: {:?}", nrf24.get_auto_ack().unwrap());
104
+        nrf24.set_pipes_rx_lengths(&[Some(32); 6]).unwrap();
105
+
106
+        info!("width: {}", nrf24.get_address_width().unwrap());
121 107
 
122
-            // Decode the packet.
123
-            let mut payload: [u8; 32] = payload.as_ref().try_into().unwrap();
124
-            let packet = match Packet::decrypt_and_parse(key, &mut payload) {
125
-                None => {
126
-                    info!("invalid packet from device {:02x}", device_id);
108
+        let rx = nrf24.rx().unwrap();
109
+
110
+        Ok(Radio {
111
+            rx: Some(rx),
112
+            updates,
113
+            rng: rand::thread_rng(),
114
+        })
115
+    }
116
+
117
+    fn run_loop(&mut self) -> Result<(), Error> {
118
+        let mut start = Instant::now();
119
+
120
+        // Receive data.
121
+        info!("Starting to receive:");
122
+        loop {
123
+            sleep(Duration::from_millis(1));
124
+            let rx = self.rx.as_mut().unwrap();
125
+            if let Some(pipe) = rx.can_read().unwrap() {
126
+                let payload = rx.read().unwrap();
127
+                info!(
128
+                    "packet received on pipe {}: {:x?}, {}",
129
+                    pipe,
130
+                    payload.as_ref(),
131
+                    payload.len()
132
+                );
133
+                if payload.len() != 32 {
127 134
                     continue;
128 135
                 }
129
-                Some(p) => p,
130
-            };
131
-            // TODO: For all packets except for salt requests, check whether the
132
-            // salt was incremented to prevent replay attacks.
133
-            // TODO: Also check whether the device bit in the salt is 0.
134 136
 
135
-            info!("packet from {}: {:?}", device_id, packet);
137
+                let mut payload: [u8; 32] = payload.as_ref().try_into().unwrap();
138
+                self.handle_packet(&mut payload)?;
136 139
 
137
-            match packet {
138
-                Packet::GetSalt => {
139
-                    // TODO
140
-                }
141
-                Packet::Salt(_) => {
142
-                    error!("received Salt packet from device.");
143
-                }
144
-                Packet::Report(payload) => {
145
-                    let location = get_location(device_id);
146
-                    let count = payload.count;
147
-                    for i in 0..count {
148
-                        match payload.values[i as usize] {
149
-                            Value::Invalid => {}
150
-                            Value::Time(_) => {
151
-                                error!("device tried to report a time");
152
-                            }
153
-                            Value::Temperature(temperature) => {
154
-                                let temperature = temperature as f32 / 10.0;
155
-                                info!("{:?} temperature: {} °C", location, temperature);
156
-                            }
157
-                            Value::Pressure(pressure) => {
158
-                                let pressure = pressure as f32 / 100.0;
159
-                                info!("{:?} pressure: {} HPa", location, pressure);
160
-                            }
161
-                            Value::Humidity(humidity) => {
162
-                                let humidity = humidity as f32 / 100.0;
163
-                                info!("{:?} humidity: {}%", location, humidity);
164
-                            }
140
+                let end = Instant::now();
141
+                let elapsed = end.duration_since(start);
142
+                info!("Debug: {:?}", elapsed);
143
+                start = end;
144
+            }
145
+        }
146
+    }
147
+
148
+    fn handle_packet(&mut self, payload: &mut [u8]) -> Result<(), Error> {
149
+        // Get the key of the device.
150
+        let device_id = payload[0];
151
+        let key = match get_key(device_id) {
152
+            Some(k) => k,
153
+            None => {
154
+                info!("packet from unknown device {:02x}", device_id);
155
+                return Ok(());
156
+            }
157
+        };
158
+
159
+        // Decode the packet.
160
+        let packet = match Packet::decrypt_and_decode(key, payload) {
161
+            None => {
162
+                info!("invalid packet from device {:02x}", device_id);
163
+                return Ok(());
164
+            }
165
+            Some(p) => p,
166
+        };
167
+        // TODO: For all packets except for salt requests, check whether the
168
+        // salt was incremented to prevent replay attacks.
169
+        // TODO: Also check whether the device bit in the salt is 0.
170
+
171
+        info!("packet from {}: {:?}", device_id, packet);
172
+
173
+        match packet {
174
+            Packet::GetSalt => {
175
+                self.send_salt(device_id)?;
176
+            }
177
+            Packet::Salt(_) => {
178
+                error!("received Salt packet from device.");
179
+            }
180
+            Packet::Report(payload) => {
181
+                let location = get_location(device_id);
182
+                let count = payload.count;
183
+                for i in 0..count {
184
+                    match payload.values[i as usize] {
185
+                        Value::Invalid => {}
186
+                        Value::Time(_) => {
187
+                            error!("device tried to report a time");
188
+                        }
189
+                        Value::Temperature(temperature) => {
190
+                            let temperature = temperature as f32 / 10.0;
191
+                            info!("{:?} temperature: {} °C", location, temperature);
192
+                        }
193
+                        Value::Pressure(pressure) => {
194
+                            let pressure = pressure as f32 / 100.0;
195
+                            info!("{:?} pressure: {} HPa", location, pressure);
196
+                        }
197
+                        Value::Humidity(humidity) => {
198
+                            let humidity = humidity as f32 / 100.0;
199
+                            info!("{:?} humidity: {}%", location, humidity);
165 200
                         }
166 201
                     }
167
-                    // TODO: Send values via MQTT
168
-                    /*
169
-                    updates
170
-                        .send(SensorUpdate {
171
-                            location: 0,
172
-                            data: vec![
173
-                                SensorData::Temperature(temperature),
174
-                                SensorData::Pressure(pressure),
175
-                                SensorData::Humidity(humidity),
176
-                            ],
177
-                        })
178
-                        .unwrap();
179
-                    */
180
-                }
181
-                Packet::GetValues(_payload) => {
182
-                    error!("GetValues not yet implemented.");
183
-                    // TODO
184
-                }
185
-                Packet::Values(_payload) => {
186
-                    error!("received Values packet from device.");
187 202
                 }
203
+                // TODO: Send values via MQTT
204
+                /*
205
+                updates
206
+                    .send(SensorUpdate {
207
+                        location: 0,
208
+                        data: vec![
209
+                            SensorData::Temperature(temperature),
210
+                            SensorData::Pressure(pressure),
211
+                            SensorData::Humidity(humidity),
212
+                        ],
213
+                    })
214
+                    .unwrap();
215
+                */
216
+            }
217
+            Packet::GetValues(_payload) => {
218
+                error!("GetValues not yet implemented.");
219
+                // TODO
220
+            }
221
+            Packet::Values(_payload) => {
222
+                error!("received Values packet from device.");
188 223
             }
224
+        }
225
+        Ok(())
226
+    }
189 227
 
190
-            let end = Instant::now();
191
-            let elapsed = end.duration_since(start);
192
-            info!("Debug: {:?}", elapsed);
193
-            start = end;
228
+    fn send_salt(&mut self, device_id: u8) -> Result<(), Error> {
229
+        let salt = (self.rng.gen::<u64>() & !0xff & !(1 << 63)) | device_id as u64;
230
+        let packet = Packet::Salt(salt);
231
+        self.send_packet(device_id, packet)
232
+    }
233
+
234
+    fn send_packet(&mut self, device_id: u8, packet: Packet) -> Result<(), Error> {
235
+        /*let salt = self.rng.gen::<u64>();
236
+        let mut tx = self
237
+            .rx
238
+            .take()
239
+            .unwrap()
240
+            .standby()
241
+            .tx()
242
+            .map_err(|(_, e)| Error::Radio(e))?;
243
+        let mut encoded = [0u8; 32];
244
+        let key = get_key(device_id);
245
+        if packet.encode_and_encrypt(key.unwrap(), salt, &mut encoded) {
246
+            tx.set_tx_addr(&[0xB3, 0xB3, 0xB3, 0xB3, device_id])
247
+                .unwrap();
248
+            tx.set_rx_addr(0, &[0xB3, 0xB3, 0xB3, 0xB3, device_id])
249
+                .unwrap();
250
+            tx.send(&encoded).unwrap();
251
+        // TODO: Check whether the packet arrived.
252
+        } else {
253
+            info!("could not encode packet {:?}", packet);
194 254
         }
255
+        self.rx = Some(
256
+            tx.standby()
257
+                .map_err(Error::Radio)?
258
+                .rx()
259
+                .map_err(|(_, e)| Error::Radio(e))?,
260
+        );*/
261
+        Ok(())
195 262
     }
196 263
 }
197 264
 
@@ -203,6 +270,14 @@ fn get_location(device_id: u8) -> Location {
203 270
     }
204 271
 }
205 272
 
273
+fn get_key(device_id: u8) -> Option<&'static [u8]> {
274
+    match device_id {
275
+        DISPLAY_ID => Some(&DISPLAY_KEY),
276
+        WEATHER_STATION_0_ID => Some(&WEATHER_STATION_0_KEY),
277
+        _ => None,
278
+    }
279
+}
280
+
206 281
 fn get_pin_number(c: char, n: u64) -> u64 {
207 282
     (c as u64 - 'A' as u64) * 32 + n
208 283
 }

+ 1
- 1
common/rust-protocol/src/lib.rs View File

@@ -17,7 +17,7 @@ pub enum Packet {
17 17
 }
18 18
 
19 19
 impl Packet {
20
-    pub fn decrypt_and_parse(key: &[u8], data: &mut [u8]) -> Option<Packet> {
20
+    pub fn decrypt_and_decode(key: &[u8], data: &mut [u8]) -> Option<Packet> {
21 21
         decrypt_cbc(key, data);
22 22
         let checksummed = &data[8..];
23 23
         let remainder = State::<KERMIT>::calculate(&checksummed);

Loading…
Cancel
Save