OTX-Runtime for DotNet  
Runtime Behavior

The runtime behavior of the communication channels (ComChannel) and the associated diagnostic services (DiagService) is handled inside the OTX-DiagManager API. It is described in detail in this chapter. The description is aimed at system integrators who need precise knowledge of the behavior. Especially when the DiagManager is used by several applications at the same time.

Note: The DiagManager manages the communication channels and diagnostic services automatically!

Note: ISO 13209-3 deliberately leaves room for implementation in the runtime behavior of a ComChannel and a DiagService. This freedom is precisely specified here.

A ComChannel represents a LogicalLink (MCDLogicalLink in case of a MVCI-Server) to an ECU or a FunctionalGroup, see Functional Addressing. It can be used for communication. A LogicalLink is defined in a VehicleInformation of the ODX data base.

  1. ComChannel Lifetime - Creation
  2. ComChannel Lifetime - Closing
  3. ComChannel Lifetime - Caching

A DiagService represents a MCDDiagComPrimitive (MCDDiagComPrimitive in case of a MVCI-Server) of an MCDLogicalLink. It contains request and response parameters and can be executed synchronously or asynchronously to the ECU.

  1. DiagService Lifetime

In addition, the following diagnostic runtime system-specific topics influence the runtime behavior and should therefore be considered:

  1. Communication Modes (Multiple VCIs)
  2. Functional Addressing
  3. ComChannel Limitation

ComChannel Lifetime - Creation

A ComChannel can be created in the following different ways:

  1. DiagCom.GetComChannel
  2. DiagComPlus.CreateComChannel
  3. ComInterface.GetComChannelFromComInterface
  4. ComInterface.CreateComChannelFromComInterface

Note: Inside the DiagManager a ComChannel is assigned to a LogicalLink. Multiple ComChannel instances, which can be also inside multiple DiagManager clients, can be assigned to the same LogicalLink. Inside the DiagManager each LogicalLink has one CommandThread. Each command inside the CommandThread will be executed command by command.

GetComChannel

Syntax:

DiagCom.ComChannel DiagCom.GetComChannel(String identifier, String ecuVariantName, Boolean performVariantSelection);

The term GetComChannel creates a ComChannel for the passed combination of identifier and ecuVariantName. If the current variant is to be identified, communication with the ECU is also started and the ECU variant is identified and selected. The following pseudo-code describes the simplified behavior.

Note: Perform-Variant-Selection (PVS) practically means that the BaseVariant or EcuVariant is generated first and then a special diagnosis service is called. The ComChannel can then change its selected variant.

1 // Pseudo Code, to show the GetComChannel behaviour (simplified)
2 // =============================================================
3 
4 LogicalLink GetComChannel(string identifier, string ecuVariantName, bool performVariantSelection)
5 {
6  Project project = this.GetActiveProject();
7  if (project == null)
8  {
9  throw new DiagComException("Please LoadDbProject first!");
10  }
11 
12  LogicalLink logicalLink = null;
13  if (ecuVariantName == null || ecuVariantName == "")
14  {
15  logicalLink = project.CreateLogicalLinkByName(identifier);
16  }
17  else
18  {
19  logicalLink = project.CreateLogicalLinkByVariant(identifier, ecuVariantName);
20  }
21 
22  if (logicalLink == null)
23  {
24  throw new DiagComException("The created logical link is wrong (Invalid Object)");
25  }
26 
27  if (performVariantSelection)
28  {
29  try
30  {
31  IdentifyAndSelectVariant(logicalLink);
32  }
33  catch (DiagComException e)
34  {
35  ReleaseLogicalLink(logicalLink);
36  logicalLink.Close();
37  throw e;
38  }
39  }
40 
41  return logicalLink;
42 }
43 
44 void IdentifyAndSelectVariant(LogicalLink logicalLink)
45 {
46  StartCommunication(logicalLink);
47 
48  DiagComPrimitive diagcom = logicalLink.CreateDiagComPrimitiveByType(ObjectType.MCDVARIANTIDENTIFICATIONANDSELECTION);
49  if (diagcom != null)
50  {
51  Result result = diagcom->ExecuteSync();
52  if (result == null)
53  {
54  throw new LossOfComException("Exception occurred during the variant identification process: Invalid Result object (NULL)");
55  }
56 
57  if (result.HasError())
58  {
59  Error error = result.GetError();
60  throw new LossOfComException(result.GetServiceShortName() + " " + error.GetVendorCodeDescription());
61  }
62  }
63  else
64  {
65  throw new LossOfComException("Exception occurred during the variant identification process.");
66  }
67 }
68 
69 void StartCommunication(LogicalLink logicalLink)
70 {
71  string errorMsg;
72 
73  logicalLink.StartCommunication(errorMsg);
74 
75  if (!errorMsg.IsEmpty())
76  {
77  throw new LossOfComException(errorMsg);
78  }
79 }
@ Error
Messages with severity ERROR or above will be logged (this is the default setting)....

