Component reuse is a common use case in any type of software and this is particularly true in automotive applications. Consider the equipment in the cars such as wheels, seats, doors, lights, clutches (e.g., in a dual-clutch transmission), and so on. They are controlled by software and as they exist by pairs, it makes sense to repeat their control algorithm. Indeed, the code can be developed once, instantiated as many times as needed and parametrized. This also contributes to an efficient ROM usage.
First of all, I want to give a warm thank to Hriday Ranjan, Modeling Lead at Ford Motor Company in the United States who inspired me writing this blog article. His team develops AUTOSAR software components in model-based which contains reusable code. They use BTC EmbeddedPlatform to test the software. We discussed three possible approaches to develop reusable code as well as their pro and cons arguments. I’m happy to summarize our discussion outcomes as follow:
Approach #1: Define a multi-instance Software Component in the AUTOSAR (Classic) architecture.
To reuse code in several components of the same type, AUTOSAR provides a multi-instance concept for the Software Components. For example, an Application Software Component of a window lifter can implement the functionality and be instantiated four times in the ECU. In the AUTOSAR description, this is specified with the attribute SUPPORTS-MULTIPLE-INSTANTIATION of the component “Internal Behavior”. The instantiated components share the same code but separate memory (RAM) for the internal states. The internal states are typically handled as AUTOSAR PerInstanceMemory (PIM). When coding the function manually, the developer shall take care of a proper management of the PIMs. In model-based development, the code generator automatically converts the state variables into PerInstanceMemories.
The port interfaces (e.g., sender/receiver) of the component instances have to access instance specific data. Therefore, the runnable functions as well as the RTE API calls use an additional function argument to manage the instance specific data.
With this approach, the entire software component is reusable. The reusability is specified in the AUTOSAR description and the RTE takes care of the implementation and the handling of the instances. However, some challenges must be considered. Shifting the definition of all repeatable code at the component level could increase their number and complexify the AUTOSAR architecture work. The internal states of the algorithms have to be managed via PerInstanceMemories which either have to be anticipated or fed back to the AUTOSAR ARXMLs after implementing the component. Testing the component requires to handle the additional instance specific parameters of the runnable and the RTE functions.
Approach #2: Use AUTOSAR Client/Server interface to define the reusable code a Server function and call it in many Clients.
A Client/Server (C/S) communication is a mechanism based on function definition and function call. The reusable code can be defined as an Operation of a Client/Server interface. It can have as many input and output variables as needed, configured as Operation arguments. A Server component can reference the C/S interface and implement the algorithm. The server component can define additional calibration parameters if needed. Then several client components can reference the C/S interface to call the operation. In the example of the window lifter, this would result in:
- 1 server component implementing the reusable code as a server function
- 4 client components (one for each door) calling the server function.
With this second approach, the “reusable” component is defined (again) in the AUTOSAR description and the relationship with the client components is documented thanks to the C/S interface. The integration between the server and the client components is managed in the RTE. During the development, the server component can be implemented and tested once. The implementation of the client components includes the call to the server operation and can add additional client-specific functionally around the call when this is needed. Testing the client component requires that a stub implementation of the server is part of the simulation environment. Depending on the development environment, this is more or less easily handled. One challenge with this C/S approach is the management of internal states. The server function cannot manage the states for the clients. If this is required, the state variables have to be handled in the client implementation and exchanged with the server function via arguments of the type “INOUT”.
Approach #3: Manage the reusable code as a traditional non-AUTOSAR reusable function
In this scenario, we consider that one Application Software Component is implementing the reusable code as a subfunction. The subfunction is defined as a regular C function called inside the component. With the window lifter example, a single software component can control the four windows by calling the same subfunction four times.
In model-based environment, this is supported with Reusable Subsystems. The configuration starts by defining a library block configured to generate a reusable function. Several information can be configured such as the function name, the function input/output arguments and the definition files. Then, the block is instantiated as many times as needed in the component model.
The management of internal states is much easier. In fact, during code generation, the state variables of each instance are automatically combined in a structure and passed as pointer argument to the reusable function. The developer effort to manage internal states is almost null compared to the first two AUTOSAR mechanisms. Calibration parameters can be defined in the reusable function or if they are specific to each instance, they can be passed as function arguments.
The traditional non-AUTOSAR reusable function can even be extended to share the code across several software components. This simply requires to manage a modular and independent file structure. The reusable subsystem can declare the function in a specific header file which gets included in each component source file and define the function in its own c-file. While generating code for each component, the reusable subsystem files could be regenerated each time but since their content would be identical (coming from the same library block), only one set of the files can be kept and archived for the final integration. An alternative workflow could be to generate the reusable function from a separate model and the software component models integrate it as external code.
In general, the traditional non-AUTOSAR reusable function is very flexible. The downside is that it cannot be specified with native AUTOSAR elements plus, we have to be aware of potential naming conflicts, which are normally avoided by the AUTOSAR naming scheme for functions and variables.
The component model has to be designed with the inner reusable subsystems in mind. In practice, I can recommend to start developing the model as if there was only on instance of the reusable subsystem and once the algorithm is matured, convert it as a library and create the other instances. During testing, a unit test can be conducted on one instance of the function and to test the behavior of the all instances combined, an integration test can be performed on the component level.
Conclusion
In conclusion, several approaches are available to address reusable code in AUTOSAR components. From an approach which is fully handled in AUTOSAR with the multi-instance concept to the one where the reusable function is managed with traditional methods inside the development environment, the project can decide which one fits the best. Configuring everything in AUTOSAR reinforces the architecture definition but reduces the flexibility as any architecture update would require updating the AUTOSAR description, plus the management of internal states can become a challenge. However, the flexibility of the traditional method really depends on how flexible the development environment can manage the modularity and the independencies between the source files.
Thank you again Hriday Ranjan for the interesting discussions!