From 1852db922621d64e7184e17b2280c8f813da4b01 Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 15 Aug 2023 14:19:09 +0200 Subject: [PATCH 1/2] Add IndustryGroup, DeviceClass and FunctionCode --- src/network_management/name.rs | 529 ------------------ src/network_management/name/device_class.rs | 359 ++++++++++++ src/network_management/name/function_code.rs | 436 +++++++++++++++ src/network_management/name/industry_group.rs | 87 +++ src/network_management/name/mod.rs | 429 ++++++++++++++ src/network_management/name/name_filter.rs | 40 ++ 6 files changed, 1351 insertions(+), 529 deletions(-) delete mode 100644 src/network_management/name.rs create mode 100644 src/network_management/name/device_class.rs create mode 100644 src/network_management/name/function_code.rs create mode 100644 src/network_management/name/industry_group.rs create mode 100644 src/network_management/name/mod.rs create mode 100644 src/network_management/name/name_filter.rs diff --git a/src/network_management/name.rs b/src/network_management/name.rs deleted file mode 100644 index ac62351..0000000 --- a/src/network_management/name.rs +++ /dev/null @@ -1,529 +0,0 @@ -// Copyright 2023 Raven Industries inc. - -#[derive(PartialEq, Eq, Clone, Copy)] -pub enum NameField { - IdentityNumber(u32), - ShortIdentityNumber(u16), - ExtendedIdentityNumber(u8), - ManufacturerCode(u16), - EcuInstance(u8), - FunctionInstance(u8), - Function(u8), - DeviceClass(u8), - DeviceClassInstance(u8), - IndustryGroup(u8), - SelfConfigurableAddress(bool), -} - -#[derive(Copy, Clone, PartialEq)] -pub struct NAME { - raw_name: u64, -} - -impl NAME { - pub fn new(raw_name: u64) -> Self { - Self { raw_name } - } - - pub fn builder() -> NameBuilder { - NameBuilder::default() - } - - pub fn check_mask(name_to_check: &NAME, name_fields: &Vec) -> bool { - let mut matched = false; - if (!name_fields.is_empty()) && (&NAME::default() != name_to_check) { - matched = true; - - for field in name_fields { - if let NameField::IdentityNumber(value) = field { - if *value == name_to_check.get_identity_number() { - matched = true; - break; - } else { - matched = false; - } - } - } - - if matched { - for field in name_fields { - if let NameField::ShortIdentityNumber(value) = field { - if *value == name_to_check.get_short_identity_number() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - - if matched { - for field in name_fields { - if let NameField::ExtendedIdentityNumber(value) = field { - if *value == name_to_check.get_extended_identity_number() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - - if matched { - for field in name_fields { - if let NameField::ManufacturerCode(value) = field { - if *value == name_to_check.get_manufacturer_code() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - - if matched { - for field in name_fields { - if let NameField::EcuInstance(value) = field { - if *value == name_to_check.get_ecu_instance() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - - if matched { - for field in name_fields { - if let NameField::FunctionInstance(value) = field { - if *value == name_to_check.get_function_instance() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - - if matched { - for field in name_fields { - if let NameField::Function(value) = field { - if *value == name_to_check.get_function() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - - if matched { - for field in name_fields { - if let NameField::DeviceClass(value) = field { - if *value == name_to_check.get_device_class() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - - if matched { - for field in name_fields { - if let NameField::DeviceClassInstance(value) = field { - if *value == name_to_check.get_device_class_instance() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - - if matched { - for field in name_fields { - if let NameField::IndustryGroup(value) = field { - if *value == name_to_check.get_industry_group() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - - if matched { - for field in name_fields { - if let NameField::SelfConfigurableAddress(value) = field { - if *value == name_to_check.get_self_configurable_address() { - matched = true; - break; - } else { - matched = false; - } - } - } - } - } - return matched; - } - - pub fn get_device_class(&self) -> u8 { - ((self.raw_name >> 49) & 0x7F) as u8 - } - - pub fn set_device_class(&mut self, device_class: u8) { - self.raw_name &= !0x00FE000000000000_u64; - self.raw_name |= ((device_class & 0x7F) as u64) << 49; - } - - pub fn get_device_class_instance(&self) -> u8 { - ((self.raw_name >> 56) & 0x0F) as u8 - } - - pub fn set_device_class_instance(&mut self, device_class_instance: u8) { - self.raw_name &= !0x0F00000000000000; - self.raw_name |= ((device_class_instance & 0x0F) as u64) << 56; - } - - pub fn get_ecu_instance(&self) -> u8 { - ((self.raw_name >> 32) & 0x07) as u8 - } - - pub fn set_ecu_instance(&mut self, ecu_instance: u8) { - self.raw_name &= !0x0000000700000000; - self.raw_name |= ((ecu_instance & 0x07) as u64) << 32; - } - - pub fn get_extended_identity_number(&self) -> u8 { - ((self.raw_name >> 16) & 0x1F) as u8 - } - - pub fn set_extended_identity_number(&mut self, extended_identity_number: u8) { - self.raw_name &= !0x00000000001F0000; - self.raw_name |= ((extended_identity_number & 0x1F) as u64) << 16; - } - - pub fn get_function(&self) -> u8 { - ((self.raw_name >> 40) & 0xFF) as u8 - } - - pub fn set_function(&mut self, function: u8) { - self.raw_name &= !0x0000FF0000000000; - self.raw_name |= (function as u64) << 40; - } - - pub fn get_function_instance(&self) -> u8 { - ((self.raw_name >> 35) & 0x1F) as u8 - } - - pub fn set_function_instance(&mut self, function: u8) { - self.raw_name &= !0x000000F800000000; - self.raw_name |= ((function & 0x1F) as u64) << 35; - } - - pub fn get_identity_number(&self) -> u32 { - (self.raw_name & 0x001FFFFF) as u32 - } - - pub fn set_identity_number(&mut self, identity_number: u32) { - self.raw_name &= !0x00000000001FFFFF; - self.raw_name |= (identity_number & 0x00000000001FFFFF) as u64; - } - - pub fn get_industry_group(&self) -> u8 { - ((self.raw_name >> 60) & 0x07) as u8 - } - - pub fn set_industry_group(&mut self, industry_group: u8) { - self.raw_name &= !0x7000000000000000; - self.raw_name |= ((industry_group & 0x07) as u64) << 60; - } - - pub fn get_manufacturer_code(&self) -> u16 { - ((self.raw_name >> 21) & 0x07FF) as u16 - } - - pub fn set_manufacturer_code(&mut self, manufacturer_code: u16) { - self.raw_name &= !0x00000000FFE00000; - self.raw_name |= ((manufacturer_code & 0x07FF) as u64) << 21; - } - - pub fn get_self_configurable_address(&self) -> bool { - (self.raw_name >> 63) != 0 - } - - pub fn set_self_configurable_address(&mut self, self_configurable_address: bool) { - self.raw_name &= !0x8000000000000000; - self.raw_name |= (self_configurable_address as u64) << 63; - } - - pub fn get_short_identity_number(&self) -> u16 { - (self.raw_name & 0x0000FFFF) as u16 - } - - pub fn set_short_identity_number(&mut self, short_identity_number: u16) { - self.raw_name &= !0x000000000000FFFF; - self.raw_name |= short_identity_number as u64; - } -} - -impl Default for NAME { - fn default() -> Self { - Self { - raw_name: 0xFFFFFFFFFFFFFFFF, - } - } -} - -impl From for u64 { - fn from(name: NAME) -> Self { - name.raw_name - } -} - -#[derive(Default)] -pub struct NameBuilder { - self_configurable_address: bool, - industry_group: u8, - device_class_instance: u8, - device_class: u8, - function_code: u8, - function_instance: u8, - ecu_instance: u8, - manufacturer_code: u16, - identity_number: u32, -} - -impl NameBuilder { - pub fn new() -> NameBuilder { - NameBuilder::default() - } - - pub fn build(&self) -> NAME { - NAME { - raw_name: (self.self_configurable_address as u64) << 63 - | (self.industry_group as u64 & 0x7) << 60 - | (self.device_class_instance as u64 & 0xF) << 56 - | (self.device_class as u64 & 0x7F) << 49 - | (self.function_code as u64 & 0xFF) << 40 - | (self.function_instance as u64 & 0x1F) << 35 - | (self.ecu_instance as u64 & 0x7) << 32 - | (self.manufacturer_code as u64 & 0x7FF) << 21 - | self.identity_number as u64 & 0x1FFFFF, - } - } - - pub fn self_configurable_address(&mut self, value: impl Into) -> &mut NameBuilder { - self.self_configurable_address = value.into(); - self - } - pub fn industry_group(&mut self, value: impl Into) -> &mut NameBuilder { - self.industry_group = value.into(); - self - } - pub fn device_class_instance(&mut self, value: impl Into) -> &mut NameBuilder { - self.device_class_instance = value.into(); - self - } - pub fn device_class(&mut self, value: impl Into) -> &mut NameBuilder { - self.device_class = value.into(); - self - } - pub fn function_code(&mut self, value: impl Into) -> &mut NameBuilder { - self.function_code = value.into(); - self - } - pub fn function_instance(&mut self, value: impl Into) -> &mut NameBuilder { - self.function_instance = value.into(); - self - } - pub fn ecu_instance(&mut self, value: impl Into) -> &mut NameBuilder { - self.ecu_instance = value.into(); - self - } - pub fn manufacturer_code(&mut self, value: impl Into) -> &mut NameBuilder { - self.manufacturer_code = value.into(); - self - } - pub fn identity_number(&mut self, value: impl Into) -> &mut NameBuilder { - self.identity_number = value.into(); - self - } -} - -impl From for NameBuilder { - fn from(value: NAME) -> Self { - let value: u64 = value.into(); - NameBuilder { - self_configurable_address: (value >> 63) != 0, - industry_group: (value >> 60 & 0x7) as u8, - device_class_instance: (value >> 56 & 0xF) as u8, - device_class: (value >> 49 & 0x7F) as u8, - function_code: (value >> 40 & 0xFF) as u8, - function_instance: (value >> 35 & 0x1F) as u8, - ecu_instance: (value >> 32 & 0x7) as u8, - manufacturer_code: (value >> 21 & 0x7FF) as u16, - identity_number: (value & 0x1FFFFF) as u32, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_name_properties() { - let mut name_under_test = NAME::new(0); - - name_under_test.set_self_configurable_address(true); - name_under_test.set_industry_group(1); - name_under_test.set_device_class(2); - name_under_test.set_function(3); - name_under_test.set_identity_number(4); - name_under_test.set_ecu_instance(5); - name_under_test.set_function_instance(6); - name_under_test.set_device_class_instance(7); - name_under_test.set_manufacturer_code(8); - - assert_eq!(true, name_under_test.get_self_configurable_address()); - assert_eq!(1, name_under_test.get_industry_group()); - assert_eq!(2, name_under_test.get_device_class()); - assert_eq!(3, name_under_test.get_function()); - assert_eq!(4, name_under_test.get_identity_number()); - assert_eq!(5, name_under_test.get_ecu_instance()); - assert_eq!(6, name_under_test.get_function_instance()); - assert_eq!(7, name_under_test.get_device_class_instance()); - assert_eq!(8, name_under_test.get_manufacturer_code()); - assert_eq!(0, name_under_test.get_extended_identity_number()); - assert_eq!(4, name_under_test.get_short_identity_number()); - assert_eq!(10881826125818888196_u64, name_under_test.raw_name); - } - - #[test] - fn test_name_builder() { - let name_under_test = NAME::builder() - .identity_number(4_u32) - .manufacturer_code(8_u16) - .ecu_instance(5) - .function_instance(6) - .function_code(3) - .device_class(2) - .device_class_instance(7) - .industry_group(1) - .self_configurable_address(true) - .build(); - - assert_eq!(10881826125818888196_u64, name_under_test.into()); - } - - #[test] - fn test_out_of_range_properties() { - let mut name_under_test = NAME::new(0); - - name_under_test.set_industry_group(8); - name_under_test.set_device_class_instance(16); - name_under_test.set_device_class(128); - name_under_test.set_identity_number(2097152); - name_under_test.set_ecu_instance(8); - name_under_test.set_function_instance(32); - name_under_test.set_manufacturer_code(2048); - - assert_ne!(name_under_test.get_industry_group(), 8); - assert_ne!(name_under_test.get_device_class_instance(), 16); - assert_ne!(name_under_test.get_device_class(), 128); - assert_ne!(name_under_test.get_identity_number(), 2097151); - assert_ne!(name_under_test.get_ecu_instance(), 8); - assert_ne!(name_under_test.get_function_instance(), 32); - assert_ne!(name_under_test.get_manufacturer_code(), 2048); - } - - #[test] - fn test_name_equality() { - let test_value: u64 = 10376445291390828545; - let name_under_test1 = NAME::new(test_value); - let name_under_test2 = NAME::new(test_value); - - assert_eq!(test_value, name_under_test1.raw_name); - assert_eq!(name_under_test1.raw_name, name_under_test2.raw_name); - } - - #[test] - fn test_filter_matching() { - let mut test_name = NAME::new(0); - let mut filters_to_test = Vec::new(); - let identity_number_filter = NameField::IdentityNumber(1); - filters_to_test.push(identity_number_filter); - - assert_eq!(false, NAME::check_mask(&test_name, &filters_to_test)); - test_name.set_identity_number(1); - assert_eq!(true, NAME::check_mask(&test_name, &filters_to_test)); - - let manufacturer_number_filter = NameField::ManufacturerCode(2); - filters_to_test.push(manufacturer_number_filter); - - assert_eq!(false, NAME::check_mask(&test_name, &filters_to_test)); - test_name.set_manufacturer_code(2); - assert_eq!(true, NAME::check_mask(&test_name, &filters_to_test)); - - let ecu_instance_filter = NameField::EcuInstance(3); - filters_to_test.push(ecu_instance_filter); - - assert_eq!(false, NAME::check_mask(&test_name, &filters_to_test)); - test_name.set_ecu_instance(3); - assert_eq!(true, NAME::check_mask(&test_name, &filters_to_test)); - - let function_instance_filter = NameField::FunctionInstance(4); - filters_to_test.push(function_instance_filter); - - assert_eq!(false, NAME::check_mask(&test_name, &filters_to_test)); - test_name.set_function_instance(4); - assert_eq!(true, NAME::check_mask(&test_name, &filters_to_test)); - - let function_filter = NameField::Function(5); - filters_to_test.push(function_filter); - - assert_eq!(false, NAME::check_mask(&test_name, &filters_to_test)); - test_name.set_function(5); - assert_eq!(true, NAME::check_mask(&test_name, &filters_to_test)); - - let device_class_filter = NameField::DeviceClass(6); - filters_to_test.push(device_class_filter); - - assert_eq!(false, NAME::check_mask(&test_name, &filters_to_test)); - test_name.set_device_class(6); - assert_eq!(true, NAME::check_mask(&test_name, &filters_to_test)); - - let industry_group_filter = NameField::IndustryGroup(7); - filters_to_test.push(industry_group_filter); - - assert_eq!(false, NAME::check_mask(&test_name, &filters_to_test)); - test_name.set_industry_group(7); - assert_eq!(true, NAME::check_mask(&test_name, &filters_to_test)); - - let device_class_instance_filter = NameField::DeviceClassInstance(8); - filters_to_test.push(device_class_instance_filter); - - assert_eq!(false, NAME::check_mask(&test_name, &filters_to_test)); - test_name.set_device_class_instance(8); - assert_eq!(true, NAME::check_mask(&test_name, &filters_to_test)); - - let self_configurable_address_filter = NameField::SelfConfigurableAddress(true); - filters_to_test.push(self_configurable_address_filter); - - assert_eq!(false, NAME::check_mask(&test_name, &filters_to_test)); - test_name.set_self_configurable_address(true); - assert_eq!(true, NAME::check_mask(&test_name, &filters_to_test)); - } -} diff --git a/src/network_management/name/device_class.rs b/src/network_management/name/device_class.rs new file mode 100644 index 0000000..247d9d7 --- /dev/null +++ b/src/network_management/name/device_class.rs @@ -0,0 +1,359 @@ +// Copyright 2023 Raven Industries inc. + +use super::IndustryGroup; + +/// Enum containing all Device Classes. +/// Some Device classes belong to multiple Industry Groups. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::{IndustryGroup, DeviceClass}; +/// let device_class: DeviceClass = DeviceClass::Fertilizers; +/// +/// assert_eq!(device_class, DeviceClass::from((5, IndustryGroup::AgriculturalAndForestryEquipment))); +/// assert_eq!(device_class, (5, IndustryGroup::AgriculturalAndForestryEquipment).into()); +/// assert_eq!(5, u8::from(device_class)); +/// assert_eq!(5_u8, device_class.into()); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] +pub enum DeviceClass { + // Shared + #[default] + NotAvailable, + NonSpecificSystem(IndustryGroup), + Tractor(IndustryGroup), + + // On Highway Equipment + Trailer, + + // Agricultural And Forestry Equipment + Tillage, + SecondaryTillage, + PlantersOrSeeders, + Fertilizers, + Sprayers, + Harvesters, + RootHarvesters, + Forage, + Irrigation, + TransportOrTrailer, + FarmYardOperations, + PoweredAuxiliaryDevices, + SpecialCrops, + EarthWork, + Skidder, + SensorSystems, + TimberHarvesters, + Forwarders, + TimberLoaders, + TimberProcessingMachines, + Mulchers, + UtilityVehicles, + SlurryOrManureApplicators, + FeedersOrMixers, + Weeders, + + // Construction Equipment + SkidSteerLoader, + ArticulatedDumpTruck, + Backhoe, + Crawler, + Excavator, + Forklift, + FourWheelDriveLoader, + Grader, + MillingMachine, + RecyclerAndSoilStabilizer, + BindingAgentSpreader, + Paver, + Feeder, + ScreeningPlant, + Stacker, + Roller, + Crusher, + + // Marine Equipment + SystemTools, + SafetySystems, + Gateway, + PowerManagementAndLightingSystems, + Steeringsystems, + NavigationSystems, + CommunicationsSystems, + InstrumentationOrGeneralSystems, + EnvironmentalSystems, + DeckCargoAndFishingEquipmentSystems, + + // Industrial Process Control + IndustrialProcessControlStationary, +} + +/// Display the Device Class name. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::DeviceClass; +/// +/// assert_eq!("Fertilizers", format!("{}", DeviceClass::Fertilizers)); +/// ``` +impl core::fmt::Display for DeviceClass { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} + +/// Convert a `DeviceClass` into a u8. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::DeviceClass; +/// +/// assert_eq!(5, u8::from(DeviceClass::Fertilizers)); +/// assert_eq!(5_u8, DeviceClass::Fertilizers.into()); +/// ``` +impl From for u8 { + fn from(value: DeviceClass) -> Self { + match value { + // Shared + DeviceClass::NotAvailable => 127, + DeviceClass::NonSpecificSystem(_) => 0, + DeviceClass::Tractor(_) => 1, + + // On Highway Equipment + DeviceClass::Trailer => 2, + + // Agricultural And Forestry Equipment + DeviceClass::Tillage => 2, + DeviceClass::SecondaryTillage => 3, + DeviceClass::PlantersOrSeeders => 4, + DeviceClass::Fertilizers => 5, + DeviceClass::Sprayers => 6, + DeviceClass::Harvesters => 7, + DeviceClass::RootHarvesters => 8, + DeviceClass::Forage => 9, + DeviceClass::Irrigation => 10, + DeviceClass::TransportOrTrailer => 11, + DeviceClass::FarmYardOperations => 12, + DeviceClass::PoweredAuxiliaryDevices => 13, + DeviceClass::SpecialCrops => 14, + DeviceClass::EarthWork => 15, + DeviceClass::Skidder => 16, + DeviceClass::SensorSystems => 17, + DeviceClass::TimberHarvesters => 19, + DeviceClass::Forwarders => 20, + DeviceClass::TimberLoaders => 21, + DeviceClass::TimberProcessingMachines => 22, + DeviceClass::Mulchers => 23, + DeviceClass::UtilityVehicles => 24, + DeviceClass::SlurryOrManureApplicators => 25, + DeviceClass::FeedersOrMixers => 26, + DeviceClass::Weeders => 27, + + // Construction Equipment + DeviceClass::SkidSteerLoader => 1, + DeviceClass::ArticulatedDumpTruck => 2, + DeviceClass::Backhoe => 3, + DeviceClass::Crawler => 4, + DeviceClass::Excavator => 5, + DeviceClass::Forklift => 6, + DeviceClass::FourWheelDriveLoader => 7, + DeviceClass::Grader => 8, + DeviceClass::MillingMachine => 9, + DeviceClass::RecyclerAndSoilStabilizer => 10, + DeviceClass::BindingAgentSpreader => 11, + DeviceClass::Paver => 12, + DeviceClass::Feeder => 13, + DeviceClass::ScreeningPlant => 14, + DeviceClass::Stacker => 15, + DeviceClass::Roller => 16, + DeviceClass::Crusher => 17, + + // Marine Equipment + DeviceClass::SystemTools => 10, + DeviceClass::SafetySystems => 20, + DeviceClass::Gateway => 25, + DeviceClass::PowerManagementAndLightingSystems => 30, + DeviceClass::Steeringsystems => 40, + DeviceClass::NavigationSystems => 60, + DeviceClass::CommunicationsSystems => 70, + DeviceClass::InstrumentationOrGeneralSystems => 80, + DeviceClass::EnvironmentalSystems => 90, + DeviceClass::DeckCargoAndFishingEquipmentSystems => 100, + + // Industrial Process Control + DeviceClass::IndustrialProcessControlStationary => 0, + } + } +} + +/// Convert a u8 and `IndustryGroup` into a `DeviceClass`. +/// +/// The `IndustryGroup` is needed becouse a u8 can represent multiple `DeviceClass`es depending on the `IndustryGroup`. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::{IndustryGroup, DeviceClass}; +/// +/// assert_eq!(DeviceClass::Fertilizers, DeviceClass::from((5, IndustryGroup::AgriculturalAndForestryEquipment))); +/// assert_eq!(DeviceClass::Fertilizers, (5, IndustryGroup::AgriculturalAndForestryEquipment).into()); +/// ``` +#[rustfmt::skip] // Skip formatting the lines inside the match statement +impl From<(u8, IndustryGroup)> for DeviceClass { + fn from(value: (u8, IndustryGroup)) -> Self { + match value { + (0, IndustryGroup::IndustrialProcessControl) => DeviceClass::IndustrialProcessControlStationary, + (0, ig) => DeviceClass::NonSpecificSystem(ig), + + (1, IndustryGroup::OnHighwayEquipment) => DeviceClass::Tractor(IndustryGroup::OnHighwayEquipment), + (2, IndustryGroup::OnHighwayEquipment) => DeviceClass::Trailer, + + (1, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Tractor(IndustryGroup::AgriculturalAndForestryEquipment), + (2, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Tillage, + (3, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::SecondaryTillage, + (4, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::PlantersOrSeeders, + (5, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Fertilizers, + (6, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Sprayers, + (7, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Harvesters, + (8, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::RootHarvesters, + (9, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Forage, + (10, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Irrigation, + (11, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::TransportOrTrailer, + (12, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::FarmYardOperations, + (13, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::PoweredAuxiliaryDevices, + (14, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::SpecialCrops, + (15, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::EarthWork, + (16, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Skidder, + (17, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::SensorSystems, + (19, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::TimberHarvesters, + (20, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Forwarders, + (21, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::TimberLoaders, + (22, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::TimberProcessingMachines, + (23, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Mulchers, + (24, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::UtilityVehicles, + (25, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::SlurryOrManureApplicators, + (26, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::FeedersOrMixers, + (27, IndustryGroup::AgriculturalAndForestryEquipment) => DeviceClass::Weeders, + + (1, IndustryGroup::ConstructionEquipment) => DeviceClass::SkidSteerLoader, + (2, IndustryGroup::ConstructionEquipment) => DeviceClass::ArticulatedDumpTruck, + (3, IndustryGroup::ConstructionEquipment) => DeviceClass::Backhoe, + (4, IndustryGroup::ConstructionEquipment) => DeviceClass::Crawler, + (5, IndustryGroup::ConstructionEquipment) => DeviceClass::Excavator, + (6, IndustryGroup::ConstructionEquipment) => DeviceClass::Forklift, + (7, IndustryGroup::ConstructionEquipment) => DeviceClass::FourWheelDriveLoader, + (8, IndustryGroup::ConstructionEquipment) => DeviceClass::Grader, + (9, IndustryGroup::ConstructionEquipment) => DeviceClass::MillingMachine, + (10, IndustryGroup::ConstructionEquipment) => DeviceClass::RecyclerAndSoilStabilizer, + (11, IndustryGroup::ConstructionEquipment) => DeviceClass::BindingAgentSpreader, + (12, IndustryGroup::ConstructionEquipment) => DeviceClass::Paver, + (13, IndustryGroup::ConstructionEquipment) => DeviceClass::Feeder, + (14, IndustryGroup::ConstructionEquipment) => DeviceClass::ScreeningPlant, + (15, IndustryGroup::ConstructionEquipment) => DeviceClass::Stacker, + (16, IndustryGroup::ConstructionEquipment) => DeviceClass::Roller, + (17, IndustryGroup::ConstructionEquipment) => DeviceClass::Crusher, + + (10, IndustryGroup::MarineEquipment) => DeviceClass::SystemTools, + (20, IndustryGroup::MarineEquipment) => DeviceClass::SafetySystems, + (25, IndustryGroup::MarineEquipment) => DeviceClass::Gateway, + (30, IndustryGroup::MarineEquipment) => DeviceClass::PowerManagementAndLightingSystems, + (40, IndustryGroup::MarineEquipment) => DeviceClass::Steeringsystems, + (60, IndustryGroup::MarineEquipment) => DeviceClass::NavigationSystems, + (70, IndustryGroup::MarineEquipment) => DeviceClass::CommunicationsSystems, + (80, IndustryGroup::MarineEquipment) => DeviceClass::InstrumentationOrGeneralSystems, + (90, IndustryGroup::MarineEquipment) => DeviceClass::EnvironmentalSystems, + (100, IndustryGroup::MarineEquipment) => DeviceClass::DeckCargoAndFishingEquipmentSystems, + + _ => DeviceClass::NotAvailable, + } + } +} + +/// Derive the `IndustryGroup` from a `DeviceClass`. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::{IndustryGroup, DeviceClass}; +/// +/// assert_eq!(IndustryGroup::AgriculturalAndForestryEquipment, IndustryGroup::from(DeviceClass::Fertilizers)); +/// assert_eq!(IndustryGroup::AgriculturalAndForestryEquipment, DeviceClass::Fertilizers.into()); +/// ``` +impl From for IndustryGroup { + fn from(value: DeviceClass) -> Self { + match value { + // Shared + DeviceClass::NotAvailable => IndustryGroup::Global, + DeviceClass::NonSpecificSystem(ig) | DeviceClass::Tractor(ig) => ig, + + // On Highway Equipment + DeviceClass::Trailer => IndustryGroup::OnHighwayEquipment, + + // Agricultural And Forestry Equipment + DeviceClass::Tillage + | DeviceClass::SecondaryTillage + | DeviceClass::PlantersOrSeeders + | DeviceClass::Fertilizers + | DeviceClass::Sprayers + | DeviceClass::Harvesters + | DeviceClass::RootHarvesters + | DeviceClass::Forage + | DeviceClass::Irrigation + | DeviceClass::TransportOrTrailer + | DeviceClass::FarmYardOperations + | DeviceClass::PoweredAuxiliaryDevices + | DeviceClass::SpecialCrops + | DeviceClass::EarthWork + | DeviceClass::Skidder + | DeviceClass::SensorSystems + | DeviceClass::TimberHarvesters + | DeviceClass::Forwarders + | DeviceClass::TimberLoaders + | DeviceClass::TimberProcessingMachines + | DeviceClass::Mulchers + | DeviceClass::UtilityVehicles + | DeviceClass::SlurryOrManureApplicators + | DeviceClass::FeedersOrMixers + | DeviceClass::Weeders => IndustryGroup::AgriculturalAndForestryEquipment, + + // Construction Equipment + DeviceClass::SkidSteerLoader + | DeviceClass::ArticulatedDumpTruck + | DeviceClass::Backhoe + | DeviceClass::Crawler + | DeviceClass::Excavator + | DeviceClass::Forklift + | DeviceClass::FourWheelDriveLoader + | DeviceClass::Grader + | DeviceClass::MillingMachine + | DeviceClass::RecyclerAndSoilStabilizer + | DeviceClass::BindingAgentSpreader + | DeviceClass::Paver + | DeviceClass::Feeder + | DeviceClass::ScreeningPlant + | DeviceClass::Stacker + | DeviceClass::Roller + | DeviceClass::Crusher => IndustryGroup::ConstructionEquipment, + + // Marine Equipment + DeviceClass::SystemTools + | DeviceClass::SafetySystems + | DeviceClass::Gateway + | DeviceClass::PowerManagementAndLightingSystems + | DeviceClass::Steeringsystems + | DeviceClass::NavigationSystems + | DeviceClass::CommunicationsSystems + | DeviceClass::InstrumentationOrGeneralSystems + | DeviceClass::EnvironmentalSystems + | DeviceClass::DeckCargoAndFishingEquipmentSystems => IndustryGroup::MarineEquipment, + + // Industrial Process Control + DeviceClass::IndustrialProcessControlStationary => { + IndustryGroup::IndustrialProcessControl + } + } + } +} diff --git a/src/network_management/name/function_code.rs b/src/network_management/name/function_code.rs new file mode 100644 index 0000000..dfb987e --- /dev/null +++ b/src/network_management/name/function_code.rs @@ -0,0 +1,436 @@ +// Copyright 2023 Raven Industries inc. + +// todo!("Implement all IndustryGroup specific FunctionCode's"); + +/// Enum containing all Function Code's. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::{IndustryGroup, FunctionCode}; +/// let function_code: FunctionCode = FunctionCode::VirtualTerminal; +/// +/// assert_eq!(function_code, FunctionCode::from(29)); +/// assert_eq!(function_code, 29.into()); +/// assert_eq!(29, u8::from(function_code)); +/// assert_eq!(29_u8, function_code.into()); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] +pub enum FunctionCode { + // Shared + #[default] + NotAvailable, + + // Global + Engine, + AuxiliaryPowerUnit, + ElectricPropulsionControl, + Transmission, + BatteryPackMonitor, + ShiftControlConsole, + PowerTakeOffMain, + AxleSteering, + AxleDrive, + BrakesSystemController, + BrakesSteerAxle, + BrakesDriveAxle, + RetarderEngine, + RetarderDriveline, + CruiseControl, + FuelSystem, + SteeringController, + SuspensionSteerAxle, + SuspensionDriveAxle, + InstrumentCluster, + TripRecorder, + CabClimateControl, + AerodynamicControl, + VehicleNavigation, + VehicleSecurity, + NetworkInterconnectECU, + BodyController, + PowerTakeOffSecondary, + OffVehicleGateway, + VirtualTerminal, + ManagementComputer, + PropulsionBatteryCharger, + HeadwayController, + SystemMonitor, + HydraulicPumpController, + SuspensionSystemController, + PneumaticSystemController, + CabController, + TirePressureControl, + IgnitionControlModule, + SeatControl, + LightingOperatorControls, + WaterPumpControl, + TransmissionDisplay, + ExhaustEmissionControl, + VehicleDynamicStabilityControl, + OilSensorUnit, + InformationSystemController, + RampControl, + ClutchConverterControl, + AuxiliaryHeater, + ForwardLookingCollisionWarningSystem, + ChassisController, + AlternatorChargingSystem, + CommunicationsUnitCellular, + CommunicationsUnitSatellite, + CommunicationsUnitRadio, + SteeringColumnUnit, + FanDriveControl, + Starter, + CabDisplay, + FileServerPrinter, + OnBoardDiagnosticUnit, + EngineValveController, + EnduranceBraking, + GasFlowMeasurement, + IOController, + ElectricalSystemController, + AfterTreatmentSystemGasMeasurement, + EngineEmissionAfterTreatmentSystem, + AuxiliaryRegenerationDevice, + TransferCaseControl, + CoolantValveController, + RolloverDetectionControl, + LubricationSystem, + SupplementalFan, + TemperatureSensor, + FuelPropertiesSensor, + FireSuppressionSystem, + PowerSystemsManager, + ElectricPowertrain, + HydraulicPowertrain, + FileServer, + Printer, + StartAidDevice, + EngineInjectionControlModule, + EVCommunicationController, + DriverImpairmentDevice, + ElectricPowerConverter, + SupplyEquipmentCommunicationController, + VehicleAdapterCommunicationController, + Reserved, + OffBoardDiagnosticServiceTool, + OnBoardDataLogger, + PCKeyboard, + SafetyRestraintSystem, + Turbocharger, + GroundBasedSpeedSensor, + Keypad, + HumiditySensor, + ThermalManagementSystemController, + BrakeStrokeAlert, + OnBoardAxleGroupScale, + OnBoardAxleGroupDisplay, + BatteryCharger, + TurbochargerCompressorBypass, + TurbochargerWastegate, + Throttle, + InertialSensor, + FuelActuator, + EngineExhaustGasRecirculation, + EngineExhaustBackpressure, + OnBoardBinWeighingScale, + OnBoardBinWeighingScaleDisplay, + EngineCylinderPressureMonitoringSystem, + ObjectDetection, + ObjectDetectionDisplay, + ObjectDetectionSensor, + PersonnelDetectionDevice, +} + +/// Display the Function Code name. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::FunctionCode; +/// +/// assert_eq!("VirtualTerminal", format!("{}", FunctionCode::VirtualTerminal)); +/// ``` +impl core::fmt::Display for FunctionCode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} + +/// Convert a `FunctionCode` into a u8. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::FunctionCode; +/// +/// assert_eq!(29, u8::from(FunctionCode::VirtualTerminal)); +/// assert_eq!(29_u8, FunctionCode::VirtualTerminal.into()); +/// ``` +impl From for u8 { + fn from(value: FunctionCode) -> Self { + match value { + // Shared + FunctionCode::NotAvailable => 127, + + // Global + FunctionCode::Engine => 0, + FunctionCode::AuxiliaryPowerUnit => 1, + FunctionCode::ElectricPropulsionControl => 2, + FunctionCode::Transmission => 3, + FunctionCode::BatteryPackMonitor => 4, + FunctionCode::ShiftControlConsole => 5, + FunctionCode::PowerTakeOffMain => 6, + FunctionCode::AxleSteering => 7, + FunctionCode::AxleDrive => 8, + FunctionCode::BrakesSystemController => 9, + FunctionCode::BrakesSteerAxle => 10, + FunctionCode::BrakesDriveAxle => 11, + FunctionCode::RetarderEngine => 12, + FunctionCode::RetarderDriveline => 13, + FunctionCode::CruiseControl => 14, + FunctionCode::FuelSystem => 15, + FunctionCode::SteeringController => 16, + FunctionCode::SuspensionSteerAxle => 17, + FunctionCode::SuspensionDriveAxle => 18, + FunctionCode::InstrumentCluster => 19, + FunctionCode::TripRecorder => 20, + FunctionCode::CabClimateControl => 21, + FunctionCode::AerodynamicControl => 22, + FunctionCode::VehicleNavigation => 23, + FunctionCode::VehicleSecurity => 24, + FunctionCode::NetworkInterconnectECU => 25, + FunctionCode::BodyController => 26, + FunctionCode::PowerTakeOffSecondary => 27, + FunctionCode::OffVehicleGateway => 28, + FunctionCode::VirtualTerminal => 29, + FunctionCode::ManagementComputer => 30, + FunctionCode::PropulsionBatteryCharger => 31, + FunctionCode::HeadwayController => 32, + FunctionCode::SystemMonitor => 33, + FunctionCode::HydraulicPumpController => 34, + FunctionCode::SuspensionSystemController => 35, + FunctionCode::PneumaticSystemController => 36, + FunctionCode::CabController => 37, + FunctionCode::TirePressureControl => 38, + FunctionCode::IgnitionControlModule => 39, + FunctionCode::SeatControl => 40, + FunctionCode::LightingOperatorControls => 41, + FunctionCode::WaterPumpControl => 42, + FunctionCode::TransmissionDisplay => 43, + FunctionCode::ExhaustEmissionControl => 44, + FunctionCode::VehicleDynamicStabilityControl => 45, + FunctionCode::OilSensorUnit => 46, + FunctionCode::InformationSystemController => 47, + FunctionCode::RampControl => 48, + FunctionCode::ClutchConverterControl => 49, + FunctionCode::AuxiliaryHeater => 50, + FunctionCode::ForwardLookingCollisionWarningSystem => 51, + FunctionCode::ChassisController => 52, + FunctionCode::AlternatorChargingSystem => 53, + FunctionCode::CommunicationsUnitCellular => 54, + FunctionCode::CommunicationsUnitSatellite => 55, + FunctionCode::CommunicationsUnitRadio => 56, + FunctionCode::SteeringColumnUnit => 57, + FunctionCode::FanDriveControl => 58, + FunctionCode::Starter => 59, + FunctionCode::CabDisplay => 60, + FunctionCode::FileServerPrinter => 61, + FunctionCode::OnBoardDiagnosticUnit => 62, + FunctionCode::EngineValveController => 63, + FunctionCode::EnduranceBraking => 64, + FunctionCode::GasFlowMeasurement => 65, + FunctionCode::IOController => 66, + FunctionCode::ElectricalSystemController => 67, + FunctionCode::AfterTreatmentSystemGasMeasurement => 68, + FunctionCode::EngineEmissionAfterTreatmentSystem => 69, + FunctionCode::AuxiliaryRegenerationDevice => 70, + FunctionCode::TransferCaseControl => 71, + FunctionCode::CoolantValveController => 72, + FunctionCode::RolloverDetectionControl => 73, + FunctionCode::LubricationSystem => 74, + FunctionCode::SupplementalFan => 75, + FunctionCode::TemperatureSensor => 76, + FunctionCode::FuelPropertiesSensor => 77, + FunctionCode::FireSuppressionSystem => 78, + FunctionCode::PowerSystemsManager => 79, + FunctionCode::ElectricPowertrain => 80, + FunctionCode::HydraulicPowertrain => 81, + FunctionCode::FileServer => 82, + FunctionCode::Printer => 83, + FunctionCode::StartAidDevice => 84, + FunctionCode::EngineInjectionControlModule => 85, + FunctionCode::EVCommunicationController => 86, + FunctionCode::DriverImpairmentDevice => 87, + FunctionCode::ElectricPowerConverter => 88, + FunctionCode::SupplyEquipmentCommunicationController => 89, + FunctionCode::VehicleAdapterCommunicationController => 90, + FunctionCode::Reserved => 128, + FunctionCode::OffBoardDiagnosticServiceTool => 129, + FunctionCode::OnBoardDataLogger => 130, + FunctionCode::PCKeyboard => 131, + FunctionCode::SafetyRestraintSystem => 132, + FunctionCode::Turbocharger => 133, + FunctionCode::GroundBasedSpeedSensor => 134, + FunctionCode::Keypad => 135, + FunctionCode::HumiditySensor => 136, + FunctionCode::ThermalManagementSystemController => 137, + FunctionCode::BrakeStrokeAlert => 138, + FunctionCode::OnBoardAxleGroupScale => 139, + FunctionCode::OnBoardAxleGroupDisplay => 140, + FunctionCode::BatteryCharger => 141, + FunctionCode::TurbochargerCompressorBypass => 142, + FunctionCode::TurbochargerWastegate => 143, + FunctionCode::Throttle => 144, + FunctionCode::InertialSensor => 145, + FunctionCode::FuelActuator => 146, + FunctionCode::EngineExhaustGasRecirculation => 147, + FunctionCode::EngineExhaustBackpressure => 148, + FunctionCode::OnBoardBinWeighingScale => 149, + FunctionCode::OnBoardBinWeighingScaleDisplay => 150, + FunctionCode::EngineCylinderPressureMonitoringSystem => 151, + FunctionCode::ObjectDetection => 152, + FunctionCode::ObjectDetectionDisplay => 153, + FunctionCode::ObjectDetectionSensor => 154, + FunctionCode::PersonnelDetectionDevice => 155, + } + } +} + +/// Convert a u8 into a `FunctionCode`. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::FunctionCode; +/// +/// assert_eq!(FunctionCode::VirtualTerminal, FunctionCode::from(29)); +/// assert_eq!(FunctionCode::VirtualTerminal, 29.into()); +/// ``` +impl From for FunctionCode { + fn from(value: u8) -> Self { + match value { + 0 => FunctionCode::Engine, + 1 => FunctionCode::AuxiliaryPowerUnit, + 2 => FunctionCode::ElectricPropulsionControl, + 3 => FunctionCode::Transmission, + 4 => FunctionCode::BatteryPackMonitor, + 5 => FunctionCode::ShiftControlConsole, + 6 => FunctionCode::PowerTakeOffMain, + 7 => FunctionCode::AxleSteering, + 8 => FunctionCode::AxleDrive, + 9 => FunctionCode::BrakesSystemController, + 10 => FunctionCode::BrakesSteerAxle, + 11 => FunctionCode::BrakesDriveAxle, + 12 => FunctionCode::RetarderEngine, + 13 => FunctionCode::RetarderDriveline, + 14 => FunctionCode::CruiseControl, + 15 => FunctionCode::FuelSystem, + 16 => FunctionCode::SteeringController, + 17 => FunctionCode::SuspensionSteerAxle, + 18 => FunctionCode::SuspensionDriveAxle, + 19 => FunctionCode::InstrumentCluster, + 20 => FunctionCode::TripRecorder, + 21 => FunctionCode::CabClimateControl, + 22 => FunctionCode::AerodynamicControl, + 23 => FunctionCode::VehicleNavigation, + 24 => FunctionCode::VehicleSecurity, + 25 => FunctionCode::NetworkInterconnectECU, + 26 => FunctionCode::BodyController, + 27 => FunctionCode::PowerTakeOffSecondary, + 28 => FunctionCode::OffVehicleGateway, + 29 => FunctionCode::VirtualTerminal, + 30 => FunctionCode::ManagementComputer, + 31 => FunctionCode::PropulsionBatteryCharger, + 32 => FunctionCode::HeadwayController, + 33 => FunctionCode::SystemMonitor, + 34 => FunctionCode::HydraulicPumpController, + 35 => FunctionCode::SuspensionSystemController, + 36 => FunctionCode::PneumaticSystemController, + 37 => FunctionCode::CabController, + 38 => FunctionCode::TirePressureControl, + 39 => FunctionCode::IgnitionControlModule, + 40 => FunctionCode::SeatControl, + 41 => FunctionCode::LightingOperatorControls, + 42 => FunctionCode::WaterPumpControl, + 43 => FunctionCode::TransmissionDisplay, + 44 => FunctionCode::ExhaustEmissionControl, + 45 => FunctionCode::VehicleDynamicStabilityControl, + 46 => FunctionCode::OilSensorUnit, + 47 => FunctionCode::InformationSystemController, + 48 => FunctionCode::RampControl, + 49 => FunctionCode::ClutchConverterControl, + 50 => FunctionCode::AuxiliaryHeater, + 51 => FunctionCode::ForwardLookingCollisionWarningSystem, + 52 => FunctionCode::ChassisController, + 53 => FunctionCode::AlternatorChargingSystem, + 54 => FunctionCode::CommunicationsUnitCellular, + 55 => FunctionCode::CommunicationsUnitSatellite, + 56 => FunctionCode::CommunicationsUnitRadio, + 57 => FunctionCode::SteeringColumnUnit, + 58 => FunctionCode::FanDriveControl, + 59 => FunctionCode::Starter, + 60 => FunctionCode::CabDisplay, + 61 => FunctionCode::FileServerPrinter, + 62 => FunctionCode::OnBoardDiagnosticUnit, + 63 => FunctionCode::EngineValveController, + 64 => FunctionCode::EnduranceBraking, + 65 => FunctionCode::GasFlowMeasurement, + 66 => FunctionCode::IOController, + 67 => FunctionCode::ElectricalSystemController, + 68 => FunctionCode::AfterTreatmentSystemGasMeasurement, + 69 => FunctionCode::EngineEmissionAfterTreatmentSystem, + 70 => FunctionCode::AuxiliaryRegenerationDevice, + 71 => FunctionCode::TransferCaseControl, + 72 => FunctionCode::CoolantValveController, + 73 => FunctionCode::RolloverDetectionControl, + 74 => FunctionCode::LubricationSystem, + 75 => FunctionCode::SupplementalFan, + 76 => FunctionCode::TemperatureSensor, + 77 => FunctionCode::FuelPropertiesSensor, + 78 => FunctionCode::FireSuppressionSystem, + 79 => FunctionCode::PowerSystemsManager, + 80 => FunctionCode::ElectricPowertrain, + 81 => FunctionCode::HydraulicPowertrain, + 82 => FunctionCode::FileServer, + 83 => FunctionCode::Printer, + 84 => FunctionCode::StartAidDevice, + 85 => FunctionCode::EngineInjectionControlModule, + 86 => FunctionCode::EVCommunicationController, + 87 => FunctionCode::DriverImpairmentDevice, + 88 => FunctionCode::ElectricPowerConverter, + 89 => FunctionCode::SupplyEquipmentCommunicationController, + 90 => FunctionCode::VehicleAdapterCommunicationController, + 128 => FunctionCode::Reserved, + 129 => FunctionCode::OffBoardDiagnosticServiceTool, + 130 => FunctionCode::OnBoardDataLogger, + 131 => FunctionCode::PCKeyboard, + 132 => FunctionCode::SafetyRestraintSystem, + 133 => FunctionCode::Turbocharger, + 134 => FunctionCode::GroundBasedSpeedSensor, + 135 => FunctionCode::Keypad, + 136 => FunctionCode::HumiditySensor, + 137 => FunctionCode::ThermalManagementSystemController, + 138 => FunctionCode::BrakeStrokeAlert, + 139 => FunctionCode::OnBoardAxleGroupScale, + 140 => FunctionCode::OnBoardAxleGroupDisplay, + 141 => FunctionCode::BatteryCharger, + 142 => FunctionCode::TurbochargerCompressorBypass, + 143 => FunctionCode::TurbochargerWastegate, + 144 => FunctionCode::Throttle, + 145 => FunctionCode::InertialSensor, + 146 => FunctionCode::FuelActuator, + 147 => FunctionCode::EngineExhaustGasRecirculation, + 148 => FunctionCode::EngineExhaustBackpressure, + 149 => FunctionCode::OnBoardBinWeighingScale, + 150 => FunctionCode::OnBoardBinWeighingScaleDisplay, + 151 => FunctionCode::EngineCylinderPressureMonitoringSystem, + 152 => FunctionCode::ObjectDetection, + 153 => FunctionCode::ObjectDetectionDisplay, + 154 => FunctionCode::ObjectDetectionSensor, + 155 => FunctionCode::PersonnelDetectionDevice, + _ => FunctionCode::NotAvailable, + } + } +} diff --git a/src/network_management/name/industry_group.rs b/src/network_management/name/industry_group.rs new file mode 100644 index 0000000..a850d5a --- /dev/null +++ b/src/network_management/name/industry_group.rs @@ -0,0 +1,87 @@ +// Copyright 2023 Raven Industries inc. + +/// Enum containing all Industry Groups. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::IndustryGroup; +/// let industry_group: IndustryGroup = IndustryGroup::AgriculturalAndForestryEquipment; +/// +/// assert_eq!(industry_group, IndustryGroup::from(2)); +/// assert_eq!(industry_group, 2.into()); +/// assert_eq!(2, u8::from(industry_group)); +/// assert_eq!(2_u8, industry_group.into()); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] +#[repr(C)] +pub enum IndustryGroup { + #[default] + Global = 0, + OnHighwayEquipment = 1, + AgriculturalAndForestryEquipment = 2, + ConstructionEquipment = 3, + MarineEquipment = 4, + IndustrialProcessControl = 5, + ReservedForSAE1 = 6, + ReservedForSAE2 = 7, +} + +/// Display the Industry Group name. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::IndustryGroup; +/// +/// assert_eq!("AgriculturalAndForestryEquipment", format!("{}", IndustryGroup::AgriculturalAndForestryEquipment)); +/// ``` +impl core::fmt::Display for IndustryGroup { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} + +/// Convert a `IndustryGroup` into a u8. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::IndustryGroup; +/// +/// assert_eq!(2, u8::from(IndustryGroup::AgriculturalAndForestryEquipment)); +/// assert_eq!(2_u8, IndustryGroup::AgriculturalAndForestryEquipment.into()); +/// ``` +impl From for u8 { + fn from(value: IndustryGroup) -> Self { + value as u8 + } +} + +/// Convert a u8 into a `IndustryGroup`. +/// +/// # Examples +/// +/// ```rust +/// # use ag_iso_stack::network_management::name::IndustryGroup; +/// +/// assert_eq!(IndustryGroup::AgriculturalAndForestryEquipment, IndustryGroup::from(2)); +/// assert_eq!(IndustryGroup::AgriculturalAndForestryEquipment, 2.into()); +/// ``` +impl From for IndustryGroup { + fn from(value: u8) -> Self { + match value { + 0 => IndustryGroup::Global, + 1 => IndustryGroup::OnHighwayEquipment, + 2 => IndustryGroup::AgriculturalAndForestryEquipment, + 3 => IndustryGroup::ConstructionEquipment, + 4 => IndustryGroup::MarineEquipment, + 5 => IndustryGroup::IndustrialProcessControl, + 6 => IndustryGroup::ReservedForSAE1, + 7 => IndustryGroup::ReservedForSAE2, + _ => { + unreachable!("Internal error converting a value larger than 7 to an IndustryGroup") + } + } + } +} diff --git a/src/network_management/name/mod.rs b/src/network_management/name/mod.rs new file mode 100644 index 0000000..7e8b840 --- /dev/null +++ b/src/network_management/name/mod.rs @@ -0,0 +1,429 @@ +// Copyright 2023 Raven Industries inc. + +mod name_filter; +pub use name_filter::NameFilter; +mod industry_group; +pub use industry_group::IndustryGroup; +mod device_class; +pub use device_class::DeviceClass; +mod function_code; +pub use function_code::FunctionCode; + +#[derive(Default, Copy, Clone, PartialEq)] +pub struct NAME { + raw_name: u64, +} + +impl NAME { + pub fn new(raw_name: u64) -> Self { + Self { raw_name } + } + + pub fn builder() -> NameBuilder { + NameBuilder::default() + } + + /// Match `self` against the provided `NameFilter`s + /// + /// Returns true, only if all filters match + pub fn match_filters(&self, name_filters: &[NameFilter]) -> bool { + name_filters + .iter() + .all(|name_filter| name_filter.match_filter(self)) + } + + /// Raven specific + pub fn short_identity_number(&self) -> u16 { + (self.raw_name & 0x0000FFFF) as u16 + } + + /// Raven specific + pub fn set_short_identity_number(&mut self, short_identity_number: u16) { + self.raw_name &= !0x000000000000FFFF; + self.raw_name |= short_identity_number as u64; + } + + /// Raven specific + pub fn extended_identity_number(&self) -> u8 { + ((self.raw_name >> 16) & 0x1F) as u8 + } + + /// Raven specific + pub fn set_extended_identity_number(&mut self, extended_identity_number: u8) { + self.raw_name &= !0x00000000001F0000; + self.raw_name |= ((extended_identity_number & 0x1F) as u64) << 16; + } + + pub fn identity_number(&self) -> u32 { + (self.raw_name & 0x001FFFFF) as u32 + } + + pub fn set_identity_number(&mut self, identity_number: u32) { + self.raw_name &= !0x00000000001FFFFF; + self.raw_name |= (identity_number & 0x00000000001FFFFF) as u64; + } + + pub fn manufacturer_code(&self) -> u16 { + ((self.raw_name >> 21) & 0x07FF) as u16 + } + + pub fn set_manufacturer_code(&mut self, manufacturer_code: u16) { + self.raw_name &= !0x00000000FFE00000; + self.raw_name |= ((manufacturer_code & 0x07FF) as u64) << 21; + } + + pub fn ecu_instance(&self) -> u8 { + ((self.raw_name >> 32) & 0x07) as u8 + } + + pub fn set_ecu_instance(&mut self, ecu_instance: u8) { + self.raw_name &= !0x0000000700000000; + self.raw_name |= ((ecu_instance & 0x07) as u64) << 32; + } + + pub fn function_instance(&self) -> u8 { + ((self.raw_name >> 35) & 0x1F) as u8 + } + + pub fn set_function_instance(&mut self, function: u8) { + self.raw_name &= !0x000000F800000000; + self.raw_name |= ((function & 0x1F) as u64) << 35; + } + + pub fn function_code(&self) -> FunctionCode { + (((self.raw_name >> 40) & 0xFF) as u8).into() + } + + pub fn set_function_code(&mut self, function_code: impl Into) { + self.raw_name &= !0x0000FF0000000000; + self.raw_name |= (function_code.into() as u64) << 40; + } + + pub fn device_class(&self) -> DeviceClass { + (((self.raw_name >> 49) & 0x7F) as u8, self.industry_group()).into() + } + + pub fn set_device_class(&mut self, device_class: DeviceClass) { + self.set_industry_group(device_class.into()); // Derive the industrygroup from the device class + + self.raw_name &= !0x00FE000000000000_u64; + self.raw_name |= ((u8::from(device_class) & 0x7F) as u64) << 49; + } + + pub fn device_class_instance(&self) -> u8 { + ((self.raw_name >> 56) & 0x0F) as u8 + } + + pub fn set_device_class_instance(&mut self, device_class_instance: u8) { + self.raw_name &= !0x0F00000000000000; + self.raw_name |= ((device_class_instance & 0x0F) as u64) << 56; + } + + pub fn industry_group(&self) -> IndustryGroup { + (((self.raw_name >> 60) & 0x07) as u8).into() + } + + pub fn set_industry_group(&mut self, industry_group: IndustryGroup) { + self.raw_name &= !0x7000000000000000; + self.raw_name |= ((u8::from(industry_group) & 0x07) as u64) << 60; + } + + pub fn self_configurable_address(&self) -> bool { + (self.raw_name >> 63) != 0 + } + + pub fn set_self_configurable_address(&mut self, self_configurable_address: bool) { + self.raw_name &= !0x8000000000000000; + self.raw_name |= (self_configurable_address as u64) << 63; + } +} + +impl From for u64 { + fn from(name: NAME) -> Self { + name.raw_name + } +} + +impl core::fmt::Display for NAME { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "0x{:08X}", self.raw_name) + } +} + +impl core::fmt::Debug for NAME { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("NAME") + .field( + "identity_number", + &format_args!("{}", self.identity_number()), + ) + .field( + "manufacturer_code", + &format_args!("{}", self.manufacturer_code()), + ) + .field("ecu_instance", &format_args!("{}", self.ecu_instance())) + .field( + "function_instance", + &format_args!("{}", self.function_instance()), + ) + .field("function_code", &format_args!("{}", self.function_code())) + .field("device_class", &format_args!("{}", self.device_class())) + .field( + "device_class_instance", + &format_args!("{}", self.device_class_instance()), + ) + .field("industry_group", &format_args!("{}", self.industry_group())) + .field( + "self_configurable_address", + &format_args!("{}", self.self_configurable_address()), + ) + .finish() + } +} + +#[derive(Default)] +pub struct NameBuilder { + identity_number: u32, + manufacturer_code: u16, + ecu_instance: u8, + function_instance: u8, + function_code: FunctionCode, + device_class: DeviceClass, + device_class_instance: u8, + industry_group: IndustryGroup, + self_configurable_address: bool, +} + +impl NameBuilder { + pub fn new() -> NameBuilder { + NameBuilder::default() + } + + pub fn build(&self) -> NAME { + let mut name = NAME::default(); + name.set_identity_number(self.identity_number); + name.set_manufacturer_code(self.manufacturer_code); + name.set_ecu_instance(self.ecu_instance); + name.set_function_instance(self.function_instance); + name.set_function_code(self.function_code); + name.set_device_class(self.device_class); + name.set_device_class_instance(self.device_class_instance); + name.set_industry_group(self.industry_group); + name.set_self_configurable_address(self.self_configurable_address); + name + } + + /// Raven specific + pub fn short_identity_number(&mut self, value: u16) -> &mut NameBuilder { + self.identity_number &= !0x0000FFFF; + self.identity_number |= value as u32; + self + } + /// Raven specific + pub fn extended_identity_number(&mut self, value: u8) -> &mut NameBuilder { + self.identity_number &= !0x001F0000; + self.identity_number |= ((value & 0x1F) as u32) << 16; + self + } + pub fn identity_number(&mut self, value: u32) -> &mut NameBuilder { + self.identity_number = value; + self + } + pub fn manufacturer_code(&mut self, value: u16) -> &mut NameBuilder { + self.manufacturer_code = value; + self + } + pub fn ecu_instance(&mut self, value: u8) -> &mut NameBuilder { + self.ecu_instance = value; + self + } + pub fn function_instance(&mut self, value: u8) -> &mut NameBuilder { + self.function_instance = value; + self + } + pub fn function_code(&mut self, value: FunctionCode) -> &mut NameBuilder { + self.function_code = value; + self + } + pub fn device_class(&mut self, value: DeviceClass) -> &mut NameBuilder { + self.device_class = value; + self + } + pub fn device_class_instance(&mut self, value: u8) -> &mut NameBuilder { + self.device_class_instance = value; + self + } + pub fn industry_group(&mut self, value: IndustryGroup) -> &mut NameBuilder { + self.industry_group = value; + self + } + pub fn self_configurable_address(&mut self, value: bool) -> &mut NameBuilder { + self.self_configurable_address = value; + self + } +} + +impl From for NameBuilder { + fn from(value: NAME) -> Self { + NameBuilder { + identity_number: value.identity_number(), + manufacturer_code: value.manufacturer_code(), + ecu_instance: value.ecu_instance(), + function_instance: value.function_instance(), + function_code: value.function_code(), + device_class: value.device_class(), + device_class_instance: value.device_class_instance(), + industry_group: value.industry_group(), + self_configurable_address: value.self_configurable_address(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_name_properties() { + let mut name_under_test = NAME::new(0); + + name_under_test.set_self_configurable_address(true); + name_under_test.set_industry_group(IndustryGroup::OnHighwayEquipment); + name_under_test.set_device_class(DeviceClass::Trailer); + name_under_test.set_function_code(FunctionCode::Transmission); + name_under_test.set_identity_number(4); + name_under_test.set_ecu_instance(5); + name_under_test.set_function_instance(6); + name_under_test.set_device_class_instance(7); + name_under_test.set_manufacturer_code(8); + + assert_eq!(true, name_under_test.self_configurable_address()); + assert_eq!(1, u8::from(name_under_test.industry_group())); + assert_eq!(2, u8::from(name_under_test.device_class())); + assert_eq!(3, u8::from(name_under_test.function_code())); + assert_eq!(4, name_under_test.identity_number()); + assert_eq!(5, name_under_test.ecu_instance()); + assert_eq!(6, name_under_test.function_instance()); + assert_eq!(7, name_under_test.device_class_instance()); + assert_eq!(8, name_under_test.manufacturer_code()); + assert_eq!(0, name_under_test.extended_identity_number()); + assert_eq!(4, name_under_test.short_identity_number()); + assert_eq!(10881826125818888196_u64, name_under_test.raw_name); + } + + #[test] + fn test_name_builder() { + let name_under_test = NAME::builder() + .identity_number(4_u32) + .manufacturer_code(8_u16) + .ecu_instance(5) + .function_instance(6) + .function_code(FunctionCode::from(3)) + .device_class(DeviceClass::from((2, IndustryGroup::from(1)))) + .device_class_instance(7) + .industry_group(IndustryGroup::from(1)) + .self_configurable_address(true) + .build(); + + assert_eq!(10881826125818888196_u64, name_under_test.into()); + } + + #[test] + fn test_out_of_range_properties() { + let mut name_under_test = NAME::new(0); + + name_under_test.set_device_class_instance(16); + name_under_test.set_identity_number(2097152); + name_under_test.set_ecu_instance(8); + name_under_test.set_function_instance(32); + name_under_test.set_manufacturer_code(2048); + + assert_ne!(name_under_test.device_class_instance(), 16); + assert_ne!(name_under_test.identity_number(), 2097151); + assert_ne!(name_under_test.ecu_instance(), 8); + assert_ne!(name_under_test.function_instance(), 32); + assert_ne!(name_under_test.manufacturer_code(), 2048); + } + + #[test] + fn test_name_equality() { + let test_value: u64 = 10376445291390828545; + let name_under_test1 = NAME::new(test_value); + let name_under_test2 = NAME::new(test_value); + + assert_eq!(test_value, name_under_test1.raw_name); + assert_eq!(name_under_test1.raw_name, name_under_test2.raw_name); + assert_eq!(name_under_test1, name_under_test2); + } + + #[test] + fn test_filter_matching() { + let mut test_name = NAME::new(0); + let mut filters_to_test = Vec::new(); + let identity_number_filter = NameFilter::IdentityNumber(1); + filters_to_test.push(identity_number_filter); + + assert_eq!(false, test_name.match_filters(&filters_to_test)); + test_name.set_identity_number(1); + assert_eq!(true, test_name.match_filters(&filters_to_test)); + + let manufacturer_number_filter = NameFilter::ManufacturerCode(2); + filters_to_test.push(manufacturer_number_filter); + + assert_eq!(false, test_name.match_filters(&filters_to_test)); + test_name.set_manufacturer_code(2); + assert_eq!(true, test_name.match_filters(&filters_to_test)); + + let ecu_instance_filter = NameFilter::EcuInstance(3); + filters_to_test.push(ecu_instance_filter); + + assert_eq!(false, test_name.match_filters(&filters_to_test)); + test_name.set_ecu_instance(3); + assert_eq!(true, test_name.match_filters(&filters_to_test)); + + let function_instance_filter = NameFilter::FunctionInstance(4); + filters_to_test.push(function_instance_filter); + + assert_eq!(false, test_name.match_filters(&filters_to_test)); + test_name.set_function_instance(4); + assert_eq!(true, test_name.match_filters(&filters_to_test)); + + let function_filter = NameFilter::FunctionCode(FunctionCode::VirtualTerminal); + filters_to_test.push(function_filter); + + assert_eq!(false, test_name.match_filters(&filters_to_test)); + test_name.set_function_code(FunctionCode::VirtualTerminal); + assert_eq!(true, test_name.match_filters(&filters_to_test)); + + let device_class_filter = NameFilter::DeviceClass(DeviceClass::Tractor( + IndustryGroup::AgriculturalAndForestryEquipment, + )); + filters_to_test.push(device_class_filter); + + assert_eq!(false, test_name.match_filters(&filters_to_test)); + test_name.set_device_class(DeviceClass::Tractor( + IndustryGroup::AgriculturalAndForestryEquipment, + )); + assert_eq!(true, test_name.match_filters(&filters_to_test)); + + let industry_group_filter = + NameFilter::IndustryGroup(IndustryGroup::AgriculturalAndForestryEquipment); + filters_to_test.push(industry_group_filter); + + assert_eq!(true, test_name.match_filters(&filters_to_test)); + + let device_class_instance_filter = NameFilter::DeviceClassInstance(8); + filters_to_test.push(device_class_instance_filter); + + assert_eq!(false, test_name.match_filters(&filters_to_test)); + test_name.set_device_class_instance(8); + assert_eq!(true, test_name.match_filters(&filters_to_test)); + + let self_configurable_address_filter = NameFilter::SelfConfigurableAddress(true); + filters_to_test.push(self_configurable_address_filter); + + assert_eq!(false, test_name.match_filters(&filters_to_test)); + test_name.set_self_configurable_address(true); + assert_eq!(true, test_name.match_filters(&filters_to_test)); + } +} diff --git a/src/network_management/name/name_filter.rs b/src/network_management/name/name_filter.rs new file mode 100644 index 0000000..92e96b2 --- /dev/null +++ b/src/network_management/name/name_filter.rs @@ -0,0 +1,40 @@ +// Copyright 2023 Raven Industries inc. + +use super::{DeviceClass, FunctionCode, IndustryGroup, NAME}; + +/// A struct that associates a NAME parameter with a value of that parameter. +/// This struct is used to match a partner control function with specific criteria that +/// defines it. Use these to define what device you want to talk to. +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum NameFilter { + IdentityNumber(u32), + ShortIdentityNumber(u16), //< Raven specific + ExtendedIdentityNumber(u8), //< Raven specific + ManufacturerCode(u16), + EcuInstance(u8), + FunctionInstance(u8), + FunctionCode(FunctionCode), + DeviceClass(DeviceClass), + DeviceClassInstance(u8), + IndustryGroup(IndustryGroup), + SelfConfigurableAddress(bool), +} + +impl NameFilter { + /// Returns true if `name` matches this filter's component. + pub fn match_filter(&self, name: &NAME) -> bool { + match self { + NameFilter::IdentityNumber(val) => name.identity_number() == *val, + NameFilter::ShortIdentityNumber(val) => name.short_identity_number() == *val, + NameFilter::ExtendedIdentityNumber(val) => name.extended_identity_number() == *val, + NameFilter::ManufacturerCode(val) => name.manufacturer_code() == *val, + NameFilter::EcuInstance(val) => name.ecu_instance() == *val, + NameFilter::FunctionInstance(val) => name.function_instance() == *val, + NameFilter::FunctionCode(val) => name.function_code() == *val, + NameFilter::DeviceClass(val) => name.device_class() == *val, + NameFilter::DeviceClassInstance(val) => name.device_class_instance() == *val, + NameFilter::IndustryGroup(val) => name.industry_group() == *val, + NameFilter::SelfConfigurableAddress(val) => name.self_configurable_address() == *val, + } + } +} From ac2225d0065b2b40436229c7eb3b4f8ccd788af7 Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 15 Aug 2023 14:34:13 +0200 Subject: [PATCH 2/2] Add ObjectPool --- src/object_pool/mod.rs | 1280 ++++++++++++++++++++++++++++++++ src/object_pool/object_pool.rs | 142 ++++ src/object_pool/reader.rs | 1011 +++++++++++++++++++++++++ src/object_pool/writer.rs | 681 +++++++++++++++++ 4 files changed, 3114 insertions(+) create mode 100644 src/object_pool/mod.rs create mode 100644 src/object_pool/object_pool.rs create mode 100644 src/object_pool/reader.rs create mode 100644 src/object_pool/writer.rs diff --git a/src/object_pool/mod.rs b/src/object_pool/mod.rs new file mode 100644 index 0000000..b982e2a --- /dev/null +++ b/src/object_pool/mod.rs @@ -0,0 +1,1280 @@ +pub mod reader; +pub mod writer; + +use alloc::{string::String, vec::Vec}; + +use crate::name::Name; + +mod object_pool; +pub use object_pool::ObjectPool; + +pub enum ParseError { + DataEmpty, + UnknownObjectType, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum ObjectType { + WorkingSet = 0, + DataMask = 1, + AlarmMask = 2, + Container = 3, + SoftKeyMask = 4, + Key = 5, + Button = 6, + InputBoolean = 7, + InputString = 8, + InputNumber = 9, + InputList = 10, + OutputString = 11, + OutputNumber = 12, + OutputLine = 13, + OutputRectangle = 14, + OutputEllipse = 15, + OutputPolygon = 16, + OutputMeter = 17, + OutputLinearBarGraph = 18, + OutputArchedBarGraph = 19, + PictureGraphic = 20, + NumberVariable = 21, + StringVariable = 22, + FontAttributes = 23, + LineAttributes = 24, + FillAttributes = 25, + InputAttributes = 26, + ObjectPointer = 27, + Macro = 28, + AuxiliaryFunctionType1 = 29, + AuxiliaryInputType1 = 30, + AuxiliaryFunctionType2 = 31, + AuxiliaryInputType2 = 32, + AuxiliaryControlDesignatorType2 = 33, + WindowMask = 34, + KeyGroup = 35, + GraphicsContext = 36, + OutputList = 37, + ExtendedInputAttributes = 38, + ColourMap = 39, + ObjectLabelReferenceList = 40, + ExternalObjectDefinition = 41, + ExternalReferenceName = 42, + ExternalObjectPointer = 43, + Animation = 44, + ColourPalette = 45, + GraphicData = 46, + WorkingSetSpecialControls = 47, + ScalesGraphic = 48, +} + +impl TryFrom for ObjectType { + type Error = ParseError; + + fn try_from(val: u8) -> Result { + match val { + 0 => Ok(Self::WorkingSet), + 1 => Ok(Self::DataMask), + 2 => Ok(Self::AlarmMask), + 3 => Ok(Self::Container), + 4 => Ok(Self::SoftKeyMask), + 5 => Ok(Self::Key), + 6 => Ok(Self::Button), + 7 => Ok(Self::InputBoolean), + 8 => Ok(Self::InputString), + 9 => Ok(Self::InputNumber), + 10 => Ok(Self::InputList), + 11 => Ok(Self::OutputString), + 12 => Ok(Self::OutputNumber), + 13 => Ok(Self::OutputLine), + 14 => Ok(Self::OutputRectangle), + 15 => Ok(Self::OutputEllipse), + 16 => Ok(Self::OutputPolygon), + 17 => Ok(Self::OutputMeter), + 18 => Ok(Self::OutputLinearBarGraph), + 19 => Ok(Self::OutputArchedBarGraph), + 20 => Ok(Self::PictureGraphic), + 21 => Ok(Self::NumberVariable), + 22 => Ok(Self::StringVariable), + 23 => Ok(Self::FontAttributes), + 24 => Ok(Self::LineAttributes), + 25 => Ok(Self::FillAttributes), + 26 => Ok(Self::InputAttributes), + 27 => Ok(Self::ObjectPointer), + 28 => Ok(Self::Macro), + 29 => Ok(Self::AuxiliaryFunctionType1), + 30 => Ok(Self::AuxiliaryInputType1), + 31 => Ok(Self::AuxiliaryFunctionType2), + 32 => Ok(Self::AuxiliaryInputType2), + 33 => Ok(Self::AuxiliaryControlDesignatorType2), + 34 => Ok(Self::WindowMask), + 35 => Ok(Self::KeyGroup), + 36 => Ok(Self::GraphicsContext), + 37 => Ok(Self::OutputList), + 38 => Ok(Self::ExtendedInputAttributes), + 39 => Ok(Self::ColourMap), + 40 => Ok(Self::ObjectLabelReferenceList), + 41 => Ok(Self::ExternalObjectDefinition), + 42 => Ok(Self::ExternalReferenceName), + 43 => Ok(Self::ExternalObjectPointer), + 44 => Ok(Self::Animation), + 45 => Ok(Self::ColourPalette), + 46 => Ok(Self::GraphicData), + 47 => Ok(Self::WorkingSetSpecialControls), + 48 => Ok(Self::ScalesGraphic), + _ => Err(ParseError::UnknownObjectType), + } + } +} + +impl From for u8 { + fn from(val: ObjectType) -> Self { + match val { + ObjectType::WorkingSet => 0, + ObjectType::DataMask => 1, + ObjectType::AlarmMask => 2, + ObjectType::Container => 3, + ObjectType::SoftKeyMask => 4, + ObjectType::Key => 5, + ObjectType::Button => 6, + ObjectType::InputBoolean => 7, + ObjectType::InputString => 8, + ObjectType::InputNumber => 9, + ObjectType::InputList => 10, + ObjectType::OutputString => 11, + ObjectType::OutputNumber => 12, + ObjectType::OutputLine => 13, + ObjectType::OutputRectangle => 14, + ObjectType::OutputEllipse => 15, + ObjectType::OutputPolygon => 16, + ObjectType::OutputMeter => 17, + ObjectType::OutputLinearBarGraph => 18, + ObjectType::OutputArchedBarGraph => 19, + ObjectType::PictureGraphic => 20, + ObjectType::NumberVariable => 21, + ObjectType::StringVariable => 22, + ObjectType::FontAttributes => 23, + ObjectType::LineAttributes => 24, + ObjectType::FillAttributes => 25, + ObjectType::InputAttributes => 26, + ObjectType::ObjectPointer => 27, + ObjectType::Macro => 28, + ObjectType::AuxiliaryFunctionType1 => 29, + ObjectType::AuxiliaryInputType1 => 30, + ObjectType::AuxiliaryFunctionType2 => 31, + ObjectType::AuxiliaryInputType2 => 32, + ObjectType::AuxiliaryControlDesignatorType2 => 33, + ObjectType::WindowMask => 34, + ObjectType::KeyGroup => 35, + ObjectType::GraphicsContext => 36, + ObjectType::OutputList => 37, + ObjectType::ExtendedInputAttributes => 38, + ObjectType::ColourMap => 39, + ObjectType::ObjectLabelReferenceList => 40, + ObjectType::ExternalObjectDefinition => 41, + ObjectType::ExternalReferenceName => 42, + ObjectType::ExternalObjectPointer => 43, + ObjectType::Animation => 44, + ObjectType::ColourPalette => 45, + ObjectType::GraphicData => 46, + ObjectType::WorkingSetSpecialControls => 47, + ObjectType::ScalesGraphic => 48, + } + } +} + +#[derive(Debug)] +pub enum Object { + WorkingSet(WorkingSet), + DataMask(DataMask), + AlarmMask(AlarmMask), + Container(Container), + SoftKeyMask(SoftKeyMask), + Key(Key), + Button(Button), + InputBoolean(InputBoolean), + InputString(InputString), + InputNumber(InputNumber), + InputList(InputList), + OutputString(OutputString), + OutputNumber(OutputNumber), + OutputLine(OutputLine), + OutputRectangle(OutputRectangle), + OutputEllipse(OutputEllipse), + OutputPolygon(OutputPolygon), + OutputMeter(OutputMeter), + OutputLinearBarGraph(OutputLinearBarGraph), + OutputArchedBarGraph(OutputArchedBarGraph), + PictureGraphic(PictureGraphic), + NumberVariable(NumberVariable), + StringVariable(StringVariable), + FontAttributes(FontAttributes), + LineAttributes(LineAttributes), + FillAttributes(FillAttributes), + InputAttributes(InputAttributes), + ObjectPointer(ObjectPointer), + Macro(Macro), + AuxiliaryFunctionType1(AuxiliaryFunctionType1), + AuxiliaryInputType1(AuxiliaryInputType1), + AuxiliaryFunctionType2(AuxiliaryFunctionType2), + AuxiliaryInputType2(AuxiliaryInputType2), + AuxiliaryControlDesignatorType2(AuxiliaryControlDesignatorType2), + WindowMask(WindowMask), + KeyGroup(KeyGroup), + GraphicsContext(GraphicsContext), + OutputList(OutputList), + ExtendedInputAttributes(ExtendedInputAttributes), + ColourMap(ColourMap), + ObjectLabelReferenceList(ObjectLabelReferenceList), + ExternalObjectDefinition(ExternalObjectDefinition), + ExternalReferenceName(ExternalReferenceName), + ExternalObjectPointer(ExternalObjectPointer), + Animation(Animation), + ColourPalette(ColourPalette), + GraphicData(GraphicData), + WorkingSetSpecialControls(WorkingSetSpecialControls), + ScalesGraphic(ScalesGraphic), +} + +impl Object { + pub fn id(&self) -> ObjectId { + match self { + Object::WorkingSet(o) => o.id, + Object::DataMask(o) => o.id, + Object::AlarmMask(o) => o.id, + Object::Container(o) => o.id, + Object::SoftKeyMask(o) => o.id, + Object::Key(o) => o.id, + Object::Button(o) => o.id, + Object::InputBoolean(o) => o.id, + Object::InputString(o) => o.id, + Object::InputNumber(o) => o.id, + Object::InputList(o) => o.id, + Object::OutputString(o) => o.id, + Object::OutputNumber(o) => o.id, + Object::OutputLine(o) => o.id, + Object::OutputRectangle(o) => o.id, + Object::OutputEllipse(o) => o.id, + Object::OutputPolygon(o) => o.id, + Object::OutputMeter(o) => o.id, + Object::OutputLinearBarGraph(o) => o.id, + Object::OutputArchedBarGraph(o) => o.id, + Object::PictureGraphic(o) => o.id, + Object::NumberVariable(o) => o.id, + Object::StringVariable(o) => o.id, + Object::FontAttributes(o) => o.id, + Object::LineAttributes(o) => o.id, + Object::FillAttributes(o) => o.id, + Object::InputAttributes(o) => o.id, + Object::ObjectPointer(o) => o.id, + Object::Macro(o) => o.id, + Object::AuxiliaryFunctionType1(o) => o.id, + Object::AuxiliaryInputType1(o) => o.id, + Object::AuxiliaryFunctionType2(o) => o.id, + Object::AuxiliaryInputType2(o) => o.id, + Object::AuxiliaryControlDesignatorType2(o) => o.id, + Object::WindowMask(o) => o.id, + Object::KeyGroup(o) => o.id, + Object::GraphicsContext(o) => o.id, + Object::OutputList(o) => o.id, + Object::ExtendedInputAttributes(o) => o.id, + Object::ColourMap(o) => o.id, + Object::ObjectLabelReferenceList(o) => o.id, + Object::ExternalObjectDefinition(o) => o.id, + Object::ExternalReferenceName(o) => o.id, + Object::ExternalObjectPointer(o) => o.id, + Object::Animation(o) => o.id, + Object::ColourPalette(o) => o.id, + Object::GraphicData(o) => o.id, + Object::WorkingSetSpecialControls(o) => o.id, + Object::ScalesGraphic(o) => o.id, + } + } + + pub fn object_type(&self) -> ObjectType { + match self { + Object::WorkingSet(_) => ObjectType::WorkingSet, + Object::DataMask(_) => ObjectType::DataMask, + Object::AlarmMask(_) => ObjectType::AlarmMask, + Object::Container(_) => ObjectType::Container, + Object::SoftKeyMask(_) => ObjectType::SoftKeyMask, + Object::Key(_) => ObjectType::Key, + Object::Button(_) => ObjectType::Button, + Object::InputBoolean(_) => ObjectType::InputBoolean, + Object::InputString(_) => ObjectType::InputString, + Object::InputNumber(_) => ObjectType::InputNumber, + Object::InputList(_) => ObjectType::InputList, + Object::OutputString(_) => ObjectType::OutputString, + Object::OutputNumber(_) => ObjectType::OutputNumber, + Object::OutputLine(_) => ObjectType::OutputLine, + Object::OutputRectangle(_) => ObjectType::OutputRectangle, + Object::OutputEllipse(_) => ObjectType::OutputEllipse, + Object::OutputPolygon(_) => ObjectType::OutputPolygon, + Object::OutputMeter(_) => ObjectType::OutputMeter, + Object::OutputLinearBarGraph(_) => ObjectType::OutputLinearBarGraph, + Object::OutputArchedBarGraph(_) => ObjectType::OutputArchedBarGraph, + Object::PictureGraphic(_) => ObjectType::PictureGraphic, + Object::NumberVariable(_) => ObjectType::NumberVariable, + Object::StringVariable(_) => ObjectType::StringVariable, + Object::FontAttributes(_) => ObjectType::FontAttributes, + Object::LineAttributes(_) => ObjectType::LineAttributes, + Object::FillAttributes(_) => ObjectType::FillAttributes, + Object::InputAttributes(_) => ObjectType::InputAttributes, + Object::ObjectPointer(_) => ObjectType::ObjectPointer, + Object::Macro(_) => ObjectType::Macro, + Object::AuxiliaryFunctionType1(_) => ObjectType::AuxiliaryFunctionType1, + Object::AuxiliaryInputType1(_) => ObjectType::AuxiliaryInputType1, + Object::AuxiliaryFunctionType2(_) => ObjectType::AuxiliaryFunctionType2, + Object::AuxiliaryInputType2(_) => ObjectType::AuxiliaryInputType2, + Object::AuxiliaryControlDesignatorType2(_) => { + ObjectType::AuxiliaryControlDesignatorType2 + } + Object::WindowMask(_) => ObjectType::WindowMask, + Object::KeyGroup(_) => ObjectType::KeyGroup, + Object::GraphicsContext(_) => ObjectType::GraphicsContext, + Object::OutputList(_) => ObjectType::OutputList, + Object::ExtendedInputAttributes(_) => ObjectType::ExtendedInputAttributes, + Object::ColourMap(_) => ObjectType::ColourMap, + Object::ObjectLabelReferenceList(_) => ObjectType::ObjectLabelReferenceList, + Object::ExternalObjectDefinition(_) => ObjectType::ExternalObjectDefinition, + Object::ExternalReferenceName(_) => ObjectType::ExternalReferenceName, + Object::ExternalObjectPointer(_) => ObjectType::ExternalObjectPointer, + Object::Animation(_) => ObjectType::Animation, + Object::ColourPalette(_) => ObjectType::ColourPalette, + Object::GraphicData(_) => ObjectType::GraphicData, + Object::WorkingSetSpecialControls(_) => ObjectType::WorkingSetSpecialControls, + Object::ScalesGraphic(_) => ObjectType::ScalesGraphic, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ObjectId(u16); +impl ObjectId { + pub const NULL: ObjectId = ObjectId(0xFFFF); +} +impl Default for ObjectId { + fn default() -> Self { + Self::NULL + } +} +impl From for ObjectId { + fn from(val: u16) -> Self { + ObjectId(val) + } +} +impl From for u16 { + fn from(val: ObjectId) -> Self { + val.0 + } +} +impl From<[u8; 2]> for ObjectId { + fn from(val: [u8; 2]) -> Self { + ObjectId(u16::from_le_bytes(val)) + } +} +impl From for [u8; 2] { + fn from(val: ObjectId) -> Self { + val.0.to_le_bytes() + } +} +// impl From> for ObjectId { +// fn from(val: Vec) -> Self { +// let val: ObjectId = val.as_slice().into(); +// val +// } +// } +// impl From for Vec { +// fn from(val: ObjectId) -> Self { +// let val: [u8;2] = val.into(); +// val.to_vec() +// } +// } +impl From<&[u8]> for ObjectId { + fn from(val: &[u8]) -> Self { + match val.len() { + 2.. => ObjectId(u16::from_le_bytes([val[0], val[1]])), + _ => ObjectId::NULL, + } + } +} + +#[derive(Debug)] +pub struct ObjectRef { + pub id: ObjectId, + pub offset: Point, + // pub x: i16, + // pub y: i16, +} + +#[derive(Debug)] +pub struct MacroRef { + pub macro_id: u8, + pub event_id: u8, +} + +#[derive(Debug, Clone, Copy)] +pub struct Colour { + pub a: u8, + pub r: u8, + pub g: u8, + pub b: u8, +} + +impl Colour { + pub fn as_rgb(&self) -> [u8; 3] { + [self.r, self.g, self.b] + } + + pub fn as_rgba(&self) -> [u8; 4] { + [self.r, self.g, self.b, self.a] + } + + pub const BLACK: Colour = Colour::COLOUR_PALETTE[0]; + pub const WHITE: Colour = Colour::COLOUR_PALETTE[1]; + pub const GREEN: Colour = Colour::COLOUR_PALETTE[2]; + pub const TEAL: Colour = Colour::COLOUR_PALETTE[3]; + pub const MAROON: Colour = Colour::COLOUR_PALETTE[4]; + pub const PURPLE: Colour = Colour::COLOUR_PALETTE[5]; + pub const OLIVE: Colour = Colour::COLOUR_PALETTE[6]; + pub const SILVER: Colour = Colour::COLOUR_PALETTE[7]; + pub const GREY: Colour = Colour::COLOUR_PALETTE[8]; + pub const BLUE: Colour = Colour::COLOUR_PALETTE[9]; + pub const LIME: Colour = Colour::COLOUR_PALETTE[10]; + pub const CYAN: Colour = Colour::COLOUR_PALETTE[11]; + pub const RED: Colour = Colour::COLOUR_PALETTE[12]; + pub const MAGENTA: Colour = Colour::COLOUR_PALETTE[13]; + pub const YELLOW: Colour = Colour::COLOUR_PALETTE[14]; + pub const NAVY: Colour = Colour::COLOUR_PALETTE[15]; + + #[rustfmt::skip] // Skip formatting the lines + pub const COLOUR_PALETTE: [Colour; 256] = [ + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0xFF, g: 0xFF, b: 0xFF, a: 0xFF }, + Colour { r: 0x00, g: 0x99, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x99, b: 0x99, a: 0xFF }, + Colour { r: 0x99, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x99, g: 0x00, b: 0x99, a: 0xFF }, + Colour { r: 0x99, g: 0x99, b: 0x00, a: 0xFF }, + Colour { r: 0xCC, g: 0xCC, b: 0xCC, a: 0xFF }, + Colour { r: 0x99, g: 0x99, b: 0x99, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0xFF, a: 0xFF }, + Colour { r: 0x00, g: 0xFF, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0xFF, b: 0xFF, a: 0xFF }, + Colour { r: 0xFF, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0xFF, g: 0x00, b: 0xFF, a: 0xFF }, + Colour { r: 0xFF, g: 0xFF, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x99, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x33, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x66, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x99, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0xCC, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0xFF, a: 0xFF }, + Colour { r: 0x00, g: 0x33, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x33, b: 0x33, a: 0xFF }, + Colour { r: 0x00, g: 0x33, b: 0x66, a: 0xFF }, + Colour { r: 0x00, g: 0x33, b: 0x99, a: 0xFF }, + Colour { r: 0x00, g: 0x33, b: 0xCC, a: 0xFF }, + Colour { r: 0x00, g: 0x33, b: 0xFF, a: 0xFF }, + Colour { r: 0x00, g: 0x66, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x66, b: 0x33, a: 0xFF }, + Colour { r: 0x00, g: 0x66, b: 0x66, a: 0xFF }, + Colour { r: 0x00, g: 0x66, b: 0x99, a: 0xFF }, + Colour { r: 0x00, g: 0x66, b: 0xCC, a: 0xFF }, + Colour { r: 0x00, g: 0x66, b: 0xFF, a: 0xFF }, + Colour { r: 0x00, g: 0x99, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x99, b: 0x33, a: 0xFF }, + Colour { r: 0x00, g: 0x99, b: 0x66, a: 0xFF }, + Colour { r: 0x00, g: 0x99, b: 0x99, a: 0xFF }, + Colour { r: 0x00, g: 0x99, b: 0xCC, a: 0xFF }, + Colour { r: 0x00, g: 0x99, b: 0xFF, a: 0xFF }, + Colour { r: 0x00, g: 0xCC, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0xCC, b: 0x33, a: 0xFF }, + Colour { r: 0x00, g: 0xCC, b: 0x66, a: 0xFF }, + Colour { r: 0x00, g: 0xCC, b: 0x99, a: 0xFF }, + Colour { r: 0x00, g: 0xCC, b: 0xCC, a: 0xFF }, + Colour { r: 0x00, g: 0xCC, b: 0xFF, a: 0xFF }, + Colour { r: 0x00, g: 0xFF, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0xFF, b: 0x33, a: 0xFF }, + Colour { r: 0x00, g: 0xFF, b: 0x66, a: 0xFF }, + Colour { r: 0x00, g: 0xFF, b: 0x99, a: 0xFF }, + Colour { r: 0x00, g: 0xFF, b: 0xCC, a: 0xFF }, + Colour { r: 0x00, g: 0xFF, b: 0xFF, a: 0xFF }, + Colour { r: 0x33, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x33, g: 0x00, b: 0x33, a: 0xFF }, + Colour { r: 0x33, g: 0x00, b: 0x66, a: 0xFF }, + Colour { r: 0x33, g: 0x00, b: 0x99, a: 0xFF }, + Colour { r: 0x33, g: 0x00, b: 0xCC, a: 0xFF }, + Colour { r: 0x33, g: 0x00, b: 0xFF, a: 0xFF }, + Colour { r: 0x33, g: 0x33, b: 0x00, a: 0xFF }, + Colour { r: 0x33, g: 0x33, b: 0x33, a: 0xFF }, + Colour { r: 0x33, g: 0x33, b: 0x66, a: 0xFF }, + Colour { r: 0x33, g: 0x33, b: 0x99, a: 0xFF }, + Colour { r: 0x33, g: 0x33, b: 0xCC, a: 0xFF }, + Colour { r: 0x33, g: 0x33, b: 0xFF, a: 0xFF }, + Colour { r: 0x33, g: 0x66, b: 0x00, a: 0xFF }, + Colour { r: 0x33, g: 0x66, b: 0x33, a: 0xFF }, + Colour { r: 0x33, g: 0x66, b: 0x66, a: 0xFF }, + Colour { r: 0x33, g: 0x66, b: 0x99, a: 0xFF }, + Colour { r: 0x33, g: 0x66, b: 0xCC, a: 0xFF }, + Colour { r: 0x33, g: 0x66, b: 0xFF, a: 0xFF }, + Colour { r: 0x33, g: 0x99, b: 0x00, a: 0xFF }, + Colour { r: 0x33, g: 0x99, b: 0x33, a: 0xFF }, + Colour { r: 0x33, g: 0x99, b: 0x66, a: 0xFF }, + Colour { r: 0x33, g: 0x99, b: 0x99, a: 0xFF }, + Colour { r: 0x33, g: 0x99, b: 0xCC, a: 0xFF }, + Colour { r: 0x33, g: 0x99, b: 0xFF, a: 0xFF }, + Colour { r: 0x33, g: 0xCC, b: 0x00, a: 0xFF }, + Colour { r: 0x33, g: 0xCC, b: 0x33, a: 0xFF }, + Colour { r: 0x33, g: 0xCC, b: 0x66, a: 0xFF }, + Colour { r: 0x33, g: 0xCC, b: 0x99, a: 0xFF }, + Colour { r: 0x33, g: 0xCC, b: 0xCC, a: 0xFF }, + Colour { r: 0x33, g: 0xCC, b: 0xFF, a: 0xFF }, + Colour { r: 0x33, g: 0xFF, b: 0x00, a: 0xFF }, + Colour { r: 0x33, g: 0xFF, b: 0x33, a: 0xFF }, + Colour { r: 0x33, g: 0xFF, b: 0x66, a: 0xFF }, + Colour { r: 0x33, g: 0xFF, b: 0x99, a: 0xFF }, + Colour { r: 0x33, g: 0xFF, b: 0xCC, a: 0xFF }, + Colour { r: 0x33, g: 0xFF, b: 0xFF, a: 0xFF }, + Colour { r: 0x66, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x66, g: 0x00, b: 0x33, a: 0xFF }, + Colour { r: 0x66, g: 0x00, b: 0x66, a: 0xFF }, + Colour { r: 0x66, g: 0x00, b: 0x99, a: 0xFF }, + Colour { r: 0x66, g: 0x00, b: 0xCC, a: 0xFF }, + Colour { r: 0x66, g: 0x00, b: 0xFF, a: 0xFF }, + Colour { r: 0x66, g: 0x33, b: 0x00, a: 0xFF }, + Colour { r: 0x66, g: 0x33, b: 0x33, a: 0xFF }, + Colour { r: 0x66, g: 0x33, b: 0x66, a: 0xFF }, + Colour { r: 0x66, g: 0x33, b: 0x99, a: 0xFF }, + Colour { r: 0x66, g: 0x33, b: 0xCC, a: 0xFF }, + Colour { r: 0x66, g: 0x33, b: 0xFF, a: 0xFF }, + Colour { r: 0x66, g: 0x66, b: 0x00, a: 0xFF }, + Colour { r: 0x66, g: 0x66, b: 0x33, a: 0xFF }, + Colour { r: 0x66, g: 0x66, b: 0x66, a: 0xFF }, + Colour { r: 0x66, g: 0x66, b: 0x99, a: 0xFF }, + Colour { r: 0x66, g: 0x66, b: 0xCC, a: 0xFF }, + Colour { r: 0x66, g: 0x66, b: 0xFF, a: 0xFF }, + Colour { r: 0x66, g: 0x99, b: 0x00, a: 0xFF }, + Colour { r: 0x66, g: 0x99, b: 0x33, a: 0xFF }, + Colour { r: 0x66, g: 0x99, b: 0x66, a: 0xFF }, + Colour { r: 0x66, g: 0x99, b: 0x99, a: 0xFF }, + Colour { r: 0x66, g: 0x99, b: 0xCC, a: 0xFF }, + Colour { r: 0x66, g: 0x99, b: 0xFF, a: 0xFF }, + Colour { r: 0x66, g: 0xCC, b: 0x00, a: 0xFF }, + Colour { r: 0x66, g: 0xCC, b: 0x33, a: 0xFF }, + Colour { r: 0x66, g: 0xCC, b: 0x66, a: 0xFF }, + Colour { r: 0x66, g: 0xCC, b: 0x99, a: 0xFF }, + Colour { r: 0x66, g: 0xCC, b: 0xCC, a: 0xFF }, + Colour { r: 0x66, g: 0xCC, b: 0xFF, a: 0xFF }, + Colour { r: 0x66, g: 0xFF, b: 0x00, a: 0xFF }, + Colour { r: 0x66, g: 0xFF, b: 0x33, a: 0xFF }, + Colour { r: 0x66, g: 0xFF, b: 0x66, a: 0xFF }, + Colour { r: 0x66, g: 0xFF, b: 0x99, a: 0xFF }, + Colour { r: 0x66, g: 0xFF, b: 0xCC, a: 0xFF }, + Colour { r: 0x66, g: 0xFF, b: 0xFF, a: 0xFF }, + Colour { r: 0x99, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x99, g: 0x00, b: 0x33, a: 0xFF }, + Colour { r: 0x99, g: 0x00, b: 0x66, a: 0xFF }, + Colour { r: 0x99, g: 0x00, b: 0x99, a: 0xFF }, + Colour { r: 0x99, g: 0x00, b: 0xCC, a: 0xFF }, + Colour { r: 0x99, g: 0x00, b: 0xFF, a: 0xFF }, + Colour { r: 0x99, g: 0x33, b: 0x00, a: 0xFF }, + Colour { r: 0x99, g: 0x33, b: 0x33, a: 0xFF }, + Colour { r: 0x99, g: 0x33, b: 0x66, a: 0xFF }, + Colour { r: 0x99, g: 0x33, b: 0x99, a: 0xFF }, + Colour { r: 0x99, g: 0x33, b: 0xCC, a: 0xFF }, + Colour { r: 0x99, g: 0x33, b: 0xFF, a: 0xFF }, + Colour { r: 0x99, g: 0x66, b: 0x00, a: 0xFF }, + Colour { r: 0x99, g: 0x66, b: 0x33, a: 0xFF }, + Colour { r: 0x99, g: 0x66, b: 0x66, a: 0xFF }, + Colour { r: 0x99, g: 0x66, b: 0x99, a: 0xFF }, + Colour { r: 0x99, g: 0x66, b: 0xCC, a: 0xFF }, + Colour { r: 0x99, g: 0x66, b: 0xFF, a: 0xFF }, + Colour { r: 0x99, g: 0x99, b: 0x00, a: 0xFF }, + Colour { r: 0x99, g: 0x99, b: 0x33, a: 0xFF }, + Colour { r: 0x99, g: 0x99, b: 0x66, a: 0xFF }, + Colour { r: 0x99, g: 0x99, b: 0x99, a: 0xFF }, + Colour { r: 0x99, g: 0x99, b: 0xCC, a: 0xFF }, + Colour { r: 0x99, g: 0x99, b: 0xFF, a: 0xFF }, + Colour { r: 0x99, g: 0xCC, b: 0x00, a: 0xFF }, + Colour { r: 0x99, g: 0xCC, b: 0x33, a: 0xFF }, + Colour { r: 0x99, g: 0xCC, b: 0x66, a: 0xFF }, + Colour { r: 0x99, g: 0xCC, b: 0x99, a: 0xFF }, + Colour { r: 0x99, g: 0xCC, b: 0xCC, a: 0xFF }, + Colour { r: 0x99, g: 0xCC, b: 0xFF, a: 0xFF }, + Colour { r: 0x99, g: 0xFF, b: 0x00, a: 0xFF }, + Colour { r: 0x99, g: 0xFF, b: 0x33, a: 0xFF }, + Colour { r: 0x99, g: 0xFF, b: 0x66, a: 0xFF }, + Colour { r: 0x99, g: 0xFF, b: 0x99, a: 0xFF }, + Colour { r: 0x99, g: 0xFF, b: 0xCC, a: 0xFF }, + Colour { r: 0x99, g: 0xFF, b: 0xFF, a: 0xFF }, + Colour { r: 0xCC, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0xCC, g: 0x00, b: 0x33, a: 0xFF }, + Colour { r: 0xCC, g: 0x00, b: 0x66, a: 0xFF }, + Colour { r: 0xCC, g: 0x00, b: 0x99, a: 0xFF }, + Colour { r: 0xCC, g: 0x00, b: 0xCC, a: 0xFF }, + Colour { r: 0xCC, g: 0x00, b: 0xFF, a: 0xFF }, + Colour { r: 0xCC, g: 0x33, b: 0x00, a: 0xFF }, + Colour { r: 0xCC, g: 0x33, b: 0x33, a: 0xFF }, + Colour { r: 0xCC, g: 0x33, b: 0x66, a: 0xFF }, + Colour { r: 0xCC, g: 0x33, b: 0x99, a: 0xFF }, + Colour { r: 0xCC, g: 0x33, b: 0xCC, a: 0xFF }, + Colour { r: 0xCC, g: 0x33, b: 0xFF, a: 0xFF }, + Colour { r: 0xCC, g: 0x66, b: 0x00, a: 0xFF }, + Colour { r: 0xCC, g: 0x66, b: 0x33, a: 0xFF }, + Colour { r: 0xCC, g: 0x66, b: 0x66, a: 0xFF }, + Colour { r: 0xCC, g: 0x66, b: 0x99, a: 0xFF }, + Colour { r: 0xCC, g: 0x66, b: 0xCC, a: 0xFF }, + Colour { r: 0xCC, g: 0x66, b: 0xFF, a: 0xFF }, + Colour { r: 0xCC, g: 0x99, b: 0x00, a: 0xFF }, + Colour { r: 0xCC, g: 0x99, b: 0x33, a: 0xFF }, + Colour { r: 0xCC, g: 0x99, b: 0x66, a: 0xFF }, + Colour { r: 0xCC, g: 0x99, b: 0x99, a: 0xFF }, + Colour { r: 0xCC, g: 0x99, b: 0xCC, a: 0xFF }, + Colour { r: 0xCC, g: 0x99, b: 0xFF, a: 0xFF }, + Colour { r: 0xCC, g: 0xCC, b: 0x00, a: 0xFF }, + Colour { r: 0xCC, g: 0xCC, b: 0x33, a: 0xFF }, + Colour { r: 0xCC, g: 0xCC, b: 0x66, a: 0xFF }, + Colour { r: 0xCC, g: 0xCC, b: 0x99, a: 0xFF }, + Colour { r: 0xCC, g: 0xCC, b: 0xCC, a: 0xFF }, + Colour { r: 0xCC, g: 0xCC, b: 0xFF, a: 0xFF }, + Colour { r: 0xCC, g: 0xFF, b: 0x00, a: 0xFF }, + Colour { r: 0xCC, g: 0xFF, b: 0x33, a: 0xFF }, + Colour { r: 0xCC, g: 0xFF, b: 0x66, a: 0xFF }, + Colour { r: 0xCC, g: 0xFF, b: 0x99, a: 0xFF }, + Colour { r: 0xCC, g: 0xFF, b: 0xCC, a: 0xFF }, + Colour { r: 0xCC, g: 0xFF, b: 0xFF, a: 0xFF }, + Colour { r: 0xFF, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0xFF, g: 0x00, b: 0x33, a: 0xFF }, + Colour { r: 0xFF, g: 0x00, b: 0x66, a: 0xFF }, + Colour { r: 0xFF, g: 0x00, b: 0x99, a: 0xFF }, + Colour { r: 0xFF, g: 0x00, b: 0xCC, a: 0xFF }, + Colour { r: 0xFF, g: 0x00, b: 0xFF, a: 0xFF }, + Colour { r: 0xFF, g: 0x33, b: 0x00, a: 0xFF }, + Colour { r: 0xFF, g: 0x33, b: 0x33, a: 0xFF }, + Colour { r: 0xFF, g: 0x33, b: 0x66, a: 0xFF }, + Colour { r: 0xFF, g: 0x33, b: 0x99, a: 0xFF }, + Colour { r: 0xFF, g: 0x33, b: 0xCC, a: 0xFF }, + Colour { r: 0xFF, g: 0x33, b: 0xFF, a: 0xFF }, + Colour { r: 0xFF, g: 0x66, b: 0x00, a: 0xFF }, + Colour { r: 0xFF, g: 0x66, b: 0x33, a: 0xFF }, + Colour { r: 0xFF, g: 0x66, b: 0x66, a: 0xFF }, + Colour { r: 0xFF, g: 0x66, b: 0x99, a: 0xFF }, + Colour { r: 0xFF, g: 0x66, b: 0xCC, a: 0xFF }, + Colour { r: 0xFF, g: 0x66, b: 0xFF, a: 0xFF }, + Colour { r: 0xFF, g: 0x99, b: 0x00, a: 0xFF }, + Colour { r: 0xFF, g: 0x99, b: 0x33, a: 0xFF }, + Colour { r: 0xFF, g: 0x99, b: 0x66, a: 0xFF }, + Colour { r: 0xFF, g: 0x99, b: 0x99, a: 0xFF }, + Colour { r: 0xFF, g: 0x99, b: 0xCC, a: 0xFF }, + Colour { r: 0xFF, g: 0x99, b: 0xFF, a: 0xFF }, + Colour { r: 0xFF, g: 0xCC, b: 0x00, a: 0xFF }, + Colour { r: 0xFF, g: 0xCC, b: 0x33, a: 0xFF }, + Colour { r: 0xFF, g: 0xCC, b: 0x66, a: 0xFF }, + Colour { r: 0xFF, g: 0xCC, b: 0x99, a: 0xFF }, + Colour { r: 0xFF, g: 0xCC, b: 0xCC, a: 0xFF }, + Colour { r: 0xFF, g: 0xCC, b: 0xFF, a: 0xFF }, + Colour { r: 0xFF, g: 0xFF, b: 0x00, a: 0xFF }, + Colour { r: 0xFF, g: 0xFF, b: 0x33, a: 0xFF }, + Colour { r: 0xFF, g: 0xFF, b: 0x66, a: 0xFF }, + Colour { r: 0xFF, g: 0xFF, b: 0x99, a: 0xFF }, + Colour { r: 0xFF, g: 0xFF, b: 0xCC, a: 0xFF }, + Colour { r: 0xFF, g: 0xFF, b: 0xFF, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF }, + ]; +} + +impl Default for Colour { + fn default() -> Self { + Colour::GREY + } +} + +impl From for Colour { + fn from(val: u32) -> Self { + let b = val.to_le_bytes(); + Colour { + r: b[0], + g: b[1], + b: b[2], + a: b[3], + } + } +} + +#[derive(Debug, Default, Clone, Copy)] +pub struct Point { + pub x: T, + pub y: T, +} + +impl core::ops::Add> for Point { + type Output = Point; + + fn add(self, rhs: Point) -> Self::Output { + Point { + x: (self.x as i16 + rhs.x) as u16, + y: (self.y as i16 + rhs.y) as u16, + } + } +} + +#[derive(Debug)] +pub struct ObjectLabel { + pub id: ObjectId, + pub string_variable_reference: ObjectId, + pub font_type: u8, + pub graphic_representation: ObjectId, +} + +#[derive(Debug)] +pub struct WorkingSet { + pub id: ObjectId, + pub background_colour: u8, + pub selectable: bool, + pub active_mask: ObjectId, + pub object_refs: Vec, + pub macro_refs: Vec, + pub language_codes: Vec, +} + +#[derive(Debug)] +pub struct DataMask { + pub id: ObjectId, + pub background_colour: u8, + pub soft_key_mask: ObjectId, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct AlarmMask { + pub id: ObjectId, + pub background_colour: u8, + pub soft_key_mask: ObjectId, + pub priority: u8, + pub acoustic_signal: u8, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct Container { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub hidden: bool, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct SoftKeyMask { + pub id: ObjectId, + pub background_colour: u8, + pub objects: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct Key { + pub id: ObjectId, + pub background_colour: u8, + pub key_code: u8, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct Button { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub border_colour: u8, + pub key_code: u8, + pub options: u8, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct InputBoolean { + pub id: ObjectId, + pub background_colour: u8, + pub width: u16, + pub foreground_colour: ObjectId, + pub variable_reference: ObjectId, + pub value: bool, + pub enabled: bool, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct InputString { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub font_attributes: ObjectId, + pub input_attributes: ObjectId, + pub options: u8, + pub variable_reference: ObjectId, + pub justification: u8, + pub value: String, + pub enabled: bool, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct InputNumber { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub font_attributes: ObjectId, + pub options: u8, + pub variable_reference: ObjectId, + pub value: u32, + pub min_value: u32, + pub max_value: u32, + pub offset: i32, + pub scale: f32, + pub nr_of_decimals: u8, + pub format: bool, + pub justification: u8, + pub options2: u8, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct InputList { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub variable_reference: ObjectId, + pub value: u8, + pub options: u8, + pub list_items: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputString { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub font_attributes: ObjectId, + pub options: u8, + pub variable_reference: ObjectId, + pub justification: u8, + pub value: String, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputNumber { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub font_attributes: ObjectId, + pub options: u8, + pub variable_reference: ObjectId, + pub value: u32, + pub offset: i32, + pub scale: f32, + pub nr_of_decimals: u8, + pub format: bool, + pub justification: u8, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputList { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub variable_reference: ObjectId, + pub value: u8, + pub list_items: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputLine { + pub id: ObjectId, + pub line_attributes: ObjectId, + pub width: u16, + pub height: u16, + pub line_direction: u8, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputRectangle { + pub id: ObjectId, + pub line_attributes: ObjectId, + pub width: u16, + pub height: u16, + pub line_suppression: u8, + pub fill_attributes: ObjectId, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputEllipse { + pub id: ObjectId, + pub line_attributes: ObjectId, + pub width: u16, + pub height: u16, + pub ellipse_type: u8, + pub start_angle: u8, + pub end_angle: u8, + pub fill_attributes: ObjectId, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputPolygon { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub line_attributes: ObjectId, + pub fill_attributes: ObjectId, + pub polygon_type: u8, + pub points: Vec>, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputMeter { + pub id: ObjectId, + pub width: u16, + pub needle_colour: u8, + pub border_colour: u8, + pub arc_and_tick_colour: u8, + pub options: u8, + pub nr_of_ticks: u8, + pub start_angle: u8, + pub end_angle: u8, + pub min_value: u16, + pub max_value: u16, + pub variable_reference: ObjectId, + pub value: u16, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputLinearBarGraph { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub colour: u8, + pub target_line_colour: u8, + pub options: u8, + pub nr_of_ticks: u8, + pub min_value: u16, + pub max_value: u16, + pub variable_reference: ObjectId, + pub value: u16, + pub target_value_variable_reference: ObjectId, + pub target_value: u16, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputArchedBarGraph { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub colour: u8, + pub target_line_colour: u8, + pub options: u8, + pub start_angle: u8, + pub end_angle: u8, + pub bar_graph_width: u16, + pub min_value: u16, + pub max_value: u16, + pub variable_reference: ObjectId, + pub value: u16, + pub target_value_variable_reference: ObjectId, + pub target_value: u16, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct PictureGraphic { + pub id: ObjectId, + pub width: u16, + pub actual_width: u16, + pub actual_height: u16, + pub format: u8, + pub options: u8, + pub transparency_colour: u8, + pub data: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct NumberVariable { + pub id: ObjectId, + pub value: u32, +} + +#[derive(Debug)] +pub struct StringVariable { + pub id: ObjectId, + pub value: String, +} + +#[derive(Debug)] +pub struct FontAttributes { + pub id: ObjectId, + pub font_colour: u8, + pub font_size: u8, + pub font_type: u8, + pub font_style: u8, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct LineAttributes { + pub id: ObjectId, + pub line_colour: u8, + pub line_width: u8, + pub line_art: u16, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct FillAttributes { + pub id: ObjectId, + pub fill_type: u8, + pub fill_colour: u8, + pub fill_pattern: ObjectId, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct InputAttributes { + pub id: ObjectId, + pub validation_type: u8, + pub validation_string: String, + pub macro_refs: Vec, +} + +// TODO; Implement code planes +#[derive(Debug)] +pub struct ExtendedInputAttributes { + pub id: ObjectId, + pub validation_type: u8, + pub nr_of_code_planes: u8, +} + +#[derive(Debug)] +pub struct ObjectPointer { + pub id: ObjectId, + pub value: ObjectId, +} + +#[derive(Debug)] +pub struct Macro { + pub id: ObjectId, + pub commands: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryFunctionType1 { + pub id: ObjectId, + pub background_colour: u8, + pub function_type: u8, + pub object_refs: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryInputType1 { + pub id: ObjectId, + pub background_colour: u8, + pub function_type: u8, + pub input_id: u8, + pub object_refs: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryFunctionType2 { + pub id: ObjectId, + pub background_colour: u8, + pub function_attributes: u8, + pub object_refs: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryInputType2 { + pub id: ObjectId, + pub background_colour: u8, + pub function_attributes: u8, + pub object_refs: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryControlDesignatorType2 { + pub id: ObjectId, + pub pointer_type: u8, + pub auxiliary_object_id: ObjectId, +} + +#[derive(Debug)] +pub struct ColourMap { + pub id: ObjectId, + pub colour_map: Vec, +} + +#[derive(Debug)] +pub struct GraphicsContext { + pub id: ObjectId, + pub viewport_width: u16, + pub viewport_height: u16, + pub viewport_x: i16, + pub viewport_y: i16, + pub canvas_width: u16, + pub canvas_height: u16, + pub viewport_zoom: f32, + pub graphics_cursor_x: i16, + pub graphics_cursor_y: i16, + pub foreground_colour: u8, + pub background_colour: u8, + pub font_attributes_object: ObjectId, + pub line_attributes_object: ObjectId, + pub fill_attributes_object: ObjectId, + pub format: u8, + pub options: u8, + pub transparency_colour: u8, +} + +#[derive(Debug)] +pub struct WindowMask { + pub id: ObjectId, + pub width: u8, + pub height: u8, + pub window_type: u8, + pub background_colour: u8, + pub options: u8, + pub name: ObjectId, + pub window_title: ObjectId, + pub window_icon: ObjectId, + pub objects: Vec, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct KeyGroup { + pub id: ObjectId, + pub options: u8, + pub name: ObjectId, + pub key_group_icon: ObjectId, + pub objects: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct ObjectLabelReferenceList { + pub id: ObjectId, + pub object_labels: Vec, +} + +#[derive(Debug)] +pub struct ExternalObjectDefinition { + pub id: ObjectId, + pub options: u8, + pub name: Name, + pub objects: Vec, +} + +#[derive(Debug)] +pub struct ExternalReferenceName { + pub id: ObjectId, + pub options: u8, + pub name: Name, +} + +#[derive(Debug)] +pub struct ExternalObjectPointer { + pub id: ObjectId, + pub default_object_id: ObjectId, + pub external_reference_name_id: ObjectId, + pub external_object_id: ObjectId, +} + +#[derive(Debug)] +pub struct Animation { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub refresh_interval: u16, + pub value: u8, + pub enabled: bool, + pub first_child_index: u8, + pub last_child_index: u8, + pub default_child_index: u8, + pub options: u8, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct ColourPalette { + pub id: ObjectId, + pub options: u16, + pub colours: Vec, +} + +#[derive(Debug)] +pub struct GraphicData { + pub id: ObjectId, + pub format: u8, + pub data: Vec, +} + +#[derive(Debug)] +pub struct ScalesGraphic { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub scale_type: u8, + pub options: u8, + pub value: u16, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct WorkingSetSpecialControls { + pub id: ObjectId, + pub id_of_colour_map: ObjectId, + pub id_of_colour_palette: ObjectId, + pub language_pairs: Vec<(String, String)>, +} diff --git a/src/object_pool/object_pool.rs b/src/object_pool/object_pool.rs new file mode 100644 index 0000000..f2f274f --- /dev/null +++ b/src/object_pool/object_pool.rs @@ -0,0 +1,142 @@ +use core::cell::Cell; + +use alloc::vec::Vec; + +use crate::virtual_terminal_client::VTVersion; + +use super::*; + +#[derive(Debug)] +pub struct ObjectPool { + objects: Vec, + colour_map: [u8; 256], + colour_palette: [Colour; 256], + supported_vt_version: VTVersion, + + size_cache: Cell>, +} + +impl ObjectPool { + pub fn new() -> Self { + // Setup the default colour map + let mut colour_map = [0xFFu8; 256]; + for i in 0..(colour_map.len() as u8) { + colour_map[i as usize] = i; + } + + ObjectPool { + objects: Vec::new(), + colour_map, + colour_palette: Colour::COLOUR_PALETTE, + supported_vt_version: VTVersion::default(), + + size_cache: Cell::new(None), + } + } + + pub fn size(&self) -> usize { + if self.size_cache.get().is_none() { + self.size_cache.set(Some(self.as_iop().len())); + } + self.size_cache.get().unwrap_or_default() + } + + pub fn from_iop(data: I) -> Self + where + I: IntoIterator, + { + let mut data = data.into_iter(); + + let mut op = Self::new(); + + while let Ok(o) = Object::read(&mut data) { + op.objects.push(o); + } + + op + } + + pub fn as_iop(&self) -> Vec { + let mut data = Vec::new(); + + for obj in &self.objects { + data.extend(obj.write()); + } + + data + } + + pub fn add(&mut self, obj: Object) { + self.objects.push(obj); + } + + pub fn object_by_id(&self, id: ObjectId) -> Option<&Object> { + self.objects.iter().find(|&o| o.id() == id) + } + + pub fn objects_by_type(&self, object_type: ObjectType) -> Vec<&Object> { + self.objects + .iter() + .filter(|&o| o.object_type() == object_type) + .collect() + } + + // Get objects by type + + pub fn working_set_object(&self) -> Option<&WorkingSet> { + match &self.objects_by_type(ObjectType::WorkingSet).first() { + Some(Object::WorkingSet(o)) => Some(o), + _ => None, + } + } + + pub fn data_mask_objects(&self) -> Vec<&DataMask> { + let r: Vec<&DataMask> = self + .objects_by_type(ObjectType::DataMask) + .iter() + .filter_map(|&o| match o { + Object::DataMask(o) => Some(o), + _ => None, + }) + .collect(); + r + } + + pub fn picture_graphic_objects(&self) -> Vec<&PictureGraphic> { + let r: Vec<&PictureGraphic> = self + .objects_by_type(ObjectType::PictureGraphic) + .iter() + .filter_map(|&o| match o { + Object::PictureGraphic(o) => Some(o), + _ => None, + }) + .collect(); + r + } + + // Get typed objects by id + + pub fn data_mask_object_by_id(&self, id: ObjectId) -> Option<&DataMask> { + match &self.object_by_id(id) { + Some(Object::DataMask(o)) => Some(o), + _ => None, + } + } + + pub fn line_attributes_object_by_id(&self, id: ObjectId) -> Option<&LineAttributes> { + match &self.object_by_id(id) { + Some(Object::LineAttributes(o)) => Some(o), + _ => None, + } + } + + pub fn color_by_index(&self, index: u8) -> Colour { + self.colour_palette[self.colour_map[index as usize] as usize] + } +} + +impl Default for ObjectPool { + fn default() -> Self { + Self::new() + } +} diff --git a/src/object_pool/reader.rs b/src/object_pool/reader.rs new file mode 100644 index 0000000..59349ff --- /dev/null +++ b/src/object_pool/reader.rs @@ -0,0 +1,1011 @@ +use super::*; + +impl Object { + pub fn read(data: &mut dyn Iterator) -> Result { + let id = Self::read_u16(data)?.into(); + let object_type = Self::read_u8(data)?.try_into()?; + + match object_type { + ObjectType::WorkingSet => { + let mut o = WorkingSet { + id, + background_colour: Self::read_u8(data)?, + selectable: Self::read_bool(data)?, + active_mask: Self::read_u16(data)?.into(), + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + language_codes: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + for _ in 0..o.language_codes.capacity() { + o.language_codes.push(Self::read_string(2, data)?) + } + + Ok(Object::WorkingSet(o)) + } + ObjectType::DataMask => { + let mut o = DataMask { + id, + background_colour: Self::read_u8(data)?, + soft_key_mask: Self::read_u16(data)?.into(), + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::DataMask(o)) + } + ObjectType::AlarmMask => { + let mut o = AlarmMask { + id, + background_colour: Self::read_u8(data)?, + soft_key_mask: Self::read_u16(data)?.into(), + priority: Self::read_u8(data)?, + acoustic_signal: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::AlarmMask(o)) + } + ObjectType::Container => { + let mut o = Container { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + hidden: Self::read_bool(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::Container(o)) + } + ObjectType::SoftKeyMask => { + let mut o = SoftKeyMask { + id, + background_colour: Self::read_u8(data)?, + objects: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.objects + .extend(Self::read_objects(data, o.objects.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::SoftKeyMask(o)) + } + ObjectType::Key => { + let mut o = Key { + id, + background_colour: Self::read_u8(data)?, + key_code: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::Key(o)) + } + ObjectType::Button => { + let mut o = Button { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + border_colour: Self::read_u8(data)?, + key_code: Self::read_u8(data)?, + options: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::Button(o)) + } + ObjectType::InputBoolean => { + let mut o = InputBoolean { + id, + background_colour: Self::read_u8(data)?, + width: Self::read_u16(data)?, + foreground_colour: Self::read_u16(data)?.into(), + variable_reference: Self::read_u16(data)?.into(), + value: Self::read_bool(data)?, + enabled: Self::read_bool(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputBoolean(o)) + } + ObjectType::InputString => { + let mut o = InputString { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + font_attributes: Self::read_u16(data)?.into(), + input_attributes: Self::read_u16(data)?.into(), + options: Self::read_u8(data)?, + variable_reference: Self::read_u16(data)?.into(), + justification: Self::read_u8(data)?, + value: Self::read_string(Self::read_u8(data)?.into(), data)?, + enabled: Self::read_bool(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputString(o)) + } + ObjectType::InputNumber => { + let mut o = InputNumber { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + font_attributes: Self::read_u16(data)?.into(), + options: Self::read_u8(data)?, + variable_reference: Self::read_u16(data)?.into(), + value: Self::read_u32(data)?, + min_value: Self::read_u32(data)?, + max_value: Self::read_u32(data)?, + offset: Self::read_i32(data)?, + scale: Self::read_f32(data)?, + nr_of_decimals: Self::read_u8(data)?, + format: Self::read_bool(data)?, + justification: Self::read_u8(data)?, + options2: Self::read_u8(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputNumber(o)) + } + ObjectType::InputList => { + let mut o = InputList { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.into(), + value: Self::read_u8(data)?, + list_items: Vec::with_capacity(Self::read_u8(data)?.into()), + options: Self::read_u8(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.list_items + .extend(Self::read_objects(data, o.list_items.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputList(o)) + } + ObjectType::OutputString => { + let mut o = OutputString { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + font_attributes: Self::read_u16(data)?.into(), + options: Self::read_u8(data)?, + variable_reference: Self::read_u16(data)?.into(), + justification: Self::read_u8(data)?, + value: Self::read_string(Self::read_u16(data)?.into(), data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputString(o)) + } + ObjectType::OutputNumber => { + let mut o = OutputNumber { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + font_attributes: Self::read_u16(data)?.into(), + options: Self::read_u8(data)?, + variable_reference: Self::read_u16(data)?.into(), + value: Self::read_u32(data)?, + offset: Self::read_i32(data)?, + scale: Self::read_f32(data)?, + nr_of_decimals: Self::read_u8(data)?, + format: Self::read_bool(data)?, + justification: Self::read_u8(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputNumber(o)) + } + ObjectType::OutputLine => { + let mut o = OutputLine { + id, + line_attributes: Self::read_u16(data)?.into(), + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + line_direction: Self::read_u8(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputLine(o)) + } + ObjectType::OutputRectangle => { + let mut o = OutputRectangle { + id, + line_attributes: Self::read_u16(data)?.into(), + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + line_suppression: Self::read_u8(data)?, + fill_attributes: Self::read_u16(data)?.into(), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputRectangle(o)) + } + ObjectType::OutputEllipse => { + let mut o = OutputEllipse { + id, + line_attributes: Self::read_u16(data)?.into(), + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + ellipse_type: Self::read_u8(data)?, + start_angle: Self::read_u8(data)?, + end_angle: Self::read_u8(data)?, + fill_attributes: Self::read_u16(data)?.into(), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputEllipse(o)) + } + ObjectType::OutputPolygon => { + let mut o = OutputPolygon { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + line_attributes: Self::read_u16(data)?.into(), + fill_attributes: Self::read_u16(data)?.into(), + polygon_type: Self::read_u8(data)?, + points: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.points + .extend(Self::read_points(data, o.points.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputPolygon(o)) + } + ObjectType::OutputMeter => { + let mut o = OutputMeter { + id, + width: Self::read_u16(data)?, + needle_colour: Self::read_u8(data)?, + border_colour: Self::read_u8(data)?, + arc_and_tick_colour: Self::read_u8(data)?, + options: Self::read_u8(data)?, + nr_of_ticks: Self::read_u8(data)?, + start_angle: Self::read_u8(data)?, + end_angle: Self::read_u8(data)?, + min_value: Self::read_u16(data)?, + max_value: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.into(), + value: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputMeter(o)) + } + ObjectType::OutputLinearBarGraph => { + let mut o = OutputLinearBarGraph { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + colour: Self::read_u8(data)?, + target_line_colour: Self::read_u8(data)?, + options: Self::read_u8(data)?, + nr_of_ticks: Self::read_u8(data)?, + min_value: Self::read_u16(data)?, + max_value: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.into(), + value: Self::read_u16(data)?, + target_value_variable_reference: Self::read_u16(data)?.into(), + target_value: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputLinearBarGraph(o)) + } + ObjectType::OutputArchedBarGraph => { + let mut o = OutputArchedBarGraph { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + colour: Self::read_u8(data)?, + target_line_colour: Self::read_u8(data)?, + options: Self::read_u8(data)?, + start_angle: Self::read_u8(data)?, + end_angle: Self::read_u8(data)?, + bar_graph_width: Self::read_u16(data)?, + min_value: Self::read_u16(data)?, + max_value: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.into(), + value: Self::read_u16(data)?, + target_value_variable_reference: Self::read_u16(data)?.into(), + target_value: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputArchedBarGraph(o)) + } + ObjectType::PictureGraphic => { + let mut o = PictureGraphic { + id, + width: Self::read_u16(data)?, + actual_width: Self::read_u16(data)?, + actual_height: Self::read_u16(data)?, + format: Self::read_u8(data)?, + options: Self::read_u8(data)?, + transparency_colour: Self::read_u8(data)?, + data: Vec::with_capacity(Self::read_u32(data)? as usize), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.data.extend(Self::read_bytes(data, o.data.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::PictureGraphic(o)) + } + ObjectType::NumberVariable => { + let o = NumberVariable { + id, + value: Self::read_u32(data)?, + }; + + Ok(Object::NumberVariable(o)) + } + ObjectType::StringVariable => { + let o = StringVariable { + id, + value: Self::read_string(Self::read_u16(data)?.into(), data)?, + }; + + Ok(Object::StringVariable(o)) + } + ObjectType::FontAttributes => { + let mut o = FontAttributes { + id, + font_colour: Self::read_u8(data)?, + font_size: Self::read_u8(data)?, + font_type: Self::read_u8(data)?, + font_style: Self::read_u8(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::FontAttributes(o)) + } + ObjectType::LineAttributes => { + let mut o = LineAttributes { + id, + line_colour: Self::read_u8(data)?, + line_width: Self::read_u8(data)?, + line_art: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::LineAttributes(o)) + } + ObjectType::FillAttributes => { + let mut o = FillAttributes { + id, + fill_type: Self::read_u8(data)?, + fill_colour: Self::read_u8(data)?, + fill_pattern: Self::read_u16(data)?.into(), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::FillAttributes(o)) + } + ObjectType::InputAttributes => { + let mut o = InputAttributes { + id, + validation_type: Self::read_u8(data)?, + validation_string: Self::read_string(Self::read_u8(data)?.into(), data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputAttributes(o)) + } + ObjectType::ObjectPointer => { + let o = ObjectPointer { + id, + value: Self::read_u16(data)?.into(), + }; + + Ok(Object::ObjectPointer(o)) + } + ObjectType::Macro => { + let mut o = Macro { + id, + commands: Vec::with_capacity(Self::read_u16(data)?.into()), + }; + + o.commands + .extend(Self::read_bytes(data, o.commands.capacity())?); + + Ok(Object::Macro(o)) + } + ObjectType::AuxiliaryFunctionType1 => { + let mut o = AuxiliaryFunctionType1 { + id, + background_colour: Self::read_u8(data)?, + function_type: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + + Ok(Object::AuxiliaryFunctionType1(o)) + } + ObjectType::AuxiliaryInputType1 => { + let mut o = AuxiliaryInputType1 { + id, + background_colour: Self::read_u8(data)?, + function_type: Self::read_u8(data)?, + input_id: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + + Ok(Object::AuxiliaryInputType1(o)) + } + ObjectType::AuxiliaryFunctionType2 => { + let mut o = AuxiliaryFunctionType2 { + id, + background_colour: Self::read_u8(data)?, + function_attributes: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + + Ok(Object::AuxiliaryFunctionType2(o)) + } + ObjectType::AuxiliaryInputType2 => { + let mut o = AuxiliaryInputType2 { + id, + background_colour: Self::read_u8(data)?, + function_attributes: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + + Ok(Object::AuxiliaryInputType2(o)) + } + ObjectType::AuxiliaryControlDesignatorType2 => { + let o = AuxiliaryControlDesignatorType2 { + id, + pointer_type: Self::read_u8(data)?, + auxiliary_object_id: Self::read_u16(data)?.into(), + }; + + Ok(Object::AuxiliaryControlDesignatorType2(o)) + } + ObjectType::WindowMask => { + let mut o = WindowMask { + id, + width: Self::read_u8(data)?, + height: Self::read_u8(data)?, + window_type: Self::read_u8(data)?, + background_colour: Self::read_u8(data)?, + options: Self::read_u8(data)?, + name: Self::read_u16(data)?.into(), + window_title: Self::read_u16(data)?.into(), + window_icon: Self::read_u16(data)?.into(), + objects: Vec::with_capacity(Self::read_u8(data)?.into()), + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.objects + .extend(Self::read_objects(data, o.objects.capacity())?); + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::WindowMask(o)) + } + ObjectType::KeyGroup => { + let mut o = KeyGroup { + id, + options: Self::read_u8(data)?, + name: Self::read_u16(data)?.into(), + key_group_icon: Self::read_u16(data)?.into(), + objects: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.objects + .extend(Self::read_objects(data, o.objects.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::KeyGroup(o)) + } + ObjectType::GraphicsContext => { + let o = GraphicsContext { + id, + viewport_width: Self::read_u16(data)?, + viewport_height: Self::read_u16(data)?, + viewport_x: Self::read_i16(data)?, + viewport_y: Self::read_i16(data)?, + canvas_width: Self::read_u16(data)?, + canvas_height: Self::read_u16(data)?, + viewport_zoom: Self::read_f32(data)?, + graphics_cursor_x: Self::read_i16(data)?, + graphics_cursor_y: Self::read_i16(data)?, + foreground_colour: Self::read_u8(data)?, + background_colour: Self::read_u8(data)?, + font_attributes_object: Self::read_u16(data)?.into(), + line_attributes_object: Self::read_u16(data)?.into(), + fill_attributes_object: Self::read_u16(data)?.into(), + format: Self::read_u8(data)?, + options: Self::read_u8(data)?, + transparency_colour: Self::read_u8(data)?, + }; + + Ok(Object::GraphicsContext(o)) + } + ObjectType::OutputList => { + let mut o = OutputList { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.into(), + value: Self::read_u8(data)?, + list_items: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.list_items + .extend(Self::read_objects(data, o.list_items.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputList(o)) + } + ObjectType::ExtendedInputAttributes => { + let o = ExtendedInputAttributes { + id, + validation_type: Self::read_u8(data)?, + nr_of_code_planes: Self::read_u8(data)?, + }; + + Ok(Object::ExtendedInputAttributes(o)) + } + ObjectType::ColourMap => { + let mut o = ColourMap { + id, + colour_map: Vec::with_capacity(Self::read_u16(data)?.into()), + }; + + o.colour_map + .extend(Self::read_bytes(data, o.colour_map.capacity())?); + + Ok(Object::ColourMap(o)) + } + ObjectType::ObjectLabelReferenceList => { + let mut o = ObjectLabelReferenceList { + id, + object_labels: Vec::with_capacity(Self::read_u16(data)?.into()), + }; + + o.object_labels + .extend(Self::read_object_labels(data, o.object_labels.capacity())?); + + Ok(Object::ObjectLabelReferenceList(o)) + } + ObjectType::ExternalObjectDefinition => { + let mut o = ExternalObjectDefinition { + id, + options: Self::read_u8(data)?, + name: Self::read_name(data)?, + objects: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.objects + .extend(Self::read_objects(data, o.objects.capacity())?); + + Ok(Object::ExternalObjectDefinition(o)) + } + ObjectType::ExternalReferenceName => { + let o = ExternalReferenceName { + id, + options: Self::read_u8(data)?, + name: Self::read_name(data)?, + }; + + Ok(Object::ExternalReferenceName(o)) + } + ObjectType::ExternalObjectPointer => { + let o = ExternalObjectPointer { + id, + default_object_id: Self::read_u16(data)?.into(), + external_reference_name_id: Self::read_u16(data)?.into(), + external_object_id: Self::read_u16(data)?.into(), + }; + + Ok(Object::ExternalObjectPointer(o)) + } + ObjectType::Animation => { + let mut o = Animation { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + refresh_interval: Self::read_u16(data)?, + value: Self::read_u8(data)?, + enabled: Self::read_bool(data)?, + first_child_index: Self::read_u8(data)?, + last_child_index: Self::read_u8(data)?, + default_child_index: Self::read_u8(data)?, + options: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::Animation(o)) + } + ObjectType::ColourPalette => { + let mut o = ColourPalette { + id, + options: Self::read_u16(data)?, + colours: Vec::with_capacity(Self::read_u16(data)?.into()), + }; + + o.colours + .extend(Self::read_colours(data, o.colours.capacity())?); + + Ok(Object::ColourPalette(o)) + } + ObjectType::GraphicData => { + let mut o = GraphicData { + id, + format: Self::read_u8(data)?, + data: Vec::with_capacity(Self::read_u32(data)?.try_into().unwrap()), + }; + + o.data.extend(Self::read_bytes(data, o.data.capacity())?); + + Ok(Object::GraphicData(o)) + } + ObjectType::WorkingSetSpecialControls => { + let mut o = WorkingSetSpecialControls { + id, + id_of_colour_map: Self::read_u16(data)?.into(), + id_of_colour_palette: Self::read_u16(data)?.into(), + language_pairs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.language_pairs.extend(Self::read_language_pairs( + data, + o.language_pairs.capacity(), + )?); + + Ok(Object::WorkingSetSpecialControls(o)) + } + ObjectType::ScalesGraphic => { + let mut o = ScalesGraphic { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + scale_type: Self::read_u8(data)?, + options: Self::read_u8(data)?, + value: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::ScalesGraphic(o)) + } + } + } + + fn read_objects( + data: &mut dyn Iterator, + nr_of_objects: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_objects { + objs.push(Self::read_u16(data)?.into()); + } + Ok(objs) + } + fn read_object_refs( + data: &mut dyn Iterator, + nr_of_objects: usize, + ) -> Result, ParseError> { + let mut refs = Vec::new(); + for _ in 0..nr_of_objects { + refs.push(ObjectRef { + id: Self::read_u16(data)?.into(), + offset: Point { + x: Self::read_i16(data)?, + y: Self::read_i16(data)?, + }, + }) + } + Ok(refs) + } + fn read_macro_refs( + data: &mut dyn Iterator, + nr_of_macros: usize, + ) -> Result, ParseError> { + let mut refs = Vec::new(); + for _ in 0..nr_of_macros { + refs.push(MacroRef { + event_id: Self::read_u8(data)?, + macro_id: Self::read_u8(data)?, + }) + } + Ok(refs) + } + fn read_bytes( + data: &mut dyn Iterator, + nr_of_bytes: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_bytes { + objs.push(Self::read_u8(data)?) + } + Ok(objs) + } + fn read_points( + data: &mut dyn Iterator, + nr_of_points: usize, + ) -> Result>, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_points { + objs.push(Point { + x: Self::read_u16(data)?, + y: Self::read_u16(data)?, + }) + } + Ok(objs) + } + fn read_colours( + data: &mut dyn Iterator, + nr_of_colours: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_colours { + objs.push(Colour { + b: Self::read_u8(data)?, + g: Self::read_u8(data)?, + r: Self::read_u8(data)?, + a: Self::read_u8(data)?, + }) + } + Ok(objs) + } + fn read_object_labels( + data: &mut dyn Iterator, + nr_of_objects: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_objects { + objs.push(ObjectLabel { + id: Self::read_u16(data)?.into(), + string_variable_reference: Self::read_u16(data)?.into(), + font_type: Self::read_u8(data)?, + graphic_representation: Self::read_u16(data)?.into(), + }) + } + Ok(objs) + } + fn read_language_pairs( + data: &mut dyn Iterator, + nr_of_objects: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_objects { + objs.push((Self::read_string(2, data)?, Self::read_string(2, data)?)) + } + Ok(objs) + } + + fn read_bool(data: &mut dyn Iterator) -> Result { + match data.next() { + Some(d) => Ok(d != 0), + None => Err(ParseError::DataEmpty), + } + } + fn read_u8(data: &mut dyn Iterator) -> Result { + match data.next() { + Some(d) => Ok(d), + None => Err(ParseError::DataEmpty), + } + } + fn read_u16(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + + if a.is_none() || b.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(u16::from_le_bytes([a.unwrap(), b.unwrap()])) + } + fn read_i16(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + + if a.is_none() || b.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(i16::from_le_bytes([a.unwrap(), b.unwrap()])) + } + fn read_u32(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + let c: Option = data.next(); + let d: Option = data.next(); + + if a.is_none() || b.is_none() || c.is_none() || d.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(u32::from_le_bytes([ + a.unwrap(), + b.unwrap(), + c.unwrap(), + d.unwrap(), + ])) + } + fn read_i32(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + let c: Option = data.next(); + let d: Option = data.next(); + + if a.is_none() || b.is_none() || c.is_none() || d.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(i32::from_le_bytes([ + a.unwrap(), + b.unwrap(), + c.unwrap(), + d.unwrap(), + ])) + } + fn read_f32(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + let c: Option = data.next(); + let d: Option = data.next(); + + if a.is_none() || b.is_none() || c.is_none() || d.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(f32::from_le_bytes([ + a.unwrap(), + b.unwrap(), + c.unwrap(), + d.unwrap(), + ])) + } + fn read_string(len: usize, data: &mut dyn Iterator) -> Result { + let mut s = String::new(); + for _ in 0..len { + if let Some(c) = data.next() { + s.push(c as char); + } else { + return Err(ParseError::DataEmpty); + }; + } + Ok(s) + } + fn read_name(data: &mut dyn Iterator) -> Result { + let name: [Option; 8] = [ + data.next(), + data.next(), + data.next(), + data.next(), + data.next(), + data.next(), + data.next(), + data.next(), + ]; + + if name.contains(&None) { + return Err(ParseError::DataEmpty); + } + + Ok(Name::from(u64::from_le_bytes(name.map(|v| v.unwrap())))) + } +} diff --git a/src/object_pool/writer.rs b/src/object_pool/writer.rs new file mode 100644 index 0000000..2b389d2 --- /dev/null +++ b/src/object_pool/writer.rs @@ -0,0 +1,681 @@ +use super::*; + +impl Object { + pub fn write(&self) -> Vec { + let mut data = Vec::new(); + + match self { + Object::WorkingSet(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::WorkingSet); + Self::write_u8(&mut data, o.background_colour); + Self::write_u8(&mut data, o.selectable); + Self::write_u16(&mut data, o.active_mask); + Self::write_u8(&mut data, o.object_refs.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + Self::write_u8(&mut data, o.language_codes.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + Self::write_macro_refs(&mut data, &o.macro_refs); + Self::write_language_codes(&mut data, &o.language_codes); + } + Object::DataMask(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::DataMask); + Self::write_u8(&mut data, o.background_colour); + Self::write_u16(&mut data, o.soft_key_mask); + Self::write_u8(&mut data, o.object_refs.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::AlarmMask(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::AlarmMask); + Self::write_u8(&mut data, o.background_colour); + Self::write_u16(&mut data, o.soft_key_mask); + Self::write_u8(&mut data, o.priority); + Self::write_u8(&mut data, o.acoustic_signal); + Self::write_u8(&mut data, o.object_refs.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::Container(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::Container); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.hidden); + Self::write_u8(&mut data, o.object_refs.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::SoftKeyMask(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::SoftKeyMask); + Self::write_u8(&mut data, o.background_colour); + Self::write_u8(&mut data, o.objects.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_objects(&mut data, &o.objects); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::Key(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::Key); + Self::write_u8(&mut data, o.background_colour); + Self::write_u8(&mut data, o.key_code); + Self::write_u8(&mut data, o.object_refs.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::Button(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::Button); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.background_colour); + Self::write_u8(&mut data, o.border_colour); + Self::write_u8(&mut data, o.key_code); + Self::write_u8(&mut data, o.options); + Self::write_u8(&mut data, o.object_refs.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::InputBoolean(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::InputBoolean); + Self::write_u8(&mut data, o.background_colour); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.foreground_colour); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u8(&mut data, o.value); + Self::write_u8(&mut data, o.enabled); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::InputString(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::InputString); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.background_colour); + Self::write_u16(&mut data, o.font_attributes); + Self::write_u16(&mut data, o.input_attributes); + Self::write_u8(&mut data, o.options); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u8(&mut data, o.justification); + Self::write_string(&mut data, &o.value); + Self::write_u8(&mut data, o.enabled); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::InputNumber(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::InputNumber); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.background_colour); + Self::write_u16(&mut data, o.font_attributes); + Self::write_u8(&mut data, o.options); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u32(&mut data, o.value); + Self::write_u32(&mut data, o.min_value); + Self::write_u32(&mut data, o.max_value); + Self::write_i32(&mut data, o.offset); + Self::write_f32(&mut data, o.scale); + Self::write_u8(&mut data, o.nr_of_decimals); + Self::write_u8(&mut data, o.format); + Self::write_u8(&mut data, o.justification); + Self::write_u8(&mut data, o.options2); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::InputList(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::InputList); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u8(&mut data, o.value); + Self::write_u8(&mut data, o.list_items.len() as u8); + Self::write_u8(&mut data, o.options); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_objects(&mut data, &o.list_items); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::OutputString(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputString); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.background_colour); + Self::write_u16(&mut data, o.font_attributes); + Self::write_u8(&mut data, o.options); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u8(&mut data, o.justification); + Self::write_u16(&mut data, o.value.len() as u16); + Self::write_string(&mut data, &o.value); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::OutputNumber(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputNumber); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.background_colour); + Self::write_u16(&mut data, o.font_attributes); + Self::write_u8(&mut data, o.options); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u32(&mut data, o.value); + Self::write_i32(&mut data, o.offset); + Self::write_f32(&mut data, o.scale); + Self::write_u8(&mut data, o.nr_of_decimals); + Self::write_u8(&mut data, o.format); + Self::write_u8(&mut data, o.justification); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::OutputLine(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputLine); + Self::write_u16(&mut data, o.line_attributes); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.line_direction); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::OutputRectangle(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputRectangle); + Self::write_u16(&mut data, o.line_attributes); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.line_suppression); + Self::write_u16(&mut data, o.fill_attributes); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::OutputEllipse(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputEllipse); + Self::write_u16(&mut data, o.line_attributes); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.ellipse_type); + Self::write_u8(&mut data, o.start_angle); + Self::write_u8(&mut data, o.end_angle); + Self::write_u16(&mut data, o.fill_attributes); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::OutputPolygon(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputPolygon); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u16(&mut data, o.line_attributes); + Self::write_u16(&mut data, o.fill_attributes); + Self::write_u8(&mut data, o.polygon_type); + Self::write_u8(&mut data, o.points.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_points(&mut data, &o.points); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::OutputMeter(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputMeter); + Self::write_u16(&mut data, o.width); + Self::write_u8(&mut data, o.needle_colour); + Self::write_u8(&mut data, o.border_colour); + Self::write_u8(&mut data, o.arc_and_tick_colour); + Self::write_u8(&mut data, o.options); + Self::write_u8(&mut data, o.nr_of_ticks); + Self::write_u8(&mut data, o.start_angle); + Self::write_u8(&mut data, o.end_angle); + Self::write_u16(&mut data, o.min_value); + Self::write_u16(&mut data, o.max_value); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u16(&mut data, o.value); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::OutputLinearBarGraph(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputLinearBarGraph); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.colour); + Self::write_u8(&mut data, o.target_line_colour); + Self::write_u8(&mut data, o.options); + Self::write_u8(&mut data, o.nr_of_ticks); + Self::write_u16(&mut data, o.min_value); + Self::write_u16(&mut data, o.max_value); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u16(&mut data, o.value); + Self::write_u16(&mut data, o.target_value_variable_reference); + Self::write_u16(&mut data, o.target_value); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::OutputArchedBarGraph(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputArchedBarGraph); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.colour); + Self::write_u8(&mut data, o.target_line_colour); + Self::write_u8(&mut data, o.options); + Self::write_u8(&mut data, o.start_angle); + Self::write_u8(&mut data, o.end_angle); + Self::write_u16(&mut data, o.bar_graph_width); + Self::write_u16(&mut data, o.min_value); + Self::write_u16(&mut data, o.max_value); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u16(&mut data, o.value); + Self::write_u16(&mut data, o.target_value_variable_reference); + Self::write_u16(&mut data, o.target_value); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::PictureGraphic(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::PictureGraphic); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.actual_width); + Self::write_u16(&mut data, o.actual_height); + Self::write_u8(&mut data, o.format); + Self::write_u8(&mut data, o.options); + Self::write_u8(&mut data, o.transparency_colour); + Self::write_u32(&mut data, o.data.len() as u32); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_bytes(&mut data, &o.data); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::NumberVariable(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::NumberVariable); + Self::write_u32(&mut data, o.value); + } + Object::StringVariable(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::StringVariable); + Self::write_string(&mut data, &o.value); + } + Object::FontAttributes(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::FontAttributes); + Self::write_u8(&mut data, o.font_colour); + Self::write_u8(&mut data, o.font_size); + Self::write_u8(&mut data, o.font_type); + Self::write_u8(&mut data, o.font_style); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::LineAttributes(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::LineAttributes); + Self::write_u8(&mut data, o.line_colour); + Self::write_u8(&mut data, o.line_width); + Self::write_u16(&mut data, o.line_art); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::FillAttributes(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::FillAttributes); + Self::write_u8(&mut data, o.fill_type); + Self::write_u8(&mut data, o.fill_colour); + Self::write_u16(&mut data, o.fill_pattern); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::InputAttributes(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::InputAttributes); + Self::write_u8(&mut data, o.validation_type); + Self::write_string(&mut data, &o.validation_string); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::ObjectPointer(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::ObjectPointer); + Self::write_u16(&mut data, o.value); + } + Object::Macro(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::Macro); + Self::write_u16(&mut data, o.commands.len() as u16); + + Self::write_bytes(&mut data, &o.commands); + } + Object::AuxiliaryFunctionType1(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::AuxiliaryFunctionType1); + Self::write_u8(&mut data, o.background_colour); + Self::write_u8(&mut data, o.function_type); + Self::write_u8(&mut data, o.object_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + } + Object::AuxiliaryInputType1(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::AuxiliaryInputType1); + Self::write_u8(&mut data, o.background_colour); + Self::write_u8(&mut data, o.function_type); + Self::write_u8(&mut data, o.input_id); + Self::write_u8(&mut data, o.object_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + } + Object::AuxiliaryFunctionType2(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::AuxiliaryFunctionType2); + Self::write_u8(&mut data, o.background_colour); + Self::write_u8(&mut data, o.function_attributes); + Self::write_u8(&mut data, o.object_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + } + Object::AuxiliaryInputType2(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::AuxiliaryInputType2); + Self::write_u8(&mut data, o.background_colour); + Self::write_u8(&mut data, o.function_attributes); + Self::write_u8(&mut data, o.object_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + } + Object::AuxiliaryControlDesignatorType2(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::AuxiliaryControlDesignatorType2); + Self::write_u8(&mut data, o.pointer_type); + Self::write_u16(&mut data, o.auxiliary_object_id); + } + Object::WindowMask(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::WindowMask); + Self::write_u8(&mut data, o.width); + Self::write_u8(&mut data, o.height); + Self::write_u8(&mut data, o.window_type); + Self::write_u8(&mut data, o.background_colour); + Self::write_u8(&mut data, o.options); + Self::write_u16(&mut data, o.name); + Self::write_u16(&mut data, o.window_title); + Self::write_u16(&mut data, o.window_icon); + Self::write_u8(&mut data, o.objects.len() as u8); + Self::write_u8(&mut data, o.object_refs.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_objects(&mut data, &o.objects); + Self::write_object_refs(&mut data, &o.object_refs); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::KeyGroup(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::KeyGroup); + Self::write_u8(&mut data, o.options); + Self::write_u16(&mut data, o.name); + Self::write_u16(&mut data, o.key_group_icon); + Self::write_u8(&mut data, o.objects.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_objects(&mut data, &o.objects); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::GraphicsContext(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::GraphicsContext); + Self::write_u16(&mut data, o.viewport_width); + Self::write_u16(&mut data, o.viewport_height); + Self::write_i16(&mut data, o.viewport_x); + Self::write_i16(&mut data, o.viewport_y); + Self::write_u16(&mut data, o.canvas_width); + Self::write_u16(&mut data, o.canvas_height); + Self::write_f32(&mut data, o.viewport_zoom); + Self::write_i16(&mut data, o.graphics_cursor_x); + Self::write_i16(&mut data, o.graphics_cursor_y); + Self::write_u8(&mut data, o.foreground_colour); + Self::write_u8(&mut data, o.background_colour); + Self::write_u16(&mut data, o.font_attributes_object); + Self::write_u16(&mut data, o.line_attributes_object); + Self::write_u16(&mut data, o.fill_attributes_object); + Self::write_u8(&mut data, o.format); + Self::write_u8(&mut data, o.options); + Self::write_u8(&mut data, o.transparency_colour); + } + Object::OutputList(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::OutputList); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u16(&mut data, o.variable_reference); + Self::write_u8(&mut data, o.value); + Self::write_u8(&mut data, o.list_items.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_objects(&mut data, &o.list_items); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::ExtendedInputAttributes(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::ExtendedInputAttributes); + Self::write_u8(&mut data, o.validation_type); + Self::write_u8(&mut data, o.nr_of_code_planes); + // TODO + } + Object::ColourMap(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::ColourMap); + Self::write_u16(&mut data, o.colour_map.len() as u16); + + Self::write_bytes(&mut data, &o.colour_map); + } + Object::ObjectLabelReferenceList(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::ObjectLabelReferenceList); + Self::write_u16(&mut data, o.object_labels.len() as u16); + + Self::write_object_labels(&mut data, &o.object_labels); + } + Object::ExternalObjectDefinition(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::ExternalObjectDefinition); + Self::write_u8(&mut data, o.options); + Self::write_name(&mut data, o.name); + Self::write_u8(&mut data, o.objects.len() as u8); + + Self::write_objects(&mut data, &o.objects); + } + Object::ExternalReferenceName(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::ExternalReferenceName); + Self::write_u8(&mut data, o.options); + Self::write_name(&mut data, o.name); + } + Object::ExternalObjectPointer(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::ExternalObjectPointer); + Self::write_u16(&mut data, o.default_object_id); + Self::write_u16(&mut data, o.external_reference_name_id); + Self::write_u16(&mut data, o.external_object_id); + } + Object::Animation(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::Animation); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u16(&mut data, o.refresh_interval); + Self::write_u8(&mut data, o.value); + Self::write_u8(&mut data, o.enabled); + Self::write_u8(&mut data, o.first_child_index); + Self::write_u8(&mut data, o.last_child_index); + Self::write_u8(&mut data, o.default_child_index); + Self::write_u8(&mut data, o.options); + Self::write_u8(&mut data, o.object_refs.len() as u8); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_object_refs(&mut data, &o.object_refs); + Self::write_macro_refs(&mut data, &o.macro_refs); + } + Object::ColourPalette(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::ColourPalette); + Self::write_u16(&mut data, o.options); + Self::write_u16(&mut data, o.colours.len() as u16); + + Self::write_colours(&mut data, &o.colours); + } + Object::GraphicData(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::GraphicData); + Self::write_u8(&mut data, o.format); + Self::write_u32(&mut data, o.data.len() as u32); + + Self::write_bytes(&mut data, &o.data); + } + Object::WorkingSetSpecialControls(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::WorkingSetSpecialControls); + Self::write_u16(&mut data, o.id_of_colour_map); + Self::write_u16(&mut data, o.id_of_colour_palette); + Self::write_u8(&mut data, o.language_pairs.len() as u8); + + Self::write_language_pairs(&mut data, &o.language_pairs); + } + Object::ScalesGraphic(o) => { + Self::write_u16(&mut data, o.id); + Self::write_u8(&mut data, ObjectType::ScalesGraphic); + Self::write_u16(&mut data, o.width); + Self::write_u16(&mut data, o.height); + Self::write_u8(&mut data, o.scale_type); + Self::write_u8(&mut data, o.options); + Self::write_u16(&mut data, o.value); + Self::write_u8(&mut data, o.macro_refs.len() as u8); + + Self::write_macro_refs(&mut data, &o.macro_refs); + } + } + data + } + + fn write_objects(data: &mut Vec, objects: &Vec) { + for d in objects { + Self::write_u16(data, *d); + } + } + fn write_object_refs(data: &mut Vec, object_refs: &Vec) { + for d in object_refs { + Self::write_u16(data, d.id); + Self::write_i16(data, d.offset.x); + Self::write_i16(data, d.offset.y); + } + } + fn write_macro_refs(data: &mut Vec, macro_refs: &Vec) { + for d in macro_refs { + Self::write_u8(data, d.event_id); + Self::write_u8(data, d.macro_id); + } + } + fn write_bytes(data: &mut Vec, bytes: &Vec) { + for d in bytes { + Self::write_u8(data, *d); + } + } + fn write_language_codes(data: &mut Vec, language_codes: &Vec) { + for d in language_codes { + Self::write_string(data, d); + } + } + fn write_points(data: &mut Vec, points: &Vec>) { + for d in points { + Self::write_u16(data, d.x); + Self::write_u16(data, d.y); + } + } + fn write_colours(data: &mut Vec, colours: &Vec) { + for d in colours { + Self::write_u8(data, d.b); + Self::write_u8(data, d.g); + Self::write_u8(data, d.r); + Self::write_u8(data, d.a); + } + } + fn write_object_labels(data: &mut Vec, object_labels: &Vec) { + for d in object_labels { + Self::write_u16(data, d.id); + Self::write_u16(data, d.string_variable_reference); + Self::write_u8(data, d.font_type); + Self::write_u16(data, d.graphic_representation); + } + } + fn write_language_pairs(data: &mut Vec, language_pairs: &Vec<(String, String)>) { + for d in language_pairs { + Self::write_string(data, &d.0); + Self::write_string(data, &d.1); + } + } + + fn write_u8(data: &mut Vec, val: impl Into) { + let val: u8 = val.into(); + data.push(val); + } + fn write_u16(data: &mut Vec, val: impl Into) { + let val: u16 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_i16(data: &mut Vec, val: impl Into) { + let val: i16 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_u32(data: &mut Vec, val: impl Into) { + let val: u32 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_i32(data: &mut Vec, val: impl Into) { + let val: i32 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_f32(data: &mut Vec, val: impl Into) { + let val: f32 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_string(data: &mut Vec, val: impl Into) { + let val: String = val.into(); + data.extend(val.as_bytes()); + } + fn write_name(data: &mut Vec, val: impl Into) { + let val: Name = val.into(); + data.extend::<[u8; 8]>(val.into()); + } +}