rusEFI
The most advanced open source ECU
Public Member Functions | Data Fields | Private Member Functions | Private Attributes
OutputPin Class Reference

Single output pin reference and state. More...

#include <efi_output.h>

Inheritance diagram for OutputPin:
Inheritance graph
[legend]
Collaboration diagram for OutputPin:
Collaboration graph
[legend]

Public Member Functions

void initPin (const char *msg, brain_pin_e brainPin, pin_output_mode_e outputMode, bool forceInitWithFatalError=false)
 
void initPin (const char *msg, brain_pin_e brainPin)
 
void deInit ()
 
bool isInitialized () const
 
bool getAndSet (int logicValue)
 
void setValue (const char *msg, int logicValue, bool isForce=false)
 
TEST_VIRTUAL void setValue (int logicValue, bool isForce=false)
 
void toggle ()
 
bool getLogicValue () const
 
brain_pin_diag_e getDiag () const
 
void resetToggleStats ()
 

Data Fields

ioportid_t m_port = 0
 
uint8_t m_pin = 0
 
int pinToggleCounter = 0
 
Timer pinToggleTimer
 
uint32_t durationsInStateMs [2]
 
brain_pin_e brainPin = Gpio::Unassigned
 
bool ext = false
 
int8_t currentLogicValue = INITIAL_PIN_STATE
 

Private Member Functions

void setDefaultPinState (pin_output_mode_e mode)
 
void setOnchipValue (int electricalValue)
 

Private Attributes

pin_output_mode_e mode = OM_DEFAULT
 

Detailed Description

Single output pin reference and state.

Definition at line 50 of file efi_output.h.

Member Function Documentation

◆ deInit()

void OutputPin::deInit ( )

Definition at line 781 of file efi_gpio.cpp.

781  {
782  // Unregister under lock - we don't want other threads mucking with the pin while we're trying to turn it off
783  chibios_rt::CriticalSectionLocker csl;
784 
785  // nothing to do if not registered in the first place
786  if (!isBrainPinValid(brainPin)) {
787  return;
788  }
789 
790 #if (BOARD_EXT_GPIOCHIPS > 0)
791  ext = false;
792 #endif // (BOARD_EXT_GPIOCHIPS > 0)
793 
794  efiPrintf("unregistering %s", hwPortname(brainPin));
795 
796 #if EFI_GPIO_HARDWARE && EFI_PROD_CODE
798 #endif /* EFI_GPIO_HARDWARE */
799 
800  // Clear the pin so that it won't get set any more
802 }
bool ext
Definition: efi_output.h:91
brain_pin_e brainPin
Definition: efi_output.h:87
@ Unassigned
void efiSetPadUnused(brain_pin_e brainPin)
Definition: io_pins.cpp:20
const char * hwPortname(brain_pin_e brainPin)
bool isBrainPinValid(brain_pin_e brainPin)

Referenced by initPin(), luaDeInitPins(), stopHip9001_pins(), stopTriggerEmulatorPins(), stopVvtControlPins(), and RegisteredOutputPin::unregister().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getAndSet()

bool OutputPin::getAndSet ( int  logicValue)

Definition at line 552 of file efi_gpio.cpp.

552  {
553  bool oldValue = getLogicValue();
554  setValue(logicValue);
555  return oldValue;
556 }
bool getLogicValue() const
Definition: efi_gpio.cpp:646
void setValue(const char *msg, int logicValue, bool isForce=false)
Definition: efi_gpio.cpp:583

Referenced by disengageStarterIfNeeded(), and onStartStopButtonToggle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getDiag()

brain_pin_diag_e OutputPin::getDiag ( ) const

Definition at line 657 of file efi_gpio.cpp.

657  {
658 #if EFI_PROD_CODE
659 #if BOARD_EXT_GPIOCHIPS > 0
661  return gpiochips_getDiag(brainPin);
662  }
663 #endif
664 #endif /* EFI_PROD_CODE */
665  // TODO: add hook to board code for custom diagnostic, like it is done on S105
666  return PIN_UNKNOWN;
667 }
brain_pin_diag_e gpiochips_getDiag(brain_pin_e pin)
Get diagnostic for given gpio.
Definition: core.cpp:313
bool brain_pin_is_onchip(brain_pin_e brainPin)

