2019-12-18 01:32:44 -05:00
|
|
|
#include <Arduino.h>
|
|
|
|
#include <EEPROM.h>
|
|
|
|
#include "morse.h"
|
2020-01-04 02:11:55 -05:00
|
|
|
#include "settings.h"
|
2019-12-18 01:32:44 -05:00
|
|
|
#include "ubitx.h"
|
|
|
|
#include "nano_gui.h"
|
|
|
|
|
|
|
|
/** Menus
|
|
|
|
* The Radio menus are accessed by tapping on the function button.
|
|
|
|
* - The main loop() constantly looks for a button press and calls doMenu() when it detects
|
|
|
|
* 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 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
|
|
|
|
*/
|
|
|
|
|
2020-01-04 03:53:00 -05:00
|
|
|
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;
|
|
|
|
|
|
|
|
static const unsigned int LAYOUT_OUTER_BORDER_X = 10;
|
|
|
|
static const unsigned int LAYOUT_OUTER_BORDER_Y = 10;
|
|
|
|
static const unsigned int LAYOUT_OUTER_BORDER_WIDTH = 300;
|
|
|
|
static const unsigned int LAYOUT_OUTER_BORDER_HEIGHT = 220;
|
|
|
|
|
|
|
|
static const unsigned int LAYOUT_INNER_BORDER_X = 12;
|
|
|
|
static const unsigned int LAYOUT_INNER_BORDER_Y = 12;
|
|
|
|
static const unsigned int LAYOUT_INNER_BORDER_WIDTH = 296;
|
|
|
|
static const unsigned int LAYOUT_INNER_BORDER_HEIGHT = 216;
|
|
|
|
|
|
|
|
static const unsigned int LAYOUT_TITLE_X = LAYOUT_INNER_BORDER_X;
|
|
|
|
static const unsigned int LAYOUT_TITLE_Y = LAYOUT_INNER_BORDER_Y;
|
|
|
|
static const unsigned int LAYOUT_TITLE_WIDTH = LAYOUT_INNER_BORDER_WIDTH;
|
|
|
|
static const unsigned int LAYOUT_TITLE_HEIGHT = 35;
|
|
|
|
|
|
|
|
static const unsigned int LAYOUT_ITEM_X = 30;
|
|
|
|
static const unsigned int LAYOUT_ITEM_Y = LAYOUT_TITLE_Y + LAYOUT_TITLE_HEIGHT + 5;
|
|
|
|
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_VALUE_X = LAYOUT_ITEM_X;
|
|
|
|
static const unsigned int LAYOUT_SETTING_VALUE_Y = LAYOUT_ITEM_Y + 3*LAYOUT_ITEM_PITCH_Y;
|
|
|
|
static const unsigned int LAYOUT_SETTING_VALUE_WIDTH = LAYOUT_ITEM_WIDTH;
|
|
|
|
static const unsigned int LAYOUT_SETTING_VALUE_HEIGHT = LAYOUT_ITEM_HEIGHT;
|
|
|
|
|
|
|
|
static const unsigned int LAYOUT_INSTRUCTION_TEXT_X = 20;
|
|
|
|
static const unsigned int LAYOUT_INSTRUCTION_TEXT_Y = LAYOUT_ITEM_Y + 5*LAYOUT_ITEM_PITCH_Y;
|
|
|
|
static const unsigned int LAYOUT_INSTRUCTION_TEXT_WIDTH = LAYOUT_ITEM_WIDTH;
|
|
|
|
static const unsigned int LAYOUT_INSTRUCTION_TEXT_HEIGHT = LAYOUT_ITEM_HEIGHT;
|
|
|
|
|
2020-01-04 04:10:10 -05:00
|
|
|
void displayDialog(const __FlashStringHelper* title, const __FlashStringHelper* instructions){
|
|
|
|
strcpy_P(b,(const char*)title);
|
|
|
|
strcpy_P(c,(const char*)instructions);
|
2020-01-04 03:53:00 -05:00
|
|
|
displayClear(COLOR_BACKGROUND);
|
|
|
|
displayRect(LAYOUT_OUTER_BORDER_X,LAYOUT_OUTER_BORDER_Y,LAYOUT_OUTER_BORDER_WIDTH,LAYOUT_OUTER_BORDER_HEIGHT, COLOR_ACTIVE_BORDER);
|
|
|
|
displayRect(LAYOUT_INNER_BORDER_X,LAYOUT_INNER_BORDER_Y,LAYOUT_INNER_BORDER_WIDTH,LAYOUT_INNER_BORDER_HEIGHT, COLOR_ACTIVE_BORDER);
|
2020-01-04 04:10:10 -05:00
|
|
|
displayText(b, LAYOUT_TITLE_X, LAYOUT_TITLE_Y, LAYOUT_TITLE_WIDTH, LAYOUT_TITLE_HEIGHT, COLOR_TEXT, COLOR_TITLE_BACKGROUND, COLOR_ACTIVE_BORDER);
|
|
|
|
displayText(c, LAYOUT_INSTRUCTION_TEXT_X, LAYOUT_INSTRUCTION_TEXT_Y, LAYOUT_INSTRUCTION_TEXT_WIDTH, LAYOUT_INSTRUCTION_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND);
|
2020-01-04 03:53:00 -05:00
|
|
|
}
|
|
|
|
|
2020-01-19 02:34:41 -05:00
|
|
|
struct SettingScreen_t {
|
|
|
|
const char* const Title;
|
|
|
|
const char* const AdditionalText;
|
|
|
|
const uint16_t KnobDivider;
|
|
|
|
const uint16_t StepSize;
|
|
|
|
void (*Initialize)(long int* start_value_out);
|
|
|
|
void (*Validate)(const long int candidate_value_in, long int* validated_value_out);
|
|
|
|
void (*OnValueChange)(const long int new_value, char* buff_out, const size_t buff_out_size);
|
|
|
|
void (*Finalize)(const long int final_value);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define LIMIT(val,min,max) ((val) < (min)) ? (min) : (((max) < (val)) ? (max) : (val))
|
2020-01-19 13:48:07 -05:00
|
|
|
ssCwToneInitialize(long int* start_value_out)
|
|
|
|
{
|
|
|
|
*start_value_out = globalSettings.cwSideToneFreq;
|
|
|
|
}
|
|
|
|
ssCwToneValidate(const long int candidate_value_in, long int* validated_value_out)
|
|
|
|
{
|
|
|
|
*validated_value_out = LIMIT(candidate_value_in,100,2000);
|
|
|
|
}
|
|
|
|
ssCwToneChange(const long int new_value, char* buff_out, const size_t buff_out_size)
|
|
|
|
{
|
|
|
|
globalSettings.cwSideToneFreq = new_value;
|
|
|
|
tone(CW_TONE, globalSettings.cwSideToneFreq);
|
|
|
|
ltoa(globalSettings.cwSideToneFreq,buff_out,10);
|
|
|
|
}
|
|
|
|
ssCwToneFinalize(const long int final_value)
|
|
|
|
{
|
|
|
|
noTone(CW_TONE);
|
|
|
|
globalSettings.cwSideToneFreq = final_value;
|
|
|
|
SaveSettingsToEeprom();
|
|
|
|
}
|
2020-01-19 02:34:41 -05:00
|
|
|
const char SS_EMPTY [] PROGMEM = "";
|
|
|
|
const char SS_CW_TONE [] PROGMEM = "Set CW Tone (Hz)";
|
2020-01-19 13:48:07 -05:00
|
|
|
const SettingScreen_t settingScreens [] PROGMEM = {
|
2020-01-19 02:34:41 -05:00
|
|
|
SS_CW_TONE,
|
|
|
|
SS_EMPTY,
|
|
|
|
1,
|
|
|
|
10,
|
2020-01-19 13:48:07 -05:00
|
|
|
ssCwToneInitialize,
|
|
|
|
ssCwToneValidate,
|
|
|
|
ssCwToneChange,
|
|
|
|
ssCwToneFinalize
|
2020-01-19 02:34:41 -05:00
|
|
|
};
|
|
|
|
void runSetting(const SettingScreen_t* const screen);
|
2020-01-19 13:48:07 -05:00
|
|
|
void runToneSetting(){runSetting(&settingScreens[0]);}
|
2020-01-19 02:34:41 -05:00
|
|
|
|
2020-01-19 13:48:07 -05:00
|
|
|
void runSetting(const SettingScreen_t* const p_screen)
|
2020-01-19 02:34:41 -05:00
|
|
|
{
|
2020-01-19 13:48:07 -05:00
|
|
|
SettingScreen_t screen = {0};
|
|
|
|
memcpy_P(&screen,p_screen,sizeof(screen));
|
|
|
|
displayDialog(reinterpret_cast<const __FlashStringHelper *>(screen.Title),F("Push Tune to Save"));
|
2020-01-19 02:34:41 -05:00
|
|
|
|
|
|
|
//Wait for button to stop being pressed
|
|
|
|
while(btnDown()){
|
|
|
|
active_delay(10);
|
|
|
|
}
|
|
|
|
active_delay(10);
|
|
|
|
|
|
|
|
long int raw_value = 0;
|
|
|
|
long int last_value = 0;
|
|
|
|
|
2020-01-19 13:48:07 -05:00
|
|
|
screen.Initialize(&last_value);
|
|
|
|
screen.OnValueChange(last_value,b,sizeof(b));
|
2020-01-19 02:34:41 -05:00
|
|
|
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);
|
|
|
|
|
2020-01-19 13:48:07 -05:00
|
|
|
raw_value = last_value * screen.KnobDivider;
|
2020-01-19 02:34:41 -05:00
|
|
|
|
|
|
|
while (!btnDown())
|
|
|
|
{
|
|
|
|
int knob = enc_read();
|
|
|
|
if(knob != 0){
|
2020-01-19 13:48:07 -05:00
|
|
|
raw_value += knob * (int32_t)screen.StepSize;
|
2020-01-19 02:34:41 -05:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-01-19 13:48:07 -05:00
|
|
|
const long int candidate_value = raw_value / (int32_t)screen.KnobDivider;
|
2020-01-19 02:34:41 -05:00
|
|
|
long int value = 0;
|
2020-01-19 13:48:07 -05:00
|
|
|
screen.Validate(candidate_value,&value);
|
2020-01-19 02:34:41 -05:00
|
|
|
|
|
|
|
//If we're going out of bounds, prevent the raw value from going too far out
|
|
|
|
if(candidate_value != value){
|
2020-01-19 13:48:07 -05:00
|
|
|
raw_value = value * (int32_t)screen.KnobDivider;
|
2020-01-19 02:34:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if(value == last_value){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else{
|
2020-01-19 13:48:07 -05:00
|
|
|
screen.OnValueChange(value,b,sizeof(b));
|
2020-01-19 02:34:41 -05:00
|
|
|
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);
|
|
|
|
last_value = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-19 13:48:07 -05:00
|
|
|
screen.Finalize(last_value);
|
2020-01-19 02:34:41 -05:00
|
|
|
}
|
|
|
|
|
2020-01-15 02:33:11 -05:00
|
|
|
void printCarrierFreq(unsigned long freq)
|
|
|
|
{
|
|
|
|
formatFreq(freq,c,sizeof(c));
|
2020-01-04 03:53:00 -05:00
|
|
|
displayText(c, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_TITLE_BACKGROUND, COLOR_BACKGROUND);
|
|
|
|
}
|
|
|
|
|
2019-12-18 01:32:44 -05:00
|
|
|
void setupFreq(){
|
2020-01-04 04:10:10 -05:00
|
|
|
displayDialog(F("Set Frequency"),F("Push TUNE to Save"));
|
2019-12-18 01:32:44 -05:00
|
|
|
|
|
|
|
//round off the the nearest khz
|
2020-01-04 02:11:55 -05:00
|
|
|
{
|
|
|
|
uint32_t freq = GetActiveVfoFreq();
|
|
|
|
freq = (freq/1000l)* 1000l;
|
|
|
|
setFrequency(freq);
|
|
|
|
}
|
|
|
|
|
2020-01-04 04:10:10 -05:00
|
|
|
strcpy_P(c,(const char*)F("You should have a"));
|
|
|
|
displayText(c, LAYOUT_SETTING_VALUE_X, LAYOUT_ITEM_Y, LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND);
|
|
|
|
strcpy_P(c,(const char*)F("signal exactly at"));
|
|
|
|
displayText(c, LAYOUT_SETTING_VALUE_X, LAYOUT_ITEM_Y + 1*LAYOUT_ITEM_PITCH_Y, LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND);
|
2020-01-15 01:22:26 -05:00
|
|
|
ltoa(GetActiveVfoFreq()/1000L, c, 10);
|
2020-01-04 04:10:10 -05:00
|
|
|
strcat_P(c,(const char*)F(" KHz"));
|
2020-01-04 03:53:00 -05:00
|
|
|
displayText(c, LAYOUT_SETTING_VALUE_X, LAYOUT_ITEM_Y + 2*LAYOUT_ITEM_PITCH_Y, LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND);
|
2020-01-04 04:10:10 -05:00
|
|
|
strcpy_P(c,(const char*)F("Rotate to zerobeat"));
|
|
|
|
displayText(c, LAYOUT_SETTING_VALUE_X, LAYOUT_ITEM_Y + 4*LAYOUT_ITEM_PITCH_Y, LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND);
|
2020-01-04 03:53:00 -05:00
|
|
|
|
2020-01-04 04:50:17 -05:00
|
|
|
ltoa(globalSettings.oscillatorCal, b, 10);
|
2020-01-04 03:53:00 -05:00
|
|
|
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);
|
2019-12-18 01:32:44 -05:00
|
|
|
//keep clear of any previous button press
|
|
|
|
while (btnDown())
|
|
|
|
active_delay(100);
|
|
|
|
active_delay(100);
|
|
|
|
|
|
|
|
while (!btnDown())
|
|
|
|
{
|
2020-01-15 01:22:26 -05:00
|
|
|
int knob = enc_read();
|
|
|
|
if(knob != 0){
|
2020-01-04 02:11:55 -05:00
|
|
|
globalSettings.oscillatorCal += knob * 875;
|
2020-01-15 01:22:26 -05:00
|
|
|
}
|
|
|
|
else{
|
2019-12-18 01:32:44 -05:00
|
|
|
continue; //don't update the frequency or the display
|
2020-01-15 01:22:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
si5351bx_setfreq(0, globalSettings.usbCarrierFreq); //set back the carrier oscillator anyway, cw tx switches it off
|
2020-01-04 02:11:55 -05:00
|
|
|
si5351_set_calibration(globalSettings.oscillatorCal);
|
|
|
|
setFrequency(GetActiveVfoFreq());
|
2019-12-18 01:32:44 -05:00
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
ltoa(globalSettings.oscillatorCal, b, 10);
|
2020-01-04 03:53:00 -05:00
|
|
|
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);
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
SaveSettingsToEeprom();
|
2019-12-18 01:32:44 -05:00
|
|
|
initOscillators();
|
2020-01-04 02:11:55 -05:00
|
|
|
si5351_set_calibration(globalSettings.oscillatorCal);
|
|
|
|
setFrequency(GetActiveVfoFreq());
|
2019-12-18 01:32:44 -05:00
|
|
|
|
|
|
|
//debounce and delay
|
|
|
|
while(btnDown())
|
|
|
|
active_delay(50);
|
|
|
|
active_delay(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setupBFO(){
|
2020-01-04 04:10:10 -05:00
|
|
|
displayDialog(F("Set BFO"),F("Press TUNE to Save"));
|
2020-01-15 01:22:26 -05:00
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
si5351bx_setfreq(0, globalSettings.usbCarrierFreq);
|
|
|
|
printCarrierFreq(globalSettings.usbCarrierFreq);
|
2019-12-18 01:32:44 -05:00
|
|
|
|
|
|
|
while (!btnDown()){
|
2020-01-15 01:22:26 -05:00
|
|
|
int knob = enc_read();
|
|
|
|
if(knob != 0){
|
2020-01-04 02:11:55 -05:00
|
|
|
globalSettings.usbCarrierFreq -= 50 * knob;
|
2020-01-15 01:22:26 -05:00
|
|
|
}
|
|
|
|
else{
|
2019-12-18 01:32:44 -05:00
|
|
|
continue; //don't update the frequency or the display
|
2020-01-15 01:22:26 -05:00
|
|
|
}
|
2019-12-18 01:32:44 -05:00
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
si5351bx_setfreq(0, globalSettings.usbCarrierFreq);
|
|
|
|
setFrequency(GetActiveVfoFreq());
|
|
|
|
printCarrierFreq(globalSettings.usbCarrierFreq);
|
2019-12-18 01:32:44 -05:00
|
|
|
|
|
|
|
active_delay(100);
|
|
|
|
}
|
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
SaveSettingsToEeprom();
|
|
|
|
si5351bx_setfreq(0, globalSettings.usbCarrierFreq);
|
|
|
|
setFrequency(GetActiveVfoFreq());
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void setupCwDelay(){
|
|
|
|
int knob = 0;
|
|
|
|
int prev_cw_delay;
|
|
|
|
|
2020-01-04 04:10:10 -05:00
|
|
|
displayDialog(F("Set CW T/R Delay"),F("Press tune to Save"));
|
2019-12-18 01:32:44 -05:00
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
prev_cw_delay = globalSettings.cwActiveTimeoutMs;
|
2019-12-18 01:32:44 -05:00
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
ltoa(globalSettings.cwActiveTimeoutMs, b, 10);
|
2020-01-04 04:10:10 -05:00
|
|
|
strcat_P(b,(const char*)F(" msec"));
|
2020-01-04 03:53:00 -05:00
|
|
|
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
2019-12-18 01:32:44 -05:00
|
|
|
|
|
|
|
while (!btnDown()){
|
|
|
|
knob = enc_read();
|
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
if (knob < 0 && globalSettings.cwActiveTimeoutMs > 100)
|
|
|
|
globalSettings.cwActiveTimeoutMs -= 100;
|
|
|
|
else if (knob > 0 && globalSettings.cwActiveTimeoutMs < 1000)
|
|
|
|
globalSettings.cwActiveTimeoutMs += 100;
|
2019-12-18 01:32:44 -05:00
|
|
|
else
|
|
|
|
continue; //don't update the frequency or the display
|
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
ltoa(globalSettings.cwActiveTimeoutMs, b, 10);
|
2020-01-04 04:10:10 -05:00
|
|
|
strcat_P(b,(const char*)F(" msec"));
|
2020-01-04 03:53:00 -05:00
|
|
|
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
2019-12-18 01:32:44 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
SaveSettingsToEeprom();
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
|
|
|
|
2020-01-18 01:22:06 -05:00
|
|
|
void formatKeyerEnum(char* output, const KeyerMode_e mode)
|
|
|
|
{
|
|
|
|
if(KeyerMode_e::KEYER_STRAIGHT == mode){
|
|
|
|
strcpy_P(output,(const char*)F("< Hand Key >"));
|
2020-01-04 02:11:55 -05:00
|
|
|
}
|
2020-01-18 01:22:06 -05:00
|
|
|
else if(KeyerMode_e::KEYER_IAMBIC_A == mode){
|
|
|
|
strcpy_P(output,(const char*)F("< Iambic A >"));
|
2020-01-04 02:11:55 -05:00
|
|
|
}
|
|
|
|
else{
|
2020-01-18 01:22:06 -05:00
|
|
|
strcpy_P(output,(const char*)F("< Iambic B >"));
|
2020-01-04 02:11:55 -05:00
|
|
|
}
|
2020-01-18 01:22:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void setupKeyer(){
|
|
|
|
displayDialog(F("Set CW Keyer"),F("Press tune to Save"));
|
2019-12-18 01:32:44 -05:00
|
|
|
|
2020-01-04 02:11:55 -05:00
|
|
|
int knob = 0;
|
|
|
|
uint32_t tmp_mode = globalSettings.keyerMode;
|
2020-01-18 01:22:06 -05:00
|
|
|
formatKeyerEnum(c, tmp_mode);
|
|
|
|
displayText(c, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
|
|
|
|
2019-12-18 01:32:44 -05:00
|
|
|
while (!btnDown())
|
|
|
|
{
|
|
|
|
knob = enc_read();
|
2020-01-04 02:11:55 -05:00
|
|
|
if(knob == 0){
|
2019-12-18 01:32:44 -05:00
|
|
|
active_delay(50);
|
|
|
|
continue;
|
|
|
|
}
|
2020-01-04 02:11:55 -05:00
|
|
|
if(knob < 0 && tmp_mode > KeyerMode_e::KEYER_STRAIGHT){
|
|
|
|
tmp_mode--;
|
|
|
|
}
|
|
|
|
if(knob > 0 && tmp_mode < KeyerMode_e::KEYER_IAMBIC_B){
|
|
|
|
tmp_mode++;
|
|
|
|
}
|
|
|
|
|
2020-01-18 01:22:06 -05:00
|
|
|
formatKeyerEnum(c,tmp_mode);
|
|
|
|
displayText(c, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
active_delay(500);
|
2020-01-04 02:11:55 -05:00
|
|
|
|
|
|
|
globalSettings.keyerMode = tmp_mode;
|
|
|
|
SaveSettingsToEeprom();
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
|
|
|
|
2020-01-18 01:57:41 -05:00
|
|
|
void setupCwSpeed()
|
|
|
|
{
|
|
|
|
displayDialog(F("Set CW Speed (WPM)"),F("Press tune to Save"));
|
|
|
|
|
|
|
|
unsigned int wpm = 1200/globalSettings.cwDitDurationMs;
|
|
|
|
|
|
|
|
itoa(wpm, b, 10);
|
|
|
|
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
|
|
|
|
|
|
|
while (!btnDown()){
|
|
|
|
int knob = enc_read();
|
|
|
|
|
|
|
|
if (knob < 0 && wpm > 1)
|
|
|
|
--wpm;
|
|
|
|
else if (knob > 0 && wpm < 100)
|
|
|
|
++wpm;
|
|
|
|
else
|
|
|
|
continue;//don't update the frequency or the display
|
|
|
|
|
|
|
|
itoa(wpm, b, 10);
|
|
|
|
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
globalSettings.cwDitDurationMs = 1200/wpm;
|
|
|
|
SaveSettingsToEeprom();
|
|
|
|
}
|
|
|
|
|
|
|
|
void setupCwTone(){
|
|
|
|
displayDialog(F("Set CW Tone (Hz)"),F("Press tune to Save"));
|
|
|
|
|
|
|
|
tone(CW_TONE, globalSettings.cwSideToneFreq);
|
|
|
|
itoa(globalSettings.cwSideToneFreq, b, 10);
|
|
|
|
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
|
|
|
|
|
|
|
while(!btnDown()){
|
|
|
|
int knob = enc_read();
|
|
|
|
|
|
|
|
if (knob > 0 && globalSettings.cwSideToneFreq < 2000)
|
|
|
|
globalSettings.cwSideToneFreq += 10;
|
|
|
|
else if (knob < 0 && globalSettings.cwSideToneFreq > 100 )
|
|
|
|
globalSettings.cwSideToneFreq -= 10;
|
|
|
|
else
|
|
|
|
continue; //don't update the frequency or the display
|
|
|
|
|
|
|
|
tone(CW_TONE, globalSettings.cwSideToneFreq);
|
|
|
|
itoa(globalSettings.cwSideToneFreq, b, 10);
|
|
|
|
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
|
|
|
}
|
|
|
|
noTone(CW_TONE);
|
|
|
|
|
|
|
|
SaveSettingsToEeprom();
|
|
|
|
}
|
|
|
|
|
2020-01-18 02:10:53 -05:00
|
|
|
void setupResetAll()
|
|
|
|
{
|
2020-01-18 02:23:56 -05:00
|
|
|
displayDialog(F("Reset all cals and settings?"),F("Press tune to Confirm"));
|
|
|
|
strcpy_P(b,(const char*)F("No"));
|
|
|
|
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
|
|
|
|
|
|
|
bool reset_all = false;
|
|
|
|
while(!btnDown()){
|
|
|
|
int knob = enc_read();
|
|
|
|
|
|
|
|
if(knob > 0){
|
|
|
|
reset_all = true;
|
|
|
|
}
|
|
|
|
else if(knob < 0){
|
|
|
|
reset_all = false;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(reset_all){
|
|
|
|
strcpy_P(b,(const char*)F("Yes"));
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
strcpy_P(b,(const char*)F("No"));
|
|
|
|
}
|
|
|
|
|
|
|
|
displayText(b, LAYOUT_SETTING_VALUE_X, LAYOUT_SETTING_VALUE_Y, LAYOUT_SETTING_VALUE_WIDTH, LAYOUT_SETTING_VALUE_HEIGHT, COLOR_TEXT, COLOR_SETTING_BACKGROUND, COLOR_BACKGROUND);
|
|
|
|
}
|
|
|
|
|
2020-01-18 02:10:53 -05:00
|
|
|
while(btnDown()){
|
|
|
|
active_delay(50);
|
|
|
|
}
|
|
|
|
active_delay(50);
|
2020-01-18 02:23:56 -05:00
|
|
|
|
|
|
|
if(reset_all){
|
|
|
|
LoadDefaultSettings();
|
|
|
|
SaveSettingsToEeprom();
|
|
|
|
setup();
|
|
|
|
}
|
2020-01-18 02:10:53 -05:00
|
|
|
}
|
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
struct MenuItem_t {
|
|
|
|
const char* const ItemName;
|
|
|
|
const void (*OnSelect)();
|
|
|
|
};
|
|
|
|
|
|
|
|
void runMenu(const MenuItem_t* const menu_items, const uint16_t num_items);
|
|
|
|
#define RUN_MENU(menu) runMenu(menu,sizeof(menu)/sizeof(menu[0]))
|
|
|
|
|
|
|
|
const char MT_CAL [] PROGMEM = "Calibrations";
|
2020-01-18 01:57:41 -05:00
|
|
|
const char MI_SET_FREQ [] PROGMEM = "Local Oscillator";
|
|
|
|
const char MI_SET_BFO [] PROGMEM = "Beat Frequency Osc (BFO)";
|
2020-01-18 01:27:12 -05:00
|
|
|
const char MI_TOUCH [] PROGMEM = "Touch Screen";
|
2020-01-18 00:41:52 -05:00
|
|
|
const MenuItem_t calibrationMenu [] PROGMEM {
|
|
|
|
{MT_CAL,nullptr},//Title
|
|
|
|
{MI_SET_FREQ,setupFreq},
|
|
|
|
{MI_SET_BFO,setupBFO},
|
|
|
|
{MI_TOUCH,setupTouch},
|
|
|
|
};
|
|
|
|
void runCalibrationMenu(){RUN_MENU(calibrationMenu);}
|
2020-01-01 21:42:34 -05:00
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
const char MT_CW [] PROGMEM = "CW/Morse Setup";
|
2020-01-18 01:57:41 -05:00
|
|
|
const char MI_CW_SPEED [] PROGMEM = "Play Speed (WPM)";
|
|
|
|
const char MI_CW_TONE [] PROGMEM = "Tone Frequency";
|
2020-01-18 01:27:12 -05:00
|
|
|
const char MI_CW_DELAY [] PROGMEM = "Tx/Rx Switching Delay";
|
|
|
|
const char MI_CW_KEYER [] PROGMEM = "Keyer Type";
|
2020-01-18 00:41:52 -05:00
|
|
|
const MenuItem_t cwMenu [] PROGMEM {
|
|
|
|
{MT_CW,nullptr},//Title
|
2020-01-18 01:57:41 -05:00
|
|
|
{MI_CW_SPEED,setupCwSpeed},
|
2020-01-19 02:34:41 -05:00
|
|
|
{MI_CW_TONE,runToneSetting},
|
2020-01-18 00:41:52 -05:00
|
|
|
{MI_CW_DELAY,setupCwDelay},
|
|
|
|
{MI_CW_KEYER,setupKeyer},
|
2020-01-01 21:42:34 -05:00
|
|
|
};
|
2020-01-18 00:41:52 -05:00
|
|
|
void runCwMenu(){RUN_MENU(cwMenu);}
|
2020-01-01 21:42:34 -05:00
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
const char MT_SETTINGS [] PROGMEM = "Settings";
|
2020-01-18 02:10:53 -05:00
|
|
|
const char MI_RESET [] PROGMEM = "Reset all Cals/Settings";
|
2020-01-18 00:41:52 -05:00
|
|
|
const MenuItem_t mainMenu [] PROGMEM {
|
|
|
|
{MT_SETTINGS,nullptr},//Title
|
|
|
|
{MT_CAL,runCalibrationMenu},
|
|
|
|
{MT_CW,runCwMenu},
|
2020-01-18 02:10:53 -05:00
|
|
|
{MI_RESET,setupResetAll},
|
2020-01-01 21:42:34 -05:00
|
|
|
};
|
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
const char MI_EXIT [] PROGMEM = "Exit";
|
|
|
|
const MenuItem_t exitMenu PROGMEM = {MI_EXIT,nullptr};
|
|
|
|
|
|
|
|
void drawMenu(const MenuItem_t* const items, const uint16_t num_items)
|
|
|
|
{
|
2020-01-01 21:42:34 -05:00
|
|
|
displayClear(COLOR_BACKGROUND);
|
2020-01-18 00:41:52 -05:00
|
|
|
MenuItem_t mi = {"",nullptr};
|
|
|
|
memcpy_P(&mi,&items[0],sizeof(mi));
|
|
|
|
strcpy_P(b,mi.ItemName);
|
2020-01-01 21:42:34 -05:00
|
|
|
displayText(b, LAYOUT_TITLE_X, LAYOUT_TITLE_Y, LAYOUT_TITLE_WIDTH, LAYOUT_TITLE_HEIGHT, COLOR_TEXT, COLOR_TITLE_BACKGROUND, COLOR_ACTIVE_BORDER);
|
2020-01-18 00:41:52 -05:00
|
|
|
for(unsigned int i = 1; i < num_items; ++i){
|
|
|
|
memcpy_P(&mi,&items[i],sizeof(mi));
|
|
|
|
strcpy_P(b,mi.ItemName);
|
|
|
|
displayText(b, LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (i-1)*LAYOUT_ITEM_PITCH_Y, LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_INACTIVE_BORDER);
|
2020-01-01 21:42:34 -05:00
|
|
|
}
|
2020-01-18 00:41:52 -05:00
|
|
|
memcpy_P(&mi,&exitMenu,sizeof(mi));
|
|
|
|
strcpy_P(b,mi.ItemName);
|
|
|
|
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);
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
void movePuck(unsigned int old_index, unsigned int new_index)
|
|
|
|
{
|
2020-01-01 21:42:34 -05:00
|
|
|
//Don't update if we're already on the right selection
|
2020-01-18 00:41:52 -05:00
|
|
|
if(old_index == new_index){
|
2020-01-01 21:42:34 -05:00
|
|
|
return;
|
|
|
|
}
|
2020-01-18 00:41:52 -05:00
|
|
|
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);
|
|
|
|
}
|
2020-01-01 21:42:34 -05:00
|
|
|
//Draw new
|
2020-01-18 00:41:52 -05:00
|
|
|
displayRect(LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (new_index*LAYOUT_ITEM_PITCH_Y), LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_ACTIVE_BORDER);
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
void runMenu(const MenuItem_t* const menu_items, const uint16_t num_items)
|
|
|
|
{
|
2020-01-01 21:42:34 -05:00
|
|
|
static const unsigned int COUNTS_PER_ITEM = 10;
|
2020-01-18 00:41:52 -05:00
|
|
|
const unsigned int MAX_KNOB_VALUE = num_items*COUNTS_PER_ITEM - 1;
|
|
|
|
int knob_sum = 0;
|
|
|
|
unsigned int old_index = 0;
|
2019-12-18 01:32:44 -05:00
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
drawMenu(menu_items,num_items);
|
|
|
|
movePuck(1,0);//Force draw of puck
|
2019-12-18 01:32:44 -05:00
|
|
|
|
|
|
|
//wait for the button to be raised up
|
2020-01-18 00:41:52 -05:00
|
|
|
while(btnDown()){
|
2019-12-18 01:32:44 -05:00
|
|
|
active_delay(50);
|
2020-01-18 00:41:52 -05:00
|
|
|
}
|
2019-12-18 01:32:44 -05:00
|
|
|
active_delay(50); //debounce
|
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
while (true){
|
|
|
|
knob_sum += enc_read();
|
|
|
|
if(knob_sum < 0){
|
|
|
|
knob_sum = 0;
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
2020-01-18 00:41:52 -05:00
|
|
|
else if(MAX_KNOB_VALUE < knob_sum){
|
|
|
|
knob_sum = MAX_KNOB_VALUE;
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
uint16_t index = knob_sum/COUNTS_PER_ITEM;
|
|
|
|
movePuck(old_index,index);
|
|
|
|
old_index = index;
|
|
|
|
|
2019-12-18 01:32:44 -05:00
|
|
|
if (!btnDown()){
|
|
|
|
active_delay(50);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//wait for the touch to lift off and debounce
|
|
|
|
while(btnDown()){
|
|
|
|
active_delay(50);
|
|
|
|
}
|
2020-01-18 00:41:52 -05:00
|
|
|
active_delay(50);//debounce
|
2019-12-18 01:32:44 -05:00
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
if(num_items-1 > index){
|
|
|
|
MenuItem_t mi = {"",nullptr};
|
|
|
|
memcpy_P(&mi,&menu_items[index+1],sizeof(mi));//The 0th element in the array is the title, so offset by 1
|
|
|
|
mi.OnSelect();
|
|
|
|
drawMenu(menu_items,num_items);//Need to re-render, since whatever ran just now is assumed to have drawn something
|
|
|
|
old_index = -1;//Force redraw
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
break;
|
|
|
|
}
|
2019-12-18 01:32:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//debounce the button
|
2020-01-18 00:41:52 -05:00
|
|
|
while(btnDown()){
|
2019-12-18 01:32:44 -05:00
|
|
|
active_delay(50);
|
2020-01-18 00:41:52 -05:00
|
|
|
}
|
|
|
|
active_delay(50);//debounce
|
|
|
|
}
|
2019-12-18 01:32:44 -05:00
|
|
|
|
2020-01-18 00:41:52 -05:00
|
|
|
void doSetup2(){
|
|
|
|
RUN_MENU(mainMenu);
|
2019-12-18 01:32:44 -05:00
|
|
|
guiUpdate();
|
|
|
|
}
|