CreateComChannel

Syntax:

DiagCom.ComChannel DiagComPlus.CreateComChannel(String identifier, String ecuVariantName);

The term CreateComChannel creates a ComChannel for the passed combination of identifier and ecuVariantName.

Note: The behavior is the same as GetComChannel with performVariantSelection = false.

Note: The ComChannel will be only created. No communication with the ECU was started.

GetComChannelFromComInterface

Syntax:

DiagCom.ComChannel ComInterface.GetComChannelFromComInterface(ComInterface.ComInterface comInterface, String identifier, String ecuVariantName, Boolean performVariantSelection);

The term GetComChannelFromComInterface creates a ComChannel for the passed combination of identifier and ecuVariantName at he given ComInterface. If the current variant is to be identified, communication with the ECU is also started and the ECU variant is identified and selected.

Note: The behavior is the same as with GetComChannel, except that the given interface is used.

CreateComChannelFromComInterface

Syntax:

DiagCom.ComChannel ComInterface.CreateComChannelFromComInterface(ComInterface.ComInterface comInterface, String identifier, String ecuVariantName);

The term CreateComChannelFromComInterface creates a ComChannel for the passed combination of identifier and ecuVariantName at he given ComInterface.

Note: The behavior is the same as with CreateComChannel, except that the given interface is used.

Explicit vs. Implicit Creation

A communication channel can be created implicitly or explicitly. With implicit creation, the communication channel is created within another term and is therefore not assigned to an explicit ComChannel declaration. In the following example, the DiagService is generated implicitly with the term CreateDiagServiceByName to send a diagnostic service via ExecuteDiagService. This in turn generates the necessary ComChannel implicitly via GetComChannel.

// Implicit ComChannel and DiagService creation
DiagCom.ExecuteDiagService(DiagCom.CreateDiagServiceByName(DiagCom.GetComChannel("Identifier1","",false), "DiagnServiceName1"), ...);

Both DiagService and ComChannel only exist temporarily as they are not assigned to any declaration. When it is created explicitly, the communication channel is assigned to a ComChannel declaration, which can then be used further, see example:

// Explicit ComChannel and DiagService creation
DiagCom.ComChannel comChannel = DiagCom.GetComChannel("Identifier1", NULL, true);
DiagCom.DiagService diagService = DiagCom.CreateDiagServiceByName(comChannel, "DiagnServiceName1"));
DiagCom.ExecuteDiagService(diagService, ...);

Created DiagService objects are not cached. In contrast to this, created ComChannel objects are always cached, see ComChannel Lifetime - Caching. This means that an implicitly created ComChannel is not deleted or closed in DiagManager. This must be done explicitly, see ComChannel Lifetime - Closing.

Note: No matter how many times the same ComChannel is created explicitly or implicitly and not closed, it always returns the same ComChannel. But the content of this ComChannel can be different, see table in Subsequent ComChannel Creation.

Important: Creating a DiagService, explicitly or implicitly, always creates a new instance. Since this has an impact on memory and performance, only the necessary instances should be created for memory and performance-critical applications.

ComChannel Lifetime - Closing

An opened ComChannel will be closed immediately in the following cases:

  1. When calling CloseComChannel
  2. When changing the project, see SelectProject
  3. When calling CloseVciConnection

Any unclosed CloseComChannel is implicitly closed in the following cases:

  1. When changing to another communication mode, see Communication Modes (Multiple VCIs)
  2. When closing DiagManager

Important: A call of CloseComChannel closes the assigned LogicalLink, independent if multiple clients use the same LogicalLink! If an other client tries to use the already closed LogicalLink, an UnknownTargetException will thrown.

Important: Closing a ComChannel releases all still open DiagServices associated with that ComChannel.

Note (For experts only): If the OTX-Runtime API is used an explicit or implicit created DiagService will be released automatically if the scope of the DiagService inside OTX was lost. If the OTX-DiagManager API is used outside the OTX-Runtime API a DiagService can be released by a call of ReleaseDiagService (C++ only).

ComChannel Lifetime - Caching

