BswmdModel Details

BswmdModel - DefinitionModel

The BswmdModel provides a type safe and easy access to data of BSW modules (Ecu configuration elements).

Examples:

  • Access a single parameter /MICROSAR/ComM/ComMGeneral/ComMUseRte: comM.getComMGeneral().getComMUseRte()
  • Access containers [0:*] /MICROSAR/ComM/ComMChannel:
for(ComMChannel channel :comM.

getComMChannel()){
int value = channel.getComMChannelId().getValue();
}

The DaVinci Configurator Classic internal Model (MDF model) has a 1:1 relationship to your BswmdModel. The BswmdModel retrieves all data from the underlying MDF model.

The relationship between the MDF model and the BswmdModel
Figure 1. The relationship between the MDF model and the BswmdModel

DefinitionModel

The DefinitionModel is the base implementation of every BswmdModel. Every BswmdModel class is a subclass of the DefinitionModel where the classes begin with GI, like GIContainer.

Types of DefinitionModels

There are two types of DefinitionModels:
  1. BswmdModel (formally known as DefinitionTyped BswmdModel)
  2. DefRef API (formally known as Untyped BswmdModel)

The BswmdModel consists of generated classes for the module definition elements like ModuleDefinitions, Containers, Parameters in bswmd files. The generated class contains getter methods for each child element. So you can access every child by the corresponding getter method with compile time safety of the sub type.

The BswmdModel derives from the DefinitionModel DefRef API, so the BswmdModel contains all functionalities of the DefRef API.

The DefRef API of the DefinitionModel provides a generic access to the Ecu configuration structure via DefRefs. There are NO generated classes for the Definition structure. The DefRef API uses the base classes of the DefinitionModel to provide this DefRef based access. Every interface in the DefinitionModel starts with an GI. The Ecu Configuration elements have corresponding base interfaces for each element:

  • ModuleConfiguration - GIModuleConfiguration
  • Container - GIContainer
  • ChoiceContainer - GIChoiceContainer
  • Parameter - GIParameter<?>
    • Integer Parameter - GIParameter<BigInteger>
    • Boolean Parameter - GIParameter<Boolean>
    • Float Parameter - GIParameter<Double>
    • String Parameter - GIParameter<String>
  • Reference - GIReference<?>
    • Container Reference - GIReferenceToContainer
    • Foreign Reference- GIReference<Class>

DefRef Getter Methods of Untyped Model

The DefRef API classes have no getter methods for the specific child types, but the children can be retrieved via the generic getter methods like:

  • GIContainer.getSubContainers()
  • GIContainer.getParameters()
  • GIContainer.getParameters(TypedDefRef)
  • GIContainer.getParameter(TypedDefRef)
  • GIContainer.getReferencesToContainer(TypedDefRef)
  • GIModuleConfiguration.getSubContainer(TypedDefRef)
  • GIParameter.getValueMdf()
Additionally there are methods to retrieve other referenced elements, like parent of reference reverse lookup:
  • GIContainer.getParent()
  • GIContainer.getParent(DefRef)
  • GIContainer.getReferencesPointingToMe()
  • GIContainer.getReferencesPointingToMe(DefRef)

The following listings describe the usage of the untyped BswmdModel method:

Sample code to access element in an Untyped model with DefRefs
// Get the container from external method getCanIfInitConfigBswmd() ...
final GIContainer canIfInit = getCanIfInitConfigBswmd();

// Gets all subcontainers from a container CanIfRxPduConfig from the canIfInit instance
final List<GIContainer> subContainers = canIfInit.getSubContainers(CanIfRxPduConfig.DEFREF.castToTypedDefRef());
if (subContainers.isEmpty()) {
    // ERROR Handling
}
final GIContainer cont = subContainers.get(0);

// Gets exactly one CanIfCanRxPduHrhRef reference from the cont instance
final GIReference<MIContainer> child = cont.getReference(CanIfCanRxPduHrhRef.DEFREF.castToTypedDefRef());

Resolves a Reference target of a Reference Parameter
final GIReferenceToContainer ref = getCanIfCanRxPduHrhRefBswmd();

final GIContainer target = ref.getRefTarget();

The value of a GIParameter
final GIParameter<BigInteger> param = getCanIfInitConfigBswmd().getParameter(CanIfInitConfiguration.CANIF_NUMBER_OF_CAN_TXPDU_IDS_DEFREF);

