You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# DR004 Direct usage of Hardware Abstraction Layer
1
+
# DR004 Direct Usage of Hardware Abstraction Layer
2
2
3
3
## Context
4
4
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.
9
9
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
Factories are not necessary because this approach does not rely on objects.
67
67
@@ -70,110 +70,109 @@ Factories are not necessary because this approach does not rely on objects.
70
70
#### Option 1c)
71
71
72
72
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.
74
74
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).
76
76
77
77
### Option 2
78
78
79
-
Change the current guidelines such that the direct dependency to 3rd party HALs is allowed within hardwarerelated 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
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.
83
83
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.
85
85
*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.
89
89
90
90
[ArduinoFake]: https://platformio.org/lib/show/1689/ArduinoFake"ArduinoFake in PlaftormIO's registry"
91
91
92
92
#### Option 2a)
93
93
94
94
Instead of directly using a modified Arduino interface provided by the extensions (for example for a specific `class`), we use an adapter.
95
95
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.
97
97
98
98
#### Option 2b)
99
99
100
100
At those places in the source code where extensions are used, we introduce conditionally compiled sections.
101
101
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.
103
103
It uses the vanilla ACA which can be simply stubbed using ArduinoFake.
104
104
105
105
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`, ...).
107
107
108
108
## Comparison of Options
109
109
110
-
### Comparing variants Option 1a), b) and c)
110
+
### Comparing variants Option 1a), b), and c)
111
111
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.
115
115
116
-
Instead we should design the interfaces such that they fit the usage.
117
-
In general an objectoriented approach is sensible to represent the different peripheral components which are available through HALs.
118
-
Also an objectoriented 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.
119
119
120
-
This from those variants, **option 1a)** would be the best.
120
+
From these variants, **option 1a)** would be the best.
121
121
122
-
### Comparing Options 1a), 2a) and 2b)
122
+
### Comparing Options 1a), 2a), and 2b)
123
123
124
124
-**Option 1a)**: Implement and use adapters for the complete 3rd party HAL(s)
125
125
- 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
- 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 "¹")
131
131
- 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.
135
135
-**Option 2a)**: Use adapters only for extensions to vanilla ACA
136
136
- Pros:
137
137
- Compared to option 1a), only a fraction of the adapters would need to be written.
138
138
- 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.
145
143
This introduces *boilerplate code*.
146
144
-**Option 2b)**: Use alternative sections within source files
147
145
- Pros:
148
146
- Reduces the need for additional code to a minimum.
149
147
No adapters need to be written to use the HAL.
150
148
- 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.
153
151
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.
155
153
156
154
\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.
161
160
162
161
\note \anchor dr004_2
163
162
²: 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.
165
164
166
165
### Summary & Decision
167
166
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.
169
168
170
169
After careful consideration, we've decided on:
171
170
172
-
> **Option 2:** Allow direct dependencies from hardwarerelated code to 3rd party HAL interfaces.
171
+
> **Option 2:** Allow direct dependencies from hardware-related code to 3rd party HAL interfaces.
173
172
174
173
And more specifically for testing on native environments, use:
175
174
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.
177
176
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.
0 commit comments