kopia lustrzana https://github.com/afarhan/ubitx4
716 wiersze
14 KiB
C++
716 wiersze
14 KiB
C++
/** 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
|
|
*/
|
|
|
|
|
|
/** A generic control to read variable values
|
|
*/
|
|
int getValueByKnob(int minimum, int maximum, int step_size, int initial, char* prefix, char *postfix)
|
|
{
|
|
int knob = 0;
|
|
int knob_value;
|
|
|
|
while (btnDown())
|
|
active_delay(100);
|
|
|
|
active_delay(200);
|
|
knob_value = initial;
|
|
|
|
strcpy(b, prefix);
|
|
itoa(knob_value, c, 10);
|
|
strcat(b, c);
|
|
strcat(b, postfix);
|
|
printLine2(b);
|
|
active_delay(300);
|
|
|
|
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;
|
|
|
|
printLine2(prefix);
|
|
itoa(knob_value, c, 10);
|
|
strcpy(b, c);
|
|
strcat(b, postfix);
|
|
printLine1(b);
|
|
}
|
|
checkCAT();
|
|
}
|
|
|
|
return knob_value;
|
|
}
|
|
|
|
//# Menu: 1
|
|
|
|
int menuBand(int btn){
|
|
int knob = 0;
|
|
int band;
|
|
unsigned long offset;
|
|
|
|
// band = frequency/1000000l;
|
|
// offset = frequency % 1000000l;
|
|
|
|
if (!btn){
|
|
printLine2("Band Select \x7E");
|
|
return;
|
|
}
|
|
|
|
printLine2("Band Select:");
|
|
//wait for the button menu select button to be lifted)
|
|
while (btnDown())
|
|
active_delay(50);
|
|
active_delay(50);
|
|
ritDisable();
|
|
|
|
while(!btnDown()){
|
|
|
|
knob = enc_read();
|
|
if (knob != 0){
|
|
/*
|
|
if (band > 3 && knob < 0)
|
|
band--;
|
|
if (band < 30 && knob > 0)
|
|
band++;
|
|
if (band > 10)
|
|
isUSB = true;
|
|
else
|
|
isUSB = false;
|
|
setFrequency(((unsigned long)band * 1000000l) + offset); */
|
|
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();
|
|
}
|
|
checkCAT();
|
|
active_delay(20);
|
|
}
|
|
|
|
while(btnDown())
|
|
active_delay(50);
|
|
active_delay(50);
|
|
|
|
printLine2("");
|
|
updateDisplay();
|
|
menuOn = 0;
|
|
}
|
|
|
|
// Menu #2
|
|
void menuRitToggle(int btn){
|
|
if (!btn){
|
|
if (ritOn == 1)
|
|
printLine2("RIT On \x7E Off");
|
|
else
|
|
printLine2("RIT Off \x7E On");
|
|
}
|
|
else {
|
|
if (ritOn == 0){
|
|
//enable RIT so the current frequency is used at transmit
|
|
ritEnable(frequency);
|
|
printLine2("RIT is On");
|
|
|
|
}
|
|
else{
|
|
ritDisable();
|
|
printLine2("RIT is Off");
|
|
}
|
|
menuOn = 0;
|
|
active_delay(500);
|
|
printLine2("");
|
|
updateDisplay();
|
|
}
|
|
}
|
|
|
|
|
|
//Menu #3
|
|
void menuVfoToggle(int btn){
|
|
|
|
if (!btn){
|
|
if (vfoActive == VFO_A)
|
|
printLine2("VFO A \x7E B");
|
|
else
|
|
printLine2("VFO B \x7E A");
|
|
}
|
|
else {
|
|
if (vfoActive == VFO_B){
|
|
vfoB = frequency;
|
|
isUsbVfoB = isUSB;
|
|
EEPROM.put(VFO_B, frequency);
|
|
if (isUsbVfoB)
|
|
EEPROM.put(VFO_B_MODE, VFO_MODE_USB);
|
|
else
|
|
EEPROM.put(VFO_B_MODE, VFO_MODE_LSB);
|
|
|
|
vfoActive = VFO_A;
|
|
// printLine2("Selected VFO A ");
|
|
frequency = vfoA;
|
|
isUSB = isUsbVfoA;
|
|
}
|
|
else {
|
|
vfoA = frequency;
|
|
isUsbVfoA = isUSB;
|
|
EEPROM.put(VFO_A, frequency);
|
|
if (isUsbVfoA)
|
|
EEPROM.put(VFO_A_MODE, VFO_MODE_USB);
|
|
else
|
|
EEPROM.put(VFO_A_MODE, VFO_MODE_LSB);
|
|
|
|
vfoActive = VFO_B;
|
|
// printLine2("Selected VFO B ");
|
|
frequency = vfoB;
|
|
isUSB = isUsbVfoB;
|
|
}
|
|
|
|
ritDisable();
|
|
setFrequency(frequency);
|
|
updateDisplay();
|
|
printLine2("");
|
|
//exit the menu
|
|
menuOn = 0;
|
|
}
|
|
}
|
|
|
|
// Menu #4
|
|
void menuSidebandToggle(int btn){
|
|
if (!btn){
|
|
if (isUSB == true)
|
|
printLine2("USB \x7E LSB");
|
|
else
|
|
printLine2("LSB \x7E USB");
|
|
}
|
|
else {
|
|
if (isUSB == true){
|
|
isUSB = false;
|
|
printLine2("LSB Selected");
|
|
active_delay(500);
|
|
printLine2("");
|
|
}
|
|
else {
|
|
isUSB = true;
|
|
printLine2("USB Selected");
|
|
active_delay(500);
|
|
printLine2("");
|
|
}
|
|
//Added by KD8CEC
|
|
if (vfoActive == VFO_B){
|
|
isUsbVfoB = isUSB;
|
|
}
|
|
else {
|
|
isUsbVfoB = isUSB;
|
|
}
|
|
updateDisplay();
|
|
menuOn = 0;
|
|
}
|
|
}
|
|
|
|
//Split communication using VFOA and VFOB by KD8CEC
|
|
//Menu #5
|
|
void menuSplitToggle(int btn){
|
|
if (!btn){
|
|
if (splitOn == 0)
|
|
printLine2("Split Off \x7E On");
|
|
else
|
|
printLine2("Split On \x7E Off");
|
|
}
|
|
else {
|
|
if (splitOn == 1){
|
|
splitOn = 0;
|
|
printLine2("Split ON");
|
|
}
|
|
else {
|
|
splitOn = 1;
|
|
if (ritOn == 1)
|
|
ritOn = 0;
|
|
printLine2("Split Off");
|
|
}
|
|
active_delay(500);
|
|
printLine2("");
|
|
updateDisplay();
|
|
menuOn = 0;
|
|
}
|
|
}
|
|
|
|
int menuCWSpeed(int btn){
|
|
int knob = 0;
|
|
int wpm;
|
|
|
|
wpm = 1200/cwSpeed;
|
|
|
|
if (!btn){
|
|
strcpy(b, "CW: ");
|
|
itoa(wpm,c, 10);
|
|
strcat(b, c);
|
|
strcat(b, " WPM \x7E");
|
|
printLine2(b);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
printLine1("Press FN to Set");
|
|
strcpy(b, "5:CW>");
|
|
itoa(wpm,c, 10);
|
|
strcat(b, c);
|
|
strcat(b, " WPM");
|
|
printLine2(b);
|
|
active_delay(300);
|
|
|
|
while(!btnDown() && digitalRead(PTT) == HIGH){
|
|
|
|
knob = enc_read();
|
|
if (knob != 0){
|
|
if (wpm > 3 && knob < 0)
|
|
wpm--;
|
|
if (wpm < 50 && knob > 0)
|
|
wpm++;
|
|
|
|
strcpy(b, "5:CW>");
|
|
itoa(wpm,c, 10);
|
|
strcat(b, c);
|
|
strcat(b, " WPM");
|
|
printLine2(b);
|
|
}
|
|
//abort if this button is down
|
|
if (btnDown())
|
|
//re-enable the clock1 and clock 2
|
|
break;
|
|
checkCAT();
|
|
}
|
|
*/
|
|
wpm = getValueByKnob(1, 100, 1, wpm, "CW: ", " WPM>");
|
|
|
|
printLine2("CW Speed set!");
|
|
cwSpeed = 1200/wpm;
|
|
EEPROM.put(CW_SPEED, cwSpeed);
|
|
active_delay(500);
|
|
|
|
printLine2("");
|
|
updateDisplay();
|
|
menuOn = 0;
|
|
}
|
|
|
|
void menuExit(int btn){
|
|
|
|
if (!btn){
|
|
printLine2("Exit Menu \x7E");
|
|
}
|
|
else{
|
|
printLine2("Exiting...");
|
|
active_delay(500);
|
|
printLine2("");
|
|
updateDisplay();
|
|
menuOn = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The calibration routines are not normally shown in the menu as they are rarely used
|
|
* They can be enabled by choosing this menu option
|
|
*/
|
|
int menuSetup(int btn){
|
|
if (!btn){
|
|
if (!modeCalibrate)
|
|
printLine2("Settings \x7E");
|
|
else
|
|
printLine2("Settings \x7E Off");
|
|
}else {
|
|
if (!modeCalibrate){
|
|
modeCalibrate = true;
|
|
printLine2("Settings On");
|
|
}
|
|
else {
|
|
modeCalibrate = false;
|
|
printLine2("Settings Off");
|
|
}
|
|
|
|
while(btnDown())
|
|
active_delay(100);
|
|
active_delay(500);
|
|
printLine2("");
|
|
return 10;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//this is used by the si5351 routines in the ubitx_5351 file
|
|
extern int32_t calibration;
|
|
extern uint32_t si5351bx_vcoa;
|
|
|
|
int calibrateClock(){
|
|
int knob = 0;
|
|
int32_t prev_calibration;
|
|
|
|
|
|
//keep clear of any previous button press
|
|
while (btnDown())
|
|
active_delay(100);
|
|
active_delay(100);
|
|
|
|
digitalWrite(TX_LPF_A, 0);
|
|
digitalWrite(TX_LPF_B, 0);
|
|
digitalWrite(TX_LPF_C, 0);
|
|
|
|
prev_calibration = calibration;
|
|
calibration = 0;
|
|
|
|
isUSB = true;
|
|
|
|
//turn off the second local oscillator and the bfo
|
|
si5351_set_calibration(calibration);
|
|
startTx(TX_CW);
|
|
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();
|
|
|
|
printLine2("Calibration set!");
|
|
EEPROM.put(MASTER_CAL, calibration);
|
|
initOscillators();
|
|
setFrequency(frequency);
|
|
updateDisplay();
|
|
|
|
while(btnDown())
|
|
active_delay(50);
|
|
active_delay(100);
|
|
}
|
|
|
|
int menuSetupCalibration(int btn){
|
|
int knob = 0;
|
|
int32_t prev_calibration;
|
|
|
|
if (!btn){
|
|
printLine2("Setup:Calibrate\x7E");
|
|
return 0;
|
|
}
|
|
|
|
printLine1("Press PTT & tune");
|
|
printLine2("to exactly 10 MHz");
|
|
active_delay(2000);
|
|
calibrateClock();
|
|
}
|
|
|
|
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], 1);
|
|
printLine2(c);
|
|
}
|
|
|
|
void menuSetupCarrier(int btn){
|
|
int knob = 0;
|
|
unsigned long prevCarrier;
|
|
|
|
if (!btn){
|
|
printLine2("Setup:BFO \x7E");
|
|
return;
|
|
}
|
|
|
|
prevCarrier = usbCarrier;
|
|
printLine1("Tune to best Signal");
|
|
printLine2("Press to confirm. ");
|
|
active_delay(1000);
|
|
|
|
usbCarrier = 11995000l;
|
|
si5351bx_setfreq(0, usbCarrier);
|
|
printCarrierFreq(usbCarrier);
|
|
|
|
//disable all clock 1 and clock 2
|
|
while (!btnDown()){
|
|
knob = enc_read();
|
|
|
|
if (knob > 0)
|
|
usbCarrier -= 50;
|
|
else if (knob < 0)
|
|
usbCarrier += 50;
|
|
else
|
|
continue; //don't update the frequency or the display
|
|
|
|
si5351bx_setfreq(0, usbCarrier);
|
|
printCarrierFreq(usbCarrier);
|
|
|
|
active_delay(100);
|
|
}
|
|
|
|
printLine2("Carrier set! ");
|
|
EEPROM.put(USB_CAL, usbCarrier);
|
|
active_delay(1000);
|
|
|
|
si5351bx_setfreq(0, usbCarrier);
|
|
setFrequency(frequency);
|
|
updateDisplay();
|
|
printLine2("");
|
|
menuOn = 0;
|
|
}
|
|
|
|
void menuSetupCwTone(int btn){
|
|
int knob = 0;
|
|
int prev_sideTone;
|
|
|
|
if (!btn){
|
|
printLine2("Setup:CW Tone \x7E");
|
|
return;
|
|
}
|
|
|
|
prev_sideTone = sideTone;
|
|
printLine1("Tune CW tone");
|
|
printLine2("PTT to confirm. ");
|
|
active_delay(1000);
|
|
tone(CW_TONE, sideTone);
|
|
|
|
//disable all clock 1 and clock 2
|
|
while (digitalRead(PTT) == HIGH && !btnDown())
|
|
{
|
|
knob = enc_read();
|
|
|
|
if (knob > 0 && sideTone < 2000)
|
|
sideTone += 10;
|
|
else if (knob < 0 && sideTone > 100 )
|
|
sideTone -= 10;
|
|
else
|
|
continue; //don't update the frequency or the display
|
|
|
|
tone(CW_TONE, sideTone);
|
|
itoa(sideTone, b, 10);
|
|
printLine2(b);
|
|
|
|
checkCAT();
|
|
active_delay(20);
|
|
}
|
|
noTone(CW_TONE);
|
|
//save the setting
|
|
if (digitalRead(PTT) == LOW){
|
|
printLine2("Sidetone set! ");
|
|
EEPROM.put(CW_SIDETONE, sideTone);
|
|
active_delay(2000);
|
|
}
|
|
else
|
|
sideTone = prev_sideTone;
|
|
|
|
printLine2("");
|
|
updateDisplay();
|
|
menuOn = 0;
|
|
}
|
|
|
|
void menuSetupCwDelay(int btn){
|
|
int knob = 0;
|
|
int prev_cw_delay;
|
|
|
|
if (!btn){
|
|
printLine2("Setup:CW Delay \x7E");
|
|
return;
|
|
}
|
|
|
|
active_delay(500);
|
|
prev_cw_delay = cwDelayTime;
|
|
cwDelayTime = getValueByKnob(10, 1000, 50, cwDelayTime, "CW Delay>", " msec");
|
|
|
|
printLine1("CW Delay Set!");
|
|
printLine2("");
|
|
active_delay(500);
|
|
updateDisplay();
|
|
menuOn = 0;
|
|
}
|
|
|
|
void menuSetupKeyer(int btn){
|
|
int tmp_key, knob;
|
|
|
|
if (!btn){
|
|
if (!Iambic_Key)
|
|
printLine2("Setup:CW(Hand)\x7E");
|
|
else if (keyerControl & IAMBICB)
|
|
printLine2("Setup:CW(IambA)\x7E");
|
|
else
|
|
printLine2("Setup:CW(IambB)\x7E");
|
|
return;
|
|
}
|
|
|
|
active_delay(500);
|
|
|
|
if (!Iambic_Key)
|
|
tmp_key = 0; //hand key
|
|
else if (keyerControl & IAMBICB)
|
|
tmp_key = 2; //Iambic B
|
|
else
|
|
tmp_key = 1;
|
|
|
|
while (!btnDown())
|
|
{
|
|
knob = enc_read();
|
|
if (knob < 0 && tmp_key > 0)
|
|
tmp_key--;
|
|
if (knob > 0)
|
|
tmp_key++;
|
|
|
|
if (tmp_key > 2)
|
|
tmp_key = 0;
|
|
|
|
if (tmp_key == 0)
|
|
printLine1("Hand Key?");
|
|
else if (tmp_key == 1)
|
|
printLine1("Iambic A?");
|
|
else if (tmp_key == 2)
|
|
printLine1("Iambic B?");
|
|
}
|
|
|
|
active_delay(500);
|
|
if (tmp_key == 0)
|
|
Iambic_Key = false;
|
|
else if (tmp_key == 1){
|
|
Iambic_Key = true;
|
|
keyerControl &= ~IAMBICB;
|
|
}
|
|
else if (tmp_key == 2){
|
|
Iambic_Key = true;
|
|
keyerControl |= IAMBICB;
|
|
}
|
|
|
|
EEPROM.put(CW_KEY_TYPE, tmp_key);
|
|
|
|
printLine1("Keyer Set!");
|
|
active_delay(600);
|
|
printLine1("");
|
|
|
|
//Added KD8CEC
|
|
printLine2("");
|
|
updateDisplay();
|
|
menuOn = 0;
|
|
}
|
|
|
|
void menuReadADC(int btn){
|
|
int adc;
|
|
|
|
if (!btn){
|
|
printLine2("6:Setup>Read ADC>");
|
|
return;
|
|
}
|
|
delay(500);
|
|
|
|
while (!btnDown()){
|
|
adc = analogRead(ANALOG_KEYER);
|
|
itoa(adc, b, 10);
|
|
printLine1(b);
|
|
}
|
|
|
|
printLine1("");
|
|
updateDisplay();
|
|
}
|
|
|
|
void doMenu(){
|
|
int select=0, i,btnState;
|
|
|
|
//wait for the button to be raised up
|
|
while(btnDown())
|
|
active_delay(50);
|
|
active_delay(50); //debounce
|
|
|
|
menuOn = 2;
|
|
|
|
while (menuOn){
|
|
i = enc_read();
|
|
btnState = btnDown();
|
|
|
|
if (i > 0){
|
|
if (modeCalibrate && select + i < 150)
|
|
select += i;
|
|
if (!modeCalibrate && select + i < 80)
|
|
select += i;
|
|
}
|
|
if (i < 0 && select - i >= 0)
|
|
select += i; //caught ya, i is already -ve here, so you add it
|
|
|
|
if (select < 10)
|
|
menuBand(btnState);
|
|
else if (select < 20)
|
|
menuRitToggle(btnState);
|
|
else if (select < 30)
|
|
menuVfoToggle(btnState);
|
|
else if (select < 40)
|
|
menuSidebandToggle(btnState);
|
|
else if (select < 50)
|
|
menuSplitToggle(btnState);
|
|
else if (select < 60)
|
|
menuCWSpeed(btnState);
|
|
else if (select < 70)
|
|
select += menuSetup(btnState);
|
|
else if (select < 80 && !modeCalibrate)
|
|
menuExit(btnState);
|
|
else if (select < 90 && modeCalibrate)
|
|
menuSetupCalibration(btnState); //crystal
|
|
else if (select < 100 && modeCalibrate)
|
|
menuSetupCarrier(btnState); //lsb
|
|
else if (select < 110 && modeCalibrate)
|
|
menuSetupCwTone(btnState);
|
|
else if (select < 120 && modeCalibrate)
|
|
menuSetupCwDelay(btnState);
|
|
else if (select < 130 && modeCalibrate)
|
|
menuReadADC(btnState);
|
|
else if (select < 140 && modeCalibrate)
|
|
menuSetupKeyer(btnState);
|
|
else
|
|
menuExit(btnState);
|
|
}
|
|
|
|
//debounce the button
|
|
while(btnDown())
|
|
active_delay(50);
|
|
active_delay(50);
|
|
|
|
checkCAT();
|
|
}
|
|
|