diff --git a/PDQ_MinLib/PDQ_GFX.h b/PDQ_MinLib/PDQ_GFX.h index 5b225ef..cb9f152 100644 --- a/PDQ_MinLib/PDQ_GFX.h +++ b/PDQ_MinLib/PDQ_GFX.h @@ -145,6 +145,7 @@ public: static void drawChar(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size); static void drawCharGFX(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size); static inline void setCursor(coord_t x, coord_t y); + static inline void setBound(coord_t x, coord_t y); static inline void setTextColor(color_t c); static inline void setTextColor(color_t c, color_t bg); static inline void setTextSize(uint8_t s); @@ -157,8 +158,8 @@ public: static inline uint8_t getRotation() __attribute__ ((always_inline)) { return rotation; } static inline coord_t getCursorX() __attribute__ ((always_inline)) { return cursor_x; } static inline coord_t getCursorY() __attribute__ ((always_inline)) { return cursor_y; } - static inline void getTextBounds(char *string, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); - static inline void getTextBounds(const __FlashStringHelper *s, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + static inline void getTextBounds(char *string, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h, coord_t wi = _width); + static inline void getTextBounds(const __FlashStringHelper *s, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h, coord_t wi = _width); virtual size_t write(uint8_t); // used by Arduino "Print.h" (and the one required virtual function) @@ -167,6 +168,7 @@ protected: static coord_t WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes static coord_t _width, _height; // Display w/h as modified by current rotation static coord_t cursor_x, cursor_y; + static coord_t bound_x1, bound_x2; static color_t textcolor, textbgcolor; static uint8_t textsize; static uint8_t rotation; @@ -216,6 +218,10 @@ int16_t PDQ_GFX::cursor_x; template int16_t PDQ_GFX::cursor_y; template +int16_t PDQ_GFX::bound_x1; +template +int16_t PDQ_GFX::bound_x2; +template color_t PDQ_GFX::textcolor; template color_t PDQ_GFX::textbgcolor; @@ -239,6 +245,8 @@ PDQ_GFX::PDQ_GFX(coord_t w, coord_t h) _height = (int16_t)h; cursor_x = 0; cursor_y = 0; + bound_x1 = 0; + bound_x2 = WIDTH; rotation = 0; textsize = 1; textcolor = 0xffff; @@ -740,7 +748,7 @@ size_t PDQ_GFX::write(uint8_t c) { if(c == '\n') { - cursor_x = 0; + cursor_x = bound_x1; cursor_y += (coord_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); } else if (c != '\r') @@ -756,10 +764,10 @@ size_t PDQ_GFX::write(uint8_t c) if ((w > 0) && (h > 0)) { coord_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic - if(wrap && ((cursor_x + textsize * (xo + w)) >= _width)) + if(wrap && ((cursor_x + textsize * (xo + w)) >= bound_x2)) { // Drawing character would go off right edge; wrap to new line - cursor_x = 0; + cursor_x = bound_x1; cursor_y += (coord_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); } @@ -970,6 +978,13 @@ void PDQ_GFX::setCursor(coord_t x, coord_t y) cursor_y = (int16_t)y; } +template +void PDQ_GFX::setBound(coord_t x1, coord_t x2) +{ + bound_x1 = (int16_t)x1; + bound_x2 = (int16_t)x2; +} + template void PDQ_GFX::setTextSize(uint8_t s) { @@ -1046,10 +1061,13 @@ void PDQ_GFX::setFont(const GFXfont *f) // Pass string and a cursor position, returns UL corner and W,H. template -void PDQ_GFX::getTextBounds(char *str, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) +void PDQ_GFX::getTextBounds(char *str, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h, coord_t wi) { uint8_t c; // Current character + coord_t xs = x; + coord_t xe = xs+wi; + *x1 = x; *y1 = y; *w = *h = 0; @@ -1080,9 +1098,9 @@ void PDQ_GFX::getTextBounds(char *str, coord_t x, coord_t y, int16_t *x1, in xa = pgm_read_byte(&glyph->xAdvance); xo = pgm_read_byte(&glyph->xOffset); yo = pgm_read_byte(&glyph->yOffset); - if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) // Line wrap + if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= xe)) // Line wrap { - x = 0; // Reset x to 0 + x = xs; // Reset x to 0 y += ya; // Advance y by 1 line } gx1 = x + xo * ts; @@ -1103,7 +1121,7 @@ void PDQ_GFX::getTextBounds(char *str, coord_t x, coord_t y, int16_t *x1, in } else // Newline { - x = 0; // Reset x + x = xs; // Reset x y += ya; // Advance y by 1 line } } @@ -1158,10 +1176,12 @@ void PDQ_GFX::getTextBounds(char *str, coord_t x, coord_t y, int16_t *x1, in // Same as above, but for PROGMEM strings template -void PDQ_GFX::getTextBounds(const __FlashStringHelper *str, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) +void PDQ_GFX::getTextBounds(const __FlashStringHelper *str, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h, coord_t wi) { uint8_t *s = (uint8_t *)str; uint8_t c; + coord_t xs = x; + coord_t xe = xs+wi; *x1 = x; *y1 = y; @@ -1194,9 +1214,9 @@ void PDQ_GFX::getTextBounds(const __FlashStringHelper *str, coord_t x, coord xa = pgm_read_byte(&glyph->xAdvance); xo = pgm_read_byte(&glyph->xOffset); yo = pgm_read_byte(&glyph->yOffset); - if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) // Line wrap + if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= xe)) // Line wrap { - x = 0; // Reset x to 0 + x = xs; // Reset x to 0 y += ya; // Advance y by 1 line } gx1 = x + xo * ts; @@ -1217,7 +1237,7 @@ void PDQ_GFX::getTextBounds(const __FlashStringHelper *str, coord_t x, coord } else // Newline { - x = 0; // Reset x + x = xs; // Reset x y += ya; // Advance y by 1 line } } diff --git a/morse.cpp b/morse.cpp index 2afaeaa..20a1020 100644 --- a/morse.cpp +++ b/morse.cpp @@ -56,12 +56,12 @@ static const PROGMEM struct Morse morse_table[] = { {'?', 0x8c}, // 10001100 }; -static void morseLetter(char c){ +static void morseLetter(char c, uint16_t dit_duration_ms){ unsigned char mask = 0x80; //handle space character as three dashes if (c == ' '){ - active_delay(9 * globalSettings.cwDitDurationMs); + active_delay(7 * dit_duration_ms); //Serial.print(' '); return; } @@ -81,36 +81,28 @@ static void morseLetter(char c){ while(mask){ tone(CW_TONE, globalSettings.cwSideToneFreq,10000); if (mask & code){ - delay(3 * globalSettings.cwDitDurationMs); + delay(3 * dit_duration_ms); //Serial.print('-'); } else{ - delay(globalSettings.cwDitDurationMs); + delay(dit_duration_ms); //Serial.print('.'); } //Serial.print('#'); noTone(CW_TONE); - delay(globalSettings.cwDitDurationMs); // space between dots and dashes + delay(dit_duration_ms); // space between dots and dashes mask = mask >> 1; } //Serial.println('@'); - delay(2*globalSettings.cwDitDurationMs); // space between letters is a dash (3 dots), one dot's space has already been sent + 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 } } } -void morseText(char *text){ -// while (1){ - noTone(CW_TONE); - delay(1000); - tone(CW_TONE, 600); - delay(1000); -// } - - //Serial.println(globalSettings.cwSideToneFreq); +void morseText(char *text, uint16_t dit_duration_ms){ while(*text){ - morseLetter(*text++); + morseLetter(*text++, dit_duration_ms); } } diff --git a/morse.h b/morse.h index 9c2de08..5e7d76f 100644 --- a/morse.h +++ b/morse.h @@ -1,3 +1,3 @@ +#include "settings.h" //sends out morse code at the speed set by cwSpeed -extern int cwSpeed; //this is actuall the dot period in milliseconds -void morseText(char *text); +void morseText(char *text, uint16_t dit_duration_ms = globalSettings.cwDitDurationMs); diff --git a/nano_gui.cpp b/nano_gui.cpp index 6ca1ddb..902f2ad 100644 --- a/nano_gui.cpp +++ b/nano_gui.cpp @@ -178,7 +178,7 @@ void displayInit(void){ tft.begin(); tft.setFont(ubitx_font); - tft.setTextWrap(false); + tft.setTextWrap(true); tft.setTextColor(DISPLAY_GREEN,DISPLAY_BLACK); tft.setTextSize(1); tft.setRotation(1); @@ -217,6 +217,14 @@ void displayChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t void displayRawText(char *text, int x1, int y1, int color, int background){ tft.setTextColor(color,background); tft.setCursor(x1,y1); + tft.setBound(0,320); + tft.print(text); +} + +void displayRawText(char *text, int x1, int y1, int w, int color, int background){ + tft.setTextColor(color,background); + tft.setCursor(x1,y1); + tft.setBound(x1,x1+w); tft.print(text); } @@ -228,10 +236,10 @@ void displayText(char *text, int x1, int y1, int w, int h, int color, int backgr int16_t y1_out; uint16_t width_out; uint16_t height_out; - tft.getTextBounds(text,x1,y1,&x1_out,&y1_out,&width_out,&height_out); - x1 += (w - ( width_out + (x1_out-x1)))/2; - y1 += h - (h - height_out)/2; - displayRawText(text,x1,y1,color,background); + tft.getTextBounds(text,x1,y1,&x1_out,&y1_out,&width_out,&height_out,w); + x1 += (w - ( (int32_t)width_out + (x1_out-x1)))/2; + y1 += (ubitx_font->yAdvance + h - ( (int32_t)height_out + (y1_out-y1)))/2; + displayRawText(text,x1,y1,w,color,background); } void setupTouch(){ diff --git a/nano_gui.h b/nano_gui.h index f58cf02..b6d24ac 100644 --- a/nano_gui.h +++ b/nano_gui.h @@ -23,7 +23,6 @@ void formatFreq(uint32_t freq, char* buff, uint16_t buff_size); /* touch functions */ boolean readTouch(); -void setupTouch(); void scaleTouch(struct Point *p); // Color definitions diff --git a/setup.cpp b/setup.cpp index 10bace7..14272f7 100644 --- a/setup.cpp +++ b/setup.cpp @@ -1,9 +1,9 @@ #include -#include #include "morse.h" +#include "nano_gui.h" +#include "setup.h" #include "settings.h" #include "ubitx.h" -#include "nano_gui.h" /** Menus * The Radio menus are accessed by tapping on the function button. @@ -18,13 +18,6 @@ * - If the menu item is NOT clicked on, then the menu's prompt is to be displayed */ -void setupExit(){ - menuOn = 0; -} - - //this is used by the si5351 routines in the ubitx_5351 file -extern uint32_t si5351bx_vcoa; - 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; @@ -58,276 +51,460 @@ static const unsigned int LAYOUT_SETTING_VALUE_Y = LAYOUT_ITEM_Y + 3*LAYOUT_ITEM 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; +static const unsigned int LAYOUT_INSTRUCTIONS_TEXT_X = 20; +static const unsigned int LAYOUT_INSTRUCTIONS_TEXT_Y = LAYOUT_ITEM_Y; +static const unsigned int LAYOUT_INSTRUCTIONS_TEXT_WIDTH = LAYOUT_ITEM_WIDTH; +static const unsigned int LAYOUT_INSTRUCTIONS_TEXT_HEIGHT = LAYOUT_SETTING_VALUE_Y - LAYOUT_ITEM_Y - 1; -void displayDialog(const __FlashStringHelper* title, const __FlashStringHelper* instructions){ - strcpy_P(b,(const char*)title); - strcpy_P(c,(const char*)instructions); +static const unsigned int LAYOUT_CONFIRM_TEXT_X = 20; +static const unsigned int LAYOUT_CONFIRM_TEXT_Y = LAYOUT_ITEM_Y + 5*LAYOUT_ITEM_PITCH_Y; +static const unsigned int LAYOUT_CONFIRM_TEXT_WIDTH = LAYOUT_ITEM_WIDTH; +static const unsigned int LAYOUT_CONFIRM_TEXT_HEIGHT = LAYOUT_ITEM_HEIGHT; + +void displayDialog(const char* title, + const char* instructions){ 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); + strncpy_P(b,title,sizeof(b)); 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); + 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); + strncpy_P(b,(const char*)F("Push Tune to Save"),sizeof(b)); + displayText(b, LAYOUT_CONFIRM_TEXT_X, LAYOUT_CONFIRM_TEXT_Y, LAYOUT_CONFIRM_TEXT_WIDTH, LAYOUT_CONFIRM_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND); } -void printCarrierFreq(unsigned long freq) +struct SettingScreen_t { + const char* const Title; + const char* const AdditionalText; + const uint16_t KnobDivider; + const int16_t StepSize;//int so that it can be negative + 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); +}; + +void runSetting(const SettingScreen_t* const p_screen) { - formatFreq(freq,c,sizeof(c)); - 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); -} + SettingScreen_t screen = {0}; + memcpy_P(&screen,p_screen,sizeof(screen)); + displayDialog(screen.Title, + screen.AdditionalText); -void setupFreq(){ - displayDialog(F("Set Frequency"),F("Push TUNE to Save")); - - //round off the the nearest khz - { - uint32_t freq = GetActiveVfoFreq(); - freq = (freq/1000l)* 1000l; - setFrequency(freq); + //Wait for button to stop being pressed + while(btnDown()){ + active_delay(10); } + active_delay(10); - 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); - ltoa(GetActiveVfoFreq()/1000L, c, 10); - strcat_P(c,(const char*)F(" KHz")); - 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); - 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); - - ltoa(globalSettings.oscillatorCal, b, 10); + long int raw_value = 0; + long int last_value = 0; + + screen.Initialize(&last_value); + screen.OnValueChange(last_value,b,sizeof(b)); 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); - //keep clear of any previous button press - while (btnDown()) - active_delay(100); - active_delay(100); + + raw_value = last_value * (int32_t)screen.KnobDivider; while (!btnDown()) { int knob = enc_read(); if(knob != 0){ - globalSettings.oscillatorCal += knob * 875; + raw_value += knob * screen.StepSize; } else{ - continue; //don't update the frequency or the display - } - - si5351bx_setfreq(0, globalSettings.usbCarrierFreq); //set back the carrier oscillator anyway, cw tx switches it off - si5351_set_calibration(globalSettings.oscillatorCal); - setFrequency(GetActiveVfoFreq()); - - ltoa(globalSettings.oscillatorCal, b, 10); - 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); - } - - SaveSettingsToEeprom(); - initOscillators(); - si5351_set_calibration(globalSettings.oscillatorCal); - setFrequency(GetActiveVfoFreq()); - - //debounce and delay - while(btnDown()) - active_delay(50); - active_delay(100); -} - -void setupBFO(){ - displayDialog(F("Set BFO"),F("Press TUNE to Save")); - - si5351bx_setfreq(0, globalSettings.usbCarrierFreq); - printCarrierFreq(globalSettings.usbCarrierFreq); - - while (!btnDown()){ - int knob = enc_read(); - if(knob != 0){ - globalSettings.usbCarrierFreq -= 50 * knob; - } - else{ - continue; //don't update the frequency or the display - } - - si5351bx_setfreq(0, globalSettings.usbCarrierFreq); - setFrequency(GetActiveVfoFreq()); - printCarrierFreq(globalSettings.usbCarrierFreq); - - active_delay(100); - } - - SaveSettingsToEeprom(); - si5351bx_setfreq(0, globalSettings.usbCarrierFreq); - setFrequency(GetActiveVfoFreq()); -} - -void setupCwDelay(){ - int knob = 0; - int prev_cw_delay; - - displayDialog(F("Set CW T/R Delay"),F("Press tune to Save")); - - active_delay(500); - prev_cw_delay = globalSettings.cwActiveTimeoutMs; - - ltoa(globalSettings.cwActiveTimeoutMs, b, 10); - strcat_P(b,(const char*)F(" msec")); - 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()){ - knob = enc_read(); - - if (knob < 0 && globalSettings.cwActiveTimeoutMs > 100) - globalSettings.cwActiveTimeoutMs -= 100; - else if (knob > 0 && globalSettings.cwActiveTimeoutMs < 1000) - globalSettings.cwActiveTimeoutMs += 100; - else - continue; //don't update the frequency or the display - - ltoa(globalSettings.cwActiveTimeoutMs, b, 10); - strcat_P(b,(const char*)F(" msec")); - 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); - - } - - SaveSettingsToEeprom(); - active_delay(500); - setupExit(); -} - -void setupKeyer(){ - displayDialog(F("Set CW Keyer"),F("Press tune to Save")); - - if(KeyerMode_e::KEYER_STRAIGHT == globalSettings.keyerMode){ - strcpy_P(c,(const char*)F("< Hand Key >")); - 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); - } - else if(KeyerMode_e::KEYER_IAMBIC_A == globalSettings.keyerMode){ - strcpy_P(c,(const char*)F("< Iambic A >")); - 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); - } - else{ - strcpy_P(c,(const char*)F("< Iambic B >")); - 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); - } - - int knob = 0; - uint32_t tmp_mode = globalSettings.keyerMode; - while (!btnDown()) - { - knob = enc_read(); - if(knob == 0){ - active_delay(50); continue; } - if(knob < 0 && tmp_mode > KeyerMode_e::KEYER_STRAIGHT){ - tmp_mode--; - } - if(knob > 0 && tmp_mode < KeyerMode_e::KEYER_IAMBIC_B){ - tmp_mode++; + + const long int candidate_value = raw_value / (int32_t)screen.KnobDivider; + long int value = 0; + screen.Validate(candidate_value,&value); + + //If we're going out of bounds, prevent the raw value from going too far out + if(candidate_value != value){ + raw_value = value * (int32_t)screen.KnobDivider; } - if (KeyerMode_e::KEYER_STRAIGHT == tmp_mode){ - strcpy_P(c,(const char*)F("< Hand Key >")); - 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); + if(value == last_value){ + continue; } - else if(KeyerMode_e::KEYER_IAMBIC_A == tmp_mode){ - strcpy_P(c,(const char*)F("< Iambic A >")); - 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); - } - else if (KeyerMode_e::KEYER_IAMBIC_B == tmp_mode){ - strcpy_P(c,(const char*)F("< Iambic B >")); - 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); + else{ + screen.OnValueChange(value,b,sizeof(b)); + 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; } } - active_delay(500); + screen.Finalize(last_value); +} - globalSettings.keyerMode = tmp_mode; +#define LIMIT(val,min,max) ((val) < (min)) ? (min) : (((max) < (val)) ? (max) : (val)) + +//Local Oscillator +void ssLocalOscInitialize(long int* start_value_out){ + { + uint32_t freq = GetActiveVfoFreq(); + freq = (freq/1000L) * 1000L;//round off the current frequency the nearest kHz + setFrequency(freq); + si5351bx_setfreq(0, globalSettings.usbCarrierFreq); //set back the carrier oscillator, cw tx switches it off + } + *start_value_out = globalSettings.oscillatorCal; +} +void ssLocalOscValidate(const long int candidate_value_in, long int* validated_value_out) +{ + *validated_value_out = candidate_value_in;//No check - allow anything +} +void ssLocalOscChange(const long int new_value, char* buff_out, const size_t buff_out_size) +{ + si5351_set_calibration(new_value); + setFrequency(GetActiveVfoFreq()); + const long int u = abs(new_value); + if(new_value != u){ + strncpy_P(buff_out,(const char*)F("-"),buff_out_size); + ++buff_out; + } + formatFreq(u,buff_out,buff_out_size - strlen(buff_out)); + strncat_P(buff_out,(const char*)F("Hz"),buff_out_size - strlen(buff_out)); +} +void ssLocalOscFinalize(const long int final_value) +{ + globalSettings.oscillatorCal = final_value; SaveSettingsToEeprom(); - - setupExit(); + si5351_set_calibration(globalSettings.oscillatorCal); + setFrequency(GetActiveVfoFreq()); } - -const char MI_SET_FREQ [] PROGMEM = "Set Freq..."; -const char MI_SET_BFO [] PROGMEM = "Set BFO..."; -const char MI_CW_DELAY [] PROGMEM = "CW Delay..."; -const char MI_CW_KEYER [] PROGMEM = "CW Keyer..."; -const char MI_TOUCH [] PROGMEM = "Touch Screen..."; -const char MI_EXIT [] PROGMEM = "Exit"; - -enum MenuIds { - MENU_SET_FREQ, - MENU_SET_BFO, - MENU_CW_DELAY, - MENU_CW_KEYER, - MENU_TOUCH, - MENU_EXIT, - MENU_TOTAL +const char SS_LOCAL_OSC_T [] PROGMEM = "Local Oscillator"; +const char SS_LOCAL_OSC_A [] PROGMEM = "Exit menu, tune so that the\ndial displays the desired freq,\nthen tune here until the\nsignal is zerobeat"; +const SettingScreen_t ssLocalOsc PROGMEM = { + SS_LOCAL_OSC_T, + SS_LOCAL_OSC_A, + 1, + 875, + ssLocalOscInitialize, + ssLocalOscValidate, + ssLocalOscChange, + ssLocalOscFinalize }; +void runLocalOscSetting(){runSetting(&ssLocalOsc);} -const char* const menuItems [MENU_TOTAL] PROGMEM { - MI_SET_FREQ, - MI_SET_BFO, - MI_CW_DELAY, - MI_CW_KEYER, - MI_TOUCH, - MI_EXIT +//BFO +void ssBfoInitialize(long int* start_value_out){ + si5351bx_setfreq(0, globalSettings.usbCarrierFreq); + *start_value_out = globalSettings.usbCarrierFreq; +} +void ssBfoValidate(const long int candidate_value_in, long int* validated_value_out) +{ + *validated_value_out = LIMIT(candidate_value_in,11048000L,11060000L); +} +void ssBfoChange(const long int new_value, char* buff_out, const size_t buff_out_size) +{ + globalSettings.usbCarrierFreq = new_value; + setFrequency(GetActiveVfoFreq()); + si5351bx_setfreq(0, new_value); + formatFreq(new_value,buff_out,buff_out_size); + strncat_P(buff_out,(const char*)F("Hz"),buff_out_size - strlen(buff_out)); +} +void ssBfoFinalize(const long int final_value) +{ + globalSettings.usbCarrierFreq = final_value; + SaveSettingsToEeprom(); + si5351bx_setfreq(0, globalSettings.usbCarrierFreq); + setFrequency(GetActiveVfoFreq()); +} +const char SS_BFO_T [] PROGMEM = "Beat Frequency Osc (BFO)"; +const char SS_BFO_A [] PROGMEM = "Exit menu, tune to an unused\nfrequency, then tune here\nuntil the audio is between\n300-3000Hz"; +const SettingScreen_t ssBfo PROGMEM = { + SS_BFO_T, + SS_BFO_A, + 1, + -50,//Negative to make dial more intuitive: turning clockwise increases the perceived audio frequency + ssBfoInitialize, + ssBfoValidate, + ssBfoChange, + ssBfoFinalize }; +void runBfoSetting(){runSetting(&ssBfo);} -void drawSetupMenu(){ - displayClear(COLOR_BACKGROUND); - strcpy_P(b,(const char*)F("Setup")); - 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 = 0; i < MENU_TOTAL; ++i){ - strcpy_P(b,(const char*)pgm_read_word(&(menuItems[i]))); - displayText(b, LAYOUT_ITEM_X, LAYOUT_ITEM_Y + i*LAYOUT_ITEM_PITCH_Y, LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_INACTIVE_BORDER); +//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) +{ + *start_value_out = globalSettings.cwSideToneFreq; +} +void ssCwToneValidate(const long int candidate_value_in, long int* validated_value_out) +{ + *validated_value_out = LIMIT(candidate_value_in,100,2000); +} +void 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); + strncat_P(buff_out,(const char*)F("Hz"),buff_out_size - strlen(buff_out)); +} +void ssCwToneFinalize(const long int final_value) +{ + noTone(CW_TONE); + globalSettings.cwSideToneFreq = final_value; + SaveSettingsToEeprom(); +} +const char SS_CW_TONE_T [] PROGMEM = "CW Tone Frequency"; +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, + SS_CW_TONE_A, + 1, + 10, + ssCwToneInitialize, + ssCwToneValidate, + ssCwToneChange, + ssCwToneFinalize +}; +void runToneSetting(){runSetting(&ssTone);} + +//CW Switch Delay +void ssCwSwitchDelayInitialize(long int* start_value_out) +{ + *start_value_out = globalSettings.cwActiveTimeoutMs; +} +void ssCwSwitchDelayValidate(const long int candidate_value_in, long int* validated_value_out) +{ + *validated_value_out = LIMIT(candidate_value_in,100,1000); +} +void ssCwSwitchDelayChange(const long int new_value, char* buff_out, const size_t buff_out_size) +{ + ltoa(new_value,buff_out,10); + strncat_P(buff_out,(const char*)F("ms"),buff_out_size - strlen(buff_out)); +} +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_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, + SS_CW_SWITCH_A, + 1, + 100, + ssCwSwitchDelayInitialize, + ssCwSwitchDelayValidate, + ssCwSwitchDelayChange, + ssCwSwitchDelayFinalize +}; +void runCwSwitchDelaySetting(){runSetting(&ssCwSwitchDelay);} + +//CW Keyer +void ssKeyerInitialize(long int* start_value_out) +{ + *start_value_out = globalSettings.keyerMode; +} +void ssKeyerValidate(const long int candidate_value_in, long int* validated_value_out) +{ + *validated_value_out = LIMIT(candidate_value_in,KeyerMode_e::KEYER_STRAIGHT,KeyerMode_e::KEYER_IAMBIC_B); +} +void ssKeyerChange(const long int new_value, char* buff_out, const size_t buff_out_size) +{ + if(KeyerMode_e::KEYER_STRAIGHT == new_value){ + strncpy_P(buff_out,(const char*)F("< Hand Key >"),buff_out_size); + } + else if(KeyerMode_e::KEYER_IAMBIC_A == new_value){ + strncpy_P(buff_out,(const char*)F("< Iambic A >"),buff_out_size); + } + else{ + strncpy_P(buff_out,(const char*)F("< Iambic B >"),buff_out_size); } } +void ssKeyerFinalize(const long int final_value) +{ + globalSettings.keyerMode = final_value; + SaveSettingsToEeprom(); +} +const char SS_KEYER_T [] PROGMEM = "CW Keyer/Paddle Type"; +const char SS_KEYER_A [] PROGMEM = "Select which type of\nkeyer/paddle is being used"; +const SettingScreen_t ssKeyer PROGMEM = { + SS_KEYER_T, + SS_KEYER_A, + 10, + 1, + ssKeyerInitialize, + ssKeyerValidate, + ssKeyerChange, + ssKeyerFinalize +}; +void runKeyerSetting(){runSetting(&ssKeyer);} -void movePuck(int i){ - static int prevPuck = 1;//Start value at 1 so that on init, when we get called with 0, we'll update +//Reset all settings +void ssResetAllInitialize(long int* start_value_out) +{ + *start_value_out = 0;//Default to NOT resetting +} +void ssResetAllValidate(const long int candidate_value_in, long int* validated_value_out) +{ + *validated_value_out = LIMIT(candidate_value_in,0,1); +} +void ssResetAllChange(const long int new_value, char* buff_out, const size_t buff_out_size) +{ + if(new_value){ + strncpy_P(buff_out,(const char*)F("Yes"),buff_out_size); + } + else{ + strncpy_P(buff_out,(const char*)F("No"),buff_out_size); + } +} +void ssResetAllFinalize(const long int final_value) +{ + if(final_value){ + LoadDefaultSettings(); + SaveSettingsToEeprom(); + setup(); + } +} +const char SS_RESET_ALL_T [] PROGMEM = "Reset All Cals/Settings"; +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, + SS_RESET_ALL_A, + 20, + 1, + ssResetAllInitialize, + ssResetAllValidate, + ssResetAllChange, + ssResetAllFinalize +}; +void runResetAllSetting(){runSetting(&ssResetAll);} +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"; +const char MI_TOUCH [] PROGMEM = "Touch Screen"; +const MenuItem_t calibrationMenu [] PROGMEM { + {MT_CAL,nullptr},//Title + {SS_LOCAL_OSC_T,runLocalOscSetting}, + {SS_BFO_T,runBfoSetting}, + {MI_TOUCH,setupTouch}, +}; +void runCalibrationMenu(){RUN_MENU(calibrationMenu);} + +const char MT_CW [] PROGMEM = "CW/Morse 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}, +}; +void runCwMenu(){RUN_MENU(cwMenu);} + +const char MT_SETTINGS [] PROGMEM = "Settings"; +const MenuItem_t mainMenu [] PROGMEM { + {MT_SETTINGS,nullptr},//Title + {MT_CAL,runCalibrationMenu}, + {MT_CW,runCwMenu}, + {SS_RESET_ALL_T,runResetAllSetting}, +}; + +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) +{ + displayClear(COLOR_BACKGROUND); + MenuItem_t mi = {"",nullptr}; + memcpy_P(&mi,&items[0],sizeof(mi)); + strncpy_P(b,mi.ItemName,sizeof(b)); + 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)); + strncpy_P(b,mi.ItemName,sizeof(b)); + 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); + } + 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); +} + +void movePuck(unsigned int old_index, unsigned int new_index) +{ //Don't update if we're already on the right selection - if(prevPuck == i){ + if(old_index == new_index){ return; } - - //Clear old - displayRect(LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (prevPuck*LAYOUT_ITEM_PITCH_Y), LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_INACTIVE_BORDER); + 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); + } //Draw new - displayRect(LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (i*LAYOUT_ITEM_PITCH_Y), LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_ACTIVE_BORDER); - prevPuck = i; - + displayRect(LAYOUT_ITEM_X, LAYOUT_ITEM_Y + (new_index*LAYOUT_ITEM_PITCH_Y), LAYOUT_ITEM_WIDTH, LAYOUT_ITEM_HEIGHT, COLOR_ACTIVE_BORDER); } -void doSetup2(){ +void runMenu(const MenuItem_t* const menu_items, const uint16_t num_items) +{ static const unsigned int COUNTS_PER_ITEM = 10; - int select=0, i, btnState; + const unsigned int MAX_KNOB_VALUE = num_items*COUNTS_PER_ITEM - 1; + int knob_sum = 0; + unsigned int old_index = 0; - drawSetupMenu(); - movePuck(select); + drawMenu(menu_items,num_items); + movePuck(1,0);//Force draw of puck //wait for the button to be raised up - while(btnDown()) + while(btnDown()){ active_delay(50); + } active_delay(50); //debounce - - menuOn = 2; - while (menuOn){ - i = enc_read(); + while (true){ + knob_sum += enc_read(); + if(knob_sum < 0){ + knob_sum = 0; + } + else if(MAX_KNOB_VALUE < knob_sum){ + knob_sum = MAX_KNOB_VALUE; + } - if (i > 0){ - if (select + i < MENU_TOTAL*COUNTS_PER_ITEM) - select += i; - movePuck(select/COUNTS_PER_ITEM); - } - if (i < 0 && select + i >= 0){ - select += i; //caught ya, i is already -ve here, so you add it - movePuck(select/COUNTS_PER_ITEM); - } + uint16_t index = knob_sum/COUNTS_PER_ITEM; + movePuck(old_index,index); + old_index = index; if (!btnDown()){ active_delay(50); @@ -338,50 +515,28 @@ void doSetup2(){ while(btnDown()){ active_delay(50); } - active_delay(300); + active_delay(50);//debounce - switch(select/COUNTS_PER_ITEM){ - case MENU_SET_FREQ: - { - setupFreq(); - break; - } - case MENU_SET_BFO: - { - setupBFO(); - break; - } - case MENU_CW_DELAY: - { - setupCwDelay(); - break; - } - case MENU_CW_KEYER: - { - setupKeyer(); - break; - } - case MENU_TOUCH: - { - setupTouch(); - break; - } - case MENU_EXIT: - default: - { - menuOn = 0; - break; - } - }//switch - //redraw - drawSetupMenu(); + 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; + } } //debounce the button - while(btnDown()) + while(btnDown()){ active_delay(50); - active_delay(50); + } + active_delay(50);//debounce +} - checkCAT(); +void doSetup2(){ + RUN_MENU(mainMenu); guiUpdate(); } diff --git a/setup.h b/setup.h new file mode 100644 index 0000000..16b5b0d --- /dev/null +++ b/setup.h @@ -0,0 +1,6 @@ +#pragma once + +void doSetup2(); //main setup function, displays the setup menu, calls various dialog boxes +void setupTouch(); +void runLocalOscSetting(); +void runBfoSetting(); \ No newline at end of file diff --git a/ubitx.h b/ubitx.h index 3944a6d..0800e75 100644 --- a/ubitx.h +++ b/ubitx.h @@ -56,7 +56,7 @@ it uses an ILI9341 display controller and an XPT2046 touch controller. * the input and output from the USB port. We must keep a count of the bytes used while reading * the serial port as we can easily run out of buffer space. This is done in the serial_in_count variable. */ -extern char c[30], b[30]; +extern char c[30], b[128]; /** * The second set of 16 pins on the Raduino's bottom connector are have the three clock outputs and the digital lines to control the rig. @@ -92,10 +92,6 @@ extern char c[30], b[30]; #define HIGHEST_FREQ (30000000l) static const uint32_t THRESHOLD_USB_LSB = 10000000L; -extern unsigned long firstIF; - -extern uint8_t menuOn; - /* these are functions implemented in the main file named as ubitx_xxx.ino */ void active_delay(int delay_by); void saveVFOs(); @@ -122,11 +118,6 @@ void drawTx(); //are useful to concatanate the values with text like "Set Freq to " x " KHz" int getValueByKnob(int minimum, int maximum, int step_size, int initial, char* prefix, char *postfix); -//functions of the setup menu. implemented in seteup.cpp -void doSetup2(); //main setup function, displays the setup menu, calls various dialog boxes -void setupBFO(); -void setupFreq(); - //main functions to check if any button is pressed and other user interface events void doCommands(); //does the commands with encoder to jump from button to button void checkTouch(); //does the commands with a touch on the buttons diff --git a/ubitx_cat.cpp b/ubitx_cat.cpp index 815c18b..91c7f49 100644 --- a/ubitx_cat.cpp +++ b/ubitx_cat.cpp @@ -123,13 +123,6 @@ void catReadEEPRom(void) //for remove warnings byte temp0 = cat[0]; byte temp1 = cat[1]; -/* - itoa((int) cat[0], b, 16); - strcat(b, ":"); - itoa((int) cat[1], c, 16); - strcat(b, c); - printLine2(b); -*/ cat[0] = 0; cat[1] = 0; @@ -385,10 +378,6 @@ void processCATCommand2(byte* cmd) { default: //somehow, get this to print the four bytes ultoa(*((unsigned long *)cmd), c, 16); - /*itoa(cmd[4], b, 16); - strcat(b, ">"); - strcat(b, c); - printLine2(b);*/ response[0] = 0x00; Serial.write(response[0]); } diff --git a/ubitx_ui.cpp b/ubitx_ui.cpp index 5e4e52b..624705f 100644 --- a/ubitx_ui.cpp +++ b/ubitx_ui.cpp @@ -1,7 +1,7 @@ #include -#include #include "morse.h" #include "settings.h" +#include "setup.h" #include "ubitx.h" #include "nano_gui.h" @@ -65,8 +65,8 @@ enum btn_set_e { BUTTON_17, BUTTON_15, BUTTON_10, - BUTTON_WPM, - BUTTON_TON, + BUTTON_BLANK_1, + BUTTON_MNU, BUTTON_FRQ, BUTTON_TOTAL }; @@ -85,7 +85,7 @@ constexpr Button btn_set[BUTTON_TOTAL] PROGMEM = { {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", 'M'}, + {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 + 1*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_80, "80", '8'}, @@ -96,8 +96,8 @@ constexpr Button btn_set[BUTTON_TOTAL] PROGMEM = { {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_WPM, "WPM", 'W'}, - {LAYOUT_BUTTON_X + 3*LAYOUT_BUTTON_PITCH_X, LAYOUT_BUTTON_Y + 2*LAYOUT_BUTTON_PITCH_Y, LAYOUT_BUTTON_WIDTH, LAYOUT_BUTTON_HEIGHT, BUTTON_TON, "TON", 'T'}, + {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, "MNU", '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'}, }; @@ -165,10 +165,10 @@ int getValueByKnob(int minimum, int maximum, int step_size, int initial, const active_delay(200); knob_value = initial; - strcpy_P(b,(const char*)prefix); + strncpy_P(b,(const char*)prefix,sizeof(b)); itoa(knob_value, c, 10); - strcat(b, c); - strcat_P(b, (const char*)postfix); + strncat(b, c, sizeof(b) - strlen(b)); + strncat_P(b, (const char*)postfix, sizeof(b) - strlen(b)); drawCommandbar(b); while(!btnDown() && digitalRead(PTT) == HIGH){ @@ -179,10 +179,10 @@ int getValueByKnob(int minimum, int maximum, int step_size, int initial, const if (knob_value < maximum && knob > 0) knob_value += step_size; - strcpy_P(b,(const char*)prefix); + strncpy_P(b,(const char*)prefix,sizeof(b)); itoa(knob_value, c, 10); - strcat(b, c); - strcat_P(b,(const char*)postfix); + strncat(b, c, sizeof(b) - strlen(b)); + strncat_P(b,(const char*)postfix, sizeof(b) - strlen(b)); drawCommandbar(b); } checkCAT(); @@ -334,8 +334,8 @@ void displayRIT(){ c[0] = 0; displayFillrect(LAYOUT_MODE_TEXT_X,LAYOUT_MODE_TEXT_Y,LAYOUT_MODE_TEXT_WIDTH,LAYOUT_MODE_TEXT_HEIGHT, COLOR_BACKGROUND); if(globalSettings.ritOn){ - strcpy_P(c,(const char*)F("TX:")); - formatFreq(globalSettings.ritFrequency, c+3, sizeof(c)-3); + strncpy_P(c,(const char*)F("TX:"),sizeof(c)); + formatFreq(globalSettings.ritFrequency, c+3, sizeof(c)-strlen(c)); if (VFO_A == globalSettings.activeVfo) displayText(c, 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); else @@ -349,9 +349,9 @@ void fastTune(){ active_delay(50); active_delay(300); - strcpy_P(c,(const char*)F("Fast tune")); + 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); - while(1){ + while(true){ checkCAT(); //exit after debouncing the btnDown @@ -471,8 +471,8 @@ void enterFreq(){ }//switch }//if button hit test }// end of the button scanning loop - strcpy(b, c); - strcat_P(b,(const char*)F(" KHz")); + strncpy(b, c, sizeof(b)); + strncat_P(b,(const char*)F(" KHz"),sizeof(b) - strlen(b)); displayText(b, LAYOUT_MODE_TEXT_X, LAYOUT_MODE_TEXT_Y, LAYOUT_MODE_TEXT_WIDTH, LAYOUT_MODE_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND); active_delay(300); while(readTouch()) @@ -481,21 +481,21 @@ void enterFreq(){ } void drawCWStatus(){ - strcpy_P(b,(const char*)F(" cw: ")); + strncpy_P(b,(const char*)F(" cw: "),sizeof(b)); int wpm = 1200/globalSettings.cwDitDurationMs; itoa(wpm,c, 10); - strcat(b, c); - strcat_P(b,(const char*)F("wpm, ")); + strncat(b, c, sizeof(b) - strlen(b)); + strncat_P(b,(const char*)F("wpm, "), sizeof(b) - strlen(b)); itoa(globalSettings.cwSideToneFreq, c, 10); - strcat(b, c); - strcat_P(b,(const char*)F("hz")); + strncat(b, c, sizeof(b) - strlen(b)); + strncat_P(b,(const char*)F("hz"), sizeof(b) - strlen(b)); displayText(b, LAYOUT_CW_TEXT_X, LAYOUT_CW_TEXT_Y, LAYOUT_CW_TEXT_WIDTH, LAYOUT_CW_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND); } void drawTx(){ if (globalSettings.txActive){ - strcpy_P(b,(const char*)F("TX")); + 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); } else{ @@ -808,65 +808,6 @@ void switchBand(uint32_t bandfreq){ saveVFOs(); } -void setCwSpeed() -{ - int wpm = 1200/globalSettings.cwDitDurationMs; - - wpm = getValueByKnob(1, 100, 1, wpm,F("CW: "),F(" WPM")); - - globalSettings.cwDitDurationMs = 1200/wpm; - SaveSettingsToEeprom(); - active_delay(500); - drawStatusbar(); - //printLine2(""); - //updateDisplay(); -} - -void setCwTone(){ - int knob = 0; - int prev_sideTone; - - tone(CW_TONE, globalSettings.cwSideToneFreq); - itoa(globalSettings.cwSideToneFreq, c, 10); - strcpy_P(b,(const char*)F("CW Tone: ")); - strcat(b, c); - strcat_P(b,(const char*)F(" Hz")); - drawCommandbar(b); - - //disable all clock 1 and clock 2 - while (digitalRead(PTT) == HIGH && !btnDown()) - { - 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, c, 10); - strcpy_P(b,(const char*)F("CW Tone: ")); - strcat(b, c); - strcat_P(b,(const char*)F(" Hz")); - drawCommandbar(b); - //printLine2(b); - - checkCAT(); - active_delay(20); - } - noTone(CW_TONE); - - SaveSettingsToEeprom(); - - b[0] = 0; - drawCommandbar(b); - drawStatusbar(); - //printLine2(""); - //updateDisplay(); -} - void doCommand(Button* button){ //Serial.print(F("Doing command: ")); //Serial.print(button->text); @@ -957,14 +898,9 @@ void doCommand(Button* button){ enterFreq(); break; } - case BUTTON_WPM: + case BUTTON_MNU: { - setCwSpeed(); - break; - } - case BUTTON_TON: - { - setCwTone(); + doSetup2(); break; } default: @@ -1017,20 +953,17 @@ void drawFocus(int ibtn, int color){ } void doCommands(){ - int select=0, i, prevButton, btnState; + int select = 0; + int prev_button = 0; //wait for the button to be raised up while(btnDown()) active_delay(50); active_delay(50); //debounce - menuOn = 2; - - while (menuOn){ - + while (true){ //check if the knob's button was pressed - btnState = btnDown(); - if (btnState){ + if (btnDown()){ Button button; memcpy_P(&button, &(btn_set[select/10]), sizeof(Button)); @@ -1050,27 +983,27 @@ void doCommands(){ return; } - i = enc_read(); + int knob = enc_read(); - if (i == 0){ + if (knob == 0){ active_delay(50); continue; } - if (i > 0){ - if (select + i < BUTTON_TOTAL * 10) - select += i; + if (knob > 0){ + if (select + knob < BUTTON_TOTAL * 10) + select += knob; } - if (i < 0 && select + i >= 0) - select += i; //caught ya, i is already -ve here, so you add it + if (knob < 0 && select + knob >= 0) + select += knob; //caught ya, i is already -ve here, so you add it - if (prevButton == select / 10) + if (prev_button == select / 10) continue; //we are on a new button - drawFocus(prevButton, COLOR_INACTIVE_BORDER); + drawFocus(prev_button, COLOR_INACTIVE_BORDER); drawFocus(select/10, COLOR_ACTIVE_BORDER); - prevButton = select/10; + prev_button = select/10; } // guiUpdate(); diff --git a/ubitx_v6.3.1_code.ino b/ubitx_v6.3.1_code.ino index 8871f4f..617977e 100644 --- a/ubitx_v6.3.1_code.ino +++ b/ubitx_v6.3.1_code.ino @@ -31,6 +31,7 @@ */ #include #include "settings.h" +#include "setup.h" #include "ubitx.h" #include "nano_gui.h" @@ -40,16 +41,16 @@ * created in a memory region called the stack. The stack has just a few bytes of space on the Arduino * if you declare large strings inside functions, they can easily exceed the capacity of the stack * and mess up your programs. - * We circumvent this by declaring a few global buffers as kitchen counters where we can + * We circumvent this by declaring a few global buffers as kitchen counters where we can * slice and dice our strings. These strings are mostly used to control the display or handle * the input and output from the USB port. We must keep a count of the bytes used while reading * the serial port as we can easily run out of buffer space. This is done in the serial_in_count variable. */ -char c[30], b[30]; +char b[128]; +char c[30]; //during CAT commands, we will freeeze the display until CAT is disengaged unsigned char doingCAT = 0; -byte menuOn = 0; //set to 1 when the menu is being displayed, if a menu item sets it to zero, the menu is exited /** @@ -463,7 +464,7 @@ void initPorts(){ void setup() { Serial.begin(38400); - Serial.flush(); + Serial.flush(); initSettings(); displayInit(); @@ -473,13 +474,14 @@ void setup() //Run initial calibration routine if button is pressed during power up if(btnDown()){ + LoadDefaultSettings(); setupTouch(); SetActiveVfoMode(VfoMode_e::VFO_MODE_USB); - setFrequency(10000000l); - setupFreq(); + setFrequency(10000000L); + runLocalOscSetting(); SetActiveVfoMode(VfoMode_e::VFO_MODE_LSB); - setFrequency(7100000l); - setupBFO(); + setFrequency(7100000L); + runBfoSetting(); } guiUpdate();