final BigInteger value = param.getValueMdf();

Figure SubContainerDefRefNavigation shows the available DefRef navigation methods for the Untyped model. There are more methods to navigate with the DefRef API through the DefinitionModel, please look into the Javadoc documentation of the GI... classes for more functionality.

SubContainer DefRef navigation methods
Figure 2. SubContainer DefRef navigation methods

References

All references in the BswmdModel are subtypes of GIReference. The generated model contains generated DefintionTyped classes for references to container, for the other references there are only Untyped classes like GInstanceReference.

A GIReference has the method getRefTargetMdf(), this will always return the target in the MDF model as MIReferrable. For non GIReferenceToContainer this is the normal way to resolve references, but for references to a container you should always try to use the method getRefTarget(), which will not leave the BswmdModel.

Note: Try to use getRefTarget() as much as possible.

The following references are references to a container (References pointing to container) and are subtypes of the GIReferenceToContainer.

  • Normal Reference
  • SymbolicNameReference
  • ChoiceReference

References have the method getRefTarget(), which returns the target as BswmdModel object. If the type of the target is known at model generation time, the return type will be the generated type, otherwise the return type is GIContainer.

Note: It is always allowed to call getRefTarget(), also for references pointing to external types.

There is the other method getPossibleRefTargets(), which returns all possible target container as list. If the type of the targets is known at model generation time, the list type will be the generated type, e.G. List<CanGeneral>. Otherwise the return type is GIContainerList<List<{@link GIContainer}>.

Untyped reference interfaces in the BswmdModel
Figure 3. Untyped reference interfaces in the BswmdModel

SymbolicNameReferences have the same methods as GIReferenceToContainer and the additional methods getRefTargetParameterMdf(), which returns the target parameter as MIObject The method getRefTargetParameter() return a BswmdModel object, if the type is known at model generation time, the type will be the generated type. Otherwise the return type is GIParameter.

Note: It is always allowed to call getRefTargetParameter(), also for references pointing to external types.

Post-build selectable with BswmdModel

The BswmdModel supports the Post-build selectable use case, in respect that you do not have to switch nor cache the corresponding IModelView. The BswmdModel objects cache the so called Creation ModelView and switch transparently to that view when accessing the Model. So you don't have to switch to the correct view on access. See figure BswmdModelCreatePBSelectable. You only have to ensure, that the requested IModelView is active or passed as parameter, when you create an instance at the GIModelFactory. Note: A lazy created object will inherit the view of the existing element.
Creating a BswmdModel in the Post-build selectable use case
Figure 4. Creating a BswmdModel in the Post-build selectable use case

Creation ModelView of the BswmdModel

Every GIModelObject (BswmdModel object) has a creation IModelView. This is the IModelView, which was active or passed during creation of the BswmdModel. At every method call to the BswmdModel, the model will switch to this view. The method getCreationModelView() returns the IModelView of this GIModelObject, which was active during the creation of this BswmdModel. The method executeWithCreationModelView() executes the code under visibility of the getCreationModelView() of this GIModelObject.

The returned IModelViewExecutionContext must be used within a Java "try-with-resources" block. It makes sure, that the old view is restored when the try is completed.

GIModelObject myModelObject = ...;

try (final IModelViewExecutionContext context = myModelObject.executeWithCreationModelView()) {
        // do some operations
        ...
}
The method executeWithCreationModelView(Runnable) executes the Runnable code under visibility of the getCreationModelView() of this GIModelObject.

 GIModelObject myModelObject = ...;

 myModelObject.executeWithCreationModelView(()->{
  // do some operations
 });
The method executeWithCreationModelView() executes the Supplier code under visibility of the getCreationModelView() of this GIModelObject. You could use this method, if you want to return an object from this operation.

GIModelObject myModelObject = ...;

ReturnType returnVal = myModelObject.executeWithCreationModelView(()->{
  // do some operations
  return theValue;
 });

Lazy Instantiating

The BswmdModel is instantiated lazily; this means when you create a ModuleConfiguration object only one object for the module configuration is created.

When you call a getXXX() method on the configuration it will create the requested sub element, if it exists. So you can start at any point in the model (e.g. a Subcontainer) and the model is built successively by your calls.

It is also allowed to call getParent() on a Subcontainer, if the parent was not created yet. This technique can be used in validations when the creation of the full BswmdModel is too expensive. Then you can create only the needed container from an MDF model object.

Optional Elements