Referenced by benchOff(), and SensorChecker::onSlowCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getLogicValue()

bool OutputPin::getLogicValue ( ) const

Definition at line 646 of file efi_gpio.cpp.

646  {
647  // Compare against 1 since it could also be INITIAL_PIN_STATE (which means logical 0, but we haven't initialized the pin yet)
648  return currentLogicValue == 1;
649 }
int8_t currentLogicValue
Definition: efi_output.h:94

Referenced by canDashboardHaltech(), getAndSet(), getHellenBoardEnabled(), IdleController::getRunningOpenLoop(), Engine::isMainRelayEnabled(), lua_fan(), populateFrame(), slowStartStopButtonCallback(), NamedOutputPin::stop(), toggle(), updateFlags(), and updateTunerStudioState().

Here is the caller graph for this function:

◆ initPin() [1/2]

void OutputPin::initPin ( const char *  msg,
brain_pin_e  brainPin 
)

Definition at line 686 of file efi_gpio.cpp.

686  {
687  initPin(p_msg, p_brainPin, OM_DEFAULT);
688 }
void initPin(const char *msg, brain_pin_e brainPin, pin_output_mode_e outputMode, bool forceInitWithFatalError=false)
Definition: efi_gpio.cpp:690
Here is the call graph for this function:

◆ initPin() [2/2]

void OutputPin::initPin ( const char *  msg,
brain_pin_e  brainPin,
pin_output_mode_e  outputMode,
bool  forceInitWithFatalError = false 
)

Definition at line 690 of file efi_gpio.cpp.

