mendi 0.0.2

Rust client for the Mendi neurofeedback headband over BLE using btleplug
Documentation
use mendi::protocol::*;
use mendi::wire;
use prost::Message;

#[test]
fn mendi_service_uuid_matches_vendor_base() {
    // The Mendi app uses "fc3e" + short_code + "-c6c4-49e6-922a-6e551c455af5"
    // Service UUID: fc3eabb0-c6c4-49e6-922a-6e551c455af5
    assert_eq!(
        MENDI_SERVICE_UUID.to_string(),
        "fc3eabb0-c6c4-49e6-922a-6e551c455af5"
    );
}

#[test]
fn frame_characteristic_uuid() {
    assert_eq!(
        FRAME_CHARACTERISTIC.to_string(),
        "fc3eabb1-c6c4-49e6-922a-6e551c455af5"
    );
}

#[test]
fn sensor_characteristic_uuid() {
    assert_eq!(
        SENSOR_CHARACTERISTIC.to_string(),
        "fc3eabb2-c6c4-49e6-922a-6e551c455af5"
    );
}

#[test]
fn imu_characteristic_uuid() {
    assert_eq!(
        IMU_CHARACTERISTIC.to_string(),
        "fc3eabb3-c6c4-49e6-922a-6e551c455af5"
    );
}

#[test]
fn adc_characteristic_uuid() {
    assert_eq!(
        ADC_CHARACTERISTIC.to_string(),
        "fc3eabb4-c6c4-49e6-922a-6e551c455af5"
    );
}

#[test]
fn diagnostics_characteristic_uuid() {
    assert_eq!(
        DIAGNOSTICS_CHARACTERISTIC.to_string(),
        "fc3eabb5-c6c4-49e6-922a-6e551c455af5"
    );
}

#[test]
fn calibration_characteristic_uuid() {
    assert_eq!(
        CALIBRATION_CHARACTERISTIC.to_string(),
        "fc3eabb6-c6c4-49e6-922a-6e551c455af5"
    );
}

#[test]
fn firmware_revision_uses_bluetooth_base() {
    // Standard BLE: 00002a26-0000-1000-8000-00805f9b34fb
    assert_eq!(
        FIRMWARE_REVISION.to_string(),
        "00002a26-0000-1000-8000-00805f9b34fb"
    );
}

#[test]
fn hardware_revision_uses_bluetooth_base() {
    assert_eq!(
        HARDWARE_REVISION.to_string(),
        "00002a27-0000-1000-8000-00805f9b34fb"
    );
}

#[test]
fn mendi_uuid_helper_arbitrary_short_code() {
    // 0x1234 → fc3e1234-c6c4-49e6-922a-6e551c455af5
    let uuid = mendi_uuid(0x1234);
    assert_eq!(uuid.to_string(), "fc3e1234-c6c4-49e6-922a-6e551c455af5");
}

#[test]
fn mendi_uuid_helper_zero() {
    let uuid = mendi_uuid(0x0000);
    assert_eq!(uuid.to_string(), "fc3e0000-c6c4-49e6-922a-6e551c455af5");
}

#[test]
fn mendi_uuid_helper_ffff() {
    let uuid = mendi_uuid(0xFFFF);
    assert_eq!(uuid.to_string(), "fc3effff-c6c4-49e6-922a-6e551c455af5");
}

// ── Protobuf encode tests for write operations ───────────────────────────────

#[test]
fn calibration_encode_roundtrip() {
    let msg = wire::Calibration {
        offset_l: -10.5,
        offset_r: 20.0,
        offset_p: 0.0,
        enable: true,
        low_power_mode: false,
    };
    let bytes = msg.encode_to_vec();
    let decoded = wire::Calibration::decode(bytes.as_slice()).unwrap();
    assert!((decoded.offset_l - (-10.5)).abs() < 0.001);
    assert!((decoded.offset_r - 20.0).abs() < 0.001);
    assert!((decoded.offset_p - 0.0).abs() < 0.001);
    assert!(decoded.enable);
    assert!(!decoded.low_power_mode);
}

#[test]
fn sensor_write_encode() {
    let msg = wire::Sensor {
        read: false,
        address: 0x42,
        data: 0x00ABCDEF,
    };
    let bytes = msg.encode_to_vec();
    let decoded = wire::Sensor::decode(bytes.as_slice()).unwrap();
    assert!(!decoded.read);
    assert_eq!(decoded.address, 0x42);
    assert_eq!(decoded.data, 0x00ABCDEF);
}

#[test]
fn sensor_read_request_encode() {
    let msg = wire::Sensor {
        read: true,
        address: 0x1A,
        data: 0,
    };
    let bytes = msg.encode_to_vec();
    let decoded = wire::Sensor::decode(bytes.as_slice()).unwrap();
    assert!(decoded.read);
    assert_eq!(decoded.address, 0x1A);
    assert_eq!(decoded.data, 0);
}

#[test]
fn imu_write_encode() {
    let msg = wire::Imu {
        read: 0,
        address: 0x0F,
        data: vec![0x01, 0x02, 0x03],
    };
    let bytes = msg.encode_to_vec();
    let decoded = wire::Imu::decode(bytes.as_slice()).unwrap();
    assert_eq!(decoded.read, 0);
    assert_eq!(decoded.address, 0x0F);
    assert_eq!(decoded.data, vec![0x01, 0x02, 0x03]);
}

#[test]
fn imu_read_request_encode() {
    let msg = wire::Imu {
        read: 5,
        address: 0x20,
        data: vec![],
    };
    let bytes = msg.encode_to_vec();
    let decoded = wire::Imu::decode(bytes.as_slice()).unwrap();
    assert_eq!(decoded.read, 5);
    assert_eq!(decoded.address, 0x20);
    assert!(decoded.data.is_empty());
}