Пример #1
0
const char *trimsource_name_cb(guiObject_t *obj, const void *data)
{
    (void)obj;
    u8 i = (long)data;
    struct Trim *trim = MIXER_GetAllTrims();
    return INPUT_SourceName(tp->tmpstr, MIXER_MapChannel(trim[i].src));
}
Пример #2
0
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:
        {
            u8 changed = 0;
            pc->elem[idx].src = GUI_TextSelectHelper(pc->elem[idx].src, 0, NUM_RTC + NUM_TELEM + NUM_TIMERS + NUM_CHANNELS, dir, 1, 1, &changed);
            if(changed && dir) {
                pc->elem[idx].src = _adjust_src_for_telemetry(pc->elem[idx].src, dir);
            }
            return GetBoxSource(tempstring, 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(tempstring, pc->elem[idx].src ? pc->elem[idx].src + NUM_INPUTS : 0);
        case ELEM_TOGGLE:
        {
            pc->elem[idx].src = INPUT_SelectAbbrevSource(pc->elem[idx].src, dir);
            return INPUT_SourceNameAbbrevSwitch(tempstring, 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");
            snprintf(tempstring, sizeof(tempstring), "%s%d", _tr("Trim"),pc->elem[idx].src);
            return tempstring;
    }
    return _tr("None");
}
Пример #3
0
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));
}
Пример #4
0
static const char *channum_cb(guiObject_t *obj, const void *data)
{
    (void)obj;
    long ch = (long)data;
    INPUT_SourceName(tempstring, ch+1);
    return tempstring;
}
Пример #5
0
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;
}
Пример #6
0
const char *MIXPAGE_ChanNameProtoCB(guiObject_t *obj, const void *data)
{
    (void)obj;
    u8 ch = (long)data;
    u8 proto_map_length = PROTO_MAP_LEN;
    char tmp1[30];

    /* See if we need to name the cyclic virtual channels */
    if (_is_virt_cyclic(ch)) {
        switch(ch - NUM_OUT_CHANNELS) {
            case 0: snprintf(tempstring, sizeof(tempstring), "%s-%s", _tr("CYC"), _tr("AIL")); return tempstring;
            case 1: snprintf(tempstring, sizeof(tempstring), "%s-%s", _tr("CYC"), _tr("ELE")); return tempstring;
            case 2: snprintf(tempstring, sizeof(tempstring), "%s-%s", _tr("CYC"), _tr("COL")); return tempstring;
        }
    }
    #if defined(_DEVO7E_256_TARGET_H_) || defined(_T8SG_TARGET_H_)
    #define SWITCH_NOSTOCK ((1 << INP_HOLD0) | (1 << INP_HOLD1) | \
                            (1 << INP_FMOD0) | (1 << INP_FMOD1))
    if ((Transmitter.ignore_src & SWITCH_NOSTOCK) == SWITCH_NOSTOCK)
        proto_map_length = PROTO_MAP_LEN - 1;
    #endif
    if (ch < proto_map_length && ProtocolChannelMap[Model.protocol]) {
        INPUT_SourceNameAbbrevSwitch(tmp1, ProtocolChannelMap[Model.protocol][ch]);
        sprintf(tempstring, "%s%d-%s",
            (Model.limits[ch].flags & CH_REVERSE) ? "!" : "",
            (int)(ch + 1), tmp1);
    } else {
        INPUT_SourceName(tmp1, ch + NUM_INPUTS + 1);
        sprintf(tempstring, "%s%s",
                (ch < Model.num_channels && Model.limits[ch].flags & CH_REVERSE) ? "!" : "",
                tmp1);
    }
    return tempstring;
}
Пример #7
0
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);
}
Пример #8
0
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);
}
Пример #9
0
static const char *sourcesel_cb(guiObject_t *obj, int dir, void *data)
{
    (void)obj;
    (void)data;
    u8 changed;
    dlog->enable = GUI_TextSelectHelper(dlog->enable, 0, NUM_SOURCES, dir, 1, 1, &changed);
    if (changed)
        DATALOG_UpdateState();
    return INPUT_SourceName(tempstring, dlog->enable);
}
Пример #10
0
static const char *_channum_cb(guiObject_t *obj, const void *data)
{
    (void)obj;
    long ch = (long)data;
    if (cp->type == MONITOR_RAWINPUT) {
       INPUT_SourceName(cp->tmpstr, ch+1);
    } else {
       sprintf(cp->tmpstr, "%d", (int)ch+1);
    }
    return cp->tmpstr;
}
Пример #11
0
const char *GetBoxSource(char *str, int src)
{
    if (src) {
#if HAS_RTC
        if (src <= NUM_RTC)
            return RTC_Name(str, src - 1);
#endif
        if (src - NUM_RTC <= NUM_TIMERS)
            return TIMER_Name(str, src - NUM_RTC - 1);
        else if( src - NUM_RTC - NUM_TIMERS <= NUM_TELEM)
            return TELEMETRY_Name(str, src - NUM_RTC - NUM_TIMERS);
    }
    return INPUT_SourceName(str, src
               ? src - (NUM_TELEM + NUM_TIMERS + NUM_RTC) + NUM_INPUTS
               : 0);
}
Пример #12
0
void debug_switches()
{
    s32 data[INP_LAST];
    for(int i = INP_HAS_CALIBRATION+1; i < INP_LAST; i++) {
        data[i] = CHAN_ReadRawInput(i);
    }
    while(1) {
        u32 changed = 0;
        for(int i = INP_HAS_CALIBRATION+1; i < INP_LAST; i++) {
            s32 val = CHAN_ReadRawInput(i);
            if (val != data[i]) {
                printf("%s=%d  ", INPUT_SourceName(tempstring, i), val);
                data[i] = val;
                changed = 1;
            }
        }
        if (changed) { printf("\n"); }
        if(PWR_CheckPowerSwitch()) PWR_Shutdown();
    }
}
Пример #13
0
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);
}
Пример #14
0
static const char *channum_cb(guiObject_t *obj, const void *data)
{
    (void)obj;
    long ch = (long)data;
    if (cp->type) {
        char *p = cp->tmpstr;
        if (ch & 0x01) {
            *p = '\n';
            p++;
        }
        CONFIG_EnableLanguage(0);  //Disable translation because tiny font is limitied in character set
        INPUT_SourceName(p, ch+1);
        CONFIG_EnableLanguage(1);
        if (! (ch & 0x01)) {
            sprintf(p + strlen(p), "\n");
        }
    } else {
       sprintf(cp->tmpstr, "\n%d", (int)ch+1);
    }
    return cp->tmpstr;
}
Пример #15
0
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);
}
Пример #16
0
const char *DATALOG_Source(char *str, int idx)
{
#if HAS_RTC
    if (idx == DLOG_TIME) {
        strcpy(str, _tr("RTC Time"));
    } else
#endif
    if (idx == DLOG_GPSTIME) {
        strcpy(str, _tr("GPS Time"));
    } else if (idx == DLOG_GPSLOC) {
        strcpy(str, _tr("GPS Coords"));
    } else if (idx == DLOG_GPSALT) {
        strcpy(str, _tr("GPS Alt."));
    } else if (idx == DLOG_GPSSPEED) {
        strcpy(str, _tr("GPS Speed"));
    } else if (idx >= DLOG_INPUTS) {
        return INPUT_SourceName(str, idx - DLOG_INPUTS + 1);
    } else if (idx >= DLOG_TELEMETRY) {
        return TELEMETRY_Name(str, idx - DLOG_TELEMETRY + 1);
    } else { // idx >= DLOG_TIMERS 
        return TIMER_Name(str, idx);
    }
    return str;
}
Пример #17
0
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 "";
}
Пример #18
0
static void show_button_page()
{
    // show elements where they are located on the real tx
    enum {
        OFFSET_X    = ((LCD_WIDTH - 320) / 2), // center on Devo12-screen
        OFFSET_Y    = ((LCD_HEIGHT - 240) / 2),
    };
    enum {X = 0, Y = 1};
    struct LabelDesc alignRight = {
        .font = DEFAULT_FONT.font,
        .align = ALIGN_RIGHT,
        .font_color = DEFAULT_FONT.font_color,
        .fill_color = DEFAULT_FONT.fill_color,
        .outline_color = DEFAULT_FONT.outline_color
    };

    const int label_pos[NUM_TX_BUTTONS][2] = CHANTEST_BUTTON_PLACEMENT;
    cp->is_locked = 3;
    GUI_CreateLabelBox(&gui->lock, OFFSET_X, 34, 320, 20, &NARROW_FONT, lockstr_cb, NULL, NULL);
    for (int i = 0; i < NUM_TX_BUTTONS; i++) {
        if ((1 << (i + 1)) & Transmitter.ignore_buttons)
            continue;
        GUI_CreateLabelBox(&gui->value[i],
                OFFSET_X + (label_pos[i][X] > 0 ? label_pos[i][X] + 50 : -label_pos[i][X] -20),    // >0? box at left side of label, otherwise right
                OFFSET_Y + label_pos[i][Y],
                16, 16,
                &SMALLBOX_FONT, NULL, NULL, (void *)"");
        GUI_CreateLabelBox(&gui->chan[i],
                OFFSET_X + abs(label_pos[i][X]),                                         // no differencing for the label
                OFFSET_Y + label_pos[i][Y],
                48, 16,
                label_pos[i][X] > 0 ? &alignRight : &DEFAULT_FONT,
                button_str_cb, NULL, (void *)(long)i);
    }
}

