static const char *safety_string_cb(guiObject_t *obj, void *data) { (void)data; int i; u32 crc = Crc(tempstring, strlen(tempstring)); if (obj && crc == dialogcrc) return tempstring; int count = 0; const s8 safeval[4] = {0, -100, 0, 100}; volatile s16 *raw = MIXER_GetInputs(); u64 unsafe = PROTOCOL_CheckSafe(); tempstring[0] = 0; for(i = 0; i < NUM_SOURCES + 1; i++) { if (! (unsafe & (1LL << i))) continue; int ch = (i == 0) ? PROTOCOL_MapChannel(INP_THROTTLE, NUM_INPUTS + 2) : i-1; s16 val = RANGE_TO_PCT((ch < NUM_INPUTS) ? raw[ch+1] : MIXER_GetChannel(ch - (NUM_INPUTS), APPLY_SAFETY)); INPUT_SourceName(tempstring + strlen(tempstring), ch + 1); int len = strlen(tempstring); snprintf(tempstring + len, sizeof(tempstring) - len, _tr(" is %d%%, safe value = %d%%\n"), val, safeval[Model.safety[i]]); if (++count >= 5) break; } return tempstring; }
u64 PROTOCOL_CheckSafe() { int i; volatile s32 *raw = MIXER_GetInputs(); u64 unsafe = 0; for(i = 0; i < NUM_SOURCES + 1; i++) { if (! Model.safety[i]) continue; int ch; if (i == 0) { //Auto mode (choose 'THR' channel (or CH3) ch = PROTOCOL_MapChannel(INP_THROTTLE, NUM_INPUTS + 2); } else { ch = i-1; } s32 val = RANGE_TO_PCT((ch < NUM_INPUTS) ? raw[ch+1] : MIXER_GetChannel(ch - (NUM_INPUTS), APPLY_SAFETY)); if (Model.safety[i] == SAFE_MIN && val > -99) unsafe |= 1ULL << i; else if (Model.safety[i] == SAFE_ZERO && (val < -1 || val > 1)) unsafe |= 1ULL << i; else if (Model.safety[i] == SAFE_MAX && val < 99) unsafe |= 1ULL << i; } return unsafe; }
s32 get_boxval(u8 idx) { #if HAS_RTC if (idx <= NUM_RTC) { u32 time = RTC_GetValue(); return idx == 1 ? RTC_GetTimeValue(time) : RTC_GetDateValue(time); } #endif if (idx - NUM_RTC <= NUM_TIMERS) return TIMER_GetValue(idx - NUM_RTC - 1); if(idx - NUM_RTC - NUM_TIMERS <= NUM_TELEM) return TELEMETRY_GetValue(idx - NUM_RTC - NUM_TIMERS); return RANGE_TO_PCT(MIXER_GetChannel(idx - (NUM_RTC + NUM_TIMERS + NUM_TELEM + 1), APPLY_SAFETY | APPLY_SCALAR)); }
static void build_data_pkt() { int i; for (i = 0; i < USBHID_MAX_CHANNELS; i++) { if (i >= num_channels) { packet[i] = 0; continue; } s32 value = RANGE_TO_PCT(Channels[i]); if (value > 127) value = 127; else if (value < -127) value = -127; packet[i] = value; } }
const char *show_box_cb(guiObject_t *obj, const void *data) { (void)obj; u8 idx = (long)data; #if HAS_RTC if (idx <= NUM_RTC) { u32 time = RTC_GetValue(); idx == 1 ? RTC_GetTimeFormatted(tempstring, time) : RTC_GetDateFormatted(tempstring, time); return tempstring; } #endif if (idx - NUM_RTC <= NUM_TIMERS) { TIMER_SetString(tempstring, TIMER_GetValue(idx - NUM_RTC - 1)); } else if(idx - NUM_RTC - NUM_TIMERS <= NUM_TELEM) { TELEMETRY_GetValueStr(tempstring, idx - NUM_RTC - NUM_TIMERS); } else { sprintf(tempstring, "%3d%%", RANGE_TO_PCT(MIXER_GetChannel(idx - (NUM_RTC + NUM_TIMERS + NUM_TELEM + 1), APPLY_SAFETY | APPLY_SCALAR))); } return tempstring; }
void PAGE_ChantestEvent() { int i; if(cp->type == MONITOR_BUTTONTEST) { _handle_button_test(); return; } volatile s16 *raw = MIXER_GetInputs(); for(i = 0; i < cp->num_bars; i++) { int j = _get_input_idx(i); int v = RANGE_TO_PCT(cp->type ? raw[j+1] : Channels[j]); if (v != cp->pctvalue[i]) { guiObject_t *obj = _get_obj(i, ITEM_GRAPH); if (obj) { GUI_Redraw(obj); GUI_Redraw(_get_obj(i, ITEM_VALUE)); } cp->pctvalue[i] = v; } } }
void PAGE_ChantestEvent() { if(cp->type == MONITOR_BUTTONTEST) { _handle_button_test(); return; } volatile s32 *raw = MIXER_GetInputs(); for(int i = 0; i < cp->num_bars; i++) { int ch = get_channel_idx(cur_row * NUM_BARS_PER_ROW + i); int v = RANGE_TO_PCT((ch >= NUM_INPUTS && ch < NUM_INPUTS + NUM_OUT_CHANNELS) ? Channels[ch - NUM_INPUTS] : raw[ch + 1]); if (v != cp->pctvalue[i]) { guiObject_t *obj = _get_obj(i, ITEM_VALUE); if (obj) { GUI_Redraw(obj); GUI_Redraw(_get_obj(i, ITEM_GRAPH)); } cp->pctvalue[i] = v; } } }
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); } } } }