690  {
691 #if EFI_UNIT_TEST
692  pinToggleCounter = 0;
693 #endif
694 
695  if (!isBrainPinValid(p_brainPin)) {
696  return;
697  }
698 
699  // Enter a critical section so that other threads can't change the pin state out from underneath us
700  chibios_rt::CriticalSectionLocker csl;
701 
702  if (!forceInitWithFatalError && hasFirmwareError()) {
703  // Don't allow initializing more pins if we have a fatal error.
704  // Pins should have just been reset, so we shouldn't try to init more.
705  return;
706  }
707 
708  // Check that this OutputPin isn't already assigned to another pin (reinit is allowed to change mode)
709  // To avoid this error, call deInit() first
710  if (isBrainPinValid(brainPin) && brainPin != p_brainPin) {
711  firmwareError(ObdCode::CUSTOM_OBD_PIN_CONFLICT, "outputPin [%s] already assigned, cannot reassign without unregister first", msg);
712  return;
713  }
714 
715  if (outputMode > OM_OPENDRAIN_INVERTED) {
716  firmwareError(ObdCode::CUSTOM_INVALID_MODE_SETTING, "%s invalid pin_output_mode_e %d %s",
717  msg,
718  outputMode,
719  hwPortname(p_brainPin)
720  );
721  return;
722  }
723 
724 #if EFI_GPIO_HARDWARE && EFI_PROD_CODE
725  iomode_t l_mode = (outputMode == OM_DEFAULT || outputMode == OM_INVERTED) ?
726  PAL_MODE_OUTPUT_PUSHPULL : PAL_MODE_OUTPUT_OPENDRAIN;
727 
728  #if (BOARD_EXT_GPIOCHIPS > 0)
729  this->ext = false;
730  #endif
731  if (brain_pin_is_onchip(p_brainPin)) {
732  m_port = getHwPort(msg, p_brainPin);
733  m_pin = getHwPin(msg, p_brainPin);
734 
735  // Validate port
736  if (m_port == GPIO_NULL) {
737  criticalError("OutputPin::initPin got invalid port for pin idx %d", static_cast<int>(p_brainPin));
738  return;
739  }
740  }
741  #if (BOARD_EXT_GPIOCHIPS > 0)
742  else {
743  this->ext = true;
744  }
745  #endif
746 #endif // briefly leave the include guard because we need to set default state in tests
747 
748  brainPin = p_brainPin;
749 
750  // The order of the next two calls may look strange, which is a good observation.
751  // We call them in this order so that the pin is set to a known state BEFORE
752  // it's enabled. Enabling the pin then setting it could result in a (brief)
753  // mystery state being driven on the pin (potentially dangerous).
754  setDefaultPinState(outputMode);
755 
756 #if EFI_GPIO_HARDWARE && EFI_PROD_CODE
757  efiSetPadMode(msg, brainPin, l_mode);
759  // todo: handle OM_OPENDRAIN and OM_OPENDRAIN_INVERTED as well
760  if (outputMode == OM_DEFAULT || outputMode == OM_INVERTED) {
761 #ifndef DISABLE_PIN_STATE_VALIDATION
762  int actualValue = palReadPad(m_port, m_pin);
763  // we had enough drama with pin configuration in board.h and else that we shall self-check
764 
765  const int logicalValue =
766  (outputMode == OM_INVERTED)
767  ? !actualValue
768  : actualValue;
769 
770  // if the pin was set to logical 1, then set an error and disable the pin so that things don't catch fire
771  if (logicalValue) {
772  criticalError("HARDWARE VALIDATION FAILED %s: unexpected startup pin state %s actual value=%d logical value=%d mode=%s", msg, hwPortname(brainPin), actualValue, logicalValue, getPin_output_mode_e(outputMode));
774  }
775 #endif
776  }
777  }
778 #endif /* EFI_GPIO_HARDWARE */
779 }
const char * getPin_output_mode_e(pin_output_mode_e value)
void efiSetPadMode(const char *msg, brain_pin_e brainPin, iomode_t mode)
void deInit()
Definition: efi_gpio.cpp:781
ioportid_t m_port
Definition: efi_output.h:72
int pinToggleCounter
Definition: efi_output.h:77
uint8_t m_pin
Definition: efi_output.h:73
void setDefaultPinState(pin_output_mode_e mode)
Definition: efi_gpio.cpp:651
ioportid_t getHwPort(const char *msg, brain_pin_e brainPin)
ioportmask_t getHwPin(const char *msg, brain_pin_e brainPin)
void firmwareError(ObdCode code, const char *fmt,...)
uint32_t iomode_t
Digital I/O modes.
Definition: hal_pal_lld.h:83
static const char * msg
@ CUSTOM_INVALID_MODE_SETTING
@ CUSTOM_OBD_PIN_CONFLICT

Referenced by boardInitHardware(), configureHellenCanTerminator(), hellenMegaAccelerometerPreInitCS2Pin(), RegisteredOutputPin::init(), SimpleTransmissionController::init(), Generic4TransmissionController::init(), Gm4l6xTransmissionController::init(), initAccelerometer(), initErrorLed(), initGpPwm(), StepDirectionStepper::initialize(), initMiscOutputPins(), initPin(), initStatusLeds(), initWarningRunningPins(), nm_bus_init(), portInitAdc(), runSchedulingPrecisionTestIfNeeded(), setHellenEnPin(), DcHardware::start(), EnginePins::startAuxValves(), startHip9001_pins(), EnginePins::startIgnitionPins(), EnginePins::startInjectionPins(), startSimplePwmExt(), startSmartCsPins(), and startTriggerEmulatorPins().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isInitialized()

bool OutputPin::isInitialized ( ) const

Definition at line 536 of file efi_gpio.cpp.

536  {
537 #if EFI_GPIO_HARDWARE && EFI_PROD_CODE
538 #if (BOARD_EXT_GPIOCHIPS > 0)
539  if (ext)
540  return true;
541 #endif /* (BOARD_EXT_GPIOCHIPS > 0) */
542  return m_port != NULL;
543 #else /* EFI_GPIO_HARDWARE */
544  return true;
545 #endif /* EFI_GPIO_HARDWARE */
546 }

Referenced by assertPinAssigned(), hellenMegaAccelerometerPreInitCS2Pin(), initAccelerometer(), isGdiEngine(), HpfpController::onFastCallback(), HpfpController::scheduleNextCycle(), NamedOutputPin::stop(), and InjectionEvent::update().

