#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Name {
unique_number: u32,
manufacturer_code: u16,
device_instance: u8,
device_function: u8,
device_class: u8,
system_instance: u8,
industry_group: u8,
arbitrary_address_capable: bool,
}
impl From<Name> for crate::engine::encode::EncodeValue {
fn from(name: Name) -> Self {
crate::engine::encode::EncodeValue::Raw(name.to_u64())
}
}
impl Name {
pub fn new(manufacturer_code: u16, unique_number: u32) -> Self {
Self {
unique_number,
manufacturer_code,
device_instance: 0,
device_function: 0,
device_class: 0,
system_instance: 0,
industry_group: 4, arbitrary_address_capable: true,
}
}
pub fn device_function(mut self, v: u8) -> Self {
self.device_function = v;
self
}
pub fn device_class(mut self, v: u8) -> Self {
self.device_class = v;
self
}
pub fn device_instance(mut self, v: u8) -> Self {
self.device_instance = v;
self
}
pub fn system_instance(mut self, v: u8) -> Self {
self.system_instance = v & 0x0f;
self
}
pub fn industry_group(mut self, v: u8) -> Self {
self.industry_group = v & 0x07;
self
}
pub fn arbitrary_address_capable(mut self, v: bool) -> Self {
self.arbitrary_address_capable = v;
self
}
pub fn is_arbitrary_address_capable(&self) -> bool {
self.arbitrary_address_capable
}
pub fn to_u64(self) -> u64 {
let unique = (self.unique_number & 0x1f_ffff) as u64;
let mfr = (self.manufacturer_code & 0x7ff) as u64;
let di = self.device_instance as u64;
unique
| (mfr << 21)
| ((di & 0x07) << 32)
| (((di >> 3) & 0x1f) << 35)
| ((self.device_function as u64 & 0xff) << 40)
| ((self.device_class as u64 & 0x7f) << 49)
| ((self.system_instance as u64 & 0x0f) << 56)
| ((self.industry_group as u64 & 0x07) << 60)
| ((self.arbitrary_address_capable as u64) << 63)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn matches_socketcan_gateway_packing() {
let (unique, manufacturer, system_instance) = (0x0012_3456_u32, 275_u16, 3_u8);
let expected = {
let unique = (unique & 0x1fffff) as u64;
let manufacturer = manufacturer as u64 & 0x7ff;
let device_instance: u64 = 0;
let device_function: u64 = 130;
let device_class: u64 = 25;
let system_instance = system_instance as u64 & 0x0f;
let industry_group: u64 = 4;
let arbitrary: u64 = 1;
unique
| (manufacturer << 21)
| ((device_instance & 0x07) << 32)
| ((device_instance >> 3 & 0x1f) << 35)
| ((device_function & 0xff) << 40)
| ((device_class & 0x7f) << 49)
| ((system_instance & 0x0f) << 56)
| ((industry_group & 0x07) << 60)
| (arbitrary << 63)
};
let got = Name::new(manufacturer, unique)
.device_function(130)
.device_class(25)
.system_instance(system_instance)
.to_u64();
assert_eq!(got, expected);
}
#[test]
fn matches_motion_quirk_packing() {
let unique = 0x0001_abcd_u32 & 0x1f_ffff;
let expected = {
const MFG_BANDG: u64 = 381;
const DEVICE_FUNCTION: u64 = 140;
const DEVICE_CLASS: u64 = 60;
const INDUSTRY_MARINE: u64 = 4;
let arbitrary: u64 = 1;
(unique as u64)
| (MFG_BANDG << 21)
| (DEVICE_FUNCTION << 40)
| (DEVICE_CLASS << 49)
| (INDUSTRY_MARINE << 60)
| (arbitrary << 63)
};
let got = Name::new(381, unique)
.device_function(140)
.device_class(60)
.to_u64();
assert_eq!(got, expected);
}
#[test]
fn a_name_is_pushed_as_itself() {
use crate::engine::field::simnet_data_source_selection::SOURCE;
let db = crate::engine::PgnDatabase::embedded(crate::engine::Units::Si);
let name = Name::new(275, 0x1abcd).device_function(130);
let frame = db
.encode("simnetDataSourceSelection")
.unwrap()
.push(SOURCE, name)
.unwrap()
.build()
.unwrap();
let d = db.decode(&frame).unwrap();
match d.field(SOURCE).map(|f| &f.value) {
Some(crate::engine::FieldValue::IsoName { value, .. }) => {
assert_eq!(*value, name.to_u64())
}
other => panic!("expected an ISO NAME, got {other:?}"),
}
}
}