diff --git a/src/switch_data.rs b/src/switch_data.rs index a06f79e..9ad5cf2 100644 --- a/src/switch_data.rs +++ b/src/switch_data.rs @@ -1,4 +1,4 @@ -use crate::types::{RangeIndex, Reverse}; +use crate::types::{Command, RangeIndex}; use binrw::{BinRead, BinWrite}; #[derive(Debug, BinRead, BinWrite)] @@ -9,5 +9,5 @@ pub struct SwitchData { range_index: RangeIndex, #[brw(pad_after = 1)] - reverse: Reverse, + command: Command, } diff --git a/src/types/command.rs b/src/types/command.rs new file mode 100644 index 0000000..3269b31 --- /dev/null +++ b/src/types/command.rs @@ -0,0 +1,52 @@ +use crate::types::util::primitive::read_u8_bits; +use crate::types::{ProfilePointDetection, StepDirection}; +use binrw::meta::{EndianKind, ReadEndian, WriteEndian}; +use binrw::{BinRead, BinResult, Endian}; +use std::io::{Read, Seek}; + +const MASK_STEP_DIRECTION: u8 = 0b0100_0000; +const SHIFT_STEP_DIRECTION: usize = 6; + +const MASK_PROFILE_POINT_DETECTION: u8 = 0b0000_0001; + +#[derive(Debug, Clone, Eq, PartialEq, derive_new::new)] +pub struct Command { + pub profile_point_detection: ProfilePointDetection, + pub step_direction: StepDirection, +} + +impl ReadEndian for Command { + const ENDIAN: EndianKind = EndianKind::None; +} + +impl WriteEndian for Command { + const ENDIAN: EndianKind = EndianKind::None; +} + +impl BinRead for Command { + type Args<'a> = (); + + fn read(reader: &mut R) -> BinResult + where + Self: ReadEndian, + { + let raw = u8::read(reader)?; + let pos = reader.stream_position()?; + + let profile_point_detection = + read_u8_bits::(raw, MASK_PROFILE_POINT_DETECTION, 0, pos)?; + let step_direction = + read_u8_bits::(raw, MASK_STEP_DIRECTION, SHIFT_STEP_DIRECTION, pos)?; + + Ok(Self { profile_point_detection, step_direction }) + } + + #[inline] + fn read_options( + reader: &mut R, + _: Endian, + _: Self::Args<'_>, + ) -> BinResult { + Self::read(reader) + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs index 492a9e0..ba06495 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,5 +1,6 @@ mod acceleration; mod angle; +mod command; mod config; mod data; mod data_bits; @@ -13,14 +14,15 @@ mod motion_config; mod motor_calibrate; pub mod primitive; mod profile_grid; +mod profile_point_detection; mod range_index; -mod reverse; mod sensor_available; mod sensor_information; mod sonar_return_header; mod sonar_return_magic; mod sonar_return_status; mod sonar_type; +mod step_direction; mod step_size; mod transducer; mod util; @@ -28,6 +30,7 @@ mod zero; pub use acceleration::Acceleration; pub use angle::Angle; +pub use command::Command; pub use config::Config; pub use data_bits::DataBits; pub use data_length::DataSizeIndex; @@ -38,14 +41,15 @@ pub use logf::Logf; pub use mode::Mode; pub use motion_config::MotionConfig; pub use profile_grid::ProfileGrid; +pub use profile_point_detection::ProfilePointDetection; pub use range_index::RangeIndex; -pub use reverse::Reverse; pub use sensor_available::SensorAvailable; pub use sensor_information::SensorInformation; pub use sonar_return_header::SonarReturnHeader; pub use sonar_return_magic::SonarReturnMagic; pub use sonar_return_status::SonarReturnStatus; pub use sonar_type::SonarType; +pub use step_direction::StepDirection; pub use step_size::StepSize; pub use transducer::Transducer; pub use zero::Zero; diff --git a/src/types/primitive/profile_range.rs b/src/types/primitive/profile_range.rs index 1b5ceda..e2fa443 100644 --- a/src/types/primitive/profile_range.rs +++ b/src/types/primitive/profile_range.rs @@ -16,3 +16,43 @@ pub fn write(profile_range: &f32, range_index: &RangeIndex) -> BinResult<()> { value.write_options(writer, endian, ())?; Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::types::primitive::u14; + use crate::types::RangeIndex; + use binrw::{io::Cursor, BinRead, BinWrite, Endian}; + use std::ops::Range; + + use log::info; + use test_log::test; + + const BINARY_ENDIAN: Endian = Endian::Little; + const BINARY_CASES: [(f32, [u8; 2], RangeIndex); 2] = + [(16.383, [0b1111_1111, 0b0111_1111], RangeIndex::X2m), (0.0, [0, 0], RangeIndex::X25cm)]; + + #[test] + fn test_parse() { + for &(want, bytes, range_index) in BINARY_CASES.iter() { + info!("Parsing {bytes:?} with RangeIndex {range_index:?}, want {want:?}"); + let mut cursor = Cursor::new(bytes); + let got = parse(&mut cursor, BINARY_ENDIAN, (range_index,)) + .expect("It should not return an error"); + assert!((got - want).abs() < f32::EPSILON); + } + } + + #[test] + fn test_write() { + for (profile_range, want, range_index) in BINARY_CASES.iter() { + info!("Writing {profile_range:?} with RangeIndex {range_index:?}, want {want:?}"); + let mut cursor = Cursor::new(Vec::new()); + write(&profile_range, &mut cursor, BINARY_ENDIAN, (range_index,)) + .expect("It should not return an error"); + let inner = cursor.into_inner(); + let got = inner.as_slice(); + assert_eq!(want, got); + } + } +} diff --git a/src/types/profile_point_detection.rs b/src/types/profile_point_detection.rs new file mode 100644 index 0000000..9dcde37 --- /dev/null +++ b/src/types/profile_point_detection.rs @@ -0,0 +1,9 @@ +use num_derive::{FromPrimitive, ToPrimitive}; + +/// New in Ethernet Specification v1.01, revision `03` from March 22, 2023. +#[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)] +#[repr(u8)] +pub enum ProfilePointDetection { + CenterOfPulse = 0, + StartOfPulse = 1, +} diff --git a/src/types/reverse.rs b/src/types/step_direction.rs similarity index 69% rename from src/types/reverse.rs rename to src/types/step_direction.rs index ce449b4..cdd33b3 100644 --- a/src/types/reverse.rs +++ b/src/types/step_direction.rs @@ -2,27 +2,26 @@ use binrw::{BinRead, BinWrite}; use num_derive::{FromPrimitive, ToPrimitive}; use std::fmt::{Display, Formatter}; -#[derive(Debug, Eq, PartialEq, Copy, Clone, BinRead, BinWrite, ToPrimitive, FromPrimitive)] +#[derive(Debug, Eq, PartialEq, Copy, Clone, ToPrimitive, FromPrimitive)] #[repr(u8)] -#[brw(repr = u8)] #[cfg_attr( target_family = "wasm", derive(tsify::Tsify, serde::Serialize, serde::Deserialize), tsify(into_wasm_abi, from_wasm_abi), serde(rename_all = "UPPERCASE") )] -pub enum Reverse { - Normal = 0b0000_0000, - Reverse = 0b0100_0000, +pub enum StepDirection { + Normal = 0, + Reverse = 1, } -impl Default for Reverse { +impl Default for StepDirection { fn default() -> Self { Self::Normal } } -impl Display for Reverse { +impl Display for StepDirection { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, @@ -44,13 +43,16 @@ mod tests { #[test] fn test_default() { - let got = Reverse::default(); - assert_eq!(Reverse::Normal, got); + let got = StepDirection::default(); + assert_eq!(StepDirection::Normal, got); } #[test] fn test_display() { - let cases = vec![(Reverse::Normal, "normal"), (Reverse::Reverse, "reverse step direction")]; + let cases = vec![ + (StepDirection::Normal, "normal"), + (StepDirection::Reverse, "reverse step direction"), + ]; for (reverse, want) in cases { info!("Displaying {reverse:?}, expecting {want:?}");