1299 lines
44 KiB
C
1299 lines
44 KiB
C
/*
|
|
* Copyright (C) 2019-2025 Roger Clark, VK3KYY / G4KYF
|
|
* Daniel Caujolle-Bert, F1RMB
|
|
*
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
|
* in the documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* 4. Use of this source code or binary releases for commercial purposes is strictly forbidden. This includes, without limitation,
|
|
* incorporation in a commercial product or incorporation into a product or project which allows commercial use.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
#include "user_interface/uiGlobals.h"
|
|
#include "user_interface/menuSystem.h"
|
|
#include "user_interface/uiUtilities.h"
|
|
#include "user_interface/uiLocalisation.h"
|
|
#include "interfaces/gps.h"
|
|
#include "usb/usb_com.h"
|
|
|
|
#if defined(HAS_GPS)
|
|
|
|
static void updateScreen(bool isFirstRun, bool forceRedraw);
|
|
static void handleEvent(uiEvent_t *ev);
|
|
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
#define CURRENT_PAGE_ON_MONOCHOME(p) if (menuDataGlobal.currentItemIndex == (p))
|
|
#else
|
|
#define CURRENT_PAGE_ON_MONOCHOME(p)
|
|
#endif
|
|
|
|
#define POLAR_GRAPHICS_X_OFFSET 0
|
|
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
#if defined(PLATFORM_RD5R)
|
|
#define POLAR_GRAPHICS_Y_OFFSET 31
|
|
#define RSSI_X_OFFSET 0
|
|
#define RSSI_BARS_Y_POS 60
|
|
#define MAIDENHEAD_HDOP_Y_POS 40
|
|
#define NUM_BARS 14
|
|
#define DOT_RADIUS 1
|
|
#define MAIDENHEAD_HDOP_MARGIN 0
|
|
|
|
#define VALUES_FONT_SIZE FONT_SIZE_3
|
|
#define VALUES_FONT_SIZE_SMALL FONT_SIZE_2
|
|
#define UNITS_FONT_SIZE FONT_SIZE_1
|
|
#define UNITS_Y_OFFSET 0
|
|
#define VALUES_RD5R_V_GAP FONT_SIZE_3_HEIGHT
|
|
#define VALUES_RD5R_V_OFFSET 4
|
|
|
|
#define VALUES_FONT_WIDTH 8
|
|
#define VALUES_FONT_HEIGHT 8
|
|
|
|
#define DIRECTION_REGION_V_OFFSET 0
|
|
#define DIRECTION_REGION_H_OFFSET 0
|
|
#define CARDINALS_REGION_HEIGHT (FONT_SIZE_2_HEIGHT - 1)
|
|
|
|
#define DIRECTION_SATS_X_POS 11
|
|
#define DIRECTION_SATS_Y_POS 28
|
|
|
|
#define DIRECTION_CARDINAL_OFFSET 8
|
|
#define DIRECTION_COURSE_X_POS 75
|
|
#define DIRECTION_COURSE_Y_POS 25
|
|
|
|
#define DIRECTION_ALT_X_POS 81
|
|
#define DIRECTION_ALT_Y_POS 28
|
|
|
|
#define DIRECTION_HDOP_X_POS 42
|
|
#define DIRECTION_HDOP_Y_POS 28
|
|
|
|
#define DIRECTION_HEADING_X_POS 28
|
|
#define DIRECTION_HEADING_Y_POS 31
|
|
#define DIRECTION_HEADING_RADIUS 16
|
|
#define TOP_ARROW_OFFSET (DIRECTION_HEADING_RADIUS - 6)
|
|
#define BASE_ARROW_OFFSET (DIRECTION_HEADING_RADIUS >> 1)
|
|
|
|
#define DIRECTION_FIXTYPE_X_POS 25
|
|
#define DIRECTION_FIXTYPE_Y_POS 28
|
|
|
|
#define DIRECTION_SPEED_X_POS 65
|
|
#define DIRECTION_SPEED_Y_POS 40
|
|
|
|
#define MAX_RADIUS 15
|
|
|
|
#define MAX_RSSI_Y_PIXELS 29
|
|
|
|
#else // PLATFORM_RD5R
|
|
|
|
#define POLAR_GRAPHICS_Y_OFFSET 40
|
|
#define RSSI_X_OFFSET 0
|
|
#define RSSI_BARS_Y_POS 54
|
|
#define MAIDENHEAD_HDOP_Y_POS 48
|
|
#define NUM_BARS 14
|
|
#define DOT_RADIUS 1
|
|
#define MAIDENHEAD_HDOP_MARGIN 0
|
|
|
|
#define VALUES_FONT_SIZE FONT_SIZE_3
|
|
#define VALUES_FONT_SIZE_SMALL FONT_SIZE_2
|
|
#define UNITS_FONT_SIZE FONT_SIZE_1
|
|
#define UNITS_Y_OFFSET 6
|
|
#define VALUES_RD5R_V_GAP 0
|
|
#define VALUES_RD5R_V_OFFSET 0
|
|
|
|
#define VALUES_FONT_WIDTH 8
|
|
#define VALUES_FONT_HEIGHT 16
|
|
|
|
#define DIRECTION_REGION_V_OFFSET 2
|
|
#define DIRECTION_REGION_H_OFFSET 5
|
|
#define CARDINALS_REGION_HEIGHT (FONT_SIZE_2_HEIGHT - 1)
|
|
|
|
#define DIRECTION_SATS_X_POS 11
|
|
#define DIRECTION_SATS_Y_POS 34
|
|
|
|
#define DIRECTION_CARDINAL_OFFSET 8
|
|
#define DIRECTION_COURSE_X_POS 75
|
|
#define DIRECTION_COURSE_Y_POS 29
|
|
|
|
#define DIRECTION_ALT_X_POS 81
|
|
#define DIRECTION_ALT_Y_POS 34
|
|
|
|
#define DIRECTION_HDOP_X_POS 42
|
|
#define DIRECTION_HDOP_Y_POS 34
|
|
|
|
#define DIRECTION_HEADING_X_POS 28
|
|
#define DIRECTION_HEADING_Y_POS 39
|
|
#define DIRECTION_HEADING_RADIUS 24
|
|
#define TOP_ARROW_OFFSET (DIRECTION_HEADING_RADIUS - 7)
|
|
#define BASE_ARROW_OFFSET ((DIRECTION_HEADING_RADIUS >> 1) + 1)
|
|
|
|
#define DIRECTION_FIXTYPE_X_POS 25
|
|
#define DIRECTION_FIXTYPE_Y_POS 36
|
|
|
|
#define DIRECTION_SPEED_X_POS 65
|
|
#define DIRECTION_SPEED_Y_POS 47
|
|
|
|
#define MAX_RADIUS 22
|
|
|
|
#define MAX_RSSI_Y_PIXELS 25
|
|
|
|
#endif // PLATFORM_RD5R
|
|
|
|
#else
|
|
|
|
#define POLAR_GRAPHICS_Y_OFFSET 72
|
|
#define RSSI_X_OFFSET 2
|
|
#define RSSI_BARS_Y_POS 120
|
|
#define MAIDENHEAD_HDOP_Y_POS 32
|
|
#define NUM_BARS 17
|
|
#define DOT_RADIUS 2
|
|
#define MAIDENHEAD_HDOP_MARGIN 8
|
|
|
|
#define VALUES_FONT_SIZE FONT_SIZE_4
|
|
#define VALUES_FONT_SIZE_SMALL FONT_SIZE_3
|
|
#define UNITS_FONT_SIZE FONT_SIZE_2
|
|
#define UNITS_Y_OFFSET 18
|
|
#define VALUES_RD5R_V_GAP 0
|
|
#define VALUES_RD5R_V_OFFSET 0
|
|
|
|
#define VALUES_FONT_WIDTH 16
|
|
#define VALUES_FONT_HEIGHT 32
|
|
|
|
#define DIRECTION_REGION_V_OFFSET 6
|
|
#define DIRECTION_REGION_H_OFFSET 13
|
|
#define CARDINALS_REGION_HEIGHT FONT_SIZE_3_HEIGHT
|
|
|
|
#define DIRECTION_SATS_X_POS 122
|
|
#define DIRECTION_SATS_Y_POS 30
|
|
|
|
#define DIRECTION_CARDINAL_OFFSET 10
|
|
#define DIRECTION_COURSE_X_POS 56
|
|
#define DIRECTION_COURSE_Y_POS 31
|
|
|
|
#define DIRECTION_ALT_X_POS 12
|
|
#define DIRECTION_ALT_Y_POS 71
|
|
|
|
#define DIRECTION_HDOP_X_POS 111
|
|
#define DIRECTION_HDOP_Y_POS 71
|
|
|
|
#define DIRECTION_HEADING_X_POS 27
|
|
#define DIRECTION_HEADING_Y_POS 39
|
|
#define DIRECTION_HEADING_RADIUS 25
|
|
#define TOP_ARROW_OFFSET (DIRECTION_HEADING_RADIUS - 8)
|
|
#define BASE_ARROW_OFFSET (DIRECTION_HEADING_RADIUS >> 1)
|
|
|
|
#define DIRECTION_FIXTYPE_X_POS 25
|
|
#define DIRECTION_FIXTYPE_Y_POS 36
|
|
|
|
#define DIRECTION_SPEED_X_POS 40
|
|
#define DIRECTION_SPEED_Y_POS 98
|
|
|
|
#define MAX_RADIUS 44
|
|
|
|
#define MAX_RSSI_Y_PIXELS 59
|
|
|
|
#endif
|
|
|
|
typedef enum
|
|
{
|
|
PAGE_COORDS = 0,
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
PAGE_RSSI,
|
|
#else
|
|
PAGE_RSSI = 0,
|
|
#endif
|
|
PAGE_POLAR,
|
|
PAGE_DIRECTION, // MD9600: Sat/HDOP/Alt, MD-UV380 everything in that page
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
PAGE_DIRECTION_2, // Heading/Course
|
|
#endif
|
|
PAGES_MAX
|
|
} Pages_t;
|
|
|
|
typedef enum
|
|
{
|
|
FIELD_SATS_CLEAR = (1 << 0),
|
|
FIELD_SATS_ZERO = (1 << 1),
|
|
FIELD_COURSE_CLEAR = (1 << 2),
|
|
FIELD_COURSE_ZERO = (1 << 3),
|
|
FIELD_ALT_CLEAR = (1 << 4),
|
|
FIELD_ALT_ZERO = (1 << 5),
|
|
FIELD_HDOP_CLEAR = (1 << 6),
|
|
FIELD_HDOP_ZERO = (1 << 7),
|
|
FIELD_SPEED_CLEAR = (1 << 8),
|
|
FIELD_SPEED_ZERO = (1 << 9),
|
|
FIELD_BACKGROUND = (1 << 10),
|
|
FIELD_ALL_CLEAR = (FIELD_SATS_CLEAR | FIELD_COURSE_CLEAR | FIELD_ALT_CLEAR | FIELD_HDOP_CLEAR | FIELD_SPEED_CLEAR),
|
|
FIELD_ALL_ZERO = (FIELD_SATS_ZERO | FIELD_COURSE_ZERO | FIELD_ALT_ZERO | FIELD_HDOP_ZERO | FIELD_SPEED_ZERO)
|
|
} DirectionFieldsFlags_t;
|
|
|
|
typedef enum
|
|
{
|
|
FIXTYPE_NONE = (1 << 1),
|
|
FIXTYPE_1D = (1 << 2),
|
|
FIXTYPE_2D = (1 << 3),
|
|
FIXTYPE_3D = (1 << 4),
|
|
} DirectionFixtype_t;
|
|
|
|
static menuStatus_t menuGPSExitCode = MENU_STATUS_SUCCESS;
|
|
static uint8_t prevGPSState = 0xff;
|
|
static uint32_t updateTick = 0;
|
|
static uint16_t prevSatsInView = 0xFFFF;
|
|
static char directions[16][4];
|
|
|
|
menuStatus_t menuGPS(uiEvent_t *ev, bool isFirstRun)
|
|
{
|
|
if (isFirstRun)
|
|
{
|
|
menuDataGlobal.numItems = PAGES_MAX;
|
|
|
|
// Prepare directions from cardinals
|
|
char N = currentLanguageGetSymbol(SYMBOLS_NORTH);
|
|
char S = currentLanguageGetSymbol(SYMBOLS_SOUTH);
|
|
char E = currentLanguageGetSymbol(SYMBOLS_EAST);
|
|
char W = currentLanguageGetSymbol(SYMBOLS_WEST);
|
|
|
|
sprintf(directions[0], "%c", N);
|
|
sprintf(directions[1], "%c%c%c", N, N, E);
|
|
sprintf(directions[2], "%c%c", N, E);
|
|
sprintf(directions[3], "%c%c%c", E, N, E);
|
|
sprintf(directions[4], "%c", E);
|
|
sprintf(directions[5], "%c%c%c", E, S, E);
|
|
sprintf(directions[6], "%c%c", S, E);
|
|
sprintf(directions[7], "%c%c%c", S, S, E);
|
|
sprintf(directions[8], "%c", S);
|
|
sprintf(directions[9], "%c%c%c", S, S, W);
|
|
sprintf(directions[10], "%c%c", S, W);
|
|
sprintf(directions[11], "%c%c%c", W, S, W);
|
|
sprintf(directions[12], "%c", W);
|
|
sprintf(directions[13], "%c%c%c", W, N, W);
|
|
sprintf(directions[14], "%c%c", N, W);
|
|
sprintf(directions[15], "%c%c%c", N, N, W);
|
|
|
|
prevGPSState = 0xff;
|
|
|
|
voicePromptsInit();
|
|
voicePromptsAppendPrompt(PROMPT_SILENCE);
|
|
voicePromptsAppendLanguageString(currentLanguage->gps);
|
|
voicePromptsAppendLanguageString(currentLanguage->menu);
|
|
voicePromptsAppendPrompt(PROMPT_SILENCE);
|
|
|
|
updateScreen(true, false);
|
|
|
|
return (MENU_STATUS_LIST_TYPE | MENU_STATUS_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
menuGPSExitCode = MENU_STATUS_SUCCESS;
|
|
|
|
if (ev->hasEvent)
|
|
{
|
|
handleEvent(ev);
|
|
}
|
|
else
|
|
{
|
|
updateTick++;
|
|
// Limits updateScreen() calling frequency rate to every second, if a new GPS info is available, GPS_STATUS_TIME_UPDATED excepted.
|
|
// The functions called by updateScreen() are also filtering and limiting the screen redrawing, depending on the displayed page.
|
|
if ((updateTick > 1000) &&
|
|
(gpsData.Status & (GPS_STATUS_FIX_UPDATED | GPS_STATUS_FIXTYPE_UPDATED | GPS_STATUS_POSITION_UPDATED |
|
|
GPS_STATUS_HDOP_UPDATED | GPS_STATUS_COURSE_UPDATED | GPS_STATUS_SPEED_UPDATED | GPS_STATUS_HEIGHT_UPDATED |
|
|
GPS_STATUS_GPS_SATS_UPDATED | GPS_STATUS_BD_SATS_UPDATED)))
|
|
{
|
|
updateTick = 0;
|
|
updateScreen(false, false);
|
|
}
|
|
}
|
|
}
|
|
return menuGPSExitCode;
|
|
}
|
|
|
|
static int displayBars(gpsSatellitesData_t *satellitesArray, uint16_t satCount, bool numbersInBold, int dispPosition, float spacing, themeItem_t fgColour, themeItem_t bgColour)
|
|
{
|
|
#if ! defined(HAS_COLOURS)
|
|
#if ! defined(PLATFORM_RD5R)
|
|
uint8_t numberFont = (numbersInBold ? FONT_SIZE_1_BOLD : FONT_SIZE_1);
|
|
#endif
|
|
#else
|
|
uint8_t numberFont = FONT_SIZE_1;
|
|
#endif
|
|
|
|
for (uint16_t i = 0; i < satCount; i++)
|
|
{
|
|
if (satellitesArray[i].RSSI > 0)
|
|
{
|
|
int xPos = RSSI_X_OFFSET + 2 + dispPosition * spacing;
|
|
|
|
if (xPos > (DISPLAY_SIZE_X - spacing + 2))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Scale down (max @ 50dB), clipping higher
|
|
int8_t rssi = SAFE_MIN(MAX_RSSI_Y_PIXELS, ((int8_t)((MAX_RSSI_Y_PIXELS * 0.020) * satellitesArray[i].RSSI)));
|
|
#if ! defined(PLATFORM_RD5R)
|
|
char buf[3];
|
|
uint16_t sNumber = (satellitesArray[i].Number % 100); // limits to 2 last digits
|
|
|
|
displayThemeApply(THEME_ITEM_FG_GPS_NUMBER, THEME_ITEM_BG);
|
|
sprintf(buf, "%d", (sNumber % 10));
|
|
displayPrintAt(xPos + 1, RSSI_BARS_Y_POS, buf, numberFont);
|
|
|
|
sprintf(buf, "%d", (sNumber / 10));
|
|
displayPrintAt(xPos + 1, RSSI_BARS_Y_POS - 8, buf, numberFont);
|
|
#endif
|
|
|
|
displayThemeApply(fgColour, bgColour);
|
|
displayFillRect(xPos, RSSI_BARS_Y_POS - 12 - 2 - rssi, spacing - 2, rssi, false);
|
|
displayThemeResetToDefault();
|
|
|
|
dispPosition++;
|
|
|
|
if (dispPosition > (NUM_BARS - 1))
|
|
{
|
|
return dispPosition;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dispPosition;
|
|
}
|
|
|
|
static uint16_t getTotalNumberOfUsableSats(void)
|
|
{
|
|
uint16_t n = 0;
|
|
|
|
for (uint16_t i = 0; i < gpsData.SatsInViewGP; i++)
|
|
{
|
|
n += ((gpsData.GPSatellites[i].RSSI > 0) ? 1 : 0);
|
|
}
|
|
|
|
for (uint16_t i = 0; i < gpsData.SatsInViewBD; i++)
|
|
{
|
|
n += ((gpsData.BDSatellites[i].RSSI > 0) ? 1 : 0);
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static void displayDirectionFixType(DirectionFixtype_t type)
|
|
{
|
|
uint16_t fgColour, bgColour;
|
|
|
|
displayGetForegroundAndBackgroundColours(&fgColour, &bgColour);
|
|
displayThemeApply(THEME_ITEM_FG_DECORATION, THEME_ITEM_BG);
|
|
|
|
displayFillCircle(DIRECTION_HEADING_X_POS, DIRECTION_HEADING_Y_POS, (DIRECTION_HEADING_RADIUS >> 2) + 1, ((type & FIXTYPE_NONE) != 0));
|
|
|
|
if (type & (FIXTYPE_1D | FIXTYPE_2D | FIXTYPE_3D))
|
|
{
|
|
displayDrawCircle(DIRECTION_HEADING_X_POS, DIRECTION_HEADING_Y_POS, (DIRECTION_HEADING_RADIUS >> 2) + 1, true);
|
|
}
|
|
|
|
if (type & (FIXTYPE_2D | FIXTYPE_3D))
|
|
{
|
|
displayThemeResetToDefault();
|
|
displayPrintAt(DIRECTION_FIXTYPE_X_POS, DIRECTION_FIXTYPE_Y_POS, ((type & FIXTYPE_2D) ? "2" : "3"), FONT_SIZE_2);
|
|
}
|
|
|
|
displaySetForegroundAndBackgroundColours(fgColour, bgColour);
|
|
}
|
|
|
|
static void displayDirectionInfoBackground(DirectionFieldsFlags_t flags)
|
|
{
|
|
//
|
|
// Full background redrawing
|
|
//
|
|
if (flags & FIELD_BACKGROUND)
|
|
{
|
|
// Clear background
|
|
displayFillRect(0, 16, DISPLAY_SIZE_X, (DISPLAY_SIZE_Y - 16), true);
|
|
|
|
displayThemeApply(THEME_ITEM_FG_DECORATION, THEME_ITEM_BG);
|
|
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION)
|
|
{
|
|
// Sats in view
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
displayPrintAt(DIRECTION_SATS_X_POS - 3, (DIRECTION_SATS_Y_POS - 7), currentLanguage->satellite_short, FONT_SIZE_1);
|
|
displayDrawFastHLine((DIRECTION_SATS_X_POS - 7), (DIRECTION_SATS_Y_POS - 9), 5, true);
|
|
displayDrawFastVLine((DIRECTION_SATS_X_POS - 7), (DIRECTION_SATS_Y_POS - 8), FONT_SIZE_3_HEIGHT + VALUES_RD5R_V_GAP + 6, true);
|
|
displayDrawFastHLine((DIRECTION_SATS_X_POS - 7), ((DIRECTION_SATS_Y_POS - 8) + FONT_SIZE_3_HEIGHT + VALUES_RD5R_V_GAP + 6), ((2 * 8) + 7), true);
|
|
displayDrawFastVLine(((DIRECTION_SATS_X_POS - 7) + ((2 * 8) + 7)), ((DIRECTION_SATS_Y_POS - 4) + (FONT_SIZE_3_HEIGHT + VALUES_RD5R_V_GAP - 1)), 4, true);
|
|
#else
|
|
displayPrintAt(DIRECTION_SATS_X_POS, (DIRECTION_SATS_Y_POS - 3), currentLanguage->satellite_short, FONT_SIZE_2);
|
|
displayDrawFastHLine((DIRECTION_SATS_X_POS - 6), (DIRECTION_SATS_Y_POS - 5), 5, true);
|
|
displayDrawFastVLine((DIRECTION_SATS_X_POS - 6), (DIRECTION_SATS_Y_POS - 4), FONT_SIZE_4_HEIGHT, true);
|
|
displayDrawFastHLine((DIRECTION_SATS_X_POS - 6), ((DIRECTION_SATS_Y_POS - 4) + FONT_SIZE_4_HEIGHT), ((2 * 16) + 7), true);
|
|
displayDrawFastVLine(((DIRECTION_SATS_X_POS - 6) + ((2 * 16) + 7)), ((DIRECTION_SATS_Y_POS - 4) + (FONT_SIZE_4_HEIGHT - 4)), 5, true);
|
|
#endif
|
|
|
|
// Altitude
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
displayPrintAt(DIRECTION_ALT_X_POS - 3, (DIRECTION_ALT_Y_POS - 7), currentLanguage->altitude, FONT_SIZE_1);
|
|
displayPrintAt((DIRECTION_ALT_X_POS + (4 * 8) + 2), (DIRECTION_ALT_Y_POS + 6), "m", FONT_SIZE_1);
|
|
displayDrawFastHLine((DIRECTION_ALT_X_POS - 7), (DIRECTION_ALT_Y_POS - 9), 5, true);
|
|
displayDrawFastVLine((DIRECTION_ALT_X_POS - 7), (DIRECTION_ALT_Y_POS - 8), FONT_SIZE_3_HEIGHT + VALUES_RD5R_V_GAP + 6, true);
|
|
displayDrawFastHLine((DIRECTION_ALT_X_POS - 7), ((DIRECTION_ALT_Y_POS - 8) + FONT_SIZE_3_HEIGHT + VALUES_RD5R_V_GAP + 6), ((4 * 8) + 7 + 8), true);
|
|
displayDrawFastVLine(((DIRECTION_ALT_X_POS - 7) + ((4 * 8) + 7) + 8), ((DIRECTION_ALT_Y_POS - 4) + (FONT_SIZE_3_HEIGHT + VALUES_RD5R_V_GAP - 1)), 4, true);
|
|
#else
|
|
displayPrintAt(DIRECTION_ALT_X_POS, (DIRECTION_ALT_Y_POS - 3), currentLanguage->altitude, FONT_SIZE_2);
|
|
displayPrintAt((DIRECTION_ALT_X_POS + (4 * 16) + 2), (DIRECTION_ALT_Y_POS + 18), "m", FONT_SIZE_2);
|
|
displayDrawFastHLine((DIRECTION_ALT_X_POS - 6), (DIRECTION_ALT_Y_POS - 5), 5, true);
|
|
displayDrawFastVLine((DIRECTION_ALT_X_POS - 6), (DIRECTION_ALT_Y_POS - 4), FONT_SIZE_4_HEIGHT, true);
|
|
displayDrawFastHLine((DIRECTION_ALT_X_POS - 6), ((DIRECTION_ALT_Y_POS - 4) + FONT_SIZE_4_HEIGHT), ((4 * 16) + 7 + 10), true);
|
|
displayDrawFastVLine(((DIRECTION_ALT_X_POS - 6) + ((4 * 16) + 7) + 10), ((DIRECTION_ALT_Y_POS - 4) + (FONT_SIZE_4_HEIGHT - 4)), 5, true);
|
|
#endif
|
|
|
|
// HDOP
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
displayPrintAt(DIRECTION_HDOP_X_POS - 3, (DIRECTION_HDOP_Y_POS - 7), "HDOP", FONT_SIZE_1);
|
|
displayPrintAt((DIRECTION_HDOP_X_POS + (2 * 8) + 2), (DIRECTION_HDOP_Y_POS + 6), "m", FONT_SIZE_1);
|
|
displayDrawFastHLine((DIRECTION_HDOP_X_POS - 7), (DIRECTION_HDOP_Y_POS - 9), 5, true);
|
|
displayDrawFastVLine((DIRECTION_HDOP_X_POS - 7), (DIRECTION_HDOP_Y_POS - 8), FONT_SIZE_3_HEIGHT + VALUES_RD5R_V_GAP + 6, true);
|
|
displayDrawFastHLine((DIRECTION_HDOP_X_POS - 7), ((DIRECTION_HDOP_Y_POS - 8) + FONT_SIZE_3_HEIGHT + VALUES_RD5R_V_GAP + 6), ((2 * 8) + 7 + 8), true);
|
|
displayDrawFastVLine(((DIRECTION_HDOP_X_POS - 7) + ((2 * 8) + 7) + 8), ((DIRECTION_HDOP_Y_POS - 4) + (FONT_SIZE_3_HEIGHT + VALUES_RD5R_V_GAP - 1)), 4, true);
|
|
#else
|
|
displayPrintAt(DIRECTION_HDOP_X_POS, (DIRECTION_HDOP_Y_POS - 3), "HDOP", FONT_SIZE_2);
|
|
displayPrintAt((DIRECTION_HDOP_X_POS + (2 * 16) + 2), (DIRECTION_HDOP_Y_POS + 18), "m", FONT_SIZE_2);
|
|
displayDrawFastHLine((DIRECTION_HDOP_X_POS - 6), (DIRECTION_HDOP_Y_POS - 5), 5, true);
|
|
displayDrawFastVLine((DIRECTION_HDOP_X_POS - 6), (DIRECTION_HDOP_Y_POS - 4), FONT_SIZE_4_HEIGHT, true);
|
|
displayDrawFastHLine((DIRECTION_HDOP_X_POS - 6), ((DIRECTION_HDOP_Y_POS - 4) + FONT_SIZE_4_HEIGHT), ((2 * 16) + 7 + 10), true);
|
|
displayDrawFastVLine(((DIRECTION_HDOP_X_POS - 6) + ((2 * 16) + 7) + 10), ((DIRECTION_HDOP_Y_POS - 4) + (FONT_SIZE_4_HEIGHT - 4)), 5, true);
|
|
#endif
|
|
|
|
}
|
|
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION_2)
|
|
{
|
|
// Course
|
|
char deg[2] = { 176, 0 };
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
displayPrintAt((DIRECTION_COURSE_X_POS + (3 * 8)), (DIRECTION_COURSE_Y_POS + 1), deg, FONT_SIZE_1);
|
|
displayFillRect(((DIRECTION_COURSE_X_POS + 12) - 12 - 5), (DIRECTION_COURSE_Y_POS - 6), 4, 2, false);
|
|
displayFillRect(((DIRECTION_COURSE_X_POS + 12) + 12 + 1), (DIRECTION_COURSE_Y_POS - 6), 4, 2, false);
|
|
displayDrawFastVLine((DIRECTION_COURSE_X_POS - 7), (((DIRECTION_COURSE_Y_POS - 3) + FONT_SIZE_3_HEIGHT + (VALUES_RD5R_V_GAP >> 1) + 2) - 4), 4, true);
|
|
displayDrawFastHLine((DIRECTION_COURSE_X_POS - 6), ((DIRECTION_COURSE_Y_POS - 3) + FONT_SIZE_3_HEIGHT + (VALUES_RD5R_V_GAP >> 1) + 1), ((3 * 8) + 7 + 7), true);
|
|
displayDrawFastVLine(((DIRECTION_COURSE_X_POS - 1) + ((3 * 8) + 7 + 2)), (DIRECTION_COURSE_Y_POS - 8), (FONT_SIZE_3_HEIGHT + (VALUES_RD5R_V_GAP >> 1) + 7), true);
|
|
displayDrawFastHLine(((DIRECTION_COURSE_X_POS - 1) + ((3 * 8) + 7 + 2) - 4), (DIRECTION_COURSE_Y_POS - 9), 5, true);
|
|
#else
|
|
displayPrintAt((DIRECTION_COURSE_X_POS + (3 * 16) + 1), (DIRECTION_COURSE_Y_POS + 5), deg, FONT_SIZE_2);
|
|
displayFillRect(((DIRECTION_COURSE_X_POS + 24) - 12 - 8), (DIRECTION_COURSE_Y_POS - 4), 7, 2, false);
|
|
displayFillRect(((DIRECTION_COURSE_X_POS + 24) + 12 + 1), (DIRECTION_COURSE_Y_POS - 4), 7, 2, false);
|
|
displayDrawFastVLine((DIRECTION_COURSE_X_POS - 2), (((DIRECTION_COURSE_Y_POS - 5) + FONT_SIZE_4_HEIGHT) - 4), 5, true);
|
|
displayDrawFastHLine((DIRECTION_COURSE_X_POS - 1), ((DIRECTION_COURSE_Y_POS - 5) + FONT_SIZE_4_HEIGHT), ((3 * 16) + 7 + 2), true);
|
|
displayDrawFastVLine(((DIRECTION_COURSE_X_POS - 1) + ((3 * 16) + 7 + 2)), (DIRECTION_COURSE_Y_POS - 5), (FONT_SIZE_4_HEIGHT + 1), true);
|
|
displayDrawFastHLine(((DIRECTION_COURSE_X_POS - 1) + ((3 * 16) + 7 + 2) - 4), (DIRECTION_COURSE_Y_POS - 6), 5, true);
|
|
#endif
|
|
// Heading
|
|
{
|
|
|
|
for (int16_t i = 0; i < 360; i += 15)
|
|
{
|
|
int16_t x1 = (int16_t)(DIRECTION_HEADING_X_POS + (DIRECTION_HEADING_RADIUS) * cos((double)(i * DEG_TO_RAD)));
|
|
int16_t y1 = (int16_t)(DIRECTION_HEADING_Y_POS + (DIRECTION_HEADING_RADIUS) * sin((double)(i * DEG_TO_RAD)));
|
|
|
|
int16_t x2 = (int16_t)(DIRECTION_HEADING_X_POS + (DIRECTION_HEADING_RADIUS - ((i % 45) ? 2 : 4)) * cos((double)(i * DEG_TO_RAD)));
|
|
int16_t y2 = (int16_t)(DIRECTION_HEADING_Y_POS + (DIRECTION_HEADING_RADIUS - ((i % 45) ? 2 : 4)) * sin((double)(i * DEG_TO_RAD)));
|
|
|
|
if (i == 270)
|
|
{
|
|
displayThemeApply(THEME_ITEM_FG_GPS_COLOUR, THEME_ITEM_BG);
|
|
displayDrawLine((x1 - 1), y1, (x2 - 1), y2, true);
|
|
}
|
|
|
|
displayDrawLine(x1, y1, x2, y2, true);
|
|
|
|
if (i == 270)
|
|
{
|
|
displayDrawLine((x1 + 1), y1, (x2 + 1), y2, true);
|
|
displayThemeApply(THEME_ITEM_FG_DECORATION, THEME_ITEM_BG);
|
|
}
|
|
}
|
|
|
|
displayDrawCircle(DIRECTION_HEADING_X_POS, DIRECTION_HEADING_Y_POS, DIRECTION_HEADING_RADIUS, true);
|
|
displayDirectionFixType(FIXTYPE_NONE);
|
|
}
|
|
|
|
|
|
// Speed
|
|
displayPrintAt((DIRECTION_SPEED_X_POS + (3 * VALUES_FONT_WIDTH) + 2), (DIRECTION_SPEED_Y_POS + UNITS_Y_OFFSET), "km/h", UNITS_FONT_SIZE);
|
|
}
|
|
|
|
displayThemeResetToDefault();
|
|
}
|
|
|
|
//
|
|
// Region clearing
|
|
//
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION)
|
|
{
|
|
if (flags & (FIELD_SATS_CLEAR | FIELD_SATS_ZERO))
|
|
{
|
|
displayFillRect(DIRECTION_SATS_X_POS, (DIRECTION_SATS_Y_POS + VALUES_RD5R_V_OFFSET + DIRECTION_REGION_V_OFFSET), (2 * VALUES_FONT_WIDTH), (VALUES_FONT_HEIGHT - DIRECTION_REGION_H_OFFSET), true);
|
|
}
|
|
|
|
if (flags & (FIELD_ALT_CLEAR | FIELD_ALT_ZERO))
|
|
{
|
|
displayFillRect(DIRECTION_ALT_X_POS, (DIRECTION_ALT_Y_POS + VALUES_RD5R_V_OFFSET + DIRECTION_REGION_V_OFFSET), (4 * VALUES_FONT_WIDTH), (VALUES_FONT_HEIGHT - DIRECTION_REGION_H_OFFSET), true);
|
|
}
|
|
|
|
if (flags & (FIELD_HDOP_CLEAR | FIELD_HDOP_ZERO))
|
|
{
|
|
displayFillRect(DIRECTION_HDOP_X_POS, (DIRECTION_HDOP_Y_POS + VALUES_RD5R_V_OFFSET + DIRECTION_REGION_V_OFFSET), (2 * VALUES_FONT_WIDTH), (VALUES_FONT_HEIGHT - DIRECTION_REGION_H_OFFSET), true);
|
|
}
|
|
}
|
|
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION_2)
|
|
{
|
|
if (flags & (FIELD_COURSE_CLEAR | FIELD_COURSE_ZERO))
|
|
{
|
|
displayFillRect(((DIRECTION_COURSE_X_POS + ((VALUES_FONT_WIDTH * 3) >> 1)) - 12), (DIRECTION_COURSE_Y_POS - DIRECTION_CARDINAL_OFFSET), (3 * 8), CARDINALS_REGION_HEIGHT, true);
|
|
displayFillRect(DIRECTION_COURSE_X_POS, (DIRECTION_COURSE_Y_POS + DIRECTION_REGION_V_OFFSET), (3 * VALUES_FONT_WIDTH), (VALUES_FONT_HEIGHT - DIRECTION_REGION_H_OFFSET), true);
|
|
displayFillCircle(DIRECTION_HEADING_X_POS, DIRECTION_HEADING_Y_POS, (DIRECTION_HEADING_RADIUS - 6), false);
|
|
displayDirectionFixType(FIXTYPE_NONE);
|
|
}
|
|
|
|
if (flags & (FIELD_SPEED_CLEAR | FIELD_SPEED_ZERO))
|
|
{
|
|
displayFillRect(DIRECTION_SPEED_X_POS, (DIRECTION_SPEED_Y_POS + DIRECTION_REGION_V_OFFSET), (3 * VALUES_FONT_WIDTH), (VALUES_FONT_HEIGHT - DIRECTION_REGION_H_OFFSET), true);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Zeroing values
|
|
//
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION)
|
|
{
|
|
if (flags & FIELD_SATS_ZERO)
|
|
{
|
|
displayPrintAt(DIRECTION_SATS_X_POS, DIRECTION_SATS_Y_POS + VALUES_RD5R_V_OFFSET, "--", VALUES_FONT_SIZE);
|
|
}
|
|
|
|
if (flags & FIELD_ALT_ZERO)
|
|
{
|
|
displayPrintAt(DIRECTION_ALT_X_POS, DIRECTION_ALT_Y_POS + VALUES_RD5R_V_OFFSET, "----", VALUES_FONT_SIZE);
|
|
}
|
|
|
|
if (flags & FIELD_HDOP_ZERO)
|
|
{
|
|
displayPrintAt(DIRECTION_HDOP_X_POS, DIRECTION_HDOP_Y_POS + VALUES_RD5R_V_OFFSET, "--", VALUES_FONT_SIZE);
|
|
}
|
|
}
|
|
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION_2)
|
|
{
|
|
if (flags & FIELD_COURSE_ZERO)
|
|
{
|
|
displayPrintAt(((DIRECTION_COURSE_X_POS + ((VALUES_FONT_WIDTH * 3) >> 1)) - 12), (DIRECTION_COURSE_Y_POS - DIRECTION_CARDINAL_OFFSET), "---", VALUES_FONT_SIZE_SMALL);
|
|
displayPrintAt(DIRECTION_COURSE_X_POS, DIRECTION_COURSE_Y_POS, "---", VALUES_FONT_SIZE);
|
|
}
|
|
|
|
if (flags & FIELD_SPEED_ZERO)
|
|
{
|
|
displayPrintAt(DIRECTION_SPEED_X_POS, DIRECTION_SPEED_Y_POS, "---", VALUES_FONT_SIZE);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void displayDirectionCourseZeroing(void)
|
|
{
|
|
DirectionFixtype_t ft = FIXTYPE_1D;
|
|
|
|
if (gpsData.Status & (GPS_STATUS_2D_FIX | GPS_STATUS_3D_FIX))
|
|
{
|
|
ft &= ~FIXTYPE_1D;
|
|
ft |= ((gpsData.Status & GPS_STATUS_2D_FIX) ? FIXTYPE_2D : FIXTYPE_3D);
|
|
}
|
|
|
|
displayDirectionInfoBackground(FIELD_COURSE_ZERO);
|
|
displayDirectionFixType(ft);
|
|
}
|
|
|
|
static bool displayDirectionInfo(bool isFirstRun, bool forceRedraw)
|
|
{
|
|
char buffer[SCREEN_LINE_BUFFER_SIZE];
|
|
|
|
if (gpsData.Status & GPS_STATUS_HAS_FIX)
|
|
{
|
|
uint16_t inViewAndUsableSats = getTotalNumberOfUsableSats();
|
|
|
|
if (isFirstRun || forceRedraw || (prevSatsInView != inViewAndUsableSats) ||
|
|
(gpsData.Status & (GPS_STATUS_FIX_UPDATED | GPS_STATUS_COURSE_UPDATED |
|
|
GPS_STATUS_SPEED_UPDATED | GPS_STATUS_HDOP_UPDATED | GPS_STATUS_FIXTYPE_UPDATED | GPS_STATUS_HEIGHT_UPDATED)))
|
|
{
|
|
// Draw the background
|
|
if (isFirstRun || forceRedraw)
|
|
{
|
|
displayDirectionInfoBackground(FIELD_BACKGROUND);
|
|
}
|
|
|
|
// Update, only clear screen regions
|
|
if (((isFirstRun || forceRedraw) == false) &&
|
|
((gpsData.Status & (GPS_STATUS_FIX_UPDATED | GPS_STATUS_COURSE_UPDATED |
|
|
GPS_STATUS_SPEED_UPDATED | GPS_STATUS_HDOP_UPDATED | GPS_STATUS_FIXTYPE_UPDATED | GPS_STATUS_HEIGHT_UPDATED))))
|
|
{
|
|
DirectionFieldsFlags_t f = 0;
|
|
|
|
if (gpsData.Status & GPS_STATUS_COURSE_UPDATED)
|
|
{
|
|
f |= FIELD_COURSE_CLEAR;
|
|
}
|
|
|
|
if (gpsData.Status & GPS_STATUS_SPEED_UPDATED)
|
|
{
|
|
f |= FIELD_SPEED_CLEAR;
|
|
}
|
|
|
|
if (gpsData.Status & GPS_STATUS_HDOP_UPDATED)
|
|
{
|
|
f |= FIELD_HDOP_CLEAR;
|
|
}
|
|
|
|
if (gpsData.Status & GPS_STATUS_HEIGHT_UPDATED)
|
|
{
|
|
f |= FIELD_ALT_CLEAR;
|
|
}
|
|
|
|
displayDirectionInfoBackground(f);
|
|
}
|
|
|
|
if (isFirstRun || forceRedraw || (prevSatsInView != inViewAndUsableSats))
|
|
{
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION)
|
|
{
|
|
displayDirectionInfoBackground(FIELD_SATS_CLEAR);
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%2u", inViewAndUsableSats);
|
|
displayPrintAt(DIRECTION_SATS_X_POS, DIRECTION_SATS_Y_POS + VALUES_RD5R_V_OFFSET, buffer, VALUES_FONT_SIZE);
|
|
}
|
|
}
|
|
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION_2)
|
|
{
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & (GPS_STATUS_FIX_UPDATED | GPS_STATUS_FIXTYPE_UPDATED | GPS_STATUS_COURSE_UPDATED)))
|
|
{
|
|
DirectionFixtype_t ft = FIXTYPE_1D;
|
|
|
|
if (gpsData.Status & (GPS_STATUS_2D_FIX | GPS_STATUS_3D_FIX))
|
|
{
|
|
ft &= ~FIXTYPE_1D;
|
|
ft |= ((gpsData.Status & GPS_STATUS_2D_FIX) ? FIXTYPE_2D : FIXTYPE_3D);
|
|
}
|
|
|
|
displayDirectionFixType(ft);
|
|
}
|
|
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & GPS_STATUS_COURSE_UPDATED))
|
|
{
|
|
int dir = (int)(((gpsData.CourseInHundredthDeg * 1E-2) + 11.25f) / 22.5f);
|
|
|
|
if (gpsData.SpeedInHundredthKn > GPS_SPEED_THRESHOLD_MIN)
|
|
{
|
|
int16_t x1, x2, x3, y1, y2, y3;
|
|
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%s", directions[dir % 16]);
|
|
displayPrintAt(((DIRECTION_COURSE_X_POS + ((VALUES_FONT_WIDTH * 3) >> 1)) - ((strlen(buffer) * 8) >> 1)), (DIRECTION_COURSE_Y_POS - DIRECTION_CARDINAL_OFFSET), buffer, VALUES_FONT_SIZE_SMALL);
|
|
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%03u", (uint16_t)(gpsData.CourseInHundredthDeg * 1E-2));
|
|
displayPrintAt(DIRECTION_COURSE_X_POS, DIRECTION_COURSE_Y_POS, buffer, VALUES_FONT_SIZE);
|
|
|
|
displayThemeApply(THEME_ITEM_FG_GPS_COLOUR, THEME_ITEM_BG);
|
|
|
|
// Needle
|
|
float needle = ((gpsData.CourseInHundredthDeg * 1E-2) - 90.0);
|
|
|
|
if (needle > 360.0)
|
|
{
|
|
needle -= 360.0;
|
|
}
|
|
|
|
needle *= DEG_TO_RAD;
|
|
|
|
x1 = (int16_t)(DIRECTION_HEADING_X_POS + 1 + TOP_ARROW_OFFSET * cos(needle));
|
|
y1 = (int16_t)(DIRECTION_HEADING_Y_POS + 1 + TOP_ARROW_OFFSET * sin(needle));
|
|
|
|
x2 = (int16_t)(DIRECTION_HEADING_X_POS + 1 + BASE_ARROW_OFFSET * cos(needle + (30 * DEG_TO_RAD)));
|
|
y2 = (int16_t)(DIRECTION_HEADING_Y_POS + 1 + BASE_ARROW_OFFSET * sin(needle + (30 * DEG_TO_RAD)));
|
|
|
|
x3 = (int16_t)(DIRECTION_HEADING_X_POS + 1 + BASE_ARROW_OFFSET * cos(needle - (30 * DEG_TO_RAD)));
|
|
y3 = (int16_t)(DIRECTION_HEADING_Y_POS + 1 + BASE_ARROW_OFFSET * sin(needle - (30 * DEG_TO_RAD)));
|
|
|
|
displayFillTriangle(x1, y1, x2, y2, x3, y3, true);
|
|
displayThemeResetToDefault();
|
|
}
|
|
else
|
|
{
|
|
displayDirectionCourseZeroing();
|
|
}
|
|
}
|
|
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & GPS_STATUS_SPEED_UPDATED))
|
|
{
|
|
uint16_t speed = (uint16_t)((gpsData.SpeedInHundredthKn * 1E-2) * KMPH_PER_KNOT);
|
|
|
|
// Speed < 1km/h and Course is not not updated => display zero course
|
|
if ((speed == 0) && ((isFirstRun || forceRedraw) == false) && ((gpsData.Status & GPS_STATUS_COURSE_UPDATED) == 0))
|
|
{
|
|
displayDirectionCourseZeroing();
|
|
}
|
|
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%03u", speed);
|
|
displayPrintAt(DIRECTION_SPEED_X_POS, DIRECTION_SPEED_Y_POS, buffer, VALUES_FONT_SIZE);
|
|
}
|
|
}
|
|
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION)
|
|
{
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & GPS_STATUS_HDOP_UPDATED))
|
|
{
|
|
if (gpsData.AccuracyInCm < 100)
|
|
{
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%s", "<1");
|
|
}
|
|
else
|
|
{
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%2u", SAFE_MIN((gpsData.AccuracyInCm / 100), 99));
|
|
}
|
|
|
|
displayPrintAt(DIRECTION_HDOP_X_POS, DIRECTION_HDOP_Y_POS + VALUES_RD5R_V_OFFSET, buffer, VALUES_FONT_SIZE);
|
|
}
|
|
}
|
|
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & GPS_STATUS_HEIGHT_UPDATED))
|
|
{
|
|
CURRENT_PAGE_ON_MONOCHOME(PAGE_DIRECTION)
|
|
{
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%4d", gpsData.HeightInM);
|
|
displayPrintAt(DIRECTION_ALT_X_POS, DIRECTION_ALT_Y_POS + VALUES_RD5R_V_OFFSET, buffer, VALUES_FONT_SIZE);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// |--> fix got lost
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & GPS_STATUS_FIX_UPDATED))
|
|
{
|
|
displayDirectionInfoBackground((FIELD_BACKGROUND | FIELD_ALL_ZERO));
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool displayRSSI(bool isFirstRun, bool forceRedraw)
|
|
{
|
|
float spacing = 9.0;
|
|
int dispPosition = 0;
|
|
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & (GPS_STATUS_GPS_SATS_UPDATED | GPS_STATUS_BD_SATS_UPDATED)))
|
|
{
|
|
// Update, only clear screen regions
|
|
if (((isFirstRun || forceRedraw) == false) && (gpsData.Status & (GPS_STATUS_GPS_SATS_UPDATED | GPS_STATUS_BD_SATS_UPDATED)))
|
|
{
|
|
// Bars.
|
|
displayFillRect(0, (RSSI_BARS_Y_POS - 12 - 2 - MAX_RSSI_Y_PIXELS), DISPLAY_SIZE_X, MAX_RSSI_Y_PIXELS, true);
|
|
#if ! defined(PLATFORM_RD5R)
|
|
// Numbers
|
|
displayFillRect(0, (RSSI_BARS_Y_POS - 8), DISPLAY_SIZE_X, (8 * 2), true);
|
|
#endif
|
|
}
|
|
|
|
if (isFirstRun || forceRedraw)
|
|
{
|
|
for(int i = 0; i < NUM_BARS; i++)
|
|
{
|
|
int xPos = 2 + (i * spacing);
|
|
|
|
displayFillRect(RSSI_X_OFFSET + xPos, RSSI_BARS_Y_POS - 12 - 2, spacing - 2, 2, false);
|
|
}
|
|
}
|
|
|
|
if ((gpsData.SatsInViewGP + gpsData.SatsInViewBD) > 0)
|
|
{
|
|
dispPosition = displayBars(gpsData.GPSatellites, gpsData.SatsInViewGP, false, dispPosition, spacing, THEME_ITEM_FG_GPS_COLOUR, THEME_ITEM_BG);
|
|
displayBars(gpsData.BDSatellites, gpsData.SatsInViewBD, true, dispPosition, spacing, THEME_ITEM_FG_BD_COLOUR, THEME_ITEM_BG);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void displaySatellitesPolar(gpsSatellitesData_t *satellitesArray, bool circle)
|
|
{
|
|
float az, elFactor, s, c;
|
|
int x, y;
|
|
|
|
for (int i = 0; ((i < GPS_STORAGE_MAX) && (satellitesArray[i].Number != 0)); i++)
|
|
{
|
|
if (satellitesArray[i].RSSI > 0)
|
|
{
|
|
az = (M_PI * satellitesArray[i].Az) / 180.0;
|
|
|
|
if (satellitesArray[i].El <= 0)
|
|
{
|
|
elFactor = 0;// put in the middle of the screen if there is no real elevation data
|
|
}
|
|
else
|
|
{
|
|
elFactor = (1 - (fabs(satellitesArray[i].El) / 90)) * MAX_RADIUS;
|
|
}
|
|
|
|
s = sin(az);
|
|
c = cos(az);
|
|
x = POLAR_GRAPHICS_X_OFFSET + (DISPLAY_SIZE_X / 2) + (s * elFactor);
|
|
y = POLAR_GRAPHICS_Y_OFFSET - (c * elFactor);
|
|
#if ! defined(HAS_COLOURS)
|
|
if (circle)
|
|
{
|
|
displayFillCircle(x, y, (DOT_RADIUS + 1), false);
|
|
displayDrawCircle(x, y, (DOT_RADIUS + 1), true);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
displayFillCircle(x, y, (DOT_RADIUS + 1), true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool displayPolar(bool isFirstRun, bool forceRedraw)
|
|
{
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & (GPS_STATUS_GPS_SATS_UPDATED | GPS_STATUS_BD_SATS_UPDATED)))
|
|
{
|
|
displayThemeApply(THEME_ITEM_FG_POLAR_DRAWING, THEME_ITEM_BG);
|
|
|
|
// Update, only clear screen region
|
|
if (((isFirstRun || forceRedraw) == false) && (gpsData.Status & (GPS_STATUS_GPS_SATS_UPDATED | GPS_STATUS_BD_SATS_UPDATED)))
|
|
{
|
|
displayFillCircle(POLAR_GRAPHICS_X_OFFSET + (DISPLAY_SIZE_X / 2), POLAR_GRAPHICS_Y_OFFSET, MAX_RADIUS, false);
|
|
}
|
|
|
|
displayDrawCircle(POLAR_GRAPHICS_X_OFFSET + (DISPLAY_SIZE_X / 2), POLAR_GRAPHICS_Y_OFFSET, MAX_RADIUS, true);
|
|
displayDrawCircle(POLAR_GRAPHICS_X_OFFSET + (DISPLAY_SIZE_X / 2), POLAR_GRAPHICS_Y_OFFSET, (MAX_RADIUS / 3 ) * 2, true);
|
|
displayDrawCircle(POLAR_GRAPHICS_X_OFFSET + (DISPLAY_SIZE_X / 2), POLAR_GRAPHICS_Y_OFFSET, (MAX_RADIUS / 3 ), true);
|
|
|
|
#if defined(PLATFORM_RD5R)
|
|
displayDrawFastVLine(POLAR_GRAPHICS_X_OFFSET + (DISPLAY_SIZE_X / 2),
|
|
(POLAR_GRAPHICS_Y_OFFSET) - MAX_RADIUS, MAX_RADIUS * 2, true);
|
|
displayDrawFastHLine((POLAR_GRAPHICS_X_OFFSET + (DISPLAY_SIZE_X / 2)) - MAX_RADIUS,
|
|
(POLAR_GRAPHICS_Y_OFFSET), MAX_RADIUS * 2, true);
|
|
#else
|
|
displayDrawFastVLine(POLAR_GRAPHICS_X_OFFSET + (DISPLAY_SIZE_X / 2),
|
|
(POLAR_GRAPHICS_Y_OFFSET) - (MAX_RADIUS + 4), (MAX_RADIUS + 4) * 2, true);
|
|
displayDrawFastHLine((POLAR_GRAPHICS_X_OFFSET + (DISPLAY_SIZE_X / 2)) - (MAX_RADIUS + 4),
|
|
(POLAR_GRAPHICS_Y_OFFSET), (MAX_RADIUS + 4) * 2, true);
|
|
#endif
|
|
|
|
if ((gpsData.SatsInViewGP + gpsData.SatsInViewBD) > 0)
|
|
{
|
|
displayThemeApply(THEME_ITEM_FG_GPS_COLOUR, THEME_ITEM_BG);
|
|
displaySatellitesPolar(gpsData.GPSatellites, false);
|
|
displayThemeApply(THEME_ITEM_FG_BD_COLOUR, THEME_ITEM_BG);
|
|
displaySatellitesPolar(gpsData.BDSatellites, true);
|
|
}
|
|
|
|
displayThemeResetToDefault();
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool displayCoords(bool isFirstRun, bool forceRedraw)
|
|
{
|
|
char buffer[LOCATION_TEXT_BUFFER_SIZE]; // larger screen is available on MD-UV380 and friends
|
|
|
|
if (gpsData.Status & GPS_STATUS_HAS_FIX)
|
|
{
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & (GPS_STATUS_FIX_UPDATED | GPS_STATUS_POSITION_UPDATED | GPS_STATUS_HDOP_UPDATED | GPS_STATUS_HEIGHT_UPDATED)))
|
|
{
|
|
const uint16_t coords_Y_positions[] = {
|
|
#if defined(PLATFORM_RD5R)
|
|
16U, 26U
|
|
#else
|
|
16U, 32U
|
|
#endif
|
|
};
|
|
char maidenheadBuf[7];
|
|
char *p;
|
|
|
|
// Update, only clear screen regions
|
|
if (((isFirstRun || forceRedraw) == false) && (gpsData.Status & (GPS_STATUS_FIX_UPDATED | GPS_STATUS_POSITION_UPDATED | GPS_STATUS_HDOP_UPDATED | GPS_STATUS_HEIGHT_UPDATED)))
|
|
{
|
|
displayFillRect(0, (int16_t)coords_Y_positions[0], DISPLAY_SIZE_X, FONT_SIZE_3_HEIGHT, true);
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
displayFillRect(0, (int16_t)coords_Y_positions[1], DISPLAY_SIZE_X, FONT_SIZE_3_HEIGHT, true);
|
|
#endif
|
|
displayFillRect(0, MAIDENHEAD_HDOP_Y_POS, DISPLAY_SIZE_X, FONT_SIZE_3_HEIGHT, true);
|
|
}
|
|
|
|
buildLocationAndMaidenheadStrings(buffer, maidenheadBuf, true);
|
|
|
|
p = strchr(buffer, ' ');
|
|
|
|
*p = 0; // split locations Lat/Lon parts
|
|
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
// Lat: Centered
|
|
displayPrintAt(((DISPLAY_SIZE_X - (8 * 8)) >> 1), coords_Y_positions[0], buffer, FONT_SIZE_3);
|
|
|
|
// Lon: Centered
|
|
displayPrintAt(((DISPLAY_SIZE_X - (9 * 8)) >> 1), coords_Y_positions[1], (p + 1), FONT_SIZE_3);
|
|
#else
|
|
// Lat: Left
|
|
displayPrintAt(5, 16, buffer, FONT_SIZE_3);
|
|
|
|
// Lon: Right
|
|
displayPrintAt((DISPLAY_SIZE_X - ((9 * 8) + 5)), coords_Y_positions[0], (p + 1), FONT_SIZE_3);
|
|
#endif
|
|
|
|
displayPrintAt(MAIDENHEAD_HDOP_MARGIN, MAIDENHEAD_HDOP_Y_POS, maidenheadBuf, FONT_SIZE_3);
|
|
|
|
if (gpsData.AccuracyInCm < 100)
|
|
{
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%s", "+/-<1m");
|
|
}
|
|
else
|
|
{
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "+/-%dm", (gpsData.AccuracyInCm / 100));
|
|
}
|
|
|
|
displayPrintAt((DISPLAY_SIZE_X - ((strlen(buffer) * 8) + MAIDENHEAD_HDOP_MARGIN)), MAIDENHEAD_HDOP_Y_POS, buffer, FONT_SIZE_3);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool displayGPSData(bool isFirstRun, bool forceRedraw)
|
|
{
|
|
char buffer[SCREEN_LINE_BUFFER_SIZE];
|
|
bool res = false;
|
|
|
|
if (SETTINGS_GPS_MODE_GET(nonVolatileSettings) > GPS_MODE_OFF)
|
|
{
|
|
switch(menuDataGlobal.currentItemIndex)
|
|
{
|
|
case PAGE_COORDS: // with PAGE_RSSI on MD-UV380
|
|
res = displayCoords(isFirstRun, forceRedraw);
|
|
#if !(defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12))
|
|
res |= displayRSSI(isFirstRun, forceRedraw);
|
|
#endif
|
|
break;
|
|
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
case PAGE_RSSI:
|
|
res = displayRSSI(isFirstRun, forceRedraw);
|
|
break;
|
|
#endif
|
|
|
|
case PAGE_POLAR:
|
|
res = displayPolar(isFirstRun, forceRedraw);
|
|
break;
|
|
|
|
case PAGE_DIRECTION:
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
case PAGE_DIRECTION_2:
|
|
#endif
|
|
res = displayDirectionInfo(isFirstRun, forceRedraw);
|
|
break;
|
|
|
|
case PAGES_MAX:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update the Voice Prompts
|
|
//
|
|
if (gpsData.Status & GPS_STATUS_HAS_FIX)
|
|
{
|
|
bool vpIsPlaying = voicePromptsIsPlaying();
|
|
uint16_t inViewAndUsableSats = getTotalNumberOfUsableSats();
|
|
|
|
if (((isFirstRun || vpIsPlaying) == false) &&
|
|
((prevSatsInView != inViewAndUsableSats) || (gpsData.Status & (GPS_STATUS_FIX_UPDATED | GPS_STATUS_POSITION_UPDATED | GPS_STATUS_HEIGHT_UPDATED))))
|
|
{
|
|
prevSatsInView = inViewAndUsableSats;
|
|
|
|
if (gpsData.Status & GPS_STATUS_FIX_UPDATED)
|
|
{
|
|
if (nonVolatileSettings.audioPromptMode >= AUDIO_PROMPT_MODE_VOICE_THRESHOLD)
|
|
{
|
|
voicePromptsInitWithOverride();
|
|
}
|
|
else
|
|
{
|
|
soundSetMelody(MELODY_ACK_BEEP);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
voicePromptsInit();
|
|
}
|
|
|
|
if (!vpIsPlaying)
|
|
{
|
|
if (gpsData.Status & GPS_STATUS_HAS_POSITION)
|
|
{
|
|
char locationBuffer[LOCATION_TEXT_BUFFER_SIZE];
|
|
char maidenheadBuf[7];
|
|
|
|
buildLocationAndMaidenheadStrings(locationBuffer, maidenheadBuf, true);
|
|
|
|
voicePromptsAppendLanguageString(currentLanguage->location);
|
|
voicePromptsAppendString(locationBuffer);
|
|
voicePromptsAppendPrompt(PROMPT_SILENCE);
|
|
voicePromptsAppendPrompt(PROMPT_SILENCE);
|
|
voicePromptsAppendPrompt(PROMPT_SILENCE);
|
|
voicePromptsAppendString(maidenheadBuf);
|
|
}
|
|
|
|
if (prevSatsInView != 0xFFFF)
|
|
{
|
|
voicePromptsAppendLanguageString(currentLanguage->satellite);
|
|
voicePromptsAppendInteger(prevSatsInView);
|
|
}
|
|
|
|
if (gpsData.Status & GPS_STATUS_HAS_HEIGHT)
|
|
{
|
|
voicePromptsAppendLanguageString(currentLanguage->altitude);
|
|
voicePromptsAppendInteger(gpsData.HeightInM);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// |--> fix got lost
|
|
if (isFirstRun || forceRedraw || (gpsData.Status & GPS_STATUS_FIX_UPDATED))
|
|
{
|
|
prevSatsInView = 0xFFFF;
|
|
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
if (menuDataGlobal.currentItemIndex < PAGE_RSSI) // Do not display anything on RSSI, Polar and Direction* screens
|
|
#else
|
|
if (menuDataGlobal.currentItemIndex < PAGE_POLAR) // Do not display anything on Polar and Direction* screens
|
|
#endif
|
|
{
|
|
// Update, only clear screen regions
|
|
if (((isFirstRun || forceRedraw) == false) && (gpsData.Status & (GPS_STATUS_FIX_UPDATED)))
|
|
{
|
|
displayFillRect(0, 16, DISPLAY_SIZE_X, FONT_SIZE_3_HEIGHT, true);
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
displayFillRect(0, 32, DISPLAY_SIZE_X, FONT_SIZE_3_HEIGHT, true);
|
|
#endif
|
|
displayFillRect(0, MAIDENHEAD_HDOP_Y_POS, DISPLAY_SIZE_X, FONT_SIZE_3_HEIGHT, true);
|
|
}
|
|
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%s", currentLanguage->gps_acquiring);
|
|
displayPrintCentered(16, buffer, FONT_SIZE_3);
|
|
}
|
|
|
|
if (!isFirstRun)
|
|
{
|
|
if (gpsData.Status & GPS_STATUS_FIX_UPDATED)
|
|
{
|
|
if (nonVolatileSettings.audioPromptMode >= AUDIO_PROMPT_MODE_VOICE_THRESHOLD)
|
|
{
|
|
voicePromptsInitWithOverride();
|
|
}
|
|
else
|
|
{
|
|
soundSetMelody(MELODY_NACK_BEEP);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
voicePromptsInit();
|
|
}
|
|
}
|
|
|
|
voicePromptsAppendLanguageString(currentLanguage->gps_acquiring);
|
|
|
|
res = true;
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (isFirstRun || forceRedraw || (prevGPSState != SETTINGS_GPS_MODE_GET(nonVolatileSettings)))
|
|
{
|
|
if ((isFirstRun || forceRedraw) == false) // only clear if the GPS power status has changed
|
|
{
|
|
displayFillRect(0, (((DISPLAY_SIZE_Y - FONT_SIZE_3_HEIGHT) >> 1) + (FONT_SIZE_3_HEIGHT >> 1)), DISPLAY_SIZE_X, FONT_SIZE_3_HEIGHT, true);
|
|
}
|
|
|
|
if (SETTINGS_GPS_MODE_GET(nonVolatileSettings) == GPS_MODE_OFF)
|
|
{
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%s %s", currentLanguage->gps, currentLanguage->off);
|
|
displayThemeApply(THEME_ITEM_FG_WARNING_NOTIFICATION, THEME_ITEM_BG);
|
|
displayPrintCentered(((DISPLAY_SIZE_Y - FONT_SIZE_3_HEIGHT) >> 1) + (FONT_SIZE_3_HEIGHT >> 1), buffer, FONT_SIZE_3);
|
|
displayThemeResetToDefault();
|
|
|
|
if (forceRedraw == false)
|
|
{
|
|
voicePromptsAppendLanguageString(currentLanguage->gps);
|
|
voicePromptsAppendLanguageString(currentLanguage->off);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%s %s", currentLanguage->no, currentLanguage->gps);
|
|
displayThemeApply(THEME_ITEM_FG_ERROR_NOTIFICATION, THEME_ITEM_BG);
|
|
displayPrintCentered(((DISPLAY_SIZE_Y - FONT_SIZE_3_HEIGHT) >> 1) + (FONT_SIZE_3_HEIGHT >> 1), buffer, FONT_SIZE_3);
|
|
displayThemeResetToDefault();
|
|
|
|
if (forceRedraw == false)
|
|
{
|
|
voicePromptsAppendLanguageString(currentLanguage->no);
|
|
voicePromptsAppendLanguageString(currentLanguage->gps);
|
|
}
|
|
}
|
|
|
|
res = true;
|
|
}
|
|
}
|
|
|
|
// First run
|
|
if ((isFirstRun || (gpsData.Status & GPS_STATUS_FIX_UPDATED)) && (voicePromptsIsPlaying() == false))
|
|
{
|
|
promptsPlayNotAfterTx();
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static void updateScreen(bool isFirstRun, bool forceRedraw)
|
|
{
|
|
bool res;
|
|
|
|
if (isFirstRun || forceRedraw)
|
|
{
|
|
char buffer[SCREEN_LINE_BUFFER_SIZE];
|
|
|
|
displayClearBuf();
|
|
menuDisplayTitle(currentLanguage->gps);
|
|
|
|
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%d/%d", (menuDataGlobal.currentItemIndex + 1), PAGES_MAX);
|
|
displayThemeApply(THEME_ITEM_FG_MENU_NAME, THEME_ITEM_BG);
|
|
displayPrintCore(0, 3, buffer, FONT_SIZE_1, TEXT_ALIGN_RIGHT, false);
|
|
displayThemeResetToDefault();
|
|
}
|
|
|
|
res = displayGPSData(isFirstRun, forceRedraw);
|
|
|
|
if (isFirstRun || forceRedraw || res)
|
|
{
|
|
displayRender();
|
|
}
|
|
|
|
// GPS power mode (Off/On/NMEA) has changed, display update is now done, store the new state.
|
|
if (prevGPSState != SETTINGS_GPS_MODE_GET(nonVolatileSettings))
|
|
{
|
|
prevGPSState = SETTINGS_GPS_MODE_GET(nonVolatileSettings);
|
|
}
|
|
|
|
// Clear all the *_UPDATED flags.
|
|
gpsData.Status &= ~(GPS_STATUS_FIX_UPDATED | GPS_STATUS_FIXTYPE_UPDATED | GPS_STATUS_POSITION_UPDATED |
|
|
GPS_STATUS_HDOP_UPDATED | GPS_STATUS_COURSE_UPDATED | GPS_STATUS_SPEED_UPDATED | GPS_STATUS_HEIGHT_UPDATED |
|
|
GPS_STATUS_GPS_SATS_UPDATED | GPS_STATUS_BD_SATS_UPDATED);
|
|
}
|
|
|
|
static void handleEvent(uiEvent_t *ev)
|
|
{
|
|
bool isDirty = false;
|
|
|
|
if (ev->events & BUTTON_EVENT)
|
|
{
|
|
if (repeatVoicePromptOnSK1(ev))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ev->events & FUNCTION_EVENT)
|
|
{
|
|
if (ev->function == FUNC_REDRAW)
|
|
{
|
|
isDirty = true;
|
|
goto eventHanderExit;
|
|
}
|
|
else if (QUICKKEY_TYPE(ev->function) == QUICKKEY_MENU)
|
|
{
|
|
menuDataGlobal.currentItemIndex = QUICKKEY_ENTRYID(ev->function);
|
|
isDirty = true;
|
|
goto eventHanderExit;
|
|
}
|
|
}
|
|
|
|
if (KEYCHECK_SHORTUP(ev->keys, KEY_UP))
|
|
{
|
|
if (menuDataGlobal.currentItemIndex > PAGE_COORDS)
|
|
{
|
|
menuDataGlobal.currentItemIndex--;
|
|
isDirty = true;
|
|
}
|
|
}
|
|
else if (KEYCHECK_SHORTUP(ev->keys, KEY_DOWN))
|
|
{
|
|
if (menuDataGlobal.currentItemIndex < (PAGES_MAX - 1))
|
|
{
|
|
menuDataGlobal.currentItemIndex++;
|
|
isDirty = true;
|
|
}
|
|
}
|
|
else if ((KEYCHECK_SHORTUP(ev->keys, KEY_GREEN) && BUTTONCHECK_DOWN(ev, BUTTON_SK2))
|
|
#if defined(PLATFORM_MD9600) || defined(CPU_MK22FN512VLL12)
|
|
// Let the operator to set the GPS power status to GPS_MODE_ON only, on longpress GREEN (A/B mic button also).
|
|
|| (KEYCHECK_LONGDOWN(ev->keys, KEY_GREEN) && (SETTINGS_GPS_MODE_GET(nonVolatileSettings) > GPS_NOT_DETECTED) && (SETTINGS_GPS_MODE_GET(nonVolatileSettings) < GPS_MODE_ON))
|
|
#endif
|
|
)
|
|
{
|
|
gpsOnUsingQuickKey(true);
|
|
}
|
|
else if (KEYCHECK_SHORTUP(ev->keys, KEY_RED) && BUTTONCHECK_DOWN(ev, BUTTON_SK2))
|
|
{
|
|
gpsOnUsingQuickKey(false);
|
|
}
|
|
else if (KEYCHECK_SHORTUP(ev->keys, KEY_RED))
|
|
{
|
|
menuSystemPopPreviousMenu();
|
|
}
|
|
else if (KEYCHECK_SHORTUP_NUMBER(ev->keys) && (BUTTONCHECK_DOWN(ev, BUTTON_SK2)))
|
|
{
|
|
saveQuickkeyMenuIndex(ev->keys.key, menuSystemGetCurrentMenuNumber(), menuDataGlobal.currentItemIndex, 0);
|
|
}
|
|
|
|
eventHanderExit:
|
|
|
|
if (isDirty)
|
|
{
|
|
updateScreen(false, true);
|
|
}
|
|
}
|
|
#endif
|