use crate::point::{Accuracy, SatelliteCount};
use crate::units::Radians;
use byteorder::{LittleEndian, ReadBytesExt};
use std::fs::File;
use std::io::{BufReader, Read, Seek};
use std::iter::IntoIterator;
use std::path::Path;
#[derive(Debug)]
#[allow(missing_docs)]
pub struct Reader<R: Read + Seek> {
pub avgint: f64,
pub devint: f64,
pub maxint: f64,
pub version: Version,
reader: R,
}
impl Reader<BufReader<File>> {
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Reader<BufReader<File>>, std::io::Error> {
let reader = BufReader::new(File::open(path)?);
Reader::new(reader)
}
}
impl<R: Seek + Read> Reader<R> {
fn new(mut reader: R) -> Result<Reader<R>, std::io::Error> {
let mut preamble = [0; 35];
reader.read_exact(&mut preamble)?;
let major = reader.read_u16::<LittleEndian>()?;
let minor = reader.read_u16::<LittleEndian>()?;
let version = Version::new(major, minor);
let avgint = reader.read_f64::<LittleEndian>()?;
let maxint = reader.read_f64::<LittleEndian>()?;
let devint = reader.read_f64::<LittleEndian>()?;
Ok(Reader {
avgint,
devint,
maxint,
reader,
version,
})
}
pub fn read_accuracy(&mut self) -> Result<Option<Accuracy>, std::io::Error> {
use std::io::ErrorKind;
let time = match self.reader.read_f64::<LittleEndian>() {
Ok(time) => time,
Err(err) => match err.kind() {
ErrorKind::UnexpectedEof => return Ok(None),
_ => return Err(err),
},
};
let north = self.reader.read_f64::<LittleEndian>()?;
let east = self.reader.read_f64::<LittleEndian>()?;
let down = self.reader.read_f64::<LittleEndian>()?;
let roll = self.reader.read_f64::<LittleEndian>()?;
let pitch = self.reader.read_f64::<LittleEndian>()?;
let yaw = self.reader.read_f64::<LittleEndian>()?;
let pdop = self.reader.read_f64::<LittleEndian>()?;
let satellite_count = if self.version.specifies_satellite_count() {
let ngps = self.reader.read_u16::<LittleEndian>()?;
let nglonass = self.reader.read_u16::<LittleEndian>()?;
SatelliteCount::Specified {
gps: ngps,
glonass: nglonass,
}
} else {
SatelliteCount::Unspecified(self.reader.read_u16::<LittleEndian>()?)
};
Ok(Some(Accuracy {
time,
y: north,
x: east,
z: down,
roll: Radians::from_degrees(roll),
pitch: Radians::from_degrees(pitch),
yaw: Radians::from_degrees(yaw),
pdop,
satellite_count: Some(satellite_count),
}))
}
}
impl<R: Seek + Read> IntoIterator for Reader<R> {
type Item = Accuracy;
type IntoIter = ReaderIterator<R>;
fn into_iter(self) -> Self::IntoIter {
ReaderIterator { reader: self }
}
}
#[derive(Debug)]
pub struct ReaderIterator<R: Read + Seek> {
reader: Reader<R>,
}
impl<R: Read + Seek> Iterator for ReaderIterator<R> {
type Item = Accuracy;
fn next(&mut self) -> Option<Self::Item> {
self.reader.read_accuracy().unwrap()
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Version {
major: u16,
minor: u16,
}
impl Version {
pub fn new(major: u16, minor: u16) -> Version {
Version { major, minor }
}
fn specifies_satellite_count(&self) -> bool {
self.minor >= 1
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn iter() {
let reader = Reader::from_path("data/sbet_mission_1.poq").unwrap();
let records: Vec<_> = reader.into_iter().zip(0..5571).map(|(r, _)| r).collect();
assert_eq!(5571, records.len());
}
}