|
|
@@ -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
|
|