All elements (Container, Parameter ...) are considered optional if they have a multiplicity of 0:1. The BswmdModel provides a special handling of optional elements to support you in recognizing optional elements during development (in most cases some kind of special handling is needed).

An optional element has other access methods than a required element: The method getXXX() will not return the element directly — it will return a GIOptional<Element> object instead. You can query the GIOptional object if the element exists (optElement.exists()). Then optElement.get() can be called to retrieve the real object.

You also have the choice to use the method existsXXX() to check for element existence. This method is equivalent to getXXX().exists(). The difference is that you get a compile error if you try to use the optional element without any check.

When you are sure that the element must exist you can directly call getXXXUnsafe().

Note: If you use any of the get methods (optElement.get() or getXXXUnsafe()) and the element does not exist, the normal BswmdModelException is thrown.

Class and Interface Structure of the BswmdModel

The class structure shows the Untyped API (GI... interfaces) in the upper part. The bottom left part is an example of a DefinitionTyped (generated) class for the CanIf module. The bottom right part shows the classes used by the DefinitionTyped model, which are not visible in the Untyped model.

Class and Interface Structure of the BswmdModel
Figure 5. Class and Interface Structure of the BswmdModel

BswmdModel Write Access

The BswmdModel supports a write access for ECU configuration elements. This means new elements can be created and existing elements can be modified and deleted by the BswmdModel.

NOTE: The model is in read-only state by default, so no objects can be created. For this reason all calls to an API which creates or deletes elements has to be executed within a transaction.

Optional and required Elements (0:1/1:1 Multiplicity)

For optional or required elements, the following additional methods are generated, if BswmdModelWriteAccess is enabled:

  • get...OrNull(): Returns the requested element or null if it is missing.
  • get...OrCreate(): Returns the existing requested element or implicitly creates a new one if it is missing.

E.g. EcucGeneral:

Ecuc ecuc = getEcucModuleConfig();

//Gets the EcucGeneral container or null if it is missing.
EcucGeneral ecucGeneralOrNull = ecuc.getEcucGeneralOrNull();

//Gets the existing EcucGeneral container or creates a new one if it is missing.
EcucGeneral ecucGeneralOrCreate = ecuc.getEcucGeneralOrCreate();

Multiple elements (Upper Multiplicity > 1)

For each multiple element, the return type for these elements is changed from List<> to GIPList<> for parameter and GICList<> for container, if BswmdModelWriteAccess is enabled. These new interfaces provide methods which allow creating and adding new children for the corresponding elements:

  • createAndAdd(): Creates a new child element, appends it to the list and returns the new element.
  • createAndAdd(int index): Creates a new child element, inserts it to the list at the specified index position and returns the new element.
  • For GICList<> only:
    • createAndAdd(String shortName): Creates a new child element with the specified shortName, appends it to the list and returns the new element.
    • createAndAdd(String shortName, int index): Creates a new child element with the specified shortName, inserts it to the list at the specified index position and returns the new element.
    • byName(String shortName): Gets the container by specified shortName or throws an exception if it is missing.
    • byNameOrNull(String shortName): Gets the container by specified shortName or null if it is missing.
    • byNameOrCreate(String shortName): Gets the container by specified shortName or implicitly creates a new one if it is missing.
    • exists(String shortname): Returns true if the container exists, otherwise false.

The following example creates EcucCoreDefinition via the Write API:

Ecuc ecuc = getEcucModuleConfig();

//Gets the EcucCoreDefinition list (create EcucHardware container if it is missing)
GICList<EcucCoreDefinition> ecucCores = ecuc.getEcucHardwareOrCreate().getEcucCoreDefinition();

//Adds two EcucCores
EcucCoreDefinition core0 = ecucCores.createAndAdd("EcucCore0");
EcucCoreDefinition core1 = ecucCores.createAndAdd("EcucCore1");

if(ecucCores.exists("EcucCore0")){
    //Sets EcucCoreId from EcucCore0 to 0
    ecucCores.byName("EcucCore0").getEcucCoreId().setValue(0);
}

//Creates a new EcucCore by method byNameOrCreate
EcucCoreDefinition core2 = ecucCores.byNameOrCreate("EcucCore2");

...

Other write API

  • Deleting model objects: It is also possible to delete objects from the model.
    • moRemove: Deletes the specified object from the model.
    • moIsRemoved: Returns true, if the object was removed from repository, or is invisible in the current active IModelView.