void _handle_button_test()
{
    if (cp->is_locked == 0 && SPITouch_IRQ()) {
        BUTTON_RegisterCallback(&cp->action, 0xFFFFFFFF,
               BUTTON_PRESS | BUTTON_RELEASE | BUTTON_LONGPRESS | BUTTON_PRIORITY,
               button_capture_cb, NULL);
        GUI_Redraw(&gui->lock); //Textbox
        cp->is_locked++;
    } else if (cp->is_locked == 1 && ! SPITouch_IRQ()) {
        cp->is_locked++;
    } else if (cp->is_locked == 2 && SPITouch_IRQ()) {
        BUTTON_UnregisterCallback(&cp->action);
        GUI_Redraw(&gui->lock); //Textbox
        cp->is_locked++;
    } else if (cp->is_locked == 3 && ! SPITouch_IRQ()) {
        cp->is_locked = 0;
    }
    u32 buttons = ScanButtons();
    for (int i = 0; i < NUM_TX_BUTTONS; i++) {
        GUI_SetLabelDesc(&gui->value[i],
               CHAN_ButtonIsPressed(buttons, i+1)
               ? &SMALLBOXNEG_FONT
               : &SMALLBOX_FONT);
    }
    return;
}

static inline guiObject_t *_get_obj(int chan, int objid)
{
    return objid == ITEM_GRAPH ? (guiObject_t *)&gui->bar[chan] : (guiObject_t *)&gui->value[chan];
}

