Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(radio): Mix delay not working. #4364

Merged
merged 3 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions radio/src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,15 @@ enum MainRequest {

extern uint8_t mainRequestFlags;

#define DELAY_POS_MARGIN 3

PACK(struct SwOn {
PACK(struct MixState {
uint16_t delay:14; // max = 2550
uint8_t activeMix:1;
uint8_t activeExpo:1;
int16_t now; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
int16_t prev;
});

extern SwOn swOn[MAX_MIXERS];
extern MixState mixState[MAX_MIXERS];
extern int32_t act[MAX_MIXERS];

// static variables used in evalFlightModeMixes - moved here so they don't interfere with the stack
Expand Down
83 changes: 52 additions & 31 deletions radio/src/mixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include "hal/trainer_driver.h"
#include "hal/switch_driver.h"

#define DELAY_POS_MARGIN 3

uint8_t s_mixer_first_run_done = false;

int8_t virtualInputsTrims[MAX_INPUTS];
Expand All @@ -38,8 +40,8 @@ int16_t trims[MAX_TRIMS] = {0};
int32_t chans[MAX_OUTPUT_CHANNELS] = {0};
BeepANACenter bpanaCenter = 0;

int32_t act [MAX_MIXERS] = {0};
SwOn swOn [MAX_MIXERS]; // TODO better name later...
int32_t act [MAX_MIXERS] = {0};
MixState mixState [MAX_MIXERS];

uint8_t mixWarning;

Expand Down Expand Up @@ -158,7 +160,7 @@ void applyExpos(int16_t * anas, uint8_t mode, uint8_t ovwrIdx, int16_t ovwrValue
int8_t cur_chn = -1;

for (uint8_t i=0; i<MAX_EXPOS; i++) {
if (mode == e_perout_mode_normal) swOn[i].activeExpo = false;
if (mode == e_perout_mode_normal) mixState[i].activeExpo = false;
ExpoData * ed = expoAddress(i);
if (!EXPO_VALID(ed)) break; // end of list
if (ed->chn == cur_chn)
Expand All @@ -180,7 +182,7 @@ void applyExpos(int16_t * anas, uint8_t mode, uint8_t ovwrIdx, int16_t ovwrValue
v = limit<int32_t>(-1024, v, 1024);
}
if (EXPO_MODE_ENABLE(ed, v)) {
if (mode == e_perout_mode_normal) swOn[i].activeExpo = true;
if (mode == e_perout_mode_normal) mixState[i].activeExpo = true;
cur_chn = ed->chn;

//========== CURVE=================
Expand Down Expand Up @@ -635,7 +637,7 @@ static inline bitfield_channels_t channel_dirty(bitfield_channels_t mask, uint16

static inline bitfield_channels_t upper_channels_mask(uint16_t ch)
{
// take the 2's complement to generate a bit pattern
// take the 1's complement to generate a bit pattern
// that has all bits of 'ch' order and above set
//
// Examples (mask for max 8 channels):
Expand Down Expand Up @@ -731,12 +733,15 @@ void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms)
uint8_t lv_mixWarning = 0;
bitfield_channels_t dirtyChannels = all_channels_dirty;

// Calculate locally and then copy to mixState array - prevent UI seeing phantom values while calculating
bool activeMixes[MAX_MIXERS];

do {
bitfield_channels_t passDirtyChannels = 0;

for (uint8_t i=0; i<MAX_MIXERS; i++) {
if (mode == e_perout_mode_normal && pass == 0)
swOn[i].activeMix = 0;
activeMixes[i] = 0;

MixData * md = mixAddress(i);

Expand All @@ -757,22 +762,26 @@ void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms)
chans[md->destCh] = 0;

//========== FLIGHT MODE && SWITCH =====
bool mixCondition = (md->flightModes != 0 || md->swtch);
bool fmEnabled = (md->flightModes & (1 << mixerCurrentFlightMode)) == 0;
bool mixLineActive = fmEnabled && getSwitch(md->swtch);
delayval_t mixEnabled = (mixLineActive) ? DELAY_POS_MARGIN+1 : 0;

if (mixLineActive) {
// disable mixer using trainer channels if not connected
if (md->srcRaw >= MIXSRC_FIRST_TRAINER &&
md->srcRaw <= MIXSRC_LAST_TRAINER && !is_trainer_connected()) {
mixLineActive = false;
mixCondition = true;
mixEnabled = 0;
}

#if defined(LUA_MODEL_SCRIPTS)
// disable mixer if Lua script is used as source and script was killed
if (md->srcRaw >= MIXSRC_FIRST_LUA && md->srcRaw <= MIXSRC_LAST_LUA) {
div_t qr = div(md->srcRaw - MIXSRC_FIRST_LUA, MAX_SCRIPT_OUTPUTS);
if (scriptInternalData[qr.quot].state != SCRIPT_OK) {
mixLineActive = false;
mixCondition = true;
mixEnabled = 0;
}
}
#endif
Expand All @@ -782,8 +791,10 @@ void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms)
getvalue_t v = 0;

if (mode > e_perout_mode_inactive_flight_mode) {
if (!mixLineActive) continue;
v = getValue(md->srcRaw);
if (mixEnabled)
v = getValue(md->srcRaw);
else
continue;
} else {
mixsrc_t srcRaw = md->srcRaw;
v = getValue(srcRaw);
Expand Down Expand Up @@ -811,43 +822,51 @@ void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms)
}
}
}
if (!mixCondition)
mixEnabled = v;
}

bool applyOffsetAndCurve = true;

//========== DELAYS ===============
delayval_t _swOn = swOn[i].now;
delayval_t _swPrev = swOn[i].prev;

delayval_t v_active = mixLineActive ? v : 0;
delayval_t _swOn = mixState[i].now;
delayval_t _swPrev = mixState[i].prev;
bool swTog = (mixEnabled > _swOn+DELAY_POS_MARGIN || mixEnabled < _swOn-DELAY_POS_MARGIN);

bool swTog = (v_active > _swOn + DELAY_POS_MARGIN || v_active < _swOn - DELAY_POS_MARGIN);
if (mode == e_perout_mode_normal && swTog) {
if (!swOn[i].delay) { swOn[i].prev = _swOn; }
swOn[i].now = v_active;
swOn[i].delay = (v_active > _swOn ? md->delayUp : md->delayDown) * 10;
if (!mixState[i].delay)
_swPrev = _swOn;
mixState[i].delay = (mixEnabled > _swOn ? md->delayUp : md->delayDown) * 10;
mixState[i].now = mixEnabled;
mixState[i].prev = _swPrev;
}
if (mode == e_perout_mode_normal && swOn[i].delay > 0) {
swOn[i].delay = max<int16_t>(0, (int16_t)swOn[i].delay - tick10ms);
v = _swPrev;
if (mode == e_perout_mode_normal && mixState[i].delay > 0) {
mixState[i].delay = max<int16_t>(0, (int16_t)mixState[i].delay - tick10ms);
// Freeze value until delay expires
if (!mixCondition)
v = _swPrev;
else if (mixEnabled)
continue;
}
else {
if (mode == e_perout_mode_normal) {
swOn[i].now = swOn[i].prev = v_active;
mixState[i].now = mixState[i].prev = mixEnabled;
}
if (!mixLineActive) {
if (!mixEnabled) {
if ((md->speedDown || md->speedUp) && md->mltpx != MLTPX_REPL) {
v = (md->mltpx == MLTPX_ADD ? 0 : RESX);
applyOffsetAndCurve = false;
} else {
if (mixCondition) {
v = (md->mltpx == MLTPX_ADD ? 0 : RESX);
applyOffsetAndCurve = false;
}
} else if (mixCondition) {
continue;
}
}
}

if (mode == e_perout_mode_normal && (mixLineActive || swOn[i].delay)) {
if (mode == e_perout_mode_normal && (!mixCondition || mixEnabled || mixState[i].delay)) {
if (md->mixWarn) lv_mixWarning |= 1 << (md->mixWarn - 1);
swOn[i].activeMix = true;
activeMixes[i] = true;
}

if (applyOffsetAndCurve) {
Expand Down Expand Up @@ -932,8 +951,8 @@ void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms)
case MLTPX_REPL:
*ptr = dv;
if (mode == e_perout_mode_normal) {
for (uint8_t m=i-1; m<MAX_MIXERS && mixAddress(m)->destCh==md->destCh; m--)
swOn[m].activeMix = false;
for (int8_t m = i - 1; m >= 0 && mixAddress(m)->destCh == md->destCh; m--)
activeMixes[m] = false;
}
break;
case MLTPX_MUL:
Expand Down Expand Up @@ -987,14 +1006,16 @@ void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms)
// *ptr=limit( int32_t(int32_t(-1)<<23), *ptr, int32_t(int32_t(1)<<23)); // limit code cost 72 bytes
// *ptr=limit( int32_t((-32767+RESXl)<<8), *ptr, int32_t((32767-RESXl)<<8)); // limit code cost 80 bytes
#endif

} //endfor mixers

tick10ms = 0;
dirtyChannels &= passDirtyChannels;

} while (++pass < 5 && dirtyChannels);

for (uint8_t i=0; i<MAX_MIXERS; i++)
mixState[i].activeMix = activeMixes[i];

mixWarning = lv_mixWarning;
}

Expand Down
4 changes: 2 additions & 2 deletions radio/src/opentx.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,12 +459,12 @@ void moveTrimsToOffsets();

inline bool isExpoActive(uint8_t expo)
{
return swOn[expo].activeExpo;
return mixState[expo].activeExpo;
}

inline bool isMixActive(uint8_t mix)
{
return swOn[mix].activeMix;
return mixState[mix].activeMix;
}

enum FunctionsActive {
Expand Down
2 changes: 1 addition & 1 deletion radio/src/tests/gtests.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ inline void MIXER_RESET()
memset(chans, 0, sizeof(chans));
memset(ex_chans, 0, sizeof(ex_chans));
memset(act, 0, sizeof(act));
memset(swOn, 0, sizeof(swOn));
memset(mixState, 0, sizeof(mixState));
mixerCurrentFlightMode = lastFlightMode = 0;
lastAct = 0;
logicalSwitchesReset();
Expand Down
2 changes: 1 addition & 1 deletion radio/src/tests/mixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ TEST_F(MixerTest, DelayOnSwitch2)
g_model.mixData[0].mltpx = MLTPX_ADD;
g_model.mixData[0].srcRaw = MIXSRC_FIRST_SWITCH;
g_model.mixData[0].weight = 100;
g_model.mixData[0].swtch = SWSRC_ON;
// g_model.mixData[0].swtch = SWSRC_ON;
g_model.mixData[0].delayUp = 50;
g_model.mixData[0].delayDown = 50;

Expand Down