diff --git a/morse.cpp b/morse.cpp index 2551577..9dc2931 100644 --- a/morse.cpp +++ b/morse.cpp @@ -15,48 +15,53 @@ struct Morse { * The first zero after the 1s indicates the start of the letter, it MUST be discarded */ static const PROGMEM struct Morse morse_table[] = { -{'a', 0xf9}, // 11111001 -{'b', 0xe8}, // 11101000 -{'c', 0xea}, // 11101010 -{'d', 0xf4}, // 11110100 -{'e', 0xfc}, // 11111100 -{'f', 0xe2}, // 11100010 -{'g', 0xf6}, // 11110110 -{'h', 0xe0}, // 11100000 -{'i', 0xf8}, // 11111000 -{'j', 0xe7}, // 11100111 -{'k', 0xf6}, // 11110101 -{'l', 0xe4}, // 11100100 -{'m', 0xfb}, // 11111011 -{'n', 0xfa}, // 11111010 -{'o', 0xf7}, // 11110111 -{'p', 0xe6}, // 11100110 -{'q', 0xed}, // 11101101 -{'r', 0xf2}, // 11110010 -{'s', 0xf0}, // 11110000 -{'t', 0xfd}, // 11111101 -{'u', 0xf1}, // 11110001 -{'v', 0xe1}, // 11100001 -{'w', 0xf3}, // 11110011 -{'x', 0xe9}, // 11101001 -{'y', 0xe3}, // 11101011 -{'z', 0xec}, // 11101100 -{'1', 0xcf}, // 11001111 -{'2', 0xc7}, // 11000111 -{'3', 0xc3}, // 11000011 -{'4', 0xc1}, // 11000001 -{'5', 0xc0}, // 11000000 -{'6', 0xd0}, // 11010000 -{'7', 0xd8}, // 11011000 -{'8', 0xdc}, // 11011100 -{'9', 0xde}, // 11011110 -{'0', 0xdf}, // 11011111 -{'.', 0x95}, // 10010101 -{',', 0xb3}, // 10110011 -{'?', 0x8c}, // 10001100 +{'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 }; -static void morseLetter(char c, uint16_t dit_duration_ms){ +void morseLetter(char c, uint16_t dit_duration_ms){ + if(!globalSettings.morseMenuOn){ + return; + } unsigned char mask = 0x80; //handle space character as three dashes @@ -100,9 +105,23 @@ static void morseLetter(char c, uint16_t dit_duration_ms){ } } +static const uint8_t RELATIVE_OFFSET_HZ = 100; void morseText(char *text, uint16_t dit_duration_ms){ - while(*text){ + 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; + } + tone(CW_TONE, globalSettings.cwSideToneFreq + (val ? RELATIVE_OFFSET_HZ : -RELATIVE_OFFSET_HZ)); + delay(3*globalSettings.cwDitDurationMs); + noTone(CW_TONE); + delay(3*globalSettings.cwDitDurationMs); +} diff --git a/morse.h b/morse.h index 5e7d76f..44ed35a 100644 --- a/morse.h +++ b/morse.h @@ -1,3 +1,7 @@ #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(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/settings.cpp b/settings.cpp index 2c395a1..a17ea65 100644 --- a/settings.cpp +++ b/settings.cpp @@ -20,10 +20,11 @@ static const uint16_t EEPROM_ADDR_TOUCH_SLOPE_X = 32;//int16_t static const uint16_t EEPROM_ADDR_TOUCH_SLOPE_Y = 36;//int16_t static const uint16_t EEPROM_ADDR_TOUCH_OFFSET_X = 40;//int16_t static const uint16_t EEPROM_ADDR_TOUCH_OFFSET_Y = 44;//int16_t -static const uint16_t EEPROM_ADDR_CW_DELAYTIME = 48; -static const uint16_t EEPROM_ADDR_VFO_A_MODE = 256; -static const uint16_t EEPROM_ADDR_VFO_B_MODE = 257; -static const uint16_t EEPROM_ADDR_CW_KEY_TYPE = 358; +static const uint16_t EEPROM_ADDR_MORSE_MENU = 46;//uint8_t +static const uint16_t EEPROM_ADDR_CW_DELAYTIME = 48;//uint16_t +static const uint16_t EEPROM_ADDR_VFO_A_MODE = 256;//uint8_t +static const uint16_t EEPROM_ADDR_VFO_B_MODE = 257;//uint8_t +static const uint16_t EEPROM_ADDR_CW_KEY_TYPE = 358;//uint8_t template bool LoadSane(T& dest,uint16_t addr, T min, T max) @@ -81,6 +82,7 @@ void LoadDefaultSettings() globalSettings.txActive = false; globalSettings.txCatActive = false; globalSettings.cwExpirationTimeMs = 0; + globalSettings.morseMenuOn = false; } void LoadSettingsFromEeprom() @@ -97,6 +99,10 @@ void LoadSettingsFromEeprom() LoadSane(globalSettings.vfoB.mode,EEPROM_ADDR_VFO_B_MODE,VFO_MODE_LSB,VFO_MODE_USB); 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; + //No sanity check on these - cal your heart out EEPROM.get(EEPROM_ADDR_MASTER_CAL,globalSettings.oscillatorCal); EEPROM.get(EEPROM_ADDR_TOUCH_SLOPE_X,globalSettings.touchSlopeX); @@ -122,6 +128,7 @@ 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); } uint32_t GetActiveVfoFreq() diff --git a/settings.h b/settings.h index efd90ba..a87f08f 100644 --- a/settings.h +++ b/settings.h @@ -97,6 +97,7 @@ struct SettingsRam bool txActive; bool txCatActive; uint32_t cwExpirationTimeMs; + bool morseMenuOn; }; //This is the shared declaration diff --git a/setup.cpp b/setup.cpp index 70852ff..78ad377 100644 --- a/setup.cpp +++ b/setup.cpp @@ -226,38 +226,6 @@ const SettingScreen_t ssBfo PROGMEM = { }; void runBfoSetting(){runSetting(&ssBfo);} -//CW Speed -void ssCwSpeedInitialize(long int* start_value_out) -{ - *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); -} -void ssCwSpeedChange(const long int new_value, char* buff_out, const size_t /*buff_out_size*/) -{ - ltoa(new_value, buff_out, 10); -} -void ssCwSpeedFinalize(const long int final_value) -{ - globalSettings.cwDitDurationMs = 1200L/final_value; - SaveSettingsToEeprom(); -} -const char SS_CW_SPEED_T [] PROGMEM = "CW Play Speed"; -const char SS_CW_SPEED_A [] PROGMEM = "Select speed to play CW\ncharacters"; -const SettingScreen_t ssCwSpeed PROGMEM = { - SS_CW_SPEED_T, - SS_CW_SPEED_A, - 5, - 1, - ssCwSpeedInitialize, - ssCwSpeedValidate, - ssCwSpeedChange, - ssCwSpeedFinalize -}; -void runCwSpeedSetting(){runSetting(&ssCwSpeed);} - //CW Tone void ssCwToneInitialize(long int* start_value_out) { @@ -280,7 +248,7 @@ void ssCwToneFinalize(const long int final_value) globalSettings.cwSideToneFreq = final_value; SaveSettingsToEeprom(); } -const char SS_CW_TONE_T [] PROGMEM = "CW Tone Frequency"; +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 SettingScreen_t ssTone PROGMEM = { SS_CW_TONE_T, @@ -307,13 +275,15 @@ 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) { globalSettings.cwActiveTimeoutMs = final_value; SaveSettingsToEeprom(); } -const char SS_CW_SWITCH_T [] PROGMEM = "CW Tx -> Rx Switch Delay"; +const char SS_CW_SWITCH_T [] PROGMEM = "Tx to Rx Delay"; const char SS_CW_SWITCH_A [] PROGMEM = "Select how long the radio\nshould wait before switching\nbetween TX and RX when in\nCW mode"; const SettingScreen_t ssCwSwitchDelay PROGMEM = { SS_CW_SWITCH_T, @@ -338,22 +308,28 @@ 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); + 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); + 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); + 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) { globalSettings.keyerMode = (KeyerMode_e)final_value; SaveSettingsToEeprom(); } -const char SS_KEYER_T [] PROGMEM = "CW Keyer/Paddle Type"; +const char SS_KEYER_T [] PROGMEM = "Keyer Type"; const char SS_KEYER_A [] PROGMEM = "Select which type of\nkeyer/paddle is being used"; const SettingScreen_t ssKeyer PROGMEM = { SS_KEYER_T, @@ -367,6 +343,82 @@ const SettingScreen_t ssKeyer PROGMEM = { }; void runKeyerSetting(){runSetting(&ssKeyer);} +//Morse menu playback +void ssMorseMenuInitialize(long int* start_value_out) +{ + *start_value_out = globalSettings.morseMenuOn; +} +void ssMorseMenuValidate(const long int candidate_value_in, long int* validated_value_out) +{ + *validated_value_out = LIMIT(candidate_value_in,0,1); +} +void ssMorseMenuChange(const long int new_value, char* buff_out, const size_t buff_out_size) +{ + char m; + if(new_value){ + strncpy_P(buff_out,(const char*)F("Yes"),buff_out_size); + m = 'Y'; + } + else{ + strncpy_P(buff_out,(const char*)F("No"),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(); +} +const char SS_MORSE_MENU_T [] PROGMEM = "Menu Audio"; +const char SS_MORSE_MENU_A [] PROGMEM = "When on, menu selections\nwill play morse code"; +const SettingScreen_t ssMorseMenu PROGMEM = { + SS_MORSE_MENU_T, + SS_MORSE_MENU_A, + 10, + 1, + ssMorseMenuInitialize, + ssMorseMenuValidate, + ssMorseMenuChange, + ssMorseMenuFinalize +}; +void runMorseMenuSetting(){runSetting(&ssMorseMenu);} + +//CW Speed +void ssCwSpeedInitialize(long int* start_value_out) +{ + *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); +} +void ssCwSpeedChange(const long int new_value, char* buff_out, const size_t /*buff_out_size*/) +{ + ltoa(new_value, buff_out, 10); + morseText(buff_out,1200L/new_value); + enc_read();//Consume any rotations during morse playback +} +void ssCwSpeedFinalize(const long int final_value) +{ + globalSettings.cwDitDurationMs = 1200L/final_value; + SaveSettingsToEeprom(); +} +const char SS_CW_SPEED_T [] PROGMEM = "Play Speed"; +const char SS_CW_SPEED_A [] PROGMEM = "Select speed to play CW\ncharacters"; +const SettingScreen_t ssCwSpeed PROGMEM = { + SS_CW_SPEED_T, + SS_CW_SPEED_A, + 5, + 1, + ssCwSpeedInitialize, + ssCwSpeedValidate, + ssCwSpeedChange, + ssCwSpeedFinalize +}; +void runCwSpeedSetting(){runSetting(&ssCwSpeed);} + //Reset all settings void ssResetAllInitialize(long int* start_value_out) { @@ -378,12 +430,17 @@ void ssResetAllValidate(const long int candidate_value_in, long int* validated_v } void ssResetAllChange(const long int new_value, char* buff_out, const size_t buff_out_size) { + char m; if(new_value){ strncpy_P(buff_out,(const char*)F("Yes"),buff_out_size); + m = 'Y'; } else{ strncpy_P(buff_out,(const char*)F("No"),buff_out_size); + m = 'N'; } + morseLetter(m); + enc_read();//Consume any rotations during morse playback } void ssResetAllFinalize(const long int final_value) { @@ -393,7 +450,7 @@ void ssResetAllFinalize(const long int final_value) setup(); } } -const char SS_RESET_ALL_T [] PROGMEM = "Reset All Cals/Settings"; +const char SS_RESET_ALL_T [] PROGMEM = "Reset All"; const char SS_RESET_ALL_A [] PROGMEM = "WARNING: Selecting \"Yes\"\nwill reset all calibrations and\nsettings to their default\nvalues"; const SettingScreen_t ssResetAll PROGMEM = { SS_RESET_ALL_T, @@ -425,13 +482,14 @@ const MenuItem_t calibrationMenu [] PROGMEM { }; void runCalibrationMenu(){RUN_MENU(calibrationMenu);} -const char MT_CW [] PROGMEM = "CW/Morse Setup"; +const char MT_CW [] PROGMEM = "CW Setup"; const MenuItem_t cwMenu [] PROGMEM { {MT_CW,nullptr},//Title - {SS_CW_SPEED_T,runCwSpeedSetting}, {SS_CW_TONE_T,runToneSetting}, {SS_CW_SWITCH_T,runCwSwitchDelaySetting}, {SS_KEYER_T,runKeyerSetting}, + {SS_MORSE_MENU_T,runMorseMenuSetting}, + {SS_CW_SPEED_T,runCwSpeedSetting}, }; void runCwMenu(){RUN_MENU(cwMenu);} @@ -482,10 +540,10 @@ void runMenu(const MenuItem_t* const menu_items, const uint16_t num_items) static const unsigned int COUNTS_PER_ITEM = 10; const int MAX_KNOB_VALUE = num_items*COUNTS_PER_ITEM - 1; int knob_sum = 0; - unsigned int old_index = 0; + unsigned int old_index = -1; drawMenu(menu_items,num_items); - movePuck(1,0);//Force draw of puck + movePuck(-1,0);//Force draw of puck //wait for the button to be raised up while(btnDown()){ @@ -504,6 +562,21 @@ void runMenu(const MenuItem_t* const menu_items, const uint16_t num_items) uint16_t index = knob_sum/COUNTS_PER_ITEM; movePuck(old_index,index); + + if(globalSettings.morseMenuOn //Only spend cycles copying menu item into RAM if we actually need to + && (old_index != index)){ + 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 + strncpy_P(b,mi.ItemName,sizeof(b)); + } + else{ + strncpy_P(b,MI_EXIT,sizeof(b)); + } + morseText(b); + enc_read();//Consume any rotations during morse playback + } + old_index = index; if (!btnDown()){ diff --git a/ubitx_ui.cpp b/ubitx_ui.cpp index 62b7e18..4e0b0b8 100644 --- a/ubitx_ui.cpp +++ b/ubitx_ui.cpp @@ -84,29 +84,55 @@ struct Button { unsigned int id; char text[5]; char morse; + void (*morse_status)(int8_t* val_out);//-1 if a low tone should play, +1 if a high tone should play }; +void msVfoA(int8_t* val_out){ + *val_out = (Vfo_e::VFO_A == globalSettings.activeVfo) ? 1 : -1; +} +void msVfoB(int8_t* val_out){ + *val_out = (Vfo_e::VFO_B == globalSettings.activeVfo) ? 1 : -1; +} +void msRit(int8_t* val_out){ + *val_out = globalSettings.ritOn ? 1 : -1; +} +void msUsb(int8_t* val_out){ + *val_out = (VfoMode_e::VFO_MODE_USB == GetActiveVfoMode()) ? 1 : -1; +} +void msLsb(int8_t* val_out){ + *val_out = (VfoMode_e::VFO_MODE_LSB == GetActiveVfoMode()) ? 1 : -1; +} +void msCw(int8_t* val_out){ + *val_out = (TuningMode_e::TUNE_CW == globalSettings.tuningMode) ? 1 : -1; +} +void msSpl(int8_t* val_out){ + *val_out = globalSettings.splitOn ? 1 : -1; +} +void msIgnore(int8_t* val_out){ + *val_out = 0; +} + constexpr Button btn_set[BUTTON_TOTAL] PROGMEM = { - {LAYOUT_VFO_LABEL_X + 0*LAYOUT_VFO_LABEL_PITCH_X, LAYOUT_VFO_LABEL_Y, LAYOUT_VFO_LABEL_WIDTH, LAYOUT_VFO_LABEL_HEIGHT, BUTTON_VFOA, "VFOA", 'A'}, - {LAYOUT_VFO_LABEL_X + 1*LAYOUT_VFO_LABEL_PITCH_X, LAYOUT_VFO_LABEL_Y, LAYOUT_VFO_LABEL_WIDTH, LAYOUT_VFO_LABEL_HEIGHT, BUTTON_VFOB, "VFOB", 'B'}, + {LAYOUT_VFO_LABEL_X + 0*LAYOUT_VFO_LABEL_PITCH_X, LAYOUT_VFO_LABEL_Y, LAYOUT_VFO_LABEL_WIDTH, LAYOUT_VFO_LABEL_HEIGHT, BUTTON_VFOA, "VFOA", 'A', msVfoA}, + {LAYOUT_VFO_LABEL_X + 1*LAYOUT_VFO_LABEL_PITCH_X, LAYOUT_VFO_LABEL_Y, LAYOUT_VFO_LABEL_WIDTH, LAYOUT_VFO_LABEL_HEIGHT, BUTTON_VFOB, "VFOB", 'B', msVfoB}, - {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_RIT, "RIT", 'R'}, - {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_USB, "USB", 'U'}, - {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_LSB, "LSB", 'L'}, - {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_CW , "CW", 'C'}, - {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_SPL, "SPL", 'S'}, + {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_RIT, "RIT", 'R', msRit}, + {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_USB, "USB", 'U', msUsb}, + {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_LSB, "LSB", 'L', msLsb}, + {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_CW , "CW", 'C', msCw}, + {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_SPL, "SPL", 'S', msSpl}, - {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_80, "80", '8'}, - {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_40, "40", '4'}, - {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_30, "30", '3'}, - {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_20, "20", '2'}, - {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_17, "17", '7'}, + {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_80, "80", '8', msIgnore}, + {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_40, "40", '4', msIgnore}, + {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_30, "30", '3', msIgnore}, + {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_20, "20", '2', msIgnore}, + {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_17, "17", '7', msIgnore}, - {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_15 , "15", '5'}, - {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_10 , "10", '1'}, - {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_BLANK_1, "", '\0'}, - {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_MNU, "\x7F", 'M'}, - {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_FRQ, "FRQ", 'F'}, + {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_15 , "15", '5', msIgnore}, + {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_10 , "10", '1', msIgnore}, + {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_BLANK_1, "", '\0', msIgnore}, + {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_MNU, "\x7F", 'M', msIgnore}, + {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_FRQ, "FRQ", 'F', msIgnore}, }; static const unsigned int KEYS_OFFSET = 256;//Unique from buttons @@ -129,23 +155,23 @@ enum keypad_e { KEYS_TOTAL = KEYS_CANCEL - KEYS_OFFSET + 1 }; constexpr Button keypad[KEYS_TOTAL] PROGMEM = { - {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_1, "1", '1'}, - {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_2, "2", '2'}, - {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_3, "3", '3'}, - {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_BLANK_1, "", '\0'}, - {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_OK, "OK", 'K'}, + {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_1, "1", '1', msIgnore}, + {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_2, "2", '2', msIgnore}, + {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_3, "3", '3', msIgnore}, + {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_BLANK_1, "", '\0', msIgnore}, + {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 0*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_OK, "OK", 'K', msIgnore}, - {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_4, "4", '4'}, - {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_5, "5", '5'}, - {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_6, "6", '6'}, - {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_0, "0", '0'}, - {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_BACKSPACE, "<-", 'B'}, + {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_4, "4", '4', msIgnore}, + {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_5, "5", '5', msIgnore}, + {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_6, "6", '6', msIgnore}, + {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_0, "0", '0', msIgnore}, + {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_BACKSPACE, "<-", 'B', msIgnore}, - {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_7, "7", '7'}, - {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_8, "8", '8'}, - {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_9, "9", '9'}, - {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_BLANK_2, "", '\0'}, - {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_CANCEL, "Can", 'C'}, + {LAYOUT_BUTTON_X + 0*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_7, "7", '7', msIgnore}, + {LAYOUT_BUTTON_X + 1*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_8, "8", '8', msIgnore}, + {LAYOUT_BUTTON_X + 2*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_9, "9", '9', msIgnore}, + {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_BLANK_2, "", '\0', msIgnore}, + {LAYOUT_BUTTON_X + 4*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, KEYS_CANCEL, "Can", 'C', msIgnore}, }; boolean getButton(btn_set_e index, Button* button){ @@ -357,7 +383,7 @@ void fastTune(){ //if the btn is down, wait until it is up while(btnDown()) active_delay(50); - active_delay(300); + active_delay(50); strncpy_P(c,(const char*)F("Fast tune"),sizeof(c)); displayText(c, LAYOUT_MODE_TEXT_X, LAYOUT_MODE_TEXT_Y, LAYOUT_MODE_TEXT_WIDTH, LAYOUT_MODE_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND); @@ -371,7 +397,7 @@ void fastTune(){ //wait until the button is realsed and then return while(btnDown()) active_delay(50); - active_delay(300); + active_delay(50); return; } @@ -400,12 +426,23 @@ void enterFreq(){ btnDraw(&button); } + while(btnDown()) + active_delay(50); + active_delay(50); + int cursor_pos = 0; memset(c, 0, sizeof(c)); - while(1){ + bool exit = false; + while(!exit){ checkCAT(); + if(btnDown()){ + while(btnDown()) + active_delay(50); + active_delay(50); + break; + } if(!readTouch()) continue; @@ -450,8 +487,7 @@ void enterFreq(){ setFrequency(new_freq); saveVFOs(); } - guiUpdate(); - return; + exit = true; break; } @@ -466,8 +502,7 @@ void enterFreq(){ } case KEYS_CANCEL: { - guiUpdate(); - return; + exit = true; break; } case KEYS_0: @@ -500,7 +535,10 @@ void enterFreq(){ active_delay(300); while(readTouch()) checkCAT(); - } // end of event loop : while(1) + } // end of event loop : while(!exit) + + guiUpdate(); + enc_read();//clear out any tuner turning that happened during entry } void drawCWStatus(){ @@ -730,22 +768,18 @@ void doCommand(Button* button){ } case BUTTON_VFOA: { - if(VFO_A == globalSettings.activeVfo){ - fastTune(); - } - else{ - switchVFO(VFO_A); - } + switchVFO(VFO_A); + uint32_t freq = globalSettings.vfoA.frequency; + ltoa(freq,b,10); + morseText(b); break; } case BUTTON_VFOB: { - if(VFO_B == globalSettings.activeVfo){ - fastTune(); - } - else{ - switchVFO(VFO_B); - } + switchVFO(VFO_B); + uint32_t freq = globalSettings.vfoB.frequency; + ltoa(freq,b,10); + morseText(b); break; } case BUTTON_80: @@ -851,12 +885,23 @@ void doCommands(){ active_delay(50); active_delay(50); //debounce + Button button; + memcpy_P(&button, &(btn_set[select/10]), sizeof(Button)); + morseLetter(button.morse); + int8_t morse_status = 0; + button.morse_status(&morse_status); + if(morse_status){ + if(morse_status > 0){ + morseBool(true); + } + else{ + morseBool(false); + } + } + while (true){ //check if the knob's button was pressed if (btnDown()){ - Button button; - memcpy_P(&button, &(btn_set[select/10]), sizeof(Button)); - doCommand(&button); //unfocus the buttons @@ -889,11 +934,26 @@ void doCommands(){ if (prev_button == select / 10) continue; - - //we are on a new button - drawFocus(prev_button, COLOR_INACTIVE_BORDER); - drawFocus(select/10, COLOR_ACTIVE_BORDER); - prev_button = select/10; + + //we are on a new button + drawFocus(prev_button, COLOR_INACTIVE_BORDER); + drawFocus(select/10, COLOR_ACTIVE_BORDER); + memcpy_P(&button, &(btn_set[select/10]), sizeof(Button)); + morseLetter(button.morse); + morse_status = 0; + button.morse_status(&morse_status); + Serial.println((uint16_t)button.morse_status); + Serial.println(morse_status); + if(morse_status){ + if(morse_status > 0){ + morseBool(true); + } + else{ + morseBool(false); + } + } + enc_read();//Clear any rotation that was done while the letter was playing + prev_button = select/10; } // guiUpdate(); diff --git a/ubitxv6.ino b/ubitxv6.ino index 0efc991..e1ee89f 100644 --- a/ubitxv6.ino +++ b/ubitxv6.ino @@ -30,10 +30,11 @@ * Si5351 object to control the clocks. */ #include +#include "morse.h" +#include "nano_gui.h" #include "settings.h" #include "setup.h" #include "ubitx.h" -#include "nano_gui.h" /** * The Arduino, unlike C/C++ on a regular computer with gigabytes of RAM, has very little memory. @@ -65,8 +66,6 @@ unsigned char doingCAT = 0; void active_delay(int delay_by){ unsigned long timeStart = millis(); while (millis() - timeStart <= (unsigned long)delay_by) { - delay(10); - //Background Work checkCAT(); } } @@ -320,7 +319,15 @@ void checkButton(){ active_delay(10); downTime++; if (downTime > 300){ - doSetup2(); + if(!globalSettings.morseMenuOn){ + globalSettings.morseMenuOn = true;//set before playing + morseLetter(2); + } + else{ + morseLetter(4); + globalSettings.morseMenuOn = false;//unset after playing + } + SaveSettingsToEeprom(); return; } }