Creating communication channels (ComChannel) takes time. Especially when a variant detection is to be carried out. Also, the author of an OTX sequence wants to use only one communication channel and not care about the lifetime of the communication channels. Therefore, open communication channels are cached.

Important: It is recommended to create each ComChannel with PVS (Perform-Variant-Selection).

// The recommended default case to create a ComChannel
GetComChannel("Identifier1", NULL, true);

Note: If PVS is used, EcuVariantName makes no sense. This is checked using the checker rule DiagCom_Chk201 "GetComChannel EcuVariantName must be omitted in PVS".

ComChannel First Creation

The table below shows the behavior of GetComChannel when GetComChannel is called for the first time. Identifier1 corresponds to the SHORT-NAME of the relevant MCDLogicalLink, for example "LL_Gateway". EcuVariantName1 and EcuVariantName2 are the SHORT-NAME of the MCDDbEcuVariant of the relevant MCDLogicalLink, for example "EV_GatewaySupplier1_001". PVS means PerformVariantSelection and is a parameter of GetComChannel.

Note: EcuVariantName2 is the actual ECU variant.

Note: An error in variant identification always throws a LossOfComException.

Note: Row 8 is the default case in the OTX Development Environment.

No Identifier EcuVariantName PVS Result
1 not exists - - UnknownTargetException
2 Identifier1 not exists - UnknownTargetException
3 Identifier1 Empty String false BaseVariant
4 Identifier1 NULL false BaseVariant
5 Identifier1 EcuVariantName2 false EcuVariantName2
6 Identifier1 EcuVariantName1 false EcuVariantName1
7 Identifier1 Empty String true EcuVariantName2
8 Identifier1 NULL true EcuVariantName2
9 Identifier1 EcuVariantName2 true EcuVariantName2
10 Identifier1 EcuVariantName1 true EcuVariantName2

Subsequent ComChannel Creation

The behavior for each further creation of the same GetComChannel depends on the ComChannel created first and is described in the following table.

Note: Many combinations make no technical sense and throw a DiagComException.

Note: If an exception occurs with GetComChannel, this has no effect on a previously created ComChannel.

Note: Row 46 is the default case in the OTX Development Environment.

No. Identifier 1. EcuVariantName 1. PVS 1. Result 2. EcuVariantName 2. PVS 2. Result
01 Identifier1 Empty String false BaseVariant Empty String false BaseVariant
02 NULL BaseVariant BaseVariant
03 EcuVariantName2 EcuVariantName2 DiagComException
04 EcuVariantName1 EcuVariantName1 DiagComException
05 Empty String true EcuVariantName2 DiagComException
06 NULL EcuVariantName2 DiagComException
07 EcuVariantName2 EcuVariantName2 DiagComException
08 EcuVariantName1 EcuVariantName2 DiagComException
09 Empty String false BaseVariant NULL BaseVariant
10 NULL BaseVariant BaseVariant
11 EcuVariantName2 EcuVariantName2 EcuVariantName2
12 EcuVariantName1 EcuVariantName1 EcuVariantName1
13 Empty String true EcuVariantName2 EcuVariantName2
14 NULL EcuVariantName2 EcuVariantName2
15 EcuVariantName2 EcuVariantName2 EcuVariantName2
16 EcuVariantName1 EcuVariantName2 EcuVariantName2
17 Empty String false BaseVariant EcuVariantName2 DiagComException
18 NULL BaseVariant DiagComException
19 EcuVariantName2 EcuVariantName2 EcuVariantName2
20 EcuVariantName1 EcuVariantName1 DiagComException
21 Empty String true EcuVariantName2 DiagComException
22 NULL EcuVariantName2 DiagComException
23 EcuVariantName2 EcuVariantName2 DiagComException
24 EcuVariantName1 EcuVariantName2 DiagComException
25 Empty String false BaseVariant EcuVariantName1 DiagComException
26 NULL BaseVariant DiagComException
27 EcuVariantName2 EcuVariantName2 DiagComException
28 EcuVariantName1 EcuVariantName1 EcuVariantName1
29 Empty String true EcuVariantName2 DiagComException
30 NULL EcuVariantName2 DiagComException
31 EcuVariantName2 EcuVariantName2 DiagComException
32 EcuVariantName1 EcuVariantName2 DiagComException
33 Empty String false BaseVariant Empty String true DiagComException
34 NULL BaseVariant DiagComException
35 EcuVariantName2 EcuVariantName2 DiagComException
36 EcuVariantName1 EcuVariantName1 DiagComException
37 Empty String true EcuVariantName2 DiagComException
38 NULL EcuVariantName2 DiagComException
39 EcuVariantName2 EcuVariantName2 DiagComException
40 EcuVariantName1 EcuVariantName2 DiagComException
41 Empty String false BaseVariant NULL EcuVariantName2
42 NULL BaseVariant EcuVariantName2
43 EcuVariantName2 EcuVariantName2 EcuVariantName2
44 EcuVariantName1 EcuVariantName1 EcuVariantName2
45 Empty String true EcuVariantName2 EcuVariantName2
46 NULL EcuVariantName2 EcuVariantName2
47 EcuVariantName2 EcuVariantName2 EcuVariantName2
48 EcuVariantName1 EcuVariantName2 EcuVariantName2
49 Empty String false BaseVariant EcuVariantName2 DiagComException
50 NULL BaseVariant DiagComException
51 EcuVariantName2 EcuVariantName2 DiagComException
52 EcuVariantName1 EcuVariantName1 DiagComException
53 Empty String true EcuVariantName2 DiagComException
54 NULL EcuVariantName2 DiagComException
55 EcuVariantName2 EcuVariantName2 DiagComException
56 EcuVariantName1 EcuVariantName2 DiagComException
57 Empty String false BaseVariant EcuVariantName1 DiagComException
58 NULL BaseVariant DiagComException
59 EcuVariantName2 EcuVariantName2 DiagComException
60 EcuVariantName1 EcuVariantName1 DiagComException
51 Empty String true EcuVariantName2 DiagComException
62 NULL EcuVariantName2 DiagComException
63 EcuVariantName2 EcuVariantName2 DiagComException
64 EcuVariantName1 EcuVariantName2 DiagComException

