From 09d687dcdf149b8aac4307355d5307657899eb3b Mon Sep 17 00:00:00 2001 From: Sheikah <> Date: Mon, 30 Jan 2023 22:31:00 +0800 Subject: [PATCH] add pointer mode --- Core/App/Graphic/ui.c | 87 ++++++++++++--------- Core/App/Graphic/ui.h | 5 +- Core/App/app.c | 171 +++++++++++++++++++++++++++++++++++++----- Core/App/global.c | 3 +- Core/App/global.h | 19 ++++- 5 files changed, 229 insertions(+), 56 deletions(-) diff --git a/Core/App/Graphic/ui.c b/Core/App/Graphic/ui.c index 192de42..16d2f7b 100644 --- a/Core/App/Graphic/ui.c +++ b/Core/App/Graphic/ui.c @@ -1,5 +1,7 @@ #include #include "global.h" +#include "ui.h" +#include "time.h" #include "st7735.h" #include "Images/digi18x32.h" #include "monoimg.h" @@ -74,51 +76,52 @@ void ui_com_title_bar(uint8_t clear, uint8_t *text, uint32_t bytes_len) { bmf_draw_text(font_unifont_16x16, text, bytes_len, off_x, 1, ST7735_WIDTH - 2, 16, ST7735_YELLOW); } -void ui_com_freq_digital(uint8_t clear) { +void ui_com_freq_digital(uint8_t clear, uint8_t only_pointer) { // 5位数字, 即高32+2(小数点高度),宽90 uint16_t off_x = (ST7735_WIDTH - 90) / 2; uint16_t off_y = (ST7735_HEIGHT - 34 - 34 - 18) / 2 + 17; + uint16_t freq_num; if (global_data.rf_mode == G_RF_MODE_AM) { - uint16_t scale = 10000; - uint32_t tmp = 0; - if (clear) { - ST7735_FillRectangle(off_x, off_y+32, 90, 2, ST7735_BLACK); // 清除小数点 - } - while (scale > 0) { - if (clear) { - ui_text_number18x32_with_bg(tmp, off_x, off_y, ST7735_COLOR565(0xFF, 0x7F, 0), ST7735_BLACK); - } else { - ui_text_number18x32(tmp, off_x, off_y, ST7735_COLOR565(0xFF, 0x7F, 0)); - } - off_x += 18; - scale /= 10; - } + freq_num = global_data.freq; } else { - uint16_t fm_freq = global_data.freq / 20; - uint8_t fm_freq_float = (global_data.freq % 20) * 5; - uint16_t scale = 100; - uint16_t tmp = 0; - if (clear) { - ST7735_FillRectangle(off_x, off_y + 32, 18 * 3 - 1, 2, ST7735_BLACK); // 清除小数点 - ST7735_FillRectangle(off_x + (18 * 3) + 1, off_y + 32, 18 * 2 - 1, 2, ST7735_BLACK); // 清除小数点 + freq_num = global_data.freq * 5; + } + uint16_t color_orange = ST7735_COLOR565(0xFF, 0x7F, 0); + if (clear) { + if (global_data.rf_mode == G_RF_MODE_AM) { + ST7735_FillRectangle(off_x, off_y+32, 90, 3, ST7735_BLACK); // 清除小数点 + } else { + ST7735_FillRectangle(off_x, off_y + 32, 18 * 3 - 1, 3, ST7735_BLACK); // 清除小数点 + ST7735_FillRectangle(off_x + (18 * 3) + 1, off_y + 32, 18 * 2 - 1, 3, ST7735_BLACK); // 清除小数点 + ST7735_FillRectangle(off_x + (18 * 3) - 1, off_y + 34, 2, 1, ST7735_BLACK); } - while (scale > 0) { - tmp = (fm_freq / scale) % 10; - if (clear) { - ui_text_number18x32_with_bg(tmp, off_x, off_y, ST7735_COLOR565(0xFF, 0x7F, 0), ST7735_BLACK); - } else { - ui_text_number18x32(tmp, off_x, off_y, ST7735_COLOR565(0xFF, 0x7F, 0)); - } - off_x += 18; - scale /= 10; + } + if (global_data.rf_mode == G_RF_MODE_FM) { + // 绘制小数点 + ST7735_FillRectangle(off_x + (18 * 3) - 1, off_y + 32, 2, 2, color_orange); + } + if (global_data.point_mode & G_PMOD_MODE_MASK) { + // 绘制光标 + uint8_t blink_state = (ticks_ms() / UI_BLINK_MS) % 2; + uint8_t blink_state2 = !(global_data.point_mode & G_PMOD_PBLINK_MASK); + if (!(global_data.point_mode & G_PMOD_PMOVE_MASK) || (blink_state ^ blink_state2)) { + uint8_t p_pos = (global_data.point_mode & G_POMD_POS_MASK) >> G_POMD_POS_BOFF; + uint16_t p_off = (4 - p_pos) * 18 + 2 + off_x; + ST7735_FillRectangle(p_off, off_y + 33, 14, 2, color_orange); + global_data.point_mode = global_data.point_mode | G_PMOD_PBLINK2_MASK; + } else { + global_data.point_mode = global_data.point_mode & (~G_PMOD_PBLINK2_MASK); } - scale = 10; + } + uint16_t scale = 10000; + uint32_t tmp = 0; + if (!only_pointer) { while (scale > 0) { - tmp = (fm_freq_float / scale) % 10; + tmp = (freq_num / scale) % 10; if (clear) { - ui_text_number18x32_with_bg(tmp, off_x, off_y, ST7735_COLOR565(0xFF, 0x7F, 0), ST7735_BLACK); + ui_text_number18x32_with_bg(tmp, off_x, off_y, color_orange, ST7735_BLACK); } else { - ui_text_number18x32(tmp, off_x, off_y, ST7735_COLOR565(0xFF, 0x7F, 0)); + ui_text_number18x32(tmp, off_x, off_y, color_orange); } off_x += 18; scale /= 10; @@ -200,7 +203,19 @@ void ui_screen_main() { ui_com_main_border(); ui_com_title_bar(0, u8str("Radio"), 5); ui_com_fm_am(0); - ui_com_freq_digital(0); + ui_com_freq_digital(0, 0); ui_com_vol_bar(0); ui_com_sig_bar(0); } + +void ui_screen_main_animation() { + // 绘制闪烁效果 + if ((global_data.point_mode & G_PMOD_MODE_MASK) && (global_data.point_mode & G_PMOD_PMOVE_MASK)) { + uint8_t blink_state = (ticks_ms() / UI_BLINK_MS) % 2; + uint8_t blink_state2 = !(global_data.point_mode & G_PMOD_PBLINK_MASK); + uint8_t blink_state3 = (global_data.point_mode & G_PMOD_PBLINK2_MASK) ? 1 : 0; + if ((blink_state ^ blink_state2) ^ blink_state3) { + ui_com_freq_digital(1, 1); + } + } +} diff --git a/Core/App/Graphic/ui.h b/Core/App/Graphic/ui.h index e44d51f..5c58dc9 100644 --- a/Core/App/Graphic/ui.h +++ b/Core/App/Graphic/ui.h @@ -1,13 +1,16 @@ #pragma once #include +#define UI_BLINK_MS 250 + void ui_text_number18x32(uint32_t num, uint16_t x, uint16_t y, uint16_t color); /* 绘制界面元素 */ void ui_com_title_bar(uint8_t clear, uint8_t *text, uint32_t bytes_len); -void ui_com_freq_digital(uint8_t clear); +void ui_com_freq_digital(uint8_t clear, uint8_t only_pointer); void ui_com_fm_am(uint8_t clear); void ui_com_vol_bar(uint8_t clear); void ui_com_sig_bar(uint8_t clear); /* 绘制主界面 */ void ui_screen_main(); +void ui_screen_main_animation(); diff --git a/Core/App/app.c b/Core/App/app.c index ee056d7..6f8d8c9 100644 --- a/Core/App/app.c +++ b/Core/App/app.c @@ -3,6 +3,29 @@ #include "ui.h" #include "keypad.h" #include "global.h" +#include "time.h" + +void __limit_freq_range() { + uint16_t limit_min = (global_data.rf_mode == G_RF_MODE_AM) ? G_AM_FREQ_MIN : G_FM_FREQ_MIN; + uint16_t limit_max = (global_data.rf_mode == G_RF_MODE_AM) ? G_AM_FREQ_MAX : G_FM_FREQ_MAX; + if (global_data.freq < limit_min) { + global_data.freq = limit_min; + } else if (global_data.freq > limit_max) { + global_data.freq = limit_max; + } +} + +void __send_freq() { + // TODO: 发送频率 +} + +void __switch_to_fm() { + // TODO: 切换到FM模式 +} + +void __switch_to_am() { + // TODO: 切换到AM模式 +} void app_init() { // 程序开始时执行一次 @@ -17,37 +40,151 @@ void app_main_loop() { uint8_t event_type = kp_Type(event); uint8_t event_value = kp_Value(event); if (event_type == kp_ROTATE_RIGHT || event_type == kp_ROTATE_LEFT) { - // 调整频率 - if (event_type == kp_ROTATE_RIGHT) { - global_data.freq += event_value; + if (global_data.point_mode & G_PMOD_MODE_MASK) { + // 指针模式调整 + uint8_t p_pos = (global_data.point_mode & G_POMD_POS_MASK) >> G_POMD_POS_BOFF; + if (global_data.point_mode & G_PMOD_PMOVE_MASK) { + // 调整指针位置 + if (event_type == kp_ROTATE_RIGHT) { + p_pos += 100; + p_pos -= event_value; + } else { + p_pos += event_value; + } + p_pos %= 5; // 0~4, 右边第一个数值为0号位置 + global_data.point_mode = global_data.point_mode & (~G_POMD_POS_MASK); + global_data.point_mode = global_data.point_mode | ((p_pos << G_POMD_POS_BOFF) & G_POMD_POS_MASK); + printf("Adjust Point Pos: %u\n", p_pos); + } else { + // 调整指针位置的数字 + uint16_t num_freq; + if (global_data.rf_mode == G_RF_MODE_AM) { + num_freq = global_data.freq; + } else { + num_freq = global_data.freq * 5; + } + /* adjust number at all */ + uint16_t scale = 1; + if (p_pos == 0 && global_data.rf_mode == G_RF_MODE_FM) { + scale = 5; + } else { + uint8_t tmp; + for (tmp = 0; tmp < p_pos; tmp ++) { + scale *= 10; + } + } + if (event_type == kp_ROTATE_RIGHT) { + num_freq += scale * event_value; + } else { + if (scale * event_value < num_freq) { + num_freq -= scale * event_value; + } else { + num_freq = 0; + } + } + uint16_t limit_min = (global_data.rf_mode == G_RF_MODE_AM) ? G_AM_FREQ_MIN : G_FM_FREQ_MIN * 5; + uint16_t limit_max = (global_data.rf_mode == G_RF_MODE_AM) ? G_AM_FREQ_MAX : G_FM_FREQ_MAX * 5; + if (num_freq > limit_max || num_freq < limit_min) { + return; // ignore if overflow + } + /* adjust number one by one */ + // uint8_t scale = 1; + // uint16_t tmp; + // uint16_t num_lower, num_upper; + // uint8_t inc = (p_pos == 0 && global_data.rf_mode == G_RF_MODE_FM) ? 5 : 1; + // uint8_t lim = 10; + // if (p_pos == 4) { + // if (global_data.rf_mode == G_RF_MODE_AM) { + // lim = 3; + // } else { + // lim = 1; + // } + // } + // for (tmp = 0; tmp < p_pos; tmp ++) { + // scale *= 10; + // } + // num_lower = num_freq % scale; + // num_upper = num_freq / scale / 10; + // tmp = num_freq / scale % 10; + // if (event_type == kp_ROTATE_RIGHT) { + // tmp += (event_value * inc); + // } else { + // tmp += lim % 100; + // tmp -= (event_value * inc); + // } + // tmp %= lim; + // num_freq = (num_upper * scale * 10) + (tmp * scale) + num_lower; + if (global_data.rf_mode == G_RF_MODE_AM) { + global_data.freq = num_freq; + } else { + global_data.freq = num_freq / 5; + } + printf("Adjust Freq: %u\n", global_data.freq); + } } else { - global_data.freq -= event_value; + // 直接调整频率 + if (event_type == kp_ROTATE_RIGHT) { + global_data.freq += event_value; + } else { + global_data.freq -= event_value; + } + __limit_freq_range(); + __send_freq(); + printf("Adjust Freq: %u\n", global_data.freq); } - uint16_t limit_min = (global_data.rf_mode == G_RF_MODE_AM) ? G_AM_FREQ_MIN : G_FM_FREQ_MIN; - uint16_t limit_max = (global_data.rf_mode == G_RF_MODE_AM) ? G_AM_FREQ_MAX : G_FM_FREQ_MAX; - if (global_data.freq < limit_min) { - global_data.freq = limit_min; - } else if (global_data.freq > limit_max) { - global_data.freq = limit_max; - } - printf("Freq: %d\n", global_data.freq); - ui_com_freq_digital(1); + ui_com_freq_digital(1, 0); } else if (event_type == kp_SHORT_CLICK) { - if (event_value == kp_KEY1) { + if (global_data.point_mode & G_PMOD_MODE_MASK) { + if (event_value == kp_KEYENCODER) { + if (global_data.point_mode & G_PMOD_PMOVE_MASK) { + // 退出移动指针模式 + global_data.point_mode = global_data.point_mode & (~G_PMOD_PMOVE_MASK); + printf("Exit Pointer Move Mode.\n"); + } else { + // 进入移动指针模式 + global_data.point_mode = global_data.point_mode | G_PMOD_PMOVE_MASK; + uint8_t blink_state = (ticks_ms() / UI_BLINK_MS) % 2; // 该时间段指示条消失 + if (blink_state) { + global_data.point_mode = global_data.point_mode | G_PMOD_PBLINK_MASK; + } else { + global_data.point_mode = global_data.point_mode & (~G_PMOD_PBLINK_MASK); + } + printf("Enter Pointer Move Mode.\n"); + } + ui_com_freq_digital(1, 0); + } + } else if (event_value == kp_KEY1) { // 切换FM和AM if (global_data.rf_mode == G_RF_MODE_AM) { global_data.rf_mode = G_RF_MODE_FM; global_data.freq = G_FM_FREQ_MIN; + __switch_to_fm(); } else { global_data.rf_mode = G_RF_MODE_AM; global_data.freq = G_AM_FREQ_MIN; + __switch_to_am(); } ui_com_fm_am(1); - ui_com_freq_digital(1); + ui_com_freq_digital(1, 0); } } else if (event_type == kp_LONG_PRESS) { - // + if (event_value == kp_KEYENCODER) { + if (global_data.point_mode & G_PMOD_MODE_MASK) { + // 退出指针模式 + global_data.point_mode = global_data.point_mode & (~G_PMOD_MODE_MASK); + __limit_freq_range(); + __send_freq(); + printf("Exit Pointer Mode.\n"); + } else { + // 进入指针模式 + global_data.point_mode = global_data.point_mode | G_PMOD_MODE_MASK; + global_data.point_mode = global_data.point_mode & (~G_PMOD_PMOVE_MASK); + printf("Enter Pointer Mode.\n"); + } + ui_com_freq_digital(1, 0); + } } else if (event_type != kp_NOP) { - printf("event: %d, key: %d\n", event_type, event_value); + printf("event: %u, key: %u\n", event_type, event_value); } + ui_screen_main_animation(); } diff --git a/Core/App/global.c b/Core/App/global.c index d6fe198..157e727 100644 --- a/Core/App/global.c +++ b/Core/App/global.c @@ -5,5 +5,6 @@ GlobalData global_data = { 880 * 2, // freq G_RF_MODE_FM, //rf_mode 16, // volumn - 97 //signal + 97, //signal + 0b00000000 //point_mode }; diff --git a/Core/App/global.h b/Core/App/global.h index 3201c31..455fc7c 100644 --- a/Core/App/global.h +++ b/Core/App/global.h @@ -8,11 +8,28 @@ #define G_AM_FREQ_MIN 100 #define G_AM_FREQ_MAX 33000 +#define G_PMOD_MODE_MASK 0b00000001 +#define G_PMOD_PMOVE_MASK 0b00000010 +#define G_POMD_POS_MASK 0b00011100 +#define G_POMD_POS_BOFF 2 +#define G_POMD_POS_BLEN 3 +#define G_PMOD_PBLINK_MASK 0b00100000 +#define G_PMOD_PBLINK2_MASK 0b01000000 + typedef struct GlobalData { - uint16_t freq; // FM x50kHz AM x1kHz + /** FM x50kHz AM x1kHz */ + uint16_t freq; uint8_t rf_mode; uint8_t volumn; uint8_t signal; + /** 指针模式变量 + * bit 0 标记是否进入指针模式 + * bit 1 标记是否正在移动指针 + * bit 2~4 记录了当前指针的位置 + * bit 5 标记了当前时间段指针指示是否要显示(用于闪烁动画) + * bit 6 标记了当前指针的状态(用于闪烁动画) + */ + volatile uint8_t point_mode; } GlobalData; extern GlobalData global_data;