소스 검색

base-station: Use rust-protocol library for packet handling.

Mathias Gottschlag 5 년 전
부모
커밋
eccba895bf
3개의 변경된 파일97개의 추가작업 그리고 134개의 파일을 삭제
  1. 9
    2
      base-station/software/Cargo.lock
  2. 1
    2
      base-station/software/Cargo.toml
  3. 87
    130
      base-station/software/src/radio.rs

+ 9
- 2
base-station/software/Cargo.lock 파일 보기

@@ -24,15 +24,14 @@ dependencies = [
24 24
 name = "base-station"
25 25
 version = "0.1.0"
26 26
 dependencies = [
27
- "crc16",
28 27
  "embedded-hal",
29 28
  "embedded-nrf24l01",
30 29
  "env_logger",
31 30
  "linux-embedded-hal",
32 31
  "log",
33 32
  "mqtt-protocol",
33
+ "protocol",
34 34
  "thiserror",
35
- "xxtea-nostd",
36 35
 ]
37 36
 
38 37
 [[package]]
@@ -234,6 +233,14 @@ dependencies = [
234 233
  "unicode-xid",
235 234
 ]
236 235
 
236
+[[package]]
237
+name = "protocol"
238
+version = "0.1.0"
239
+dependencies = [
240
+ "crc16",
241
+ "xxtea-nostd",
242
+]
243
+
237 244
 [[package]]
238 245
 name = "quick-error"
239 246
 version = "1.2.3"

+ 1
- 2
base-station/software/Cargo.toml 파일 보기

@@ -14,5 +14,4 @@ mqtt-protocol = "0.8"
14 14
 env_logger = "0.7"
15 15
 log = "0.4"
16 16
 thiserror = "1.0"
17
-crc16 = "0.4.0"
18
-xxtea-nostd = "0.1.0"
17
+protocol = { path = "../../common/rust-protocol" }

+ 87
- 130
base-station/software/src/radio.rs 파일 보기

@@ -4,18 +4,22 @@ use std::thread;
4 4
 use std::thread::sleep;
5 5
 use std::time::{Duration, Instant};
6 6
 
7
-use crc16::{State, KERMIT};
8 7
 use embedded_nrf24l01::{Configuration, CrcMode, DataRate, NRF24L01};
9 8
 use linux_embedded_hal::spidev::{SpiModeFlags, Spidev, SpidevOptions};
10 9
 use linux_embedded_hal::sysfs_gpio::Direction;
11 10
 use linux_embedded_hal::Pin;
12 11
 use log::{error, info};
13
-use xxtea_nostd::{decrypt, encrypt};
12
+use protocol::{Location, Packet, Value};
14 13
 
15 14
 use crate::spi::EmbeddedHalSpidev;
16 15
 use crate::Error;
17 16
 use crate::{SensorData, SensorUpdate};
18 17
 
18
+const DISPLAY_ID: u8 = 0x20;
19
+const DISPLAY_KEY: [u8; 16] = include!("../../../common/display_key.txt");
20
+const WEATHER_STATION_0_ID: u8 = 0x30;
21
+const WEATHER_STATION_0_KEY: [u8; 16] = include!("../../../common/weather_station_0_key.txt");
22
+
19 23
 pub fn start(updates: mpsc::Sender<SensorUpdate>) {
20 24
     // TODO: Channels for sensor readings.
21 25
     thread::spawn(move || {
@@ -73,9 +77,9 @@ fn radio_thread(updates: &mpsc::Sender<SensorUpdate>) -> Result<(), Error> {
73 77
     nrf24.set_rf(DataRate::R2Mbps, 3)?;
74 78
     nrf24.set_crc(Some(CrcMode::OneByte))?;
75 79
     nrf24.set_auto_retransmit(250, 3)?;
76
-    nrf24.set_pipes_rx_enable(&[false, true, false, false, false, false])?; // TODO enable pipe 0 once the base station receives messages
80
+    nrf24.set_pipes_rx_enable(&[true, false, false, false, false, false])?; // TODO enable pipe 0 once the base station receives messages
77 81
     nrf24
78
-        .set_rx_addr(1, &[0xB3, 0xB3, 0xB3, 0xB3, 0x00])
82
+        .set_rx_addr(0, &[0xB3, 0xB3, 0xB3, 0xB3, 0x00])
79 83
         .unwrap();
80 84
     nrf24.flush_rx().unwrap();
81 85
     nrf24.flush_tx().unwrap();
@@ -104,124 +108,85 @@ fn radio_thread(updates: &mpsc::Sender<SensorUpdate>) -> Result<(), Error> {
104 108
                 continue;
105 109
             }
106 110
 
107
-            let mut payload = payload.as_ref().to_vec();
108
-
109
-            let sensor_id = payload[0];
110
-
111
-            // Decrypt the package
112
-            let key = [
113
-                0x9e, 0x37, 0x79, 0xb9, 0x9b, 0x97, 0x73, 0xe9, 0xb9, 0x79, 0x37, 0x9e, 0x6b, 0x69,
114
-                0x51, 0x56,
115
-            ]; //TODO: define somewhere else
116
-            decrypt_cbc(&key, &mut payload);
117
-            info!("decrypted: {:x?}", payload);
118
-
119
-            // Calculate the CRC
120
-            let crc_calculation_buffer = payload[8..30].to_vec();
121
-            let calculated_crc = State::<KERMIT>::calculate(&crc_calculation_buffer);
122
-            info!("calculated crc: 0x{:x}", calculated_crc);
123
-            let crc = u16::from_le_bytes(payload[30..32].try_into().unwrap());
124
-
125
-            if crc != calculated_crc {
126
-                info!("malformed packet received: crc mismatch!");
127
-                info!(
128
-                    "Calculated crc: 0x{:x}, received crc: 0x{:x}",
129
-                    calculated_crc, crc
130
-                );
131
-                continue;
132
-            }
133
-
134
-            let packet_identifier = payload[8];
135
-            let packet_payload = &payload[9..30];
136
-            info!("sensor id: 0x{:x}", sensor_id);
137
-            info!("crc: 0x{:x}", crc);
138
-
139
-            let packet_type = packet_identifier & 0x1F;
140
-            let element_count = (packet_identifier & 0xE0) >> 5;
141
-
142
-            let mut temperature = 0;
143
-            let mut pressure = 0;
144
-            let mut humidity = 0;
145
-
146
-            if packet_type == 1 {
147
-                let mut i = 0;
148
-                let mut buffer_position = 0;
149
-                info!("report packet received");
150
-                while i < element_count {
151
-                    let value_type = packet_payload[buffer_position];
152
-
153
-                    buffer_position += 1; // Set the position to the value
154
-
155
-                    if value_type == 0 {
156
-                        info!("time value not yet supported");
157
-                        buffer_position += 8;
158
-                    } else if value_type == 1 {
159
-                        temperature = i16::from_le_bytes(
160
-                            packet_payload[buffer_position..buffer_position + 2]
161
-                                .try_into()
162
-                                .unwrap(),
163
-                        );
164
-                        buffer_position += 2;
165
-                    } else if value_type == 2 {
166
-                        pressure = u32::from_le_bytes(
167
-                            packet_payload[buffer_position..buffer_position + 4]
168
-                                .try_into()
169
-                                .unwrap(),
170
-                        );
171
-                        buffer_position += 4;
172
-                    } else if value_type == 3 {
173
-                        humidity = u16::from_le_bytes(
174
-                            packet_payload[buffer_position..buffer_position + 2]
175
-                                .try_into()
176
-                                .unwrap(),
177
-                        );
178
-                        buffer_position += 2;
179
-                    } else {
180
-                        info!("unknown value type");
181
-                    }
182
-
183
-                    i += 1;
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;
184 119
                 }
185
-            } else {
186
-                info!("unknown packet type");
187
-                continue;
188
-            }
120
+            };
121
+
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);
127
+                    continue;
128
+                }
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.
189 134
 
190
-            /* Check the values for validity */
191
-            if pressure < 50000 || pressure > 150000 {
192
-                info!("pressure outside of range: {}", pressure);
193
-                continue;
194
-            }
135
+            info!("packet from {}: {:?}", device_id, packet);
195 136
 
196
-            if temperature < -50 * 10 || temperature > 100 * 10 {
197
-                info!("temperature outside of range: {}", temperature);
198
-                continue;
199
-            }
200
-
201
-            if humidity > 10000 {
202
-                info!("humidity outside of range: {}", humidity);
203
-                continue;
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
+                            }
165
+                        }
166
+                    }
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
+                }
204 188
             }
