Skip to content

Commit

Permalink
feat: add support for ais msg type 16
Browse files Browse the repository at this point in the history
  • Loading branch information
salsabiljb committed Aug 21, 2024
1 parent d23349e commit 929fefc
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 0 deletions.
140 changes: 140 additions & 0 deletions src/messages/assignment_mode_command.rs
Original file line number Diff line number Diff line change
@@ -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<u32>,
pub offset2: Option<u16>,
pub increment2: Option<u16>,
}

impl<'a> AisMessageType<'a> for AssignmentModeCommand {
fn name(&self) -> &'static str {
"Assignment Mode Command"
}

fn parse(data: &'a [u8]) -> Result<Self> {
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<P00";
let bitstream = crate::messages::unarmor(bytestream, 0).unwrap();
let report = AssignmentModeCommand::parse(bitstream.as_ref()).unwrap();

assert_eq!(report.message_type, 16);
assert_eq!(report.repeat_indicator, 0);
assert_eq!(report.mmsi, 2053501);
assert_eq!(report.mmsi1, 224251000);
assert_eq!(report.offset1, 200);
assert_eq!(report.increment1, 0);
assert_eq!(report.mmsi2, None);
assert_eq!(report.offset2, None);
assert_eq!(report.increment2, None);
}

#[test]
fn test_type16_example_2_single_station() {
let bytestream = b"@01uEO@hsqJ0<P00";
let bitstream = crate::messages::unarmor(bytestream, 0).unwrap();
let report = AssignmentModeCommand::parse(bitstream.as_ref()).unwrap();

assert_eq!(report.message_type, 16);
assert_eq!(report.repeat_indicator, 0);
assert_eq!(report.mmsi, 2053501);
assert_eq!(report.mmsi1, 205252000);
assert_eq!(report.offset1, 200);
assert_eq!(report.increment1, 0);
assert_eq!(report.mmsi2, None);
assert_eq!(report.offset2, None);
assert_eq!(report.increment2, None);
}

#[test]
fn test_type16_example_with_two_stations() {
let bytestream = b"@6STUk004lQ206bCKNOBAb6SJ@5s";
let bitstream = crate::messages::unarmor(bytestream, 0).unwrap();
let report = AssignmentModeCommand::parse(bitstream.as_ref()).unwrap();

assert_eq!(report.message_type, 16);
assert_eq!(report.repeat_indicator, 0);
assert_eq!(report.mmsi, 439952844);
assert_eq!(report.mmsi1, 315920);
assert_eq!(report.offset1, 2049);
assert_eq!(report.increment1, 681);
assert_eq!(report.mmsi2, Some(230137673));
assert_eq!(report.offset2, Some(424));
assert_eq!(report.increment2, Some(419));
}
}
5 changes: 5 additions & 0 deletions src/messages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::sentence::AisRawData;

pub mod addressed_safety_related;
pub mod aid_to_navigation_report;
pub mod assignment_mode_command;
pub mod base_station_report;
pub mod binary_addressed;
pub mod binary_broadcast_message;
Expand Down Expand Up @@ -54,6 +55,7 @@ pub enum AisMessage {
SafetyRelatedAcknowledgment(safety_related_acknowledgment::SafetyRelatedAcknowledge),
LongRangeAisBroadcastMessage(long_range_ais_broadcast::LongRangeAisBroadcastMessage),
BinaryAddressedMessage(binary_addressed::BinaryAddressedMessage),
AssignmentModeCommand(assignment_mode_command::AssignmentModeCommand),
}

/// Trait that describes specific types of AIS messages
Expand Down Expand Up @@ -104,6 +106,9 @@ pub fn parse(unarmored: &[u8]) -> Result<AisMessage> {
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)?,
)),
Expand Down

0 comments on commit 929fefc

Please sign in to comment.