Here is the caller graph for this function:

◆ resetToggleStats()

void OutputPin::resetToggleStats ( )

Definition at line 575 of file efi_gpio.cpp.

575  {
577  pinToggleCounter = 0;
578 }
uint32_t durationsInStateMs[2]
Definition: efi_output.h:82

Referenced by resetPinStats().

Here is the caller graph for this function:

◆ setDefaultPinState()

void OutputPin::setDefaultPinState ( pin_output_mode_e  mode)
private

we track current pin status so that we do not touch the actual hardware if we want to write new pin bit which is same as current pin value. This maybe helps in case of status leds, but maybe it's a total over-engineering

Definition at line 651 of file efi_gpio.cpp.

651  {
652  assertOMode(mode);
653  this->mode = outputMode;
654  setValue(false, /*force*/true); // initial state
655 }
pin_output_mode_e mode
Definition: efi_output.h:105

Referenced by initPin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setOnchipValue()

void OutputPin::setOnchipValue ( int  electricalValue)
private

Definition at line 560 of file efi_gpio.cpp.

560  {
562  // todo: make 'setOnchipValue' or 'reportsetOnchipValueError' virtual and override for NamedOutputPin?
563  warning(ObdCode::CUSTOM_ERR_6586, "attempting to change unassigned pin");
564  return;
565  }
566  palWritePad(m_port, m_pin, electricalValue);
567 }
@ Invalid
bool warning(ObdCode code, const char *fmt,...)
@ CUSTOM_ERR_6586

Referenced by setValue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setValue() [1/2]

void OutputPin::setValue ( const char *  msg,
int  logicValue,
bool  isForce = false 
)

Definition at line 583 of file efi_gpio.cpp.

583  {
584  UNUSED(msg);
585  if ((qcDirectPinControlMode || getOutputOnTheBenchTest() == this) && !isForce) {
586  return;
587  }
588 
589 #if ENABLE_PERF_TRACE
590 // todo: https://github.com/rusefi/rusefi/issues/1638
591 // ScopePerf perf(PE::OutputPinSetValue);
592 #endif // ENABLE_PERF_TRACE
593 
594 #if EFI_UNIT_TEST
595  if (currentLogicValue != logicValue) {
597  }
598 #endif // EFI_UNIT_TEST
599 
600 #if EFI_SIMULATOR
601  if (currentLogicValue != logicValue) {
602  if (pinToggleCounter > 0) {
604  durationsInStateMs[1] = pinToggleTimer.getElapsedUs() / 1000;
605  }
607  pinToggleTimer.reset();
608  }
609 #endif // EFI_SIMULATOR
610 
611 #if EFI_UNIT_TEST
612  if (verboseMode) {
613  efiPrintf("pin goes %d", logicValue);
614  }
615 #endif // EFI_UNIT_TEST
616 
617  // Always store the current logical value of the pin (so it can be
618  // used internally even if not connected to a real hardware pin)
619  currentLogicValue = logicValue;
620 
621  // Nothing else to do if not configured
622  if (!isBrainPinValid(brainPin)) {
623  return;
624  }
625 
626  efiAssertVoid(ObdCode::CUSTOM_ERR_6622, mode <= OM_OPENDRAIN_INVERTED, "invalid pin_output_mode_e");
627  int electricalValue = getElectricalValue(logicValue, mode);
628 
629 #if EFI_PROD_CODE
630  #if (BOARD_EXT_GPIOCHIPS > 0)
631  if (!this->ext) {
632  setOnchipValue(electricalValue);
633  } else {
634  /* external pin */
635  gpiochips_writePad(this->brainPin, logicValue);
636  /* TODO: check return value */
637  }
638  #else
639  setOnchipValue(electricalValue);
640  #endif
641 #else /* EFI_PROD_CODE */
642  setMockState(brainPin, electricalValue);
643 #endif /* EFI_PROD_CODE */
644 }
const OutputPin * getOutputOnTheBenchTest()
Definition: bench_test.cpp:32
Timer pinToggleTimer
Definition: efi_output.h:81
void setOnchipValue(int electricalValue)
Definition: efi_gpio.cpp:560
int gpiochips_writePad(brain_pin_e pin, int value)
Set value to gpio of gpiochip.
Definition: core.cpp:275
bool verboseMode
bool qcDirectPinControlMode
void setMockState(brain_pin_e pin, bool state)
Definition: io_pins.cpp:129
UNUSED(samplingTimeSeconds)
@ CUSTOM_ERR_6622

