diff --git a/README.md b/README.md
index 33a74b6..aefe8b6 100644
--- a/README.md
+++ b/README.md
@@ -1,67 +1,80 @@
-# uBiTXv6
+# uBiTXv6 - modified by DL9OBN
-This project is found at https://github.com/reedbn/ubitxv6/
-
-It was forked from https://github.com/afarhan/ubitxv6/
-
-The purpose of this project is to clean up (modularize) the source code, and add features that were not present
-in Ashhar's original version of the project, without requiring any hardware modifications to a stock uBiTXv6.
+The purpose of this fork is to adapt Reed Nightingale's very good and valuable work (https://github.com/reedbn/ubitxv6/) to my personal needs. While adding new functionality I focused on my main operating mode: CW.
New features include:
-* Much faster screen refresh (vs Ashhar's 6.3.1 aka 6.0 release)
-* Morse code readback for sightless operation
-* Save/recall your favorite frequencies
-* When adjusting settings, the existing/current setting is shown as reference
-* Cancel touch recalibration
+* A morse practice mode is available, where the TX line is muted while keying CW. The "CW audio mode" has been removed for this.
+* Removed the option for "CW keying" with the PTT key, straight key or paddles are to be used for this exclusively.
+* Tuning step size can be changed with a short tune button press in the main menu. The tuning step size changes between 10Hz - 20Hz - 50Hz - 100Hz and is displayed by little circles, in the middle between the two VFO frequencies. The "menu selection" mode, where a button is selected by the tune knob, can be entered and confirmed with a long button press of the tune button now.
+* When the uBitX is started in CW mode (see `CW_IS_DEFAULT` config value below), the minimum frequency for each band will be used as start frequency.
+* Simplified the setting of start frequency when changing bands (mainly to save some memory)
+* Added display of current CW speed in the main screen. Since we need the space, the RIT frequency is now always displayed directly under "VFO A".
+* Added support for setting the min/max frequencies of all bands, based on the configured IARU region (1/2/3)
+* Added a check for the current TX frequency, if we're "out of band" the "TX" button isn't displayed and the TX line is muted.
+* The "TX" button is now always visible when the current frequency is valid (see item before), and simply changes its colour when the uBitX goes into "TX" mode.
+* Added support for a different GUI theme, which is more based on "Google Materials" (rounded buttons and such). In order for the program to still fit, I had to remove the "calibration" options from the setup menu and had to disable CAT support!
-User Manual: https://docs.google.com/document/d/1jlllZbvFMCzO1MJLzlJDGb10HXSehlFNMDPsxGJZtvY/edit?usp=drivesdk
-
-# Installing on Your Radio
+# Installing on your radio
There are plenty of tutorials on how to upload sketches to Arduino Nanos. Just search for them. Addtionally,
Ashhar created a video explaining the process specifically for uBiTX v6: https://www.youtube.com/watch?v=3n_V3prSJ_E
-I developed this code using the Arduino IDE 1.8.9 toolchain, with -Wall and -Wextra compiler options turned on.
-Arduino IDE 1.8.13 was reported to compile too big (see https://groups.io/g/BITX20/topic/75008576), but this
-should be resolved in this project's tag R1.5.1.
+# Personalized config values
+
+To edit e.g. the callsign displayed, open the file `config.h` and change the defines of the config values (defines)
+
+
+- CALLSIGN_TEXT
+- Your callsign as it should be displayed in the main screen.
+
+- IARU_REGION
+- Sets the limit frequencies (min/max) for all bands according to regulations for regions 1, 2 and 3.
+
+- DISPLAY_CW_SPEED
+- Change whether you want to display the current CW speed as "wpm", "cpm" or "BpM".
+
+- CW_IS_DEFAULT
+- If set to "1", the uBitX will start up in CW mode.
+
+- DEFAULT_TUNING_STEP_SIZE
+- Set the default tuning step size (10Hz, 20Hz, 50Hz or 100Hz).
+
+- GUI_THEME
+- Set the GUI theming to either "0" (the default) or "1" (Google materials style). Be aware that for the latter option, the calibration and CAT functionalities had to be removed and aren't available!
+
+
+Then re-compile and upload.
+
+# Comparison of GUI themes
+
+## Default theme
+
+These are some images for the default theme, as was used in the original version by Reed Nightingale.
+
+
-# Personalized Callsign
+
-To edit the callsign displayed, open the file `callsign.cpp` and change the string. Then re-compile and upload.
+
-# Future Features/Modifications
+
-There are some features that would be good to add, but I just didn't get around to.
-* Setting to choose the tuning step size
-* Setting to choose whether or not the knob tuning should accelerate (current behavior) or have a fixed interval
-* Provide an option in each menu screen to load the default option for each setting
+## New theme
-While the current code (as of 2020-05-05) is ~100 bytes shy of the full 30720 available on the nano, there's still
-opportunity to add new features by "creating" room. Below is a list of places you might create room:
+Following some examples of my new theme, using Google Material features like rounded buttons and also
+a reduced set of colors.
-I added lots of bounds checking, especially on string writes, that, if removed, could free a good number of bytes.
-While keeping them is best practice, for a non-IoT, non-critical piece of hardware, it shouldn't be a huge issue.
-I added the RACK to the CAT to better emulate the FT-817 (I hope, at least!). Removing the RACK's and just leaving
-the default ACK's will also free up bytes.
+
-I added a bunch of strings to the menuing with the intention of helping people understand their functions, but
-technically they're not necessary, and could all be removed.
+
-I switched to a smaller footprint font than Ashhar's original code, but there are MUCH smaller fonts out there.
-Changing to a lower resolution, scaled up font can save hundreds or thousands of bytes, but won't look as pretty.
-Also, the star, gear, and numpad icons will need to be either added to the new font, or replaced with characters.
+
-The first change I made to this fork was to replace Ashhar's original (incredibly slow) screen drawing routines
-with PDQ. Since that change, Ashhar has updated his drawing routine to be MUCH faster than his original, but
-still slightly slower than PDQ. It may be that Ashhar's new routines are smaller that PDQ, but I don't actually
-know that for certain.
+
-There are a good number of instances of back-to-back calls of strncpy_P and displayText. Creating a single
-function that performs these operations together, and then calling that new function instead of the
-back-to-back calls everywhere may save space.
# License
diff --git a/bands.cpp b/bands.cpp
index de05d66..cb0242e 100644
--- a/bands.cpp
+++ b/bands.cpp
@@ -2,6 +2,7 @@
#include "bands.h"
#include "utils.h"
+#include "config.h"
/*
* These are the bands for USA. Your bands may vary
@@ -16,20 +17,36 @@ struct Band_t {
const char UNKNOWN_BAND_NAME [] PROGMEM = "??";
constexpr Band_t bands [] PROGMEM {
-// { 0UL, 255UL, 255, "U8"},//Utility conversion option
-// { 0UL, 65535UL, 254, "UF"},//Utility conversion option
-// { 530000UL, 1700000UL, 253, "AM"},//Broadcast AM, actually centers at 268, but uint8 can't do that
-// { 1800000UL, 2000000UL, 160, "A0"},//0xA0 is 160
+#if IARU_REGION == 1
+ // Africa, Europe, Middle East, and northern Asia
+ { 3500000UL, 3800000UL, 80, "80"},
+ { 7000000UL, 7200000UL, 40, "40"},
+ {10100000UL, 10150000UL, 30, "30"},
+ {14000000UL, 14350000UL, 20, "20"},
+ {18068000UL, 18168000UL, 17, "17"},
+ {21000000UL, 21450000UL, 15, "15"},
+ {28000000UL, 29700000UL, 10, "10"},
+#else
+#if IARU_REGION == 3
+ // the rest of Asia and the Pacific
+ { 3500000UL, 3900000UL, 80, "80"},
+ { 7000000UL, 7200000UL, 40, "40"},
+ {10110000UL, 10150000UL, 30, "30"},
+ {14000000UL, 14350000UL, 20, "20"},
+ {18068000UL, 18168000UL, 17, "17"},
+ {21000000UL, 21450000UL, 15, "15"},
+ {28000000UL, 29700000UL, 10, "10"},
+#else
+ // The default - the Americas
{ 3500000UL, 4000000UL, 80, "80"},
-// { 5330500UL, 5403500UL, 60, "60"},
{ 7000000UL, 7300000UL, 40, "40"},
{10100000UL, 10150000UL, 30, "30"},
{14000000UL, 14350000UL, 20, "20"},
{18068000UL, 18168000UL, 17, "17"},
{21000000UL, 21450000UL, 15, "15"},
-// {24890000UL, 24990000UL, 12, "12"},
-// {26965000UL, 27405000UL, 11, "CB"},//Citizen's Band
{28000000UL, 29700000UL, 10, "10"},
+#endif // of: #if IARU_REGION == 3
+#endif // of: #if IARU_REGION == 1
};
constexpr uint8_t NUM_BANDS = sizeof(bands)/sizeof(bands[0]);
@@ -87,25 +104,15 @@ uint32_t getFreqInBand(const uint32_t frequency,
return frequency;
}
- //See if we're currrently in a valid band
- int8_t current_band_index = findBandIndexFromFreq(frequency);
-
- if(-1 == current_band_index){
- //We're not in a known band - just go to the center of the target band
- Band_t band;
- memcpy_P(&band,&bands[target_band_index],sizeof(band));
- return band.min + ((band.max - band.min)/2/100)*100;//midpoint truncated to 100Hz resolution
- }
- else{
- //We're in a known band. Match the relative position in the target band.
- Band_t current_band;
- memcpy_P(¤t_band,&bands[current_band_index],sizeof(current_band));
- Band_t target_band;
- memcpy_P(&target_band,&bands[target_band_index],sizeof(target_band));
- const uint32_t range_current = current_band.max - current_band.min;
- const uint32_t range_target = target_band.max - target_band.min;
- return (((frequency - current_band.min) * (uint64_t)range_target / range_current + target_band.min)/100)*100;//truncated 100Hz
- }
+ Band_t band;
+ memcpy_P(&band,&bands[target_band_index],sizeof(band));
+#if CW_IS_DEFAULT == 0
+ // go to the center of the target band
+ return band.min + ((band.max - band.min)/2/100)*100;//midpoint truncated to 100Hz resolution
+#else
+ // for CW we prefer the start of each band
+ return band.min;
+#endif
}
bool isFreqInBand(const uint32_t frequency,
@@ -128,3 +135,12 @@ bool isFreqInBand(const uint32_t frequency,
return false;
}
+/** Return false if the given frequency is outside of any ham band.
+ *
+ * This will be used to suppress TX when we're "out
+ * of band".
+*/
+bool freqInAnyBand(const uint32_t frequency)
+{
+ return findBandIndexFromFreq(frequency) != -1;
+}
diff --git a/bands.h b/bands.h
index 8303e5e..49e9dae 100644
--- a/bands.h
+++ b/bands.h
@@ -8,4 +8,6 @@ uint32_t getFreqInBand(const uint32_t frequency,
const uint8_t target_band);
bool isFreqInBand(const uint32_t frequency,
- const uint8_t band);
\ No newline at end of file
+ const uint8_t band);
+
+bool freqInAnyBand(const uint32_t frequency);
diff --git a/button.cpp b/button.cpp
index 536f196..8203714 100644
--- a/button.cpp
+++ b/button.cpp
@@ -8,27 +8,6 @@
void drawButton(Button* button)
{
- uint16_t tc = COLOR_INACTIVE_TEXT;
- uint16_t bgc = COLOR_INACTIVE_BACKGROUND;
- const uint16_t bdc = COLOR_INACTIVE_BORDER;
- switch(button->status())
- {
- case ButtonStatus_e::Stateless://Fallthrough intended
- case ButtonStatus_e::Inactive://Fallthrough intended
- default:
- {
- //Colors are initialized for this, so we're done
- break;
- }
- case ButtonStatus_e::Active:
- {
- tc = COLOR_ACTIVE_TEXT;
- bgc = COLOR_ACTIVE_BACKGROUND;
- break;
- }
- }
-
-
if(nullptr != button->text){
strncpy_P(b,button->text,sizeof(b));
}
@@ -40,7 +19,22 @@ void drawButton(Button* button)
//Serial.println(F("No text for button!"));
return;
}
- displayText(b, button->x, button->y, button->w, button->h, tc, bgc, bdc);
+#if GUI_THEME == 0
+ if (button->status() == ButtonStatus_e::Active) {
+ displayText(b, button->x, button->y, button->w, button->h, COLOR_ACTIVE_TEXT, COLOR_ACTIVE_BACKGROUND, COLOR_INACTIVE_BORDER);
+ } else {
+ displayText(b, button->x, button->y, button->w, button->h, COLOR_INACTIVE_TEXT, COLOR_INACTIVE_BACKGROUND, COLOR_INACTIVE_BORDER);
+ }
+#else
+ displayFillrect(button->x, button->y, button->w, button->h, COLOR_BACKGROUND);
+ if (button->status() == ButtonStatus_e::Active) {
+ displayFillroundrect(button->x, button->y, button->w, button->h, button->h/2, COLOR_ACTIVE_BACKGROUND);
+ displayText(b, button->x, button->y, button->w, button->h, COLOR_ACTIVE_TEXT, COLOR_ACTIVE_BACKGROUND, COLOR_ACTIVE_BACKGROUND);
+ } else {
+ displayText(b, button->x, button->y, button->w, button->h, COLOR_INACTIVE_TEXT, COLOR_INACTIVE_BACKGROUND, COLOR_INACTIVE_BACKGROUND);
+ displayRoundrect(button->x, button->y, button->w, button->h, button->h/2, COLOR_INACTIVE_TEXT);
+ }
+#endif
}
void extractAndDrawButton(Button* button_out, const Button* button_P)
diff --git a/callsign.cpp b/callsign.cpp
index 4c7203a..0977896 100644
--- a/callsign.cpp
+++ b/callsign.cpp
@@ -1,4 +1,5 @@
#include "callsign.h"
+#include "config.h"
-const char CALLSIGN_STRING_PRIVATE [] PROGMEM = "CALLSIGN";
+const char CALLSIGN_STRING_PRIVATE [] PROGMEM = CALLSIGN_TEXT;
const char* const CALLSIGN_STRING = CALLSIGN_STRING_PRIVATE;
\ No newline at end of file
diff --git a/color_theme.h b/color_theme.h
index d76155e..7a2ed65 100644
--- a/color_theme.h
+++ b/color_theme.h
@@ -1,12 +1,21 @@
#pragma once
#include "colors.h"
+#include "config.h"
+#if GUI_THEME == 0
static const unsigned int COLOR_TEXT = DISPLAY_WHITE;
static const unsigned int COLOR_BACKGROUND = DISPLAY_NAVY;
static const unsigned int COLOR_ACTIVE_VFO_TEXT = DISPLAY_WHITE;
static const unsigned int COLOR_ACTIVE_VFO_BACKGROUND = DISPLAY_BLACK;
+#else
+static const unsigned int COLOR_TEXT = DISPLAY_GREEN;
+static const unsigned int COLOR_BACKGROUND = DISPLAY_BLACK;
+
+static const unsigned int COLOR_ACTIVE_VFO_TEXT = DISPLAY_BLACK;
+static const unsigned int COLOR_ACTIVE_VFO_BACKGROUND = DISPLAY_GREEN;
+#endif
static const unsigned int COLOR_INACTIVE_VFO_TEXT = DISPLAY_GREEN;
static const unsigned int COLOR_INACTIVE_VFO_BACKGROUND = DISPLAY_BLACK;
@@ -19,4 +28,4 @@ static const unsigned int COLOR_ACTIVE_TEXT = DISPLAY_BLACK;
static const unsigned int COLOR_ACTIVE_BACKGROUND = DISPLAY_ORANGE;
static const unsigned int COLOR_ACTIVE_BORDER = DISPLAY_WHITE;
-static const unsigned int COLOR_VERSION_TEXT = DISPLAY_LIGHTGREY;
\ No newline at end of file
+static const unsigned int COLOR_VERSION_TEXT = DISPLAY_LIGHTGREY;
diff --git a/colors.h b/colors.h
index bb56762..950e7d8 100644
--- a/colors.h
+++ b/colors.h
@@ -1,4 +1,9 @@
// Color definitions
+//
+// Note that the GFX library uses a 5-6-5 encoding
+// for 16-bit color: the highest 5 bits are the red
+// value, the middle 6 are green, and the lowest 5
+// are blue.
static const uint16_t DISPLAY_BLACK = 0x0000; ///< 0, 0, 0
static const uint16_t DISPLAY_NAVY = 0x000F; ///< 0, 0, 123
static const uint16_t DISPLAY_DARKGREEN = 0x03E0; ///< 0, 125, 0
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..f2c59ba
--- /dev/null
+++ b/config.h
@@ -0,0 +1,40 @@
+#pragma once
+//
+// Header file that keeps some global configuration values
+//
+
+// The callsign that appears on the main menu
+#define CALLSIGN_TEXT "CALLSIGN"
+
+// The software version number of the ubitx firmware
+#define VERSION_TEXT "R2.0.1"
+
+// Set to your preferred region for the correct band frequencies
+// 1 - Africa, Europe, Middle East, and northern Asia
+// 2 - the Americas
+// 3 - the rest of Asia and the Pacific
+#define IARU_REGION 2
+
+// Display CW speed as
+// 0 - words per minute (wpm)
+// 1 - chars per minute (cpm)
+// 2 - Buchstaben pro Minute (BpM, German special)
+#define DISPLAY_CW_SPEED 0
+
+// Sets the default tuning mode to
+// 0 - SSB
+// 1 - CW
+#define CW_IS_DEFAULT 0
+
+// Sets the default tuning step size to
+// 0 - 10Hz
+// 1 - 20Hz
+// 2 - 50Hz
+// 3 - 100Hz
+#define DEFAULT_TUNING_STEP_SIZE 2
+
+// Sets the GUI theme to use
+// 0 - default
+// 1 - more oriented towards Google Materials (e.g. rounded buttons), be aware that for this
+// option, the calibration and CAT functionalities had to be removed and aren't available!
+#define GUI_THEME 0
diff --git a/images/20230108_093317.jpg b/images/20230108_093317.jpg
new file mode 100644
index 0000000..131be88
Binary files /dev/null and b/images/20230108_093317.jpg differ
diff --git a/images/20230108_093331.jpg b/images/20230108_093331.jpg
new file mode 100644
index 0000000..ae365cf
Binary files /dev/null and b/images/20230108_093331.jpg differ
diff --git a/images/20230108_093343.jpg b/images/20230108_093343.jpg
new file mode 100644
index 0000000..9118ac8
Binary files /dev/null and b/images/20230108_093343.jpg differ
diff --git a/images/20230108_093403.jpg b/images/20230108_093403.jpg
new file mode 100644
index 0000000..2d239dc
Binary files /dev/null and b/images/20230108_093403.jpg differ
diff --git a/images/20230108_101446.jpg b/images/20230108_101446.jpg
new file mode 100644
index 0000000..0113f13
Binary files /dev/null and b/images/20230108_101446.jpg differ
diff --git a/images/20230108_101458.jpg b/images/20230108_101458.jpg
new file mode 100644
index 0000000..0b21aa9
Binary files /dev/null and b/images/20230108_101458.jpg differ
diff --git a/images/20230108_101511.jpg b/images/20230108_101511.jpg
new file mode 100644
index 0000000..c5ec739
Binary files /dev/null and b/images/20230108_101511.jpg differ
diff --git a/images/20230108_101535.jpg b/images/20230108_101535.jpg
new file mode 100644
index 0000000..26ba7c8
Binary files /dev/null and b/images/20230108_101535.jpg differ
diff --git a/keyer.cpp b/keyer.cpp
index 0a13dca..2edeabd 100644
--- a/keyer.cpp
+++ b/keyer.cpp
@@ -2,6 +2,7 @@
#include "pin_definitions.h"
#include "settings.h"
#include "tuner.h"
+#include "config.h"
/**
CW Keyer
@@ -107,10 +108,9 @@ void cwKeyer(void){
bool continue_loop = true;
char tmpKeyControl = 0;
- if((KeyerMode_e::KEYER_STRAIGHT == globalSettings.keyerMode)
- || (digitalRead(PIN_PTT) == 0)){//use the PTT as the key for tune up, quick QSOs
+ if(KeyerMode_e::KEYER_STRAIGHT == globalSettings.keyerMode){
while(1){
- tmpKeyControl = update_PaddleLatch(0) | (digitalRead(PIN_PTT)?0:DIT_L);
+ tmpKeyControl = update_PaddleLatch(0);
//Serial.println((int)tmpKeyControl);
if ((tmpKeyControl & DIT_L) == DIT_L) {
// if we are here, it is only because the key is pressed
@@ -121,7 +121,7 @@ void cwKeyer(void){
cwKeydown();
while ( tmpKeyControl & DIT_L == DIT_L){
- tmpKeyControl = update_PaddleLatch(0) | (digitalRead(PIN_PTT)?0:DIT_L);
+ tmpKeyControl = update_PaddleLatch(0);
//Serial.println((int)tmpKeyControl);
}
@@ -134,8 +134,9 @@ void cwKeyer(void){
}
return;//Tx stop control by Main Loop
}
-
+#if GUI_THEME == 0
checkCAT();
+#endif
} //end of while
}
@@ -217,8 +218,9 @@ void cwKeyer(void){
}
break;
}
-
+#if GUI_THEME == 0
checkCAT();
+#endif
} //end of while
}//end of KEYER_IAMBIC_*
}
diff --git a/menu_main.cpp b/menu_main.cpp
index 08e8ff4..4e77c8b 100644
--- a/menu_main.cpp
+++ b/menu_main.cpp
@@ -7,12 +7,12 @@
#include "button.h"
#include "color_theme.h"
#include "menu_utils.h"
-#include "morse.h"
#include "nano_gui.h"
#include "scratch_space.h"
#include "settings.h"
#include "tuner.h"//THRESHOLD_USB_LSB
#include "utils.h"
+#include "setup.h"
void drawMainMenu(void);
MenuReturn_e runMainMenu(const ButtonPress_e tuner_button,
@@ -39,11 +39,11 @@ void drawMainMenu(void)
memcpy_P(&bp, &(mainMenuButtons[i]), sizeof(bp));
extractAndDrawButton(&button,bp);
}
+ drawTuningStepSize();
drawVersion();
drawCallsign();
-
- ltoa(GetActiveVfoFreq(),b,10);
- morseText(b);
+ drawWpM();
+ drawTx();
}
void drawMainMenuIncrement()
@@ -52,9 +52,12 @@ void drawMainMenuIncrement()
static uint32_t last_freq = 0;
static Vfo_e last_vfo = Vfo_e::VFO_A;
static VfoMode_e last_mode = VfoMode_e::VFO_MODE_LSB;
+ static uint16_t last_tuning_step = 0;
static bool last_split = false;
static bool last_rit = false;
+ static uint16_t last_cw_duration = 0;
static TuningMode_e last_tuning = TuningMode_e::TUNE_SSB;
+ bool draw_tx = false;
Button button;
@@ -68,11 +71,18 @@ void drawMainMenuIncrement()
//We set this here so that we're always hearing what's displayed
setFrequency(last_freq);
+ draw_tx = true;
+ }
+
+ if(last_tuning_step != globalSettings.tuningStepSize){
+ drawTuningStepSize();
+ last_tuning_step = globalSettings.tuningStepSize;
}
if(last_mode != GetActiveVfoMode()){
updateSidebandButtons();
last_mode = GetActiveVfoMode();
+ draw_tx = true;
}
if(last_split != globalSettings.splitOn){
@@ -80,17 +90,28 @@ void drawMainMenuIncrement()
extractAndDrawButton(&button,&bVfoB);
extractAndDrawButton(&button,&bSpl);
last_split = globalSettings.splitOn;
+ draw_tx = true;
}
if(last_rit != globalSettings.ritOn){
extractAndDrawButton(&button,&bRit);
last_rit = globalSettings.ritOn;
+ draw_tx = true;
}
if(last_tuning != globalSettings.tuningMode){
extractAndDrawButton(&button,&bCw);
last_tuning = globalSettings.tuningMode;
}
+
+ if(last_cw_duration != globalSettings.cwDitDurationMs){
+ drawWpM();
+ last_cw_duration = globalSettings.cwDitDurationMs;
+ }
+
+ if (draw_tx) {
+ drawTx();
+ }
}
void mainMenuTune(int16_t knob)
@@ -101,8 +122,14 @@ void mainMenuTune(int16_t knob)
}
const uint32_t current_freq = GetActiveVfoFreq();
- const uint32_t new_freq = current_freq + (50 * knob);
-
+ uint32_t new_freq = current_freq + (globalSettings.tuningStepSize * knob);
+ // Ensure that we're in the given step size grid
+ if (knob > 0) {
+ new_freq -= new_freq % globalSettings.tuningStepSize;
+ } else {
+ new_freq += new_freq % globalSettings.tuningStepSize;
+ }
+
SetActiveVfoFreq(new_freq);
autoSelectSidebandChanged(current_freq);
}
@@ -122,6 +149,25 @@ MenuReturn_e runMainMenu(const ButtonPress_e tuner_button,
break;
}
case ButtonPress_e::ShortPress:
+ {
+ if(!mainMenuSelecting){
+ // Increase tuning step size
+ switch (globalSettings.tuningStepSize) {
+ case 10: globalSettings.tuningStepSize = 20;
+ break;
+ case 20: globalSettings.tuningStepSize = 50;
+ break;
+ case 50: globalSettings.tuningStepSize = 100;
+ break;
+ default: globalSettings.tuningStepSize = 10;
+ break;
+ }
+ }
+ //Don't handle touch or knob on this run
+ return MenuReturn_e::StillActive;//main menu always returns StillActive
+ break;
+ }
+ case ButtonPress_e::LongPress:
{
if(mainMenuSelecting){
uint8_t menu_index = mainMenuSelectedItemRaw/MENU_KNOB_COUNTS_PER_ITEM;
@@ -135,8 +181,7 @@ MenuReturn_e runMainMenu(const ButtonPress_e tuner_button,
else{
initSelector(&mainMenuSelectedItemRaw,
mainMenuButtons,
- MAIN_MENU_NUM_BUTTONS,
- MorsePlaybackType_e::PlayChar);
+ MAIN_MENU_NUM_BUTTONS);
}
mainMenuSelecting = !mainMenuSelecting;
@@ -144,21 +189,6 @@ MenuReturn_e runMainMenu(const ButtonPress_e tuner_button,
return MenuReturn_e::StillActive;//main menu always returns StillActive
break;
}
- case ButtonPress_e::LongPress:
- {
- if(!globalSettings.morseMenuOn){
- globalSettings.morseMenuOn = true;//set before playing
- morseLetter(2);
- }
- else{
- morseLetter(4);
- globalSettings.morseMenuOn = false;//unset after playing
- }
- SaveSettingsToEeprom();
- //Don't handle touch or knob on this run
- return MenuReturn_e::StillActive;//main menu always returns StillActive
- break;
- }
}//switch
}//tuner_button
@@ -178,8 +208,7 @@ MenuReturn_e runMainMenu(const ButtonPress_e tuner_button,
adjustSelector(&mainMenuSelectedItemRaw,
knob,
mainMenuButtons,
- MAIN_MENU_NUM_BUTTONS,
- MorsePlaybackType_e::PlayChar);
+ MAIN_MENU_NUM_BUTTONS);
}
else{
mainMenuTune(knob);
@@ -187,6 +216,6 @@ MenuReturn_e runMainMenu(const ButtonPress_e tuner_button,
}
drawMainMenuIncrement();
-
+
return MenuReturn_e::StillActive;//main menu always returns StillActive
}
\ No newline at end of file
diff --git a/menu_main_buttons.cpp b/menu_main_buttons.cpp
index 034b830..20599c4 100644
--- a/menu_main_buttons.cpp
+++ b/menu_main_buttons.cpp
@@ -11,7 +11,6 @@
#include "menu_main.h"
#include "menu_numpad.h"
#include "menu_quicklist.h"
-#include "morse.h"
#include "nano_gui.h"
#include "scratch_space.h"
#include "settings.h"
@@ -22,13 +21,13 @@
static const unsigned int LAYOUT_VFO_LABEL_X = 0;
static const unsigned int LAYOUT_VFO_LABEL_Y = 10;
-static const unsigned int LAYOUT_VFO_LABEL_WIDTH = 159;
+static const unsigned int LAYOUT_VFO_LABEL_WIDTH = 149;
static const unsigned int LAYOUT_VFO_LABEL_HEIGHT = 36;
static const unsigned int LAYOUT_VFO_LABEL_PITCH_X = 160;
static const unsigned int LAYOUT_MODE_TEXT_X = 0;
static const unsigned int LAYOUT_MODE_TEXT_Y = LAYOUT_VFO_LABEL_Y + LAYOUT_VFO_LABEL_HEIGHT + 1;
-static const unsigned int LAYOUT_MODE_TEXT_WIDTH = 320;
+static const unsigned int LAYOUT_MODE_TEXT_WIDTH = 159;
static const unsigned int LAYOUT_MODE_TEXT_HEIGHT = 36;
static const unsigned int LAYOUT_BUTTON_X = 2;
@@ -40,7 +39,7 @@ static const unsigned int LAYOUT_BUTTON_PITCH_Y = 40;
static const unsigned int LAYOUT_CW_TEXT_X = 0;
static const unsigned int LAYOUT_CW_TEXT_Y = LAYOUT_BUTTON_Y + 3*LAYOUT_BUTTON_PITCH_Y + 1;
-static const unsigned int LAYOUT_CW_TEXT_WIDTH = 220;
+static const unsigned int LAYOUT_CW_TEXT_WIDTH = 200;
static const unsigned int LAYOUT_CW_TEXT_HEIGHT = 36;
static const unsigned int LAYOUT_VERSION_TEXT_X = LAYOUT_CW_TEXT_X + LAYOUT_CW_TEXT_WIDTH + 1;
@@ -48,19 +47,51 @@ static const unsigned int LAYOUT_VERSION_TEXT_Y = LAYOUT_CW_TEXT_Y;
static const unsigned int LAYOUT_VERSION_TEXT_WIDTH = 320 - LAYOUT_CW_TEXT_WIDTH - 1;
static const unsigned int LAYOUT_VERSION_TEXT_HEIGHT = LAYOUT_CW_TEXT_HEIGHT;
-static const unsigned int LAYOUT_TX_X = 280;
+static const unsigned int LAYOUT_TX_X = 260;
static const unsigned int LAYOUT_TX_Y = LAYOUT_MODE_TEXT_Y;
-static const unsigned int LAYOUT_TX_WIDTH = 40;
+static const unsigned int LAYOUT_TX_WIDTH = 60;
static const unsigned int LAYOUT_TX_HEIGHT = 36;
+static const unsigned int LAYOUT_TUNING_STEP_SIZE_WIDTH = 20;
+
void drawTx()
{
- if(globalSettings.txActive){
- strncpy_P(b,(const char*)F("TX"),sizeof(b));
- displayText(b,LAYOUT_TX_X,LAYOUT_TX_Y,LAYOUT_TX_WIDTH,LAYOUT_TX_HEIGHT,COLOR_ACTIVE_TEXT,COLOR_ACTIVE_BACKGROUND,COLOR_BACKGROUND);
+ // On which frequency would we be sending?
+ uint32_t current_tx_freq = 0;
+ if (globalSettings.ritOn) {
+ current_tx_freq = globalSettings.ritFrequency;
+ } else {
+ if(globalSettings.splitOn) {
+ if(Vfo_e::VFO_B == globalSettings.activeVfo){
+ current_tx_freq = globalSettings.vfoA.frequency;
+ } else{
+ current_tx_freq = globalSettings.vfoB.frequency;
+ }
+ } else {
+ current_tx_freq = GetActiveVfoFreq();
+ }
}
- else{
- displayFillrect(LAYOUT_TX_X,LAYOUT_TX_Y,LAYOUT_TX_WIDTH,LAYOUT_TX_HEIGHT,COLOR_BACKGROUND);
+
+ // Is our TX frequency inside a HAM band?
+ if (freqInAnyBand(current_tx_freq)) {
+ // Yes
+ strncpy_P(b,(const char*)F("TX"),sizeof(b));
+ if (globalSettings.txActive){
+ // We're currently sending...
+ if (globalSettings.morsePracticeMode) {
+ // ... but in practice mode.
+ displayButtonText(b,LAYOUT_TX_X,LAYOUT_TX_Y,LAYOUT_TX_WIDTH,LAYOUT_TX_HEIGHT,DISPLAY_ORANGE,DISPLAY_OLIVE,DISPLAY_OLIVE);
+ } else {
+ // ... for real.
+ displayButtonText(b,LAYOUT_TX_X,LAYOUT_TX_Y,LAYOUT_TX_WIDTH,LAYOUT_TX_HEIGHT,COLOR_ACTIVE_TEXT,COLOR_ACTIVE_BACKGROUND,COLOR_ACTIVE_BACKGROUND);
+ }
+ } else {
+ // Not sending
+ displayButtonText(b,LAYOUT_TX_X,LAYOUT_TX_Y,LAYOUT_TX_WIDTH,LAYOUT_TX_HEIGHT,DISPLAY_DARKGREY,DISPLAY_LIGHTGREY,DISPLAY_LIGHTGREY);
+ }
+ } else {
+ // We're not inside a HAM band, so don't display the button at all
+ displayFillrect(LAYOUT_TX_X,LAYOUT_TX_Y,LAYOUT_TX_WIDTH,LAYOUT_TX_HEIGHT, COLOR_BACKGROUND);
}
}
@@ -95,7 +126,7 @@ void toVfoB(char* text_out, const uint16_t max_text_size);
ButtonStatus_e bsVfoB();
void osVfoB();
constexpr Button bVfoB PROGMEM = {
- LAYOUT_VFO_LABEL_X + 1*LAYOUT_VFO_LABEL_PITCH_X,
+ LAYOUT_VFO_LABEL_X + 1*LAYOUT_VFO_LABEL_PITCH_X + LAYOUT_TUNING_STEP_SIZE_WIDTH/2,
LAYOUT_VFO_LABEL_Y,
LAYOUT_VFO_LABEL_WIDTH,
LAYOUT_VFO_LABEL_HEIGHT,
@@ -351,7 +382,6 @@ void updateBandButtons(const uint32_t old_freq)
for(uint8_t i = 0; i < sizeof(bands)/sizeof(bands[0]); ++i){
if(isFreqInBand(old_freq,bands[i]) != isFreqInBand(curr_freq,bands[i])){
extractAndDrawButton(&button,band_buttons[i]);
- morseBool(ButtonStatus_e::Active == button.status());
}
}
}
@@ -416,9 +446,6 @@ void osVfo(const Vfo_e vfo){
globalSettings.activeVfo = vfo;
SaveSettingsToEeprom();
- ltoa(GetActiveVfoFreq(),b,10);
- morseText(b);
-
Button button;
extractAndDrawButton(&button,&bVfoA);
extractAndDrawButton(&button,&bVfoB);
@@ -457,12 +484,7 @@ void osRit(){
strncpy_P(b,(const char*)F("TX: "),sizeof(b));
formatFreq(globalSettings.ritFrequency, b + strlen(b), sizeof(b)-strlen(b));
- if (VFO_A == globalSettings.activeVfo){
- displayText(b, LAYOUT_VFO_LABEL_X + 0*LAYOUT_VFO_LABEL_PITCH_X, LAYOUT_MODE_TEXT_Y, LAYOUT_VFO_LABEL_WIDTH, LAYOUT_MODE_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND, TextJustification_e::Left);
- }
- else{
- displayText(b, LAYOUT_VFO_LABEL_X + 1*LAYOUT_VFO_LABEL_PITCH_X, LAYOUT_MODE_TEXT_Y, LAYOUT_VFO_LABEL_WIDTH, LAYOUT_MODE_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND, TextJustification_e::Left);
- }
+ displayText(b, LAYOUT_VFO_LABEL_X + 0*LAYOUT_VFO_LABEL_PITCH_X, LAYOUT_MODE_TEXT_Y, LAYOUT_VFO_LABEL_WIDTH, LAYOUT_MODE_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND, TextJustification_e::Left);
}
else{
globalSettings.ritOn = false;
diff --git a/menu_np_ql_shared.cpp b/menu_np_ql_shared.cpp
index fc988d1..a0dd25a 100644
--- a/menu_np_ql_shared.cpp
+++ b/menu_np_ql_shared.cpp
@@ -39,8 +39,7 @@ MenuReturn_e runNpQlShared(const ButtonPress_e tuner_button,
adjustSelector(menuSelectedItemRaw,
knob,
menu_buttons,
- menu_num_buttons,
- MorsePlaybackType_e::PlayChar);
+ menu_num_buttons);
}
if(ButtonPress_e::NotPressed == *selection_mode){
diff --git a/menu_numpad.cpp b/menu_numpad.cpp
index 1fa060f..b9a1570 100644
--- a/menu_numpad.cpp
+++ b/menu_numpad.cpp
@@ -41,8 +41,7 @@ void initNumpad(void)
drawNumpad();
initSelector(&numpadMenuSelectedItemRaw,
numpadMenuButtons,
- NUMPAD_MENU_NUM_BUTTONS,
- MorsePlaybackType_e::PlayChar);
+ NUMPAD_MENU_NUM_BUTTONS);
}
MenuReturn_e runNumpad(const ButtonPress_e tuner_button,
diff --git a/menu_numpad_buttons.cpp b/menu_numpad_buttons.cpp
index c9cdabe..db9ad00 100644
--- a/menu_numpad_buttons.cpp
+++ b/menu_numpad_buttons.cpp
@@ -115,6 +115,9 @@ void updateCurrentEnteredFrequency(void)
{
formatFreq(numpadMenuFrequency,b,sizeof(b),0);
strncat_P(b,(const char*)F(" Hz"),sizeof(b)-strlen(b));
+#if GUI_THEME != 0
+ displayFillrect(LAYOUT_MODE_TEXT_X,LAYOUT_MODE_TEXT_Y,LAYOUT_MODE_TEXT_WIDTH,LAYOUT_MODE_TEXT_HEIGHT,COLOR_BACKGROUND);
+#endif
displayText(b,LAYOUT_MODE_TEXT_X,LAYOUT_MODE_TEXT_Y,LAYOUT_MODE_TEXT_WIDTH,LAYOUT_MODE_TEXT_HEIGHT,COLOR_TEXT,COLOR_BACKGROUND,COLOR_BACKGROUND,TextJustification_e::Right);
}
diff --git a/menu_quicklist.cpp b/menu_quicklist.cpp
index 63526af..2073c51 100644
--- a/menu_quicklist.cpp
+++ b/menu_quicklist.cpp
@@ -44,8 +44,7 @@ void initQuickList(void)
drawQuickList();
initSelector(&quickListMenuSelectedItemRaw,
quickListMenuButtons,
- QUICKLIST_MENU_NUM_BUTTONS,
- MorsePlaybackType_e::PlayChar);
+ QUICKLIST_MENU_NUM_BUTTONS);
}
MenuReturn_e runQuickList(const ButtonPress_e tuner_button,
diff --git a/menu_quicklist_buttons.cpp b/menu_quicklist_buttons.cpp
index 5b4fdfa..46da380 100644
--- a/menu_quicklist_buttons.cpp
+++ b/menu_quicklist_buttons.cpp
@@ -45,7 +45,7 @@ QUICKLIST_BUTTON_GENERATE(1);
QUICKLIST_BUTTON_GENERATE(2);
QUICKLIST_BUTTON_GENERATE(3);
-constexpr char txtQLCancel [] PROGMEM = "Can";
+constexpr char txtQLCancel [] PROGMEM = "Cancel";
void osQLCancel();
constexpr Button bQLCancel PROGMEM = {
LAYOUT_BUTTON_X,
diff --git a/menu_utils.cpp b/menu_utils.cpp
index d5fcf6e..baba83d 100644
--- a/menu_utils.cpp
+++ b/menu_utils.cpp
@@ -4,10 +4,14 @@
#include "button.h"
#include "color_theme.h"
-#include "morse.h"
#include "nano_gui.h"
#include "utils.h"
+#if GUI_THEME != 0
+static const unsigned int SELECT_CORNER_SIZE = 7;
+static const unsigned int SELECT_CORNER_COLOR = DISPLAY_ORANGE;
+#endif
+
bool findPressedButton(const Button* const* buttons,
const uint8_t num_buttons,
Button *const button_out,
@@ -31,37 +35,26 @@ bool findPressedButton(const Button* const* buttons,
void movePuck(const Button *const b_old,
const Button *const b_new)
{
+#if GUI_THEME == 0
if(nullptr != b_old){
displayRect(b_old->x,b_old->y,b_old->w,b_old->h,COLOR_INACTIVE_BORDER);
}
if(nullptr != b_new){
displayRect(b_new->x,b_new->y,b_new->w,b_new->h,COLOR_ACTIVE_BORDER);
}
-}
-
-void playButtonMorse(const Button *const button,
- const MorsePlaybackType_e play_type)
-{
- if(MorsePlaybackType_e::PlayText == play_type){
- morseText(button->text);
- }
- else{
- morseLetter(button->morse);
- }
-
- const ButtonStatus_e bs = button->status();
- if(ButtonStatus_e::Inactive == bs){
- morseBool(false);
+#else
+ if(nullptr != b_old){
+ displayCorner(b_old->x, b_old->y, SELECT_CORNER_SIZE, COLOR_BACKGROUND);
}
- else if(ButtonStatus_e::Active == bs){
- morseBool(true);
+ if(nullptr != b_new){
+ displayCorner(b_new->x, b_new->y, SELECT_CORNER_SIZE, SELECT_CORNER_COLOR);
}
+#endif
}
void initSelector(int16_t *const raw_select_val_in_out,
const Button* const* buttons,
- const uint8_t num_buttons,
- const MorsePlaybackType_e play_type)
+ const uint8_t num_buttons)
{
*raw_select_val_in_out = 0;
if(0 < num_buttons){
@@ -70,15 +63,13 @@ void initSelector(int16_t *const raw_select_val_in_out,
memcpy_P(&bp,&(buttons[0]),sizeof(bp));
memcpy_P(&button,bp,sizeof(button));
movePuck(nullptr,&button);
- playButtonMorse(&button,play_type);
}
}
void adjustSelector(int16_t *const raw_select_val_in_out,
const int16_t knob,
const Button* const* buttons,
- const uint8_t num_buttons,
- const MorsePlaybackType_e play_type)
+ const uint8_t num_buttons)
{
const uint8_t prev_select = (*raw_select_val_in_out)/MENU_KNOB_COUNTS_PER_ITEM;
*raw_select_val_in_out = LIMIT((*raw_select_val_in_out)+knob,0,num_buttons*MENU_KNOB_COUNTS_PER_ITEM - 1);
@@ -93,7 +84,6 @@ void adjustSelector(int16_t *const raw_select_val_in_out,
memcpy_P(&new_button,bp,sizeof(new_button));
movePuck(&prev_button,&new_button);
- playButtonMorse(&new_button,play_type);
}
}
diff --git a/menu_utils.h b/menu_utils.h
index d84be30..356dd59 100644
--- a/menu_utils.h
+++ b/menu_utils.h
@@ -9,19 +9,13 @@ bool findPressedButton(const Button* const* buttons,
Button *const button_out,
const Point touch_point);
-enum MorsePlaybackType_e : uint8_t {
- PlayChar,
- PlayText
-};
void initSelector(int16_t *const raw_select_val_in_out,
const Button* const* buttons,
- const uint8_t num_buttons,
- const MorsePlaybackType_e);
+ const uint8_t num_buttons);
void adjustSelector(int16_t *const raw_select_val_in_out,
int16_t knob,
const Button* const* buttons,
- const uint8_t num_buttons,
- const MorsePlaybackType_e);
+ const uint8_t num_buttons);
void endSelector(const Button *const button);
diff --git a/morse.cpp b/morse.cpp
deleted file mode 100644
index eb7d9e6..0000000
--- a/morse.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-#include "toneAC2/toneAC2.h"
-
-#include "encoder.h"
-#include "morse.h"
-#include "pin_definitions.h"
-#include "settings.h"
-
-struct Morse {
- char letter;
- unsigned char code;
-};
-
-/*
- * Each byte of the morse table stores one letter.
- * The 0 is a dot, a 1 is a dash
- * From the Most significant byte onwards, the letter is padded with 1s.
- * The first zero after the 1s indicates the start of the letter, it MUST be discarded
- */
-static const PROGMEM struct Morse morse_table[] = {
-{'a', 0b11111001},
-{'b', 0b11101000},
-{'c', 0b11101010},
-{'d', 0b11110100},
-{'e', 0b11111100},
-{'f', 0b11100010},
-{'g', 0b11110110},
-{'h', 0b11100000},
-{'i', 0b11111000},
-{'j', 0b11100111},
-{'k', 0b11110101},
-{'l', 0b11100100},
-{'m', 0b11111011},
-{'n', 0b11111010},
-{'o', 0b11110111},
-{'p', 0b11100110},
-{'q', 0b11101101},
-{'r', 0b11110010},
-{'s', 0b11110000},
-{'t', 0b11111101},
-{'u', 0b11110001},
-{'v', 0b11100001},
-{'w', 0b11110011},
-{'x', 0b11101001},
-{'y', 0b11101011},
-{'z', 0b11101100},
-{'1', 0b11001111},
-{'2', 0b11000111},
-{'3', 0b11000011},
-{'4', 0b11000001},
-{'5', 0b11000000},
-{'6', 0b11010000},
-{'7', 0b11011000},
-{'8', 0b11011100},
-{'9', 0b11011110},
-{'0', 0b11011111},
-{'.', 0b10010101},
-{',', 0b10110011},
-{'?', 0b10001100},
-{ 2 , 0b11010101}, // ASCII 0x02 is Start of Text -
-{ 4 , 0b10000101}, // ASCII 0x04 is End of Transmission - is too long for our encoding scheme in 8 bits, but fits
-};
-
-void morseLetter(char c, uint16_t dit_duration_ms){
- if(!globalSettings.morseMenuOn){
- return;
- }
- unsigned char mask = 0x80;
-
- //handle space character as three dashes
- if (c == ' '){
- delay(7 * dit_duration_ms);
- //Serial.print(' ');
- return;
- }
-
- for (unsigned int i = 0; i < sizeof(morse_table)/ sizeof(struct Morse); i++){
- struct Morse m;
- memcpy_P(&m, morse_table + i, sizeof(struct Morse));
-
- if (m.letter == tolower(c)){
- unsigned char code = m.code;
- //Serial.print(m.letter); Serial.println(' ');
-
- while(mask & code && mask > 1)
- mask = mask >> 1;
- //now we are at the first zero, skip and carry on
- mask = mask >> 1;
- while(mask){
- toneAC2(PIN_CW_TONE, globalSettings.cwSideToneFreq);
- if (mask & code){
- delay(3 * dit_duration_ms);
- //Serial.print('-');
- }
- else{
- delay(dit_duration_ms);
- //Serial.print('.');
- }
- //Serial.print('#');
- noToneAC2();
- delay(dit_duration_ms); // space between dots and dashes
- mask = mask >> 1;
- }
- //Serial.println('@');
- delay(2*dit_duration_ms); // space between letters is a dash (3 dots), one dot's space has already been sent
- break;//We've played the letter, so don't bother checking the rest of the list
- }
- }
-}
-
-static const uint8_t RELATIVE_OFFSET_HZ = 100;
-void morseText(const char *text, uint16_t dit_duration_ms){
- int16_t total_counts = 0;
- morseBool(false);
- enc_read();//Don't count initial tone against total_counts
- while(*text && (abs(total_counts) < 10)){
- morseLetter(*text++, dit_duration_ms);
- total_counts += enc_read();
- }
-}
-
-void morseBool(bool val){
- if(!globalSettings.morseMenuOn){
- return;
- }
- toneAC2(PIN_CW_TONE, globalSettings.cwSideToneFreq + (val ? RELATIVE_OFFSET_HZ : -RELATIVE_OFFSET_HZ));
- delay(3*globalSettings.cwDitDurationMs);
- noToneAC2();
- delay(3*globalSettings.cwDitDurationMs);
-}
diff --git a/morse.h b/morse.h
deleted file mode 100644
index b842996..0000000
--- a/morse.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "settings.h"
-//sends out morse code at the speed set by cwSpeed
-void morseLetter(char c, uint16_t dit_duration_ms = globalSettings.cwDitDurationMs);
-void morseText(const char *text, uint16_t dit_duration_ms = globalSettings.cwDitDurationMs);
-
-//Plays either a higher or lower tone to indicate a boolean value
-void morseBool(bool val);
diff --git a/nano_gui.cpp b/nano_gui.cpp
index 821d1d7..73b2515 100644
--- a/nano_gui.cpp
+++ b/nano_gui.cpp
@@ -6,6 +6,7 @@
#include "scratch_space.h"
#include "settings.h"
#include "touch.h"
+#include "config.h"
#include
#include
@@ -62,10 +63,29 @@ void displayRect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,uns
tft.fillRect(x+w-1,y,1,h,c);
}
+void displayCorner(unsigned int x, unsigned int y, unsigned int w, unsigned int c){
+ for (unsigned int i = 0; w > 0; --w) {
+ tft.drawFastHLine(x, y+i, w, c);
+ ++i;
+ }
+}
+
+void displayRoundrect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int r,unsigned int c){
+ tft.drawRoundRect(x, y, w, h, r, c);
+}
+
void displayFillrect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c){
tft.fillRect(x,y,w,h,c);
}
+void displayFillroundrect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int r,unsigned int c){
+ tft.fillRoundRect(x,y,w,h,r,c);
+}
+
+void displayFillcircle(unsigned int x, unsigned int y, unsigned int r, unsigned int c){
+ tft.fillCircle(x, y, r, c);
+}
+
void displayChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg) {
tft.drawCharGFX(x,y,c,color,bg,1);
}
@@ -77,11 +97,8 @@ void displayRawText(const char *text, int x1, int y1, int w, int color, int back
tft.print(text);
}
-void displayText(const char *const text, int x1, int y1, int w, int h, int color, int background, int border, TextJustification_e justification)
+void displayAlignedText(const char *const text, int x1, int y1, int w, int h, int color, int background, TextJustification_e justification)
{
- displayFillrect(x1, y1, w ,h, background);
- displayRect(x1, y1, w ,h, border);
-
int16_t x1_out;
int16_t y1_out;
uint16_t width_out;
@@ -100,6 +117,30 @@ void displayText(const char *const text, int x1, int y1, int w, int h, int color
displayRawText(text,x1,y1,w,color,background);
}
+void displayText(const char *const text, int x1, int y1, int w, int h, int color, int background, int border, TextJustification_e justification)
+{
+#if GUI_THEME == 0
+ displayFillrect(x1, y1, w ,h, background);
+ displayRect(x1, y1, w ,h, border);
+#else
+ if (background != border) {
+ displayRect(x1, y1, w ,h, border);
+ }
+#endif
+ displayAlignedText(text, x1, y1, w, h, color, background, justification);
+}
+
+void displayButtonText(const char *const text, int x1, int y1, int w, int h, int color, int background, int border, TextJustification_e justification)
+{
+#if GUI_THEME == 0
+ displayFillrect(x1, y1, w ,h, background);
+ displayRect(x1, y1, w ,h, border);
+#else
+ displayFillroundrect(x1, y1, w ,h, h/2, background);
+#endif
+ displayAlignedText(text, x1, y1, w, h, color, background, justification);
+}
+
void drawCross(int16_t x_center,int16_t y_center,uint16_t color)
{
constexpr uint8_t HALF_SIZE = 10;
diff --git a/nano_gui.h b/nano_gui.h
index c8681ad..5cf7851 100644
--- a/nano_gui.h
+++ b/nano_gui.h
@@ -13,13 +13,22 @@ void displayClear(unsigned int color);
void displayPixel(unsigned int x, unsigned int y, unsigned int c);
void displayHline(unsigned int x, unsigned int y, unsigned int l, unsigned int c);
void displayVline(unsigned int x, unsigned int y, unsigned int l, unsigned int c);
+void displayCorner(unsigned int x, unsigned int y, unsigned int w, unsigned int c);
void displayRect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c);
+void displayRoundrect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int r,unsigned int c);
void displayFillrect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c);
+void displayFillroundrect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int r,unsigned int c);
+void displayFillcircle(unsigned int x, unsigned int y, unsigned int r, unsigned int c);
void displayChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg);
-void displayText(const char *const text, int x1, int y1, int w, int h, int color, int background, int border, TextJustification_e justification = TextJustification_e::Center);
+void displayText(const char *const text, int x1, int y1, int w, int h,
+ int color, int background, int border, TextJustification_e justification = TextJustification_e::Center);
+void displayButtonText(const char *const text, int x1, int y1, int w, int h,
+ int color, int background, int border, TextJustification_e justification = TextJustification_e::Center);
/* these functions are called universally to update the display */
void drawTx();
+void drawWpM();
+void drawTuningStepSize();
#define TEXT_LINE_HEIGHT 18
#define TEXT_LINE_INDENT 5
diff --git a/settings.cpp b/settings.cpp
index 7abad2e..3977e31 100644
--- a/settings.cpp
+++ b/settings.cpp
@@ -5,9 +5,10 @@
#include "nano_gui.h"//redrawVFOs() function
#include "settings.h"
#include "si5351.h"
+#include "config.h"
/**
- * These are the "magic" indices where these user changable settinngs are stored in the EEPROM
+ * These are the "magic" indices where these user changeable settings are stored in the EEPROM
*/
static const uint16_t EEPROM_ADDR_MASTER_CAL = 0;//int32_t
//4 is currently unused, but may have been LSB_CAL on other versions
@@ -65,6 +66,15 @@ void LoadDefaultSettings()
globalSettings.vfoA.mode = VFO_MODE_LSB;
globalSettings.vfoB.frequency = 14150000UL;
globalSettings.vfoB.mode = VFO_MODE_USB;
+#if DEFAULT_TUNING_STEP_SIZE == 0
+ globalSettings.tuningStepSize = 10;
+#elif DEFAULT_TUNING_STEP_SIZE == 1
+ globalSettings.tuningStepSize = 20;
+#elif DEFAULT_TUNING_STEP_SIZE == 2
+ globalSettings.tuningStepSize = 50;
+#else
+ globalSettings.tuningStepSize = 100;
+#endif
for(uint8_t i = 0; i < NUM_QUICKLIST_SETTINGS; ++i){
globalSettings.quickList[i].frequency = i*1000000;
@@ -83,15 +93,17 @@ void LoadDefaultSettings()
globalSettings.ritOn = false;
globalSettings.ritFrequency = globalSettings.vfoA.frequency;
-
+#if CW_IS_DEFAULT == 0
globalSettings.tuningMode = TuningMode_e::TUNE_SSB;
-
+#else
+ globalSettings.tuningMode = TuningMode_e::TUNE_CW;
+#endif
globalSettings.splitOn = false;
globalSettings.txActive = false;
globalSettings.txCatActive = false;
globalSettings.cwExpirationTimeMs = 0;
- globalSettings.morseMenuOn = false;
+ globalSettings.morsePracticeMode = false;
}
void LoadSettingsFromEeprom()
@@ -100,7 +112,7 @@ void LoadSettingsFromEeprom()
LoadSane(globalSettings.vfoA.frequency,EEPROM_ADDR_VFO_A_FREQ,SI5351_MIN_FREQUENCY_HZ,SI5351_MAX_FREQUENCY_HZ);
LoadSane(globalSettings.vfoB.frequency,EEPROM_ADDR_VFO_B_FREQ,SI5351_MIN_FREQUENCY_HZ,SI5351_MAX_FREQUENCY_HZ);
LoadSane(globalSettings.cwSideToneFreq,EEPROM_ADDR_CW_SIDETONE,100UL,2000UL);
- LoadSane(globalSettings.cwDitDurationMs,EEPROM_ADDR_CW_DIT_TIME,10U,1000U);
+ LoadSane(globalSettings.cwDitDurationMs,EEPROM_ADDR_CW_DIT_TIME,20U,300U);
if(LoadSane(globalSettings.cwActiveTimeoutMs,EEPROM_ADDR_CW_DELAYTIME,10U,100U)){
globalSettings.cwActiveTimeoutMs *= 10;//scale by 10 for legacy reasons
}
@@ -109,8 +121,7 @@ void LoadSettingsFromEeprom()
LoadSane(globalSettings.keyerMode,EEPROM_ADDR_CW_KEY_TYPE,KEYER_STRAIGHT,KEYER_IAMBIC_B);
uint8_t morse_on = 0;
- LoadSane(morse_on,EEPROM_ADDR_MORSE_MENU,(uint8_t)0,(uint8_t)1);
- globalSettings.morseMenuOn = morse_on;
+ globalSettings.morsePracticeMode = morse_on;
for(uint8_t i = 0; i < NUM_QUICKLIST_SETTINGS; ++i){
LoadSane(globalSettings.quickList[i].frequency,EEPROM_ADDR_QUICKLIST_FREQ+(sizeof(uint32_t)*i),SI5351_MIN_FREQUENCY_HZ,SI5351_MAX_FREQUENCY_HZ);
@@ -142,7 +153,6 @@ void SaveSettingsToEeprom()
EEPROM.put(EEPROM_ADDR_VFO_A_MODE,globalSettings.vfoA.mode);
EEPROM.put(EEPROM_ADDR_VFO_B_MODE,globalSettings.vfoB.mode);
EEPROM.put(EEPROM_ADDR_CW_KEY_TYPE,globalSettings.keyerMode);
- EEPROM.put(EEPROM_ADDR_MORSE_MENU,(uint8_t)globalSettings.morseMenuOn);
for(uint8_t i = 0; i < NUM_QUICKLIST_SETTINGS; ++i){
EEPROM.put(EEPROM_ADDR_QUICKLIST_FREQ+(sizeof(uint32_t)*i),globalSettings.quickList[i].frequency);
diff --git a/settings.h b/settings.h
index 19d4e28..22e9eed 100644
--- a/settings.h
+++ b/settings.h
@@ -1,6 +1,6 @@
/*
* This class deals with all of the radio settings,
- * so that other areas of the code doesn't have to
+ * so that other areas of the code don't have to
*
* Example usage:
* LoadSettingsFromEeprom();
@@ -80,6 +80,7 @@ struct SettingsRam
Vfo_e activeVfo;
VfoSettings_t vfoA;
VfoSettings_t vfoB;
+ int16_t tuningStepSize;
VfoSettings_t quickList[4];
@@ -103,7 +104,7 @@ struct SettingsRam
bool txActive;
bool txCatActive;
uint32_t cwExpirationTimeMs;
- bool morseMenuOn;
+ bool morsePracticeMode;
};
//This is the shared declaration
diff --git a/setup.cpp b/setup.cpp
index 64691f9..c558245 100644
--- a/setup.cpp
+++ b/setup.cpp
@@ -1,8 +1,8 @@
#include "toneAC2/toneAC2.h"
+#include //F()
#include "colors.h"
#include "encoder.h"
#include "menu.h"
-#include "morse.h"
#include "nano_gui.h"
#include "pin_definitions.h"
#include "scratch_space.h"
@@ -11,6 +11,7 @@
#include "si5351.h"
#include "tuner.h"
#include "utils.h"
+#include "config.h"
/** Menus
* The Radio menus are accessed by tapping on the function button.
@@ -18,19 +19,31 @@
* a function button press.
* - As the encoder is rotated, at every 10th pulse, the next or the previous menu
* item is displayed. Each menu item is controlled by it's own function.
- * - Eache menu function may be called to display itself
+ * - Each menu function may be called to display itself
* - Each of these menu routines is called with a button parameter.
* - The btn flag denotes if the menu itme was clicked on or not.
* - If the menu item is clicked on, then it is selected,
* - If the menu item is NOT clicked on, then the menu's prompt is to be displayed
*/
+#if GUI_THEME == 0
static const unsigned int COLOR_TEXT = DISPLAY_WHITE;
static const unsigned int COLOR_BACKGROUND = DISPLAY_BLACK;
static const unsigned int COLOR_TITLE_BACKGROUND = DISPLAY_NAVY;
static const unsigned int COLOR_SETTING_BACKGROUND = DISPLAY_NAVY;
static const unsigned int COLOR_ACTIVE_BORDER = DISPLAY_WHITE;
static const unsigned int COLOR_INACTIVE_BORDER = COLOR_BACKGROUND;
+#else
+static const unsigned int COLOR_TEXT = DISPLAY_GREEN;
+static const unsigned int COLOR_BACKGROUND = DISPLAY_BLACK;
+static const unsigned int COLOR_TITLE_BACKGROUND = DISPLAY_BLACK;
+static const unsigned int COLOR_SETTING_BACKGROUND = DISPLAY_BLACK;
+static const unsigned int COLOR_ACTIVE_BORDER = DISPLAY_ORANGE;
+static const unsigned int COLOR_INACTIVE_BORDER = COLOR_BACKGROUND;
+
+static const unsigned int LAYOUT_ITEM_PADDING = 20;
+static const unsigned int LAYOUT_PIXEL_PER_CHAR = 10;
+#endif
static const unsigned int LAYOUT_TITLE_X = 12;
static const unsigned int LAYOUT_TITLE_Y = 12;
@@ -43,14 +56,22 @@ static const unsigned int LAYOUT_ITEM_WIDTH = 260;
static const unsigned int LAYOUT_ITEM_HEIGHT = 30;
static const unsigned int LAYOUT_ITEM_PITCH_Y = LAYOUT_ITEM_HEIGHT + 1;
-static const unsigned int LAYOUT_SETTING_REF_VALUE_X = LAYOUT_ITEM_X;
static const unsigned int LAYOUT_SETTING_REF_VALUE_Y = LAYOUT_ITEM_Y + 3*LAYOUT_ITEM_PITCH_Y;
+#if GUI_THEME == 0
+static const unsigned int LAYOUT_SETTING_REF_VALUE_X = LAYOUT_ITEM_X;
static const unsigned int LAYOUT_SETTING_REF_VALUE_WIDTH = LAYOUT_ITEM_WIDTH;
+#else
+static const unsigned int LAYOUT_SETTING_REF_VALUE_WIDTH = 140;
+#endif
static const unsigned int LAYOUT_SETTING_REF_VALUE_HEIGHT = LAYOUT_ITEM_HEIGHT;
-static const unsigned int LAYOUT_SETTING_VALUE_X = LAYOUT_ITEM_X;
static const unsigned int LAYOUT_SETTING_VALUE_Y = LAYOUT_ITEM_Y + 4*LAYOUT_ITEM_PITCH_Y;
+#if GUI_THEME == 0
+static const unsigned int LAYOUT_SETTING_VALUE_X = LAYOUT_ITEM_X;
static const unsigned int LAYOUT_SETTING_VALUE_WIDTH = LAYOUT_ITEM_WIDTH;
+#else
+static const unsigned int LAYOUT_SETTING_VALUE_WIDTH = 140;
+#endif
static const unsigned int LAYOUT_SETTING_VALUE_HEIGHT = LAYOUT_ITEM_HEIGHT;
static const unsigned int LAYOUT_INSTRUCTIONS_TEXT_X = 20;
@@ -63,6 +84,21 @@ static const unsigned int LAYOUT_CONFIRM_TEXT_Y = LAYOUT_ITEM_Y + 5*LAYOUT_ITEM_
static const unsigned int LAYOUT_CONFIRM_TEXT_WIDTH = LAYOUT_ITEM_WIDTH;
static const unsigned int LAYOUT_CONFIRM_TEXT_HEIGHT = LAYOUT_ITEM_HEIGHT;
+// For display of WpM in "mode" area
+static const unsigned int LAYOUT_VFO_LABEL_Y = 10;
+static const unsigned int LAYOUT_VFO_LABEL_HEIGHT = 36;
+static const unsigned int LAYOUT_TX_X = 260;
+static const unsigned int LAYOUT_MODE_TEXT_X = 160;
+static const unsigned int LAYOUT_MODE_TEXT_Y = LAYOUT_VFO_LABEL_Y + LAYOUT_VFO_LABEL_HEIGHT + 1;
+static const unsigned int LAYOUT_MODE_TEXT_WIDTH = LAYOUT_TX_X - 1 - LAYOUT_MODE_TEXT_X;
+static const unsigned int LAYOUT_MODE_TEXT_HEIGHT = 36;
+
+// For the display of the tuning step size
+static const unsigned int LAYOUT_TUNING_STEP_SIZE_WIDTH = 20;
+static const unsigned LAYOUT_TUNING_STEP_DISTANCE = 10;
+static const unsigned LAYOUT_TUNING_STEP_RADIUS = 3;
+
+
constexpr char strYes [] PROGMEM = "Yes";
constexpr char strNo [] PROGMEM = "No";
constexpr char strHz [] PROGMEM = "Hz";
@@ -71,7 +107,11 @@ void displayDialog(const char* title,
const char* instructions){
displayClear(COLOR_BACKGROUND);
strncpy_P(b,title,sizeof(b));
+#if GUI_THEME == 0
displayText(b, LAYOUT_TITLE_X, LAYOUT_TITLE_Y, LAYOUT_TITLE_WIDTH, LAYOUT_TITLE_HEIGHT, COLOR_TEXT, COLOR_TITLE_BACKGROUND, COLOR_ACTIVE_BORDER);
+#else
+ displayButtonText(b, LAYOUT_TITLE_X, LAYOUT_TITLE_Y, LAYOUT_TITLE_WIDTH, LAYOUT_TITLE_HEIGHT, COLOR_TITLE_BACKGROUND, COLOR_TEXT, COLOR_TEXT);
+#endif
strncpy_P(b,instructions,sizeof(b));
displayText(b, LAYOUT_INSTRUCTIONS_TEXT_X, LAYOUT_INSTRUCTIONS_TEXT_Y, LAYOUT_INSTRUCTIONS_TEXT_WIDTH, LAYOUT_INSTRUCTIONS_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND, TextJustification_e::Left);
strncpy_P(b,(const char*)F("Push Tune to Save"),sizeof(b));
@@ -123,8 +163,15 @@ void initSetting()
drawSetting(&screen);
screen.Initialize(&setupMenuLastValue);
screen.OnValueChange(setupMenuLastValue,b,sizeof(b));
+#if GUI_THEME == 0
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_TITLE_BACKGROUND, COLOR_BACKGROUND);
displayText(b, LAYOUT_SETTING_REF_VALUE_X, LAYOUT_SETTING_REF_VALUE_Y, LAYOUT_SETTING_REF_VALUE_WIDTH, LAYOUT_SETTING_REF_VALUE_HEIGHT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND, COLOR_BACKGROUND);
+#else
+ displayFillrect(160 - LAYOUT_SETTING_VALUE_WIDTH/2, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_BACKGROUND);
+ displayButtonText(b, 160 - LAYOUT_SETTING_VALUE_WIDTH/2, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_BACKGROUND, COLOR_ACTIVE_BORDER, COLOR_ACTIVE_BORDER);
+ displayFillrect(160 - LAYOUT_SETTING_VALUE_WIDTH/2, LAYOUT_SETTING_REF_VALUE_Y, LAYOUT_SETTING_REF_VALUE_WIDTH, LAYOUT_SETTING_REF_VALUE_HEIGHT, COLOR_BACKGROUND);
+ displayText(b, 160 - LAYOUT_SETTING_VALUE_WIDTH/2, LAYOUT_SETTING_REF_VALUE_Y, LAYOUT_SETTING_REF_VALUE_WIDTH, LAYOUT_SETTING_REF_VALUE_HEIGHT, DISPLAY_DARKGREY, COLOR_BACKGROUND, COLOR_BACKGROUND);
+#endif
setupMenuRawValue = setupMenuLastValue * (int32_t)screen.KnobDivider;
}
@@ -161,7 +208,12 @@ MenuReturn_e runSetting(const ButtonPress_e tuner_button,
if(value != setupMenuLastValue){
screen.OnValueChange(value,b,sizeof(b));
+#if GUI_THEME == 0
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_TITLE_BACKGROUND, COLOR_BACKGROUND);
+#else
+ displayFillrect(160 - LAYOUT_SETTING_VALUE_WIDTH/2, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_BACKGROUND);
+ displayButtonText(b, 160 - LAYOUT_SETTING_VALUE_WIDTH/2, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_BACKGROUND, COLOR_ACTIVE_BORDER, COLOR_ACTIVE_BORDER);
+#endif
setupMenuLastValue = value;
}
}
@@ -175,6 +227,7 @@ void activateSetting(const SettingScreen_t *const new_setting_P)
enterSubmenu(&setupMenuActiveSettingMenu);
}
+#if GUI_THEME == 0
//Local Oscillator
void ssLocalOscInitialize(long int* start_value_out){
{
@@ -258,6 +311,7 @@ const SettingScreen_t ssBfo PROGMEM = {
ssBfoFinalize
};
void runBfoSetting(){activateSetting(&ssBfo);}
+#endif // of: #if GUI_THEME == 0
//CW Tone
void ssCwToneInitialize(long int* start_value_out)
@@ -282,7 +336,7 @@ void ssCwToneFinalize(const long int final_value)
SaveSettingsToEeprom();
}
const char SS_CW_TONE_T [] PROGMEM = "Tone";
-const char SS_CW_TONE_A [] PROGMEM = "Select a frequency that\nCW mode to tune for";
+const char SS_CW_TONE_A [] PROGMEM = "Select a tone frequency\nfor CW mode";
const SettingScreen_t ssTone PROGMEM = {
SS_CW_TONE_T,
SS_CW_TONE_A,
@@ -308,7 +362,6 @@ void ssCwSwitchDelayChange(const long int new_value, char* buff_out, const size_
{
ltoa(new_value,buff_out,10);
strncat_P(buff_out,(const char*)F("ms"),buff_out_size - strlen(buff_out));
- morseText(buff_out);
enc_read();//Consume any rotations during morse playback
}
void ssCwSwitchDelayFinalize(const long int final_value)
@@ -341,20 +394,15 @@ void ssKeyerValidate(const long int candidate_value_in, long int* validated_valu
}
void ssKeyerChange(const long int new_value, char* buff_out, const size_t buff_out_size)
{
- char m;
if(KeyerMode_e::KEYER_STRAIGHT == new_value){
strncpy_P(buff_out,(const char*)F("Hand Key"),buff_out_size);
- m = 'S';
}
else if(KeyerMode_e::KEYER_IAMBIC_A == new_value){
strncpy_P(buff_out,(const char*)F("Iambic A"),buff_out_size);
- m = 'A';
}
else{
strncpy_P(buff_out,(const char*)F("Iambic B"),buff_out_size);
- m = 'B';
}
- morseLetter(m);
enc_read();//Consume any rotations during morse playback
}
void ssKeyerFinalize(const long int final_value)
@@ -376,10 +424,10 @@ const SettingScreen_t ssKeyer PROGMEM = {
};
void runKeyerSetting(){activateSetting(&ssKeyer);}
-//Morse menu playback
+//Morse practice mode menu
void ssMorseMenuInitialize(long int* start_value_out)
{
- *start_value_out = globalSettings.morseMenuOn;
+ *start_value_out = globalSettings.morsePracticeMode;
}
void ssMorseMenuValidate(const long int candidate_value_in, long int* validated_value_out)
{
@@ -396,16 +444,14 @@ void ssMorseMenuChange(const long int new_value, char* buff_out, const size_t bu
strncpy_P(buff_out,strNo,buff_out_size);
m = 'N';
}
- morseLetter(m);
enc_read();//Consume any rotations during morse playback
}
void ssMorseMenuFinalize(const long int final_value)
{
- globalSettings.morseMenuOn = final_value;
- SaveSettingsToEeprom();
+ globalSettings.morsePracticeMode = final_value;
}
-const char SS_MORSE_MENU_T [] PROGMEM = "Menu Audio";
-const char SS_MORSE_MENU_A [] PROGMEM = "Menu selections will play\nmorse code";
+const char SS_MORSE_MENU_T [] PROGMEM = "Morse practice";
+const char SS_MORSE_MENU_A [] PROGMEM = "Mute the TX line\nwhile keying";
const SettingScreen_t ssMorseMenu PROGMEM = {
SS_MORSE_MENU_T,
SS_MORSE_MENU_A,
@@ -421,25 +467,36 @@ void runMorseMenuSetting(){activateSetting(&ssMorseMenu);}
//CW Speed
void ssCwSpeedInitialize(long int* start_value_out)
{
+ // Convert dot length in ms to wpm
*start_value_out = 1200L/globalSettings.cwDitDurationMs;
}
void ssCwSpeedValidate(const long int candidate_value_in, long int* validated_value_out)
{
- *validated_value_out = LIMIT(candidate_value_in,1,100);
+ *validated_value_out = LIMIT(candidate_value_in,20,300); // 4 - 60 wpm
}
void ssCwSpeedChange(const long int new_value, char* buff_out, const size_t /*buff_out_size*/)
{
+#if DISPLAY_CW_SPEED == 0
ltoa(new_value, buff_out, 10);
- morseText(buff_out,1200L/new_value);
+#else
+ ltoa(new_value * 5, buff_out, 10);
+#endif
enc_read();//Consume any rotations during morse playback
}
void ssCwSpeedFinalize(const long int final_value)
{
+ // Convert wpm back to a dot length in ms
globalSettings.cwDitDurationMs = 1200L/final_value;
SaveSettingsToEeprom();
}
-const char SS_CW_SPEED_T [] PROGMEM = "Play Speed";
-const char SS_CW_SPEED_A [] PROGMEM = "Speed to play CW characters";
+const char SS_CW_SPEED_T [] PROGMEM = "CW Speed";
+#if DISPLAY_CW_SPEED == 2
+const char SS_CW_SPEED_A [] PROGMEM = "Keyer speed in BpM";
+#elif DISPLAY_CW_SPEED == 1
+const char SS_CW_SPEED_A [] PROGMEM = "Keyer speed in cpm";
+#else
+const char SS_CW_SPEED_A [] PROGMEM = "Keyer speed in wpm";
+#endif
const SettingScreen_t ssCwSpeed PROGMEM = {
SS_CW_SPEED_T,
SS_CW_SPEED_A,
@@ -472,7 +529,6 @@ void ssResetAllChange(const long int new_value, char* buff_out, const size_t buf
strncpy_P(buff_out,strNo,buff_out_size);
m = 'N';
}
- morseLetter(m);
enc_read();//Consume any rotations during morse playback
}
void ssResetAllFinalize(const long int final_value)
@@ -504,6 +560,7 @@ struct MenuItem_t {
void initSetupMenu(const MenuItem_t* const menu_items,
const uint16_t num_items);
+
MenuReturn_e runSetupMenu(const MenuItem_t* const menu_items,
const uint16_t num_items,
const ButtonPress_e tuner_button,
@@ -539,6 +596,7 @@ MenuReturn_e runSetupMenu(const MenuItem_t* const menu_items,
enterSubmenu(&setupMenu##menu_name);\
}\
+#if GUI_THEME == 0
const char MI_TOUCH [] PROGMEM = "Touch Screen";
void setupTouchSetting();
@@ -555,7 +613,7 @@ void setupTouchSetting(){
setupTouch();
initSetupMenuCalibration();
}
-
+#endif // of: #if GUI_THEME == 0
const char MT_CW [] PROGMEM = "CW Setup";
const MenuItem_t menuItemsCw [] PROGMEM {
{MT_CW,nullptr},//Title
@@ -570,7 +628,9 @@ GENERATE_MENU_T(Cw);
const char MT_SETTINGS [] PROGMEM = "Settings";
const MenuItem_t menuItemsSetupRoot [] PROGMEM {
{MT_SETTINGS,nullptr},//Title
+#if GUI_THEME == 0
{MT_CAL,runCalibrationMenu},
+#endif
{MT_CW,runCwMenu},
{SS_RESET_ALL_T,runResetAllSetting},
};
@@ -586,6 +646,7 @@ void drawMenu(const MenuItem_t* const items, const uint16_t num_items)
MenuItem_t mi = {"",nullptr};
memcpy_P(&mi,&items[0],sizeof(mi));
strncpy_P(b,mi.ItemName,sizeof(b));
+#if GUI_THEME == 0
displayText(b, LAYOUT_TITLE_X, LAYOUT_TITLE_Y, LAYOUT_TITLE_WIDTH, LAYOUT_TITLE_HEIGHT, COLOR_TEXT, COLOR_TITLE_BACKGROUND, COLOR_ACTIVE_BORDER);
for(unsigned int i = 1; i < num_items; ++i){
memcpy_P(&mi,&items[i],sizeof(mi));
@@ -595,25 +656,74 @@ void drawMenu(const MenuItem_t* const items, const uint16_t num_items)
memcpy_P(&mi,&exitMenu,sizeof(mi));
strncpy_P(b,mi.ItemName,sizeof(b));
displayText(b, LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (num_items-1)*LAYOUT_ITEM_PITCH_Y, LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_INACTIVE_BORDER, TextJustification_e::Left);
+#else
+ uint16_t width_out = LAYOUT_PIXEL_PER_CHAR * strlen(b);
+ // Display title centered with some padding
+ displayButtonText(b, 160 - width_out/2 - LAYOUT_ITEM_PADDING, LAYOUT_TITLE_Y,
+ width_out + 2*LAYOUT_ITEM_PADDING, LAYOUT_TITLE_HEIGHT, COLOR_TITLE_BACKGROUND, COLOR_TEXT, COLOR_INACTIVE_BORDER);
+
+ for(unsigned int i = 1; i < num_items; ++i){
+ memcpy_P(&mi,&items[i],sizeof(mi));
+ strncpy_P(b,mi.ItemName,sizeof(b));
+ width_out = LAYOUT_PIXEL_PER_CHAR * strlen(b);
+ // Display menu item centered with some padding
+ displayText(b, 160 - width_out/2 - LAYOUT_ITEM_PADDING, LAYOUT_ITEM_Y + (i-1)*LAYOUT_ITEM_PITCH_Y,
+ width_out + 2*LAYOUT_ITEM_PADDING, LAYOUT_ITEM_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_INACTIVE_BORDER);
+ }
+
+ memcpy_P(&mi,&exitMenu,sizeof(mi));
+ strncpy_P(b,mi.ItemName,sizeof(b));
+ width_out = LAYOUT_PIXEL_PER_CHAR * strlen(b);
+ // Display exit button centered with some padding
+ displayText(b, 160 - width_out/2 - LAYOUT_ITEM_PADDING, LAYOUT_ITEM_Y + (num_items-1)*LAYOUT_ITEM_PITCH_Y,
+ width_out + 2*LAYOUT_ITEM_PADDING, LAYOUT_ITEM_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_INACTIVE_BORDER);
+#endif // of: #if GUI_THEME == 0
}
+#if GUI_THEME == 0
void movePuck(unsigned int old_index,
unsigned int new_index)
{
+#else
+void movePuck(unsigned int old_index,
+ unsigned int new_index,
+ const MenuItem_t* const menu_items)
+{
+ MenuItem_t mi = {"",nullptr};
+ uint16_t width_out = 0;
+#endif
//Don't update if we're already on the right selection
if(old_index == new_index){
return;
}
else if(((unsigned int)-1) != old_index){
//Clear old
- displayRect(LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (old_index*LAYOUT_ITEM_PITCH_Y), LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_INACTIVE_BORDER);
+#if GUI_THEME == 0
+ displayRect(LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (old_index*LAYOUT_ITEM_PITCH_Y),
+ LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_INACTIVE_BORDER);
+#else
+ memcpy_P(&mi,&menu_items[old_index+1],sizeof(mi));
+ strncpy_P(b,mi.ItemName,sizeof(b));
+ width_out = LAYOUT_PIXEL_PER_CHAR * strlen(b);
+ displayRoundrect(160 - width_out/2 - LAYOUT_ITEM_PADDING, LAYOUT_ITEM_Y + (old_index*LAYOUT_ITEM_PITCH_Y),
+ width_out + 2*LAYOUT_ITEM_PADDING, LAYOUT_ITEM_HEIGHT, LAYOUT_ITEM_HEIGHT/2, COLOR_INACTIVE_BORDER);
+#endif
}
//Draw new
- displayRect(LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (new_index*LAYOUT_ITEM_PITCH_Y), LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_ACTIVE_BORDER);
+#if GUI_THEME == 0
+ displayRect(LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (new_index*LAYOUT_ITEM_PITCH_Y),
+ LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_ACTIVE_BORDER);
+#else
+ memcpy_P(&mi,&menu_items[new_index+1],sizeof(mi));
+ strncpy_P(b,mi.ItemName,sizeof(b));
+ width_out = LAYOUT_PIXEL_PER_CHAR * strlen(b);
+ displayRoundrect(160 - width_out/2 - LAYOUT_ITEM_PADDING, LAYOUT_ITEM_Y + (new_index*LAYOUT_ITEM_PITCH_Y),
+ width_out + 2*LAYOUT_ITEM_PADDING, LAYOUT_ITEM_HEIGHT, LAYOUT_ITEM_HEIGHT/2, COLOR_TEXT);
+#endif
}
int16_t setupMenuSelector = 0;
-
+#if GUI_THEME == 0
void initSetupMenu(const MenuItem_t* const menu_items,
const uint16_t num_items)
{
@@ -621,6 +731,15 @@ void initSetupMenu(const MenuItem_t* const menu_items,
setupMenuSelector = 0;
movePuck(-1,0);//Force draw of puck
}
+#else
+void initSetupMenu(const MenuItem_t* menu_items,
+ const uint16_t num_items)
+{
+ drawMenu(menu_items,num_items);
+ setupMenuSelector = 0;
+ movePuck(-1,0, menu_items);//Force draw of puck
+}
+#endif
MenuReturn_e runSetupMenu(const MenuItem_t* const menu_items,
const uint16_t num_items,
@@ -649,20 +768,60 @@ MenuReturn_e runSetupMenu(const MenuItem_t* const menu_items,
setupMenuSelector = LIMIT(setupMenuSelector + knob,0,(int16_t)(num_items*MENU_KNOB_COUNTS_PER_ITEM - 1));
const int16_t new_index = setupMenuSelector/MENU_KNOB_COUNTS_PER_ITEM;
if(cur_index != new_index){
+#if GUI_THEME == 0
movePuck(cur_index,new_index);
- if(globalSettings.morseMenuOn){//Only spend cycles copying menu item into RAM if we actually need to
- if(exit_index <= cur_index){
- strncpy_P(b,MI_EXIT,sizeof(b));
- }
- else{
- MenuItem_t mi = {"",nullptr};
- memcpy_P(&mi,&menu_items[cur_index+1],sizeof(mi));//The 0th element in the array is the title, so offset by 1
- strncpy_P(b,mi.ItemName,sizeof(b));
- }
- morseText(b);
- }
+#else
+ movePuck(cur_index,new_index, menu_items);
+#endif
}
}
return MenuReturn_e::StillActive;
}
+
+void drawWpM()
+{
+#if DISPLAY_CW_SPEED == 0
+ uint16_t value = 1200L/globalSettings.cwDitDurationMs;
+#else
+ uint16_t value = (1200L * 5)/globalSettings.cwDitDurationMs;
+#endif
+ if (globalSettings.morsePracticeMode) {
+ b[0] = 0;
+ strncat_P(b,(const char*)F("("),1);
+ ltoa(value, b+1, 10);
+ strncat_P(b,(const char*)F(") "),2);
+ } else {
+ ltoa(value, b, 10);
+ }
+ // Append unit
+#if DISPLAY_CW_SPEED == 2
+ strncat_P(b,(const char*)F("BpM"),3);
+#elif DISPLAY_CW_SPEED == 1
+ strncat_P(b,(const char*)F("cpm"),3);
+#else
+ strncat_P(b,(const char*)F("wpm"),3);
+#endif
+ displayFillrect(LAYOUT_MODE_TEXT_X,LAYOUT_MODE_TEXT_Y,LAYOUT_MODE_TEXT_WIDTH,LAYOUT_MODE_TEXT_HEIGHT, COLOR_TITLE_BACKGROUND);
+ displayText(b,LAYOUT_MODE_TEXT_X, LAYOUT_MODE_TEXT_Y, LAYOUT_MODE_TEXT_WIDTH, LAYOUT_MODE_TEXT_HEIGHT,COLOR_TEXT, COLOR_TITLE_BACKGROUND, COLOR_TITLE_BACKGROUND, TextJustification_e::Left);
+}
+
+void drawTuningStepSize()
+{
+ displayFillrect(LAYOUT_MODE_TEXT_X - LAYOUT_TUNING_STEP_SIZE_WIDTH/2,0,LAYOUT_TUNING_STEP_SIZE_WIDTH,LAYOUT_VFO_LABEL_Y + LAYOUT_VFO_LABEL_HEIGHT, COLOR_TITLE_BACKGROUND);
+ // Always draw first dot
+ displayFillcircle(LAYOUT_MODE_TEXT_X, 1 * LAYOUT_TUNING_STEP_DISTANCE, LAYOUT_TUNING_STEP_RADIUS, COLOR_TEXT);
+
+ if (globalSettings.tuningStepSize > 10) {
+ // Draw second dot
+ displayFillcircle(LAYOUT_MODE_TEXT_X, 2 * LAYOUT_TUNING_STEP_DISTANCE, LAYOUT_TUNING_STEP_RADIUS, COLOR_TEXT);
+ }
+ if (globalSettings.tuningStepSize > 20) {
+ // Draw third dot
+ displayFillcircle(LAYOUT_MODE_TEXT_X, 3 * LAYOUT_TUNING_STEP_DISTANCE, LAYOUT_TUNING_STEP_RADIUS, COLOR_TEXT);
+ }
+ if (globalSettings.tuningStepSize > 50) {
+ // Draw fourth dot
+ displayFillcircle(LAYOUT_MODE_TEXT_X, 4 * LAYOUT_TUNING_STEP_DISTANCE, LAYOUT_TUNING_STEP_RADIUS, COLOR_TEXT);
+ }
+}
diff --git a/setup.h b/setup.h
index 16e6c07..142a1d0 100644
--- a/setup.h
+++ b/setup.h
@@ -1,9 +1,13 @@
#pragma once
#include "menu.h"
+#include "config.h"
extern Menu_t* const setupMenu;
+#if GUI_THEME == 0
void setupTouch();
void runLocalOscSetting();
-void runBfoSetting();
\ No newline at end of file
+void runBfoSetting();
+#endif
+void runCwSpeedSetting();
\ No newline at end of file
diff --git a/tuner.cpp b/tuner.cpp
index 9e99ea6..4525a13 100644
--- a/tuner.cpp
+++ b/tuner.cpp
@@ -2,6 +2,7 @@
#include
+#include "bands.h"
#include "nano_gui.h"
#include "pin_definitions.h"
#include "si5351.h"
@@ -15,7 +16,7 @@ void saveVFOs()
void switchVFO(Vfo_e new_vfo){
- ritDisable();//If we are in RIT mode, we need to disable it before setting the active VFO so that the correct VFO gets it's frequency restored
+ ritDisable();//If we are in RIT mode, we need to disable it before setting the active VFO so that the correct VFO gets its frequency restored
globalSettings.activeVfo = new_vfo;
setFrequency(GetActiveVfoFreq());
@@ -125,54 +126,63 @@ void setFrequency(const unsigned long freq,
* startTx is called by the PTT, cw keyer and CAT protocol to
* put the uBitx in tx mode. It takes care of rit settings, sideband settings
* Note: In cw mode, doesnt key the radio, only puts it in tx mode
- * CW offest is calculated as lower than the operating frequency when in LSB mode, and vice versa in USB mode
+ * CW offset is calculated as lower than the operating frequency when in LSB mode, and vice versa in USB mode
*/
void startTx(TuningMode_e tx_mode){
globalSettings.tuningMode = tx_mode;
- if (globalSettings.ritOn){
- //save the current as the rx frequency
- uint32_t rit_tx_freq = globalSettings.ritFrequency;
- globalSettings.ritFrequency = GetActiveVfoFreq();
- setFrequency(rit_tx_freq,true);
- }
- else{
- if(globalSettings.splitOn){
- if(Vfo_e::VFO_B == globalSettings.activeVfo){
- globalSettings.activeVfo = Vfo_e::VFO_A;
- }
- else{
- globalSettings.activeVfo = Vfo_e::VFO_B;
+ if (!globalSettings.morsePracticeMode) {
+ uint32_t current_tx_freq = 0;
+ if (globalSettings.ritOn){
+ //save the current as the rx frequency
+ current_tx_freq = globalSettings.ritFrequency;
+ globalSettings.ritFrequency = GetActiveVfoFreq();
+ setFrequency(current_tx_freq,true);
+ }
+ else{
+ if(globalSettings.splitOn){
+ if(Vfo_e::VFO_B == globalSettings.activeVfo){
+ globalSettings.activeVfo = Vfo_e::VFO_A;
+ }
+ else{
+ globalSettings.activeVfo = Vfo_e::VFO_B;
+ }
}
+ current_tx_freq = GetActiveVfoFreq();
+ setFrequency(current_tx_freq,true);
+ }
+ if (freqInAnyBand(current_tx_freq)) {
+ digitalWrite(PIN_TX_RXn, 1);//turn on the tx
}
- setFrequency(GetActiveVfoFreq(),true);
}
-
- digitalWrite(PIN_TX_RXn, 1);//turn on the tx
globalSettings.txActive = true;
drawTx();
}
void stopTx(){
- digitalWrite(PIN_TX_RXn, 0);//turn off the tx
+ if (!globalSettings.morsePracticeMode) {
+ digitalWrite(PIN_TX_RXn, 0);//turn off the tx
+ }
globalSettings.txActive = false;
- if(globalSettings.ritOn){
- uint32_t rit_rx_freq = globalSettings.ritFrequency;
- globalSettings.ritFrequency = GetActiveVfoFreq();
- setFrequency(rit_rx_freq);
- }
- else{
- if(globalSettings.splitOn){
- if(Vfo_e::VFO_B == globalSettings.activeVfo){
- globalSettings.activeVfo = Vfo_e::VFO_A;
- }
- else{
- globalSettings.activeVfo = Vfo_e::VFO_B;
+ if (!globalSettings.morsePracticeMode) {
+ if(globalSettings.ritOn){
+ uint32_t rit_rx_freq = globalSettings.ritFrequency;
+ globalSettings.ritFrequency = GetActiveVfoFreq();
+ setFrequency(rit_rx_freq);
+ }
+ else{
+ if(globalSettings.splitOn){
+ if(Vfo_e::VFO_B == globalSettings.activeVfo){
+ globalSettings.activeVfo = Vfo_e::VFO_A;
+ }
+ else{
+ globalSettings.activeVfo = Vfo_e::VFO_B;
+ }
}
+ setFrequency(GetActiveVfoFreq());
}
- setFrequency(GetActiveVfoFreq());
}
drawTx();
}
diff --git a/tuner.h b/tuner.h
index cce5e97..64fb1bc 100644
--- a/tuner.h
+++ b/tuner.h
@@ -1,6 +1,7 @@
#pragma once
#include "settings.h"
+#include "config.h"
void saveVFOs();
void setFrequency(const unsigned long freq, const bool transmit = false);
@@ -8,7 +9,9 @@ void startTx(TuningMode_e tx_mode);
void stopTx();
void ritEnable(unsigned long f);
void ritDisable();
+#if GUI_THEME == 0
void checkCAT();
+#endif
void cwKeyer(void);
void switchVFO(Vfo_e vfoSelect);
diff --git a/ubitx_cat.cpp b/ubitx_cat.cpp
index b5fd491..d81a4ee 100644
--- a/ubitx_cat.cpp
+++ b/ubitx_cat.cpp
@@ -3,9 +3,12 @@
#include "scratch_space.h"
#include "settings.h"
#include "tuner.h"
+#include "config.h"
+
+#if GUI_THEME == 0
/**
- * The CAT protocol is used by many radios to provide remote control to comptuers through
+ * The CAT protocol is used by many radios to provide remote control to computers through
* the serial port.
*
* This is very much a work in progress. Parts of this code have been liberally
@@ -417,4 +420,4 @@ void checkCAT(){
timeout = 0;
}
-
+#endif // of: #if GUI_THEME == 0
diff --git a/ubitxv6.ino b/ubitxv6.ino
index 38f4da4..b898b69 100644
--- a/ubitxv6.ino
+++ b/ubitxv6.ino
@@ -33,7 +33,6 @@
#include "encoder.h"
#include "menu.h"
#include "menu_main.h"
-#include "morse.h"
#include "pin_definitions.h"
#include "push_button.h"
#include "nano_gui.h"
@@ -132,9 +131,10 @@ void initPorts(){
void setup()
{
+#if GUI_THEME == 0
Serial.begin(38400);
Serial.flush();
-
+#endif
initSettings();
displayInit();
initTouch();
@@ -142,6 +142,7 @@ void setup()
initOscillators();
setFrequency(globalSettings.vfoA.frequency);
+#if GUI_THEME == 0
//Run initial calibration routine if button is pressed during power up
if(ButtonPress_e::NotPressed != CheckTunerButton()){
LoadDefaultSettings();
@@ -153,7 +154,7 @@ void setup()
setFrequency(7100000L);
runBfoSetting();
}
-
+#endif
rootMenu->initMenu();
}
@@ -170,7 +171,9 @@ void loop(){
checkPTT();
}
+#if GUI_THEME == 0
checkCAT();
+#endif
if(globalSettings.txActive){
//Don't run menus when transmitting
diff --git a/version.cpp b/version.cpp
index 316e0bf..e981901 100644
--- a/version.cpp
+++ b/version.cpp
@@ -1,4 +1,5 @@
#include "version.h"
+#include "config.h"
-const char VERSION_STRING_PRIVATE [] PROGMEM = "R1.5.1";
+const char VERSION_STRING_PRIVATE [] PROGMEM = VERSION_TEXT;
const char* const VERSION_STRING = VERSION_STRING_PRIVATE;
\ No newline at end of file