rusefi/firmware/hw_layer/pin_repository.cpp

317 lines
8.0 KiB
C++
Raw Normal View History

2015-07-10 06:01:56 -07:00
/**
* @file pin_repository.cpp
* @brief I/O pin registry code
*
* This job of this class is to make sure that we are not using same hardware pin for two
* different purposes.
*
* @date Jan 15, 2013
2020-01-13 18:57:43 -08:00
* @author Andrey Belomutskiy, (c) 2012-2020
2015-07-10 06:01:56 -07:00
*/
#include "pch.h"
2023-08-21 20:09:30 -07:00
static size_t getBrainPinTotalNum() {
return BRAIN_PIN_TOTAL_PINS;
}
2023-08-21 20:09:30 -07:00
const char* & getBrainUsedPin(size_t index) {
return engine->pinRepository.getBrainUsedPin(index);
}
/* Common for firmware and unit tests */
bool isBrainPinValid(brain_pin_e brainPin) {
if ((brainPin == Gpio::Unassigned) || (brainPin == Gpio::Invalid))
return false;
if (brainPin > BRAIN_PIN_LAST)
/* something terribly wrong */
return false;
return true;
}
2023-08-21 20:09:30 -07:00
int brainPin_to_index(Gpio brainPin) {
if (brainPin < Gpio::A0)
return -1;
2023-08-21 20:09:30 -07:00
size_t i = brainPin - Gpio::A0;
if (i >= getBrainPinTotalNum())
return -1;
return i;
}
/**
* See also brain_pin_markUnused()
* @return true if this pin was already used, false otherwise
*/
2023-08-21 20:09:30 -07:00
bool brain_pin_markUsed(Gpio brainPin, const char *msg) {
#if ! EFI_BOOTLOADER
2022-06-19 08:03:26 -07:00
efiPrintf("pin_markUsed: %s on %s", msg, hwPortname(brainPin));
#endif
int index = brainPin_to_index(brainPin);
if (index < 0)
return true;
2023-11-24 11:35:56 -08:00
if (engine->pinRepository.getBrainUsedPin(index) != nullptr) {
// hwPortname and share a buffer behind the scenes, even while they probably never use it for different
// values here let's have an explicit second buffer to make this more reliable
char physicalPinName[32];
strncpy(physicalPinName, hwPhysicalPinName(brainPin), sizeof(physicalPinName) - 1);
2023-11-24 11:35:56 -08:00
criticalError("Pin \"%s\" (%s) required by \"%s\" but is used by \"%s\"",
hwPortname(brainPin),
physicalPinName,
msg,
2023-08-21 20:09:30 -07:00
getBrainUsedPin(index));
return true;
}
getBrainUsedPin(index) = msg;
return false;
}
/**
* See also brain_pin_markUsed()
*/
void brain_pin_markUnused(brain_pin_e brainPin) {
2022-06-19 08:03:26 -07:00
#if ! EFI_BOOTLOADER
efiPrintf("pin_markUnused: %s", hwPortname(brainPin));
#endif
int index = brainPin_to_index(brainPin);
if (index < 0)
return;
getBrainUsedPin(index) = nullptr;
}
#if EFI_PROD_CODE
#include "memstreams.h"
static MemoryStream portNameStream;
static char portNameBuffer[20];
#endif /* EFI_PROD_CODE */
2016-04-03 08:02:57 -07:00
PinRepository::PinRepository() {
#if EFI_PROD_CODE
msObjectInit(&portNameStream, (uint8_t*) portNameBuffer, sizeof(portNameBuffer), 0);
#endif /* EFI_PROD_CODE */
2016-04-03 08:02:57 -07:00
2021-07-14 23:00:48 -07:00
memset(PIN_USED, 0, sizeof(PIN_USED));
}
#if EFI_PROD_CODE
2022-09-07 12:56:45 -07:00
#include "eficonsole.h"
#include "drivers/gpio/gpio_ext.h"
#include "smart_gpio.h"
#include "hardware.h"
2022-01-03 11:21:54 -08:00
void pinDiag2string(char *buffer, size_t size, brain_pin_diag_e pin_diag) {
/* use autogeneraged helpers here? */
if (pin_diag == PIN_OK) {
chsnprintf(buffer, size, "Ok");
} else if (pin_diag != PIN_UNKNOWN) {
chsnprintf(buffer, size, "%s%s%s%s%s%s",
pin_diag & PIN_DRIVER_OFF ? "driver_off " : "",
2022-01-03 11:21:54 -08:00
pin_diag & PIN_OPEN ? "open_load " : "",
pin_diag & PIN_SHORT_TO_GND ? "short_to_gnd " : "",
pin_diag & PIN_SHORT_TO_BAT ? "short_to_bat " : "",
pin_diag & PIN_OVERLOAD ? "overload " : "",
pin_diag & PIN_DRIVER_OVERTEMP ? "overtemp": "");
} else {
chsnprintf(buffer, size, "INVALID");
}
}
static brain_pin_e index_to_brainPin(unsigned int i)
{
if (i < getBrainPinTotalNum())
return Gpio::A0 + i;
return Gpio::Invalid;
}
static void reportPins() {
int totalPinsUsed = 0;
for (unsigned int i = 0; i < getBrainPinOnchipNum(); i++) {
const char *pin_user = getBrainUsedPin(i);
/* show used pins */
if (pin_user != NULL) {
brain_pin_e brainPin = index_to_brainPin(i);
int pin = getBrainPinIndex(brainPin);
ioportid_t port = getBrainPinPort(brainPin);
2023-07-05 19:18:22 -07:00
const char *boardPinName = getBoardSpecificPinName(brainPin);
efiPrintf("pin %s%d (%s): %s", portname(port), pin, boardPinName, pin_user);
totalPinsUsed++;
2015-07-10 06:01:56 -07:00
}
}
#if (BOARD_EXT_GPIOCHIPS > 0)
for (unsigned int i = getBrainPinOnchipNum() ; i < getBrainPinTotalNum(); i++) {
static char pin_error[64];
brain_pin_e brainPin = index_to_brainPin(i);
2022-01-03 11:21:54 -08:00
const char *pin_name = gpiochips_getPinName(brainPin);
const char *pin_user = getBrainUsedPin(i);
brain_pin_diag_e pin_diag = gpiochips_getDiag(brainPin);
pinDiag2string(pin_error, sizeof(pin_error), pin_diag);
/* here show all pins, unused too */
if (pin_name != NULL) {
2019-04-13 08:22:40 -07:00
// this probably uses a lot of output buffer!
efiPrintf("ext %s: %s diagnostic: %s",
pin_name, pin_user ? pin_user : "free", pin_error);
} else {
const char *chip_name = gpiochips_getChipName(brainPin);
/* if chip exist */
if (chip_name != NULL) {
efiPrintf("ext %s.%d: %s diagnostic: %s",
chip_name, gpiochips_getPinOffset(brainPin), pin_user ? pin_user : "free", pin_error);
}
}
if (pin_user != NULL) {
totalPinsUsed++;
}
}
#endif
efiPrintf("Total pins used: %d", totalPinsUsed);
2015-07-10 06:01:56 -07:00
}
2022-03-22 13:53:24 -07:00
__attribute__((weak)) const char * getBoardSpecificPinName(brain_pin_e /*brainPin*/) {
return nullptr;
}
const char *hwPhysicalPinName(Gpio brainPin) {
if (brainPin == Gpio::Invalid) {
2015-07-10 06:01:56 -07:00
return "INVALID";
}
if (brainPin == Gpio::Unassigned) {
2019-07-14 19:47:11 -07:00
return "NONE";
}
2015-07-10 06:01:56 -07:00
portNameStream.eos = 0; // reset
if (brain_pin_is_onchip(brainPin)) {
ioportid_t hwPort = getHwPort("hostname", brainPin);
if (hwPort == GPIO_NULL) {
return "NONE";
}
2019-07-14 19:47:11 -07:00
int hwPin = getHwPin("hostname", brainPin);
chprintf((BaseSequentialStream *) &portNameStream, "%s%d", portname(hwPort), hwPin);
}
#if (BOARD_EXT_GPIOCHIPS > 0)
else {
2020-09-09 07:20:21 -07:00
const char *pin_name = gpiochips_getPinName(brainPin);
if (pin_name) {
chprintf((BaseSequentialStream *) &portNameStream, "ext:%s",
pin_name);
} else {
chprintf((BaseSequentialStream *) &portNameStream, "ext:%s.%d",
gpiochips_getChipName(brainPin), gpiochips_getPinOffset(brainPin));
}
}
#endif
2015-07-10 06:01:56 -07:00
portNameStream.buffer[portNameStream.eos] = 0; // need to terminate explicitly
2015-07-10 06:01:56 -07:00
return portNameBuffer;
}
const char *hwPortname(brain_pin_e brainPin) {
const char * boardSpecificPinName = getBoardSpecificPinName(brainPin);
if (boardSpecificPinName != nullptr) {
return boardSpecificPinName;
}
return hwPhysicalPinName(brainPin);
}
2015-07-10 06:01:56 -07:00
void initPinRepository(void) {
/**
* this method cannot use console because this method is invoked before console is initialized
*/
addConsoleAction(CMD_PINS, reportPins);
#if (BOARD_TLE8888_COUNT > 0)
addConsoleAction("tle8888", tle8888_dump_regs);
Tle8888 big update 1 (#1892) * smart gpio: fix tle8888 direct pin mapping for MRE * MRE: use TLE8888 pins instead of MCU gpios that drives TLE8888 * TLE8888: cleanup * TLE8888: do not reset driver private data on WD/undervoltage reset * TLE8888: diagnostic updates * TLE8888 driver: BIG driver rework * TLE8888: check SPI answers for abnormal states Reply with other than requested register can be a sign of: -Power-On-Reset, then OpStat0 will be replyed -WatchDog reset, then FWDStat1 will be replyed -Invalid communication frame, then Diag0 will be replyed Keep tracking last accessed register and check with the next reply. * TLE8888: debug clean-up * TLE8888: implement spi array write This reduce CS inactive state time between two consequent accesses from 8.8 uS to 1.4 uS * TLE8888: fix PP outputs in OD mode * TLE8888: cleanup register definitions * TLE8888: run separate driver thread for each chip instance Calculating poll interval for few chips become more complex, avoid this running thread for each device. * TLE8888: fix cypress and kinetic compilation Both platforms define its own MAX and cause redifination error if common.h is included in driver. * MRE: update mapping.yaml and fix direct pin mapping for TLE8888 * TLE8888: diagnnostic: disable switch off in case of overcurrent For all output, use current limiting instead * TLE8888: check for overvoltage on OUT8..OUT13 * TLE8888: add TODO note about how to recover from failure condition Currently TLE8888 automaticly recovers only from overcurrent and (may be) overtemperature conditions. Short to bat cause output disable (bit in OECONFIG is reset) and needs driver/host intervention. * TLE8888: save few bytes of RAM * TLE8888: Lada Kalina is test mule for IDLE stepper on TLE8888 Don't forget to enable PP mode for TLE8888 outputs 21..24: uncomment line 1087 in tle8888.c * TLE8888: reorder code, cleanup * TLE8888: mode all debug/statisctic to per-chip struct * TLE8888: rework poll interval calculation * MRE: use TLE8888 pins instead of MCU gpios that drives TLE8888 #2
2020-10-23 09:25:30 -07:00
addConsoleAction("tle8888init", tle8888_req_init);
#endif
2015-07-10 06:01:56 -07:00
}
bool brain_pin_is_onchip(brain_pin_e brainPin)
{
if ((brainPin < Gpio::A0) || (brainPin > BRAIN_PIN_ONCHIP_LAST))
return false;
return true;
}
bool brain_pin_is_ext(brain_pin_e brainPin)
{
if (brainPin > BRAIN_PIN_ONCHIP_LAST)
return true;
return false;
}
/**
* Marks on-chip gpio port-pin as used. Works only for on-chip gpios
* To be replaced with brain_pin_markUsed later
*/
bool gpio_pin_markUsed(ioportid_t port, ioportmask_t pin, const char *msg) {
int index = getPortPinIndex(port, pin);
2017-04-21 13:27:15 -07:00
if (getBrainUsedPin(index) != NULL) {
2017-04-21 13:27:15 -07:00
/**
* todo: the problem is that this warning happens before the console is even
* connected, so the warning is never displayed on the console and that's quite a problem!
*/
// warning(ObdCode::OBD_PCM_Processor_Fault, "%s%d req by %s used by %s", portname(port), pin, msg, getBrainUsedPin(index));
firmwareError(ObdCode::CUSTOM_ERR_PIN_ALREADY_USED_1, "%s%d req by %s used by %s", portname(port), pin, msg, getBrainUsedPin(index));
2017-04-21 13:27:15 -07:00
return true;
}
getBrainUsedPin(index) = msg;
2017-04-21 13:27:15 -07:00
return false;
2015-07-10 06:01:56 -07:00
}
/**
* Marks on-chip gpio port-pin as UNused. Works only for on-chip gpios
* To be replaced with brain_pin_markUnused later
*/
void gpio_pin_markUnused(ioportid_t port, ioportmask_t pin) {
int index = getPortPinIndex(port, pin);
2019-09-22 05:22:35 -07:00
getBrainUsedPin(index) = nullptr;
}
const char *getPinFunction(brain_input_pin_e brainPin) {
int index;
index = brainPin_to_index(brainPin);
if (index < 0)
return NULL;
2015-07-10 06:01:56 -07:00
return getBrainUsedPin(index);
2015-07-10 06:01:56 -07:00
}
2019-09-19 18:41:52 -07:00
#else
const char *hwPhysicalPinName(Gpio brainPin) {
return "N/A";
}
const char *hwPortname(Gpio brainPin) {
2019-09-19 18:41:52 -07:00
(void)brainPin;
return "N/A";
}
#endif /* EFI_PROD_CODE */