205 189
 
206
-            let pressure = pressure as f32 / 100.0;
207
-            let temperature = temperature as f32 / 10.0;
208
-            let humidity = humidity as f32 / 100.0;
209
-            info!("pressure: {} HPa", pressure);
210
-            info!("temperature: {} °C", temperature);
211
-            info!("humidity: {}%", humidity);
212
-
213
-            /*
214
-            updates
215
-                .send(SensorUpdate {
216
-                    location: 0,
217
-                    data: vec![
218
-                        SensorData::Temperature(temperature),
219
-                        SensorData::Pressure(pressure),
220
-                        SensorData::Humidity(humidity),
221
-                    ],
222
-                })
223
-                .unwrap();
224
-            */
225 190
             let end = Instant::now();
226 191
             let elapsed = end.duration_since(start);
227 192
             info!("Debug: {:?}", elapsed);
@@ -230,19 +195,11 @@ fn radio_thread(updates: &mpsc::Sender<SensorUpdate>) -> Result<(), Error> {
230 195
     }
231 196
 }
232 197
 
233
-fn decrypt_cbc(key: &[u8], data: &mut [u8]) {
234
-    let mut blocks = data.rchunks_mut(8).peekable();
235
-    loop {
236
-        let block = blocks.next().unwrap();
237
-        let prev_block = match blocks.peek() {
238
-            Some(b) => b,
239
-            None => break,
240
-        };
241
-        decrypt(&key, block);
242
-
243
-        for i in 0..8 {
244
-            block[i] ^= prev_block[i];
245
-        }
198
+fn get_location(device_id: u8) -> Location {
199
+    match device_id {
200
+        DISPLAY_ID => Location::Bedroom,
201
+        WEATHER_STATION_0_ID => Location::Livingroom,
202
+        _ => Location::Livingroom,
246 203
     }
247 204
 }
248 205
 

Loading…
취소
저장