pub fn from_mmsi(mmsi: u32) -> u32 {
mmsi
}
pub fn from_mmsi_optional(mmsi: u32) -> Option<u32> {
if mmsi == 0 {
None
} else {
Some(mmsi)
}
}
pub fn from_turn(raw: u8) -> Option<f32> {
let signed_val = raw as i8;
match signed_val {
-128 => None, -127 => Some(-720.0), 127 => Some(720.0), val => {
let rot_ais = val as f32;
Some((rot_ais / 4.733).powi(2).copysign(rot_ais))
}
}
}
pub fn from_speed(raw: u16) -> Option<f32> {
match raw {
1023 => None, 1022 => Some(102.2), val => Some(val as f32 / 10.0),
}
}
pub fn from_longitude(raw: u32) -> Option<f64> {
let signed_val = if raw & 0x08000000 != 0 {
(raw as i32) | (0xF0000000u32 as i32)
} else {
raw as i32
};
if signed_val == 0x6791AC0 {
None
} else {
Some(signed_val as f64 / 600000.0)
}
}
pub fn from_latitude(raw: u32) -> Option<f64> {
let signed_val = if raw & 0x04000000 != 0 {
(raw as i32) | (0xF8000000u32 as i32)
} else {
raw as i32
};
if signed_val == 0x3412140 {
None
} else {
Some(signed_val as f64 / 600000.0)
}
}
pub fn from_course(raw: u16) -> Option<f32> {
match raw {
3600..=4095 => None, val => Some(val as f32 / 10.0),
}
}
pub fn from_heading(raw: u16) -> Option<u16> {
if raw >= 360 {
None
} else {
Some(raw)
}
}
pub fn from_imo(raw: u32) -> Option<u32> {
if raw == 0 {
None
} else {
Some(raw)
}
}
pub fn from_draught(raw: u8) -> Option<f32> {
match raw {
0 => None, 255 => Some(25.5), val => Some(val as f32 / 10.0),
}
}
pub fn from_altitude(raw: u16) -> Option<u16> {
if raw == 4095 {
None
} else {
Some(raw)
}
}
pub fn from_year(raw: u16) -> Option<u16> {
if raw == 0 {
None
} else {
Some(raw)
}
}
pub fn from_month(raw: u8) -> Option<u8> {
if raw == 0 {
None
} else {
Some(raw)
}
}
pub fn from_day(raw: u8) -> Option<u8> {
if raw == 0 {
None
} else {
Some(raw)
}
}
pub fn from_hour(raw: u8) -> Option<u8> {
if raw == 24 {
None
} else {
Some(raw)
}
}
pub fn from_minute(raw: u8) -> Option<u8> {
if raw == 60 {
None
} else {
Some(raw)
}
}
pub fn from_second(raw: u8) -> Option<u8> {
if raw == 60 {
None
} else {
Some(raw)
}
}
pub fn from_sixbit_ascii_18(raw: u32, length: usize) -> String {
let mut result = String::new();
for i in 0..length {
let shift = 6 * (length - 1 - i);
let char_bits = (raw >> shift) & 0x3F;
let ch = match char_bits as u8 {
0 => '@', 1..=31 => (char_bits as u8 + 64) as char, 32..=63 => char_bits as u8 as char, _ => '@',
};
if ch != '@' {
result.push(ch);
}
}
result.trim().to_string()
}
pub fn from_sixbit_ascii_42(raw: u64, length: usize) -> String {
let mut result = String::new();
for i in 0..length {
let shift = 6 * (length - 1 - i);
let char_bits = (raw >> shift) & 0x3F;
let ch = match char_bits as u8 {
0 => '@', 1..=31 => (char_bits as u8 + 64) as char, 32..=63 => char_bits as u8 as char, _ => '@',
};
if ch != '@' {
result.push(ch);
}
}
result.trim().to_string()
}
pub fn from_sixbit_ascii(raw: u64, length: usize) -> String {
let mut result = String::new();
for i in 0..length {
let shift = 6 * (length - 1 - i);
let char_bits = (raw >> shift) & 0x3F;
let ch = match char_bits as u8 {
0 => '@', 1..=31 => (char_bits as u8 + 64) as char, 32..=63 => char_bits as u8 as char, _ => '@',
};
if ch != '@' {
result.push(ch);
}
}
result.trim().to_string()
}
pub fn from_10th_minutes_longitude(raw: u32) -> f64 {
if raw == 0x3FFFF {
0.0
} else {
let signed = if raw & 0x20000 != 0 {
(raw | 0xFFFC0000) as i32
} else {
raw as i32
};
signed as f64 / 10.0
}
}
pub fn from_10th_minutes_latitude(raw: u32) -> f64 {
if raw == 0x1FFFF {
0.0
} else {
let signed = if raw & 0x10000 != 0 {
(raw | 0xFFFE0000) as i32
} else {
raw as i32
};
signed as f64 / 10.0
}
}
pub fn from_sixbit_ascii_120(raw: u128, length: usize) -> String {
let mut result = String::new();
for i in 0..length {
let shift = 6 * (length - 1 - i);
let char_bits = (raw >> shift) & 0x3F;
let ch = match char_bits as u8 {
0 => '@', 1..=31 => (char_bits as u8 + 64) as char, 32..=63 => char_bits as u8 as char, _ => '@',
};
if ch != '@' {
result.push(ch);
}
}
result.trim().to_string()
}
pub fn from_sixbit_ascii_optional(raw: u128, length: usize) -> Option<String> {
let result = from_sixbit_ascii_120(raw, length);
if result.is_empty() {
None
} else {
Some(result)
}
}
pub fn from_sixbit_ascii_48(raw: u64, length: usize) -> String {
let mut result = String::new();
for i in 0..length {
let shift = 6 * (length - 1 - i);
let char_bits = (raw >> shift) & 0x3F;
let ch = match char_bits as u8 {
0 => '@', 1..=31 => (char_bits as u8 + 64) as char, 32..=63 => char_bits as u8 as char, _ => '@',
};
if ch != '@' {
result.push(ch);
}
}
result.trim().to_string()
}
pub fn from_10th_u16(raw: u16) -> f32 {
raw as f32 / 10.0
}
pub fn from_100th_u16(raw: u16) -> f32 {
raw as f32 / 100.0
}
pub fn from_variable_binary_data(bits: deku::bitvec::BitVec) -> Vec<u8> {
let mut result = Vec::new();
let mut byte_buffer = 0u8;
let mut bit_count = 0;
for bit in bits.iter() {
byte_buffer = (byte_buffer << 1) | (*bit as u8);
bit_count += 1;
if bit_count == 8 {
result.push(byte_buffer);
byte_buffer = 0;
bit_count = 0;
}
}
if bit_count > 0 {
byte_buffer <<= 8 - bit_count;
result.push(byte_buffer);
}
result
}
pub fn from_10th_minutes(raw: u32, bits: usize) -> f64 {
let max_val = (1u32 << bits) - 1;
if raw == max_val {
0.0
} else {
let sign_bit = 1u32 << (bits - 1);
let signed = if raw & sign_bit != 0 {
let mask = (!0u32) << bits;
(raw | mask) as i32
} else {
raw as i32
};
signed as f64 / 10.0
}
}
pub fn from_longitude_600(raw: u32) -> Option<f64> {
if raw == 0x3FFFF {
None
} else {
let signed = if raw & 0x20000 != 0 {
(raw | 0xFFFC0000) as i32
} else {
raw as i32
};
Some(signed as f64 / 600.0)
}
}
pub fn from_latitude_600(raw: u32) -> Option<f64> {
if raw == 0x1FFFF {
None
} else {
let signed = if raw & 0x10000 != 0 {
(raw | 0xFFFE0000) as i32
} else {
raw as i32
};
Some(signed as f64 / 600.0)
}
}
pub fn from_speed_longrange(raw: u8) -> Option<u8> {
if raw == 63 {
None
} else {
Some(raw)
}
}
pub fn from_course_longrange(raw: u16) -> Option<u16> {
if raw >= 360 {
None
} else {
Some(raw)
}
}
pub fn from_speed_sar(raw: u16) -> Option<u16> {
if raw == 1023 {
None
} else {
Some(raw)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_turn() {
assert_eq!(from_turn(0x80), None); assert_eq!(from_turn(0), Some(0.0));
let val = 20.0_f32;
let expected_rot = (val / 4.733).powi(2);
assert!((from_turn(20).unwrap() - expected_rot).abs() < 1e-6);
let val = -20.0_f32;
let expected_rot = -(val / 4.733).powi(2);
assert!((from_turn(0xec).unwrap() - expected_rot).abs() < 1e-6);
assert_eq!(from_turn(127), Some(720.0));
assert_eq!(from_turn(0x81), Some(-720.0)); }
#[test]
fn test_from_speed() {
assert_eq!(from_speed(0), Some(0.0));
assert_eq!(from_speed(100), Some(10.0));
assert_eq!(from_speed(1023), None);
}
#[test]
fn test_from_longitude() {
assert_eq!(from_longitude(0), Some(0.0));
assert_eq!(from_longitude(0x6791AC0), None);
assert!((from_longitude(600000).unwrap() - 1.0).abs() < 0.000001);
let neg_one_raw = 0x10000000 - 600000; assert!((from_longitude(neg_one_raw).unwrap() - (-1.0)).abs() < 0.000001);
}
#[test]
fn test_from_latitude() {
assert_eq!(from_latitude(0), Some(0.0));
assert_eq!(from_latitude(0x3412140), None);
assert!((from_latitude(600000).unwrap() - 1.0).abs() < 0.000001);
let neg_one_raw = 0x08000000 - 600000; assert!((from_latitude(neg_one_raw).unwrap() - (-1.0)).abs() < 0.000001);
}
#[test]
fn test_from_course() {
assert_eq!(from_course(0), Some(0.0));
assert_eq!(from_course(900), Some(90.0));
assert_eq!(from_course(3600), None); }
#[test]
fn test_from_draught() {
assert_eq!(from_draught(0), None);
assert_eq!(from_draught(122), Some(12.2));
assert_eq!(from_draught(255), Some(25.5));
}
#[test]
fn test_sixbit_ascii_ais_standard() {
assert_eq!(from_sixbit_ascii(6 << 30, 6).chars().next().unwrap(), 'F'); assert_eq!(from_sixbit_ascii(15 << 30, 6).chars().next().unwrap(), 'O'); assert_eq!(from_sixbit_ascii(51 << 30, 6).chars().next().unwrap(), '3'); assert_eq!(from_sixbit_ascii(56 << 30, 6).chars().next().unwrap(), '8');
}
#[test]
fn test_variable_binary_data() {
use deku::bitvec::BitVec;
let mut bits = BitVec::new();
for &bit in &[true, true, true, false, true, false, true, true] {
bits.push(bit);
}
let result = from_variable_binary_data(bits);
assert_eq!(result, vec![0xEB]);
let mut bits = BitVec::new();
for &bit in &[true, true, true, true, false] {
bits.push(bit);
}
let result = from_variable_binary_data(bits);
assert_eq!(result, vec![0xF0]); }
#[test]
fn test_from_mmsi_optional() {
assert_eq!(from_mmsi_optional(0), None);
assert_eq!(from_mmsi_optional(123456789), Some(123456789));
}
}