rusefi/firmware/hw_layer/pin_repository.cpp

297 lines
7.5 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
*/
2018-09-16 19:26:57 -07:00
#include "global.h"
/* 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;
}
2019-01-03 21:16:08 -08:00
#if EFI_PROD_CODE
2019-07-05 17:03:32 -07:00
#include "os_access.h"
2015-07-10 06:01:56 -07:00
#include "pin_repository.h"
#include "eficonsole.h"
#include "memstreams.h"
#include "drivers/gpio/gpio_ext.h"
2020-04-06 10:05:30 -07:00
#include "smart_gpio.h"
2020-04-08 19:36:18 -07:00
#include "hardware.h"
EXTERN_CONFIG;
static PinRepository pinRepository;
static int brainPin_to_index(brain_pin_e brainPin)
{
unsigned int i;
if (brainPin < GPIOA_0)
return -1;
i = brainPin - GPIOA_0;
if (i >= getBrainPinTotalNum())
return -1;
return i;
}
static brain_pin_e index_to_brainPin(unsigned int i)
{
if (i < getBrainPinTotalNum())
return (brain_pin_e)((int)GPIOA_0 + i);;
return GPIO_INVALID;
}
static MemoryStream portNameStream;
static char portNameBuffer[20];
2016-04-03 08:02:57 -07:00
PinRepository::PinRepository() {
msObjectInit(&portNameStream, (uint8_t*) portNameBuffer, sizeof(portNameBuffer), 0);
2016-04-03 08:02:57 -07:00
initBrainUsedPins();
}
2015-07-10 06:01:56 -07:00
static void reportPins(void) {
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);
efiPrintf("pin %s%d: %s", portname(port), pin, pin_user);
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];
const char *pin_name;
const char *pin_user;
brain_pin_diag_e pin_diag;
brain_pin_e brainPin = index_to_brainPin(i);
pin_name = gpiochips_getPinName(brainPin);
pin_user = getBrainUsedPin(i);
pin_diag = gpiochips_getDiag(brainPin);
/* use autogeneraged helpers here? */
if (pin_diag == PIN_OK) {
chsnprintf(pin_error, sizeof(pin_error), "Ok");
} else if (pin_diag != PIN_INVALID) {
chsnprintf(pin_error, sizeof(pin_error), "%s%s%s%s%s",
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(pin_error, sizeof(pin_error), "INVALID");
}
/* 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);
}
}
}
#endif
efiPrintf("Total pins count: %d", pinRepository.totalPinsUsed);
2015-07-10 06:01:56 -07:00
}
void printSpiConfig(const char *msg, spi_device_e device) {
2021-02-05 19:29:23 -08:00
#if HAL_USE_SPI
efiPrintf("%s %s mosi=%s", msg, getSpi_device_e(device), hwPortname(getMosiPin(device)));
efiPrintf("%s %s miso=%s", msg, getSpi_device_e(device), hwPortname(getMisoPin(device)));
efiPrintf("%s %s sck=%s", msg, getSpi_device_e(device), hwPortname(getSckPin(device)));
2021-02-05 19:29:23 -08:00
#endif // HAL_USE_SPI
2020-04-08 19:36:18 -07:00
}
2015-07-10 06:01:56 -07:00
const char *hwPortname(brain_pin_e brainPin) {
if (brainPin == GPIO_INVALID) {
return "INVALID";
}
2019-07-14 19:47:11 -07:00
if (brainPin == GPIO_UNASSIGNED) {
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;
}
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 < GPIOA_0) || (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;
}
2015-07-13 17:02:18 -07:00
/**
* See also brain_pin_markUnused()
2017-04-21 13:27:15 -07:00
* @return true if this pin was already used, false otherwise
2015-07-13 17:02:18 -07:00
*/
bool brain_pin_markUsed(brain_pin_e brainPin, const char *msg) {
#if ! EFI_BOOTLOADER
efiPrintf("%s on %s", msg, hwPortname(brainPin));
#endif
int index = brainPin_to_index(brainPin);
if (index < 0)
return true;
if (getBrainUsedPin(index) != NULL) {
/* TODO: get readable name of brainPin... */
firmwareError(CUSTOM_ERR_PIN_ALREADY_USED_1, "Pin \"%s\" required by \"%s\" but is used by \"%s\" %s",
hwPortname(brainPin),
msg,
getBrainUsedPin(index),
getEngine_type_e(engineConfiguration->engineType));
return true;
}
getBrainUsedPin(index) = msg;
pinRepository.totalPinsUsed++;
return false;
}
/**
* See also brain_pin_markUsed()
*/
void brain_pin_markUnused(brain_pin_e brainPin) {
int index = brainPin_to_index(brainPin);
if (index < 0)
return;
if (getBrainUsedPin(index) != NULL)
pinRepository.totalPinsUsed--;
2019-09-22 05:22:35 -07:00
getBrainUsedPin(index) = nullptr;
}
/**
* 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(OBD_PCM_Processor_Fault, "%s%d req by %s used by %s", portname(port), pin, msg, getBrainUsedPin(index));
firmwareError(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;
pinRepository.totalPinsUsed++;
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);
if (getBrainUsedPin(index) != NULL)
pinRepository.totalPinsUsed--;
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 *hwPortname(brain_pin_e brainPin) {
(void)brainPin;
return "N/A";
}
#endif /* EFI_PROD_CODE */