-
-
Save Restioson/a362b26f64c28e078f3a3b16297c701d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* config.rs */ | |
pub const SERIAL_DATA_LABELS: &[&'static str] = &[ | |
"latitude", | |
"longitude", | |
"altitude", | |
"course", | |
"heading", | |
"speed", | |
"year", | |
"month", | |
"day", | |
"hour", | |
"minute", | |
"second", | |
"temperature", | |
"humidity", | |
"pitch", | |
"roll", | |
"object_distance_front", | |
"object_distance_back", | |
]; | |
pub const SERIAL_SEPARATOR: char = ' '; | |
pub const SERIAL_TERMINATOR: char = '\n'; | |
/* protocol.rs */ | |
#[derive(Debug, Deserialize, PartialEq)] | |
pub struct Data { | |
latitude: f64, | |
longitude: f64, | |
altitude: f64, | |
course: f32, | |
heading: f32, | |
speed: f32, | |
year: u16, | |
month: u8, | |
day: u8, | |
hour: u8, | |
minute: u8, | |
second: u8, | |
temperature: f32, | |
humidity: f32, | |
pitch: f32, | |
roll: f32, | |
object_distance_front: u16, | |
object_distance_back: f32, | |
} | |
pub struct SerialParser { | |
data_records: csv::DeserializeRecordsIntoIter<Cursor<Vec<u8>>, Data>, | |
} | |
impl SerialParser { | |
pub fn new() -> Self { | |
let mut csv_reader = csv::ReaderBuilder::new() | |
.delimiter(config::SERIAL_SEPARATOR as u8) | |
.terminator(csv::Terminator::Any(config::SERIAL_TERMINATOR as u8)) | |
.from_reader(Cursor::new(Vec::new())); | |
// Add the headers | |
let mut headers: String = config::SERIAL_DATA_LABELS | |
.iter() | |
.map(|it| it.to_string()) | |
.collect::<Vec<_>>() | |
.join(config::SERIAL_SEPARATOR.encode_utf8(&mut [0u8; 2])); | |
headers.push(config::SERIAL_TERMINATOR); | |
// Write headers to csv reader | |
let mut position = csv_reader.position().clone(); | |
position.set_byte(0); | |
{ | |
let cursor = csv_reader.get_mut(); | |
cursor.set_position(position.byte()); | |
cursor.write_all(headers.as_bytes()).unwrap(); | |
// TODO | |
eprintln!("Cursor contents: {:?}", cursor.get_ref()); | |
} | |
csv_reader | |
.seek_raw(std::io::SeekFrom::Start(position.byte()), position.clone()) | |
.unwrap(); | |
// TODO cleanup all these get_mut's | |
csv_reader.get_mut().set_position(position.byte()); | |
csv_reader.get_mut().write_all(headers.as_bytes()).expect( | |
"Error writing into Vec, meaning it's full (shouldn't be) -- this is a bug!", | |
); | |
csv_reader.get_mut().set_position(0); | |
// Read headers | |
csv_reader.records().next(); | |
// Clear cursor of headers | |
csv_reader.get_mut().get_mut().clear(); | |
SerialParser { data_records: csv_reader.into_deserialize() } | |
} | |
pub fn parse<'a>(&mut self, packet: &'a str) -> Result<Option<Message>, ParseError<'a>> { | |
let tag = match packet.split(config::SERIAL_SEPARATOR).next() { | |
Some(tag) => tag, | |
None => return Err(ParseError::NoTag), | |
}; | |
trace!("{}", tag); // TODO | |
trace!("\"{}\"", packet); // TODO | |
if packet.len() < tag.len() + 1 { | |
return Err(ParseError::PacketTooShort); | |
} | |
// Remove the tag and delimiter, and trim leading/trailing spaces | |
let data = packet[tag.len() + 1..].trim(); | |
// TODO remove | |
trace!("\"{}\"", data); | |
trace!("{}", data.len()); | |
// TODO | |
eprintln!("\"{}\"", data); | |
eprintln!("{}", data.len()); | |
// Thanks to daschl | |
// https://github.com/BurntSushi/rust-csv/issues/91 | |
let mut position = self.data_records.reader().position().clone(); | |
position.set_byte(0); | |
{ | |
let cursor = self.data_records.reader_mut().get_mut(); | |
cursor.set_position(position.byte()); | |
cursor.write_all(data.as_bytes()).unwrap(); | |
// TODO | |
eprintln!("Cursor contents: {:?}", cursor.get_ref()); | |
} | |
{ | |
let reader = self.data_records.reader_mut(); | |
reader | |
.seek_raw(std::io::SeekFrom::Start(position.byte()), position.clone()) | |
.unwrap(); | |
reader.get_mut().set_position(position.byte()); | |
} | |
let value = match tag { | |
"DATA" => { | |
let value = match self.data_records.next() { | |
Some(Ok(data)) => Ok(Some(Message::Data(data))), | |
Some(Err(error)) => Err(ParseError::CsvError(error)), | |
None => Ok(None), | |
}; | |
// TODO needed | |
// Clear cursor to prevent overflow | |
self.data_records.reader_mut().get_mut().get_mut().clear(); | |
value | |
} | |
"CMD" => { | |
match data { | |
// TODO capitalised? | |
"SHUTDOWN" => Ok(Some(Message::Command(Command::Shutdown))), | |
command => Err(ParseError::InvalidCommand(command)), | |
} | |
} | |
_ => Err(ParseError::InvalidTag(tag)), // Unknown tag | |
}; | |
value | |
} | |
} | |
// (test to make it runnable) | |
#[cfg(test)] | |
mod test { | |
use super::*; | |
/* Error in this func */ | |
#[test] | |
fn csv_dynamic() { | |
let data = "-100.00 100.00 100.00 77.39 195.9 1.111 2017 9 29 13 14 48 0 0 2.1 -1.3 82 67.3\n"; | |
/* Set up reader */ | |
let mut csv_reader = csv::ReaderBuilder::new() | |
.delimiter(config::SERIAL_SEPARATOR as u8) | |
.terminator(csv::Terminator::Any(config::SERIAL_TERMINATOR as u8)) | |
.from_reader(Cursor::new(Vec::new())); | |
// Add the headers | |
let mut headers: String = config::SERIAL_DATA_LABELS | |
.iter() | |
.map(|it| it.to_string()) | |
.collect::<Vec<_>>() | |
.join(config::SERIAL_SEPARATOR.encode_utf8(&mut [0u8; 2])); | |
eprintln!("Headers: {}", headers); | |
headers.push(config::SERIAL_TERMINATOR); | |
// Write headers to csv reader | |
let mut position = csv_reader.position().clone(); | |
position.set_byte(0); | |
{ | |
let cursor = csv_reader.get_mut(); | |
cursor.set_position(position.byte()); | |
cursor.write_all(headers.as_bytes()).unwrap(); | |
// TODO | |
eprintln!("Cursor contents: {:?}", cursor.get_ref()); | |
} | |
csv_reader | |
.seek_raw(std::io::SeekFrom::Start(position.byte()), position.clone()) | |
.unwrap(); | |
// TODO cleanup all these get_mut's | |
csv_reader.get_mut().set_position(position.byte()); | |
csv_reader.get_mut().write_all(headers.as_bytes()).expect( | |
"Error writing into Vec, meaning it's full (shouldn't be) -- this is a bug!", | |
); | |
csv_reader.get_mut().set_position(0); | |
// Read headers | |
csv_reader.records().next(); | |
// Clear cursor of headers | |
csv_reader.get_mut().get_mut().clear(); | |
/* Feed data */ | |
let mut position = csv_reader.position().clone(); | |
position.set_byte(0); | |
{ | |
let cursor = csv_reader.get_mut(); | |
cursor.set_position(position.byte()); | |
cursor.write_all(data.as_bytes()).unwrap(); | |
// TODO | |
eprintln!("Cursor contents: {:?}", cursor.get_ref()); | |
} | |
{ | |
let reader = &mut csv_reader; | |
reader | |
.seek_raw(std::io::SeekFrom::Start(position.byte()), position.clone()) | |
.unwrap(); | |
reader.get_mut().set_position(position.byte()); | |
} | |
/* Parse */ | |
println!("{:?}", csv_reader.deserialize::<Data>().next().unwrap().unwrap()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment