Skip to content

Commit c1cdc1f

Browse files
committed
Improvements to language.
1 parent db0cffb commit c1cdc1f

1 file changed

Lines changed: 73 additions & 74 deletions

File tree

doc/decisions/dr-004.md

Lines changed: 73 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,67 @@
1-
# DR004 Direct usage of Hardware Abstraction Layer
1+
# DR004 Direct Usage of Hardware Abstraction Layer
22

33
## Context
44

5-
Currently we violate the requirement to use libraries and frameworks only through adapters, as it is required by the objectives of the software architecture (see
6-
[relevant section in Software Architecture](<\ref flexible_structure> "relevant section in Software Architecture")):
7-
We currently use an implementation of the [ArduinoCore-API][ACA] (ACA) as a hardware abstraction layer (HAL) from outside of the adapters layer.
8-
More specifically we use an implementation of the ACA from Espressif coined for ESP32s.
5+
Currently, we are in violation of the requirement to only use libraries and frameworks through adapters, as mandated by the objectives of the software architecture (see
6+
[relevant section in Software Architecture](<\ref flexible_structure> "relevant section in Software Architecture")).
7+
Currently, we utilize an implementation of the [ArduinoCore-API][ACA] (ACA) as a hardware abstraction layer (HAL) from outside the adapters layer.
8+
More specifically, we employ an implementation of the ACA from Espressif, tailored for ESP32s.
99

10-
It is generally assumed that using HALs is only necessary from the
10+
It is generally understood that using HALs is only necessary from the
1111
[board adapters package](<\ref board_adapters> "board adapters package").
1212

1313
[ACA]: https://github.com/arduino/ArduinoCore-API
1414

1515
## Options
1616

17-
There are several options on how to resolve this violation of our own rules.
17+
There are several options for resolving this violation of our own rules.
1818

1919
### Option 1
2020

21-
Abide to the current guidelines.
21+
Adhere to the current guidelines.
2222

23-
According to the current state of the software architecture we should use the 3rd party HAL indirectly through adapters.
24-
Those adapters would reside in the
23+
According to the current state of the software architecture, we should use the 3rd party HAL indirectly through adapters.
24+
These adapters would reside in the
2525
[3rd party adapters package](<\ref third_party_adapters> "3rd party adapters package").
2626

2727
#### Option 1a)
2828

29-
For an object oriented (OO) variant, defining an interface and inheriting from it would require to:
29+
For an object-oriented (OO) variant, defining an interface and inheriting from it would require:
3030

31-
- define one or several interfaces inside the
31+
- Defining one or several interfaces inside the
3232
[board adapters package](<\ref board_adapters> "board adapters package")
33-
(header files)
34-
- implement those as adapters inside the
33+
(header files).
34+
- Implementing those as adapters inside the
3535
[3rd party adapters package](<\ref third_party_adapters> "3rd party adapters package")
36-
(source files)
37-
- define interfaces for the factories (see
36+
(source files).
37+
- Defining interfaces for the factories (see
3838
[dependency injection](<\ref dependency_injection> "dependency injection"))
3939
inside the
4040
[board adapters package](<\ref board_adapters> "board adapters package")
41-
(header files)
42-
- implement those factories inside the
41+
(header files).
42+
- Implementing those factories inside the
4343
[3rd party adapters package](<\ref third_party_adapters> "3rd party adapters package")
44-
(source files)
44+
(source files).
4545

46-
This is the usual way dependency injection and therefore the
47-
[dependency rule](<\ref interpretation_dependency_rule> "dependency rule")
46+
This is the typical way dependency injection, and therefore the
47+
[dependency rule](<\ref interpretation_dependency_rule> "dependency rule"),
4848
is implemented.
4949

5050
#### Option 1b)
5151

52-
Instead of using an object oriented approach using inheritance, one could create an interface to the HAL based on free functions.
52+
Instead of using an object-oriented approach using inheritance, one could create an interface to the HAL based on free functions.
5353

54-
This option would require to:
54+
This option would require:
5555

56-
- define one or several interfaces (free function declarations) inside the
56+
- Defining one or several interfaces (free function declarations) inside the
5757
[board adapters package](<\ref board_adapters> "board adapters package")
58-
(header files)
59-
- implement those as adapters inside the
58+
(header files).
59+
- Implementing those as adapters inside the
6060
[3rd party adapters package](<\ref third_party_adapters> "3rd party adapters package")
61-
(source files)
62-
- if the build configuration (see [`lib_ldf_mode`][1]) requires it, one may have to define
61+
(source files).
62+
- If the build configuration (see [`lib_ldf_mode`][1]) requires it, one may have to define
6363
[proxy headers](<\ref proxy_header> "proxy headers")
64-
(header files)
64+
(header files).
6565

6666
Factories are not necessary because this approach does not rely on objects.
6767

@@ -70,110 +70,109 @@ Factories are not necessary because this approach does not rely on objects.
7070
#### Option 1c)
7171

7272
A hybrid approach (OO and free functions) is also possible.
73-
This would fit well to the ACA as is also consists of classes and free functions.
73+
This would fit well with the ACA as it also consists of classes and free functions.
7474

75-
The steps required would be a mixture of those of options 1a) and 1b).
75+
The required steps would be a mixture of those of options 1a) and 1b).
7676

7777
### Option 2
7878

79-
Change the current guidelines such that the direct dependency to 3rd party HALs is allowed within hardware related packages (which is currently only the
79+
Change the current guidelines so that direct dependency on 3rd party HALs is allowed within hardware-related packages (currently only the
8080
[board adapters package](<\ref board_adapters> "board adapters package")).
8181

82-
This approach eliminates the requirement to define 3rd party adapters to the HAL.
82+
This approach eliminates the requirement to define 3rd party adapters for the HAL.
8383

84-
In order to be able to test code depending on the ACA, the 3rd party interface needs to be stubbed.
84+
In order to test code depending on the ACA, the 3rd party interface needs to be stubbed.
8585
*For vanilla ACA, stubbing the proprietary interface can be greatly simplified by using [ArduinoFake][].*
86-
We use an [implementation of the Arduino Core API (ACA) specific for ESP32s by Espressif](https://github.com/espressif/arduino-esp32/) which extends the ACA.
87-
Following the approach of this option, to directly use ACA and ArduinoFake for testing, we would need to deal with the extensions separately.
88-
The following variants of this option, specifies different methods to cope with the extensions.
86+
We utilize an [implementation of the Arduino Core API (ACA) specific for ESP32s by Espressif](https://github.com/espressif/arduino-esp32/) which extends the ACA.
87+
Following this option's approach, to directly use ACA and ArduinoFake for testing, we would need to manage the extensions separately.
88+
The following variants of this option specify different methods to handle the extensions.
8989

9090
[ArduinoFake]: https://platformio.org/lib/show/1689/ArduinoFake "ArduinoFake in PlaftormIO's registry"
9191

9292
#### Option 2a)
9393

9494
Instead of directly using a modified Arduino interface provided by the extensions (for example for a specific `class`), we use an adapter.
9595
The adapters would be integrated just as for option 1.
96-
But compared to option 1 this only needs to be done for those smallest indivisible interfaces which are not compatible to the vanilla ACA.
96+
But compared to option 1, this only needs to be done for those smallest indivisible interfaces which are not compatible with the vanilla ACA.
9797

9898
#### Option 2b)
9999

100100
At those places in the source code where extensions are used, we introduce conditionally compiled sections.
101101
One section uses the modified version of the ACA, necessary for the productive code.
102-
The alternative section is instead used when compiling for native tests.
102+
The alternative section is used when compiling for native tests.
103103
It uses the vanilla ACA which can be simply stubbed using ArduinoFake.
104104

105105
The selection of conditionally compiled sections is done using `constexpr if`, where possible.
106-
Else the C preprocessor (CPP) is used for conditional inclusion (`#if`, ...).
106+
Else, the C preprocessor (CPP) is used for conditional inclusion (`#if`, ...).
107107

108108
## Comparison of Options
109109

110-
### Comparing variants Option 1a), b) and c)
110+
### Comparing variants Option 1a), b), and c)
111111

112-
Assuming that we do define interfaces for one or several HALs, we should not follow the structure of the currently used one just out of convenience (what option 1c) suggests).
113-
Because that would possibly complicate to write adapters for different HAL implementations.
114-
And allowing variants is one of the purposes of the adapters.
112+
Assuming that we do define interfaces for one or several HALs, we should not follow the structure of the currently used one just for convenience (as option 1c suggests).
113+
This could complicate writing adapters for different HAL implementations.
114+
Allowing variants is one of the purposes of the adapters.
115115

116-
Instead we should design the interfaces such that they fit the usage.
117-
In general an object oriented approach is sensible to represent the different peripheral components which are available through HALs.
118-
Also an object oriented approach is the most straightforward to implement dependency inversion.
116+
Instead, we should design the interfaces to fit the usage.
117+
In general, an object-oriented approach is sensible to represent the different peripheral components available through HALs.
118+
Also, an object-oriented approach is the most straightforward for implementing dependency inversion.
119119

120-
This from those variants, **option 1a)** would be the best.
120+
From these variants, **option 1a)** would be the best.
121121

122-
### Comparing Options 1a), 2a) and 2b)
122+
### Comparing Options 1a), 2a), and 2b)
123123

124124
- **Option 1a)**: Implement and use adapters for the complete 3rd party HAL(s)
125125
- Pros:
126-
- Clean separation of concerns, dependency inversion and injection.
127-
- Fits to the overall design to use dependency inversion in order to fulfill the
126+
- Clean separation of concerns, dependency inversion, and injection.
127+
- Fits the overall design to use dependency inversion to fulfill the
128128
[dependency rule](<\ref interpretation_dependency_rule> "dependency rule").
129-
- Using a different implementation of our - to be defined - HAL interface would not require to modify the users of our HAL interface.
130-
Instead only a different adapter - implementing our HAL interface - would be required.[¹](<\ref dr004_1 "¹")
129+
- Using a different implementation of our - to be defined - HAL interface would not require modifying the users of our HAL interface.
130+
Instead, only a different adapter - implementing our HAL interface - would be required.[¹](<\ref dr004_1 "¹")
131131
- Cons:
132-
- This approach requires to write adapters for all used HAL interfaces to 3rd party libraries.
133-
A reusable interface is difficult to design and the adapters may result in boilerplate code.
134-
Note, that this approach would mean to write adapters to a HAL implementation, which is an adapter (to proprietary peripheral drivers) in itself.
132+
- This approach requires writing adapters for all used HAL interfaces to 3rd party libraries.
133+
Designing a reusable interface is challenging, and the adapters may result in boilerplate code.
134+
Note that this approach would mean writing adapters to a HAL implementation, which is an adapter (to proprietary peripheral drivers) in itself.
135135
- **Option 2a)**: Use adapters only for extensions to vanilla ACA
136136
- Pros:
137137
- Compared to option 1a), only a fraction of the adapters would need to be written.
138138
- Cons:
139-
- Our board adapters would have a high degree of dependency to the ACA.
140-
The *Single Responsibility Principle* is violated[²](<\ref dr004_2 "²") as the board adapters would not only depend on the board and its hardware.
141-
But also on an interface of a 3rd party HAL.
142-
- To deal with the extensions made compared to vanilla ACA, some adapters need to be written.
143-
- Adapting a variation from the ACA in one member function of a class requires to create an interface containing all used member functions of that class.
144-
Even if those other member functions are used without alterations.
139+
- Our board adapters would have a high degree of dependency on the ACA.
140+
The *Single Responsibility Principle* is violated[²](<\ref dr004_2 "²") as the board adapters would not only depend on the board and its hardware but also on an interface of a 3rd party HAL.
141+
- Dealing with the extensions made compared to vanilla ACA requires writing some adapters.
142+
- Adapting a variation from the ACA in one member function of a class requires creating an interface containing all used member functions of that class, even if those other member functions are used without alterations.
145143
This introduces *boilerplate code*.
146144
- **Option 2b)**: Use alternative sections within source files
147145
- Pros:
148146
- Reduces the need for additional code to a minimum.
149147
No adapters need to be written to use the HAL.
150148
- Cons:
151-
- Our board adapters would have a high degree of dependency to the ACA.
152-
The *Single Responsibility Principle* is violated[²](<\ref dr004_2 "²") even further (compared to option 2a)) by depending on the vanilla ACA which is required for testing on the native build environment only.
149+
- Our board adapters would have a high degree of dependency on the ACA.
150+
The *Single Responsibility Principle* is violated[²](<\ref dr004_2 "²") even further (compared to option 2a)) by depending on the vanilla ACA required for testing in the native build environment only.
153151
Changes to the test infrastructure should not necessitate changes in the source file containing productive code.
154-
- In general conditionally compiled sections of code reduces its readability.
152+
- In general, conditionally compiled sections of code reduces its readability.
155153

156154
\note \anchor dr004_1
157-
¹: *In practice* our HAL interface may not be suitable to accommodate the new HAL implementation (see [Rule of Three](https://en.wikipedia.org/w/index.php%3Ftitle%3DRule_of_three_%28computer_programming%29%26oldid%3D1173684754)).
158-
Thus we would have to adjust our HAL interface and the code using it accordingly.
159-
In other words: It is difficult to design a HAL interface such that we would actually benefit when changing the HAL implementation to a different 3rd party library. Thus this advantage may not be relevant for that case.
160-
Also - in case the HAL implementation is changed - it may be less effort to adjust all the uses of the new HAL interface than to write adapters for the changed 3rd party library.
155+
¹: *In practice*, our HAL interface may not be suitable to accommodate the new HAL implementation (see [Rule of Three](https://en.wikipedia.org/w/index.php%3Ftitle%3DRule_of_three_%28computer_programming%29%26oldid%3D1173684754)).
156+
Thus, we would have to adjust our HAL interface and the code using it accordingly.
157+
In other words, it is difficult to design a HAL interface such that we would actually benefit when changing the HAL implementation to a different 3rd party library.
158+
Thus, this advantage may not be relevant for that case.
159+
Also, in case the HAL implementation is changed, it may be less effort to adjust all the uses of the new HAL interface than to write adapters for the changed 3rd party library.
161160

162161
\note \anchor dr004_2
163162
²: The source file (of a non-adapter) would depend on a 3rd party interface.
164-
Changes to that 3rd party interface may necessitate changes to the source file even though the requirements to that source files remain the same.
163+
Changes to that 3rd party interface may necessitate changes to the source file even though the requirements to that source file remain the same.
165164

166165
### Summary & Decision
167166

168-
Writing adapters adds additional effort, potentially boilerplate code and the advantage is dubious.
167+
Writing adapters adds additional effort, potentially resulting in boilerplate code, and the advantage is dubious.
169168

170169
After careful consideration, we've decided on:
171170

172-
> **Option 2:** Allow direct dependencies from hardware related code to 3rd party HAL interfaces.
171+
> **Option 2:** Allow direct dependencies from hardware-related code to 3rd party HAL interfaces.
173172
174173
And more specifically for testing on native environments, use:
175174

176-
> **Option 2b):** Where the ACA is used, it is allowed to add small conditionally compiled sections for tests in order to cope with deviations of the ACA used in productive code from the vanilla ACA.
175+
> **Option 2b):** Where the ACA is used, it is allowed to add small conditionally compiled sections for tests to cope with deviations of the ACA used in productive code from the vanilla ACA.
177176
178-
The latter relaxation is in order to facilitate the use of ArduinoFake to stub the HAL's interface.
177+
The latter relaxation is to facilitate the use of ArduinoFake to stub the HAL's interface.
179178

0 commit comments

Comments
 (0)