/** * 菜单系统实现 * 基于 OLED 128x64 的层级菜单 UI */ #include "menu.h" #include #include /* 全局页面状态 */ Page_t g_page; /* 通道输出值 (混控后) */ int16_t g_channels[CHANNEL_COUNT]; /* 模型类型名称 */ static const char *model_types[] = {"Airplane", "Car", "Boat", "MultiRotor"}; /* 输入名称缓存 */ static char input_name_buf[16]; /* 获取输入名称 */ static const char* GetInputName(uint8_t idx, uint8_t type) { if (type == INPUT_TYPE_ADC) { snprintf(input_name_buf, sizeof(input_name_buf), "ADC_IN%d", idx); } else if (type == INPUT_TYPE_KEY) { snprintf(input_name_buf, sizeof(input_name_buf), "KEY_IN%d", idx); } else { snprintf(input_name_buf, sizeof(input_name_buf), "None"); } return input_name_buf; } /* 获取通道值显示 */ static const char* GetChannelValue(uint8_t ch) { Model_t *m = Storage_GetActiveModel(); if (m->input_type[ch] == INPUT_TYPE_ADC) { snprintf(input_name_buf, sizeof(input_name_buf), "%4d", adc_values[m->channel_map[ch]]); } else if (m->input_type[ch] == INPUT_TYPE_KEY) { snprintf(input_name_buf, sizeof(input_name_buf), "%s", key_values[m->channel_map[ch]] ? "ON " : "OFF"); } else { snprintf(input_name_buf, sizeof(input_name_buf), "----"); } return input_name_buf; } void Menu_Init(void) { memset(&g_page, 0, sizeof(Page_t)); g_page.page_id = PAGE_HOME; g_page.cursor = 0; } /* ---- 混控计算 ---- */ void Mixer_Compute(int16_t *channels) { Model_t *m = Storage_GetActiveModel(); for (uint8_t i = 0; i < CHANNEL_COUNT; i++) { if (m->input_type[i] == INPUT_TYPE_NONE) { channels[i] = 0; continue; } int16_t raw = 0; if (m->input_type[i] == INPUT_TYPE_ADC) { /* ADC: 0-4095 -> -1000 ~ +1000 */ raw = (int16_t)(adc_values[m->channel_map[i]]) - 2048; raw = raw * 1000 / 2048; } else { /* 按键: 0/1 -> -1000/+1000 */ raw = key_values[m->channel_map[i]] ? 1000 : -1000; } /* 应用混控 */ switch (m->mixer_type[i]) { case MIXER_TYPE_SIMPLE: channels[i] = (raw * m->mixer_scale[i] / 100) + m->mixer_offset[i]; break; case MIXER_TYPE_DELTA: /* 三角翼: CH1=elevon_left, CH2=elevon_right */ if (i == 0) channels[i] = (raw * m->mixer_scale[i] / 100) + m->mixer_offset[i]; if (i == 1) channels[i] = (-raw * m->mixer_scale[i] / 100) + m->mixer_offset[i]; break; case MIXER_TYPE_VTAIL: channels[i] = (raw * m->mixer_scale[i] / 100) + m->mixer_offset[i]; break; case MIXER_TYPE_ELEVON: channels[i] = (raw * m->mixer_scale[i] / 100) + m->mixer_offset[i]; break; default: channels[i] = raw; break; } /* 限幅 */ if (channels[i] > 1000) channels[i] = 1000; if (channels[i] < -1000) channels[i] = -1000; } } /* ---- 通用菜单导航 ---- */ static void Menu_Navigate(void) { uint8_t key = Input_GetKey(); if (key == KEY_UP) { if (g_page.cursor > 0) g_page.cursor--; } else if (key == KEY_DOWN) { if (g_page.cursor < g_page.item_count - 1) g_page.cursor++; } else if (key == KEY_OK) { /* 执行选中项 */ if (g_page.cursor < g_page.item_count && g_page.items[g_page.cursor].target_page != 0xFF) { g_page.page_id = g_page.items[g_page.cursor].target_page; g_page.cursor = 0; g_page.item_count = 0; } if (g_page.cursor < g_page.item_count && g_page.items[g_page.cursor].action) { g_page.items[g_page.cursor].action(); } } else if (key == KEY_BACK) { /* 返回上一级 */ if (g_page.page_id == PAGE_HOME) { /* 首页按返回: 切换值/回传 */ g_config.home_page = !g_config.home_page; } else if (g_page.page_id == PAGE_MAIN_MENU) { g_page.page_id = PAGE_HOME; } else if (g_page.page_id >= PAGE_MODEL_LIST && g_page.page_id <= PAGE_MIXER_EDIT) { g_page.page_id = PAGE_MAIN_MENU; } else { g_page.page_id = PAGE_MAIN_MENU; } g_page.cursor = 0; g_page.item_count = 0; } } /* ---- 首页 ---- */ void Menu_DrawHome(void) { OLED_Clear(); if (g_config.home_page == 0) { /* 回传信息页 */ OLED_ShowString(0, 0, "Telemetry", 6); OLED_DrawLine(0, 9, 127, 9); /* 电压 */ OLED_ShowString(0, 14, "V:", 6); OLED_ShowNum(18, 14, 0, 4, 6); /* TODO: 实际电压 */ OLED_ShowString(48, 14, "V", 6); /* RSSI */ OLED_ShowString(0, 24, "RSSI:", 6); OLED_ShowNum(36, 24, 0, 3, 6); /* 丢包率 */ OLED_ShowString(0, 34, "Lost:", 6); OLED_ShowNum(36, 34, 0, 3, 6); OLED_ShowString(60, 34, "%", 6); /* 模型名 */ Model_t *m = Storage_GetActiveModel(); OLED_ShowString(0, 48, m->name, 6); /* 高频头状态 */ OLED_ShowString(80, 48, g_config.rf_type == 0 ? "NRF" : "CRFS", 6); OLED_ShowString(80, 56, nrf_connected ? "OK" : "--", 6); } else { /* INx 值页 */ OLED_ShowString(0, 0, "ADC Values", 6); OLED_DrawLine(0, 9, 127, 9); Model_t *m = Storage_GetActiveModel(); for (uint8_t i = 0; i < 8; i++) { uint8_t row = i / 2; uint8_t col = (i % 2) * 64; OLED_ShowString(col, 12 + row * 12, "IN", 6); OLED_ShowNum(col + 12, 12 + row * 12, i, 2, 6); OLED_ShowString(col + 24, 12 + row * 12, ":", 6); if (m->input_type[i] == INPUT_TYPE_ADC) { OLED_ShowNum(col + 30, 12 + row * 12, adc_values[m->channel_map[i]], 4, 6); } else { OLED_ShowString(col + 30, 12 + row * 12, key_values[m->channel_map[i]] ? "ON " : "OFF", 6); } } } OLED_Display(); Menu_Navigate(); /* 首页长按确认 -> 高频头快捷页 */ if (Input_IsKeyHeld(KEY_OK)) { g_page.page_id = PAGE_RF_QUICK; g_page.cursor = 0; g_page.item_count = 0; } /* 长按返回 2s -> 关机 (已连接接收机时不关机) */ if (Input_IsKeyHeldFor(KEY_BACK, 2000) && !nrf_connected) { System_Shutdown(); } } /* ---- 主菜单 ---- */ void Menu_DrawMainMenu(void) { OLED_Clear(); OLED_ShowString(0, 0, "Main Menu", 16); OLED_DrawLine(0, 17, 127, 17); static const char *items[] = { "Model Select", "RF Config", "Channel Map", "Mixer", "PWM Driver", "Home Page" }; g_page.item_count = 6; for (uint8_t i = 0; i < g_page.item_count; i++) { uint8_t y = 20 + i * 10; if (i == g_page.cursor) { OLED_ShowString(0, y, ">", 6); } OLED_ShowString(8, y, items[i], 6); } OLED_Display(); Menu_Navigate(); /* 映射到具体页面 */ if (Input_IsKeyPressed(KEY_OK)) { switch (g_page.cursor) { case 0: g_page.page_id = PAGE_MODEL_LIST; break; case 1: g_page.page_id = PAGE_RF_CONFIG; break; case 2: g_page.page_id = PAGE_CHANNEL_MAP; break; case 3: g_page.page_id = PAGE_MIXER; break; case 4: g_page.page_id = PAGE_PWM_CONFIG; break; case 5: g_page.page_id = PAGE_HOME_SET; break; } g_page.cursor = 0; g_page.item_count = 0; } } /* ---- 模型列表 ---- */ void Menu_DrawModelList(void) { OLED_Clear(); OLED_ShowString(0, 0, "Models", 16); OLED_DrawLine(0, 17, 127, 17); g_page.item_count = 0; /* 第一项: 新建 */ OLED_ShowString(0, 20, g_page.cursor == 0 ? ">[New]" : " [New]", 6); g_page.item_count++; for (uint8_t i = 0; i < MODEL_MAX_COUNT; i++) { if (g_config.models[i].name[0] != '\0') { uint8_t y = 20 + g_page.item_count * 10; if (y > 54) break; /* 超出屏幕 */ char buf[20]; snprintf(buf, sizeof(buf), "%s[%c] %s", g_page.cursor == g_page.item_count ? ">" : " ", i == g_config.active_model ? '*' : ' ', g_config.models[i].name); OLED_ShowString(0, y, buf, 6); g_page.item_count++; } } OLED_Display(); Menu_Navigate(); /* 处理选择 */ if (Input_IsKeyPressed(KEY_OK)) { if (g_page.cursor == 0) { /* 新建模型 */ g_page.page_id = PAGE_MODEL_NEW; g_page.cursor = 0; g_page.edit_idx = 0; g_page.edit_str_len = 0; memset(g_page.edit_str, 0, sizeof(g_page.edit_str)); } else { /* 选择模型 */ uint8_t model_idx = 0xFF; uint8_t cnt = 1; for (uint8_t i = 0; i < MODEL_MAX_COUNT; i++) { if (g_config.models[i].name[0] != '\0') { if (cnt == g_page.cursor) { model_idx = i; break; } cnt++; } } if (model_idx != 0xFF) { Storage_ModelSelect(model_idx); g_page.page_id = PAGE_MAIN_MENU; } } g_page.cursor = 0; g_page.item_count = 0; } /* 长按确认 -> 编辑/删除 */ if (Input_IsKeyHeld(KEY_OK) && g_page.cursor > 0) { /* TODO: 弹出编辑/删除选项 */ } } /* ---- 新建模型 ---- */ void Menu_DrawModelNew(void) { OLED_Clear(); OLED_ShowString(0, 0, "New Model", 16); OLED_DrawLine(0, 17, 127, 17); /* 名称编辑 */ OLED_ShowString(0, 22, "Name:", 6); OLED_ShowString(36, 22, g_page.edit_str, 6); if (g_page.edit_idx == 0) { /* 闪烁光标 */ OLED_ShowString(36 + g_page.edit_str_len * 6, 22, "_", 6); } /* 类型选择 */ OLED_ShowString(0, 34, "Type:", 6); OLED_ShowString(36, 34, (char*)model_types[g_page.edit_value], 6); /* 按钮 */ OLED_ShowString(20, 50, "[OK]", 6); OLED_ShowString(80, 50, "[Cancel]", 6); OLED_Display(); /* 处理输入 */ uint8_t key = Input_GetKey(); if (g_page.edit_idx == 0) { /* 编辑名称 */ if (key == KEY_UP) { /* 字符递增 */ if (g_page.edit_str_len < 8) { g_page.edit_str[g_page.edit_str_len] = 'A'; g_page.edit_str_len++; } } else if (key == KEY_DOWN) { if (g_page.edit_str_len > 0) { g_page.edit_str_len--; g_page.edit_str[g_page.edit_str_len] = '\0'; } } else if (key == KEY_OK) { g_page.edit_idx = 1; /* 切换到类型选择 */ } } else if (g_page.edit_idx == 1) { if (key == KEY_UP && g_page.edit_value < 3) g_page.edit_value++; if (key == KEY_DOWN && g_page.edit_value > 0) g_page.edit_value--; if (key == KEY_OK) g_page.edit_idx = 2; /* 到确认按钮 */ } else if (g_page.edit_idx == 2) { /* 确认/取消 */ if (key == KEY_UP || key == KEY_DOWN) g_page.edit_idx = (g_page.edit_idx == 2) ? 3 : 2; if (key == KEY_OK) { if (g_page.edit_idx == 2) { /* 确认创建 */ Storage_ModelAdd(g_page.edit_str, g_page.edit_value); g_page.page_id = PAGE_MODEL_LIST; } else { g_page.page_id = PAGE_MODEL_LIST; } g_page.cursor = 0; g_page.item_count = 0; } } if (key == KEY_BACK) { g_page.page_id = PAGE_MODEL_LIST; g_page.cursor = 0; g_page.item_count = 0; } } /* ---- 通道映射 ---- */ void Menu_DrawChannelMap(void) { OLED_Clear(); OLED_ShowString(0, 0, "Channel Map", 16); OLED_DrawLine(0, 17, 127, 17); Model_t *m = Storage_GetActiveModel(); g_page.item_count = CHANNEL_COUNT + 1; /* +1 for [Next] */ uint8_t start = g_page.scroll_offset; for (uint8_t i = start; i < start + 4 && i < CHANNEL_COUNT; i++) { uint8_t y = 20 + (i - start) * 10; char buf[32]; snprintf(buf, sizeof(buf), "%s[CH%d]->[%s]", i == g_page.cursor ? ">" : " ", i + 1, GetInputName(m->channel_map[i], m->input_type[i])); OLED_ShowString(0, y, buf, 6); } /* [下一步] 按钮 */ if (g_page.cursor >= CHANNEL_COUNT - 4) { OLED_ShowString(40, 56, "[Next]", 6); } OLED_Display(); Menu_Navigate(); /* 编辑通道映射 */ if (Input_IsKeyPressed(KEY_OK) && g_page.cursor < CHANNEL_COUNT) { /* 循环切换输入源 */ m->input_type[g_page.cursor]++; if (m->input_type[g_page.cursor] > INPUT_TYPE_KEY) m->input_type[g_page.cursor] = INPUT_TYPE_ADC; } /* 下一步 */ if (Input_IsKeyPressed(KEY_OK) && g_page.cursor == CHANNEL_COUNT) { g_page.page_id = PAGE_MIXER; g_page.cursor = 0; g_page.item_count = 0; } } /* ---- 混控列表 ---- */ void Menu_DrawMixer(void) { OLED_Clear(); OLED_ShowString(0, 0, "Mixer", 16); OLED_DrawLine(0, 17, 127, 17); g_page.item_count = CHANNEL_COUNT + 1; uint8_t start = g_page.scroll_offset; for (uint8_t i = start; i < start + 4 && i < CHANNEL_COUNT; i++) { uint8_t y = 20 + (i - start) * 10; char buf[20]; snprintf(buf, sizeof(buf), "%s[CH%d]: %4d", i == g_page.cursor ? ">" : " ", i + 1, g_channels[i]); OLED_ShowString(0, y, buf, 6); } if (g_page.cursor >= CHANNEL_COUNT - 4) { OLED_ShowString(40, 56, "[Next]", 6); } OLED_Display(); Menu_Navigate(); if (Input_IsKeyPressed(KEY_OK) && g_page.cursor < CHANNEL_COUNT) { g_page.page_id = PAGE_MIXER_EDIT; g_page.edit_idx = g_page.cursor; g_page.cursor = 0; g_page.item_count = 0; } } /* ---- 混控编辑 ---- */ void Menu_DrawMixerEdit(void) { OLED_Clear(); OLED_ShowString(0, 0, "Mixer Edit", 16); OLED_DrawLine(0, 17, 127, 17); Model_t *m = Storage_GetActiveModel(); uint8_t ch = g_page.edit_idx; char buf[32]; snprintf(buf, sizeof(buf), "CH%d Mixer", ch + 1); OLED_ShowString(0, 20, buf, 6); /* 混控类型 */ static const char *mixer_names[] = {"None", "Simple", "Delta", "V-Tail", "Elevon"}; snprintf(buf, sizeof(buf), "Type: %s", mixer_names[m->mixer_type[ch]]); OLED_ShowString(0, 30, buf, 6); /* 比例 */ snprintf(buf, sizeof(buf), "Scale: %d%%", m->mixer_scale[ch]); OLED_ShowString(0, 40, buf, 6); /* 偏移 */ snprintf(buf, sizeof(buf), "Offset: %d", m->mixer_offset[ch]); OLED_ShowString(0, 50, buf, 6); OLED_Display(); uint8_t key = Input_GetKey(); if (key == KEY_UP) { if (g_page.cursor == 0) { m->mixer_type[ch]++; if (m->mixer_type[ch] > MIXER_TYPE_ELEVON) m->mixer_type[ch] = MIXER_TYPE_NONE; } else if (g_page.cursor == 1) { m->mixer_scale[ch] += 5; if (m->mixer_scale[ch] > 200) m->mixer_scale[ch] = 200; } else if (g_page.cursor == 2) { m->mixer_offset[ch] += 10; } } else if (key == KEY_DOWN) { if (g_page.cursor == 0) { if (m->mixer_type[ch] > 0) m->mixer_type[ch]--; } else if (g_page.cursor == 1) { m->mixer_scale[ch] -= 5; if (m->mixer_scale[ch] < 0) m->mixer_scale[ch] = 0; } else if (g_page.cursor == 2) { m->mixer_offset[ch] -= 10; } } else if (key == KEY_OK) { g_page.cursor++; if (g_page.cursor > 2) g_page.cursor = 0; } else if (key == KEY_BACK) { g_page.page_id = PAGE_MIXER; g_page.cursor = 0; g_page.item_count = 0; } } /* ---- 高频头配置 ---- */ void Menu_DrawRFConfig(void) { OLED_Clear(); OLED_ShowString(0, 0, "RF Config", 16); OLED_DrawLine(0, 17, 127, 17); g_page.item_count = 2; OLED_ShowString(0, 22, g_page.cursor == 0 ? ">[NRF24]" : " [NRF24]", 6); OLED_ShowString(0, 34, g_page.cursor == 1 ? ">[CRFS]" : " [CRFS]", 6); OLED_Display(); Menu_Navigate(); if (Input_IsKeyPressed(KEY_OK)) { if (g_page.cursor == 0) { g_config.rf_type = 0; g_page.page_id = PAGE_NRF_CONFIG; } else { g_config.rf_type = 1; g_page.page_id = PAGE_CRFS_CONFIG; } g_page.cursor = 0; g_page.item_count = 0; } } /* ---- NRF24 配置 ---- */ void Menu_DrawNRFConfig(void) { OLED_Clear(); OLED_ShowString(0, 0, "NRF24 Config", 16); OLED_DrawLine(0, 17, 127, 17); g_page.item_count = 5; char buf[32]; snprintf(buf, sizeof(buf), "%sPhrase: %s", g_page.cursor == 0 ? ">" : " ", g_config.nrf_phrase); OLED_ShowString(0, 20, buf, 6); snprintf(buf, sizeof(buf), "%sChannel: %d", g_page.cursor == 1 ? ">" : " ", g_config.nrf_channel); OLED_ShowString(0, 30, buf, 6); snprintf(buf, sizeof(buf), "%sAddr: %02X%02X%02X%02X%02X", g_page.cursor == 2 ? ">" : " ", g_config.nrf_addr[0], g_config.nrf_addr[1], g_config.nrf_addr[2], g_config.nrf_addr[3], g_config.nrf_addr[4]); OLED_ShowString(0, 40, buf, 6); static const char *rates[] = {"250K", "1M", "2M"}; snprintf(buf, sizeof(buf), "%sRate: %s", g_page.cursor == 3 ? ">" : " ", rates[g_config.nrf_rate]); OLED_ShowString(0, 50, buf, 6); snprintf(buf, sizeof(buf), "%sPower: %d", g_page.cursor == 4 ? ">" : " ", g_config.nrf_power); OLED_ShowString(0, 60, buf, 6); OLED_Display(); Menu_Navigate(); } /* ---- CRFS 配置 ---- */ void Menu_DrawCRFSConfig(void) { OLED_Clear(); OLED_ShowString(0, 0, "CRFS Config", 16); OLED_DrawLine(0, 17, 127, 17); g_page.item_count = 3; char buf[32]; snprintf(buf, sizeof(buf), "%sPkt Rate: %dHz", g_page.cursor == 0 ? ">" : " ", g_config.crfs_packet_rate); OLED_ShowString(0, 22, buf, 6); snprintf(buf, sizeof(buf), "%sTelem: 1:%d", g_page.cursor == 1 ? ">" : " ", g_config.crfs_telemetry_ratio); OLED_ShowString(0, 34, buf, 6); snprintf(buf, sizeof(buf), "%sPower: %dmW", g_page.cursor == 2 ? ">" : " ", g_config.crfs_power); OLED_ShowString(0, 46, buf, 6); OLED_Display(); Menu_Navigate(); } /* ---- PWM 配置 ---- */ void Menu_DrawPWMConfig(void) { OLED_Clear(); OLED_ShowString(0, 0, "PWM Config", 16); OLED_DrawLine(0, 17, 127, 17); g_page.item_count = 5; static const char *pwm_modes[] = {"Disabled", "WS2812", "LED", "Vibrate"}; char buf[32]; snprintf(buf, sizeof(buf), "%sPWM1: %s", g_page.cursor == 0 ? ">" : " ", pwm_modes[g_config.pwm1_mode]); OLED_ShowString(0, 20, buf, 6); snprintf(buf, sizeof(buf), "%sPWM2: %s", g_page.cursor == 1 ? ">" : " ", pwm_modes[g_config.pwm2_mode]); OLED_ShowString(0, 30, buf, 6); snprintf(buf, sizeof(buf), "%sWS2812 Effect: %d", g_page.cursor == 2 ? ">" : " ", g_config.ws2812_effect); OLED_ShowString(0, 40, buf, 6); snprintf(buf, sizeof(buf), "%sLED Bright: %d%%", g_page.cursor == 3 ? ">" : " ", g_config.led_brightness); OLED_ShowString(0, 50, buf, 6); snprintf(buf, sizeof(buf), "%sVibrate: Lv%d", g_page.cursor == 4 ? ">" : " ", g_config.vibrate_level); OLED_ShowString(0, 60, buf, 6); OLED_Display(); Menu_Navigate(); } /* ---- 首页设置 ---- */ void Menu_DrawHomeSet(void) { OLED_Clear(); OLED_ShowString(0, 0, "Home Page", 16); OLED_DrawLine(0, 17, 127, 17); g_page.item_count = 2; OLED_ShowString(0, 25, g_page.cursor == 0 ? ">Telemetry" : " Telemetry", 6); OLED_ShowString(0, 37, g_page.cursor == 1 ? ">INx Values" : " INx Values", 6); OLED_Display(); Menu_Navigate(); if (Input_IsKeyPressed(KEY_OK)) { g_config.home_page = g_page.cursor; g_page.page_id = PAGE_MAIN_MENU; g_page.cursor = 0; g_page.item_count = 0; } } /* ---- 对频页 ---- */ void Menu_DrawBind(void) { OLED_Clear(); OLED_ShowString(0, 0, "Binding...", 16); OLED_DrawLine(0, 17, 127, 17); OLED_ShowString(0, 30, "Scanning channels", 6); OLED_DrawProgressBar(10, 45, 108, 8, 50); /* 示例进度 */ OLED_Display(); Menu_Navigate(); } /* ---- 高频头快捷页 ---- */ void Menu_DrawRFQuick(void) { OLED_Clear(); if (g_config.rf_type == 0) { OLED_ShowString(0, 0, "NRF24 Quick", 16); OLED_DrawLine(0, 17, 127, 17); g_page.item_count = 3; char buf[32]; snprintf(buf, sizeof(buf), "%s[Bind]", g_page.cursor == 0 ? ">" : " "); OLED_ShowString(0, 22, buf, 6); snprintf(buf, sizeof(buf), "%sCh: %d", g_page.cursor == 1 ? ">" : " ", g_config.nrf_channel); OLED_ShowString(0, 34, buf, 6); snprintf(buf, sizeof(buf), "%sAddr: %02X%02X%02X%02X%02X", g_page.cursor == 2 ? ">" : " ", g_config.nrf_addr[0], g_config.nrf_addr[1], g_config.nrf_addr[2], g_config.nrf_addr[3], g_config.nrf_addr[4]); OLED_ShowString(0, 46, buf, 6); } else { OLED_ShowString(0, 0, "CRFS Quick", 16); OLED_DrawLine(0, 17, 127, 17); OLED_ShowString(0, 30, "CRFS mode active", 6); } OLED_Display(); Menu_Navigate(); if (Input_IsKeyPressed(KEY_OK) && g_page.cursor == 0) { /* 进入对频模式 */ g_page.page_id = PAGE_BIND; g_page.cursor = 0; g_page.item_count = 0; } if (Input_IsKeyPressed(KEY_BACK)) { g_page.page_id = PAGE_HOME; g_page.cursor = 0; g_page.item_count = 0; } } /* ---- 主运行循环 ---- */ void Menu_Run(void) { switch (g_page.page_id) { case PAGE_HOME: Menu_DrawHome(); break; case PAGE_MAIN_MENU: Menu_DrawMainMenu(); break; case PAGE_MODEL_LIST: Menu_DrawModelList(); break; case PAGE_MODEL_NEW: Menu_DrawModelNew(); break; case PAGE_CHANNEL_MAP: Menu_DrawChannelMap(); break; case PAGE_MIXER: Menu_DrawMixer(); break; case PAGE_MIXER_EDIT: Menu_DrawMixerEdit(); break; case PAGE_RF_CONFIG: Menu_DrawRFConfig(); break; case PAGE_NRF_CONFIG: Menu_DrawNRFConfig(); break; case PAGE_CRFS_CONFIG: Menu_DrawCRFSConfig(); break; case PAGE_PWM_CONFIG: Menu_DrawPWMConfig(); break; case PAGE_HOME_SET: Menu_DrawHomeSet(); break; case PAGE_BIND: Menu_DrawBind(); break; case PAGE_RF_QUICK: Menu_DrawRFQuick(); break; default: g_page.page_id = PAGE_HOME; break; } }