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-04-25 02:23:43 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       56641 : bool isBrainPinValid(brain_pin_e brainPin) {
      24       56641 :         if ((brainPin == Gpio::Unassigned) || (brainPin == Gpio::Invalid))
      25       55223 :                 return false;
      26             : 
      27        1418 :         if (brainPin > BRAIN_PIN_LAST)
      28             :                 /* something terribly wrong */
      29           0 :                 return false;
      30             : 
      31        1418 :         return true;
      32             : }
      33             : 
      34        1045 : int brainPin_to_index(Gpio brainPin) {
      35        1045 :         if (brainPin < Gpio::A0)
      36        1025 :                 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             : #if ! 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        1030 : void brain_pin_markUnused(brain_pin_e brainPin) {
      82             : #if ! EFI_BOOTLOADER
      83        1030 :         efiPrintf("pin_markUnused: %s", hwPortname(brainPin));
      84             : #endif
      85        1030 :         int index = brainPin_to_index(brainPin);
      86        1030 :         if (index < 0)
      87        1025 :                 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         388 : PinRepository::PinRepository() {
      99             : #if EFI_PROD_CODE
     100             :         msObjectInit(&portNameStream, (uint8_t*) portNameBuffer, sizeof(portNameBuffer), 0);
     101             : #endif /* EFI_PROD_CODE */
     102             : 
     103         388 :         memset(PIN_USED, 0, sizeof(PIN_USED));
     104         388 : }
     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             :                         brain_pin_e brainPin = index_to_brainPin(i);
     147             :                         int pin = getBrainPinIndex(brainPin);
     148             :                         ioportid_t port = getBrainPinPort(brainPin);
     149             : 
     150             :             const char *boardPinName = getBoardSpecificPinName(brainPin);
     151             :                         efiPrintf("pin %s%d (%s): %s", portname(port), pin, boardPinName, pin_user);
     152             :                         totalPinsUsed++;
     153             :                 }
     154             :         }
     155             : 
     156             :         #if (BOARD_EXT_GPIOCHIPS > 0)
     157             :                 for (unsigned int i = getBrainPinOnchipNum() ; i < getBrainPinTotalNum(); i++) {
     158             :                         static char pin_error[64];
     159             :                         brain_pin_e brainPin = index_to_brainPin(i);
     160             : 
     161             :                         const char *pin_name = gpiochips_getPinName(brainPin);
     162             :                         const char *pin_user = getBrainUsedPin(i);
     163             :                         brain_pin_diag_e pin_diag = gpiochips_getDiag(brainPin);
     164             : 
     165             :                         pinDiag2string(pin_error, sizeof(pin_error), pin_diag);
     166             : 
     167             :                         /* here show all pins, unused too */
     168             :                         if (pin_name != NULL) {
     169             :                                 // this probably uses a lot of output buffer!
     170             :                                 efiPrintf("ext %s: %s diagnostic: %s",
     171             :                                         pin_name, pin_user ? pin_user : "free", pin_error);
     172             :                         } else {
     173             :                                 const char *chip_name = gpiochips_getChipName(brainPin);
     174             :                                 /* if chip exist */
     175             :                                 if (chip_name != NULL) {
     176             :                                         efiPrintf("ext %s.%d: %s diagnostic: %s",
     177             :                                                 chip_name, gpiochips_getPinOffset(brainPin), pin_user ? pin_user : "free", pin_error);
     178             :                                 }
     179             :                         }
     180             :                         if (pin_user != NULL) {
     181             :                                 totalPinsUsed++;
     182             :                         }
     183             :                 }
     184             :         #endif
     185             : 
     186             :         efiPrintf("Total pins used: %d", totalPinsUsed);
     187             : }
     188             : 
     189             : __attribute__((weak)) const char * getBoardSpecificPinName(brain_pin_e /*brainPin*/) {
     190             :         return nullptr;
     191             : }
     192             : 
     193             : const char *hwPhysicalPinName(Gpio brainPin) {
     194             :         if (brainPin == Gpio::Invalid) {
     195             :                 return "INVALID";
     196             :         }
     197             :         if (brainPin == Gpio::Unassigned) {
     198             :                 return "NONE";
     199             :         }
     200             : 
     201             :         portNameStream.eos = 0; // reset
     202             :         if (brain_pin_is_onchip(brainPin)) {
     203             : 
     204             :                 ioportid_t hwPort = getHwPort("hostname", brainPin);
     205             :                 if (hwPort == GPIO_NULL) {
     206             :                         return "NONE";
     207             :                 }
     208             :                 int hwPin = getHwPin("hostname", brainPin);
     209             :                 chprintf((BaseSequentialStream *) &portNameStream, "%s%d", portname(hwPort), hwPin);
     210             :         }
     211             :         #if (BOARD_EXT_GPIOCHIPS > 0)
     212             :                 else {
     213             : 
     214             :                         const char *pin_name = gpiochips_getPinName(brainPin);
     215             : 
     216             :                         if (pin_name) {
     217             :                                 chprintf((BaseSequentialStream *) &portNameStream, "ext:%s",
     218             :                                         pin_name);
     219             :                         } else {
     220             :                                 chprintf((BaseSequentialStream *) &portNameStream, "ext:%s.%d",
     221             :                                         gpiochips_getChipName(brainPin), gpiochips_getPinOffset(brainPin));
     222             :                         }
     223             :                 }
     224             :         #endif
     225             :         portNameStream.buffer[portNameStream.eos] = 0; // need to terminate explicitly
     226             : 
     227             :         return portNameBuffer;
     228             : }
     229             : 
     230             : const char *hwPortname(brain_pin_e brainPin) {
     231             :         const char * boardSpecificPinName = getBoardSpecificPinName(brainPin);
     232             :         if (boardSpecificPinName != nullptr) {
     233             :                 return boardSpecificPinName;
     234             :         }
     235             :         return hwPhysicalPinName(brainPin);
     236             : }
     237             : 
     238             : void initPinRepository(void) {
     239             :         /**
     240             :          * this method cannot use console because this method is invoked before console is initialized
     241             :          */
     242             : 
     243             :         addConsoleAction(CMD_PINS, reportPins);
     244             : 
     245             : #if (BOARD_TLE8888_COUNT > 0)
     246             :         addConsoleAction("tle8888", tle8888_dump_regs);
     247             :         addConsoleAction("tle8888init", tle8888_req_init);
     248             : #endif
     249             : }
     250             : 
     251             : bool brain_pin_is_onchip(brain_pin_e brainPin)
     252             : {
     253             :         if ((brainPin < Gpio::A0) || (brainPin > BRAIN_PIN_ONCHIP_LAST))
     254             :                 return false;
     255             : 
     256             :         return true;
     257             : }
     258             : 
     259             : bool brain_pin_is_ext(brain_pin_e brainPin)
     260             : {
     261             :         if (brainPin > BRAIN_PIN_ONCHIP_LAST)
     262             :                 return true;
     263             : 
     264             :         return false;
     265             : }
     266             : 
     267             : /**
     268             :  * Marks on-chip gpio port-pin as used. Works only for on-chip gpios
     269             :  * To be replaced with brain_pin_markUsed later
     270             :  */
     271             : 
     272             : bool gpio_pin_markUsed(ioportid_t port, ioportmask_t pin, const char *msg) {
     273             :         int index = getPortPinIndex(port, pin);
     274             : 
     275             :         if (getBrainUsedPin(index) != NULL) {
     276             :                 /**
     277             :                  * todo: the problem is that this warning happens before the console is even
     278             :                  * connected, so the warning is never displayed on the console and that's quite a problem!
     279             :                  */
     280             : //              warning(ObdCode::OBD_PCM_Processor_Fault, "%s%d req by %s used by %s", portname(port), pin, msg, getBrainUsedPin(index));
     281             :                 firmwareError(ObdCode::CUSTOM_ERR_PIN_ALREADY_USED_1, "%s%d req by %s used by %s", portname(port), pin, msg, getBrainUsedPin(index));
     282             :                 return true;
     283             :         }
     284             :         getBrainUsedPin(index) = msg;
     285             :         return false;
     286             : }
     287             : 
     288             : /**
     289             :  * Marks on-chip gpio port-pin as UNused. Works only for on-chip gpios
     290             :  * To be replaced with brain_pin_markUnused later
     291             :  */
     292             : 
     293             : void gpio_pin_markUnused(ioportid_t port, ioportmask_t pin) {
     294             :         int index = getPortPinIndex(port, pin);
     295             : 
     296             :         getBrainUsedPin(index) = nullptr;
     297             : }
     298             : 
     299             : const char *getPinFunction(brain_input_pin_e brainPin) {
     300             :         int index;
     301             : 
     302             :         index = brainPin_to_index(brainPin);
     303             :         if (index < 0)
     304             :                 return NULL;
     305             : 
     306             :         return getBrainUsedPin(index);
     307             : }
     308             : #else
     309           0 : const char *hwPhysicalPinName(Gpio brainPin) {
     310           0 :         return "N/A";
     311             : }
     312        1167 : const char *hwPortname(Gpio brainPin) {
     313             :         (void)brainPin;
     314        1167 :         return "N/A";
     315             : }
     316             : #endif /* EFI_PROD_CODE */

Generated by: LCOV version 1.14