#![allow(missing_docs)]
use cobs_codec_rs::framing::{FrameDecoder, frame_to_vec};
use prost::Message;
#[derive(Clone, PartialEq, prost::Message)]
struct SensorReading {
#[prost(uint32, tag = "1")]
node_id: u32,
#[prost(float, tag = "2")]
temperature_c: f32,
#[prost(uint64, tag = "3")]
uptime_ms: u64,
#[prost(string, tag = "4")]
label: String,
}
fn main() {
let readings = [
SensorReading {
node_id: 1,
temperature_c: 21.5,
uptime_ms: 1_000,
label: "cabin".into(),
},
SensorReading {
node_id: 2,
temperature_c: 100.0,
uptime_ms: 1_256,
label: "boiler".into(),
},
SensorReading {
node_id: 7,
temperature_c: -4.25,
uptime_ms: 99_999,
label: "outside".into(),
},
];
let mut wire: Vec<u8> = Vec::new();
let mut frame_starts: Vec<usize> = Vec::new();
for reading in &readings {
frame_starts.push(wire.len());
let payload = reading.encode_to_vec(); wire.extend_from_slice(&frame_to_vec(&payload)); }
println!(
"device: {} readings -> {} wire bytes; the only zeros are the {} frame delimiters",
readings.len(),
wire.len(),
readings.len(),
);
wire[frame_starts[1]] = 0xFF;
println!("noise: flipped a byte inside reading #2's frame\n");
let mut rx = FrameDecoder::new().max_frame_len(256);
let mut received = 0usize;
for chunk in wire.chunks(5) {
rx.push(chunk, |frame| match frame {
Ok(bytes) => match SensorReading::decode(&*bytes) {
Ok(msg) => {
received += 1;
println!(
"host <- node {:>2}: {:+6.2} C, up {:>6} ms, \"{}\"",
msg.node_id, msg.temperature_c, msg.uptime_ms, msg.label,
);
}
Err(err) => println!("host <- valid COBS frame but bad protobuf: {err}"),
},
Err(err) => println!("host <- dropped a corrupt frame ({err}); resyncing on next 0x00"),
});
}
println!(
"\nreceived {received}/{} readings: the corrupted frame was skipped and the \
stream resynced on the next delimiter.",
readings.len(),
);
assert_eq!(received, readings.len() - 1);
}