DiagService Lifetime

A DiagService represents a MCDDiagComPrimitive (MCDDiagComPrimitive in case of a MVCI-Server) of an MCDLogicalLink. It contains request and response parameters and can be executed synchronously or asynchronously to the ECU.

A DiagService can be explicit created using the following methods. Each call creates a new DiagService object.

  1. CreateDiagServiceByName
  2. CreateDiagServiceBySemantic

Note: A DiagService can be also implicit created, e.g. by calling the method GetComChannel with performVariantSelection is true.

Depending on its content, each DiagService object occupies a considerable amount of memory. The used memory should be released as follows:

Implicit:

The DiagService object is removed implicitly when the last remaining shared pointer owning the DiagService object is removed.

// Declares DiagService shared pointer
// Creates 1 reference of the DiagService
diagService = OpenTestSystem.Otx.DiagManager.OtxDiagApi.IDiagCom.CreateDiagServiceByName(comChannel, diagServiceName);
// 0 references -> ReleaseDiagService (see below) will be called implicitly
diagService = NULL;
Identical to a datatype in the OTX standard ISO 13209. A detailed specification can be found there.
Definition: IDiagService.cs:13
The class is identical to an extension in OTX standard ISO 13209. A detailed specification can be fou...
Definition: IDiagCom.cs:26
IDiagService CreateDiagServiceByName(IComChannel comChannel, string name)
Identical to an action or term in the OTX standard ISO 13209. A detailed specification can be found t...
Namespace containing all exceptions
Namespace covering all actions and terms of all diagnostic related OTX extension by an identical meth...
Namespace containing all objects for the communication to various, interchangeable diagnostic runtime...
Namespace containing all objects which are standardized according to ISO 13209 (OTX)
Namespace containing all objects related to testing inside automotive industry

Explicit:

The DiagService object is removed explicitly by calling one of the following methods:

Method Which DiagService will be released?
ReleaseDiagService (C++ only) The given DiagService
CloseComChannel All DiagServices related to the given ComChannel
DeselectProject All DiagServices
UnprepareInterface All DiagServices
UnprepareVciAccessLayer All DiagServices
CloseVciConnection All DiagServices
ResetDiagRuntimeSystem All DiagServices
CloseAllComChannels (C++ only) All DiagServices

Note: The OTX runtime manages the generated DiagService objects automatically. After executing a procedure, all DiagService objects generated by this procedure that have not already been cleaned up by CloseComChannel are removed.

Communication Modes (Multiple VCIs)

A diagnostic runtime system according to ISO 22900 (MVCI) supports two communication modes:

  1. Simple mode (MCDSystem::prepareInterface) and
  2. Extended mode (MCDSystem::prepareVciAccessLayer).

In simple mode there is only one general VCI available. In extended mode there can be multiple VCIs. Both communication modes are mutually exclusive. So it can only be communicated in one. In order to communicate in another, the existing mode must be terminated beforehand.

