diff --git a/copper_clock/src/lib.rs b/copper_clock/src/lib.rs index 96fd7e6c0..9f9394c74 100644 --- a/copper_clock/src/lib.rs +++ b/copper_clock/src/lib.rs @@ -46,7 +46,9 @@ impl RobotClock { ) } - pub fn elapsed(&self) -> Duration { + // Now returns the time that passed since the reference time, usually the start time. + // It is a monotonically increasing value. + pub fn now(&self) -> Duration { self.inner.now() - self.ref_time } } @@ -64,9 +66,9 @@ mod tests { #[test] fn test_mock() { let (clock, mock) = RobotClock::mock(); - assert_eq!(clock.elapsed(), Duration::from_secs(0)); + assert_eq!(clock.now(), Duration::from_secs(0)); mock.increment(Duration::from_secs(1)); - assert_eq!(clock.elapsed(), Duration::from_secs(1)); + assert_eq!(clock.now(), Duration::from_secs(1)); } #[test] @@ -74,7 +76,7 @@ mod tests { let tolerance_ms = 10; let clock = RobotClock::from_ref_time(1_000_000_000); assert_relative_eq!( - clock.elapsed().as_millis() as f64, + clock.now().as_millis() as f64, Duration::from_secs(1).as_millis() as f64, epsilon = tolerance_ms as f64 ); diff --git a/copper_datalogger/Cargo.toml b/copper_datalogger/Cargo.toml new file mode 100644 index 000000000..3c9aee94d --- /dev/null +++ b/copper_datalogger/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "copper_datalogger" +version = "0.1.0" +edition = "2021" + +[dependencies] +bincode = { version = "2.0.0-rc.3", features = ["serde", "bincode_derive"] } +bincode_derive = { version = "2.0.0-rc.3" } +memmap2 = "0.9.4" +libc = "0.2.155" diff --git a/copper_datalogger/src/lib.rs b/copper_datalogger/src/lib.rs new file mode 100644 index 000000000..cea425dd7 --- /dev/null +++ b/copper_datalogger/src/lib.rs @@ -0,0 +1,95 @@ +use libc; + +use bincode::encode_into_slice; +use bincode_derive::{Decode, Encode}; + +use bincode::config::Configuration; +use memmap2::MmapMut; +use std::fs::OpenOptions; + +const MAIN_MAGIC: [u8; 4] = [0xB4, 0xA5, 0x50, 0xFF]; + +const SECTION_MAGIC: [u8; 2] = [0xFA, 0x57]; + +#[derive(Encode, Decode)] +struct MainHeader { + magic: [u8; 4], + first_section_offset: u16, // This is to align with a page at write time. +} + +#[derive(Encode, Decode)] +enum EntryType { + StructuredLogLine, + CopperList, +} + +#[derive(Encode, Decode)] +struct SectionHeader { + magic: [u8; 2], + entry_type: EntryType, + section_size: u32, // offset of section_magic + section_size -> should be the index of the next section_magic +} + +pub struct DataLogger { + file: MmapMut, + page_size: usize, + current_position: usize, + config: Configuration, +} + +impl DataLogger { + pub fn new(file_path: &str) -> std::io::Result { + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(file_path)?; + let config = bincode::config::standard(); + let mut mmap = unsafe { MmapMut::map_mut(&file)? }; + let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; + let mmap_start_addr = &mmap[0] as *const u8 as usize; + let next_aligned_addr = (mmap_start_addr + page_size - 1) & !(page_size - 1); + let main_header = MainHeader { + magic: MAIN_MAGIC, + first_section_offset: (next_aligned_addr - mmap_start_addr) as u16, + }; + let nb_bytes = encode_into_slice(&main_header, &mut mmap[..], config) + .expect("Failed to encode main header"); + + Ok(Self { + file: mmap, + page_size, + current_position: nb_bytes, + config, + }) + } + + pub fn add_section(&mut self, entry_type: EntryType, section_size: u32) { + let section_header = SectionHeader { + magic: SECTION_MAGIC, + entry_type, + section_size, + }; + + let nb_bytes = encode_into_slice( + §ion_header, + &mut self.file[self.current_position..], + self.config, + ) + .expect("Failed to encode section header"); + self.current_position += nb_bytes; + } + + #[inline] + fn allocated_len(&self) -> usize { + self.file.len() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() {} +}