//Deletes the container 'EcucGeneral' from the model.
ecucGeneral.moRemove();

//Deletes the parameter 'EcuCSafeBswChecks' from the model.
ecucGeneral.getEcuCSafeBswChecks.moRemove();

//Deletes the child container 'EcucCoreDefinition' with shortname 'EcucCore0' from the model.
ecucCores.byName("EcucCore0").moRemove();

// Checks if the container 'EcucGeneral' was removed from repository, or is invisible in the current active `IModelView`.
if(ecucGeneral.moIsRemoved()){
    ...
}
  • Duplication of containers: The method duplicate() copies a container with all its children and appends it to the same parent.
//Duplicates the container 'EcucGeneral'
EcucGeneral duplicatedEcucGeneral = ecucGeneral.duplicate();

//Duplicates the child container 'EcucCoreDefinition' with shortname 'EcucCore0'
var duplicatedEcucCore0 = ecucCores.byName("EcucCore0").duplicate();
  • Parameter values: The method setValue(VALUE) sets the value of a parameter. This method checks if the specified parameters configuration object is available and sets the new value. If the parameter object is missing it is implicitly created in the model.
//Sets the value of the parameter 'EcuCSafeBswChecks' to 'true'
ecucGeneral.getEcuCSafeBswChecks.setValue(true);
  • Reference targets: The method setRefTarget(REF_TARGET) sets the target of a reference. This method sets the specified target object as reference target of the specified reference parameter. If the reference parameter object is missing it is implicitly created in the model.
//Gets the container 'OsCounter' with shortname 'SystemTimer'
OsCounter osCounterTarget = os.getOsCounters.byName("SystemTimer");

//Sets the reference target of the parameter 'CanCounterRef'
can.getCanGeneral().getCanCounterRef().setRefTarget(osCounterTarget);

BswmdModel Declaration API

The BswmdModel supports declaration API to declare an AUTOSAR ECU configuration structure in code, which is then synchronized with the existing structure to create elements in a declarative way.

Note: The model is in read-only state by default, so no objects can be created or synchronized. You must have an open transaction running, when using the Declaration API, because it will change the model.

Entrypoint into Declaration

You can enter the Declaration API on every module configuration or container with the method declare{}. Inside the declare{} block you use the Declaration API.

Start declaration API on a Module
can.declare {
    //Inside here you can use the Declaration API
}

Usage of the Declaration API on an existing container:

Start declaration API on any existing container
CanGeneral canGeneral = can.canGeneral
canGeneral.declare { CanGeneralDeclaration decl ->
    //Inside here you can use the Declaration API
}

API Structure

Every module or container class has a corresponding <ElementName>Declaration class, which is used to declare the structure of the module or container tree.

Every <Name>Declaration class defines the methods to declare its direct child containers and child parameters:

  • <ContainerName>(Action) method: For 0:1 or 1:1 child containers
  • <ContainerName>(String shortname, Action) method: For 0:* child containers
  • <ParameterName>(value) method: For 0:1 or 1:1 child parameters
  • <ParameterName>(values...) method: For 0:* child parameters
  • <ReferenceName>(referenceTarget) method: For 0:1 or 1:1 child references
  • <ReferenceName>(referenceTargets...) method: For 0:* child references

The declaration methods will return the created or existing BswmdModel element (GIxxx), which was used by the called declaration. So the CanGeneral{} method returns the CanGeneral container. This can be useful, if you need the element as a reference target for a reference pointing to that container.

Semantics

The Declaration API does not clean the underlying AUTOSAR model, it tries to synchronize the existing model with your declared structure. If you want to declare a new structure, you have to delete (with moRemove()) the model element before declaring elements.

So a call to the CanGeneral{} in the Can module with multiplicity 1:1 will use the existing container. If no container exists, a new container will be created with the name CanGeneral.

Container declaration with 0:1 or 1:1 multiplicity
can.declare {
    CanGeneral {
        //Declares the CanGeneral container
    }
}

For the 0:* multiplicity, the Declaration API tries to find the container with the given shortname, otherwise it will create the container with the shortname. That is the reason why 0:* containers need a shortname in the API.

Container declaration with upper multiplicity > 1
can.declare {
    CanConfigSet("Config1") {
        //Declares "Config1" CanConfigSet container
    }
    CanConfigSet("Config2") {
        //Declares "Config2" CanConfigSet container
    }
}

