jamesmunns / postcard

A no_std + serde compatible message library for Rust
Apache License 2.0
874 stars 87 forks source link

How to deserialize multiple values from an arbitrary set of bytes? #119

Closed avsaase closed 10 months ago

avsaase commented 10 months ago

Hi, thanks for making this crate. I would like to use it as a logging format to log data to a SD card via a serial connection. The data is serialized in a no_std environment and deserialized later in a std env into a vec of messages.

I recorded some test data with a serial monitor but I don't understand how to deserialize it.

My data type are like this

#[derive(Debug, Serialize, Deserialize)]
pub struct SensorUpdate {
    pub data: SensorData,
    pub updated_at: u64,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum SensorData {
    Baro(BaroData),
    Imu(ImuData),
    Gps(GpsData),
}

#[derive(Debug, Serialize, Deserialize)]
pub struct BaroData {
    pub pressure_pa: f32,
    pub temperature_c: f32,
    pub altitude_m: f32,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct GpsData {
    pub fix_type: GpsFix,
    pub sats_in_use: u8,
    pub latitude: f32,
    pub longitude: f32,
    pub altitude: f32,
    pub horizontal_accuracy: f32,
    pub vertical_accuracy: f32,
    pub heading: f32,
    pub heading_accuracy: f32,
    pub speed: f32,
    pub vel_north: f32,
    pub vel_east: f32,
    pub vel_down: f32,
    pub speed_accuracy: f32,
    pub time: GpsTime,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum GpsFix {
    NoFix = 0,
    DeadReckoningOnly = 1,
    Fix2D = 2,
    Fix3D = 3,
    GPSPlusDeadReckoning = 4,
    TimeOnlyFix = 5,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct GpsTime {
    pub year: u16,
    pub month: u8,
    pub day: u8,
    pub hour: u8,
    pub min: u8,
    pub sec: u8,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ImuData {
    pub gyro_x: f32,
    pub gyro_y: f32,
    pub gyro_z: f32,
    pub acc_x: f32,
    pub acc_y: f32,
    pub acc_z: f32,
}

On serialization side I have:

let mut buffer = [0u8; 256];
loop {
    let sensor_update = // load sensor values
    let buffer = to_slice_cobs(&sensor_update, &mut buffer).unwrap();
    // Write `buffer` to the serial connection
}

On the deserialization side I'm including the data with include_bytes!("../serial_output.txt") but what do I do from there? I found the example for CobsAccumulator but I'm not sure if it's applicable or how to adjust it to my use case. I hope you can point me in the right direction. Thanks!

I uploaded some example data here.

avsaase commented 10 months ago

I should have read more about COBS encoding before opening this issue. It's trivial to split the bytes from the file on the zero byte and decode each message separately. Works like a charm.