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
use core::fmt::Debug;
use core::str::from_utf8_unchecked as utf8;

pub mod date;
pub mod latitude;
pub mod longitude;
pub mod position_mode;
pub mod time;

pub type Quality = position_mode::PositionMode;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum OperationMode {
    Auto,
    Manual,
}

impl Default for OperationMode {
    fn default() -> Self {
        Self::Manual
    }
}

impl From<&[u8]> for OperationMode {
    fn from(bytes: &[u8]) -> Self {
        match bytes.first().map(|&b| b).unwrap_or(b'M') {
            b'A' => Self::Auto,
            b'M' => Self::Manual,
            _ => Self::Manual,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum NavigationMode {
    NoFix,
    _3DFix,
    _2DFix,
}

impl Default for NavigationMode {
    fn default() -> Self {
        Self::NoFix
    }
}

impl From<&[u8]> for NavigationMode {
    fn from(bytes: &[u8]) -> Self {
        match bytes.first().map(|&b| b).unwrap_or(b'1') {
            b'1' => Self::NoFix,
            b'2' => Self::_2DFix,
            b'3' => Self::_3DFix,
            _ => Self::NoFix,
        }
    }
}

#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Status(pub bool);

impl From<&[u8]> for Status {
    fn from(bytes: &[u8]) -> Self {
        Self(bytes.first().map(|&b| b).unwrap_or(b'V') == b'A')
    }
}

#[derive(Copy, Clone, Default, PartialEq)]
pub struct IntegerDecimal(isize);

impl IntegerDecimal {
    pub fn new(value: isize, decimal_length: u8) -> Self {
        Self(value << 8 | decimal_length as isize)
    }

    pub fn decimal_length(self) -> u8 {
        self.0 as u8
    }

    pub fn exp(self) -> usize {
        let decimal_length = self.0 as u8;
        10_usize.pow(decimal_length as u32)
    }

    pub fn integer(self) -> isize {
        let number = self.0 >> 8;
        number / self.exp() as isize
    }

    pub fn decimal(self) -> usize {
        let number = self.0 >> 8;
        let number = if number < 0 { -number } else { number } as usize;
        number % self.exp()
    }
}

impl core::ops::AddAssign<isize> for IntegerDecimal {
    fn add_assign(&mut self, value: isize) {
        self.0 += value * self.exp() as isize
    }
}

impl Into<f32> for IntegerDecimal {
    fn into(self) -> f32 {
        let number = self.0 >> 8;
        number as f32 / self.exp() as f32
    }
}

impl Debug for IntegerDecimal {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(f, "{}.{}#{}", self.integer(), self.decimal(), self.decimal_length())
    }
}

impl From<&[u8]> for IntegerDecimal {
    fn from(bytes: &[u8]) -> Self {
        if bytes.len() == 0 {
            return Self::default();
        }
        let mut splitted = bytes.split(|&b| b == b'.');
        let mut integer = 0;
        if let Some(field) = splitted.next() {
            integer = unsafe { utf8(field) }.parse().unwrap_or_default();
        }
        let mut decimal_length = 0;
        let mut decimal = 0;
        if let Some(field) = splitted.next() {
            decimal_length = core::cmp::min(field.len(), 255);
            decimal = unsafe { utf8(&field[..decimal_length]) }.parse().unwrap_or_default();
            if integer < 0 {
                decimal = -decimal
            }
        }
        let exp = 10_isize.pow(decimal_length as u32);
        Self::new(integer * exp + decimal, decimal_length as u8)
    }
}