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 |