1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
use std::{
    error::Error, fmt::{self, Display, Formatter},
};

use self::ParseError::*;
use formats::v3::{AccelerationVectorV3, SensorValuesV3};

#[derive(Debug, PartialEq)]
pub struct SensorValues {
    /// Humidity in parts per million
    pub humidity: Option<u32>,
    /// temperature in millicelsius
    pub temperature: Option<i32>,
    /// pressure in pascals
    pub pressure: Option<u32>,
    /// 3-dimensional acceleration vector, each component in milli-G
    pub acceleration: Option<AccelerationVector>,
    /// battery potential in millivolts
    pub battery_potential: Option<u16>,
}

impl SensorValues {
    pub fn from_manufacturer_specific_data(id: u16, value: &[u8]) -> Result<Self, ParseError> {
        if id == 0x0499 && value.len() > 0 {
            let format_version = value[0];

            if value[0] == 3 {
                if let Ok(values) = SensorValuesV3::from_manufacturer_specific_data(value) {
                    Ok(Self::from(values))
                } else {
                    Err(InvalidValueLength {
                        version: 3,
                        length: value.len(),
                        expected: 14,
                    })
                }
            } else {
                Err(UnsupportedFormatVersion(format_version))
            }
        } else if value.len() == 0 {
            Err(EmptyValue)
        } else {
            Err(UnknownManufacturerId(id))
        }
    }
}

impl From<SensorValuesV3> for SensorValues {
    fn from(values: SensorValuesV3) -> SensorValues {
        let AccelerationVectorV3(ref a_x, ref a_y, ref a_z) = values.acceleration;

        SensorValues {
            humidity: Some(values.humidity_ppm()),
            temperature: Some(values.temperature_millicelsius()),
            pressure: Some(values.pressure_pascals()),
            acceleration: Some(AccelerationVector(*a_x, *a_y, *a_z)),
            battery_potential: Some(values.battery_potential),
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct AccelerationVector(pub i16, pub i16, pub i16);

#[derive(Debug, PartialEq)]
pub enum ParseError {
    UnknownManufacturerId(u16),
    UnsupportedFormatVersion(u8),
    InvalidValueLength {
        version: u8,
        length: usize,
        expected: usize,
    },
    EmptyValue,
}

impl Display for ParseError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        match self {
            UnknownManufacturerId(id) => write!(
                formatter,
                "Unknown manufacturer id {:#04X}, only 0x0499 is supported",
                id
            ),
            UnsupportedFormatVersion(format_version) => write!(
                formatter,
                "Unsupported data format version {}, only version 3 is supported",
                format_version
            ),
            InvalidValueLength {
                version,
                length,
                expected,
            } => write!(
                formatter,
                "Invalid data length of {} for format version {}, expected length of {}",
                length, version, expected
            ),
            EmptyValue => write!(formatter, "Empty value, expected at least one byte"),
        }
    }
}

impl Error for ParseError {}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_unsupported_manufacturer_id() {
        let value = vec![3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        let result = SensorValues::from_manufacturer_specific_data(0x0477, &value);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), UnknownManufacturerId(0x0477));
    }

    #[test]
    fn parse_unsupported_format() {
        let value = vec![0, 1, 2, 3];
        let result = SensorValues::from_manufacturer_specific_data(0x0499, &value);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), UnsupportedFormatVersion(0));
    }

    #[test]
    fn parse_empty_data() {
        let value = vec![];
        let result = SensorValues::from_manufacturer_specific_data(0x0499, &value);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), EmptyValue);
    }

    #[test]
    fn parse_version_3_data_with_invalid_length() {
        let value = vec![3, 103, 22, 50, 60, 70];
        let result = SensorValues::from_manufacturer_specific_data(0x0499, &value);
        assert!(result.is_err());
        assert_eq!(
            result.unwrap_err(),
            InvalidValueLength {
                version: 3,
                length: 6,
                expected: 14
            }
        );
    }

    #[test]
    fn parse_valid_version_3_data() {
        let value = vec![
            3, 0x17, 0x01, 0x45, 0x35, 0x58, 0x03, 0xE8, 0x04, 0xE7, 0x05, 0xE6, 0x08, 0x86,
        ];
        let result = SensorValues::from_manufacturer_specific_data(0x0499, &value);

        assert_eq!(
            result,
            Ok(SensorValues {
                humidity: Some(115_000),
                temperature: Some(1690),
                pressure: Some(63656),
                acceleration: Some(AccelerationVector(1000, 1255, 1510)),
                battery_potential: Some(2182)
            })
        );
    }
}