libexail 0.1.0

A rust library for communicating with Exail devices through their binary protocol
Documentation
//! External sensor data block structs (bits 0–28 of the external bitmask).

use super::{block_enum, parse_blocks};
use crate::error::{Error, Result};
use binrw::BinRead;
use serde::Serialize;
use std::io::{Cursor, Read};

block_enum! {
    /// An external sensor data block (bits 0–28 of the external bitmask).
    /// Bit 23 is reserved and skipped during parsing.
    pub enum ExternalBlock {
        0  => Utc(UtcData, 5),
        1  => Gnss1(GnssData, 46),
        2  => Gnss2(GnssData, 46),
        3  => ManualGnss(GnssData, 46),
        4  => Emlog1(EmlogData, 13),
        5  => Emlog2(EmlogData, 13),
        6  => Usbl1(UsblData, 49),
        7  => Usbl2(UsblData, 49),
        8  => Usbl3(UsblData, 49),
        9  => Depth(DepthData, 12),
        10 => Dvl1GroundSpeed(DvlGroundSpeed, 37),
        11 => Dvl1WaterSpeed(DvlWaterSpeed, 33),
        12 => SoundVelocity(SoundVelocity, 8),
        13 => Dmi(DmiData, 8),
        14 => Lbl1(LblData, 41),
        15 => Lbl2(LblData, 41),
        16 => Lbl3(LblData, 41),
        17 => Lbl4(LblData, 41),
        18 => EventMarkerA(EventMarker, 9),
        19 => EventMarkerB(EventMarker, 9),
        20 => EventMarkerC(EventMarker, 9),
        21 => Dvl2GroundSpeed(DvlGroundSpeed, 37),
        22 => Dvl2WaterSpeed(DvlWaterSpeed, 33),
        // bit 23 is reserved (28 bytes), skipped during parsing
        24 => TurretAngles(TurretAngles, 16),
        25 => Vtg1(VtgData, 17),
        26 => Vtg2(VtgData, 17),
        27 => LogBook(LogBook, 40),
        28 => Date(DateData, 8),
    }
    read_fn();
}

/// Parse external sensor blocks from the cursor given the bitmask.
pub fn parse_external_blocks(
    bitmask: u32,
    cursor: &mut Cursor<&[u8]>,
) -> Result<Vec<ExternalBlock>> {
    parse_blocks(bitmask, 29, |bit| {
        if bit == 23 {
            // Reserved (28 bytes) — skip
            let mut skip = [0u8; 28];
            cursor
                .read_exact(&mut skip)
                .map_err(|e| Error::InvalidBlock(binrw::Error::Io(e)))?;
            return Ok(None);
        }
        ExternalBlock::read(bit, cursor).map(Some)
    })
}

/// UTC data (bit 0, 5 bytes).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct UtcData {
    /// Time tag in steps of 100 us.
    pub validity_time: u32,
    /// 0: UTC1, 1: UTC2.
    pub source: u8,
}

/// GNSS data (bits 1, 2, 3 — GNSS1, GNSS2, Manual GNSS; 46 bytes each).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct GnssData {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// 0: GNSS1, 1: GNSS2, 2: Manual GNSS.
    pub gnss_id: u8,
    /// Quality indicator (see GNSS quality table). Fixed to 1 for manual GNSS.
    pub gnss_quality: u8,
    /// In degrees, positive North, inside [-90, 90].
    pub latitude: f64,
    /// In degrees, positive East, inside [0, 360).
    pub longitude: f64,
    /// In meters, positive up, in geoid reference.
    pub altitude: f32,
    /// In meters.
    pub latitude_std_dev: f32,
    /// In meters.
    pub longitude_std_dev: f32,
    /// In meters.
    pub altitude_std_dev: f32,
    /// In meters^2. Fixed to 0 for manual GNSS.
    pub lat_lon_covariance: f32,
    /// In meters.
    pub geoidal_separation: f32,
}

/// EMLOG data (bits 4, 5 — EMLOG1, EMLOG2; 13 bytes each).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct EmlogData {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// 0: EMLOG1, 1: EMLOG2.
    pub emlog_id: u8,
    /// XV1 longitudinal water speed in m/s, positive forward.
    pub xv1_speed: f32,
    /// XV1 speed standard deviation in m/s.
    pub xv1_speed_std_dev: f32,
}

/// USBL data (bits 6, 7, 8 — USBL1, USBL2, USBL3; 49 bytes each).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct UsblData {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// 0: USBL1, 1: USBL2, 2: USBL3.
    pub usbl_id: u8,
    /// 8 ASCII characters, null-padded.
    pub beacon_id: [u8; 8],
    /// In degrees, positive North, inside [-90, 90].
    pub latitude: f64,
    /// In degrees, positive East, inside [0, 360).
    pub longitude: f64,
    /// In meters, as received from USBL system.
    pub altitude: f32,
    /// In meters.
    pub north_std_dev: f32,
    /// In meters.
    pub east_std_dev: f32,
    /// In meters^2.
    pub lat_lon_covariance: f32,
    /// In meters.
    pub altitude_std_dev: f32,
}

