LCOV - code coverage report
Current view: top level - firmware/hw_layer - pin_repository.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 33 42 78.6 %
Date: 2024-07-27 03:14:29 Functions: 8 9 88.9 %

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

Generated by: LCOV version 1.14