Skip to content

Commit

Permalink
Basic support for software components
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielT committed Jul 26, 2024
1 parent e4010ba commit 3348098
Show file tree
Hide file tree
Showing 4 changed files with 373 additions and 3 deletions.
1 change: 1 addition & 0 deletions autosar-data-abstraction/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use autosar_data::{AutosarDataError, AutosarModel, Element, EnumItem};
use thiserror::Error;

pub mod communication;
pub mod software_component;

mod arpackage;
mod ecuinstance;
Expand Down
312 changes: 312 additions & 0 deletions autosar-data-abstraction/src/software_component/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
use crate::*;
use autosar_data::ElementName;

pub trait AbstractSwComponentType: AbstractionElement {
/// iterator over the instances of the component type
fn instances(&self) -> SwComponentPrototypeIterator {
let model_result = self.element().model();
let path_result = self.element().path();
if let (Ok(model), Ok(path)) = (model_result, path_result) {
let reflist = model.get_references_to(&path);
SwComponentPrototypeIterator::new(reflist)
} else {
SwComponentPrototypeIterator::new(vec![])
}
}

/// iterator over all compositions containing instances of the component type
fn compositions(&self) -> impl Iterator<Item = CompositionSwComponentType> {
self.instances()
.filter_map(|swcp| swcp.element().named_parent().ok().flatten())
.filter_map(|elem| CompositionSwComponentType::try_from(elem).ok())
}
}

//##################################################################

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CompositionSwComponentType(Element);
abstraction_element!(CompositionSwComponentType, CompositionSwComponentType);

impl CompositionSwComponentType {
/// create a new composition component with the given name
pub fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
let composition = elements.create_named_sub_element(ElementName::CompositionSwComponentType, name)?;
Ok(Self(composition))
}

/// check if the composition is a parent (or grand-parent, etc.) of the component
pub fn is_parent_of<T: AbstractSwComponentType>(&self, other: &T) -> bool {
// the expectation is that in normal cases each component has only one parent
// additionally there should never be any cycles in the composition hierarchy
let mut work_items = other.compositions().collect::<Vec<_>>();
let mut counter = 1000; // just to prevent infinite loops, since I don't trust files generated by other tools
while !work_items.is_empty() && counter > 0 {
counter -= 1;
if work_items.contains(self) {
return true;
}
// the uses of pop here makes this a depth-first search in the case where there are multiple parents
let item = work_items.pop().unwrap();
work_items.extend(item.compositions());
}

false
}

/// add a component of type component_type to the composition
///
/// It is not allowed to form cycles in the composition hierarchy, and this will return an error
pub fn add_component(&self, name: &str, component_type: &SwComponentType) -> Result<(), AutosarAbstractionError> {
if let SwComponentType::Composition(composition_component) = component_type {
if composition_component.is_parent_of(self) {
return Err(AutosarAbstractionError::InvalidParameter(
"Creating a cycle in the composition hierarchy".to_string(),
));
}
}

let components = self.element().get_or_create_sub_element(ElementName::Components)?;
let component = components.create_named_sub_element(ElementName::SwComponentPrototype, name)?;
component
.create_sub_element(ElementName::TypeTref)?
.set_reference_target(&component_type.element())?;
Ok(())
}

/// get an iterator over the components of the composition
pub fn components(&self) -> CompositionComponentsIter {
CompositionComponentsIter::new(self.element().get_sub_element(ElementName::Components))
}
}

impl AbstractSwComponentType for CompositionSwComponentType {}

//##################################################################

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ApplicationSwComponentType(Element);
abstraction_element!(ApplicationSwComponentType, ApplicationSwComponentType);

impl ApplicationSwComponentType {
pub fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
let application = elements.create_named_sub_element(ElementName::ApplicationSwComponentType, name)?;
Ok(Self(application))
}
}

impl AbstractSwComponentType for ApplicationSwComponentType {}

//##################################################################

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ComplexDeviceDriverSwComponentType(Element);
abstraction_element!(ComplexDeviceDriverSwComponentType, ComplexDeviceDriverSwComponentType);

impl ComplexDeviceDriverSwComponentType {
pub fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
let cdd = elements.create_named_sub_element(ElementName::ComplexDeviceDriverSwComponentType, name)?;
Ok(Self(cdd))
}
}

impl AbstractSwComponentType for ComplexDeviceDriverSwComponentType {}

