diff --git a/ubitx_20/cw_autokey.ino b/ubitx_20/cw_autokey.ino index c9dba8b..4d2d93f 100644 --- a/ubitx_20/cw_autokey.ino +++ b/ubitx_20/cw_autokey.ino @@ -36,7 +36,7 @@ //27 + 10 + 18 + 1(SPACE) = //56 const PROGMEM uint8_t cwAZTable[27] = {0b00100100 , 0b01001000 , 0b01001010 , 0b00111000 , 0b00010000, 0b01000010, 0b00111100, 0b01000000 , //A ~ H 0b00100000, 0b01000111 ,0b00111010, 0b01000100, 0b00101100, 0b00101000 , 0b00111110, 0b01000110, 0b01001101, 0b00110100, //I ~ R -0b00110000, 0b00011000, 0b00110010, 0b01000001, 0b00110110, 0b01001001, 0b01001011, 0b00111000}; //S ~ Z +0b00110000, 0b00011000, 0b00110010, 0b01000001, 0b00110110, 0b01001001, 0b01001011, 0b01001100}; //S ~ Z PGM_P pCwAZTable = reinterpret_cast(cwAZTable); const PROGMEM uint8_t cw09Table[27] = {0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001, 0b00000000, 0b00010000, 0b00011000, 0b00011100, 0b00011110}; @@ -297,7 +297,7 @@ void controlAutoCW(){ displayScrolStep = 0; } - printLineFromEEPRom(0, 2, cwStartIndex + displayScrolStep + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ); + printLineFromEEPRom(0, 2, cwStartIndex + displayScrolStep + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ, 0); byte diplayAutoCWLine = 0; if ((displayOption1 & 0x01) == 0x01) diff --git a/ubitx_20/ubitx.h b/ubitx_20/ubitx.h new file mode 100644 index 0000000..64fcd3f --- /dev/null +++ b/ubitx_20/ubitx.h @@ -0,0 +1,80 @@ +/************************************************************************* + header file for C++ by KD8CEC +----------------------------------------------------------------------------- + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +**************************************************************************/ +#define WSPR_COUNT 443 //WSPR_MESSAGE_COUNT +#define WSPR_MESSAGE1 444 // +#define WSPR_MESSAGE2 490 // +#define WSPR_MESSAGE3 536 // +#define WSPR_MESSAGE4 582 // + +#define WSPR_BAND_COUNT 3 + +#define TX_SSB 0 +#define TX_CW 1 + + +extern void printLine1(const char *c); +extern void printLine2(const char *c); +extern void printLineF(char linenmbr, const __FlashStringHelper *c); +extern void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetType); +extern byte delay_background(unsigned delayTime, byte fromType); +extern int btnDown(void); +extern char c[30]; +extern char b[30]; + +extern unsigned long frequency; + +#define printLineF1(x) (printLineF(1, x)) +#define printLineF2(x) (printLineF(0, x)) + + +/** + * 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. + * This assignment is as follows : + * Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + * GND +5V CLK0 GND GND CLK1 GND GND CLK2 GND D2 D3 D4 D5 D6 D7 + * These too are flexible with what you may do with them, for the Raduino, we use them to : + * - TX_RX line : Switches between Transmit and Receive after sensing the PTT or the morse keyer + * - CW_KEY line : turns on the carrier for CW + */ + +#define TX_RX (7) +#define CW_TONE (6) +#define TX_LPF_A (5) +#define TX_LPF_B (4) +#define TX_LPF_C (3) +#define CW_KEY (2) + +//we directly generate the CW by programmin the Si5351 to the cw tx frequency, hence, both are different modes +//these are the parameter passed to startTx +#define TX_SSB 0 +#define TX_CW 1 + +extern void si5351bx_init(void); +extern void si5351bx_setfreq(uint8_t clknum, uint32_t fout); +extern void si5351_set_calibration(int32_t cal); +extern void initOscillators(void); +extern void Set_WSPR_Param(void); +extern void TXSubFreq(unsigned long P2); + +extern void startTx(byte txMode, byte isDisplayUpdate); +extern void stopTx(void); +extern void setTXFilters(unsigned long freq); + +extern void SendWSPRManage(void); +extern byte WsprMSGCount; + + diff --git a/ubitx_20/ubitx_20.ino b/ubitx_20/ubitx_20.ino index 2beacab..0e61328 100644 --- a/ubitx_20/ubitx_20.ino +++ b/ubitx_20/ubitx_20.ino @@ -38,6 +38,7 @@ */ #include #include +#include "ubitx.h" /** The main chip which generates upto three oscillators of various frequencies in the @@ -180,6 +181,12 @@ int count = 0; //to generally count ticks, loops, etc //(7:Enable / Disable //0: enable, 1:disable, (default is applied shift) //6 : 0 : Adjust Pulus, 1 : Adjust Minus //0~5: Adjust Value : * 10 = Adjust Value (0~300) +#define COMMON_OPTION0 360 //0: Confirm : CW Frequency Shift + //1 : IF Shift Save + // + // + // +#define IF_SHIFTVALUE 363 #define DISPLAY_OPTION1 361 //Display Option1 #define DISPLAY_OPTION2 362 //Display Option2 @@ -272,6 +279,7 @@ byte isTxType = 0; //000000[0 - isSplit] [0 - isTXStop] long arTuneStep[5]; byte tuneStepIndex; //default Value 0, start Offset is 0 because of check new user +byte commonOption0 = 0; byte displayOption1 = 0; byte displayOption2 = 0; @@ -330,7 +338,7 @@ byte line2DisplayStatus = 0; //0:Clear, 1 : menu, 1: DisplayFrom Idle, char lcdMeter[17]; byte isIFShift = 0; //1 = ifShift, 2 extend -long ifShiftValue = 0; // +int ifShiftValue = 0; // /** * Below are the basic functions that control the uBitx. Understanding the functions before @@ -491,28 +499,29 @@ void setTXFilters(unsigned long freq){ void setFrequency(unsigned long f){ f = (f / arTuneStep[tuneStepIndex -1]) * arTuneStep[tuneStepIndex -1]; - setTXFilters(f); + unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (inTx == 0) ? ifShiftValue : 0)); + if (cwMode == 0) { if (isUSB){ - si5351bx_setfreq(2, SECOND_OSC_USB - usbCarrier + f + (isIFShift ? ifShiftValue : 0)); + si5351bx_setfreq(2, SECOND_OSC_USB - appliedCarrier + f); si5351bx_setfreq(1, SECOND_OSC_USB); } else{ - si5351bx_setfreq(2, SECOND_OSC_LSB + usbCarrier + f + (isIFShift ? ifShiftValue : 0)); + si5351bx_setfreq(2, SECOND_OSC_LSB + appliedCarrier + f); si5351bx_setfreq(1, SECOND_OSC_LSB); } } else { if (cwMode == 1){ //CWL - si5351bx_setfreq(2, SECOND_OSC_LSB + cwmCarrier + f + (isIFShift ? ifShiftValue : 0)); + si5351bx_setfreq(2, SECOND_OSC_LSB + appliedCarrier + f); si5351bx_setfreq(1, SECOND_OSC_LSB); } else{ //CWU - si5351bx_setfreq(2, SECOND_OSC_USB - cwmCarrier + f + (isIFShift ? ifShiftValue : 0)); + si5351bx_setfreq(2, SECOND_OSC_USB - appliedCarrier + f); si5351bx_setfreq(1, SECOND_OSC_USB); } } @@ -542,7 +551,9 @@ void startTx(byte txMode, byte isDisplayUpdate){ ritRxFrequency = frequency; setFrequency(ritTxFrequency); } - else if (splitOn == 1) { + else + { + if (splitOn == 1) { if (vfoActive == VFO_B) { vfoActive = VFO_A; frequency = vfoA; @@ -553,10 +564,12 @@ void startTx(byte txMode, byte isDisplayUpdate){ frequency = vfoB; byteToMode(vfoB_mode, 0); } + } - setFrequency(frequency); + setFrequency(frequency); } //end of else - + + SetCarrierFreq(); if (txMode == TX_CW){ //turn off the second local oscillator and the bfo @@ -589,19 +602,24 @@ void startTx(byte txMode, byte isDisplayUpdate){ updateDisplay(); } -void stopTx(){ +void stopTx(void){ inTx = 0; digitalWrite(TX_RX, 0); //turn off the tx +/* if (cwMode == 0) si5351bx_setfreq(0, usbCarrier + (isIFShift ? ifShiftValue : 0)); //set back the carrier oscillator anyway, cw tx switches it off else si5351bx_setfreq(0, cwmCarrier + (isIFShift ? ifShiftValue : 0)); //set back the carrier oscillator anyway, cw tx switches it off +*/ + SetCarrierFreq(); if (ritOn) setFrequency(ritRxFrequency); - else if (splitOn == 1) { + else + { + if (splitOn == 1) { //vfo Change if (vfoActive == VFO_B){ vfoActive = VFO_A; @@ -613,10 +631,10 @@ void stopTx(){ frequency = vfoB; byteToMode(vfoB_mode, 0); } - setFrequency(frequency); - } //end of else - else + } + setFrequency(frequency); + } //end of else updateDisplay(); } @@ -706,8 +724,7 @@ void doTuningWithThresHold(){ (vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) return; - if (isCWAutoMode == 0 || cwAutoDialType == 1) - s = enc_read(); + s = enc_read(); //if time is exceeded, it is recognized as an error, //ignore exists values, because of errors @@ -886,6 +903,7 @@ void initSettings(){ } + EEPROM.get(COMMON_OPTION0, commonOption0); EEPROM.get(DISPLAY_OPTION1, displayOption1); EEPROM.get(DISPLAY_OPTION2, displayOption2); @@ -973,18 +991,29 @@ void initSettings(){ //Display Type for CW mode isShiftDisplayCWFreq = EEPROM.read(CW_DISPLAY_SHIFT); - //Adjust CW Mode Freq - shiftDisplayAdjustVal = (isShiftDisplayCWFreq & 0x3F) * 10; + //Enable / Diable Check for CW Display Cofiguration Group + if ((commonOption0 & 0x80) != 0x00) + { + //Adjust CW Mode Freq + shiftDisplayAdjustVal = (isShiftDisplayCWFreq & 0x3F) * 10; + + //check Minus + if ((isShiftDisplayCWFreq & 0x40) == 0x40) + shiftDisplayAdjustVal = shiftDisplayAdjustVal * -1; + + //Shift Display Check (Default : 0) + if ((isShiftDisplayCWFreq & 0x80) == 0) //Enabled + isShiftDisplayCWFreq = 1; + else //Disabled + isShiftDisplayCWFreq = 0; + } - //check Minus - if ((isShiftDisplayCWFreq & 0x40) == 0x40) - shiftDisplayAdjustVal = shiftDisplayAdjustVal * -1; - - //Shift Display Check (Default : 0) - if ((isShiftDisplayCWFreq & 0x80) == 0) //Enabled - isShiftDisplayCWFreq = 1; - else //Disabled - isShiftDisplayCWFreq = 0; + //Stored IF Shift Option + if ((commonOption0 & 0x40) != 0x00) + { + EEPROM.get(IF_SHIFTVALUE, ifShiftValue); + isIFShift = ifShiftValue != 0; + } //default Value (for original hardware) if (cwAdcSTFrom >= cwAdcSTTo) @@ -1022,10 +1051,10 @@ void initSettings(){ //original code with modified by kd8cec if (usbCarrier > 12010000l || usbCarrier < 11990000l) - usbCarrier = 11995000l; + usbCarrier = 11997000l; if (cwmCarrier > 12010000l || cwmCarrier < 11990000l) - cwmCarrier = 11995000l; + cwmCarrier = 11997000l; if (vfoA > 35000000l || 3500000l > vfoA) { vfoA = 7150000l; @@ -1109,7 +1138,8 @@ void setup() //Serial.begin(9600); lcd.begin(16, 2); - printLineF(1, F("CECBT v1.04")); + //printLineF(1, F("CECBT v1.05")); + printLineF(1, F("CE v1.06")); Init_Cat(38400, SERIAL_8N1); initMeter(); //not used in this build @@ -1117,7 +1147,7 @@ void setup() if (userCallsignLength > 0 && ((userCallsignLength & 0x80) == 0x80)) { userCallsignLength = userCallsignLength & 0x7F; - printLineFromEEPRom(0, 0, 0, userCallsignLength -1); //eeprom to lcd use offset (USER_CALLSIGN_DAT) + printLineFromEEPRom(0, 0, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT) delay(500); } else { @@ -1177,12 +1207,13 @@ void loop(){ //tune only when not tranmsitting if (!inTx){ - if (ritOn) - doRIT(); - //else if (isIFShift) - // doIFShift(); - else - doTuningWithThresHold(); + if (isCWAutoMode == 0 || cwAutoDialType == 1) + { + if (ritOn) + doRIT(); + else + doTuningWithThresHold(); + } if (isCWAutoMode == 0 && beforeIdle_ProcessTime < millis() - 250) { idle_process(); diff --git a/ubitx_20/ubitx_idle.ino b/ubitx_20/ubitx_idle.ino index 663a291..87aa25e 100644 --- a/ubitx_20/ubitx_idle.ino +++ b/ubitx_20/ubitx_idle.ino @@ -32,14 +32,6 @@ void updateLine2Buffer(char isDirectCall) if (ritOn) { strcpy(line2Buffer, "RitTX:"); - /* - line2Buffer[0] = 'R'; - line2Buffer[1] = 'i'; - line2Buffer[2] = 't'; - line2Buffer[3] = 'T'; - line2Buffer[4] = 'X'; - line2Buffer[5] = ':'; - */ //display frequency tmpFreq = ritTxFrequency; diff --git a/ubitx_20/ubitx_keyer.ino b/ubitx_20/ubitx_keyer.ino index 308bf7d..1ac1c2f 100644 --- a/ubitx_20/ubitx_keyer.ino +++ b/ubitx_20/ubitx_keyer.ino @@ -168,6 +168,8 @@ void cwKeyer(void){ break; case KEYED_PREP: + //modified KD8CEC + /* ktimer += millis(); // set ktimer to interval end time keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits keyerState = KEYED; // next state @@ -179,6 +181,19 @@ void cwKeyer(void){ cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT; startTx(TX_CW, 1); } + */ + if (!inTx){ + //DelayTime Option + delay_background(delayBeforeCWStartTime * 2, 2); + + keyDown = 0; + cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT; + startTx(TX_CW, 1); + } + ktimer += millis(); // set ktimer to interval end time + keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits + keyerState = KEYED; // next state + cwKeydown(); break; diff --git a/ubitx_20/ubitx_menu.ino b/ubitx_20/ubitx_menu.ino index c531305..4b7d9be 100644 --- a/ubitx_20/ubitx_menu.ino +++ b/ubitx_20/ubitx_menu.ino @@ -10,8 +10,7 @@ * - 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 */ -#define printLineF1(x) (printLineF(1, x)) -#define printLineF2(x) (printLineF(0, x)) +#include "ubitx.h" //Current Frequency and mode to active VFO by KD8CEC void FrequencyToVFO(byte isSaveFreq) @@ -64,11 +63,13 @@ void menuBand(int btn){ btnPressCount = 0; if (tuneTXType > 0) { //Just toggle 0 <-> 2, if tuneTXType is 100, 100 -> 0 -> 2 tuneTXType = 0; - printLineF2(F("General mode")); + //printLineF2(F("General mode")); + printLineF2(F("General")); } else { tuneTXType = 2; - printLineF2(F("Ham band mode")); + //printLineF2(F("Ham band mode")); + printLineF2(F("Ham band")); } delay_background(1000, 0); printLine2ClearAndUpdate(); @@ -179,7 +180,7 @@ void menuIFSSetup(int btn){ if (isIFShift == 1) printLineF2(F("IF Shift Change?")); else - printLineF2(F("IF Shift:Off, On?")); + printLineF2(F("IF Shift On?")); } else { isIFShift = 1; @@ -194,11 +195,13 @@ void menuIFSSetup(int btn){ { updateLine2Buffer(1); setFrequency(frequency); - + /* if (cwMode == 0) si5351bx_setfreq(0, usbCarrier + (isIFShift ? ifShiftValue : 0)); //set back the carrier oscillator anyway, cw tx switches it off else si5351bx_setfreq(0, cwmCarrier + (isIFShift ? ifShiftValue : 0)); //set back the carrier oscillator anyway, cw tx switches it off + */ + SetCarrierFreq(); needApplyChangeValue = 0; } @@ -206,12 +209,13 @@ void menuIFSSetup(int btn){ knob = enc_read(); if (knob != 0){ if (knob < 0) - ifShiftValue -= 50l; + ifShiftValue -= 50; else if (knob > 0) ifShiftValue += 50; needApplyChangeValue = 1; } + Check_Cat(0); //To prevent disconnections } delay_background(500, 0); //for check Long Press function key @@ -219,13 +223,18 @@ void menuIFSSetup(int btn){ if (btnDown() || ifShiftValue == 0) { isIFShift = 0; - printLineF2(F("IF Shift is OFF")); + ifShiftValue = 0; + //printLineF2(F("IF Shift is OFF")); + //printLineF2(F("OFF")); + //clearLine2(); setFrequency(frequency); - delay_background(1500, 0); + SetCarrierFreq(); + //delay_background(1500, 0); } + + //Store IF Shiift + EEPROM.put(IF_SHIFTVALUE, ifShiftValue); - //menuOn = 0; - //printLine2ClearAndUpdate(); menuClearExit(0); } } @@ -303,10 +312,13 @@ void menuSelectMode(int btn){ FrequencyToVFO(1); } + /* if (cwMode == 0) si5351bx_setfreq(0, usbCarrier + (isIFShift ? ifShiftValue : 0)); //set back the carrier oscillator anyway, cw tx switches it off else si5351bx_setfreq(0, cwmCarrier + (isIFShift ? ifShiftValue : 0)); //set back the carrier oscillator anyway, cw tx switches it off + */ + SetCarrierFreq(); setFrequency(frequency); menuClearExit(500); @@ -339,7 +351,8 @@ void menuCHMemory(int btn, byte isMemoryToVfo){ if (selectChannel >= 20 || selectChannel <=-1) { - strcpy(c, "Exit setup?"); + //strcpy(c, "Exit setup?"); + strcpy(c, "Exit?"); } else { @@ -603,9 +616,9 @@ void menuVfoToggle(int btn) void menuRitToggle(int btn){ if (!btn){ if (ritOn == 1) - printLineF2(F("RIT:On, Off?")); + printLineF2(F("RIT Off?")); else - printLineF2(F("RIT:Off, On?")); + printLineF2(F("RIT On?")); } else { if (ritOn == 0){ @@ -633,20 +646,21 @@ void menuSplitOnOff(int btn){ else { if (splitOn == 1){ splitOn = 0; - printLineF2(F("Split Off!")); + //printLineF2(F("Split Off!")); + printLineF2(F("[OFF]")); } else { splitOn = 1; if (ritOn == 1) ritOn = 0; - printLineF2(F("Split On!")); + //printLineF2(F("Split On!")); + printLineF2(F("[ON]")); } menuClearExit(500); } } - //Function to disbled transmission //by KD8CEC void menuTxOnOff(int btn, byte optionType){ @@ -756,23 +770,29 @@ void menuCWSpeed(int btn){ menuClearExit(1000); } +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("CW AutoKey Mode?")); - return; + 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) { - printLineF2(F("Empty CW data")); - delay_background(2000, 0); + displayEmptyData(); return; } - printLineF1(F("Press PTT to Send")); + //printLineF1(F("Press PTT to Send")); + printLineF1(F("PTT to Send")); delay_background(500, 0); updateDisplay(); beforeCWTextIndex = 255; //255 value is for start check @@ -780,6 +800,27 @@ void menuCWAutoKey(int btn){ 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); +} + + + //Modified by KD8CEC void menuSetupCwDelay(int btn){ int knob = 0; @@ -836,12 +877,6 @@ void menuSetupTXCWInterval(int btn){ } printLineF1(F("Press, set Delay")); - /* - strcpy(b, "Start Delay:"); - itoa(tmpTXCWInterval,c, 10); - strcat(b, c); - printLine2(b); - */ delay_background(300, 0); while(!btnDown()){ @@ -1261,8 +1296,6 @@ void doMenu(){ while (!btnDown()) { - //Check_Cat(0); //To prevent disconnections - //delay(50); //debounce delay_background(50, 0); if (isNeedDisplay) { @@ -1307,42 +1340,87 @@ void doMenu(){ btnState = btnDown(); if (i > 0){ - if (modeCalibrate && select + i < 220) + if (modeCalibrate && select + i < 240) select += i; - if (!modeCalibrate && select + i < 120) + if (!modeCalibrate && select + i < 130) select += i; } - //if (i < 0 && select - i >= 0) + if (i < 0 && select - i >= -10) select += i; //caught ya, i is already -ve here, so you add it - if (select < -5) - menuExit(btnState); - else if (select < 10) - menuBand(btnState); - else if (select < 20) - menuVfoToggle(btnState); - else if (select < 30) - menuSelectMode(btnState); - else if (select < 40) - menuRitToggle(btnState); - else if (select < 50) - menuIFSSetup(btnState); - else if (select < 60) - menuCWSpeed(btnState); - else if (select < 70) - menuSplitOnOff(btnState); //SplitOn / off - else if (select < 80) - menuCHMemory(btnState, 0); //VFO to Memroy - else if (select < 90) - menuCHMemory(btnState, 1); //Memory to VFO - else if (select < 100) - menuCWAutoKey(btnState); - else if (select < 110) - menuSetup(btnState); - else if (select < 120) - menuExit(btnState); - + //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 : + menuCWSpeed(btnState); + break; + case 6 : + menuSplitOnOff(btnState); //SplitOn / off + break; + case 7 : + menuCHMemory(btnState, 0); //VFO to Memroy + break; + case 8 : + menuCHMemory(btnState, 1); //Memory to VFO + break; + case 9 : + menuCWAutoKey(btnState); + break; + case 10 : + menuWSPRSend(btnState); + break; + case 11 : + menuSetup(btnState); + break; + case 12 : + menuExit(btnState); + break; + case 13 : + menuSetupCalibration(btnState); //crystal + break; + case 14 : + menuSetupCarrier(btnState); //lsb + break; + case 15 : + menuSetupCWCarrier(btnState); //lsb + break; + case 16 : + menuSetupCwTone(btnState); + break; + case 17 : + menuSetupCwDelay(btnState); + break; + case 18 : + menuSetupTXCWInterval(btnState); + break; + case 19 : + menuSetupKeyType(btnState); + break; + case 20 : + menuADCMonitor(btnState); + break; + case 21 : + menuTxOnOff(btnState, 0x01); //TX OFF / ON + break; + default : + menuExit(btnState); break; + } /* else if (select < 130 && modeCalibrate) menuSetupCalibration(btnState); //crystal @@ -1366,30 +1444,6 @@ void doMenu(){ menuExit(btnState); */ - else if (modeCalibrate) - { - if (select < 130) - menuSetupCalibration(btnState); //crystal - else if (select < 140) - menuSetupCarrier(btnState); //lsb - else if (select < 150) - menuSetupCWCarrier(btnState); //lsb - else if (select < 160) - menuSetupCwTone(btnState); - else if (select < 170) - menuSetupCwDelay(btnState); - else if (select < 180) - menuSetupTXCWInterval(btnState); - else if (select < 190) - menuSetupKeyType(btnState); - else if (select < 200) - menuADCMonitor(btnState); - else if (select < 210) - menuTxOnOff(btnState, 0x01); //TX OFF / ON - else if (select < 220) - menuExit(btnState); - } - Check_Cat(0); //To prevent disconnections } diff --git a/ubitx_20/ubitx_si5351.ino b/ubitx_20/ubitx_si5351.ino index 6d16af2..87819f8 100644 --- a/ubitx_20/ubitx_si5351.ino +++ b/ubitx_20/ubitx_si5351.ino @@ -1,3 +1,19 @@ +/************************************************************************************ + * KD8CEC + * kd8cec@gmail.com http://www.hamskey.com + * + * Merge two SI5351 Librarys + * KE7ER's fixed vco and variable Clocks Configure values + * G3ZIL's fixed Clock Configure Value and variable VCO + * * I have combined the two libraries above. All licenses follow the above library. + * + * PLL-A is generated by fixing 850Mhz clock. All output clocks use PLL-A to + * generate the frequency. This is the method used in QRP radios such as uBITX. + * When switching to WSPR transmission mode, PLL-B operates for the base frequency to transmit WSPR. + * The output clock channel that controls the frequency is connected to the PLL-B. + * The WSPR protocol is generated by changing the clock of the PLL-B. + ************************************************************************************/ + // ************* SI5315 routines - tks Jerry Gaffke, KE7ER *********************** // An minimalist standalone set of Si5351 routines. @@ -108,15 +124,48 @@ void si5351_set_calibration(int32_t cal){ si5351bx_setfreq(0, usbCarrier); } +void SetCarrierFreq() +{ + unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (inTx == 0) ? ifShiftValue : 0)); + si5351bx_setfreq(0, appliedCarrier); + + /* + if (cwMode == 0) + si5351bx_setfreq(0, usbCarrier + (isIFShift ? ifShiftValue : 0)); + else + si5351bx_setfreq(0, cwmCarrier + (isIFShift ? ifShiftValue : 0)); + */ +} + void initOscillators(){ //initialize the SI5351 si5351bx_init(); si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + calibration; // apply the calibration correction factor + SetCarrierFreq(); +} - if (cwMode == 0) - si5351bx_setfreq(0, usbCarrier + (isIFShift ? ifShiftValue : 0)); - else - si5351bx_setfreq(0, cwmCarrier + (isIFShift ? ifShiftValue : 0)); +//============================================================ +// ADD FUNCTIONS by KD8CEC +//============================================================ +uint8_t Wspr_Reg1[8] = {0xFF,0xFE, 0x00, 0, 0, 0, 0, 0}; //3, 4, 5, 6, 7 +uint8_t Wspr_Reg2[8] = {0, 1, 0, 0, 0, 0, 0, 0}; //2, 3, 4 + +void Set_WSPR_Param(void) +{ + i2cWrite(18, 128); + i2cWriten(34, Wspr_Reg1, 8); + i2cWriten(58, Wspr_Reg2, 8); + i2cWrite(177, 128); + i2cWrite(18, 111); + + si5351bx_clken &= ~(1 << 2); + i2cWrite(3, si5351bx_clken); +} + +void TXSubFreq(unsigned long P2) +{ + i2cWrite(40, (P2 & 65280) >> 8); + i2cWrite(41, P2 & 255); } diff --git a/ubitx_20/ubitx_ui.ino b/ubitx_20/ubitx_ui.ino index ad55426..c5089ea 100644 --- a/ubitx_20/ubitx_ui.ino +++ b/ubitx_20/ubitx_ui.ino @@ -9,7 +9,7 @@ //#define printLineF2(x) (printLineF(0, x)) //returns true if the button is pressed -int btnDown(){ +int btnDown(void){ if (digitalRead(FBUTTON) == HIGH) return 0; else @@ -173,7 +173,7 @@ void printLineF(char linenmbr, const __FlashStringHelper *c) } #define LCD_MAX_COLUMN 16 -void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex) { +void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) { if ((displayOption1 & 0x01) == 0x01) linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle @@ -182,7 +182,7 @@ void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, b for (byte i = eepromStartIndex; i <= eepromEndIndex; i++) { if (++lcdColumn <= LCD_MAX_COLUMN) - lcd.write(EEPROM.read(USER_CALLSIGN_DAT + i)); + lcd.write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i)); else break; } diff --git a/ubitx_20/ubitx_wspr.cpp b/ubitx_20/ubitx_wspr.cpp new file mode 100644 index 0000000..c87c1a7 --- /dev/null +++ b/ubitx_20/ubitx_wspr.cpp @@ -0,0 +1,193 @@ +/********************************************************************************** +WSPR SENDER for uBITX by KD8CEC +Some of the code that sends WSPR referenced the code in G3ZIL. +Thanks to G3ZIL for sharing great code. + +Due to the limited memory of uBITX, I have implemented at least only a few of the codes in uBITX. + +Thanks for testing +Beta Tester : + +----------------------------------------------------------------------------- + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +**********************************************************************************/ + +#include +#include +#include "ubitx.h" + +//begin of test +byte WsprToneCode[164]; + +long lastTime=0; +unsigned long TX_MSNB_P2; // Si5351 register MSNB_P2 PLLB for Tx +unsigned long TX_P2; // Variable values for MSNB_P2 which defines the frequencies for the data + +extern int enc_read(void); + +byte WsprMSGCount = 0; +#define PTT (A3) + +#define WSPR_BAND1 401 + +extern uint8_t Wspr_Reg1[8]; //3, 4, 5, 6, 7 +extern uint8_t Wspr_Reg2[8]; //2, 3, 4 + +void SendWSPRManage() +{ + int knob = 0; + byte knobPosition = 0; + char isNeedDisplayInfo = 0; + char nowSelectedIndex = 0; + char nowWsprStep = 0; //0 : select Message, 1 : select band, 2 : send + char selectedWsprMessageIndex = -1; + char selectedWsprBandIndex = -1; + + unsigned long WsprTXFreq = 0; + unsigned int WsprMultiChan = 0; + unsigned long prevFreq; + char loopIndex; + + delay_background(500, 0); + + //Readed WsprMSGCount, WsprTone + while(1) + { + knob = enc_read(); + + if (knobPosition > 0 && knob < 0) + knobPosition--; + else if (knob > 0 && (knobPosition <= (nowWsprStep == 0 ? WsprMSGCount : WSPR_BAND_COUNT) * 10 -2)) + knobPosition++; + + nowSelectedIndex = knobPosition / 10; + + if (nowWsprStep == 0) //select Message status + { + printLineF2(F("WSPR:")); + + if (selectedWsprMessageIndex != nowSelectedIndex) + { + selectedWsprMessageIndex = nowSelectedIndex; + int wsprMessageBuffIndex = selectedWsprMessageIndex * 46; + + //Display WSPR Name tag + printLineFromEEPRom(0, 6, wsprMessageBuffIndex, wsprMessageBuffIndex + 4, 1); + + //Load WSPR Tonecode + //Read Tone Code + for (int i = 0; i < 41; i++) + { + byte readData = EEPROM.read(WSPR_MESSAGE1 + 5 + (wsprMessageBuffIndex) + i); //NAME TAG 5, MESSAGE 41 = 46 + WsprToneCode[i * 4 + 0] = readData & 3; + WsprToneCode[i * 4 + 1] = (readData >> 2) & 3; + WsprToneCode[i * 4 + 2] = (readData >> 4) & 3; + WsprToneCode[i * 4 + 3] = (readData >> 6) & 3; + } + } + else if (btnDown()) + { + nowWsprStep = 1; //Change Status to Select Band + knobPosition = 0; + nowSelectedIndex = 0; + delay_background(500, 0); + } + } + else if (nowWsprStep == 1) + { + //printLineF2(F("Select Band")); + if (selectedWsprBandIndex != nowSelectedIndex) + { + selectedWsprBandIndex = nowSelectedIndex; + int bandBuffIndex = WSPR_BAND1 + selectedWsprBandIndex * 14; + + EEPROM.get(bandBuffIndex, WsprTXFreq); + EEPROM.get(bandBuffIndex + 4, WsprMultiChan); + + /* + //3, 4, 5, 6, 7 + Wspr_Reg1[3] = EEPROM.read(bandBuffIndex + 6); + Wspr_Reg1[4] = EEPROM.read(bandBuffIndex + 7); + Wspr_Reg1[5] = EEPROM.read(bandBuffIndex + 8); + Wspr_Reg1[6] = EEPROM.read(bandBuffIndex + 9); + Wspr_Reg1[7] = EEPROM.read(bandBuffIndex + 10); + */ + for (loopIndex = 3; loopIndex < 8; loopIndex++) + Wspr_Reg1[loopIndex] = EEPROM.read(bandBuffIndex + loopIndex + 3); + + /* + Wspr_Reg2[2] = EEPROM.read(bandBuffIndex + 11); + Wspr_Reg2[3] = EEPROM.read(bandBuffIndex + 12); + Wspr_Reg2[4] = EEPROM.read(bandBuffIndex + 13); + */ + //2, 3, 4 + for (loopIndex = 2; loopIndex < 5; loopIndex++) + Wspr_Reg2[loopIndex] = EEPROM.read(bandBuffIndex + loopIndex + 9); + + TX_MSNB_P2 = ((unsigned long)Wspr_Reg1[5] & 0x0F) << 16 | ((unsigned long)Wspr_Reg1[6]) << 8 | Wspr_Reg1[7]; + } + + ltoa(WsprTXFreq, b, DEC); + if (digitalRead(PTT) == 0) + strcpy(c, "SEND:"); + else + strcpy(c, "PTT->"); + + strcat(c, b); + printLine1(c); + + if (digitalRead(PTT) == 0) + { + //printLineF1(F("Transmitting")); + //SEND WSPR + //If you need to consider the Rit and Sprite modes, uncomment them below. + //remark = To reduce the size of the program + //prevFreq = frequency; + //frequency = WsprTXFreq; + setTXFilters(WsprTXFreq); + startTx(TX_CW, 0); + + //Start WSPR + Set_WSPR_Param(); + digitalWrite(CW_KEY, 1); + + for (int i = 0; i < 162; i++) + { // Now this is the message loop + lastTime = millis(); // Store away the time when the last message symbol was sent + TX_P2 = TX_MSNB_P2 + WsprMultiChan * WsprToneCode[i]; // This represents the 1.46 Hz shift and is correct only for the bands specified in the array + TXSubFreq(TX_P2); // TX at the appropriate channel frequency for.... + + //if (btnDown()) + // break; + + while (millis() < lastTime + 683){} // .... 0,683 seconds + } + + digitalWrite(CW_KEY, 0); + stopTx(); //call setFrequency -> recovery TX Filter + //frequency = prevFreq; + + selectedWsprBandIndex = -1; + } //end of PTT Check + else if (btnDown()) + { + return; + } + + } //end of status check + + //delay_background(50, 1); + } //end of while +} +