All 0:1 and 1:1 parameters and references are automatically created, when their values are set. And also existing parameters are synchronized with the new values.

Parameter declaration with 0:1 or 1:1 multiplicity
can.declare {
    CanGeneral {
        //Declares 0:1 or 1:1 parameters
        CanDevErrorDetection(true)
        CanInterruptLock(ECanInterruptLock.APPL)
        CanGenericConfirmation(false)
    }
}

For 0:* parameters and references, the Declaration API will synchronize the existing parameters with the new values by index. If there is no parameter for that index, a new parameter will be created. But existing ones are not deleted. The 0:* parameters have a vararg parameter, where the index in the vararg array is the index of the resulting parameter.

Parameter declaration with upper multiplicity > 1
can.canGeneral.declare {
    CanMainFunctionRWPeriods {
        //Declares 3 parameters of type CanMainFunctionReadPeriod
        CanMainFunctionReadPeriod(10, 30, 50)
    }
}

Interop with BswmdModel and MDF Model

The Declaration API provides interop methods to switch into the normal BswmdModel or the MDF model for each element. You can use the methods getBswmdModelObject() or getMdfObject() to switch to them.

Declaration API interop
can.declare {
    CanGeneral {
        //Switch into the normal BswmdModel API
        CanGeneral theBswmdObject = bswmdModelObject
        def theObjectLink = bswmdModelObject.objectLink
        //Switch into the MDF model
        MIContainer theMdfObj = mdfObject
    }
}

You can also interleave other model operation code with the Declaration API code. The Declaration API will synchronize the model directly at the method call and the BswmdModel will reflect the change immediately.

The method setShortname() can be used to rename an object.

Container shortname API
can.declare {
    CanGeneral {
        //Get the current shortName
        String theShortName = shortname
        //Set shortName of the container
        shortname = theShortName + "New"
    }
}

The Declaration API uses the underlying BswmdModel Write Access to synchronize the model, so the same post-build selectable write semantics apply.

Usage Sample

The following sample declares a structure on the Can module with the Declaration API.

Example BswmdModel Declaration API on a Can module
can.declare {

    CanGeneral {
        CanDevErrorDetection(true)
        CanGetStatus(false)
        CanIdenticalIdCancellation(false)
        CanInterruptLock(ECanInterruptLock.APPL)
        CanIndex(5)
        CanGenericPreTransmit(false)
    }

    CanConfigSet("CanConfigSet") {
        CanController("Controller1") {
            CanControllerId(1)
            CanBusName("CanBus1")

            def baud1 = CanControllerBaudrateConfig("Baud1") {
                CanSamplingMode(ECanSamplingMode.OneSample)
            }
            //Second Baudrate config
            CanControllerBaudrateConfig("Baud2") {
                CanSamplingMode(ECanSamplingMode.ThreeSamples)
            }

            CanControllerDefaultBaudrate(baud1) //Assign a refTarget to reference
        }

        CanController("Controller2") {
            CanControllerId(2)
        }
    }
}

BswmdModel generation

The BswmdModel for the automation interface is generated automatically by the DaVinci Configurator.

DerivativeMapping

If the BSW Package contains one or more modules with a DerivativeMapping, the BswmdModel classes for these modules can only be generated for one certain derivative. By default, the first derivative is selected, sorted by UUID.

If a other derivative shall be selected for BswmdModel generation a Settings_BswmdModel.xml file can be defined in the BSW Package. The supported location depends on the BSW Package structure:

  • Legacy structure (no Components/ folder):
    place the file at <SIP-ROOT-PATH>/DaVinciConfigurator/Generators/Settings_BswmdModel.xml
  • Current structure (has Components/ folder):
    place the file in any component's generator folder,
    e.g. <SIP-ROOT-PATH>/Components/<Module>/GeneratorDvC6/Settings_BswmdModel.xml. Note: DaVinciConfigurator/Generators/ is not evaluated for BSW packages with the current structure. If multiple components each define a Settings_BswmdModel.xml with the same setting key but different values, loading will fail with an error. If all files define the same value, the duplicates are silently ignored.

Sample file:

 <Settings>
     <Settings Name="com.vector.cfg.bswmdmgen.BswmdAutomationModelSettings">
              <!--Selects the derivative with the name or UUID specified by Value-->
              <Setting Name="SelectedDerivative" Value="SPX546B"/>
     </Settings>
 </Settings>