UI: Add digital mode screen

Use main screen bottom bar in mode screen

mode screen: Move frequency and channel name to center

Show S-meter without squelch bar for digital modes

Change S-meter for digital modes, add audio level meter

Print FM information in mode screen

Add mode screen fonts
replace/257fc50b64998e7b4f49884d01b1581e35cd74b9
Federico Amedeo Izzo 2021-05-06 13:03:41 +02:00 zatwierdzone przez Silvano Seva
rodzic 92ea1535ff
commit 118c514081
9 zmienionych plików z 375 dodań i 35 usunięć

Wyświetl plik

@ -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',

Wyświetl plik

@ -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.

Wyświetl plik

@ -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;
/**

Wyświetl plik

@ -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.

Wyświetl plik

@ -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);

Wyświetl plik

@ -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();
}

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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 <http://www.gnu.org/licenses/> *
***************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <ui.h>
#include <string.h>
/* 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();
}

Wyświetl plik

@ -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;