#include #include "button.h" #include "color_theme.h" #include "morse.h" #include "nano_gui.h" #include "settings.h" #include "setup.h" #include "ubitx.h" #include "version.h" static const unsigned int LAYOUT_VFO_LABEL_X = 0; static const unsigned int LAYOUT_VFO_LABEL_Y = 10; static const unsigned int LAYOUT_VFO_LABEL_WIDTH = 159; static const unsigned int LAYOUT_VFO_LABEL_HEIGHT = 36; static const unsigned int LAYOUT_VFO_LABEL_PITCH_X = 160; static const unsigned int LAYOUT_MODE_TEXT_X = 0; static const unsigned int LAYOUT_MODE_TEXT_Y = LAYOUT_VFO_LABEL_Y + LAYOUT_VFO_LABEL_HEIGHT + 1; static const unsigned int LAYOUT_MODE_TEXT_WIDTH = 320; static const unsigned int LAYOUT_MODE_TEXT_HEIGHT = 36; static const unsigned int LAYOUT_BUTTON_X = 2; static const unsigned int LAYOUT_BUTTON_Y = LAYOUT_MODE_TEXT_Y + LAYOUT_MODE_TEXT_HEIGHT + 1; static const unsigned int LAYOUT_BUTTON_WIDTH = 60; static const unsigned int LAYOUT_BUTTON_HEIGHT = 36; static const unsigned int LAYOUT_BUTTON_PITCH_X = 64; static const unsigned int LAYOUT_BUTTON_PITCH_Y = 40; static const unsigned int LAYOUT_CW_TEXT_X = 0; static const unsigned int LAYOUT_CW_TEXT_Y = LAYOUT_BUTTON_Y + 3*LAYOUT_BUTTON_PITCH_Y + 1; static const unsigned int LAYOUT_CW_TEXT_WIDTH = 220; static const unsigned int LAYOUT_CW_TEXT_HEIGHT = 36; static const unsigned int LAYOUT_VERSION_TEXT_X = LAYOUT_CW_TEXT_X + LAYOUT_CW_TEXT_WIDTH + 1; static const unsigned int LAYOUT_VERSION_TEXT_Y = LAYOUT_CW_TEXT_Y; static const unsigned int LAYOUT_VERSION_TEXT_WIDTH = 320 - LAYOUT_CW_TEXT_WIDTH - 1; static const unsigned int LAYOUT_VERSION_TEXT_HEIGHT = LAYOUT_CW_TEXT_HEIGHT; static const unsigned int LAYOUT_TX_X = 280; static const unsigned int LAYOUT_TX_Y = LAYOUT_MODE_TEXT_Y; static const unsigned int LAYOUT_TX_WIDTH = 40; static const unsigned int LAYOUT_TX_HEIGHT = 36; enum btn_set_e { BUTTON_VFOA, BUTTON_VFOB, BUTTON_RIT, BUTTON_USB, BUTTON_LSB, BUTTON_CW, BUTTON_SPL, BUTTON_80, BUTTON_40, BUTTON_30, BUTTON_20, BUTTON_17, BUTTON_15, BUTTON_10, BUTTON_BLANK_1, BUTTON_MNU, BUTTON_FRQ, BUTTON_TOTAL }; 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', 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', 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', 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', 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 enum keypad_e { KEYS_1 = KEYS_OFFSET, KEYS_2, KEYS_3, KEYS_BLANK_1, KEYS_OK, KEYS_4, KEYS_5, KEYS_6, KEYS_0, KEYS_BACKSPACE, KEYS_7, KEYS_8, KEYS_9, KEYS_BLANK_2, KEYS_CANCEL, 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', 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', 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', 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){ if(BUTTON_TOTAL == index){ return false; } memcpy_P(button, &(btn_set[index]), sizeof(Button)); return true; } inline void drawCommandbar(char* text){ displayText(text, LAYOUT_MODE_TEXT_X, LAYOUT_MODE_TEXT_Y, LAYOUT_MODE_TEXT_WIDTH, LAYOUT_MODE_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND); } /** A generic control to read variable values */ int getValueByKnob(int minimum, int maximum, int step_size, int initial, const __FlashStringHelper* prefix, const __FlashStringHelper* postfix) { int knob = 0; int knob_value; while (btnDown()) active_delay(100); active_delay(200); knob_value = initial; strncpy_P(b,(const char*)prefix,sizeof(b)); itoa(knob_value, c, 10); strncat(b, c, sizeof(b) - strlen(b)); strncat_P(b, (const char*)postfix, sizeof(b) - strlen(b)); drawCommandbar(b); while(!btnDown() && digitalRead(PTT) == HIGH){ knob = enc_read(); if (knob != 0){ if (knob_value > minimum && knob < 0) knob_value -= step_size; if (knob_value < maximum && knob > 0) knob_value += step_size; strncpy_P(b,(const char*)prefix,sizeof(b)); itoa(knob_value, c, 10); strncat(b, c, sizeof(b) - strlen(b)); strncat_P(b,(const char*)postfix, sizeof(b) - strlen(b)); drawCommandbar(b); } checkCAT(); } b[0] = 0; drawCommandbar(b); return knob_value; } void displayVFO(Vfo_e vfo){ uint16_t displayColor = COLOR_INACTIVE_TEXT; uint16_t displayBackground = COLOR_INACTIVE_BACKGROUND; uint16_t displayBorder = COLOR_INACTIVE_BORDER; Button button; if (globalSettings.splitOn){ if (vfo == globalSettings.activeVfo){ c[0] = 'R'; } else{ c[0] = 'T'; } } else{ if(VFO_A == vfo){ c[0] = 'A'; } else if(VFO_B == vfo){ c[0] = 'B'; } else{ c[0] = '?'; } } c[1] = ':'; c[2] = ' '; if (VFO_A == vfo){ getButton(BUTTON_VFOA, &button); formatFreq(globalSettings.vfoA.frequency, c+3, sizeof(c)-3, 10); if (VFO_A == globalSettings.activeVfo){ displayColor = COLOR_ACTIVE_VFO_TEXT; displayBackground = COLOR_ACTIVE_VFO_BACKGROUND; displayBorder = COLOR_ACTIVE_BORDER; }else{ displayColor = COLOR_INACTIVE_VFO_TEXT; displayBackground = COLOR_INACTIVE_VFO_BACKGROUND; displayBorder = COLOR_INACTIVE_BORDER; } } if (VFO_B == vfo){ getButton(BUTTON_VFOB, &button); formatFreq(globalSettings.vfoB.frequency, c+3, sizeof(c)-3, 10); if (VFO_B == globalSettings.activeVfo){ displayColor = COLOR_ACTIVE_VFO_TEXT; displayBackground = COLOR_ACTIVE_VFO_BACKGROUND; displayBorder = COLOR_ACTIVE_BORDER; } else { displayColor = COLOR_INACTIVE_VFO_TEXT; displayBackground = COLOR_INACTIVE_VFO_BACKGROUND; displayBorder = COLOR_INACTIVE_BORDER; } } displayText(c, button.x, button.y, button.w, button.h, displayColor, displayBackground, displayBorder); } void btnDrawActive(Button* button){ displayText(button->text, button->x, button->y, button->w, button->h, COLOR_ACTIVE_TEXT, COLOR_ACTIVE_BACKGROUND, COLOR_INACTIVE_BORDER); } void btnDrawInactive(Button* button){ displayText(button->text, button->x, button->y, button->w, button->h, COLOR_INACTIVE_TEXT, COLOR_INACTIVE_BACKGROUND, COLOR_INACTIVE_BORDER); } void btnDraw(struct Button *button){ switch(button->id){ case BUTTON_VFOA: { displayVFO(VFO_A); break; } case BUTTON_VFOB: { displayVFO(VFO_B); break; } case BUTTON_RIT: { if(globalSettings.ritOn){ btnDrawActive(button); } else{ btnDrawInactive(button); } break; } case BUTTON_USB: { if(VFO_MODE_USB == GetActiveVfoMode()){ btnDrawActive(button); } else{ btnDrawInactive(button); } break; } case BUTTON_LSB: { if(VFO_MODE_LSB == GetActiveVfoMode()){ btnDrawActive(button); } else{ btnDrawInactive(button); } break; } case BUTTON_SPL: { if(globalSettings.splitOn){ btnDrawActive(button); } else{ btnDrawInactive(button); } break; } case BUTTON_CW: { if(TuningMode_e::TUNE_CW == globalSettings.tuningMode){ btnDrawActive(button); } else{ btnDrawInactive(button); } break; } default: { btnDrawInactive(button); break; } }//End switch } 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){ 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 displayText(c, LAYOUT_VFO_LABEL_X + 1*LAYOUT_VFO_LABEL_PITCH_X, LAYOUT_MODE_TEXT_Y, LAYOUT_VFO_LABEL_WIDTH, LAYOUT_MODE_TEXT_HEIGHT, COLOR_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND); } } void fastTune(){ //if the btn is down, wait until it is up while(btnDown()) active_delay(50); 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); while(true){ checkCAT(); //exit after debouncing the btnDown if (btnDown()){ displayFillrect(LAYOUT_MODE_TEXT_X, LAYOUT_MODE_TEXT_Y, LAYOUT_MODE_TEXT_WIDTH, LAYOUT_MODE_TEXT_HEIGHT, COLOR_BACKGROUND); //wait until the button is realsed and then return while(btnDown()) active_delay(50); active_delay(50); return; } int encoder = enc_read(); if (encoder != 0){ uint32_t freq = GetActiveVfoFreq(); if (encoder > 0 && freq < 30000000l){ freq += 50000l; } else if (encoder < 0 && freq > 600000l){ freq -= 50000l; } setFrequency(freq); displayVFO(globalSettings.activeVfo); } }// end of the event loop } void enterFreq(){ //force the display to refresh everything //display all the buttons for (int i = 0; i < KEYS_TOTAL; i++){ Button button; memcpy_P(&button, &(keypad[i]), sizeof(Button)); btnDraw(&button); } while(btnDown()) active_delay(50); active_delay(50); int cursor_pos = 0; memset(c, 0, sizeof(c)); bool exit = false; while(!exit){ checkCAT(); if(btnDown()){ while(btnDown()) active_delay(50); active_delay(50); break; } if(!readTouch(&ts_point)) continue; scaleTouch(&ts_point); for (int i = 0; i < KEYS_TOTAL; i++){ Button button; memcpy_P(&button, &(keypad[i]), sizeof(Button)); int x2 = button.x + button.w; int y2 = button.y + button.h; if(button.x < ts_point.x && ts_point.x < x2 && button.y < ts_point.y && ts_point.y < y2){ //Serial.print(F("Entered key: ")); //Serial.println(button.text); switch(button.id){ case KEYS_OK: { uint32_t new_freq = atol(c); if((LOWEST_FREQ/1000 <= new_freq) && (new_freq <= HIGHEST_FREQ/1000)){ new_freq *= 1000L; uint32_t prev_freq = GetActiveVfoFreq(); //Transition from below to above the traditional threshold for USB if(prev_freq < THRESHOLD_USB_LSB && new_freq >= THRESHOLD_USB_LSB){ SetActiveVfoMode(VfoMode_e::VFO_MODE_USB); } //Transition from aboveo to below the traditional threshold for USB if(prev_freq >= THRESHOLD_USB_LSB && new_freq < THRESHOLD_USB_LSB){ SetActiveVfoMode(VfoMode_e::VFO_MODE_LSB); } if (VFO_A == globalSettings.activeVfo){ globalSettings.vfoA.frequency = new_freq; } else{ globalSettings.vfoB.frequency = new_freq; } setFrequency(new_freq); saveVFOs(); } exit = true; break; } case KEYS_BACKSPACE: { c[cursor_pos] = 0; if (cursor_pos > 0){ cursor_pos--; } c[cursor_pos] = 0; break; } case KEYS_CANCEL: { exit = true; break; } case KEYS_0: case KEYS_1: case KEYS_2: case KEYS_3: case KEYS_4: case KEYS_5: case KEYS_6: case KEYS_7: case KEYS_8: case KEYS_9: { c[cursor_pos++] = button.text[0]; c[cursor_pos] = 0; break; } default: { //Serial.print(F("Unknown key id: ")); //Serial.println(button.id); break; } }//switch }//if button hit test }// end of the button scanning loop 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(&ts_point)) checkCAT(); } // end of event loop : while(!exit) guiUpdate(); enc_read();//clear out any tuner turning that happened during entry } void drawCWStatus(){ strncpy_P(b,(const char*)F(" cw: "),sizeof(b)); int wpm = 1200/globalSettings.cwDitDurationMs; itoa(wpm,c, 10); strncat(b, c, sizeof(b) - strlen(b)); strncat_P(b,(const char*)F("wpm, "), sizeof(b) - strlen(b)); itoa(globalSettings.cwSideToneFreq, c, 10); 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, TextJustification_e::Left); } void drawVersion() { strncpy_P(b,VERSION_STRING,sizeof(b)); displayText(b, LAYOUT_VERSION_TEXT_X, LAYOUT_VERSION_TEXT_Y, LAYOUT_VERSION_TEXT_WIDTH, LAYOUT_VERSION_TEXT_HEIGHT, COLOR_VERSION_TEXT, COLOR_BACKGROUND, COLOR_BACKGROUND, TextJustification_e::Right); } void drawTx(){ if (globalSettings.txActive){ strncpy_P(b,(const char*)F("TX"), sizeof(b)); displayText(b, LAYOUT_TX_X, LAYOUT_TX_Y, LAYOUT_TX_WIDTH, LAYOUT_TX_HEIGHT, COLOR_ACTIVE_TEXT, COLOR_ACTIVE_BACKGROUND, COLOR_BACKGROUND); } else{ displayFillrect(LAYOUT_TX_X, LAYOUT_TX_Y, LAYOUT_TX_WIDTH, LAYOUT_TX_HEIGHT, COLOR_BACKGROUND); } } void drawStatusbar(){ drawCWStatus(); drawVersion(); } void guiUpdate(){ /* if (doingCAT) return; */ // use the current frequency as the VFO frequency for the active VFO displayClear(COLOR_BACKGROUND); displayVFO(VFO_A); displayVFO(VFO_B); checkCAT(); displayRIT(); checkCAT(); //force the display to refresh everything //display all the buttons for (int i = 0; i < BUTTON_TOTAL; i++){ Button button; memcpy_P(&button, &(btn_set[i]), sizeof(Button)); btnDraw(&button); checkCAT(); } drawStatusbar(); checkCAT(); } // this builds up the top line of the display with frequency and mode void updateDisplay() { displayVFO(globalSettings.activeVfo); } void ritToggle(struct Button *button){ if(!globalSettings.ritOn){ ritEnable(GetActiveVfoFreq()); } else{ ritDisable(); } btnDraw(button); displayRIT(); } void splitToggle(Button *button){ globalSettings.splitOn = !globalSettings.splitOn; btnDraw(button); //disable rit as well ritDisable(); Button button2; getButton(BUTTON_RIT, &button2); btnDraw(&button2); displayRIT(); displayVFO(VFO_A); displayVFO(VFO_B); } void vfoReset(){ Button button; if (VFO_A == globalSettings.activeVfo) globalSettings.vfoB.frequency = globalSettings.vfoA.frequency; else globalSettings.vfoA.frequency = globalSettings.vfoB.frequency; if(globalSettings.splitOn){ getButton(BUTTON_SPL, &button); splitToggle(&button); } if(globalSettings.ritOn){ getButton(BUTTON_RIT, &button); ritToggle(&button); } displayVFO(VFO_A); displayVFO(VFO_B); saveVFOs(); } void cwToggle(struct Button *b){ if (TuningMode_e::TUNE_SSB == globalSettings.tuningMode){ globalSettings.tuningMode = TuningMode_e::TUNE_CW; } else{ globalSettings.tuningMode = TuningMode_e::TUNE_SSB; } setFrequency(GetActiveVfoFreq()); btnDraw(b); } void sidebandToggle(Button* button){ if(BUTTON_LSB == button->id){ SetActiveVfoMode(VfoMode_e::VFO_MODE_LSB); } else{ SetActiveVfoMode(VfoMode_e::VFO_MODE_USB); } setFrequency(GetActiveVfoFreq()); struct Button button2; getButton(BUTTON_USB, &button2); btnDraw(&button2); getButton(BUTTON_LSB, &button2); btnDraw(&button2); saveVFOs(); } void redrawVFOs(){ struct Button button; ritDisable(); getButton(BUTTON_RIT, &button); btnDraw(&button); displayRIT(); displayVFO(VFO_A); displayVFO(VFO_B); //draw the lsb/usb buttons, the sidebands might have changed getButton(BUTTON_LSB, &button); btnDraw(&button); getButton(BUTTON_USB, &button); btnDraw(&button); } void switchBand(uint32_t bandfreq){ //Serial.println(frequency); //Serial.println(bandfreq); uint32_t offset; uint32_t freq = GetActiveVfoFreq(); if (3500000L <= freq && freq <= 4000000L) offset = freq - 3500000l; else if (24800000L <= freq && freq <= 25000000L) offset = freq - 24800000L; else offset = freq % 1000000L; //Serial.println(offset); setFrequency(bandfreq + offset); if(bandfreq >= THRESHOLD_USB_LSB){ SetActiveVfoMode(VfoMode_e::VFO_MODE_USB); } else{ SetActiveVfoMode(VfoMode_e::VFO_MODE_LSB); } updateDisplay(); saveVFOs(); } void doCommand(Button* button){ //Serial.print(F("Doing command: ")); //Serial.print(button->text); //Serial.print(F(", Hitbox: ")); //Serial.print(button->x);Serial.print(F(",")); //Serial.print(button->y);Serial.print(F(";")); //Serial.print(button->x + button->w);Serial.print(F(",")); //Serial.println(button->y + button->h); switch(button->id){ case BUTTON_RIT: { ritToggle(button); break; } case BUTTON_LSB: case BUTTON_USB: { sidebandToggle(button); break; } case BUTTON_CW: { cwToggle(button); break; } case BUTTON_SPL: { splitToggle(button); break; } case BUTTON_VFOA: { switchVFO(VFO_A); uint32_t freq = globalSettings.vfoA.frequency; ltoa(freq,b,10); morseText(b); break; } case BUTTON_VFOB: { switchVFO(VFO_B); uint32_t freq = globalSettings.vfoB.frequency; ltoa(freq,b,10); morseText(b); break; } case BUTTON_80: { switchBand(3500000L); break; } case BUTTON_40: { switchBand(7000000L); break; } case BUTTON_30: { switchBand(10000000L); break; } case BUTTON_20: { switchBand(14000000L); break; } case BUTTON_17: { switchBand(18000000L); break; } case BUTTON_15: { switchBand(21000000L); break; } case BUTTON_10: { switchBand(28000000L); break; } case BUTTON_FRQ: { enterFreq(); break; } case BUTTON_MNU: { doSetup2(); break; } default: { //Serial.print(F("Unknown command: ")); //Serial.println(button.id); break; } } } #include "menu.h" static const uint8_t DEBOUNCE_DELAY_MS = 50; static const uint16_t LONG_PRESS_TIME_MS = 3000; static const uint8_t LONG_PRESS_POLL_TIME_MS = 10; ButtonPress_e checkTouch(Point *const touch_point_out){ if (!readTouch(touch_point_out)){ return ButtonPress_e::NotPressed; } delay(DEBOUNCE_DELAY_MS); if (!readTouch(touch_point_out)){//debounce return ButtonPress_e::NotPressed; } uint16_t down_time = 0; while(readTouch(touch_point_out) && (down_time < LONG_PRESS_TIME_MS)){ delay(LONG_PRESS_POLL_TIME_MS); down_time += LONG_PRESS_POLL_TIME_MS; } scaleTouch(touch_point_out); if(down_time < LONG_PRESS_TIME_MS){ return ButtonPress_e::ShortPress; } else{ return ButtonPress_e::LongPress; } } //returns true if the button is pressed int btnDown(){ if (digitalRead(FBUTTON) == HIGH) return 0; else return 1; } void drawFocus(int ibtn, int color){ Button button; memcpy_P(&button, &(btn_set[ibtn]), sizeof(Button)); displayRect(button.x, button.y, button.w, button.h, color); } void doCommands(){ int select = 0; int prev_button = 0; //wait for the button to be raised up while(btnDown()) 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()){ doCommand(&button); //unfocus the buttons drawFocus(select, COLOR_INACTIVE_BORDER); if (VFO_A == globalSettings.activeVfo) drawFocus(BUTTON_VFOA, COLOR_ACTIVE_BORDER); else drawFocus(BUTTON_VFOB, COLOR_ACTIVE_BORDER); //wait for the button to be up and debounce while(btnDown()) active_delay(100); active_delay(500); return; } int knob = enc_read(); if (knob == 0){ active_delay(50); continue; } if (knob > 0){ if (select + knob < BUTTON_TOTAL * 10) select += knob; } if (knob < 0 && select + knob >= 0) select += knob; //caught ya, i is already -ve here, so you add it if (prev_button == select / 10) continue; //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(); //debounce the button while(btnDown()) active_delay(50); active_delay(50); checkCAT(); }