Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment_Mode_Command_Type_16 #6

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
pull_request:
workflow_dispatch:

jobs:
test:
name: ${{ matrix.os }} / ${{ matrix.rust }} (${{ matrix.feature }})
Expand All @@ -19,18 +19,15 @@ jobs:
RUST_BACKTRACE: full
RUSTV: ${{ matrix.rust }}
steps:
- uses: actions/checkout@v3

- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust ${{ matrix.rust }}
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
profile: minimal
override: true
components: rustfmt, clippy

- name: Cache cargo registry
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
Expand Down Expand Up @@ -65,4 +62,4 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --no-default-features --features "${{ matrix.feature }}"
args: --verbose --no-default-features --features "${{ matrix.feature }}"
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "ais"
version = "0.11.0"
authors = ["Kevin Rauwolf <sweetpea-git@tentacle.net>"]
authors = ["Kevin R <sweetpea-git@tentacle.net>"]
description = "An AIS parser library"
homepage = "https://github.com/squidpickles/ais"
repository = "https://github.com/squidpickles/ais.git"
Expand Down
145 changes: 145 additions & 0 deletions src/messages/assignment_mode_command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//! Assignment Mode Command (type 16)

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)
}

// Helper function to calculate remaining bits
fn remaining_bits(data: (&[u8], usize)) -> usize {
(data.0.len() * 8) - data.1
}

#[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 @@ -4,6 +4,7 @@ use crate::lib;
use crate::sentence::AisRawData;

pub mod aid_to_navigation_report;
pub mod assignment_mode_command;
pub mod base_station_report;
pub mod binary_broadcast_message;
pub mod data_link_management_message;
Expand Down Expand Up @@ -42,6 +43,7 @@ pub enum AisMessage {
AidToNavigationReport(aid_to_navigation_report::AidToNavigationReport),
StaticDataReport(static_data_report::StaticDataReport),
UtcDateResponse(utc_date_response::UtcDateResponse),
AssignmentModeCommand(assignment_mode_command::AssignmentModeCommand),
}

/// Trait that describes specific types of AIS messages
Expand Down Expand Up @@ -77,6 +79,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
10 changes: 2 additions & 8 deletions src/messages/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ impl EpfdType {
}
}


#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum ShipType {
Reserved(u8),
Expand Down Expand Up @@ -241,18 +240,13 @@ impl From<ShipType> for u8 {
}
}

#[derive(Debug, PartialEq, Eq)]
#[derive(Default, Debug, PartialEq, Eq)]
pub enum Dte {
Ready,
#[default]
NotReady,
}

impl Default for Dte {
fn default() -> Self {
Dte::NotReady
}
}

impl From<u8> for Dte {
fn from(value: u8) -> Self {
match value {
Expand Down
3 changes: 3 additions & 0 deletions src/sentence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,9 @@ mod tests {
fragment_number: 1,
message_id: None,
channel: Some('A'),
#[cfg(any(feature = "std", feature = "alloc"))]
data: GOOD_CHECKSUM[AIS_START_IDX..AIS_END_IDX].into(),
#[cfg(all(not(feature = "std"), not(feature = "alloc")))]
data: GOOD_CHECKSUM[AIS_START_IDX..AIS_END_IDX]
.try_into()
.unwrap(),
Expand Down
Loading