libexail 0.1.0

A rust library for communicating with Exail devices through their binary protocol
Documentation
//! Sync byte detection and checksum calculation for Exail frames.

use crate::header::SyncType;

/// Check if two bytes form a valid sync pattern.
pub fn is_sync(b1: u8, b2: u8) -> Option<SyncType> {
    match (b1, b2) {
        (b'I', b'X') => Some(SyncType::NavData),
        (b'C', b'M') => Some(SyncType::Command),
        (b'A', b'N') => Some(SyncType::Answer),
        _ => None,
    }
}

/// Calculate the checksum: unsigned 32-bit sum of all bytes.
pub fn calculate_checksum(data: &[u8]) -> u32 {
    data.iter().map(|&b| b as u32).sum()
}

/// Validate the checksum of a complete frame.
///
/// The last 4 bytes of the frame are the checksum (big-endian u32).
/// The checksum covers all preceding bytes (header + body).
/// Return None if fewer than four bytes are present in the data.
pub fn validate_checksum(frame: &[u8]) -> Option<bool> {
    if frame.len() < 4 {
        return None;
    }
    let (data, cksum_bytes) = frame.split_at(frame.len() - 4);
    let expected = u32::from_be_bytes([
        cksum_bytes[0],
        cksum_bytes[1],
        cksum_bytes[2],
        cksum_bytes[3],
    ]);
    let calculated = calculate_checksum(data);
    Some(calculated == expected)
}

#[cfg(test)]
mod tests {
    use crate::{framing, header::SyncType};

    #[test]
    fn test_checksum_empty() {
        assert_eq!(framing::calculate_checksum(&[]), 0);
    }

    #[test]
    fn test_checksum_simple() {
        assert_eq!(framing::calculate_checksum(&[1, 2, 3, 4]), 10);
    }

    #[test]
    fn test_sync_detection() {
        assert_eq!(framing::is_sync(b'I', b'X'), Some(SyncType::NavData));
        assert_eq!(framing::is_sync(b'C', b'M'), Some(SyncType::Command));
        assert_eq!(framing::is_sync(b'A', b'N'), Some(SyncType::Answer));
        assert_eq!(framing::is_sync(b'X', b'X'), None);
    }

    #[test]
    fn test_validate_checksum() {
        let frame = [0x01, 0x02, 0x00, 0x00, 0x00, 0x03];
        assert_eq!(framing::validate_checksum(&frame), Some(true));

        let bad_frame = [0x01, 0x02, 0x00, 0x00, 0x00, 0x04];
        assert_eq!(framing::validate_checksum(&bad_frame), Some(false));

        let short_frame = [0x01, 0x02, 0x00];
        assert!(framing::validate_checksum(&short_frame).is_none());
    }
}