Referenced by applyPinState(), PwmConfig::applyPwmValue(), benchOff(), benchOn(), blink_digits(), boardOnConfigurationChange(), configureHellenCanTerminator(), TwoPinDcMotor::disable(), TwoPinDcMotor::enable(), firmwareError(), getAndSet(), hellenDisableEn(), hellenEnableEn(), hellenMegaAccelerometerPreInitCS2Pin(), hipThread(), StepDirectionStepper::initialize(), nm_bus_init(), AcController::onSlowCallback(), FuelPumpController::onSlowCallback(), HarleyAcr::onSlowCallback(), MainRelayController::onSlowCallback(), Engine::OnTriggerSynchronization(), Engine::periodicSlowCallback(), StepDirectionStepper::pulse(), readSlowAnalogInputs(), InjectorOutputPin::reset(), runSchedulingPrecisionTestIfNeeded(), TwoPinDcMotor::set(), setDefaultPinState(), StepDirectionStepper::setDirection(), NamedOutputPin::setHigh(), NamedOutputPin::setLow(), GppwmChannel::setOutput(), PwmWrapper::setSimplePwmDutyCycle(), Generic4TransmissionController::setTccState(), setValue(), DcHardware::start(), startSmartCsPins(), NamedOutputPin::stop(), toggle(), turnAllPinsOff(), and SimpleTransmissionController::update().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setValue() [2/2]

void OutputPin::setValue ( int  logicValue,
bool  isForce = false 
)

Definition at line 570 of file efi_gpio.cpp.

570  {
571  setValue(nullptr, logicValue, isForce);
572 }
Here is the call graph for this function:

◆ toggle()

void OutputPin::toggle ( )

Definition at line 548 of file efi_gpio.cpp.

548  {
549  setValue("toggle", !getLogicValue());
550 }

Referenced by TriggerDecoderBase::decodeTriggerEvent(), and toggleTestAndScheduleNext().

Here is the call graph for this function:
Here is the caller graph for this function:

Field Documentation

◆ brainPin

brain_pin_e OutputPin::brainPin = Gpio::Unassigned

◆ currentLogicValue

int8_t OutputPin::currentLogicValue = INITIAL_PIN_STATE

◆ durationsInStateMs

uint32_t OutputPin::durationsInStateMs[2]

Definition at line 82 of file efi_output.h.

Referenced by resetToggleStats(), runBench(), sendPinStatePackets(), and setValue().

◆ ext

bool OutputPin::ext = false

Definition at line 91 of file efi_output.h.

Referenced by deInit(), initPin(), isInitialized(), and setValue().

◆ m_pin

uint8_t OutputPin::m_pin = 0

Definition at line 73 of file efi_output.h.

Referenced by initPin(), nm_bus_init(), and setOnchipValue().

◆ m_port

ioportid_t OutputPin::m_port = 0

Definition at line 72 of file efi_output.h.

Referenced by initPin(), isInitialized(), nm_bus_init(), and setOnchipValue().

◆ mode

pin_output_mode_e OutputPin::mode = OM_DEFAULT
private

Definition at line 105 of file efi_output.h.

Referenced by setDefaultPinState(), and setValue().

◆ pinToggleCounter

int OutputPin::pinToggleCounter = 0

Definition at line 77 of file efi_output.h.

Referenced by initPin(), resetToggleStats(), runBench(), sendPinStatePackets(), and setValue().

◆ pinToggleTimer

Timer OutputPin::pinToggleTimer

Definition at line 81 of file efi_output.h.

Referenced by setValue().


The documentation for this class was generated from the following files: