diff --git a/meson.build b/meson.build index 5620979f..f22406c9 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,7 @@ def = {'VCOM_ENABLED' : ''} openrtx_src = ['openrtx/src/state.c', 'openrtx/src/ui/ui.c', 'openrtx/src/ui/ui_main.c', + 'openrtx/src/ui/ui_mode.c', 'openrtx/src/ui/ui_menu.c', 'openrtx/src/threads.c', 'openrtx/src/battery.c', diff --git a/openrtx/include/interfaces/graphics.h b/openrtx/include/interfaces/graphics.h index 27146e6b..dd7d43be 100644 --- a/openrtx/include/interfaces/graphics.h +++ b/openrtx/include/interfaces/graphics.h @@ -298,10 +298,31 @@ void gfx_drawBattery(point_t start, uint16_t width, uint16_t height, uint8_t per * @param height: Smeter height * @param rssi: rssi level in dBm * @param squelch: squelch level in percentage - * @param color: color of the squelch and smeter bar + * @param color: color of the squelch bar */ void gfx_drawSmeter(point_t start, uint16_t width, uint16_t height, float rssi, float squelch, color_t color); +/** + * Function to draw Smeter of arbitrary size. + * Version without squelch bar for digital protocols + * Starting coordinates are relative to the top left point. + * @param start: Smeter start point, in pixel coordinates. + * @param width: Smeter width + * @param height: Smeter height + * @param rssi: rssi level in dBm + */ +void gfx_drawSmeterNoSquelch(point_t start, uint16_t width, uint16_t height, float rssi); + +/** + * Function to draw level meter of arbitrary size. + * Starting coordinates are relative to the top left point. + * @param start: level meter start point, in pixel coordinates. + * @param width: level meter width + * @param height: level meter height + * @param level: level in range {0, 255} + */ +void gfx_drawLevelMeter(point_t start, uint16_t width, uint16_t height, uint8_t level); + /** * Function to draw GPS SNR bar graph of arbitrary size. * Starting coordinates are relative to the top left point. diff --git a/openrtx/include/ui.h b/openrtx/include/ui.h index bd9a3d0a..2ba848c3 100644 --- a/openrtx/include/ui.h +++ b/openrtx/include/ui.h @@ -40,6 +40,8 @@ enum uiScreen MAIN_VFO = 0, MAIN_VFO_INPUT, MAIN_MEM, + MODE_VFO, + MODE_MEM, MENU_TOP, MENU_ZONE, MENU_CHANNEL, @@ -134,6 +136,8 @@ typedef struct layout_t fontSize_t bottom_font; fontSize_t input_font; fontSize_t menu_font; + fontSize_t mode_font_big; + fontSize_t mode_font_small; } layout_t; /** diff --git a/openrtx/src/graphics.c b/openrtx/src/graphics.c index e94128e5..5db7f9f7 100644 --- a/openrtx/src/graphics.c +++ b/openrtx/src/graphics.c @@ -612,15 +612,15 @@ void gfx_drawBattery(point_t start, uint16_t width, uint16_t height, * Function to draw RSSI-meter of arbitrary size * starting coordinates are relative to the top left point. * - * * * * * * * *| - * ***************************************** | - * ****************************************** <- RSSI | - * ****************************************** | <-- Height (px) - * ****************************************** | - * **************** <-- Squelch | - * *************** | - * * * * * * * *| - * ___________________________________________________________________ + * 1 2 3 4 5 6 7 8 9 +10 +20| + * ****************************************** | + * ****************************************** <- RSSI | + * ****************************************** | <-- Height (px) + * ****************************************** | + * **************** <-- Squelch | + * *************** | + * * * * * * * * * * * *| + * _________________________________________________________________ * * ^ * | @@ -675,6 +675,101 @@ void gfx_drawSmeter(point_t start, uint16_t width, uint16_t height, float rssi, gfx_drawRect(squelch_pos, squelch_width, squelch_height, color, true); } +/* + * Function to draw RSSI-meter of arbitrary size + * Version without squelch bar for digital protocols + * starting coordinates are relative to the top left point. + * + * ****************************************** | + * ****************************************** <- RSSI | + * ****************************************** | <-- Height (px) + * ****************************************** | + * 1 2 3 4 5 6 7 8 9 +10 +20| + * _________________________________________________________________ + * + * ^ + * | + * + * Width (px) + * + */ +void gfx_drawSmeterNoSquelch(point_t start, uint16_t width, uint16_t height, float rssi) +{ + color_t white = {255, 255, 255, 255}; + color_t yellow = {250, 180, 19 , 255}; + color_t red = {255, 0, 0 , 255}; + + fontSize_t font = FONT_SIZE_5PT; + uint8_t font_height = gfx_getFontHeight(font); + // S-level marks and numbers + for(int i = 0; i < 11; i++) + { + color_t color = (i % 3 == 0) ? yellow : white; + color = (i > 9) ? red : color; + point_t pixel_pos = {start.x + i * (width - 1) / 11, start.y}; + pixel_pos.y += ((height - 1) + font_height); + if (i == 10) { + pixel_pos.x -= 8; + gfx_print(pixel_pos, font, TEXT_ALIGN_LEFT, color, "+%d", i); + } + else + gfx_print(pixel_pos, font, TEXT_ALIGN_LEFT, color, "%d", i); + if (i == 10) { + pixel_pos.x += 8; + } + } + + point_t pixel_pos = {start.x + width - 11, start.y}; + pixel_pos.y += ((height - 1) + font_height); + gfx_print(pixel_pos, font, TEXT_ALIGN_LEFT, red, "+20"); + + // RSSI bar + uint16_t rssi_height = height - 4; + float s_level = (127.0f + rssi) / 6.0f; + uint16_t rssi_width = (s_level < 0.0f) ? 0 : (s_level * (width - 1) / 11); + rssi_width = (s_level > 10.0f) ? width : rssi_width; + point_t rssi_pos = { start.x, start.y + 1 }; + gfx_drawRect(rssi_pos, rssi_width, rssi_height, white, true); +} + +/* + * Function to draw level meter of arbitrary size + * starting coordinates are relative to the top left point. + * + * * * * * *| + * ****************************************** | + * ****************************************** <- level | + * ****************************************** | <-- Height (px) + * ****************************************** | + * * * * * *| + * _________________________________________________________________ + * + * ^ + * | + * + * Width (px) + * + */ +void gfx_drawLevelMeter(point_t start, uint16_t width, uint16_t height, uint8_t level) +{ + color_t white = {255, 255, 255, 255}; + + // S-level marks and numbers + for(int i = 0; i <= 4; i++) + { + point_t pixel_pos = {start.x + i * (width - 1) / 4, start.y}; + gfx_setPixel(pixel_pos, white); + pixel_pos.y += (height - 1); + gfx_setPixel(pixel_pos, white); + } + + // Level bar + uint16_t level_height = height - 4; + uint16_t level_width = (level / 255 * width); + point_t level_pos = { start.x, start.y + 2 }; + gfx_drawRect(level_pos, level_width, level_height, white, true); +} + /* * Function to draw GPS satellites snr bar graph of arbitrary size * starting coordinates are relative to the top left point. diff --git a/openrtx/src/ui/ui.c b/openrtx/src/ui/ui.c index 8bf4120a..ed8ea54d 100644 --- a/openrtx/src/ui/ui.c +++ b/openrtx/src/ui/ui.c @@ -85,6 +85,8 @@ extern void _ui_drawMEMBottom(); extern void _ui_drawMainVFO(); extern void _ui_drawMainVFOInput(ui_state_t* ui_state); extern void _ui_drawMainMEM(); +extern void _ui_drawModeVFO(); +extern void _ui_drawModeMEM(); /* UI menu functions, their implementation is in "ui_menu.c" */ extern void _ui_drawMenuTop(ui_state_t* ui_state); extern void _ui_drawMenuZone(ui_state_t* ui_state); @@ -226,6 +228,10 @@ layout_t _ui_calculateLayout() const fontSize_t input_font = FONT_SIZE_12PT; // Menu font const fontSize_t menu_font = FONT_SIZE_8PT; + // Mode screen frequency font: 12 pt + const fontSize_t mode_font_big = FONT_SIZE_12PT; + // Mode screen details font: 9 pt + const fontSize_t mode_font_small = FONT_SIZE_9PT; // Radioddity GD-77 #elif SCREEN_HEIGHT > 63 @@ -256,6 +262,10 @@ layout_t _ui_calculateLayout() const fontSize_t input_font = FONT_SIZE_8PT; // Menu font const fontSize_t menu_font = FONT_SIZE_6PT; + // Mode screen frequency font: 9 pt + const fontSize_t mode_font_big = FONT_SIZE_9PT; + // Mode screen details font: 6 pt + const fontSize_t mode_font_small = FONT_SIZE_6PT; // Radioddity RD-5R #elif SCREEN_HEIGHT > 47 @@ -283,6 +293,10 @@ layout_t _ui_calculateLayout() const fontSize_t input_font = FONT_SIZE_8PT; // Menu font const fontSize_t menu_font = FONT_SIZE_6PT; + // Mode screen frequency font: 9 pt + const fontSize_t mode_font_big = FONT_SIZE_9PT; + // Mode screen details font: 6 pt + const fontSize_t mode_font_small = FONT_SIZE_6PT; // Not present on this resolution const fontSize_t line1_font = 0; const fontSize_t bottom_font = 0; @@ -321,7 +335,9 @@ layout_t _ui_calculateLayout() line3_font, bottom_font, input_font, - menu_font + menu_font, + mode_font_big, + mode_font_small }; return new_layout; } @@ -779,6 +795,11 @@ void ui_updateFSM(event_t event, bool *sync_rtx) state.ui_screen = MAIN_MEM; } } + else if(msg.keys & KEY_F1) + { + // Switch to Digital Mode VFO screen + state.ui_screen = MODE_VFO; + } else if(input_isNumberPressed(msg)) { // Open Frequency input screen @@ -847,6 +868,46 @@ void ui_updateFSM(event_t event, bool *sync_rtx) _ui_fsm_loadChannel(state.channel_index - 1, sync_rtx); } break; + // Digital Mode VFO screen + case MODE_VFO: + if(msg.keys & KEY_ENTER) + { + // Save current main state + ui_state.last_main_state = state.ui_screen; + // Open Menu + state.ui_screen = MENU_TOP; + } + else if(msg.keys & KEY_ESC) + { + // Switch to VFO screen + state.ui_screen = MAIN_VFO; + } + else if(msg.keys & KEY_F1) + { + // Switch to Main VFO screen + state.ui_screen = MAIN_VFO; + } + break; + // Digital Mode MEM screen + case MODE_MEM: + if(msg.keys & KEY_ENTER) + { + // Save current main state + ui_state.last_main_state = state.ui_screen; + // Open Menu + state.ui_screen = MENU_TOP; + } + else if(msg.keys & KEY_ESC) + { + // Switch to MEM screen + state.ui_screen = MAIN_MEM; + } + else if(msg.keys & KEY_F1) + { + // Switch to Main MEM screen + state.ui_screen = MAIN_MEM; + } + break; // Top menu screen case MENU_TOP: if(msg.keys & KEY_UP || msg.keys & KNOB_LEFT) @@ -1173,6 +1234,14 @@ void ui_updateGUI() case MAIN_MEM: _ui_drawMainMEM(); break; + // Digital Mode VFO screen + case MODE_VFO: + _ui_drawModeVFO(); + break; + // Digital Mode MEM screen + case MODE_MEM: + _ui_drawModeMEM(); + break; // Top menu screen case MENU_TOP: _ui_drawMenuTop(&ui_state); diff --git a/openrtx/src/ui/ui_main.c b/openrtx/src/ui/ui_main.c index 7fdce81b..f00e7b92 100644 --- a/openrtx/src/ui/ui_main.c +++ b/openrtx/src/ui/ui_main.c @@ -145,22 +145,40 @@ void _ui_drawVFOMiddleInput(ui_state_t* ui_state) } } -void _ui_drawBottom() +void _ui_drawMainBottom() { // Squelch bar float rssi = last_state.rssi; float squelch = last_state.sqlLevel / 16.0f; - point_t smeter_pos = { layout.horizontal_pad, - layout.bottom_pos.y + - layout.status_v_pad + - layout.text_v_offset - - layout.bottom_h }; - gfx_drawSmeter(smeter_pos, - SCREEN_WIDTH - 2 * layout.horizontal_pad, - layout.bottom_h - 1, - rssi, - squelch, - color_white); + point_t meter_pos = { layout.horizontal_pad, + layout.bottom_pos.y + + layout.status_v_pad + + layout.text_v_offset - + layout.bottom_h }; + uint16_t meter_height = layout.bottom_h - 1; + switch(last_state.channel.mode) + { + case FM: + gfx_drawSmeter(meter_pos, + SCREEN_WIDTH - 2 * layout.horizontal_pad, + meter_height, + rssi, + squelch, + color_white); + break; + case DMR: + meter_height = (meter_height / 2); + gfx_drawLevelMeter(meter_pos, + SCREEN_WIDTH - 2 * layout.horizontal_pad, + meter_height, + 255); + meter_pos.y += meter_height; + gfx_drawSmeterNoSquelch(meter_pos, + SCREEN_WIDTH - 2 * layout.horizontal_pad, + meter_height, + rssi); + break; + } } void _ui_drawMainVFO() @@ -168,7 +186,7 @@ void _ui_drawMainVFO() gfx_clearScreen(); _ui_drawMainTop(); _ui_drawFrequency(); - _ui_drawBottom(); + _ui_drawMainBottom(); } void _ui_drawMainVFOInput(ui_state_t* ui_state) @@ -176,7 +194,7 @@ void _ui_drawMainVFOInput(ui_state_t* ui_state) gfx_clearScreen(); _ui_drawMainTop(); _ui_drawVFOMiddleInput(ui_state); - _ui_drawBottom(); + _ui_drawMainBottom(); } void _ui_drawMainMEM() @@ -185,5 +203,5 @@ void _ui_drawMainMEM() _ui_drawMainTop(); _ui_drawZoneChannel(); _ui_drawFrequency(); - _ui_drawBottom(); + _ui_drawMainBottom(); } diff --git a/openrtx/src/ui/ui_menu.c b/openrtx/src/ui/ui_menu.c index d24ffff3..4b2ce940 100644 --- a/openrtx/src/ui/ui_menu.c +++ b/openrtx/src/ui/ui_menu.c @@ -594,17 +594,34 @@ bool _ui_drawMacroMenu() { // Smeter bar float rssi = last_state.rssi; float squelch = last_state.sqlLevel / 16.0f; - point_t smeter_pos = { layout.horizontal_pad, + point_t meter_pos = { layout.horizontal_pad, layout.bottom_pos.y + layout.status_v_pad + layout.text_v_offset - layout.bottom_h }; - gfx_drawSmeter(smeter_pos, - SCREEN_WIDTH - 2 * layout.horizontal_pad, - layout.bottom_h - 1, - rssi, - squelch, - yellow_fab413); - + uint16_t meter_height = layout.bottom_h - 1; + switch(last_state.channel.mode) + { + case FM: + gfx_drawSmeter(meter_pos, + SCREEN_WIDTH - 2 * layout.horizontal_pad, + meter_height, + rssi, + squelch, + yellow_fab413); + break; + case DMR: + meter_height = (meter_height / 2); + gfx_drawLevelMeter(meter_pos, + SCREEN_WIDTH - 2 * layout.horizontal_pad, + meter_height, + 255); + meter_pos.y += meter_height; + gfx_drawSmeterNoSquelch(meter_pos, + SCREEN_WIDTH - 2 * layout.horizontal_pad, + meter_height, + rssi); + break; + } return true; } diff --git a/openrtx/src/ui/ui_mode.c b/openrtx/src/ui/ui_mode.c new file mode 100644 index 00000000..c6904b4f --- /dev/null +++ b/openrtx/src/ui/ui_mode.c @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#include +#include +#include +#include + +/* UI main screen helper functions, their implementation is in "ui_main.c" */ +extern void _ui_drawMainTop(); +extern void _ui_drawMainBottom(); + +void _ui_drawModeVFOFreq() +{ + // Print VFO RX Frequency on line 1 of 3 + gfx_printLine(1, 3, layout.top_h, SCREEN_HEIGHT - layout.bottom_h, + layout.horizontal_pad, layout.mode_font_big, + TEXT_ALIGN_CENTER, color_white, "%03lu.%05lu", + (unsigned long)last_state.channel.rx_frequency/1000000, + (unsigned long)last_state.channel.rx_frequency%1000000/10); +} + +void _ui_drawMEMChannel() +{ + // Print Channel name on line 1 of 3 + gfx_printLine(1, 3, layout.top_h, SCREEN_HEIGHT - layout.bottom_h, + layout.horizontal_pad, layout.mode_font_small, + TEXT_ALIGN_CENTER, color_white, "%03d: %.12s", + last_state.channel_index, last_state.channel.name); +} + +void _ui_drawModeDetails() +{ + char bw_str[8] = { 0 }; + char encdec_str[9] = { 0 }; + switch(last_state.channel.mode) + { + case FM: + // Get Bandwith string + if(last_state.channel.bandwidth == BW_12_5) + snprintf(bw_str, 8, "12.5"); + else if(last_state.channel.bandwidth == BW_20) + snprintf(bw_str, 8, "20"); + else if(last_state.channel.bandwidth == BW_25) + snprintf(bw_str, 8, "25"); + // Get encdec string + bool tone_tx_enable = last_state.channel.fm.txToneEn; + bool tone_rx_enable = last_state.channel.fm.rxToneEn; + if (tone_tx_enable && tone_rx_enable) + snprintf(encdec_str, 9, "E+D"); + else if (tone_tx_enable && !tone_rx_enable) + snprintf(encdec_str, 9, "E"); + else if (!tone_tx_enable && tone_rx_enable) + snprintf(encdec_str, 9, "D"); + else + snprintf(encdec_str, 9, " "); + + // Print Bandwidth info + gfx_printLine(2, 3, layout.top_h, SCREEN_HEIGHT - layout.bottom_h, + layout.horizontal_pad, layout.mode_font_small, + TEXT_ALIGN_LEFT, color_white, "BW:%s", bw_str); + // Print Tone and encdec info + gfx_printLine(3, 3, layout.top_h, SCREEN_HEIGHT - layout.bottom_h, + layout.horizontal_pad, layout.mode_font_small, + TEXT_ALIGN_LEFT, color_white, "T:%4.1f S:%s", + ctcss_tone[last_state.channel.fm.txTone]/10.0f, + encdec_str); + break; + case DMR: + // Print Module Frequency on line 2 of 3 + gfx_printLine(2, 3, layout.top_h, SCREEN_HEIGHT - layout.bottom_h, + layout.horizontal_pad, layout.mode_font_small, + TEXT_ALIGN_LEFT, color_white, "TG:"); + // Print User ID on line 3 of 3 + gfx_printLine(3, 3, layout.top_h, SCREEN_HEIGHT - layout.bottom_h, + layout.horizontal_pad, layout.mode_font_small, + TEXT_ALIGN_LEFT, color_white, "ID:"); + break; + } +} + +void _ui_drawModeVFO() +{ + gfx_clearScreen(); + _ui_drawMainTop(); + _ui_drawModeVFOFreq(); + _ui_drawModeDetails(); + _ui_drawMainBottom(); +} + +void _ui_drawModeMEM() +{ + gfx_clearScreen(); + _ui_drawMainTop(); + _ui_drawMEMChannel(); + _ui_drawModeDetails(); + _ui_drawMainBottom(); +} diff --git a/platform/drivers/keyboard/keyboard_linux.c b/platform/drivers/keyboard/keyboard_linux.c index c1789f72..c67c9366 100644 --- a/platform/drivers/keyboard/keyboard_linux.c +++ b/platform/drivers/keyboard/keyboard_linux.c @@ -50,7 +50,7 @@ keyboard_t kbd_getKeys() { if (state[SDL_SCANCODE_RIGHT]) keys |= KEY_RIGHT; if (state[SDL_SCANCODE_RETURN]) keys |= KEY_ENTER; if (state[SDL_SCANCODE_NONUSHASH]) keys |= KEY_HASH; - if (state[SDL_SCANCODE_MINUS]) keys |= KEY_F1; + if (state[SDL_SCANCODE_N]) keys |= KEY_F1; if (state[SDL_SCANCODE_M]) keys |= KEY_MONI; if (state[SDL_SCANCODE_PAGEUP]) keys |= KNOB_LEFT; if (state[SDL_SCANCODE_PAGEDOWN]) keys |= KNOB_RIGHT;