Important: The DiagManager always starts with the simple communication mode.

Note: The simple mode is significantly faster when establishing and terminating a connection than the extended mode.

All actions and terms of the OTX extensions supported in DiagManager can be executed in the extended communication mode. Some actions and terms of the ComInterface extension can only be executed in the extended communication mode. They therefore require a change to the extended mode.

If the DiagManager is in the normal communication mode, the following terms of the ComInterface extension switch to the extended communication mode:

  1. GetComInterface
  2. GetComInterfaceNameList
  3. GetComInterfaceNameListFromEthernet
  4. GetDefaultComInterfaceName

Note: Simple mode is sufficient for normal diagnostic communication. As soon as you want to communicate via the ComInterface extension or via DoIP, the extended mode is required.

Important: When changing to another communication mode, all open ComChannel must be closed, see ComChannel Lifetime - Closing. If necessary, previously opened ComChannel and DiagService are automatically reopened or created so that the application does not notice anything. The only exception are dynamically set request parameters of a DiagService. These are currently not restored when switching from simple to extended mode.

Functional Addressing

With physical addressing, exactly one ECU responds to a request, see ExecuteDiagService. With functional addressing, more than one ECU can respond. The result of ExecuteDiagService can then contain more than one response.

Note: From the point of view of OTX, apart from the number of responses, there is no difference between physical and functional addressing in the runtime behavior described here.

Note: With inline mapping of ExecuteDiagService, in case of functional addressing only the first response is mapped. All other responses must be evaluated via "dynamic response", see ExecuteDiagService.

Note: The term GetComChannelIdentifierFromResponse can be used to retrieve information about various responding ECUs.

ComChannel Limitation

The DiagManager is designed to support the execution of several OTX processes at the same time. Even if each individual process would work without problems on its own, parallel execution can lead to a system overload because too many ComChannels are open at the same time. It does not matter which component of the system causes the overload. Possible components include the VCI or the control units in the vehicle. Gateway control units in particular are possible causes here.

In order to prevent a system overload, it is possible to specify a maximum number of ComChannels that can be opened simultaneously for the CommandProcessor. If this limit is exceeded, the CommandProcessor automatically begins to close open ComChannels if they are not currently being used. If an implicitly closed ComChannel is later accessed again by the diagnostic application, the ComChannel is automatically reopened and, if necessary, another ComChannel is closed for it.

Closing a ComChannel also invalidates all DiagService handles that were previously created for it. If the diagnostic application accesses the handle again later, the DiagService must also be recreated. It receives a new handle. In order for the diagnostic application to continue working with the originally assigned handle, the DiagService handles must be translated.

Important: The ComChannel limitation can significantly reduce performance and should only switched ON if it is really necessary! Per default the ComChannel limitation is switched OFF.

How ​MaxChannels and DiagServiceHandleMapping work

By default, there is no limit to the number of ComChannels that can be opened simultaneously. This means that as many ComChannels as the diagnostic application requests are opened. The diagnostic application itself is responsible for knowing and taking into account any restrictions that may exist.

Because in this case ComChannels are not closed automatically, DiagServiceHandleMapping is also not required, because the handles of the DiagServices do not become invalid as long as the diagnostic application does not close them.

However, if a maximum number of simultaneously opened ComChannels is specified, then the DiagServiceHandleMapping is usually also required.

Procedure for specifying a maximum number of simultaneously opened ComChannels

Within the CommandProcessor, the ComChannelManager component is responsible for managing the ComChannels. Relevant methods:

  • SetMaxChannels
  • GetMaxChannels
  • StartDiagServiceHandleMapping

The ComChannelManager is part of the CommandDispatcher, and the @ç CommandDispatcher is in turn part of the CommandProcessor. The procedure for creating the @ç CommandProcessor to set an upper limit of 8 channels could therefore look like this:

auto commandDispatcher = std::make_unique<CommandDispatcher>();
auto* comChannelManager = commandDispatcher->GetComChannelManager();
comChannelManager->SetMaxChannels(8);
auto* commandProcessor = new CommandProcessor();
commandProcessor->SetCommandDispatcher(commandDispatcher);
commandProcessor->StartDiagServiceHandleMapping();

Note: Currently, it is not possible to query the CommandDispatcher used from the outside at the CommandProcessor. Therefore, to access the ComChannelManager, a new CommandDispatcher must be created and set using the @ç SetCommandDispatcher method. The SetComamndDispatcher method is therefore mandatory for this feature.