GCC Code Coverage Report


Directory: ./
File: firmware/hw_layer/pin_repository.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 62.5% 25 0 40
Functions: 77.8% 7 0 9
Branches: 45.0% 9 0 20
Decisions: 57.1% 8 - 14

Line Branch Decision Exec Source
1 /**
2 * @file pin_repository.cpp
3 * @brief I/O pin registry code
4 *
5 * This job of this class is to make sure that we are not using same hardware pin for two
6 * different purposes.
7 *
8 * @date Jan 15, 2013
9 * @author Andrey Belomutskiy, (c) 2012-2020
10 */
11
12 #include "pch.h"
13
14 PinRepository pinRepository CCM_OPTIONAL;
15
16 2 static size_t getBrainPinTotalNum() {
17 2 return BRAIN_PIN_TOTAL_PINS;
18 }
19
20 2 const char* & getBrainUsedPin(size_t index) {
21 2 return pinRepository.getBrainUsedPin(index);
22 }
23
24 /* Common for firmware and unit tests */
25 62767 bool isBrainPinValid(brain_pin_e brainPin) {
26
3/4
✓ Branch 0 taken 2071 times.
✓ Branch 1 taken 60696 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2071 times.
2/2
✓ Decision 'true' taken 60696 times.
✓ Decision 'false' taken 2071 times.
62767 if ((brainPin == Gpio::Unassigned) || (brainPin == Gpio::Invalid))
27 60696 return false;
28
29
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2071 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2071 times.
2071 if (brainPin > BRAIN_PIN_LAST)
30 /* something terribly wrong */
31 return false;
32
33 2071 return true;
34 }
35
36 1314 int brainPin_to_index(Gpio brainPin) {
37
2/2
✓ Branch 0 taken 1312 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 1312 times.
✓ Decision 'false' taken 2 times.
1314 if (brainPin < Gpio::A0)
38 1312 return -1;
39
40 2 size_t i = brainPin - Gpio::A0;
41
42
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
2 if (i >= getBrainPinTotalNum())
43 return -1;
44
45 2 return i;
46 }
47
48 /**
49 * See also brain_pin_markUnused()
50 * @return true if this pin was already used, false otherwise
51 */
52
53 bool brain_pin_markUsed(Gpio brainPin, const char *msg) {
54 #ifndef EFI_BOOTLOADER
55 // efiPrintf("pin_markUsed: %s on %s", msg, hwPortname(brainPin));
56 #endif
57
58 int index = brainPin_to_index(brainPin);
59 if (index < 0)
60 return true;
61
62 if (pinRepository.getBrainUsedPin(index) != nullptr) {
63 // hwPortname and share a buffer behind the scenes, even while they probably never use it for different
64 // values here let's have an explicit second buffer to make this more reliable
65 char physicalPinName[32];
66 strncpy(physicalPinName, hwPhysicalPinName(brainPin), sizeof(physicalPinName) - 1);
67 criticalError("Pin \"%s\" (%s) required by \"%s\" but is used by \"%s\"",
68 hwPortname(brainPin),
69 physicalPinName,
70 msg,
71 getBrainUsedPin(index));
72 return true;
73 }
74
75 getBrainUsedPin(index) = msg;
76 return false;
77 }
78
79 /**
80 * See also brain_pin_markUsed()
81 */
82
83 1314 void brain_pin_markUnused(brain_pin_e brainPin) {
84 #ifndef EFI_BOOTLOADER
85 // efiPrintf("pin_markUnused: %s", hwPortname(brainPin));
86 #endif
87 1314 int index = brainPin_to_index(brainPin);
88
2/2
✓ Branch 0 taken 1312 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 1312 times.
✓ Decision 'false' taken 2 times.
1314 if (index < 0)
89 1312 return;
90
91 2 getBrainUsedPin(index) = nullptr;
92 }
93
94 #if EFI_PROD_CODE
95 #include "memstreams.h"
96 static MemoryStream portNameStream;
97 static char portNameBuffer[20];
98 #endif /* EFI_PROD_CODE */
99
100 584 PinRepository::PinRepository() {
101 #if EFI_PROD_CODE
102 msObjectInit(&portNameStream, (uint8_t*) portNameBuffer, sizeof(portNameBuffer), 0);
103 #endif /* EFI_PROD_CODE */
104
105 584 memset(PIN_USED, 0, sizeof(PIN_USED));
106 584 }
107
108 #if EFI_PROD_CODE
109
110 #include "eficonsole.h"
111 #include "drivers/gpio/gpio_ext.h"
112 #include "smart_gpio.h"
113 #include "hardware.h"
114
115 void pinDiag2string(char *buffer, size_t size, brain_pin_diag_e pin_diag) {
116 /* use autogeneraged helpers here? */
117 if (pin_diag == PIN_OK) {
118 chsnprintf(buffer, size, "Ok");
119 } else if (pin_diag != PIN_UNKNOWN) {
120 chsnprintf(buffer, size, "%s%s%s%s%s%s",
121 pin_diag & PIN_DRIVER_OFF ? "driver_off " : "",
122 pin_diag & PIN_OPEN ? "open_load " : "",
123 pin_diag & PIN_SHORT_TO_GND ? "short_to_gnd " : "",
124 pin_diag & PIN_SHORT_TO_BAT ? "short_to_bat " : "",
125 pin_diag & PIN_OVERLOAD ? "overload " : "",
126 pin_diag & PIN_DRIVER_OVERTEMP ? "overtemp": "");
127 } else {
128 chsnprintf(buffer, size, "INVALID");
129 }
130 }
131
132 static brain_pin_e index_to_brainPin(unsigned int i)
133 {
134 if (i < getBrainPinTotalNum())
135 return Gpio::A0 + i;
136
137 return Gpio::Invalid;
138 }
139
140 static void reportPins() {
141 int totalPinsUsed = 0;
142
143 for (unsigned int i = 0; i < getBrainPinOnchipNum(); i++) {
144 const char *pin_user = getBrainUsedPin(i);
145
146 /* show used pins */
147 if (pin_user) {
148 static char pin_state[64];
149 brain_pin_e brainPin = index_to_brainPin(i);
150 int pin = getBrainPinIndex(brainPin);
151 ioportid_t port = getBrainPinPort(brainPin);
152 debugBrainPin(pin_state, sizeof(pin_state), brainPin);
153
154 const char *boardPinName = getBoardSpecificPinName(brainPin);
155 efiPrintf("pin %s%d (%s): %s %s", portname(port), pin, boardPinName, pin_user, pin_state);
156 totalPinsUsed++;
157 }
158 }
159
160 #if (BOARD_EXT_GPIOCHIPS > 0)
161 for (unsigned int i = getBrainPinOnchipNum() ; i < getBrainPinTotalNum(); i++) {
162 static char pin_error[64];
163 brain_pin_e brainPin = index_to_brainPin(i);
164
165 const char *pin_name = gpiochips_getPinName(brainPin);
166 const char *pin_user = getBrainUsedPin(i);
167 brain_pin_diag_e pin_diag = gpiochips_getDiag(brainPin);
168
169 pinDiag2string(pin_error, sizeof(pin_error), pin_diag);
170
171 /* here show all pins, unused too */
172 if (pin_name) {
173 // this probably uses a lot of output buffer!
174 efiPrintf("ext %s: %s diagnostic: %s",
175 pin_name, pin_user ? pin_user : "free", pin_error);
176 } else {
177 const char *chip_name = gpiochips_getChipName(brainPin);
178 /* if chip exist */
179 if (chip_name) {
180 efiPrintf("ext %s.%d: %s diagnostic: %s",
181 chip_name, gpiochips_getPinOffset(brainPin), pin_user ? pin_user : "free", pin_error);
182 }
183 }
184 if (pin_user) {
185 totalPinsUsed++;
186 }
187 }
188 #endif
189
190 efiPrintf("Total pins used: %d", totalPinsUsed);
191
192 gpiochips_debug();
193 }
194
195 __attribute__((weak)) const char * getBoardSpecificPinName(brain_pin_e /*brainPin*/) {
196 return nullptr;
197 }
198
199 const char *hwOnChipPhysicalPinName(ioportid_t hwPort, int hwPin) {
200 portNameStream.eos = 0; // reset
201 if (!hwPort) {
202 return "NONE";
203 }
204 chprintf((BaseSequentialStream *) &portNameStream, "%s%d", portname(hwPort), hwPin);
205 portNameStream.buffer[portNameStream.eos] = 0; // need to terminate explicitly
206 return portNameBuffer;
207 }
208
209 const char *hwPhysicalPinName(Gpio brainPin) {
210 if (brainPin == Gpio::Invalid) {
211 return "INVALID";
212 }
213 if (brainPin == Gpio::Unassigned) {
214 return "NONE";
215 }
216
217 if (brain_pin_is_onchip(brainPin)) {
218 ioportid_t hwPort = getHwPort("hostname", brainPin);
219 int hwPin = getHwPin("hostname", brainPin);
220 return hwOnChipPhysicalPinName(hwPort, hwPin);
221 }
222 #if (BOARD_EXT_GPIOCHIPS > 0)
223 else {
224 portNameStream.eos = 0; // reset
225 const char *pin_name = gpiochips_getPinName(brainPin);
226
227 if (pin_name) {
228 chprintf((BaseSequentialStream *) &portNameStream, "ext:%s",
229 pin_name);
230 } else {
231 chprintf((BaseSequentialStream *) &portNameStream, "ext:%s.%d",
232 gpiochips_getChipName(brainPin), gpiochips_getPinOffset(brainPin));
233 }
234 portNameStream.buffer[portNameStream.eos] = 0; // need to terminate explicitly
235 return portNameBuffer;
236 }
237 #endif
238 return "unexpected";
239 }
240
241 const char *hwPortname(brain_pin_e brainPin) {
242 const char * boardSpecificPinName = getBoardSpecificPinName(brainPin);
243 if (boardSpecificPinName != nullptr) {
244 return boardSpecificPinName;
245 }
246 return hwPhysicalPinName(brainPin);
247 }
248
249 void initPinRepository(void) {
250 /**
251 * this method cannot use console because this method is invoked before console is initialized
252 */
253
254 addConsoleAction(CMD_PINS, reportPins);
255
256 #if (BOARD_TLE8888_COUNT > 0)
257 addConsoleAction("tle8888", tle8888_dump_regs);
258 addConsoleAction("tle8888init", tle8888_req_init);
259 #endif
260 }
261
262 bool brain_pin_is_onchip(brain_pin_e brainPin)
263 {
264 if ((brainPin < Gpio::A0) || (brainPin > BRAIN_PIN_ONCHIP_LAST))
265 return false;
266
267 return true;
268 }
269
270 bool brain_pin_is_ext(brain_pin_e brainPin)
271 {
272 if (brainPin > BRAIN_PIN_ONCHIP_LAST)
273 return true;
274
275 return false;
276 }
277
278 /**
279 * Marks on-chip gpio port-pin as used. Works only for on-chip gpios
280 * To be replaced with brain_pin_markUsed later
281 */
282
283 bool gpio_pin_markUsed(ioportid_t port, ioportmask_t pin, const char *msg) {
284 int index = getPortPinIndex(port, pin);
285 #ifndef EFI_BOOTLOADER
286 // efiPrintf("pin_markUsed: %s on %s", msg, hwOnChipPhysicalPinName(port, pin));
287 #endif
288
289 if (getBrainUsedPin(index) != NULL) {
290 /**
291 * todo: the problem is that this warning happens before the console is even
292 * connected, so the warning is never displayed on the console and that's quite a problem!
293 */
294 // warning(ObdCode::OBD_PCM_Processor_Fault, "%s%d req by %s used by %s", portname(port), pin, msg, getBrainUsedPin(index));
295 firmwareError(ObdCode::CUSTOM_ERR_PIN_ALREADY_USED_1, "%s%d req by %s used by %s", portname(port), (int)pin, msg, getBrainUsedPin(index));
296 return true;
297 }
298 getBrainUsedPin(index) = msg;
299 return false;
300 }
301
302 /**
303 * Marks on-chip gpio port-pin as UNused. Works only for on-chip gpios
304 * To be replaced with brain_pin_markUnused later
305 */
306
307 void gpio_pin_markUnused(ioportid_t port, ioportmask_t pin) {
308 int index = getPortPinIndex(port, pin);
309
310 getBrainUsedPin(index) = nullptr;
311 }
312
313 const char *getPinFunction(brain_input_pin_e brainPin) {
314 int index;
315
316 index = brainPin_to_index(brainPin);
317 if (index < 0)
318 return NULL;
319
320 return getBrainUsedPin(index);
321 }
322 #else
323 const char *hwPhysicalPinName(Gpio brainPin) {
324 return "N/A";
325 }
326 8 const char *hwPortname(Gpio brainPin) {
327 (void)brainPin;
328 8 return "N/A";
329 }
330 #endif /* EFI_PROD_CODE */
331