/// Depth data (bit 9, 12 bytes).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct DepthData {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// In meters.
    pub depth: f32,
    /// In meters.
    pub depth_std_dev: f32,
}

/// DVL ground speed data (bits 10, 21 — DVL1, DVL2; 37 bytes each).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct DvlGroundSpeed {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// 0: DVL1, 1: DVL2.
    pub dvl_id: u8,
    /// XS1 forward ground speed in m/s.
    pub xs1_ground_speed: f32,
    /// XS2 transverse ground speed in m/s.
    pub xs2_ground_speed: f32,
    /// XS3 vertical ground speed in m/s.
    pub xs3_ground_speed: f32,
    /// DVL speed of sound in m/s.
    pub speed_of_sound: f32,
    /// DVL altitude (bottom range) in meters.
    pub altitude: f32,
    /// XS1 speed standard deviation in m/s.
    pub xs1_speed_std_dev: f32,
    /// XS2 speed standard deviation in m/s.
    pub xs2_speed_std_dev: f32,
    /// XS3 speed standard deviation in m/s.
    pub xs3_speed_std_dev: f32,
}

/// DVL water speed data (bits 11, 22 — DVL1, DVL2; 33 bytes each).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct DvlWaterSpeed {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// 0: DVL1, 1: DVL2.
    pub dvl_id: u8,
    /// XS1 forward water speed in m/s.
    pub xs1_water_speed: f32,
    /// XS2 transverse water speed in m/s.
    pub xs2_water_speed: f32,
    /// XS3 vertical water speed in m/s.
    pub xs3_water_speed: f32,
    /// DVL speed of sound in m/s.
    pub speed_of_sound: f32,
    /// XS1 speed standard deviation in m/s.
    pub xs1_speed_std_dev: f32,
    /// XS2 speed standard deviation in m/s.
    pub xs2_speed_std_dev: f32,
    /// XS3 speed standard deviation in m/s.
    pub xs3_speed_std_dev: f32,
}

/// External sound velocity (bit 12, 8 bytes).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct SoundVelocity {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// External sensor speed of sound in m/s.
    pub speed_of_sound: f32,
}

/// DMI data (bit 13, 8 bytes).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct DmiData {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// Number of pulses received since last DMI event.
    pub pulse_count: i32,
}

/// LBL data (bits 14-17 — LBL1 to LBL4; 41 bytes each).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct LblData {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// Reserved for future use.
    pub rfu: u8,
    /// 8 ASCII characters, null-padded.
    pub beacon_id: [u8; 8],
    /// In degrees, positive North, inside [-90, 90].
    pub beacon_latitude: f64,
    /// In degrees, positive East, inside [0, 360).
    pub beacon_longitude: f64,
    /// In meters, positive up.
    pub beacon_altitude: f32,
    /// In meters, positive.
    pub range: f32,
    /// In meters.
    pub range_std_dev: f32,
}

/// Event marker (bits 18, 19, 20 — A, B, C; 9 bytes each).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct EventMarker {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// 0: Event A, 1: Event B, 2: Event C.
    pub event_id: u8,
    /// Number of events received since last protocol update.
    pub event_count: i32,
}

/// Turret angles (bit 24, 16 bytes).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct TurretAngles {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// Heading/bearing/drift angle in degrees, positive clockwise.
    pub heading: f32,
    /// In degrees, positive when right side up, inside [-180, 180).
    pub roll: f32,
    /// Elevation/pitch in degrees, positive gun up, inside [-90, 90].
    pub pitch: f32,
}

/// VTG data (bits 25, 26 — VTG1, VTG2; 17 bytes each).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct VtgData {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// 0: VTG1, 1: VTG2.
    pub vtg_id: u8,
    /// True course in degrees.
    pub true_course: f32,
    /// Magnetic course in degrees.
    pub magnetic_course: f32,
    /// Speed over ground in m/s.
    pub speed_over_ground: f32,
}

/// Log book (bit 27, 40 bytes).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct LogBook {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// Log identifier, determined by the application.
    pub identifier: u32,
    /// 32 ASCII characters.
    pub custom_text: [u8; 32],
}

/// Date data (bit 28, 8 bytes).
#[derive(Debug, Clone, BinRead, Serialize)]
#[brw(big)]
pub struct DateData {
    /// Time tag in steps of 100 us.
    pub validity_time: i32,
    /// Day inside [0, 31], 0 if unavailable.
    pub day: u8,
    /// Month inside [0, 12], 0 if unavailable.
    pub month: u8,
    /// Year inside [0, 65535], 0 if unavailable.
    pub year: u16,
}