//##################################################################

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ServiceSwComponentType(Element);
abstraction_element!(ServiceSwComponentType, ServiceSwComponentType);

impl ServiceSwComponentType {
pub fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
let service = elements.create_named_sub_element(ElementName::ServiceSwComponentType, name)?;
Ok(Self(service))
}
}

impl AbstractSwComponentType for ServiceSwComponentType {}

//##################################################################

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SensorActuatorSwComponentType(Element);
abstraction_element!(SensorActuatorSwComponentType, SensorActuatorSwComponentType);

impl SensorActuatorSwComponentType {
pub fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
let sensor_actuator = elements.create_named_sub_element(ElementName::SensorActuatorSwComponentType, name)?;
Ok(Self(sensor_actuator))
}
}

impl AbstractSwComponentType for SensorActuatorSwComponentType {}

//##################################################################

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EcuAbstractionSwComponentType(Element);
abstraction_element!(EcuAbstractionSwComponentType, EcuAbstractionSwComponentType);

impl EcuAbstractionSwComponentType {
pub fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
let ecu_abstraction = elements.create_named_sub_element(ElementName::EcuAbstractionSwComponentType, name)?;
Ok(Self(ecu_abstraction))
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SwComponentType {
Composition(CompositionSwComponentType),
Application(ApplicationSwComponentType),
ComplexDeviceDriver(ComplexDeviceDriverSwComponentType),
Service(ServiceSwComponentType),
SensorActuator(SensorActuatorSwComponentType),
EcuAbstraction(EcuAbstractionSwComponentType),
}

impl AbstractionElement for SwComponentType {
fn element(&self) -> &Element {
match self {
SwComponentType::Composition(comp) => comp.element(),
SwComponentType::Application(app) => app.element(),
SwComponentType::ComplexDeviceDriver(cdd) => cdd.element(),
SwComponentType::Service(service) => service.element(),
SwComponentType::SensorActuator(sensor_actuator) => sensor_actuator.element(),
SwComponentType::EcuAbstraction(ecu_abstraction) => ecu_abstraction.element(),
}
}
}

impl TryFrom<Element> for SwComponentType {
type Error = AutosarAbstractionError;

fn try_from(element: Element) -> Result<Self, Self::Error> {
match element.element_name() {
ElementName::CompositionSwComponentType => {
Ok(SwComponentType::Composition(CompositionSwComponentType(element)))
}
ElementName::ApplicationSwComponentType => {
Ok(SwComponentType::Application(ApplicationSwComponentType(element)))
}
ElementName::ComplexDeviceDriverSwComponentType => Ok(SwComponentType::ComplexDeviceDriver(
ComplexDeviceDriverSwComponentType(element),
)),
ElementName::ServiceSwComponentType => Ok(SwComponentType::Service(ServiceSwComponentType(element))),
ElementName::SensorActuatorSwComponentType => {
Ok(SwComponentType::SensorActuator(SensorActuatorSwComponentType(element)))
}
ElementName::EcuAbstractionSwComponentType => {
Ok(SwComponentType::EcuAbstraction(EcuAbstractionSwComponentType(element)))
}
_ => Err(AutosarAbstractionError::ConversionError {
element,
dest: "SwComponentType".to_string(),
}),
}
}
}

impl From<CompositionSwComponentType> for SwComponentType {
fn from(comp: CompositionSwComponentType) -> Self {
SwComponentType::Composition(comp)
}
}

impl From<ApplicationSwComponentType> for SwComponentType {
fn from(app: ApplicationSwComponentType) -> Self {
SwComponentType::Application(app)
}
}

impl From<ComplexDeviceDriverSwComponentType> for SwComponentType {
fn from(cdd: ComplexDeviceDriverSwComponentType) -> Self {
SwComponentType::ComplexDeviceDriver(cdd)
}
}

impl From<ServiceSwComponentType> for SwComponentType {
fn from(service: ServiceSwComponentType) -> Self {
SwComponentType::Service(service)
}
}

impl From<SensorActuatorSwComponentType> for SwComponentType {
fn from(sensor_actuator: SensorActuatorSwComponentType) -> Self {
SwComponentType::SensorActuator(sensor_actuator)
}
}

impl From<EcuAbstractionSwComponentType> for SwComponentType {
fn from(ecu_abstraction: EcuAbstractionSwComponentType) -> Self {
SwComponentType::EcuAbstraction(ecu_abstraction)
}
}

impl AbstractSwComponentType for SwComponentType {}

//##################################################################

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SwComponentPrototype(Element);
abstraction_element!(SwComponentPrototype, SwComponentPrototype);

//##################################################################

element_iterator!(CompositionComponentsIter, SwComponentType, Some);

//##################################################################

reflist_iterator!(SwComponentPrototypeIterator, SwComponentPrototype);

//##################################################################

#[cfg(test)]
mod test {
use autosar_data::AutosarVersion;

use super::*;

#[test]
fn software_compositions() {
let model = AutosarModel::new();
let _file = model.create_file("filename", AutosarVersion::LATEST).unwrap();
let package = ArPackage::get_or_create(&model, "/package").unwrap();

let comp1 = CompositionSwComponentType::new("comp1", &package).unwrap();
let comp2 = CompositionSwComponentType::new("comp2", &package).unwrap();
let comp3 = CompositionSwComponentType::new("comp3", &package).unwrap();
let comp4 = CompositionSwComponentType::new("comp4", &package).unwrap();

comp1.add_component("comp2", &comp2.clone().into()).unwrap();
comp2.add_component("comp3", &comp3.clone().into()).unwrap();
comp3.add_component("comp4", &comp4.clone().into()).unwrap();

assert_eq!(comp1.instances().count(), 0);
assert_eq!(comp2.instances().count(), 1);
assert_eq!(comp3.instances().count(), 1);
assert_eq!(comp4.instances().count(), 1);

assert!(comp1.is_parent_of(&comp2));
assert!(comp1.is_parent_of(&comp3));
assert!(comp1.is_parent_of(&comp4));

assert!(!comp2.is_parent_of(&comp1));
assert!(comp2.is_parent_of(&comp3));
assert!(comp2.is_parent_of(&comp4));

assert!(!comp3.is_parent_of(&comp1));
assert!(!comp3.is_parent_of(&comp2));
assert!(comp3.is_parent_of(&comp4));

assert!(!comp4.is_parent_of(&comp1));
assert!(!comp4.is_parent_of(&comp2));
assert!(!comp4.is_parent_of(&comp3));
}
}
24 changes: 23 additions & 1 deletion autosar-data-abstraction/src/system.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::iter::FusedIterator;

use crate::communication::{
CanCluster, CanClusterSettings, CanFrame, Cluster, ContainerIPdu, DcmIPdu, EthernetCluster, FlexrayCluster, FlexrayClusterSettings, FlexrayFrame, GeneralPurposeIPdu, GeneralPurposePdu, ISignal, ISignalGroup, ISignalIPdu, MultiplexedIPdu, NPdu, NmPdu, SecuredIPdu, SystemSignal, SystemSignalGroup
CanCluster, CanClusterSettings, CanFrame, Cluster, ContainerIPdu, DcmIPdu, EthernetCluster, FlexrayCluster,
FlexrayClusterSettings, FlexrayFrame, GeneralPurposeIPdu, GeneralPurposePdu, ISignal, ISignalGroup, ISignalIPdu,
MultiplexedIPdu, NPdu, NmPdu, SecuredIPdu, SystemSignal, SystemSignalGroup,
};
use crate::software_component::CompositionSwComponentType;
use crate::{abstraction_element, AbstractionElement, ArPackage, AutosarAbstractionError, EcuInstance};
use autosar_data::{AutosarDataError, AutosarModel, Element, ElementName, WeakElement};

Expand Down Expand Up @@ -665,6 +668,25 @@ impl System {
.create_sub_element(ElementName::FibexElementRef)?;
fibex_element_ref.set_reference_target(elem)
}

/// set the root software composition of the system
pub fn set_root_sw_composition(
&self,
name: &str,
composition_type: &CompositionSwComponentType,
) -> Result<(), AutosarAbstractionError> {
let root_compositions = self.0
.get_or_create_sub_element(ElementName::RootSoftwareCompositions)?;

if let Some(existing_composition) = root_compositions.get_sub_element(ElementName::RootSwCompositionPrototype) {
root_compositions.remove_sub_element(existing_composition)?;
}
root_compositions
.create_named_sub_element(ElementName::RootSwCompositionPrototype, name)?
.get_or_create_sub_element(ElementName::SoftwareCompositionTref)?
.set_reference_target(composition_type.element())?;
Ok(())
}
}

//#########################################################
Expand Down
Loading

0 comments on commit 3348098

Please sign in to comment.