/* This source code started with Farhan's original source. The license rules are followed as well. Calibration related functions kept the original source except for the minor ones. The part is collected in the last minute of this source. Ian KD8CEC */ #include "ubitx.h" #include "ubitx_eemap.h" //Current Frequency and mode to active VFO by KD8CEC void FrequencyToVFO(byte isSaveFreq) { //Save Frequency & Mode Information if (vfoActive == VFO_A) { vfoA = frequency; vfoA_mode = modeToByte(); if (isSaveFreq) storeFrequencyAndMode(1); } else { vfoB = frequency; vfoB_mode = modeToByte(); if (isSaveFreq) storeFrequencyAndMode(2); } } //Commonly called functions when exiting menus by KD8CEC void menuClearExit(int delayTime) { if (delayTime > 0) delay_background(delayTime, 0); printLine2ClearAndUpdate(); menuOn = 0; } //Ham band or general band movement by KD8CEC void menuBand(int btn){ int knob = 0; int stepChangeCount = 0; byte btnPressCount = 0; if (!btn){ printLineF2(F("Band Select?")); return; } //printLineF2(F("Press to confirm")); //wait for the button menu select button to be lifted) while (btnDown()) { delay_background(50, 0); if (btnPressCount++ > 20) { btnPressCount = 0; if (tuneTXType > 0) { //Just toggle 0 <-> 2, if tuneTXType is 100, 100 -> 0 -> 2 tuneTXType = 0; printLineF2(F("General")); } else { tuneTXType = 2; printLineF2(F("Ham band")); } delay_background(1000, 0); printLine2ClearAndUpdate(); } } printLineF2(F("Press to confirm")); char currentBandIndex = -1; //Save Band Information if (tuneTXType == 2 || tuneTXType == 3 || tuneTXType == 102 || tuneTXType == 103) { //only ham band move //Get Now Band Index currentBandIndex = getIndexHambanBbyFreq(frequency); if (currentBandIndex >= 0) { //Save Frequency to Band Frequncy Record saveBandFreqByIndex(frequency, modeToByte(), currentBandIndex); } } //delay(50); ritDisable(); while(!btnDown()){ knob = enc_read(); if (knob != 0){ if (tuneTXType == 2 || tuneTXType == 3 || tuneTXType == 102 || tuneTXType == 103) { //only ham band move if (knob < 0) { if (stepChangeCount-- < -3) { setNextHamBandFreq(frequency, -1); //Prior Band stepChangeCount = 0; } } else if (knob > 0) { if (stepChangeCount++ > 3) { setNextHamBandFreq(frequency, 1); //Next Band stepChangeCount = 0; } } } //end of only ham band move else { //original source if (knob < 0 && frequency > 3000000l) setFrequency(frequency - 200000l); if (knob > 0 && frequency < 30000000l) setFrequency(frequency + 200000l); if (frequency > 10000000l) isUSB = true; else isUSB = false; } updateDisplay(); } delay_background(20, 0); } FrequencyToVFO(1); menuClearExit(500); } //Convert Mode, Number by KD8CEC //0: default, 1:not use, 2:LSB, 3:USB, 4:CWL, 5:CWU, 6:FM byte modeToByte(){ if (cwMode == 0) { if (isUSB) return 3; else return 2; } else if (cwMode == 1) { return 4; } else { return 5; } } //Convert Number to Mode by KD8CEC //autoSetModebyFreq : 0 //autoSetModebyFreq : 1, if (modValue is not set, set mode by frequency) void byteToMode(byte modeValue, byte autoSetModebyFreq){ if (modeValue == 4) cwMode = 1; else if (modeValue == 5) cwMode = 2; else { cwMode = 0; if (modeValue == 3) isUSB = 1; else if (autoSetModebyFreq == 1 && (modeValue == 0)) isUSB = (frequency > 10000000l) ? true : false; else isUSB = 0; } } //Memory to VFO, VFO to Memory by KD8CEC void menuCHMemory(int btn, byte isMemoryToVfo){ int knob = 0; int selectChannel = 0; byte isDisplayInfo = 1; int moveStep = 0; unsigned long resultFreq, tmpFreq = 0; byte loadMode = 0; if (!btn){ if (isMemoryToVfo == 1) printLineF2(F("Channel To VFO?")); else printLineF2(F("VFO To Channel?")); } else { delay_background(500, 0); while(!btnDown()){ if (isDisplayInfo == 1) { //Display Channel info ********************************* memset(c, 0, sizeof(c)); if (selectChannel >= 20 || selectChannel <=-1) { //strcpy(c, "Exit setup?"); strcpy(c, "Exit?"); } else { //Read Frequency from eeprom EEPROM.get(CHANNEL_FREQ + 4 * selectChannel, resultFreq); loadMode = (byte)(resultFreq >> 29); resultFreq = resultFreq & 0x1FFFFFFF; //display channel description if (selectChannel < 10 && EEPROM.read(CHANNEL_DESC + 6 * selectChannel) == 0x03) { //0x03 is display Chnnel Name //display Channel Name for (int i = 0; i < 5; i++) c[i] = EEPROM.read(CHANNEL_DESC + 6 * selectChannel + i + 1); c[5] = ':'; } else { //Display frequency //1 LINE : Channel Information : CH00 strcpy(c, "CH"); if (selectChannel < 9) c[2] = '0'; ltoa(selectChannel + 1, b, 10); strcat(c, b); //append channel Number; strcat(c, " :"); //append channel Number; } //display frequency tmpFreq = resultFreq; for (int i = 15; i >= 6; i--) { if (tmpFreq > 0) { if (i == 12 || i == 8) c[i] = '.'; else { c[i] = tmpFreq % 10 + 0x30; tmpFreq /= 10; } } else c[i] = ' '; } } printLine2(c); isDisplayInfo = 0; } knob = enc_read(); if (knob != 0) { moveStep += (knob > 0 ? 1 : -1); if (moveStep < -3) { if (selectChannel > -1) selectChannel--; isDisplayInfo = 1; moveStep = 0; } else if (moveStep > 3) { if (selectChannel < 20) selectChannel++; isDisplayInfo = 1; moveStep = 0; } } Check_Cat(0); //To prevent disconnections } //end of while (knob) if (selectChannel < 20 && selectChannel >= 0) { if (isMemoryToVfo == 1) { if (resultFreq > 3000 && resultFreq < 60000000) { byteToMode(loadMode, 1); setFrequency(resultFreq); } } else { //Save current Frequency to Channel (selectChannel) EEPROM.put(CHANNEL_FREQ + 4 * selectChannel, (frequency & 0x1FFFFFFF) | (((unsigned long)modeToByte()) << 29) ); printLine2("Saved Frequency"); } } menuClearExit(500); } } //Analog pin monitoring with CW Key and function keys connected. //by KD8CEC #ifdef ENABLE_ADCMONITOR void menuADCMonitor(int btn){ int adcPinA0 = 0; //A0(BLACK, EncoderA) int adcPinA1 = 0; //A1(BROWN, EncoderB) int adcPinA2 = 0; //A2(RED, Function Key) int adcPinA3 = 0; //A3(ORANGE, CW Key) int adcPinA6 = 0; //A6(BLUE, Ptt) int adcPinA7 = 0; //A7(VIOLET, Spare) unsigned long pressKeyTime = 0; if (!btn){ printLineF2(F("ADC Line Monitor")); return; } printLineF2(F("Exit:Long PTT")); delay_background(2000, 0); printLineF1(F("A0 A1 A2")); printLineF2(F("A3 A6 A7")); delay_background(3000, 0); while (true) { adcPinA0 = analogRead(A0); //A0(BLACK, EncoderA) adcPinA1 = analogRead(A1); //A1(BROWN, EncoderB) adcPinA2 = analogRead(A2); //A2(RED, Function Key) adcPinA3 = analogRead(A3); //A3(PTT) adcPinA6 = analogRead(A6); //A6(KEYER) adcPinA7 = analogRead(A7); //A7(VIOLET, Spare) if (adcPinA3 < 50) { if (pressKeyTime == 0) pressKeyTime = millis(); else if (pressKeyTime < (millis() - 3000)) break; } else pressKeyTime = 0; ltoa(adcPinA0, c, 10); //strcat(b, c); strcpy(b, c); strcat(b, ", "); ltoa(adcPinA1, c, 10); strcat(b, c); strcat(b, ", "); ltoa(adcPinA2, c, 10); strcat(b, c); printLine1(b); //strcpy(b, " "); ltoa(adcPinA3, c, 10); strcpy(b, c); strcat(b, ", "); ltoa(adcPinA6, c, 10); strcat(b, c); strcat(b, ", "); ltoa(adcPinA7, c, 10); strcat(b, c); printLine2(b); delay_background(200, 0); } //end of while menuClearExit(0); } #endif //VFO Toggle and save VFO Information, modified by KD8CEC void menuVfoToggle(int btn) { if (!btn){ if (vfoActive == VFO_A) printLineF2(F("Select VFO B?")); else printLineF2(F("Select VFO A?")); } else { FrequencyToVFO(1); if (vfoActive == VFO_B){ vfoActive = VFO_A; frequency = vfoA; saveCheckFreq = frequency; byteToMode(vfoA_mode, 0); } else { vfoActive = VFO_B; frequency = vfoB; saveCheckFreq = frequency; byteToMode(vfoB_mode, 0); } ritDisable(); setFrequency(frequency); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(0); #endif } } //Split communication using VFOA and VFOB by KD8CEC void menuSplitOnOff(int btn){ if (!btn){ if (splitOn == 0) printLineF2(F("Split On?")); else printLineF2(F("Split Off?")); } else { if (splitOn == 1){ splitOn = 0; printLineF2(F("SPT Off")); } else { splitOn = 1; if (ritOn == 1) ritOn = 0; printLineF2(F("SPT On")); } #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(500); #endif } } //Function to disbled transmission //by KD8CEC void menuTxOnOff(int btn, byte optionType){ if (!btn){ if ((isTxType & optionType) == 0) printLineF2(F("TX OFF?")); else printLineF2(F("TX ON?")); } else { if ((isTxType & optionType) == 0){ isTxType |= optionType; printLineF2(F("TX OFF")); } else { isTxType &= ~(optionType); printLineF2(F("TX ON")); } #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(500); #endif } } //Toggle SDR MODE void menuSDROnOff(int btn) { if (!btn){ if (sdrModeOn == 0) printLineF2(F("SDR Mode On?")); else printLineF2(F("SDR Mode Off?")); } else { if (sdrModeOn == 1){ sdrModeOn = 0; printLineF2(F("SPK MODE")); } else { sdrModeOn = 1; if (ritOn == 1) ritOn = 0; if (splitOn == 1) splitOn = 0; printLineF2(F("SDR MODE")); } EEPROM.put(ENABLE_SDR, sdrModeOn); setFrequency(frequency); SetCarrierFreq(); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(500); #endif } } void displayEmptyData(void){ printLineF2(F("Empty data")); delay_background(2000, 0); } //Builtin CW Keyer Logic by KD8CEC void menuCWAutoKey(int btn){ if (!btn){ printLineF2(F("Memory Keyer")); return; } //Check CW_AUTO_MAGIC_KEY and CW Text Count EEPROM.get(CW_AUTO_COUNT, cwAutoTextCount); if (EEPROM.read(CW_AUTO_MAGIC_KEY) != 0x73 || cwAutoTextCount < 1) { displayEmptyData(); return; } printLineF1(F("PTT to Send")); delay_background(500, 0); beforeCWTextIndex = 255; //255 value is for start check isCWAutoMode = 1; updateDisplay(); menuOn = 0; } //Standalone WSPR Beacone void menuWSPRSend(int btn){ if (!btn){ printLineF2(F("WSPR Beacon")); return; } WsprMSGCount = EEPROM.read(WSPR_COUNT); if (WsprMSGCount < 1) { displayEmptyData(); return; } SendWSPRManage(); menuClearExit(1000); } //Append by KD8CEC void menuSetupCWCarrier(int btn){ int knob = 0; unsigned long prevCarrier; if (!btn){ printLineF2(F("Set CW RX BFO")); return; } prevCarrier = cwmCarrier; printLineF1(F("PTT to confirm. ")); delay_background(1000, 0); si5351bx_setfreq(0, cwmCarrier); printCarrierFreq(cwmCarrier); //disable all clock 1 and clock 2 while (digitalRead(PTT) == HIGH && !btnDown()) { knob = enc_read(); if (knob > 0) cwmCarrier -= 5; else if (knob < 0) cwmCarrier += 5; else continue; //don't update the frequency or the display si5351bx_setfreq(0, cwmCarrier); printCarrierFreq(cwmCarrier); delay_background(100, 0); } //save the setting if (digitalRead(PTT) == LOW){ printLineF2(F("Carrier set!")); EEPROM.put(CW_CAL, cwmCarrier); delay_background(1000, 0); } else cwmCarrier = prevCarrier; if (cwMode == 0) si5351bx_setfreq(0, usbCarrier); //set back the carrier oscillator anyway, cw tx switches it off else si5351bx_setfreq(0, cwmCarrier); //set back the carrier oscillator anyway, cw tx switches it off setFrequency(frequency); menuClearExit(0); } //======================================================= //BEGIN OF STANDARD TUNE SETUP for reduce Program Memory // by KD8CEC //======================================================= //valueType 0 : Normal // 1 : CW Change -> Generate Tone // 2 : IF Shift Setup -> SetFrequency, Set SideTone // 5 : ATT // 11 : Select Mode (different display type) //knobSensitivity : 1 ~ int getValueByKnob(int valueType, int targetValue, int minKnobValue, int maxKnobValue, int incStep, const char* displayTitle, int knobSensitivity) { int knob; int moveDetectStep = 0; char isInitDisplay = 1; delay_background(300, 0); //Default Delay if (valueType < 10) { strcpy(b, "Press, set "); strcat(b, displayTitle); printLine1(b); } while(!btnDown()) { knob = enc_read(); if (knob != 0 || isInitDisplay == 1) { isInitDisplay = 0; /* //Program Size : 29424 (95%) if (targetValue > minKnobValue && knob < 0) targetValue -= incStep; if (targetValue < maxKnobValue && knob > 0) targetValue += incStep; */ //Program Size : 29560 (increase 135 byte from avobe codes), but a lot of usable functions moveDetectStep += (knob > 0 ? 1 : -1); if (moveDetectStep < (knobSensitivity * -1)) { if (targetValue > minKnobValue) targetValue -= incStep; moveDetectStep = 0; } else if (moveDetectStep > knobSensitivity) { if (targetValue < maxKnobValue) targetValue += incStep; moveDetectStep = 0; } strcpy(b, displayTitle); if (valueType == 11) //Mode Select { b[targetValue * 4] = '>'; } /* else if (valueType == 4) //CW Key Type Select { if (targetValue == 0) strcat(b, "Straight"); else if (targetValue == 1) strcat(b, "IAMBICA"); else if (targetValue == 2) strcat(b, "IAMBICB"); } */ else { strcat(b, ":"); itoa(targetValue,c, 10); strcat(b, c); } printLine2(b); if (valueType == 1) //Generate Side Tone { tone(CW_TONE, targetValue); } else if (valueType == 2 || valueType == 5 ) // 2:IFS, 5:ATT { if (valueType == 2) ifShiftValue = targetValue; else attLevel = targetValue; #ifdef USE_SW_SERIAL menuOn=2; updateDisplay(); #endif setFrequency(frequency); SetCarrierFreq(); } } Check_Cat(0); //To prevent disconnections } return targetValue; } void menuCWSpeed(int btn){ int wpm; wpm = 1200/cwSpeed; if (!btn){ strcpy(b, "CW:"); itoa(wpm,c, 10); strcat(b, c); strcat(b, "WPM Change?"); printLine2(b); return; } //printLineF1(F("Press to set WPM")); //strcpy(b, "WPM:"); //itoa(wpm,c, 10); //strcat(b, c); //printLine2(b); //delay_background(300, 0); wpm = getValueByKnob(0, wpm, 3, 50, 1, "WPM", 3); /* while(!btnDown()){ knob = enc_read(); if (knob != 0){ if (wpm > 3 && knob < 0) wpm--; if (wpm < 50 && knob > 0) wpm++; strcpy(b, "WPM:"); itoa(wpm,c, 10); strcat(b, c); printLine2(b); } Check_Cat(0); //To prevent disconnections } */ //save the setting //printLineF2(F("CW Speed set!")); cwSpeed = 1200 / wpm; EEPROM.put(CW_SPEED, cwSpeed); //menuClearExit(1000); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(1000); #endif } //Modified by KD8CEC void menuSetupCwTone(int btn){ //int prev_sideTone; if (!btn){ printLineF2(F("Change CW Tone")); return; } //prev_sideTone = sideTone; //printLineF1(F("Tune CW tone")); //printLineF2(F("PTT to confirm.")); //printLineF1(F("Press to set WPM")); //delay_background(1000, 0); //tone(CW_TONE, sideTone); sideTone = getValueByKnob(1, sideTone, 100, 2000, 10, "Tone", 2); //1 : Generate Tone, targetValue, minKnobValue, maxKnobValue, stepSize noTone(CW_TONE); printLineF2(F("Sidetone set!")); EEPROM.put(CW_SIDETONE, sideTone); //delay_background(2000, 0); //menuClearExit(0); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD delay_background(2000, 0); menuClearExit(0); #endif } //Modified by KD8CEC void menuSetupCwDelay(int btn){ //int knob = 0; int tmpCWDelay = cwDelayTime * 10; if (!btn){ printLineF2(F("CW TX->RX Delay")); return; } tmpCWDelay = getValueByKnob(0, tmpCWDelay, 3, 2500, 10, "Delay", 2); //0 : Generate Tone, targetValue, minKnobValue, maxKnobValue, stepSize //save the setting cwDelayTime = tmpCWDelay / 10; EEPROM.put(CW_DELAY, cwDelayTime); //menuClearExit(1000); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(1000); #endif } //CW Time delay by KD8CEC void menuSetupTXCWInterval(int btn){ //char needDisplayInformation = 1; //int knob = 0; int tmpTXCWInterval = delayBeforeCWStartTime * 2; if (!btn){ printLineF2(F("CW Start Delay")); return; } //printLineF1(F("Press, set Delay")); //delay_background(300, 0); tmpTXCWInterval = getValueByKnob(0, tmpTXCWInterval, 0, 500, 2, "Delay", 2); //0 : Generate Tone, targetValue, minKnobValue, maxKnobValue, stepSize delayBeforeCWStartTime = tmpTXCWInterval / 2; EEPROM.put(CW_START, delayBeforeCWStartTime); //menuClearExit(1000); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(1000); #endif } //IF Shift function, BFO Change like RIT, by KD8CEC void menuIFSSetup(int btn){ //int knob = 0; //char needApplyChangeValue = 1; if (!btn){ if (isIFShift == 1) printLineF2(F("IF Shift Change?")); else printLineF2(F("IF Shift On?")); } else { isIFShift = 1; ifShiftValue = getValueByKnob(2, ifShiftValue, -20000, 20000, 50, "IFS", 2); //2 : IF Setup (updateLine2Buffer(1), SetFrequency), targetValue, minKnobValue, maxKnobValue, stepSize delay_background(500, 0); //for check Long Press function key if (btnDown() || ifShiftValue == 0) { isIFShift = 0; ifShiftValue = 0; setFrequency(frequency); SetCarrierFreq(); } //Store IF Shiift EEPROM.put(IF_SHIFTVALUE, ifShiftValue); //menuClearExit(0); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(0); #endif } } //ATT SETUP (IF1(45MHZ) SHIFT), by KD8CEC void menuATTSetup(int btn){ //int knob = 0; //char needApplyChangeValue = 1; if (!btn){ if (attLevel != 0) printLineF2(F("ATT Change?")); else printLineF2(F("ATT On?")); } else { attLevel = getValueByKnob(5, attLevel, 0, 250, 5, "ATT", 2); //2 : (SetFrequency), targetValue, minKnobValue, maxKnobValue, stepSize delay_background(500, 0); //for check Long Press function key if (btnDown() || attLevel == 0) { attLevel = 0; setFrequency(frequency); //SetCarrierFreq(); } //menuClearExit(0); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(0); #endif } } //Functions for CWL and CWU by KD8CEC void menuSelectMode(int btn){ //int knob = 0; int selectModeType = 0; int beforeMode = 0; //int moveStep = 0; if (!btn){ printLineF2(F("Select Mode?")); } else { //LSB, USB, CWL, CWU if (cwMode == 0 && isUSB == 0) selectModeType = 0; else if (cwMode == 0 && isUSB == 1) selectModeType = 1; else if (cwMode == 1) selectModeType = 2; else selectModeType = 3; beforeMode = selectModeType; selectModeType = getValueByKnob(11, selectModeType, 0, 3, 1, " LSB USB CWL CWU", 4); //3 : Select Mode, targetValue, minKnobValue, maxKnobValue, stepSize if (beforeMode != selectModeType) { //printLineF1(F("Changed Mode")); if (selectModeType == 0) { cwMode = 0; isUSB = 0; } else if (selectModeType == 1) { cwMode = 0; isUSB = 1; } else if (selectModeType == 2) { cwMode = 1; } else if (selectModeType == 3) { cwMode = 2; } FrequencyToVFO(1); } SetCarrierFreq(); setFrequency(frequency); //menuClearExit(500); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(500); #endif } } //Select CW Key Type by KD8CEC void menuSetupKeyType(int btn){ //int knob = 0; int selectedKeyType = 0; //int moveStep = 0; if (!btn){ printLineF2(F("Change Key Type?")); } else { selectedKeyType = cwKeyType; //selectedKeyType = getValueByKnob(12, selectedKeyType, 0, 2, 1, " KEY:", 5); //4 : Select Key Type, targetValue, minKnobValue, maxKnobValue, stepSize selectedKeyType = getValueByKnob(11, selectedKeyType, 0, 2, 1, " ST IA IB", 5); //4 : Select Key Type, targetValue, minKnobValue, maxKnobValue, stepSize printLineF2(F("CW Key Type set!")); cwKeyType = selectedKeyType; EEPROM.put(CW_KEY_TYPE, cwKeyType); if (cwKeyType == 0) Iambic_Key = false; else { Iambic_Key = true; if (cwKeyType == 1) keyerControl &= ~IAMBICB; else keyerControl |= IAMBICB; } //menuClearExit(1000); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(1000); #endif } } //===================================================== //END OF STANDARD Set by Knob for reduce Program Memory //===================================================== //Lock Dial move by KD8CEC void setDialLock(byte tmpLock, byte fromMode) { if (tmpLock == 1) isDialLock |= (vfoActive == VFO_A ? 0x01 : 0x02); else isDialLock &= ~(vfoActive == VFO_A ? 0x01 : 0x02); if (fromMode == 2 || fromMode == 3) return; //delay_background(1000, 0); printLine2ClearAndUpdate(); } byte btnDownTimeCount; #define PRESS_ADJUST_TUNE 20 //1000msec 20 * 50 = 1000milisec #define PRESS_LOCK_CONTROL 40 //2000msec 40 * 50 = 2000milisec //Modified by KD8CEC void doMenu(){ int select=0, i,btnState; char isNeedDisplay = 0; //for DialLock On/Off function btnDownTimeCount = 0; //wait for the button to be raised up //Appened Lines by KD8CEC for Adjust Tune step and Set Dial lock while(btnDown()){ delay_background(50, 0); if (btnDownTimeCount++ == (PRESS_ADJUST_TUNE)) { //Set Tune Step printLineF2(F("Set Tune Step?")); } else if (btnDownTimeCount > (PRESS_LOCK_CONTROL)) { //check long time Down Button -> 2.5 Second => Lock if (vfoActive == VFO_A) setDialLock((isDialLock & 0x01) == 0x01 ? 0 : 1, 0); //Reverse Dial lock else setDialLock((isDialLock & 0x02) == 0x02 ? 0 : 1, 0); //Reverse Dial lock return; } } delay(50); //debounce //ADJUST TUNE STEP if (btnDownTimeCount > PRESS_ADJUST_TUNE) { printLineF1(F("Press to set")); isNeedDisplay = 1; //check to need display for display current value while (!btnDown()) { delay_background(50, 0); if (isNeedDisplay) { strcpy(b, "Tune Step:"); itoa(arTuneStep[tuneStepIndex -1], c, 10); strcat(b, c); printLine2(b); isNeedDisplay = 0; } i = enc_read(); if (i != 0) { select += (i > 0 ? 1 : -1); if (select * select >= 25) { //Threshold 5 * 5 = 25 if (select < 0) { if (tuneStepIndex > 1) tuneStepIndex--; } else { if (tuneStepIndex < 5) tuneStepIndex++; } select = 0; isNeedDisplay = 1; } } } //end of while EEPROM.put(TUNING_STEP, tuneStepIndex); delay_background(500, 0); printLine2ClearAndUpdate(); return; } //set tune step //Below codes are origial code with modified by KD8CEC menuOn = 2; TriggerBySW = 0; //Nextion LCD and Other MCU //********************************************************************************* // New type menu for developer by KD8CEC // Selectable menu // Version : 1.097 ~ //********************************************************************************* #ifndef ENABLE_ADCMONITOR #define FN_ADCMONITOR 0 #endif #define FN_DEFAULT_MENU 2 //Setup Onff / Exit #define FN_DEFAULT_SETUP 1 //Exit #define FN_BAND_IDX (FN_BAND -1) //0 or -1 #define FN_VFO_TOGGLE_IDX (FN_BAND_IDX + FN_VFO_TOGGLE) #define FN_MODE_IDX (FN_VFO_TOGGLE_IDX + FN_MODE) #define FN_RIT_IDX (FN_MODE_IDX + FN_RIT) #define FN_IFSHIFT_IDX (FN_RIT_IDX + FN_IFSHIFT) #define FN_ATT_IDX (FN_IFSHIFT_IDX + FN_ATT) #define FN_CW_SPEED_IDX (FN_ATT_IDX + FN_CW_SPEED) #define FN_SPLIT_IDX (FN_CW_SPEED_IDX + FN_SPLIT) #define FN_VFOTOMEM_IDX (FN_SPLIT_IDX + FN_VFOTOMEM) #define FN_MEMTOVFO_IDX (FN_VFOTOMEM_IDX + FN_MEMTOVFO) #define FN_MEMORYKEYER_IDX (FN_MEMTOVFO_IDX + FN_MEMORYKEYER) #define FN_WSPR_IDX (FN_MEMORYKEYER_IDX + FN_WSPR) #define FN_SDRMODE_IDX (FN_WSPR_IDX + FN_SDRMODE) #define FN_SETUP_IDX (FN_SDRMODE_IDX + 1) #define FN_EXIT_IDX (FN_SETUP_IDX + 1) #define FN_CALIBRATION_IDX (FN_EXIT_IDX + FN_CALIBRATION) #define FN_CARRIER_IDX (FN_CALIBRATION_IDX + FN_CARRIER) #define FN_CWCARRIER_IDX (FN_CARRIER_IDX + FN_CWCARRIER) #define FN_CWTONE_IDX (FN_CWCARRIER_IDX + FN_CWTONE) #define FN_CWDELAY_IDX (FN_CWTONE_IDX + FN_CWDELAY) #define FN_TXCWDELAY_IDX (FN_CWDELAY_IDX + FN_TXCWDELAY) #define FN_KEYTYPE_IDX (FN_TXCWDELAY_IDX + FN_KEYTYPE) #define FN_ADCMONITOR_IDX (FN_KEYTYPE_IDX + FN_ADCMONITOR) #define FN_TXONOFF_IDX (FN_ADCMONITOR_IDX + FN_TXONOFF) #define FN_MENU_COUNT (FN_DEFAULT_MENU + FN_BAND + FN_VFO_TOGGLE + FN_MODE + FN_RIT + FN_IFSHIFT + FN_ATT + FN_CW_SPEED + FN_SPLIT + FN_VFOTOMEM + FN_MEMTOVFO + FN_MEMORYKEYER + FN_WSPR + FN_SDRMODE) #define FN_SETUP_COUNT (FN_DEFAULT_SETUP + FN_CALIBRATION + FN_CARRIER + FN_CWCARRIER + FN_CWTONE + FN_CWDELAY + FN_TXCWDELAY + FN_KEYTYPE + FN_ADCMONITOR + FN_TXONOFF) #define FN_STEP_COUNT (FN_MENU_COUNT + FN_SETUP_COUNT) while (menuOn){ i = enc_read(); btnState = btnDown(); if (i > 0){ if (modeCalibrate && select + i < FN_STEP_COUNT * 10) select += i; else if (!modeCalibrate && select + i < FN_MENU_COUNT * 10) select += i; } else if (i < 0 && select - i >= -10) select += i; switch (select / 10) { #if FN_BAND == 1 case FN_BAND_IDX : menuBand(btnState); break; #endif #if FN_VFO_TOGGLE == 1 case FN_VFO_TOGGLE_IDX : menuVfoToggle(btnState); break; #endif #if FN_MODE == 1 case FN_MODE_IDX : menuSelectMode(btnState); break; #endif #if FN_RIT == 1 case FN_RIT_IDX : menuRitToggle(btnState); break; #endif #if FN_IFSHIFT == 1 case FN_IFSHIFT_IDX : menuIFSSetup(btnState); break; #endif #if FN_ATT == 1 case FN_ATT_IDX : menuATTSetup(btnState); break; #endif #if FN_CW_SPEED == 1 case FN_CW_SPEED_IDX : menuCWSpeed(btnState); break; #endif #if FN_SPLIT == 1 case FN_SPLIT_IDX : menuSplitOnOff(btnState); //SplitOn / off break; #endif #if FN_VFOTOMEM == 1 case FN_VFOTOMEM_IDX : menuCHMemory(btnState, 0); //VFO to Memroy break; #endif #if FN_MEMTOVFO == 1 case FN_MEMTOVFO_IDX : menuCHMemory(btnState, 1); //Memory to VFO break; #endif #if FN_MEMORYKEYER == 1 case FN_MEMORYKEYER_IDX : menuCWAutoKey(btnState); break; #endif #if FN_WSPR == 1 case FN_WSPR_IDX : menuWSPRSend(btnState); break; #endif #if FN_SDRMODE == 1 case FN_SDRMODE_IDX : menuSDROnOff(btnState); break; #endif case FN_SETUP_IDX : menuSetup(btnState); break; case FN_EXIT_IDX : menuExit(btnState); break; #if FN_CALIBRATION == 1 case FN_CALIBRATION_IDX : menuSetupCalibration(btnState); //crystal break; #endif #if FN_CARRIER == 1 case FN_CARRIER_IDX : menuSetupCarrier(btnState); //ssb break; #endif #if FN_CWCARRIER == 1 case FN_CWCARRIER_IDX : menuSetupCWCarrier(btnState); //cw break; #endif #if FN_CWTONE == 1 case FN_CWTONE_IDX : menuSetupCwTone(btnState); break; #endif #if FN_CWDELAY == 1 case FN_CWDELAY_IDX : menuSetupCwDelay(btnState); break; #endif #if FN_TXCWDELAY == 1 case FN_TXCWDELAY_IDX : menuSetupTXCWInterval(btnState); break; #endif #if FN_KEYTYPE == 1 case FN_KEYTYPE_IDX : menuSetupKeyType(btnState); break; #endif #if FN_ADCMONITOR == 1 case FN_ADCMONITOR_IDX : menuADCMonitor(btnState); break; #endif #if FN_TXONOFF == 1 case FN_TXONOFF_IDX : menuTxOnOff(btnState, 0x01); //TX OFF / ON break; #endif default : menuExit(btnState); break; } //end of switch Check_Cat(0); //To prevent disconnections } //end of while //**************************************************************************** //Before change menu type (Version : ~ 0.95) //**************************************************************************** /* while (menuOn){ i = enc_read(); btnState = btnDown(); if (i > 0){ if (modeCalibrate && select + i < 250) select += i; else if (!modeCalibrate && select + i < 150) select += i; } else if (i < 0 && select - i >= -10) select += i; //if -> switch : reduce program memory 200byte switch (select / 10) { case 0 : menuBand(btnState); break; case 1 : menuVfoToggle(btnState); break; case 2 : menuSelectMode(btnState); break; case 3 : menuRitToggle(btnState); break; case 4 : menuIFSSetup(btnState); break; case 5 : menuATTSetup(btnState); break; case 6 : menuCWSpeed(btnState); break; case 7 : menuSplitOnOff(btnState); //SplitOn / off break; case 8 : menuCHMemory(btnState, 0); //VFO to Memroy break; case 9 : menuCHMemory(btnState, 1); //Memory to VFO break; case 10 : menuCWAutoKey(btnState); break; case 11 : menuWSPRSend(btnState); break; case 12 : menuSDROnOff(btnState); break; case 13 : menuSetup(btnState); break; case 14 : menuExit(btnState); break; case 15 : menuSetupCalibration(btnState); //crystal break; case 16 : menuSetupCarrier(btnState); //ssb break; case 17 : menuSetupCWCarrier(btnState); //cw break; case 18 : menuSetupCwTone(btnState); break; case 19 : menuSetupCwDelay(btnState); break; case 20 : menuSetupTXCWInterval(btnState); break; case 21 : menuSetupKeyType(btnState); break; #ifdef ENABLE_ADCMONITOR case 22 : menuADCMonitor(btnState); break; case 23 : #else case 22 : #endif menuTxOnOff(btnState, 0x01); //TX OFF / ON break; default : menuExit(btnState); break; } //end of case Check_Cat(0); //To prevent disconnections } //end of while */ } //************************************************************************************* //Original Source Part //The code below is the original source part that I kept unchanged for compatibility. //By KD8CEC //************************************************************************************* /** Original source comment * Menus * The Radio menus are accessed by tapping on the function button. * - The main loop() constantly looks for a button press and calls doMenu() when it detects * a function button press. * - As the encoder is rotated, at every 10th pulse, the next or the previous menu * item is displayed. Each menu item is controlled by it's own function. * - Eache menu function may be called to display itself * - Each of these menu routines is called with a button parameter. * - The btn flag denotes if the menu itme was clicked on or not. * - If the menu item is clicked on, then it is selected, * - If the menu item is NOT clicked on, then the menu's prompt is to be displayed */ /** * The calibration routines are not normally shown in the menu as they are rarely used * They can be enabled by choosing this menu option */ void menuSetup(int btn){ if (!btn) { if (!modeCalibrate) printLineF2(F("Setup On?")); else printLineF2(F("Setup Off?")); } else { modeCalibrate = ! modeCalibrate; //menuClearExit(1000); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(1000); #endif } } void menuExit(int btn){ if (!btn){ printLineF2(F("Exit Menu?")); } else menuClearExit(0); } //modified for reduce used flash memory by KD8CEC void menuRitToggle(int btn){ if (!btn){ if (ritOn == 1) printLineF2(F("RIT Off?")); else printLineF2(F("RIT On?")); } else { if (ritOn == 0){ //printLineF2(F("RIT is ON")); //enable RIT so the current frequency is used at transmit ritEnable(frequency); } else{ //printLineF2(F("RIT is OFF")); ritDisable(); } //menuClearExit(500); #ifdef USE_SW_SERIAL menuOn = 0; #else //Only Clear And Delay for Character LCD menuClearExit(500); #endif } } /** * Take a deep breath, math(ematics) ahead * The 25 mhz oscillator is multiplied by 35 to run the vco at 875 mhz * This is divided by a number to generate different frequencies. * If we divide it by 875, we will get 1 mhz signal * So, if the vco is shifted up by 875 hz, the generated frequency of 1 mhz is shifted by 1 hz (875/875) * At 12 Mhz, the carrier will needed to be shifted down by 12 hz for every 875 hz of shift up of the vco * */ //this is used by the si5351 routines in the ubitx_5351 file extern int32_t calibration; extern uint32_t si5351bx_vcoa; void factoryCalibration(int btn){ int knob = 0; //keep clear of any previous button press while (btnDown()) delay(100); delay(100); if (!btn){ printLineF2(F("Set Calibration?")); return; } calibration = 0; cwMode = 0; isUSB = true; //turn off the second local oscillator and the bfo si5351_set_calibration(calibration); startTx(TX_CW, 1); si5351bx_setfreq(2, 10000000l); strcpy(b, "#1 10 MHz cal:"); ltoa(calibration/8750, c, 10); strcat(b, c); printLine2(b); while (!btnDown()) { if (digitalRead(PTT) == LOW && !keyDown) cwKeydown(); if (digitalRead(PTT) == HIGH && keyDown) cwKeyUp(); knob = enc_read(); if (knob > 0) calibration += 875; else if (knob < 0) calibration -= 875; else continue; //don't update the frequency or the display si5351_set_calibration(calibration); si5351bx_setfreq(2, 10000000l); strcpy(b, "#1 10 MHz cal:"); ltoa(calibration/8750, c, 10); strcat(b, c); printLine2(b); } cwTimeout = 0; keyDown = 0; stopTx(); printLineF2(F("Calibration set!")); EEPROM.put(MASTER_CAL, calibration); initOscillators(); setFrequency(frequency); updateDisplay(); while(btnDown()) delay(50); menuClearExit(100); } void menuSetupCalibration(int btn){ int knob = 0; int32_t prev_calibration; if (!btn){ printLineF2(F("Set Calibration?")); return; } printLineF1(F("Set to Zero-beat,")); printLineF2(F("press PTT to save")); delay_background(1000, 0); prev_calibration = calibration; calibration = 0; si5351_set_calibration(calibration); setFrequency(frequency); strcpy(b, "cal:"); ltoa(calibration/8750, c, 10); strcat(b, c); printLine2(b); while (digitalRead(PTT) == HIGH && !btnDown()) { knob = enc_read(); if (knob > 0){ calibration += 8750; usbCarrier += 120; } else if (knob < 0){ calibration -= 8750; usbCarrier -= 120; } else continue; //don't update the frequency or the display si5351_set_calibration(calibration); si5351bx_setfreq(0, usbCarrier); setFrequency(frequency); strcpy(b, "cal:"); ltoa(calibration/8750, c, 10); strcat(b, c); printLine2(b); } //save the setting if (digitalRead(PTT) == LOW){ printLineF1(F("Calibration set!")); printLineF2(F("Set Carrier now")); EEPROM.put(MASTER_CAL, calibration); delay_background(2000, 0); } else calibration = prev_calibration; initOscillators(); //si5351_set_calibration(calibration); setFrequency(frequency); //printLine2ClearAndUpdate(); //menuOn = 0; menuClearExit(0); } void printCarrierFreq(unsigned long freq){ memset(c, 0, sizeof(c)); memset(b, 0, sizeof(b)); ultoa(freq, b, DEC); strncat(c, b, 2); strcat(c, "."); strncat(c, &b[2], 3); strcat(c, "."); strncat(c, &b[5], 3); printLine2(c); } //modified by KD8CEC (just 1 line remarked //usbCarrier = ... void menuSetupCarrier(int btn){ int knob = 0; unsigned long prevCarrier; if (!btn){ printLineF2(F("Set the BFO")); return; } prevCarrier = usbCarrier; printLineF1(F("Tune to best Signal")); printLineF1(F("PTT to confirm. ")); delay_background(1000, 0); //usbCarrier = 11995000l; //Remarked by KD8CEC, Suggest from many user, if entry routine factoryrest /* //for uBITX V5.0, but not used by KD8CEC, if you want default value of carrier on Calibration, delete remark symbols #if UBITX_BOARD_VERSION == 5 usbCarrier = 11053000l; #else usbCarrier = 11995000l; #endif */ si5351bx_setfreq(0, usbCarrier); printCarrierFreq(usbCarrier); //disable all clock 1 and clock 2 while (digitalRead(PTT) == HIGH && !btnDown()) { knob = enc_read(); if (knob > 0) usbCarrier -= 5; else if (knob < 0) usbCarrier += 5; else continue; //don't update the frequency or the display si5351bx_setfreq(0, usbCarrier); printCarrierFreq(usbCarrier); Check_Cat(0); //To prevent disconnections delay(100); } //save the setting if (digitalRead(PTT) == LOW){ printLineF2(F("Carrier set!")); EEPROM.put(USB_CAL, usbCarrier); delay_background(1000, 0); } else usbCarrier = prevCarrier; //si5351bx_setfreq(0, usbCarrier); if (cwMode == 0) si5351bx_setfreq(0, usbCarrier); //set back the carrier oscillator anyway, cw tx switches it off else si5351bx_setfreq(0, cwmCarrier); //set back the carrier oscillator anyway, cw tx switches it off setFrequency(frequency); //printLine2ClearAndUpdate(); //menuOn = 0; menuClearExit(0); }