const char *set_drsource_cb(guiObject_t *obj, int dir, void *data) { (void) obj; u8 *source = (u8 *)data; u8 is_neg = MIXER_SRC_IS_INV(*source); u8 changed; u8 oldsrc = *source; *source = GUI_TextSelectHelper(MIXER_SRC(*source), 0, NUM_SOURCES, dir, 1, 1, &changed); MIXER_SET_SRC_INV(*source, is_neg); if (changed) { sync_mixers(); if ((!! MIXER_SRC(oldsrc)) ^ (!! MIXER_SRC(*source))) { // bug fix (issues #191) : only invoke _update_rate_widgets() for expo template if (mp->cur_template == MIXERTEMPLATE_EXPO_DR) { if(data == &mp->mixer[1].sw) _update_rate_widgets(0); else if(data == &mp->mixer[2].sw) _update_rate_widgets(1); } } else { MIXPAGE_RedrawGraphs(); } } GUI_TextSelectEnablePress((guiTextSelect_t *)obj, MIXER_SRC(*source)); return INPUT_SourceName(mp->tmpstr, *source); }
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_source_cb(guiObject_t *obj, int dir, void *data) { (void) obj; u8 *source = (u8 *)data; if (!GUI_IsTextSelectEnabled(obj) ) { strcpy(mp->tmpstr, _tr("None")); return mp->tmpstr; } u8 is_neg = MIXER_SRC_IS_INV(*source); u8 changed; *source = GUI_TextSelectHelper(MIXER_SRC(*source), 1, NUM_SOURCES, dir, 1, 1, &changed); MIXER_SET_SRC_INV(*source, is_neg); if (changed) { if(mp->cur_template == MIXERTEMPLATE_COMPLEX) { guiObject_t *trim = _get_obj(COMPLEX_TRIM, 0); if(trim) { if (MIXER_SourceHasTrim(MIXER_SRC(mp->mixer[0].src))) GUI_SetHidden(trim, 0); else GUI_SetHidden(trim, 1); } } sync_mixers(); MIXPAGE_RedrawGraphs(); } GUI_TextSelectEnablePress((guiTextSelect_t *)obj, MIXER_SRC(*source)); return INPUT_SourceName(mp->tmpstr, *source); }
void sync_mixers() { switch(mp->cur_template) { case MIXERTEMPLATE_NONE: case MIXERTEMPLATE_CYC1: case MIXERTEMPLATE_CYC2: case MIXERTEMPLATE_CYC3: mp->num_mixers = 0; break; case MIXERTEMPLATE_SIMPLE: mp->mixer[0].sw = 0; MIXER_SET_MUX(&mp->mixer[0], MUX_REPLACE); mp->num_mixers = 1; break; case MIXERTEMPLATE_COMPLEX: mp->num_mixers = mp->num_complex_mixers; break; case MIXERTEMPLATE_EXPO_DR: mp->num_mixers = 1; if (MIXER_SRC(mp->mixer[1].sw)) { mp->num_mixers++; mp->mixer[1].src = mp->mixer[0].src; mp->mixer[1].dest = mp->mixer[0].dest; MIXER_SET_MUX(&mp->mixer[1], MUX_REPLACE); mp->mixer[1].offset = 0; MIXER_SET_APPLY_TRIM(&mp->mixer[1], MIXER_APPLY_TRIM(&mp->mixer[0])); } else { mp->mixer[1].src = 0; } if (mp->link_curves & 0x01) mp->mixer[1].curve = mp->mixer[0].curve; if (MIXER_SRC(mp->mixer[2].sw)) { mp->num_mixers++; mp->mixer[2].src = mp->mixer[0].src; mp->mixer[2].dest = mp->mixer[0].dest; MIXER_SET_MUX(&mp->mixer[2], MUX_REPLACE); mp->mixer[2].offset = 0; MIXER_SET_APPLY_TRIM(&mp->mixer[2], MIXER_APPLY_TRIM(&mp->mixer[0])); } else { mp->mixer[2].src = 0; } if (mp->link_curves & 0x02) mp->mixer[2].curve = mp->mixer[0].curve; MIXER_SET_MUX(&mp->mixer[0], MUX_REPLACE); mp->mixer[0].offset = 0; mp->mixer[0].sw = 0; break; } }
static const char *set_source_cb(guiObject_t *obj, int dir, void *data) { (void) obj; u8 *source = (u8 *)data; *source = GUI_TextSelectHelper(MIXER_SRC(*source), 0, NUM_SOURCES, dir, 1, 1, NULL); return INPUT_SourceName(tp->tmpstr, MIXER_MapChannel(*source)); }
static void _update_rate_widgets(u8 idx) { u8 mix = idx + 1; guiObject_t *link = GUI_GetScrollableObj(&gui->scrollable, idx ? EXPO_LINK2 : EXPO_LINK1, 0); guiObject_t *curve = GUI_GetScrollableObj(&gui->scrollable, idx ? EXPO_CURVE2 : EXPO_CURVE1, 0); guiObject_t *scale = GUI_GetScrollableObj(&gui->scrollable, idx ? EXPO_SCALE2 : EXPO_SCALE1, 0); if (MIXER_SRC(mp->mixer[mix].sw)) { if(link) GUI_ButtonEnable(link, 1); if(curve) { if(mp->link_curves & mix ) { GUI_TextSelectEnable((guiTextSelect_t *)curve, 0); } else { GUI_TextSelectEnable((guiTextSelect_t *)curve, 1); } } if(scale) GUI_TextSelectEnable((guiTextSelect_t *)scale, 1); } else { if(link) GUI_ButtonEnable(link, 0); if(curve) GUI_TextSelectEnable((guiTextSelect_t *)curve, 0); if(scale) GUI_TextSelectEnable((guiTextSelect_t *)scale, 0); } }
int compact_mixers() { unsigned max = NUM_MIXERS; unsigned i = 0; unsigned j; while(i < max) { unsigned src = MIXER_SRC(Model.mixers[i].src); if(! src || Model.templates[Model.mixers[i].dest] == MIXERTEMPLATE_NONE || Model.templates[Model.mixers[i].dest] == MIXERTEMPLATE_CYC1 || Model.templates[Model.mixers[i].dest] == MIXERTEMPLATE_CYC2 || Model.templates[Model.mixers[i].dest] == MIXERTEMPLATE_CYC3) { //Found an empty space so move all following mixers down 1 and decrease max for (j = i + 1; j < max; j++) { Model.mixers[j - 1] = Model.mixers[j]; } max--; } else { //Found a used mixer so go to the next one i++; } } //Zero outunused mixers memset(Model.mixers + max, 0, sizeof(struct Mixer) * (NUM_MIXERS - max)); return i; }
static int complex_row_cb(int absrow, int relrow, int y, void *data) { const char *label = NULL; void *tgl = NULL; void *value = NULL; data = NULL; int x = 0; int w = LEFT_VIEW_WIDTH; if (absrow + COMMON_LAST == COMPLEX_TRIM) { GUI_CreateButtonPlateText(&gui->value[relrow].but, x, y, w, ITEM_HEIGHT, &labelDesc, show_trim_cb, 0x0000, toggle_trim_cb, NULL); if (! MIXER_SourceHasTrim(MIXER_SRC(mp->mixer[0].src))) GUI_SetHidden((guiObject_t *)&gui->label[relrow], 1); return 1; } switch(absrow + COMMON_LAST) { case COMPLEX_MIXER: label = _tr_noop("Mixers"); value = set_nummixers_cb; break; case COMPLEX_PAGE: label = _tr_noop("Page"); tgl = reorder_cb; value = set_mixernum_cb; break; case COMPLEX_SWITCH: label = _tr_noop("Switch"); tgl = sourceselect_cb; value = set_drsource_cb; data = &mp->cur_mixer->sw; break; case COMPLEX_MUX: label = _tr_noop("Mux"); value = set_mux_cb; break; case COMPLEX_SRC: label = _tr_noop("Src"); tgl = sourceselect_cb; value = set_source_cb; data = &mp->cur_mixer->src; break; case COMPLEX_CURVE: label = _tr_noop("Curve"); tgl = curveselect_cb; value = set_curvename_cb; data = mp->cur_mixer; break; case COMPLEX_SCALE: label = _tr_noop("Scale"); value = set_number100_cb; data = &mp->cur_mixer->scalar; break; case COMPLEX_OFFSET: label = _tr_noop("Offset"); value = set_number100_cb; data = &mp->cur_mixer->offset; break; } labelDesc.style = LABEL_LEFTCENTER; GUI_CreateLabelBox(&gui->label[relrow], x, y, w, ITEM_HEIGHT, &labelDesc, NULL, NULL, _tr(label)); labelDesc.style = LABEL_CENTER; GUI_CreateTextSelectPlate(&gui->value[relrow].ts, x, y + ITEM_HEIGHT + 1, w, ITEM_HEIGHT, &labelDesc, tgl, value, data); if (absrow + COMMON_LAST == COMPLEX_SRC) set_src_enable(CURVE_TYPE(&mp->cur_mixer->curve)); return 1; }
void sourceselect_cb(guiObject_t *obj, void *data) { u8 *source = (u8 *)data; if (MIXER_SRC(*source)) { MIXER_SET_SRC_INV(*source, ! MIXER_SRC_IS_INV(*source)); GUI_Redraw(obj); MIXPAGE_RedrawGraphs(); } }
void toggle_source_cb(guiObject_t *obj, void *data) { u8 idx = (long)data; struct Timer *timer = &Model.timer[idx]; if(MIXER_SRC(timer->src)) { MIXER_SET_SRC_INV(timer->src, ! MIXER_SRC_IS_INV(timer->src)); TIMER_Reset(idx); GUI_Redraw(obj); } }
static void show_iconsel_page(int SelectedIcon) { struct ImageMap img; int toggleinput = MIXER_SRC(Model.pagecfg2.elem[tp->tglidx].src); PAGE_RemoveAllObjects(); PAGE_ShowHeader(INPUT_SourceNameAbbrevSwitch(tempstring, toggleinput)); GUI_CreateButton(&gui->revert, LCD_WIDTH-96-8, 4, BUTTON_96, revert_str_cb, revert_cb, NULL); // Show name of source for toggle icon // style the switch textbox struct LabelDesc outline = { .font = DEFAULT_FONT.font, .style = LABEL_TRANSPARENT, .font_color = DEFAULT_FONT.font_color, .fill_color = DEFAULT_FONT.fill_color, .outline_color = DEFAULT_FONT.outline_color }; GUI_CreateRect(&gui->toggleframe, 80+80*SelectedIcon, 39, 77, 33, &outline); GUI_CreateLabelBox(&gui->switchbox, 4, 47, 70, 22, &NORMALBOX_FONT, NULL, NULL, INPUT_SourceNameAbbrevSwitch(tempstring, Model.pagecfg2.elem[tp->tglidx].src)); int num_positions = INPUT_NumSwitchPos(toggleinput); if(num_positions < 2) num_positions = 2; GUI_CreateLabelBox(&gui->togglelabel[0], 94, 50, 30, 14, &LABEL_FONT, NULL, NULL, _tr("Pos 0")); img = TGLICO_GetImage(Model.pagecfg2.elem[tp->tglidx].extra[0]); GUI_CreateImageOffset(&gui->toggleicon[0], 124, 40, TOGGLEICON_WIDTH, TOGGLEICON_HEIGHT, img.x_off, img.y_off, img.file, SelectedIcon == 0 ? tglico_reset_cb : tglico_setpos_cb, (void *)0L); GUI_CreateLabelBox(&gui->togglelabel[1], 174, 50, 30, 14, &LABEL_FONT, NULL, NULL, _tr("Pos 1")); img = TGLICO_GetImage(Model.pagecfg2.elem[tp->tglidx].extra[1]); GUI_CreateImageOffset(&gui->toggleicon[1], 204, 40, TOGGLEICON_WIDTH, TOGGLEICON_HEIGHT, img.x_off, img.y_off, img.file, SelectedIcon == 1 ? tglico_reset_cb : tglico_setpos_cb, (void *)1L); if (num_positions == 3) { GUI_CreateLabelBox(&gui->togglelabel[2], 254, 50, 30, 14, &LABEL_FONT, NULL, NULL, _tr("Pos 2")); img = TGLICO_GetImage(Model.pagecfg2.elem[tp->tglidx].extra[2]); GUI_CreateImageOffset(&gui->toggleicon[2], 284, 40, TOGGLEICON_WIDTH, TOGGLEICON_HEIGHT, img.x_off, img.y_off, img.file, SelectedIcon == 2 ? tglico_reset_cb : tglico_setpos_cb, (void *)2L); } int count = get_toggle_icon_count(); int max_scroll = (count + NUM_SYMBOL_COLS - 1) / NUM_SYMBOL_COLS - (NUM_SYMBOL_ROWS - 1); if (max_scroll > 1) GUI_CreateScrollbar(&gui->scrollbar, LCD_WIDTH-16, 80, LCD_HEIGHT-80, max_scroll, NULL, scroll_cb, (void *)(long)SelectedIcon); show_icons(SelectedIcon, 0); } void PAGE_ToggleEditInit(int page) { tp->tglidx = page; memcpy(tp->tglicons, Model.pagecfg2.elem[tp->tglidx].extra, sizeof(tp->tglicons)); show_iconsel_page(0); }
static void navigate_toggleicons(s8 direction) { int toggleinput = MIXER_SRC(Model.pagecfg2.elem[tp->tglidx].src); int num_positions = INPUT_NumSwitchPos(toggleinput); if(num_positions < 2) num_positions = 2; current_toggleicon += direction; if (current_toggleicon < 0) current_toggleicon = num_positions; else if (current_toggleicon > num_positions) current_toggleicon = 0; show_iconsel_page(current_toggleicon); }
const char *_set_src_cb(guiTextSelect_t *obj, u8 *src, int dir, int idx, int source) { u8 changed; if (Model.mixer_mode == MIXER_STANDARD && Model.type == MODELTYPE_HELI) { //Improvement: only to intelligent switch setting for heli type in standard mode int is_neg = MIXER_SRC_IS_INV(*src); int step = mapped_std_channels.throttle + NUM_INPUTS +1; int newsrc = GUI_TextSelectHelper(MIXER_SRC(*src), 0, step, dir, step, step, &changed); MIXER_SET_SRC_INV(newsrc, is_neg); *src = newsrc; } else { if (source <= INP_NONE) *src = INPUT_SelectSource(*src, dir, &changed); else *src = INPUT_SelectInput(*src, source, &changed); } if (changed) { TIMER_Reset(idx); } GUI_TextSelectEnablePress(obj, MIXER_SRC(*src)); return INPUT_SourceName(tempstring, *src); }
u8 curpos_cb(s16 *x, s16 *y, u8 pos, void *data) { if (pos != 0) return 0; *x = mp->raw[MIXER_SRC(mp->cur_mixer->src)]; if (*x > CHAN_MAX_VALUE) *x = CHAN_MAX_VALUE; else if (*x < CHAN_MIN_VALUE) *x = CHAN_MIN_VALUE; *y = eval_mixer_cb(*x, data); return 1; }
int MIXER_GetMixers(int ch, struct Mixer *mixers, int count) { int idx = 0; int i; for(i = 0; i < NUM_MIXERS; i++) { if (MIXER_SRC(Model.mixers[i].src) && Model.mixers[i].dest == ch) { mixers[idx++] = Model.mixers[i]; if(idx == count) return count; } } return idx; }
unsigned switch_is_on(unsigned sw, volatile s32 *raw) { unsigned is_neg = MIXER_SRC_IS_INV(sw); sw = MIXER_SRC(sw); if(sw == 0) { // No switch selected is the same as an on switch return 1; } s32 value = raw[sw]; if (is_neg) value = - value; return (value > 0); }
int MIXER_SetMixers(struct Mixer *mixers, int count) { int i; if (count) { int mixer_count = 0; unsigned dest = mixers[0].dest; //Determine if we have enough free mixers for (i = 0; i < NUM_MIXERS; i++) { if (MIXER_SRC(Model.mixers[i].src) && Model.mixers[i].dest != dest) mixer_count++; } if (mixer_count + count > NUM_MIXERS) { printf("Need %d free mixers, but only %d are available\n", count, NUM_MIXERS - mixer_count); return 0; } //Remove all mixers for this channel for (i = 0; i < NUM_MIXERS; i++) { if (MIXER_SRC(Model.mixers[i].src) && Model.mixers[i].dest == dest) Model.mixers[i].src = 0; } } unsigned pos = compact_mixers(); for (i = 0; i < count; i++) { if (! MIXER_SRC(mixers[i].src) && CURVE_TYPE(&mixers[i].curve) == CURVE_FIXED) { mixers[i].src = mixers[i].sw || 1; } if (MIXER_SRC(mixers[i].src)) { Model.mixers[pos] = mixers[i]; if(Model.templates[mixers[i].dest] != MIXERTEMPLATE_COMPLEX) { //Always apply the trim if the template is not 'complex' MIXER_SET_APPLY_TRIM(&Model.mixers[pos], 1); } pos++; } } fix_mixer_dependencies(pos); return 1; }
static const char *set_source_helper(guiObject_t *obj, void *data, int changed) { (void) obj; u8 *source = (u8 *)data; if (!GUI_IsTextSelectEnabled(obj) ) { tempstring_cpy(_tr("None")); return tempstring; } if (changed) { if(mp->cur_template == MIXERTEMPLATE_COMPLEX) { guiObject_t *trim = _get_obj(COMPLEX_TRIM, 0); if(trim) { if (MIXER_SourceHasTrim(MIXER_SRC(mp->mixer[0].src))) GUI_SetHidden(trim, 0); else GUI_SetHidden(trim, 1); } } sync_mixers(); MIXPAGE_RedrawGraphs(); } GUI_TextSelectEnablePress((guiTextSelect_t *)obj, MIXER_SRC(*source)); return INPUT_SourceName(tempstring, *source); }
static const char *set_switch_cb(guiObject_t *obj, int dir, void *data) { if(! GUI_IsTextSelectEnabled(obj)){ return _tr("None"); } u8 *source = (u8 *)data; u8 changed; u8 val = MIXER_SRC(*source); int newval = GUI_TextSelectHelper(val, 0, NUM_SOURCES, dir, 1, 1, &changed); newval = INPUT_GetAbbrevSource(val, newval, dir); if (val != newval) { val = newval; *source = val; } return INPUT_SourceNameAbbrevSwitch(tp->tmpstr, *source); }
s32 MIXER_ApplyLimits(unsigned channel, struct Limit *limit, volatile s32 *_raw, volatile s32 *_Channels, enum LimitMask flags) { int applied_safety = 0; s32 value = _raw[NUM_INPUTS + 1 + channel] + get_trim(NUM_INPUTS + 1 + channel); if (channel >= NUM_OUT_CHANNELS) return value; if ((flags & APPLY_SAFETY) && MIXER_SRC(limit->safetysw) && switch_is_on(limit->safetysw, _raw)) { applied_safety = 1; value = PCT_TO_RANGE(Model.limits[channel].safetyval); } if (flags & APPLY_SCALAR) { if (value >= 0 || limit->servoscale_neg == 0) value = (s32)value * limit->servoscale / 100; else value = (s32)value * limit->servoscale_neg / 100; } if ((flags & APPLY_REVERSE) && (limit->flags & CH_REVERSE)) { value = -value; } if (flags & APPLY_SUBTRIM) value += PCT_TO_RANGE(limit->subtrim) / 10; if (! applied_safety) { //degrees / 100msec if (_Channels && (flags & APPLY_SPEED) && limit->speed) { s32 rate = CHAN_MAX_VALUE * limit->speed / 60 * MEDIUM_PRIORITY_MSEC / 100; if (value - _Channels[channel] > rate) value = _Channels[channel] + rate; else if(value - _Channels[channel] < -rate) value = _Channels[channel] - rate; } } if (flags & APPLY_LIMITS) { if (value > PCT_TO_RANGE(limit->max)) value = PCT_TO_RANGE(limit->max); else if( value < PCT_TO_RANGE(-(int)limit->min)) value = PCT_TO_RANGE(-(int)limit->min); } else { if (value > INT16_MAX) value = INT16_MAX; else if (value < INT16_MIN) value = INT16_MIN; } return value; }
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_iconsel_page(int SelectedIcon) { GUI_RemoveAllObjects(); memset(gui, 0, sizeof(*gui)); current_toggleicon = SelectedIcon; int toggleinput = MIXER_SRC(Model.pagecfg2.elem[tp->tglidx].src); //Header PAGE_ShowHeader(INPUT_SourceNameAbbrevSwitch(tempstring, toggleinput)); labelDesc.style = LABEL_CENTER; GUI_CreateButtonPlateText(&gui->revert, REVERT_X, 0, REVERT_W, HEADER_WIDGET_HEIGHT, &labelDesc, NULL, 0, revert_cb, (void *)_tr("Revert")); #if SEPARATOR GUI_CreateRect(&gui->separator, SEPARATOR_X, HEADER_WIDGET_HEIGHT, 1, LCD_HEIGHT-HEADER_HEIGHT, &labelDesc); #endif int row = ROW_Y; int num_positions = INPUT_NumSwitchPos(toggleinput); if(num_positions < 2) num_positions = 2; static const char * const tglidx[3] = {"0:", "1:", "2:"}; labelDesc.style = LABEL_INVERTED; for (int i = 0; i < num_positions; i++) { GUI_CreateLabelBox(&gui->togglelabel[i], LABEL_X, row, LABEL_W, LABEL_H, SelectedIcon == i ? &labelDesc : &DEFAULT_FONT, NULL, NULL, tglidx[i]); #ifdef HAS_CHAR_ICONS GUI_CreateLabelBox(&gui->toggleicon[i], ICON_X, row, ICON_W, LABEL_H, &DEFAULT_FONT, TGLICO_font_cb, NULL, (void *)(long)Model.pagecfg2.elem[tp->tglidx].extra[i]); #else struct ImageMap img = TGLICO_GetImage(Model.pagecfg2.elem[tp->tglidx].extra[i]); GUI_CreateImageOffset(&gui->toggleicon[i], ICON_X, row, ICON_W, LABEL_H, img.x_off, img.y_off, img.file, NULL, //SelectedIcon == 0 ? tglico_reset_cb : tglico_setpos_cb, (void *)(long)i); #endif row += ROW_INCREMENT; } int count = get_toggle_icon_count(); int rows = (count + NUM_COLS - 1) / NUM_COLS; GUI_CreateScrollable(&gui->scrollable, SCROLLABLE_X, SCROLLABLE_Y, LCD_WIDTH - SCROLLABLE_X, SCROLLABLE_H, SCROLL_ROW_H, rows, row_cb, NULL, NULL, (void *)(long)SelectedIcon); }
void MIXER_EvalMixers(volatile s32 *raw) { int i; s32 orig_value[NUM_CHANNELS]; //3rd step: apply mixers for (i = 0; i < NUM_CHANNELS; i++) { orig_value[i] = raw[i + NUM_INPUTS + 1]; } for (i = 0; i < NUM_MIXERS; i++) { struct Mixer *mixer = &Model.mixers[i]; // Linkers are pre-ordred such that we can process them in order if (MIXER_SRC(mixer->src) == 0) { // Mixer is not defined so we are done break; } //apply_mixer updates mixed[mixer->dest] MIXER_ApplyMixer(mixer, raw, &orig_value[mixer->dest]); } }
unsigned find_dependencies(unsigned ch, unsigned *deps) { unsigned found = 0; unsigned i; struct Mixer *mixer; for (i = 0; i < NUM_SOURCES; i++) deps[i] = 0; for (mixer = Model.mixers; mixer < Model.mixers + NUM_MIXERS; mixer++) { if (MIXER_SRC(mixer->src) && mixer->dest == ch) { found = 1; if (MIXER_SRC(mixer->src) > NUM_SOURCES && MIXER_SRC(mixer->src) != NUM_SOURCES + 1 + ch) { deps[MIXER_SRC(mixer->src) - NUM_SOURCES - 1] = 1; } if (MIXER_SRC(mixer->sw) > NUM_SOURCES && MIXER_SRC(mixer->sw) != NUM_SOURCES + 1 + ch) { deps[MIXER_SRC(mixer->sw) - NUM_SOURCES - 1] = 1; } } } return found; }
static const char *dlgts_cb(guiObject_t *obj, int dir, void *data) { (void)obj; int idx = (long)data; int type = ELEM_TYPE(pc.elem[idx]); switch (type) { case ELEM_SMALLBOX: case ELEM_BIGBOX: { pc.elem[idx].src = GUI_TextSelectHelper(pc.elem[idx].src, 0, NUM_RTC + NUM_TELEM + NUM_TIMERS + NUM_CHANNELS, dir, 1, 1, NULL); return GetBoxSource(lp.tmp, pc.elem[idx].src); } case ELEM_BAR: pc.elem[idx].src = GUI_TextSelectHelper(pc.elem[idx].src, 0, NUM_CHANNELS, dir, 1, 1, NULL); return INPUT_SourceName(lp.tmp, pc.elem[idx].src ? pc.elem[idx].src + NUM_INPUTS : 0); case ELEM_TOGGLE: { int val = MIXER_SRC(pc.elem[idx].src); int newval = GUI_TextSelectHelper(val, 0, NUM_SOURCES, dir, 1, 1, NULL); newval = INPUT_GetAbbrevSource(val, newval, dir); if (val != newval) { val = newval; pc.elem[idx].src = val; } return INPUT_SourceNameAbbrevSwitch(lp.tmp, pc.elem[idx].src); } case ELEM_HTRIM: case ELEM_VTRIM: pc.elem[idx].src = GUI_TextSelectHelper(pc.elem[idx].src, 0, NUM_TRIMS, dir, 1, 1, NULL); if (pc.elem[idx].src == 0) return _tr("None"); sprintf(lp.tmp, "%s%d", _tr("Trim"),pc.elem[idx].src); return lp.tmp; } return ""; }
void TIMER_Update() { unsigned i; unsigned chan_val = 0; u32 t = CLOCK_getms(); if (PROTOCOL_WaitingForSafe()) return; if( Transmitter.power_alarm > 0 ) TIMER_Power(); for (i = 0; i < NUM_TIMERS; i++) { if (Model.timer[i].src) { s16 val; if (MIXER_SRC(Model.timer[i].src) <= NUM_INPUTS) { volatile s16 *raw = MIXER_GetInputs(); val = raw[MIXER_SRC(Model.timer[i].src)]; } else { val = MIXER_GetChannel(Model.timer[i].src - NUM_INPUTS - 1, APPLY_SAFETY); } if (MIXER_SRC_IS_INV(Model.timer[i].src)) val = -val; if (Model.timer[i].type == TIMER_STOPWATCH_PROP || Model.timer[i].type == TIMER_COUNTDOWN_PROP) { chan_val = RANGE_TO_PCT(abs(val)); if (chan_val > 100) chan_val = 100; } else { unsigned new_state = (val - CHAN_MIN_VALUE > (CHAN_MAX_VALUE - CHAN_MIN_VALUE) / 20) ? 1 : 0; if (new_state != timer_state[i]) { if (new_state) last_time[i] = t; timer_state[i] = new_state; } } } if (timer_state[i]) { s32 delta = t - last_time[i]; if (Model.timer[i].type == TIMER_STOPWATCH_PROP || Model.timer[i].type == TIMER_COUNTDOWN_PROP) { delta = delta * chan_val / 100; } if (Model.timer[i].type == TIMER_PERMANENT) { timer_val[i] += delta; if( timer_val[i] >= 359999900) // Reset when 99h59mn59sec timer_val[i] = 0 ; Model.timer[i].val = timer_val[i]; } else if (Model.timer[i].type == TIMER_STOPWATCH || Model.timer[i].type == TIMER_STOPWATCH_PROP) { timer_val[i] += delta; } else { s32 warn_time; // start to beep for each prealert_interval at the last prealert_time(seconds) if (Transmitter.countdown_timer_settings.prealert_time != 0 && Transmitter.countdown_timer_settings.prealert_interval != 0 && timer_val[i] > Transmitter.countdown_timer_settings.prealert_interval && timer_val[i] < (s32)Transmitter.countdown_timer_settings.prealert_time + 1000) { // give extra 1seconds warn_time = ((timer_val[i] / Transmitter.countdown_timer_settings.prealert_interval) * Transmitter.countdown_timer_settings.prealert_interval); if (timer_val[i] > warn_time && (timer_val[i] - delta) <= warn_time) { MUSIC_Play(MUSIC_TIMER_WARNING); } } // Beep once for each timeup_interval past 0 if (timer_val[i] < 0 && Transmitter.countdown_timer_settings.timeup_interval != 0) { warn_time = ((timer_val[i] - Transmitter.countdown_timer_settings.timeup_interval) / Transmitter.countdown_timer_settings.timeup_interval) * Transmitter.countdown_timer_settings.timeup_interval; if (timer_val[i] > warn_time && (timer_val[i] - delta) <= warn_time) { MUSIC_Play(MUSIC_ALARM1 + i); } } if (timer_val[i] >= 0 && timer_val[i] < delta) { MUSIC_Play(MUSIC_ALARM1 + i); } timer_val[i] -= delta; } last_time[i] = t; } if (Model.timer[i].resetsrc) { s16 val; if (MIXER_SRC(Model.timer[i].resetsrc) <= NUM_INPUTS) { volatile s16 *raw = MIXER_GetInputs(); val = raw[MIXER_SRC(Model.timer[i].resetsrc)]; } else { val = MIXER_GetChannel(Model.timer[i].resetsrc - NUM_INPUTS - 1, APPLY_SAFETY); } if (MIXER_SRC_IS_INV(Model.timer[i].resetsrc)) val = -val; if (val - CHAN_MIN_VALUE > (CHAN_MAX_VALUE - CHAN_MIN_VALUE) / 20) { TIMER_Reset(i); } } } }
static int expo_row_cb(int absrow, int relrow, int y, void *data) { const char *label = NULL; int underline = 0; void * label_cb = NULL; void *tgl = NULL; void *value = NULL; data = NULL; void *but_tgl = NULL; void *but_txt = NULL; void *but_data = NULL; int disable = 0; int x = 0; int w = LEFT_VIEW_WIDTH; switch(absrow) { case COMMON_SRC: label = _tr("Src"); tgl = sourceselect_cb; value = set_source_cb; data = &mp->cur_mixer->src; break; case COMMON_CURVE: label = _tr("High-Rate"); tgl = curveselect_cb; value = set_curvename_cb; data = &mp->mixer[0]; break; case COMMON_SCALE: label = (void *)0; label_cb = scalestring_cb; value = set_number100_cb; data = &mp->mixer[0].scalar; break; case EXPO_SWITCH1: label = _tr("Switch1"); underline = 1; tgl = sourceselect_cb; value = set_drsource_cb; data = &mp->mixer[1].sw; break; case EXPO_LINK1: but_tgl = toggle_link_cb; but_txt = show_rate_cb; but_data = (void *)0; if(! MIXER_SRC(mp->mixer[1].sw)) disable = 1; break; case EXPO_CURVE1: tgl = curveselect_cb; value = set_curvename_cb; data = &mp->mixer[1]; if(! MIXER_SRC(mp->mixer[1].sw) || mp->link_curves & 0x01) disable = 1; break; case EXPO_SCALE1: label = (void *)1; label_cb = scalestring_cb; value = set_number100_cb; data = &mp->mixer[1].scalar; if(! MIXER_SRC(mp->mixer[1].sw)) disable = 1; break; case EXPO_SWITCH2: label = _tr("Switch2"); underline = 1; tgl = sourceselect_cb; value = set_drsource_cb; data = &mp->mixer[2].sw; break; case EXPO_LINK2: but_tgl = toggle_link_cb; but_txt = show_rate_cb; but_data = (void *)1; if(! MIXER_SRC(mp->mixer[2].sw)) disable = 1; break; case EXPO_CURVE2: tgl = curveselect_cb; value = set_curvename_cb; data = &mp->mixer[2]; if(! MIXER_SRC(mp->mixer[2].sw) || mp->link_curves & 0x02) disable = 1; break; case EXPO_SCALE2: label = (void *)2; label_cb = scalestring_cb; value = set_number100_cb; data = &mp->mixer[2].scalar; if(! MIXER_SRC(mp->mixer[2].sw)) disable = 1; break; } if(label || label_cb) { labelDesc.style = LABEL_LEFTCENTER; GUI_CreateLabelBox(&gui->label[relrow], x, y, w, ITEM_HEIGHT, &labelDesc, label_cb, NULL, label); if(underline) GUI_CreateRect(&gui->rect1, x, y, LEFT_VIEW_WIDTH, 1, &labelDesc); y += ITEM_HEIGHT + 1; } labelDesc.style = LABEL_CENTER; if(but_tgl) { GUI_CreateButtonPlateText(&gui->value[relrow].but, x, y, w, ITEM_HEIGHT, &labelDesc, but_txt, 0xffff, but_tgl, but_data); if(disable) { GUI_ButtonEnable((guiObject_t *)&gui->value[relrow].but, 0); } } else { GUI_CreateTextSelectPlate(&gui->value[relrow].ts, x, y, w, ITEM_HEIGHT, &labelDesc, tgl, value, data); if(disable) { GUI_TextSelectEnable(&gui->value[relrow].ts, 0); } } return 1; }
void PAGE_MainEvent() { int i; if (PAGE_GetModal()) { #if HAS_TELEMETRY if(pagemem.modal_page == 2) { PAGE_TelemtestEvent(); } #endif return; } volatile s32 *raw = MIXER_GetInputs(); for(i = 0; i < NUM_ELEMS; i++) { if (! ELEM_USED(pc->elem[i])) break; if (! OBJ_IS_USED(&gui->elem[i])) continue; int src = pc->elem[i].src; int type = ELEM_TYPE(pc->elem[i]); switch(type) { case ELEM_VTRIM: case ELEM_HTRIM: { int value = *(MIXER_GetTrim(src-1)); if (mp->elem[i] != value) { mp->elem[i] = value; GUI_Redraw(&gui->elem[i].bar); } break; } case ELEM_SMALLBOX: case ELEM_BIGBOX: { s32 val = get_boxval(src); #if HAS_RTC if (src <= NUM_RTC) { if (mp->elem[i] != val) { mp->elem[i] = val; GUI_Redraw(&gui->elem[i].box); } } else #endif if (src - NUM_RTC <= NUM_TIMERS) { //Timer if ((val >= 0 && mp->elem[i] < 0) || (val < 0 && mp->elem[i] >= 0)) { GUI_SetLabelDesc(&gui->elem[i].box, get_box_font(type == ELEM_BIGBOX ? 0 : 2, val < 0)); mp->elem[i] = val; GUI_Redraw(&gui->elem[i].box); } else if (mp->elem[i] / 1000 != val /1000) { mp->elem[i] = val; GUI_Redraw(&gui->elem[i].box); } } else if (src - NUM_RTC - NUM_TIMERS <= NUM_TELEM) { //Telem int alarm = TELEMETRY_HasAlarm(src - NUM_RTC - NUM_TIMERS); if (alarm || ! TELEMETRY_IsUpdated(0xff)) { GUI_SetLabelDesc(&gui->elem[i].box, get_box_font(type == ELEM_BIGBOX ? 0 : 2, 1)); } else if(mp->elem[i] != val) { GUI_SetLabelDesc(&gui->elem[i].box, get_box_font(type == ELEM_BIGBOX ? 0 : 2, 0)); mp->elem[i] = val; GUI_Redraw(&gui->elem[i].box); } } else if (mp->elem[i] != val) { //Source mp->elem[i] = val; GUI_Redraw(&gui->elem[i].box); } break; } case ELEM_BAR: { s32 chan = MIXER_GetChannel(src-1, APPLY_SAFETY); if (mp->elem[i] != chan) { mp->elem[i] = chan; GUI_Redraw(&gui->elem[i].bar); } break; } case ELEM_TOGGLE: { src = MIXER_SRC(src); int idx = -1; if(src) { if (src > INP_HAS_CALIBRATION && src < INP_LAST) { //switch for (int j = 0; j < 3; j++) { // Assume switch 0/1/2 are in order if(ELEM_ICO(pc->elem[i], j) && raw[src+j] > 0) { idx = ELEM_ICO(pc->elem[i], j); break; } } } else { //Non switch int sw = raw[src] > 0 ? 1 : 0; if (ELEM_ICO(pc->elem[i], sw)) { idx = ELEM_ICO(pc->elem[i], sw); } } } if (idx != -1) { #ifdef HAS_CHAR_ICONS gui->elem[i].box.cb_data = (void *)(long)idx; #else struct ImageMap img; img = TGLICO_GetImage(idx); GUI_ChangeImage(&gui->elem[i].img, img.file, img.x_off, img.y_off); #endif GUI_SetHidden((guiObject_t *)&gui->elem[i], 0); } else { GUI_SetHidden((guiObject_t *)&gui->elem[i], 1); } } break; case ELEM_BATTERY: _check_voltage(&gui->elem[i].box); break; } } if(HAS_TOUCH) //FIXME: Hack to let 320x240 GUI continue to work _check_voltage(NULL); #if HAS_RTC if(Display.flags & SHOW_TIME) { u32 time = RTC_GetValue() / 60; if(mp->time != time) { mp->time = time; GUI_Redraw(&gui->time); } } #endif }
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; }