autosar_data_abstraction/communication/controller/
ethernet.rsuse crate::communication::{
AbstractCommunicationConnector, AbstractCommunicationController, EthernetPhysicalChannel, EthernetVlanInfo,
};
use crate::{abstraction_element, AbstractionElement, AutosarAbstractionError, EcuInstance};
use autosar_data::{AutosarDataError, AutosarModel, Element, ElementName, ElementsIterator, WeakElement};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EthernetCommunicationController(Element);
abstraction_element!(EthernetCommunicationController, EthernetCommunicationController);
impl EthernetCommunicationController {
pub(crate) fn new(
name: &str,
ecu: &EcuInstance,
mac_address: Option<String>,
) -> Result<Self, AutosarAbstractionError> {
let commcontrollers = ecu.element().get_or_create_sub_element(ElementName::CommControllers)?;
let ctrl = commcontrollers.create_named_sub_element(ElementName::EthernetCommunicationController, name)?;
let ethccc = ctrl
.create_sub_element(ElementName::EthernetCommunicationControllerVariants)?
.create_sub_element(ElementName::EthernetCommunicationControllerConditional)?;
if let Some(mac_address) = mac_address {
let result = ethccc
.create_sub_element(ElementName::MacUnicastAddress)
.and_then(|mua| mua.set_character_data(mac_address));
if let Err(mac_address_error) = result {
let _ = commcontrollers.remove_sub_element(ctrl);
return Err(mac_address_error.into());
}
}
let coupling_port_name = format!("{name}_CouplingPort");
let _ = ethccc
.create_sub_element(ElementName::CouplingPorts)
.and_then(|cps| cps.create_named_sub_element(ElementName::CouplingPort, &coupling_port_name));
Ok(Self(ctrl))
}
pub fn connected_channels(&self) -> impl Iterator<Item = EthernetPhysicalChannel> {
if let Ok(ecu) = self.ecu_instance().map(|ecuinstance| ecuinstance.element().clone()) {
EthernetCtrlChannelsIterator::new(self, &ecu)
} else {
EthernetCtrlChannelsIterator {
connector_iter: None,
comm_controller: self.0.clone(),
model: None,
}
}
}
pub fn connect_physical_channel(
&self,
connection_name: &str,
eth_channel: &EthernetPhysicalChannel,
) -> Result<EthernetCommunicationConnector, AutosarAbstractionError> {
let ecu: Element = self.0.named_parent()?.unwrap();
let cluster_of_channel = eth_channel.cluster()?;
for phys_channel in self.connected_channels() {
if phys_channel == *eth_channel {
return Err(AutosarAbstractionError::ItemAlreadyExists);
}
if phys_channel.cluster()? != cluster_of_channel {
return Err(AutosarAbstractionError::InvalidParameter(
"The EthernetCommunicationController may only refer to different channels within the same cluster"
.to_string(),
));
}
}
let connectors = ecu.get_or_create_sub_element(ElementName::Connectors)?;
let connector = EthernetCommunicationConnector::new(connection_name, &connectors, self)?;
if let Some(category) = eth_channel
.element()
.get_sub_element(ElementName::Category)
.and_then(|cat| cat.character_data())
.and_then(|cdata| cdata.string_value())
{
let _ = connector
.element()
.create_sub_element(ElementName::Category)
.and_then(|cat| cat.set_character_data(category));
}
let channel_connctor_refs = eth_channel
.element()
.get_or_create_sub_element(ElementName::CommConnectors)?;
channel_connctor_refs
.create_sub_element(ElementName::CommunicationConnectorRefConditional)
.and_then(|ccrc| ccrc.create_sub_element(ElementName::CommunicationConnectorRef))
.and_then(|ccr| ccr.set_reference_target(connector.element()))?;
if let Some(EthernetVlanInfo { .. }) = eth_channel.vlan_info() {
if let Some(coupling_port) = self
.0
.get_sub_element(ElementName::EthernetCommunicationControllerVariants)
.and_then(|eccv| eccv.get_sub_element(ElementName::EthernetCommunicationControllerConditional))
.and_then(|eccc| eccc.get_sub_element(ElementName::CouplingPorts))
.and_then(|cps| cps.get_sub_element(ElementName::CouplingPort))
{
coupling_port
.get_or_create_sub_element(ElementName::VlanMemberships)
.and_then(|vms| vms.create_sub_element(ElementName::VlanMembership))
.and_then(|vm| vm.create_sub_element(ElementName::VlanRef))
.and_then(|vr| vr.set_reference_target(eth_channel.element()))?;
}
}
Ok(connector)
}
}
impl AbstractCommunicationController for EthernetCommunicationController {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EthernetCommunicationConnector(Element);
abstraction_element!(EthernetCommunicationConnector, EthernetCommunicationConnector);
impl EthernetCommunicationConnector {
pub(crate) fn new(
name: &str,
parent: &Element,
controller: &EthernetCommunicationController,
) -> Result<Self, AutosarAbstractionError> {
let connector = parent.create_named_sub_element(ElementName::EthernetCommunicationConnector, name)?;
connector
.create_sub_element(ElementName::CommControllerRef)
.and_then(|refelem| refelem.set_reference_target(&controller.0))?;
Ok(Self(connector))
}
}
impl AbstractCommunicationConnector for EthernetCommunicationConnector {
type CommunicationControllerType = EthernetCommunicationController;
fn controller(&self) -> Result<Self::CommunicationControllerType, AutosarAbstractionError> {
let controller = self
.element()
.get_sub_element(ElementName::CommControllerRef)
.ok_or_else(|| {
AutosarAbstractionError::ModelError(AutosarDataError::ElementNotFound {
target: ElementName::CommControllerRef,
parent: self.element().element_name(),
})
})?
.get_reference_target()?;
EthernetCommunicationController::try_from(controller)
}
}
#[doc(hidden)]
pub struct EthernetCtrlChannelsIterator {
connector_iter: Option<ElementsIterator>,
comm_controller: Element,
model: Option<AutosarModel>,
}
impl EthernetCtrlChannelsIterator {
fn new(controller: &EthernetCommunicationController, ecu: &Element) -> Self {
let iter = ecu.get_sub_element(ElementName::Connectors).map(|c| c.sub_elements());
let comm_controller = controller.element().clone();
let model = comm_controller.model().ok();
Self {
connector_iter: iter,
comm_controller,
model,
}
}
}
impl Iterator for EthernetCtrlChannelsIterator {
type Item = EthernetPhysicalChannel;
fn next(&mut self) -> Option<Self::Item> {
let model = self.model.as_ref()?;
let connector_iter = self.connector_iter.as_mut()?;
for connector in connector_iter.by_ref() {
if connector.element_name() == ElementName::EthernetCommunicationConnector {
if let Some(commcontroller_of_connector) = connector
.get_sub_element(ElementName::CommControllerRef)
.and_then(|ccr| ccr.get_reference_target().ok())
{
if commcontroller_of_connector == self.comm_controller {
for ref_origin in model
.get_references_to(&connector.path().ok()?)
.iter()
.filter_map(WeakElement::upgrade)
.filter_map(|elem| elem.named_parent().ok().flatten())
{
if ref_origin.element_name() == ElementName::EthernetPhysicalChannel {
return EthernetPhysicalChannel::try_from(ref_origin).ok();
}
}
}
}
}
}
None
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{communication::EthernetVlanInfo, ArPackage, SystemCategory};
use autosar_data::{AutosarModel, AutosarVersion};
#[test]
fn controller() {
let model = AutosarModel::new();
model.create_file("filename", AutosarVersion::Autosar_00048).unwrap();
let pkg = ArPackage::get_or_create(&model, "/test").unwrap();
let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
let result = ecu.create_ethernet_communication_controller("Controller", Some("abcdef".to_string()));
assert!(result.is_err());
let result = ecu.create_ethernet_communication_controller("Controller", Some("01:02:03:04:05:06".to_string()));
let controller = result.unwrap();
let cluster = system.create_ethernet_cluster("EthCluster", &pkg).unwrap();
let channel1 = cluster.create_physical_channel("C1", None).unwrap();
let vlan_info = EthernetVlanInfo {
vlan_name: "VLAN_1".to_string(),
vlan_id: 1,
};
let channel2 = cluster.create_physical_channel("C2", Some(vlan_info)).unwrap();
let connector = controller
.connect_physical_channel("connection_name1", &channel1)
.unwrap();
assert_eq!(connector.controller().unwrap(), controller);
let result = controller.connect_physical_channel("connection_name2", &channel1);
assert!(result.is_err());
let result = controller.connect_physical_channel("connection_name2", &channel2);
assert!(result.is_ok());
let cluster2 = system.create_ethernet_cluster("EthCluster2", &pkg).unwrap();
let channel3 = cluster2.create_physical_channel("C3", None).unwrap();
let result = controller.connect_physical_channel("connection_name3", &channel3);
assert!(result.is_err());
let count = controller.connected_channels().count();
assert_eq!(count, 2);
let ctrl_parent = controller.element().parent().unwrap().unwrap();
ctrl_parent.remove_sub_element(controller.element().clone()).unwrap();
let count = controller.connected_channels().count();
assert_eq!(count, 0);
}
#[test]
fn connector() {
let model = AutosarModel::new();
model.create_file("filename", AutosarVersion::Autosar_00048).unwrap();
let pkg = ArPackage::get_or_create(&model, "/test").unwrap();
let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
let controller = ecu
.create_ethernet_communication_controller("Controller", None)
.unwrap();
assert_eq!(controller.ecu_instance().unwrap(), ecu);
let cluster = system.create_ethernet_cluster("EthCluster", &pkg).unwrap();
let channel = cluster.create_physical_channel("C1", None).unwrap();
let connector = controller
.connect_physical_channel("connection_name", &channel)
.unwrap();
assert_eq!(connector.controller().unwrap(), controller);
assert_eq!(connector.ecu_instance().unwrap(), ecu);
let conn_parent = connector.element().parent().unwrap().unwrap();
conn_parent.remove_sub_element(connector.element().clone()).unwrap();
let result = connector.controller();
assert!(result.is_err());
}
}