static const char *channum_cb(guiObject_t *obj, const void *data)
{
    (void)obj;
    int disp = (long)data;
    int ch = get_channel_idx(cur_row * NUM_BARS_PER_ROW + disp);
    if (cp->type) {
        char *p = tempstring;
        if (disp & 0x01) {
            *p = '\n';
            p++;
        }
        CONFIG_EnableLanguage(0);  //Disable translation because tiny font is limited in character set
        INPUT_SourceName(p, ch+1);
        CONFIG_EnableLanguage(1);
        if (! (disp & 0x01)) {
            sprintf(p + strlen(p), "\n");
        }
    } else {
        ch -= NUM_INPUTS;
        if (ch < NUM_OUT_CHANNELS) {
            sprintf(tempstring, "\n%d", ch+1);
        } else {
            ch -= NUM_OUT_CHANNELS;
            if (Model.virtname[ch][0]) {
                tempstring_cpy(Model.virtname[ch]) ;
            } else {
                sprintf(tempstring, "%s%d", _tr("Virt"), ch+1);
            }
        }
    }
    return tempstring;
}
Пример #19
0
const char *MIXPAGE_ChannelNameCB(guiObject_t *obj, const void *data)
{
    (void)obj;
    return INPUT_SourceName(tempstring, (long)data + NUM_INPUTS + 1);
}
Пример #20
0
void EventLoop()
{
    CLOCK_ResetWatchdog();

#ifdef HEAP_DEBUG
    static int heap = 0;
    int h = _sbrk_r(NULL, 0);
    if(h > heap) {
        printf("heap: %x\n", h);
        heap = h;
    }
#endif
#ifdef TIMING_DEBUG
    debug_timing(0, 0);
#endif
    priority_ready &= ~(1 << MEDIUM_PRIORITY);
#if !HAS_HARD_POWER_OFF
    if(PWR_CheckPowerSwitch()) {
        if(! (BATTERY_Check() & BATTERY_CRITICAL)) {
            PAGE_Test();
            CONFIG_SaveModelIfNeeded();
            CONFIG_SaveTxIfNeeded();
        }
    	if(Transmitter.music_shutdown) {
#if HAS_EXTENDED_AUDIO
        if(AUDIO_VoiceAvailable()) {
            MUSIC_Play(MUSIC_SHUTDOWN);
            while (CLOCK_getms() < audio_queue_time) {
                // Wait for voice to finished
                CLOCK_ResetWatchdog();
            }
        } else {
#else
        {
            // We wait ~1sec for shutdown buzzer music finished
            unsigned int time;
            MUSIC_Play(MUSIC_SHUTDOWN);
            time = CLOCK_getms()+700;
            while (CLOCK_getms() < time) {
                CLOCK_ResetWatchdog();
            }
#endif
        }
	}

        PWR_Shutdown();
    }
#endif
    BUTTON_Handler();
    TOUCH_Handler();
    INPUT_CheckChanges();

    if (priority_ready & (1 << LOW_PRIORITY)) {
        priority_ready  &= ~(1 << LOW_PRIORITY);
        PAGE_Event();
        PROTOCOL_CheckDialogs();
        TIMER_Update();
        TELEMETRY_Alarm();
        BATTERY_Check();
        AUTODIMMER_Update();
#if HAS_DATALOG
        DATALOG_Update();
#endif
#if HAS_VIDEO
        VIDEO_Update();
#endif
#if HAS_EXTENDED_AUDIO
        AUDIO_CheckQueue();
#endif
        GUI_RefreshScreen();
#if HAS_HARD_POWER_OFF
        if (PAGE_ModelDoneEditing())
            CONFIG_SaveModelIfNeeded();
        CONFIG_SaveTxIfNeeded();
#endif
    }
#ifdef TIMING_DEBUG
    debug_timing(0, 1);
#endif
}

void TOUCH_Handler() {
    if(! HAS_TOUCH)
        return;
    u32 pen_down=0;

    static u32 pen_down_last=0;
    static u32 pen_down_long_at=0;

    struct touch t;

    if(SPITouch_IRQ()) {
        pen_down=1;
        t=SPITouch_GetCoords();
        if (! pen_down_last)
            pen_down_long_at=CLOCK_getms()+500;
    } else {
        pen_down=0;
    }

    if(pen_down && (!pen_down_last)) {
        AUTODIMMER_Check();
        GUI_CheckTouch(&t, 0);
    }

    if(!pen_down && pen_down_last) {
        GUI_TouchRelease();
    }

    if(pen_down && pen_down_last) {
        if(CLOCK_getms()>pen_down_long_at) {
            GUI_CheckTouch(&t, 1);
            pen_down_long_at += 100;
        }
    }
    pen_down_last=pen_down;
}

#if HAS_VIDEO
void VIDEO_Update()
{
    static u8 video_enable = 0;
    static u32 check_standard_ms = 0;

    // Check if Video is turn on
    int enabled = MIXER_SourceAsBoolean(Model.videosrc);

    if (enabled != video_enable) {
        VIDEO_Enable(enabled);
        video_enable = enabled;
        if (enabled) {
            VIDEO_SetChannel(Model.videoch);
            VIDEO_Contrast(Model.video_contrast);
            VIDEO_Brightness(Model.video_brightness);
            check_standard_ms = CLOCK_getms() + 3000;
        }
        else
            check_standard_ms = 0;
    }

    if(video_enable &&
        check_standard_ms > 0
        && check_standard_ms < CLOCK_getms()) {
            u8 video_standard_current = VIDEO_GetStandard();
            if((video_standard_current > 0) &&
               (video_standard_current < 8)) {
                VIDEO_SetStandard(video_standard_current);
                check_standard_ms = 0;
            }
            else {
                check_standard_ms = CLOCK_getms() + 3000;
            }
        }

    if(video_enable)
        AUTODIMMER_Check();
}
#endif //HAS_VIDEO

#ifdef TIMING_DEBUG
void debug_timing(u32 type, int startend)
{
    static u32 last_time[2][100];
    static u32 loop_time[4][101];
    static u32 loop_pos[4] = {-1, -1, -1, -1};
    static u32 max_last[2];
    static u32 max_loop[4];
    static int save_priority;

    if (type == 0) {
        if (! startend)
            save_priority = priority_ready;
        if (save_priority & (1 << MEDIUM_PRIORITY))
            debug_timing(2, startend);
        if (save_priority & (1 << LOW_PRIORITY))
            debug_timing(1, startend);
        return;
    }
    type--;
    if (! startend) {
        u32 t = CLOCK_getms();
        loop_pos[type] = (loop_pos[type] + 1) % 100;
        if (type < 2) {
            last_time[type][loop_pos[type]] = t;
            if (t - last_time[type][(loop_pos[type] + 99) % 100] > max_last[type])
                max_last[type] = t - last_time[type][(loop_pos[type] + 99) % 100];
        }
        loop_time[type][100] = t;
    } else {
        loop_time[type][loop_pos[type]] = CLOCK_getms() - loop_time[type][100];
        if (loop_time[type][loop_pos[type]] > max_loop[type])
            max_loop[type] = loop_time[type][loop_pos[type]];
        if (type == 0 && loop_pos[0] == 99) {
            unsigned avg_loop[4] = {0, 0, 0, 0};
            unsigned avg_last[2] = {0, 0};
            for(int i = 0; i < 99; i++) {
                for(int t = 0; t < 2; t++) {
                    u32 delay = last_time[t][(i + loop_pos[t] + 2) % 100] - last_time[t][(i + loop_pos[t] + 1) % 100];
                    avg_last[t] += delay;
                }
                for(int t = 0; t < 4; t++)
                    avg_loop[t] += loop_time[t][i];
            }
            for(int t = 0; t < 4; t++)
                avg_loop[t] /= 99;
            avg_last[0] /= 99;
            avg_last[1] /= 99;
            printf("Avg: radio: %d mix: %d med: %d/%d low: %d/%d\n", avg_loop[3], avg_loop[2], avg_loop[1], avg_last[1], avg_loop[0], avg_last[0]);
            printf("Max: radio: %d mix: %d med: %d/%d low: %d/%d\n", max_loop[3], max_loop[2], max_loop[1], max_last[1], max_loop[0], max_last[0]);
            memset(max_loop, 0, sizeof(max_loop));
            max_last[0] = 0;
            max_last[1] = 0;
        }
    }
}
#endif

void debug_switches()
{
    s32 data[INP_LAST];
    for(int i = INP_HAS_CALIBRATION+1; i < INP_LAST; i++) {
        data[i] = CHAN_ReadRawInput(i);
    }
    while(1) {
        u32 changed = 0;
        for(int i = INP_HAS_CALIBRATION+1; i < INP_LAST; i++) {
            s32 val = CHAN_ReadRawInput(i);
            if (val != data[i]) {
                printf("%s=%d  ", INPUT_SourceName(tempstring, i), val);
                data[i] = val;
                changed = 1;
            }
        }
        if (changed) { printf("\n"); }
        if(PWR_CheckPowerSwitch()) PWR_Shutdown();
    }
}