forked from afarhan/ubitxv6
-
Notifications
You must be signed in to change notification settings - Fork 11
/
tuner.cpp
217 lines (189 loc) · 6.49 KB
/
tuner.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#include "tuner.h"
#include <Arduino.h>
#include "nano_gui.h"
#include "pin_definitions.h"
#include "si5351.h"
static const uint32_t THRESHOLD_USB_LSB = 10000000L;
void saveVFOs()
{
SaveSettingsToEeprom();
}
void switchVFO(Vfo_e new_vfo){
ritDisable();//If we are in RIT mode, we need to disable it before setting the active VFO so that the correct VFO gets it's frequency restored
globalSettings.activeVfo = new_vfo;
setFrequency(GetActiveVfoFreq());
saveVFOs();
}
/**
* Select the properly tx harmonic filters
* The four harmonic filters use only three relays
* the four LPFs cover 30-21 Mhz, 18 - 14 Mhz, 7-10 MHz and 3.5 to 5 Mhz
* Briefly, it works like this,
* - When KT1 is OFF, the 'off' position routes the PA output through the 30 MHz LPF
* - When KT1 is ON, it routes the PA output to KT2. Which is why you will see that
* the KT1 is on for the three other cases.
* - When the KT1 is ON and KT2 is off, the off position of KT2 routes the PA output
* to 18 MHz LPF (That also works for 14 Mhz)
* - When KT1 is On, KT2 is On, it routes the PA output to KT3
* - KT3, when switched on selects the 7-10 Mhz filter
* - KT3 when switched off selects the 3.5-5 Mhz filter
* See the circuit to understand this
*/
void setTXFilters(unsigned long freq){
if (freq > 21000000L){ // the default filter is with 35 MHz cut-off
digitalWrite(PIN_TX_LPF_A, 0);
digitalWrite(PIN_TX_LPF_B, 0);
digitalWrite(PIN_TX_LPF_C, 0);
}
else if (freq >= 14000000L){ //thrown the KT1 relay on, the 30 MHz LPF is bypassed and the 14-18 MHz LPF is allowd to go through
digitalWrite(PIN_TX_LPF_A, 1);
digitalWrite(PIN_TX_LPF_B, 0);
digitalWrite(PIN_TX_LPF_C, 0);
}
else if (freq > 7000000L){
digitalWrite(PIN_TX_LPF_A, 0);
digitalWrite(PIN_TX_LPF_B, 1);
digitalWrite(PIN_TX_LPF_C, 0);
}
else {
digitalWrite(PIN_TX_LPF_A, 0);
digitalWrite(PIN_TX_LPF_B, 0);
digitalWrite(PIN_TX_LPF_C, 1);
}
}
/**
* This is the most frequently called function that configures the
* radio to a particular frequeny, sideband and sets up the transmit filters
*
* The transmit filter relays are powered up only during the tx so they dont
* draw any current during rx.
*
* The carrier oscillator of the detector/modulator is permanently fixed at
* uppper sideband. The sideband selection is done by placing the second oscillator
* either 12 Mhz below or above the 45 Mhz signal thereby inverting the sidebands
* through mixing of the second local oscillator.
*/
void setFrequency(const unsigned long freq,
const bool transmit){
static const unsigned long FIRST_IF = 45005000UL;
setTXFilters(freq);
//Nominal values for the oscillators
uint32_t local_osc_freq = FIRST_IF + freq;
uint32_t ssb_osc_freq = FIRST_IF;//will be changed depending on sideband
uint32_t bfo_osc_freq = globalSettings.usbCarrierFreq;
if(TuningMode_e::TUNE_CW == globalSettings.tuningMode){
if(transmit){
//We don't do any mixing or converting when transmitting
local_osc_freq = freq;
ssb_osc_freq = 0;
bfo_osc_freq = 0;
}
else{
//We offset when receiving CW so that it's audible
if(VfoMode_e::VFO_MODE_USB == GetActiveVfoMode()){
local_osc_freq -= globalSettings.cwSideToneFreq;
ssb_osc_freq += globalSettings.usbCarrierFreq;
}
else{
local_osc_freq += globalSettings.cwSideToneFreq;
ssb_osc_freq -= globalSettings.usbCarrierFreq;
}
}
}
else{//SSB mode
if(VfoMode_e::VFO_MODE_USB == GetActiveVfoMode()){
ssb_osc_freq += globalSettings.usbCarrierFreq;
}
else{
ssb_osc_freq -= globalSettings.usbCarrierFreq;
}
}
si5351bx_setfreq(2, local_osc_freq);
si5351bx_setfreq(1, ssb_osc_freq);
si5351bx_setfreq(0, bfo_osc_freq);
SetActiveVfoFreq(freq);
}
/**
* startTx is called by the PTT, cw keyer and CAT protocol to
* put the uBitx in tx mode. It takes care of rit settings, sideband settings
* Note: In cw mode, doesnt key the radio, only puts it in tx mode
* CW offest is calculated as lower than the operating frequency when in LSB mode, and vice versa in USB mode
*/
void startTx(TuningMode_e tx_mode){
globalSettings.tuningMode = tx_mode;
if (globalSettings.ritOn){
//save the current as the rx frequency
uint32_t rit_tx_freq = globalSettings.ritFrequency;
globalSettings.ritFrequency = GetActiveVfoFreq();
setFrequency(rit_tx_freq,true);
}
else{
if(globalSettings.splitOn){
if(Vfo_e::VFO_B == globalSettings.activeVfo){
globalSettings.activeVfo = Vfo_e::VFO_A;
}
else{
globalSettings.activeVfo = Vfo_e::VFO_B;
}
}
setFrequency(GetActiveVfoFreq(),true);
}
digitalWrite(PIN_TX_RXn, 1);//turn on the tx
globalSettings.txActive = true;
drawTx();
}
void stopTx(){
digitalWrite(PIN_TX_RXn, 0);//turn off the tx
globalSettings.txActive = false;
if(globalSettings.ritOn){
uint32_t rit_rx_freq = globalSettings.ritFrequency;
globalSettings.ritFrequency = GetActiveVfoFreq();
setFrequency(rit_rx_freq);
}
else{
if(globalSettings.splitOn){
if(Vfo_e::VFO_B == globalSettings.activeVfo){
globalSettings.activeVfo = Vfo_e::VFO_A;
}
else{
globalSettings.activeVfo = Vfo_e::VFO_B;
}
}
setFrequency(GetActiveVfoFreq());
}
drawTx();
}
/**
* ritEnable is called with a frequency parameter that determines
* what the tx frequency will be
*/
void ritEnable(unsigned long freq){
globalSettings.ritOn = true;
//save the non-rit frequency back into the VFO memory
//as RIT is a temporary shift, this is not saved to EEPROM
globalSettings.ritFrequency = freq;
}
// this is called by the RIT menu routine
void ritDisable(){
if(globalSettings.ritOn){
globalSettings.ritOn = false;
setFrequency(globalSettings.ritFrequency);
}
}
bool autoSelectSidebandChanged(const uint32_t old_frequency)
{
const uint32_t new_freq = GetActiveVfoFreq();
//Transition from below to above the traditional threshold for USB
if(old_frequency < THRESHOLD_USB_LSB && new_freq >= THRESHOLD_USB_LSB){
SetActiveVfoMode(VfoMode_e::VFO_MODE_USB);
setFrequency(new_freq);//Refresh tuning to activate the new sideband mode
return true;
}
//Transition from above to below the traditional threshold for USB
if(old_frequency >= THRESHOLD_USB_LSB && new_freq < THRESHOLD_USB_LSB){
SetActiveVfoMode(VfoMode_e::VFO_MODE_LSB);
setFrequency(new_freq);//Refresh tuning to activate the new sideband mode
return true;
}
return false;
}