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); }
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); }
s16 eval_mixer_cb(s16 xval, void * data) { struct Mixer *mix = data ? (struct Mixer *)data : mp->cur_mixer; if (MIXER_SRC_IS_INV(mix->src)) xval = -xval; s16 yval = CURVE_Evaluate(xval, &mix->curve); yval = yval * mix->scalar / 100 + PCT_TO_RANGE(mix->offset); /* Min/Max is a servo limit, shouldn't be shown here if(mix->dest < NUM_OUT_CHANNELS) { if (yval > PCT_TO_RANGE(mp->limit.max)) yval = PCT_TO_RANGE(mp->limit.max); else if (yval < PCT_TO_RANGE(mp->limit.min)) yval = PCT_TO_RANGE(mp->limit.min); } */ if (yval > CHAN_MAX_VALUE * 5 / 4) yval = CHAN_MAX_VALUE * 5 / 4; else if (yval <CHAN_MIN_VALUE * 5 / 4) yval = CHAN_MIN_VALUE * 5 / 4; //Don't showchannel-reverse on the graph (but do show input reverse) //if (mp->limit.flags & CH_REVERSE) // yval = -yval; return yval; }
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); } }
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); }
s16 STDMIX_EvalMixerCb(s16 xval, struct Mixer *mix, s16 max_value, s16 min_value) { if (MIXER_SRC_IS_INV(mix->src)) xval = -xval; s16 yval = CURVE_Evaluate(xval, &mix->curve); yval = yval * mix->scalar / 100 + PCT_TO_RANGE(mix->offset); if (yval > max_value) yval = max_value; else if (yval <min_value) yval = min_value; return yval; }
void PAGE_EditCurvesInit(int page) { (void)page; struct Curve *curve = edit->curveptr; u8 type = CURVE_TYPE(curve); PAGE_SetActionCB(action_cb); edit->pointnum = 0; edit->reverse = MIXER_SRC_IS_INV(pagemem.u.mixer_page.cur_mixer->src); if ((type == CURVE_EXPO || type == CURVE_DEADBAND) && curve->points[0] == curve->points[1]) { edit->pointnum = -1; } edit->curve = *curve; GUI_CreateTextSelectPlate(&gui->name, NAME_X, 0, NAME_W, HEADER_HEIGHT, &TEXTSEL_FONT, NULL, set_curvename_cb, NULL); GUI_CreateButtonPlateText(&gui->save, SAVE_X, 0, SAVE_W, HEADER_WIDGET_HEIGHT, &BUTTON_FONT , NULL, okcancel_cb, (void *)_tr("Save")); // Draw a line if (UNDERLINE) GUI_CreateRect(&gui->rect, 0, HEADER_WIDGET_HEIGHT, LCD_WIDTH, 1, &DEFAULT_FONT); u8 space = LINE_SPACE; u8 y = space; if (type >= CURVE_3POINT) { GUI_CreateLabelBox(&gui->smoothlbl, LABEL_X, y, LABEL1_W, LINE_HEIGHT, &LABEL_FONT, NULL, NULL, _tr("Smooth")); GUI_CreateTextSelectPlate(&gui->smooth, TEXTSEL1_X, y, TEXTSEL1_W, LINE_HEIGHT, &TEXTSEL_FONT, NULL, set_smooth_cb, NULL); y += space; GUI_CreateLabelBox(&gui->pointlbl, LABEL_X, y , LABEL2_W, LINE_HEIGHT, &LABEL_FONT, NULL, NULL, _tr("Point")); GUI_CreateTextSelectPlate(&gui->point, TEXTSEL2_X, y, TEXTSEL2_W, LINE_HEIGHT, &TEXTSEL_FONT, NULL, set_pointnum_cb, NULL); } else if(type == CURVE_DEADBAND || type == CURVE_EXPO) { GUI_CreateLabelBox(&gui->pointlbl, LABEL_X, y , LABEL_W, LINE_HEIGHT, &LABEL_FONT, NULL, NULL, _tr("Pos/Neg")); y += space; GUI_CreateTextSelectPlate(&gui->point, LABEL_X, y, LABEL_W, LINE_HEIGHT, &TEXTSEL_FONT, NULL, set_expopoint_cb, NULL); } y += space; GUI_CreateLabelBox(&gui->valuelbl, LABEL_X, y , LABEL_W, LINE_HEIGHT, &LABEL_FONT, NULL, NULL, _tr("Value")); y += VALUE_Y_OFFSET; GUI_CreateTextSelectPlate(&gui->value, VALUE_X, y, LABEL_W, LINE_HEIGHT, &TEXTSEL_FONT, NULL, set_value_cb, NULL); GUI_CreateXYGraph(&gui->graph, GRAPH_X, GRAPH_Y, GRAPH_W, GRAPH_H, CHAN_MIN_VALUE, CHAN_MIN_VALUE, CHAN_MAX_VALUE, CHAN_MAX_VALUE, 0, 0, //CHAN_MAX_VALUE / 4, CHAN_MAX_VALUE / 4, show_curve_cb, NULL, touch_cb, &edit->curve); GUI_SetSelected((guiObject_t *)&gui->point); }
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); }
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; }
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); } } } }