Revert "Don't keep a separate MultiChannelStateSequence for the trigger emulator. (#3513)"

This reverts commit 280dfa94e7.
This commit is contained in:
rusefillc 2021-11-09 20:42:02 -05:00
parent aea4a2ad22
commit 1db9a02f1d
8 changed files with 110 additions and 60 deletions

View File

@ -53,7 +53,7 @@ float MultiChannelStateSequence::getSwitchTime(const int index) const {
return switchTimes[index];
}
void MultiChannelStateSequence::checkSwitchTimes(const int size, const float scale) const {
void MultiChannelStateSequence::checkSwitchTimes(const int size, const float scale) {
if (switchTimes[size - 1] != 1) {
firmwareError(CUSTOM_ERR_WAVE_1, "last switch time has to be 1/%f not %.2f/%f", scale,
switchTimes[size - 1], scale * switchTimes[size - 1]);

View File

@ -72,7 +72,7 @@ public:
void reset(void);
float getSwitchTime(const int phaseIndex) const;
void setSwitchTime(const int phaseIndex, const float value);
void checkSwitchTimes(const int size, const float scale) const;
void checkSwitchTimes(const int size, const float scale);
pin_state_t getChannelState(const int channelIndex, const int phaseIndex) const;
int findAngleMatch(const float angle, const int size) const;

View File

@ -18,11 +18,10 @@
// 1% duty cycle
#define ZERO_PWM_THRESHOLD 0.01
SimplePwm::SimplePwm()
: sr(pinStates)
, seq(_switchTimes, &sr)
{
seq.waveCount = 1;
SimplePwm::SimplePwm() {
waveInstance.init(pinStates);
sr[0] = waveInstance;
init(_switchTimes, sr);
}
SimplePwm::SimplePwm(const char *name) : SimplePwm() {
@ -44,6 +43,14 @@ PwmConfig::PwmConfig() {
arg = this;
}
PwmConfig::PwmConfig(float *st, SingleChannelStateSequence *waves) : PwmConfig() {
multiChannelStateSequence.init(st, waves);
}
void PwmConfig::init(float *st, SingleChannelStateSequence *waves) {
multiChannelStateSequence.init(st, waves);
}
/**
* This method allows you to change duty cycle on the fly
* @param dutyCycle value between 0 and 1
@ -87,7 +94,7 @@ void SimplePwm::setSimplePwmDutyCycle(float dutyCycle) {
mode = PM_FULL;
} else {
mode = PM_NORMAL;
_switchTimes[0] = dutyCycle;
multiChannelStateSequence.setSwitchTime(0, dutyCycle);
}
}
@ -98,7 +105,7 @@ static efitick_t getNextSwitchTimeNt(PwmConfig *state) {
efiAssert(CUSTOM_ERR_ASSERT, state->safe.phaseIndex < PWM_PHASE_MAX_COUNT, "phaseIndex range", 0);
int iteration = state->safe.iteration;
// we handle PM_ZERO and PM_FULL separately
float switchTime = state->mode == PM_NORMAL ? state->multiChannelStateSequence->getSwitchTime(state->safe.phaseIndex) : 1;
float switchTime = state->mode == PM_NORMAL ? state->multiChannelStateSequence.getSwitchTime(state->safe.phaseIndex) : 1;
float periodNt = state->safe.periodNt;
#if DEBUG_PWM
efiPrintf("iteration=%d switchTime=%.2f period=%.2f", iteration, switchTime, period);
@ -265,11 +272,21 @@ static void timerCallback(PwmConfig *state) {
* Incoming parameters are potentially just values on current stack, so we have to copy
* into our own permanent storage, right?
*/
void copyPwmParameters(PwmConfig *state, int phaseCount, MultiChannelStateSequence const * seq) {
void copyPwmParameters(PwmConfig *state, int phaseCount, float const *switchTimes, int waveCount, pin_state_t *const *pinStates) {
state->phaseCount = phaseCount;
state->multiChannelStateSequence = seq;
for (int phaseIndex = 0; phaseIndex < phaseCount; phaseIndex++) {
state->multiChannelStateSequence.setSwitchTime(phaseIndex, switchTimes[phaseIndex]);
for (int channelIndex = 0; channelIndex < waveCount; channelIndex++) {
// print("output switch time index (%d/%d) at %.2f to %d\r\n", phaseIndex, channelIndex,
// switchTimes[phaseIndex], pinStates[waveIndex][phaseIndex]);
pin_state_t value = pinStates[channelIndex][phaseIndex];
state->multiChannelStateSequence.channels[channelIndex].setState(phaseIndex, value);
}
}
if (state->mode == PM_NORMAL) {
state->multiChannelStateSequence->checkSwitchTimes(phaseCount, 1);
state->multiChannelStateSequence.checkSwitchTimes(phaseCount, 1);
}
}
@ -279,8 +296,9 @@ void copyPwmParameters(PwmConfig *state, int phaseCount, MultiChannelStateSequen
*/
void PwmConfig::weComplexInit(const char *msg, ExecutorInterface *executor,
const int phaseCount,
MultiChannelStateSequence const * seq,
pwm_cycle_callback *pwmCycleCallback, pwm_gen_callback *stateChangeCallback) {
float const *switchTimes,
const int waveCount,
pin_state_t *const*pinStates, pwm_cycle_callback *pwmCycleCallback, pwm_gen_callback *stateChangeCallback) {
UNUSED(msg);
this->executor = executor;
isStopRequested = false;
@ -294,12 +312,14 @@ void PwmConfig::weComplexInit(const char *msg, ExecutorInterface *executor,
firmwareError(CUSTOM_ERR_PWM_2, "too many phases in PWM");
return;
}
efiAssertVoid(CUSTOM_ERR_6583, seq->waveCount > 0, "waveCount should be positive");
efiAssertVoid(CUSTOM_ERR_6583, waveCount > 0, "waveCount should be positive");
this->pwmCycleCallback = pwmCycleCallback;
this->stateChangeCallback = stateChangeCallback;
copyPwmParameters(this, phaseCount, seq);
multiChannelStateSequence.waveCount = waveCount;
copyPwmParameters(this, phaseCount, switchTimes, waveCount, pinStates);
safe.phaseIndex = 0;
safe.periodNt = -1;
@ -318,16 +338,16 @@ void startSimplePwm(SimplePwm *state, const char *msg, ExecutorInterface *execut
return;
}
state->_switchTimes[0] = dutyCycle;
state->_switchTimes[1] = 1;
state->pinStates[0] = TV_FALL;
state->pinStates[1] = TV_RISE;
float switchTimes[] = { dutyCycle, 1 };
pin_state_t pinStates0[] = { TV_FALL, TV_RISE };
state->setSimplePwmDutyCycle(dutyCycle);
pin_state_t *pinStates[1] = { pinStates0 };
state->outputPins[0] = output;
state->setFrequency(frequency);
state->setSimplePwmDutyCycle(dutyCycle); // TODO: DUP ABOVE?
state->weComplexInit(msg, executor, 2, &state->seq, NULL, (pwm_gen_callback*)applyPinState);
state->weComplexInit(msg, executor, 2, switchTimes, 1, pinStates, NULL, (pwm_gen_callback*)applyPinState);
}
void startSimplePwmExt(SimplePwm *state, const char *msg,
@ -365,7 +385,7 @@ void startSimplePwmHard(SimplePwm *state, const char *msg,
void applyPinState(int stateIndex, PwmConfig *state) /* pwm_gen_callback */ {
#if EFI_PROD_CODE
if (!engine->isPwmEnabled) {
for (int channelIndex = 0; channelIndex < state->multiChannelStateSequence->waveCount; channelIndex++) {
for (int channelIndex = 0; channelIndex < state->multiChannelStateSequence.waveCount; channelIndex++) {
OutputPin *output = state->outputPins[channelIndex];
output->setValue(0);
}
@ -374,10 +394,10 @@ void applyPinState(int stateIndex, PwmConfig *state) /* pwm_gen_callback */ {
#endif // EFI_PROD_CODE
efiAssertVoid(CUSTOM_ERR_6663, stateIndex < PWM_PHASE_MAX_COUNT, "invalid stateIndex");
efiAssertVoid(CUSTOM_ERR_6664, state->multiChannelStateSequence->waveCount <= PWM_PHASE_MAX_WAVE_PER_PWM, "invalid waveCount");
for (int channelIndex = 0; channelIndex < state->multiChannelStateSequence->waveCount; channelIndex++) {
efiAssertVoid(CUSTOM_ERR_6664, state->multiChannelStateSequence.waveCount <= PWM_PHASE_MAX_WAVE_PER_PWM, "invalid waveCount");
for (int channelIndex = 0; channelIndex < state->multiChannelStateSequence.waveCount; channelIndex++) {
OutputPin *output = state->outputPins[channelIndex];
int value = state->multiChannelStateSequence->getChannelState(channelIndex, stateIndex);
int value = state->multiChannelStateSequence.getChannelState(channelIndex, stateIndex);
output->setValue(value);
}
}

View File

@ -53,11 +53,13 @@ typedef enum {
class PwmConfig {
public:
PwmConfig();
PwmConfig(float *switchTimes, SingleChannelStateSequence *waves);
void init(float *switchTimes, SingleChannelStateSequence *waves);
void *arg = nullptr;
void weComplexInit(const char *msg,
ExecutorInterface *executor,
const int phaseCount, MultiChannelStateSequence const * seq,
const int phaseCount, float const *switchTimes, const int waveCount, pin_state_t *const*pinStates,
pwm_cycle_callback *pwmCycleCallback,
pwm_gen_callback *callback);
@ -79,7 +81,7 @@ public:
// todo: 'outputPins' should be extracted away from here since technically one can want PWM scheduler without actual pin output
OutputPin *outputPins[PWM_PHASE_MAX_WAVE_PER_PWM];
MultiChannelStateSequence const * multiChannelStateSequence = nullptr;
MultiChannelStateSequence multiChannelStateSequence;
efitick_t togglePwmState();
void stop();
@ -125,10 +127,12 @@ public:
explicit SimplePwm(const char *name);
void setSimplePwmDutyCycle(float dutyCycle) override;
pin_state_t pinStates[2];
SingleChannelStateSequence sr;
SingleChannelStateSequence sr[1];
float _switchTimes[2];
MultiChannelStateSequence seq;
hardware_pwm* hardPwm = nullptr;
private:
SingleChannelStateSequence waveInstance;
};
/**
@ -163,5 +167,6 @@ void startSimplePwmHard(SimplePwm *state, const char *msg,
brain_pin_e brainPin, OutputPin *output, float frequency,
float dutyCycle);
void copyPwmParameters(PwmConfig *state, int phaseCount, MultiChannelStateSequence const * seq);
void copyPwmParameters(PwmConfig *state, int phaseCount, float const *switchTimes,
int waveCount, pin_state_t *const *pinStates);

View File

@ -81,6 +81,7 @@ void TriggerWaveform::initialize(operation_mode_e operationMode) {
gapBothDirections = false;
this->operationMode = operationMode;
privateTriggerDefinitionSize = 0;
triggerShapeSynchPointIndex = 0;
memset(initialState, 0, sizeof(initialState));
memset(switchTimesBuffer, 0, sizeof(switchTimesBuffer));
@ -95,7 +96,7 @@ void TriggerWaveform::initialize(operation_mode_e operationMode) {
}
size_t TriggerWaveform::getSize() const {
return wave.waveCount;
return privateTriggerDefinitionSize;
}
int TriggerWaveform::getTriggerWaveformSynchPointIndex() const {
@ -145,9 +146,9 @@ angle_t TriggerWaveform::getAngle(int index) const {
* See also trigger_central.cpp
* See also getEngineCycleEventCount()
*/
efiAssert(CUSTOM_ERR_ASSERT, wave.waveCount != 0, "shapeSize=0", NAN);
int crankCycle = index / wave.waveCount;
int remainder = index % wave.waveCount;
efiAssert(CUSTOM_ERR_ASSERT, privateTriggerDefinitionSize != 0, "shapeSize=0", NAN);
int crankCycle = index / privateTriggerDefinitionSize;
int remainder = index % privateTriggerDefinitionSize;
auto cycleStartAngle = getCycleDuration() * crankCycle;
auto positionWithinCycle = getSwitchAngle(remainder);
@ -227,9 +228,9 @@ void TriggerWaveform::addEvent(angle_t angle, trigger_wheel_e const channelIndex
#endif
#if EFI_UNIT_TEST
assertIsInBounds(wave.waveCount, triggerSignalIndeces, "trigger shape overflow");
triggerSignalIndeces[wave.waveCount] = channelIndex;
triggerSignalStates[wave.waveCount] = state;
assertIsInBounds(privateTriggerDefinitionSize, triggerSignalIndeces, "trigger shape overflow");
triggerSignalIndeces[privateTriggerDefinitionSize] = channelIndex;
triggerSignalStates[privateTriggerDefinitionSize] = state;
#endif // EFI_UNIT_TEST
@ -241,21 +242,21 @@ void TriggerWaveform::addEvent(angle_t angle, trigger_wheel_e const channelIndex
}
efiAssertVoid(CUSTOM_ERR_6599, angle > 0 && angle <= 1, "angle should be positive not above 1");
if (wave.waveCount > 0) {
if (privateTriggerDefinitionSize > 0) {
if (angle <= previousAngle) {
warning(CUSTOM_ERR_TRG_ANGLE_ORDER, "invalid angle order %s %s: new=%.2f/%f and prev=%.2f/%f, size=%d",
getTrigger_wheel_e(channelIndex),
getTrigger_value_e(state),
angle, angle * getCycleDuration(),
previousAngle, previousAngle * getCycleDuration(),
wave.waveCount);
privateTriggerDefinitionSize);
setShapeDefinitionError(true);
return;
}
}
previousAngle = angle;
if (wave.waveCount == 0) {
wave.waveCount = 1;
if (privateTriggerDefinitionSize == 0) {
privateTriggerDefinitionSize = 1;
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
SingleChannelStateSequence *wave = &this->wave.channels[i];
@ -273,14 +274,14 @@ void TriggerWaveform::addEvent(angle_t angle, trigger_wheel_e const channelIndex
return;
}
int exactMatch = wave.findAngleMatch(angle, wave.waveCount);
int exactMatch = wave.findAngleMatch(angle, privateTriggerDefinitionSize);
if (exactMatch != (int)EFI_ERROR_CODE) {
warning(CUSTOM_ERR_SAME_ANGLE, "same angle: not supported");
setShapeDefinitionError(true);
return;
}
int index = wave.findInsertionAngle(angle, wave.waveCount);
int index = wave.findInsertionAngle(angle, privateTriggerDefinitionSize);
/**
* todo: it would be nice to be able to provide trigger angles without sorting them externally
@ -297,11 +298,11 @@ void TriggerWaveform::addEvent(angle_t angle, trigger_wheel_e const channelIndex
*/
isRiseEvent[index] = TV_RISE == state;
if ((unsigned)index != wave.waveCount) {
if ((unsigned)index != privateTriggerDefinitionSize) {
firmwareError(ERROR_TRIGGER_DRAMA, "are we ever here?");
}
wave.waveCount++;
privateTriggerDefinitionSize++;
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
pin_state_t value = wave.getChannelState(/* channelIndex */i, index - 1);

View File

@ -193,13 +193,6 @@ public:
int triggerSignalStates[PWM_PHASE_MAX_COUNT];
#endif
/**
* waveCount member is total count of shaft events per CAM or CRANK shaft revolution.
* TODO this should be migrated to CRANKshaft revolution, this would go together
* this variable is public for performance reasons (I want to avoid costs of method if it's not inlined)
* but name is supposed to hint at the fact that decoders should not be assigning to it
* Please use "getTriggerSize()" macro or "getSize()" method to read this value
*/
MultiChannelStateSequence wave;
// todo: add a runtime validation which would verify that this field was set properly
@ -208,6 +201,15 @@ public:
bool isRiseEvent[PWM_PHASE_MAX_COUNT];
/**
* Total count of shaft events per CAM or CRANK shaft revolution.
* TODO this should be migrated to CRANKshaft revolution, this would go together
* this variable is public for performance reasons (I want to avoid costs of method if it's not inlined)
* but name is supposed to hint at the fact that decoders should not be assigning to it
* Please use "getTriggerSize()" macro or "getSize()" method to read this value
*/
unsigned int privateTriggerDefinitionSize;
bool useOnlyRisingEdgeForTriggerTemp;
/* (0..1] angle range */
@ -323,4 +325,4 @@ void setToothedWheelConfiguration(TriggerWaveform *s, int total, int skipped, op
#define TRIGGER_WAVEFORM(x) ENGINE(triggerCentral.triggerShape).x
#define getTriggerSize() TRIGGER_WAVEFORM(wave.waveCount)
#define getTriggerSize() TRIGGER_WAVEFORM(privateTriggerDefinitionSize)

View File

@ -168,7 +168,7 @@ void prepareEventAngles(TriggerWaveform *shape,
memset(details->eventAngles, 0, sizeof(details->eventAngles));
// this may be <length for some triggers like symmetrical crank Miata NB
int triggerShapeLength = shape->getSize();
int triggerShapeLength = shape->privateTriggerDefinitionSize;
assertAngleRange(shape->triggerShapeSynchPointIndex, "triggerShapeSynchPointIndex", CUSTOM_TRIGGER_SYNC_ANGLE2);
efiAssertVoid(CUSTOM_TRIGGER_CYCLE, engine->engineCycleEventCount != 0, "zero engineCycleEventCount");

View File

@ -53,7 +53,20 @@ void TriggerEmulatorHelper::handleEmulatorCallback(const int size, const MultiCh
}
}
PwmConfig triggerSignal;
/*
* todo: should we simply re-use instances used by trigger_decoder?
* todo: since we are emulating same shape we are decoding
*/
static pin_state_t pinStates1[PWM_PHASE_MAX_COUNT];
static pin_state_t pinStates2[PWM_PHASE_MAX_COUNT];
static pin_state_t pinStates3[PWM_PHASE_MAX_COUNT];
static SingleChannelStateSequence waves[PWM_PHASE_MAX_WAVE_PER_PWM] = { SingleChannelStateSequence(pinStates1), SingleChannelStateSequence(pinStates2),
SingleChannelStateSequence(pinStates3) };
static SingleChannelStateSequence sr[PWM_PHASE_MAX_WAVE_PER_PWM] = { waves[0], waves[1], waves[2] };
static float pwmSwitchTimesBuffer[PWM_PHASE_MAX_COUNT];
PwmConfig triggerSignal(pwmSwitchTimesBuffer, sr);
static int atTriggerVersion = 0;
@ -106,7 +119,11 @@ static void updateTriggerWaveformIfNeeded(PwmConfig *state DECLARE_ENGINE_PARAME
TriggerWaveform *s = &engine->triggerCentral.triggerShape;
copyPwmParameters(state, s->getSize(), &s->wave);
pin_state_t *pinStates[PWM_PHASE_MAX_WAVE_PER_PWM] = {
s->wave.channels[0].pinStates,
s->wave.channels[1].pinStates,
s->wave.channels[2].pinStates };
copyPwmParameters(state, s->getSize(), s->wave.switchTimes, PWM_PHASE_MAX_WAVE_PER_PWM, pinStates);
state->safe.periodNt = -1; // this would cause loop re-initialization
}
}
@ -124,7 +141,7 @@ static void emulatorApplyPinState(int stateIndex, PwmConfig *state) /* pwm_gen_c
* this callback would invoke the input signal handlers directly
*/
helper.handleEmulatorCallback(state->phaseCount,
*state->multiChannelStateSequence,
state->multiChannelStateSequence,
stateIndex);
}
@ -144,11 +161,16 @@ static void initTriggerPwm(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
TriggerWaveform *s = &engine->triggerCentral.triggerShape;
setTriggerEmulatorRPM(engineConfiguration->triggerSimulatorFrequency PASS_ENGINE_PARAMETER_SUFFIX);
pin_state_t *pinStates[PWM_PHASE_MAX_WAVE_PER_PWM] = {
s->wave.channels[0].pinStates,
s->wave.channels[1].pinStates,
s->wave.channels[2].pinStates };
int phaseCount = s->getSize();
assertIsInBounds(phaseCount - 1, pwmSwitchTimesBuffer, "pwmSwitchTimesBuffer");
triggerSignal.weComplexInit("position sensor",
&engine->executor,
phaseCount, &s->wave,
updateTriggerWaveformIfNeeded, (pwm_gen_callback*)emulatorApplyPinState);
phaseCount, s->wave.switchTimes, PWM_PHASE_MAX_WAVE_PER_PWM,
pinStates, updateTriggerWaveformIfNeeded, (pwm_gen_callback*)emulatorApplyPinState);
hasInitTriggerEmulator = true;
}