void STDMIXER_InitSwitches() { struct Mixer *mix = MIXER_GetAllMixers(); if (Model.limits[mapped_std_channels.throttle].safetysw) mapped_std_channels.switches[SWITCHFUNC_HOLD] = MIXER_SRC(Model.limits[mapped_std_channels.throttle].safetysw); unsigned found_gyro_switch = 0; unsigned found_flymode_switch = 0; unsigned found_drexp_rud_switch = 0; unsigned found_drexp_ail_switch = 0; unsigned found_drexp_ele_switch = 0; for (unsigned idx = 0; idx < NUM_MIXERS; idx++) { if (!MIXER_SRC(mix[idx].src) || MIXER_MUX(&mix[idx]) != MUX_REPLACE) // all none replace mux will be considered as program mix in the Standard mode continue; if (!found_gyro_switch && mix[idx].sw != 0 && (mix[idx].dest == mapped_std_channels.gear || mix[idx].dest == mapped_std_channels.aux2)) { found_gyro_switch = 1; mapped_std_channels.switches[SWITCHFUNC_GYROSENSE] = mix[idx].sw; } else if (!found_drexp_rud_switch && mix[idx].dest == mapped_std_channels.rudd && mix[idx].sw != 0) { found_drexp_rud_switch = 1; mapped_std_channels.switches[SWITCHFUNC_DREXP_RUD] = mix[idx].sw; } else if (!found_drexp_ail_switch && mix[idx].dest == mapped_std_channels.aile && mix[idx].sw != 0) { found_drexp_ail_switch = 1; mapped_std_channels.switches[SWITCHFUNC_DREXP_AIL] = mix[idx].sw; } else if (!found_drexp_ele_switch && mix[idx].dest == mapped_std_channels.elev && mix[idx].sw != 0) { found_drexp_ele_switch = 1; mapped_std_channels.switches[SWITCHFUNC_DREXP_ELE] = mix[idx].sw; } else if (!found_flymode_switch && (mix[idx].dest == NUM_OUT_CHANNELS + 2) && mix[idx].sw != 0) { //virt3 found_flymode_switch = 1; mapped_std_channels.switches[SWITCHFUNC_FLYMODE] = mix[idx].sw; } if (found_flymode_switch && found_gyro_switch && found_drexp_rud_switch && found_drexp_ail_switch && found_drexp_ele_switch) break; // don't need to check the rest } }
const char *set_mux_cb(guiObject_t *obj, int dir, void *data) { (void)obj; (void)data; u8 changed; u8 mux = MIXER_MUX(mp->cur_mixer); mux = GUI_TextSelectHelper(mux, MUX_REPLACE, MUX_LAST-1, dir, 1, 1, &changed); if (changed) { MIXER_SET_MUX(mp->cur_mixer, mux); MIXPAGE_RedrawGraphs(); sync_mixers(); } switch(mux) { case MUX_REPLACE: return _tr("replace"); case MUX_MULTIPLY: return _tr("mult"); case MUX_ADD: return _tr("add"); case MUX_MAX: return _tr("max"); case MUX_MIN: return _tr("min"); case MUX_DELAY: return _tr("delay"); case MUX_LAST: break; } return ""; }
void STDMIXER_SetChannelOrderByProtocol() { const u8 *ch_map = CurrentProtocolChannelMap; if (! ch_map) { // for none protocol, assign any channel to thr is fine ch_map = EATRG0; } CLOCK_ResetWatchdog();// this function might be invoked after loading from template/model file, so feeding the dog in the middle unsigned safetysw = 0; s8 safetyval = 0; for (unsigned ch = 0; ch < 3; ch++) { // only the first 3 channels need to check if (Model.limits[ch].safetysw) { safetysw = Model.limits[ch].safetysw; safetyval = Model.limits[ch].safetyval; } if (ch_map[ch] == INP_THROTTLE) mapped_std_channels.throttle = ch; else if (ch_map[ch] == INP_AILERON) mapped_std_channels.actual_aile = mapped_std_channels.aile = ch; else if (ch_map[ch] == INP_ELEVATOR) mapped_std_channels.actual_elev = mapped_std_channels.elev = ch; } Model.limits[mapped_std_channels.throttle].safetysw = safetysw; Model.limits[mapped_std_channels.throttle].safetyval = safetyval; Model.limits[mapped_std_channels.aile].safetysw = 0; Model.limits[mapped_std_channels.elev].safetysw = 0; Model.limits[mapped_std_channels.aile].safetyval = 0; Model.limits[mapped_std_channels.elev].safetyval = 0; //printf("thro: %d, aile: %d, elev: %d\n\n", mapped_std_channels.throttle, mapped_std_channels.aile, mapped_std_channels.elev); MIXER_SetTemplate(mapped_std_channels.throttle, MIXERTEMPLATE_COMPLEX); MIXER_SetTemplate(mapped_std_channels.aile, MIXERTEMPLATE_CYC1); MIXER_SetTemplate(mapped_std_channels.elev, MIXERTEMPLATE_CYC2); struct Mixer *mix = MIXER_GetAllMixers(); for (unsigned idx = 0; idx < NUM_MIXERS; idx++) { if (mix[idx].src ==0) continue; if (mix[idx].dest == NUM_OUT_CHANNELS + 9) mix[idx].src = 0; // remove all mixers pointing to Virt10, because the Virt10 is reserved in Standard mode else if (MIXER_MUX(&mix[idx]) == MUX_REPLACE && mix[idx].src== INP_THROTTLE && mix[idx].dest < NUM_OUT_CHANNELS) { // src=THR && dest = virt should be pitch's mixer mix[idx].dest = mapped_std_channels.throttle; } } MIXER_SetTemplate(NUM_OUT_CHANNELS + 9, MIXERTEMPLATE_NONE);// remove all mixers pointing to Virt10 as the Virt10 is reserved in Standard mode mapped_std_channels.aile = NUM_OUT_CHANNELS; // virt 1 mapped_std_channels.elev = NUM_OUT_CHANNELS +1; // virt 2 // Simplfied timer sw, only throttle channel output is possible to be selected for (unsigned i = 0; i < NUM_TIMERS; i++) { if (Model.timer[i].src) Model.timer[i].src = mapped_std_channels.throttle + NUM_INPUTS +1; TIMER_Reset(i); } CLOCK_ResetWatchdog(); }
// Roughly verify if current model is a valid simple model unsigned STDMIXER_ValidateTraditionModel() { struct Mixer *mix = MIXER_GetAllMixers(); unsigned thro_mixer_count = 0; unsigned pit_mixer_count = 0; unsigned drexp_mixer_count = 0; unsigned gryo_mixer_count = 0; for (unsigned idx = 0; idx < NUM_MIXERS; idx++) { if (mix[idx].src == 0 || MIXER_MUX(&mix[idx]) != MUX_REPLACE) // all none replace mux will be considered as program mix in the Standard mode continue; if (mix[idx].dest == NUM_OUT_CHANNELS + 9) //mixers pointing to Virt10 as the Virt10 is reserved in Standard mode return 0; if (mix[idx].dest == mapped_std_channels.pitch) pit_mixer_count++; else if (mix[idx].dest == mapped_std_channels.throttle) thro_mixer_count++; else if (mix[idx].dest == mapped_std_channels.gear || mix[idx].dest == mapped_std_channels.aux2) gryo_mixer_count++; else if (mix[idx].dest == mapped_std_channels.aile || mix[idx].dest == mapped_std_channels.elev || mix[idx].dest == mapped_std_channels.rudd) drexp_mixer_count++; } if (thro_mixer_count != THROTTLEMIXER_COUNT || (pit_mixer_count != PITCHMIXER_COUNT && pit_mixer_count != PITCHMIXER_COUNT -1) || gryo_mixer_count < GYROMIXER_COUNT || drexp_mixer_count != DREXPMIXER_COUNT *3) return 0; unsigned cyc_template_count = 0; for (unsigned ch = 0; ch < NUM_OUT_CHANNELS; ch++) { switch(Model.templates[ch]) { case MIXERTEMPLATE_CYC1: case MIXERTEMPLATE_CYC2: case MIXERTEMPLATE_CYC3: cyc_template_count++; break; } } if (cyc_template_count != 3) return 0; return 1; }
void MIXER_ApplyMixer(struct Mixer *mixer, volatile s32 *raw, s32 *orig_value) { s32 value; if (! MIXER_SRC(mixer->src)) return; if (! switch_is_on(mixer->sw, raw)) { // Switch is off, so this mixer is not active return; } //1st: Get source value with trim value = raw[MIXER_SRC(mixer->src)]; //Invert if necessary if (MIXER_SRC_IS_INV(mixer->src)) value = - value; //2nd: apply curve value = CURVE_Evaluate(value, &mixer->curve); //3rd: apply scalar and offset value = value * mixer->scalar / 100 + PCT_TO_RANGE(mixer->offset); //4th: multiplex result switch(MIXER_MUX(mixer)) { case MUX_REPLACE: break; case MUX_MULTIPLY: value = raw[mixer->dest + NUM_INPUTS + 1] * value / CHAN_MAX_VALUE; break; case MUX_ADD: value = raw[mixer->dest + NUM_INPUTS + 1] + value; break; case MUX_MAX: value = raw[mixer->dest + NUM_INPUTS + 1] > value ? raw[mixer->dest + NUM_INPUTS + 1] : value; break; case MUX_MIN: value = raw[mixer->dest + NUM_INPUTS + 1] < value ? raw[mixer->dest + NUM_INPUTS + 1] : value; break; case MUX_DELAY: { //value initially represents 20ths of seconds to cover 60-degrees //convert value to represent #msecs to cover 60-degrees (zero->full) if (value == 0 || orig_value == NULL) { value = raw[mixer->dest + NUM_INPUTS + 1]; break; } value = abs(RANGE_TO_PCT(value)) * 50; //rate represents the maximum travel per iteration (once per MEDIUM_PRIORITY_MSEC) s32 rate = CHAN_MAX_VALUE * MEDIUM_PRIORITY_MSEC / value; value = raw[mixer->dest + NUM_INPUTS + 1]; if (value - *orig_value > rate) value = *orig_value + rate; else if(value - *orig_value < -rate) value = *orig_value - rate; } case MUX_LAST: break; } //5th: apply trim if (MIXER_APPLY_TRIM(mixer)) value = value + (MIXER_SRC_IS_INV(mixer->src) ? -1 : 1) * get_trim(MIXER_SRC(mixer->src)); //Ensure we don't overflow if (value > INT16_MAX) value = INT16_MAX; else if (value < INT16_MIN) value = INT16_MIN; raw[mixer->dest + NUM_INPUTS + 1] = value; }