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 } }
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(); }
int STDMIX_GetMixers(struct Mixer **mixers, u8 dest_channel, int count) { u8 idx; u8 i = 0; struct Mixer *mix = MIXER_GetAllMixers(); for (idx = 0; idx < NUM_MIXERS; idx++) { if (i >= count) break; if (mix[idx].src!= 0 && mix[idx].dest == dest_channel) { mixers[i++] = &mix[idx]; } } while(i < count) mixers[--count] = 0; return i; }
s16 eval_chan_cb(void * data) { (void)data; int i; struct Mixer *mix = MIXER_GetAllMixers(); for (i = 0; i < NUM_MIXERS; i++) { if(MIXER_SRC(mix->src) != 0 && mix->dest != mp->cur_mixer->dest) MIXER_ApplyMixer(mix, mp->raw, NULL); } for (i = 0; i < mp->num_mixers; i++) MIXER_ApplyMixer(&mp->mixer[i], mp->raw, NULL); s16 value = MIXER_ApplyLimits(mp->cur_mixer->dest, &mp->limit, mp->raw, NULL, APPLY_ALL); if (value > CHAN_MAX_VALUE) return CHAN_MAX_VALUE; if (value < CHAN_MIN_VALUE) return CHAN_MIN_VALUE; return value; }
static void _show_page() { u8 h = 12; int i; PAGE_RemoveAllObjects(); PAGE_ShowHeader(_tr("Mixer")); memset(gui, 0, sizeof(*gui)); struct Mixer *mix = MIXER_GetAllMixers(); u8 space = ITEM_HEIGHT + 1; u8 row = space; u8 w1 = 50; u8 w2 = LCD_WIDTH - w1 - ARROW_WIDTH - 4; for (i = 0; row < space * 5; i++) { u8 idx; labelDesc.style = LABEL_LEFT; u8 ch = mp->top_channel + i; if (ch >= Model.num_channels) ch += (NUM_OUT_CHANNELS - Model.num_channels); if (ch < NUM_OUT_CHANNELS) { GUI_CreateButtonPlateText(&gui->limit[i], 0, row, w1, h,&labelDesc, MIXPAGE_ChanNameProtoCB, 0, limitselect_cb, (void *)((long)ch)); } else if(! _is_virt_cyclic(ch)) { GUI_CreateButtonPlateText(&gui->limit[i], 0, row, w1, h,&labelDesc, MIXPAGE_ChanNameProtoCB, 0, virtname_cb, (void *)((long)ch)); } else { GUI_CreateLabelBox(&gui->name[i], 0, row, w1, h, &labelDesc, MIXPAGE_ChanNameProtoCB, NULL, (const void *)((long)ch)); } labelDesc.style = LABEL_CENTER; GUI_CreateButtonPlateText(&gui->tmpl[i], w1 + 2, row, w2, h , &labelDesc, template_name_cb, 0, templateselect_cb, (void *)((long)ch)); row += space; // bug fix: dynamically showing/hiding items won't work in devo10, it causes crash when changing template from none to simple/expo/complex for (idx = 0; idx < NUM_MIXERS; idx++) if (mix[idx].src && mix[idx].dest == ch) break; if (idx != NUM_MIXERS) { enum TemplateType template = MIXER_GetTemplate(ch); labelDesc.style = LABEL_LEFTCENTER; GUI_CreateLabelBox(&gui->src[i], 0, row, w1, h, &labelDesc, show_source, NULL, &mix[idx].src); if (template == MIXERTEMPLATE_EXPO_DR) {
// 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; }
static void _show_page() { // Note for future maintenance: DO NOT use logical view to draw all the channel items at a time for this page: I just // gave it a try, it spent very long time to construct all the 30 items and could trigger watch-dog to reboot !!! static const int XOFFSET = ((LCD_WIDTH - 320) / 2); int init_y = LCD_HEIGHT == 240 ? 44 : 36; int i; if (mp->firstObj) { GUI_RemoveHierObjects(mp->firstObj); mp->firstObj = NULL; } struct Mixer *mix = MIXER_GetAllMixers(); for (i = 0; i < ENTRIES_PER_PAGE; i++) { guiObject_t *obj; u8 idx; int row = init_y + 24 * i; u8 ch = mp->top_channel + i; if (ch >= Model.num_channels) ch += (NUM_OUT_CHANNELS - Model.num_channels); if (ch < NUM_OUT_CHANNELS) { obj = GUI_CreateButton(&gui->name[i].but, XOFFSET+4, row, BUTTON_64x16, MIXPAGE_ChanNameProtoCB, 0x0000, limitselect_cb, (void *)((long)ch)); } else if(! _is_virt_cyclic(ch)) { obj = GUI_CreateButton(&gui->name[i].but, XOFFSET+4, row, BUTTON_64x16, MIXPAGE_ChanNameProtoCB, 0x0000, virtname_cb, (void *)(long)ch); } else { obj = GUI_CreateLabelBox(&gui->name[i].lbl, XOFFSET+4, row, 64, 16, &DEFAULT_FONT, MIXPAGE_ChanNameProtoCB, NULL, (void *)((long)ch)); } if (! mp->firstObj) mp->firstObj = obj; GUI_CreateButton(&gui->tmpl[i], XOFFSET+132, row, BUTTON_64x16, template_name_cb, 0x0000, templateselect_cb, (void *)((long)ch)); for (idx = 0; idx < NUM_MIXERS; idx++) if (mix[idx].src && mix[idx].dest == ch) break; if (idx != NUM_MIXERS) { enum TemplateType template = MIXER_GetTemplate(ch); GUI_CreateLabelBox(&gui->src[i], XOFFSET+68, row, 60, 16, &NARROW_FONT, show_source, NULL, &mix[idx].src); if (template == MIXERTEMPLATE_EXPO_DR) {
static int row_cb(int absrow, int relrow, int y, void *data) { (void)data; u8 idx; struct Mixer *mix = MIXER_GetAllMixers(); int selectable = 2; int channel = absrow; if (channel >= Model.num_channels) channel += (NUM_OUT_CHANNELS - Model.num_channels); if (channel < NUM_OUT_CHANNELS) { labelDesc.style = LABEL_LEFT; GUI_CreateButtonPlateText(&gui->limit[relrow], COL1_X, y, COL1_W, LINE_HEIGHT, &labelDesc, MIXPAGE_ChanNameProtoCB, 0, limitselect_cb, (void *)((long)channel)); } else if(! _is_virt_cyclic(channel)) { GUI_CreateButtonPlateText(&gui->limit[relrow], COL1_X, y, COL1_W, LINE_HEIGHT, &labelDesc, MIXPAGE_ChanNameProtoCB, 0, virtname_cb, (void *)((long)channel)); } else { GUI_CreateLabelBox(&gui->name[relrow], COL1_X, y, COL1_W, LINE_HEIGHT, &labelDesc, MIXPAGE_ChanNameProtoCB, NULL, (const void *)((long)channel)); selectable = 1; } labelDesc.style = LABEL_CENTER; GUI_CreateButtonPlateText(&gui->tmpl[relrow], COL2_X, y, COL2_W, LINE_HEIGHT , &labelDesc, template_name_cb, 0, templateselect_cb, (void *)((long)channel)); for (idx = 0; idx < NUM_MIXERS; idx++) if (mix[idx].src && mix[idx].dest == channel) break; if (idx != NUM_MIXERS) { // don't show source if curve type is fixed, works only for the first mix per channel if(CURVE_TYPE(&mix[idx].curve) != CURVE_FIXED) { labelDesc.style = LABEL_LEFT; GUI_CreateLabelBox(&gui->src[relrow], COL3_X, y, COL3_W , LINE_HEIGHT, &labelDesc, show_source, NULL, &mix[idx].src); } } return selectable; }