diff --git a/src/messages/assignment_mode_command.rs b/src/messages/assignment_mode_command.rs new file mode 100644 index 0000000..00dfaf4 --- /dev/null +++ b/src/messages/assignment_mode_command.rs @@ -0,0 +1,140 @@ +//! Assignment Mode Command (type 16) + +use super::parsers::*; +use super::AisMessageType; +use crate::errors::Result; +use nom::bits::{bits, complete::take as take_bits}; +use nom::IResult; + +#[derive(Debug, PartialEq, Eq)] +pub struct AssignmentModeCommand { + pub message_type: u8, + pub repeat_indicator: u8, + pub mmsi: u32, + pub mmsi1: u32, + pub offset1: u16, + pub increment1: u16, + pub mmsi2: Option, + pub offset2: Option, + pub increment2: Option, +} + +impl<'a> AisMessageType<'a> for AssignmentModeCommand { + fn name(&self) -> &'static str { + "Assignment Mode Command" + } + + fn parse(data: &'a [u8]) -> Result { + let (_, report) = parse_base(data)?; + Ok(report) + } +} + +fn parse_base(data: &[u8]) -> IResult<&[u8], AssignmentModeCommand> { + bits(move |data| -> IResult<_, _> { + let (data, message_type) = take_bits(6u8)(data)?; + let (data, repeat_indicator) = take_bits(2u8)(data)?; + let (data, mmsi) = take_bits(30u32)(data)?; + let (data, _spare) = take_bits::<_, u8, _, _>(2u8)(data)?; + + let (data, mmsi1) = take_bits(30u32)(data)?; + let (data, offset1) = take_bits(12u16)(data)?; + let (data, increment1) = take_bits(10u16)(data)?; + + // Check for remaining bits, if there are enough bits for the second station + let remaining_bits = remaining_bits(data); + + if remaining_bits >= 52 { + let (data, mmsi2) = take_bits(30u32)(data)?; + let (data, offset2) = take_bits(12u16)(data)?; + let (data, increment2) = take_bits(10u16)(data)?; + + Ok(( + data, + AssignmentModeCommand { + message_type, + repeat_indicator, + mmsi, + mmsi1, + offset1, + increment1, + mmsi2: Some(mmsi2), + offset2: Some(offset2), + increment2: Some(increment2), + }, + )) + } else { + // Only one station assignment + Ok(( + data, + AssignmentModeCommand { + message_type, + repeat_indicator, + mmsi, + mmsi1, + offset1, + increment1, + mmsi2: None, + offset2: None, + increment2: None, + }, + )) + } + })(data) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_type16_example_1_single_station() { + let bytestream = b"@01uEO@mMk7P Result { 15 => Ok(AisMessage::Interrogation( interrogation::Interrogation::parse(unarmored)?, )), + 16 => Ok(AisMessage::AssignmentModeCommand( + assignment_mode_command::AssignmentModeCommand::parse(unarmored)?, + )), 17 => Ok(AisMessage::DgnssBroadcastBinaryMessage( dgnss_broadcast_binary_message::DgnssBroadcastBinaryMessage::parse(unarmored)?, )),