mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-17 05:13:25 +00:00
tuning.cpp: import full PRALINE RX/TX tuning tables with quarter-shift offsets
This commit is contained in:
+332
-99
@@ -27,8 +27,8 @@ namespace tuning {
|
||||
namespace config {
|
||||
|
||||
// Forward declarations
|
||||
Config low_band(const rf::Frequency target_frequency);
|
||||
Config mid_band(const rf::Frequency target_frequency);
|
||||
Config low_band(const rf::Frequency target_frequency, const uint32_t afe_rate, const bool transmit);
|
||||
Config mid_band(const rf::Frequency target_frequency, const uint32_t afe_rate, const bool transmit);
|
||||
Config high_band(const rf::Frequency target_frequency);
|
||||
|
||||
#ifdef PRALINE
|
||||
@@ -36,133 +36,366 @@ Config high_band(const rf::Frequency target_frequency);
|
||||
* PRALINE Tuning Configuration
|
||||
* ============================
|
||||
*
|
||||
* Reference: hackrf_usb/common/tune_config.h praline_tune_config_rx[]
|
||||
* These tables are copied verbatim from the reference firmware,
|
||||
* hackrf/firmware/common/tune_config.h (praline_tune_config_rx /
|
||||
* praline_tune_config_tx), and the selection and offset maths below reproduce
|
||||
* hackrf/firmware/common/radio.c radio_update_frequency() /
|
||||
* analog_from_digital_rf() / compute_offset().
|
||||
*
|
||||
* The hackrf_usb firmware uses a table-driven approach where each entry
|
||||
* specifies:
|
||||
* - rf_range_end_mhz: Upper frequency limit for this config
|
||||
* - if_mhz: IF frequency (what MAX2831 tunes to)
|
||||
* - high_lo: true = high-side injection, false = low-side
|
||||
* - shift: FPGA quarter-shift mode (not implemented in Mayhem yet)
|
||||
* Each entry gives, for target frequencies up to rf_range_end_mhz:
|
||||
* if_mhz the IF the MAX2831 tunes to (0 = mixer bypassed, IF = RF)
|
||||
* high_lo true -> LO = IF + analogue RF (mixer inverts the spectrum)
|
||||
* false -> LO = IF - analogue RF (no inversion)
|
||||
* shift the FPGA quarter-rate shift mode used for this entry
|
||||
*
|
||||
* Key insight: The IF frequency varies to keep the RFFC5072 VCO in a
|
||||
* safe operating range (ideally 3500-5000 MHz, avoiding extremes).
|
||||
* The quarter-rate shift is the part Mayhem was previously missing. RX entries
|
||||
* deliberately place the analogue passband a quarter of the ADC rate away from
|
||||
* the requested frequency (+8 MHz at the usual 32 Msps AFE rate) so that the
|
||||
* wanted signal never sits on the DC offset / LO leakage, and then ask the FPGA
|
||||
* to rotate it back down to DC. Both halves have to be programmed together:
|
||||
* - tuning to target + offset without asking the FPGA to rotate leaves the
|
||||
* signal 8 MHz out and the decimation filter deletes it;
|
||||
* - tuning to target with no offset (what Mayhem did) parks the signal on DC,
|
||||
* under the LO leakage and the gateware's adaptive DC block.
|
||||
*
|
||||
* RFFC5072 VCO calculation:
|
||||
* High-side injection: LO = IF + RF, VCO = LO × lodiv
|
||||
* Low-side injection: LO = IF - RF, VCO = LO × lodiv
|
||||
* Where lodiv = 2 for frequencies where VCO > 2700 MHz
|
||||
*
|
||||
* From hackrf_usb tune_config_rx (simplified):
|
||||
* 0-2100 MHz: IF=2375, high_lo=true → VCO = (2375+RF)×2
|
||||
* 2105-2115: IF=2375, high_lo=false → VCO = (2375-RF)×2
|
||||
* 2115-2130: IF=2425, high_lo=false → VCO = (2425-RF)×2
|
||||
* ... (more entries for fine-grained control)
|
||||
* 2320-2580: IF=0 (bypass mode, no mixer)
|
||||
* 2580+: High-pass mode
|
||||
* "up" and "down" are named for the direction the FPGA rotates, so
|
||||
* FPGA_QUARTER_SHIFT_MODE_UP means the analogue centre is placed ABOVE the
|
||||
* requested frequency, and DOWN below it (radio.c analog_from_digital_rf()).
|
||||
*/
|
||||
|
||||
// Simplified tune_config lookup for Mayhem
|
||||
// Returns the IF frequency in Hz for a given target frequency
|
||||
constexpr rf::Frequency praline_get_if_frequency(const rf::Frequency target_frequency) {
|
||||
const uint32_t freq_mhz = target_frequency / 1'000'000;
|
||||
namespace {
|
||||
|
||||
// Based on hackrf_usb tune_config_rx table
|
||||
if (freq_mhz < 2100) {
|
||||
// Most low-band frequencies: use 2375 MHz IF
|
||||
// This keeps VCO around 4750-4950 MHz for FM band
|
||||
return 2375'000'000;
|
||||
} else if (freq_mhz < 2320) {
|
||||
// Transition zone: use varying IF to avoid VCO edges
|
||||
// These frequencies are tricky - near MAX2831 minimum
|
||||
// Use 2425 MHz to give some margin
|
||||
return 2425'000'000;
|
||||
} else {
|
||||
// Bypass mode or high-band - IF not used for mixer
|
||||
return 0;
|
||||
struct PralineTuneConfig {
|
||||
uint16_t rf_range_end_mhz;
|
||||
uint16_t if_mhz;
|
||||
bool high_lo;
|
||||
uint8_t shift; /* 0b00 none, 0b11 up, 0b01 down */
|
||||
};
|
||||
|
||||
/* The tables below are kept column-aligned to match the reference source, so
|
||||
* they are exempt from reformatting. */
|
||||
// clang-format off
|
||||
|
||||
/* tuning table optimized for RX */
|
||||
constexpr PralineTuneConfig praline_tune_config_rx[] = {
|
||||
{ 0, 2360, true, 0b00},
|
||||
{ 50, 2320, true, 0b11},
|
||||
{ 100, 2320, true, 0b01},
|
||||
{ 140, 2320, true, 0b11},
|
||||
{ 406, 2560, true, 0b11},
|
||||
{ 511, 2380, true, 0b11},
|
||||
{ 578, 2560, true, 0b01},
|
||||
{ 741, 2340, true, 0b11},
|
||||
{ 861, 2560, true, 0b01},
|
||||
{ 921, 2560, true, 0b11},
|
||||
{ 1049, 2340, true, 0b01},
|
||||
{ 1169, 2380, true, 0b11},
|
||||
{ 1360, 2340, true, 0b11},
|
||||
{ 1544, 2560, true, 0b01},
|
||||
{ 1675, 2560, true, 0b11},
|
||||
{ 1992, 2380, true, 0b01},
|
||||
{ 2070, 2340, true, 0b01},
|
||||
{ 2150, 2360, true, 0b01},
|
||||
{ 2168, 2560, false, 0b11},
|
||||
{ 2185, 2580, false, 0b11},
|
||||
{ 2202, 2580, false, 0b01},
|
||||
{ 2205, 2520, false, 0b11},
|
||||
{ 2216, 2560, false, 0b11},
|
||||
{ 2223, 2540, false, 0b11},
|
||||
{ 2234, 2580, false, 0b11},
|
||||
{ 2240, 2560, false, 0b11},
|
||||
{ 2251, 2580, false, 0b01},
|
||||
{ 2258, 2580, false, 0b11},
|
||||
{ 2265, 2540, false, 0b01},
|
||||
{ 2271, 2580, false, 0b11},
|
||||
{ 2273, 2560, false, 0b11},
|
||||
{ 2275, 2580, false, 0b01},
|
||||
{ 2280, 2500, false, 0b01},
|
||||
{ 2284, 2540, false, 0b11},
|
||||
{ 2289, 2580, false, 0b01},
|
||||
{ 2293, 2540, false, 0b01},
|
||||
{ 2298, 2520, false, 0b01},
|
||||
{ 2300, 2580, false, 0b11},
|
||||
{ 2302, 2540, false, 0b01},
|
||||
{ 2309, 2560, false, 0b01},
|
||||
{ 2311, 2580, false, 0b01},
|
||||
{ 2314, 2540, false, 0b11},
|
||||
{ 2315, 2540, false, 0b01},
|
||||
{ 2320, 2580, false, 0b11},
|
||||
{ 2380, 0, false, 0b11},
|
||||
{ 2440, 0, false, 0b01},
|
||||
{ 2500, 0, false, 0b11},
|
||||
{ 2580, 0, false, 0b01},
|
||||
{ 2583, 2360, false, 0b11},
|
||||
{ 2584, 2380, false, 0b11},
|
||||
{ 2587, 2340, false, 0b11},
|
||||
{ 2593, 2340, false, 0b01},
|
||||
{ 2607, 2340, false, 0b11},
|
||||
{ 2609, 2360, false, 0b11},
|
||||
{ 2615, 2360, false, 0b01},
|
||||
{ 2627, 2340, false, 0b01},
|
||||
{ 2629, 2360, false, 0b01},
|
||||
{ 2631, 2380, false, 0b11},
|
||||
{ 2644, 2340, false, 0b11},
|
||||
{ 2649, 2380, false, 0b11},
|
||||
{ 2651, 2380, false, 0b01},
|
||||
{ 2654, 2500, false, 0b11},
|
||||
{ 2665, 2360, false, 0b11},
|
||||
{ 2669, 2380, false, 0b01},
|
||||
{ 2672, 2360, false, 0b01},
|
||||
{ 2682, 2340, false, 0b11},
|
||||
{ 2687, 2380, false, 0b11},
|
||||
{ 2692, 2340, false, 0b11},
|
||||
{ 2695, 2500, false, 0b11},
|
||||
{ 2705, 2360, false, 0b11},
|
||||
{ 2707, 2380, false, 0b01},
|
||||
{ 2712, 2340, false, 0b01},
|
||||
{ 2717, 2520, false, 0b11},
|
||||
{ 2728, 2380, false, 0b11},
|
||||
{ 2730, 2560, false, 0b11},
|
||||
{ 2734, 2500, false, 0b11},
|
||||
{ 2758, 2340, false, 0b11},
|
||||
{ 2780, 2360, false, 0b11},
|
||||
{ 2787, 2520, false, 0b11},
|
||||
{ 2802, 2380, false, 0b11},
|
||||
{ 2809, 2540, false, 0b11},
|
||||
{ 2822, 2380, false, 0b01},
|
||||
{ 2831, 2560, false, 0b11},
|
||||
{ 2854, 2340, false, 0b11},
|
||||
{ 2875, 2360, false, 0b11},
|
||||
{ 2898, 2380, false, 0b11},
|
||||
{ 2918, 2380, false, 0b01},
|
||||
{ 2936, 2520, false, 0b01},
|
||||
{ 2944, 2380, false, 0b01},
|
||||
{ 2959, 2560, false, 0b11},
|
||||
{ 2976, 2340, false, 0b11},
|
||||
{ 2985, 2500, false, 0b01},
|
||||
{ 3003, 2340, false, 0b11},
|
||||
{ 3009, 2540, false, 0b11},
|
||||
{ 3027, 2380, false, 0b11},
|
||||
{ 3034, 2560, false, 0b11},
|
||||
{ 3050, 2380, false, 0b01},
|
||||
{ 3069, 2500, false, 0b11},
|
||||
{ 3094, 2520, false, 0b11},
|
||||
{ 3119, 2540, false, 0b11},
|
||||
{ 3144, 2560, false, 0b11},
|
||||
{ 3169, 2560, false, 0b01},
|
||||
{ 3180, 2500, false, 0b11},
|
||||
{ 3204, 2340, false, 0b11},
|
||||
{ 3232, 2360, false, 0b11},
|
||||
{ 3292, 2340, false, 0b01},
|
||||
{ 3340, 2380, false, 0b01},
|
||||
{ 3369, 2340, false, 0b11},
|
||||
{ 3399, 2360, false, 0b11},
|
||||
{ 3429, 2380, false, 0b11},
|
||||
{ 3464, 2500, false, 0b11},
|
||||
{ 3489, 2520, false, 0b11},
|
||||
{ 3512, 2540, false, 0b11},
|
||||
{ 3551, 2500, false, 0b01},
|
||||
{ 3582, 2540, false, 0b11},
|
||||
{ 3611, 2560, false, 0b11},
|
||||
{ 3639, 2520, false, 0b11},
|
||||
{ 3729, 2340, false, 0b11},
|
||||
{ 3817, 2380, false, 0b01},
|
||||
{ 3942, 2360, false, 0b01},
|
||||
{ 4049, 2540, false, 0b11},
|
||||
{ 4134, 2500, false, 0b01},
|
||||
{ 4194, 2560, false, 0b11},
|
||||
{ 4353, 2520, false, 0b11},
|
||||
{ 4449, 2360, false, 0b01},
|
||||
{ 4562, 2500, false, 0b11},
|
||||
{ 4672, 2560, false, 0b11},
|
||||
{ 4769, 2540, false, 0b11},
|
||||
{ 4849, 2560, false, 0b01},
|
||||
{ 4889, 2560, false, 0b11},
|
||||
{ 4929, 2560, false, 0b11},
|
||||
{ 4969, 2560, false, 0b11},
|
||||
{ 5009, 2560, false, 0b11},
|
||||
{ 5049, 2560, false, 0b11},
|
||||
{ 5092, 2360, false, 0b11},
|
||||
{ 5209, 2340, false, 0b01},
|
||||
{ 5298, 2380, false, 0b01},
|
||||
{ 5468, 2340, false, 0b01},
|
||||
{ 5582, 2520, false, 0b11},
|
||||
{ 5702, 2340, false, 0b11},
|
||||
{ 5888, 2520, false, 0b01},
|
||||
{ 6092, 2340, false, 0b01},
|
||||
{ 6240, 2560, false, 0b11},
|
||||
{ 6609, 2340, false, 0b11},
|
||||
{ 6752, 2380, false, 0b01},
|
||||
{ 6930, 2520, false, 0b01},
|
||||
{ 7000, 2560, false, 0b11},
|
||||
{ 7070, 2560, false, 0b01},
|
||||
{ 7251, 2580, false, 0b01},
|
||||
{ 0, 0, false, 0b00},
|
||||
};
|
||||
|
||||
/* tuning table optimized for TX */
|
||||
constexpr PralineTuneConfig praline_tune_config_tx[] = {
|
||||
{ 2100, 2375, true, 0b00},
|
||||
{ 2105, 2375, false, 0b00},
|
||||
{ 2115, 2425, false, 0b00},
|
||||
{ 2130, 2375, false, 0b00},
|
||||
{ 2150, 2425, false, 0b00},
|
||||
{ 2160, 2475, false, 0b00},
|
||||
{ 2175, 2425, false, 0b00},
|
||||
{ 2190, 2475, false, 0b00},
|
||||
{ 2195, 2425, false, 0b00},
|
||||
{ 2210, 2375, false, 0b00},
|
||||
{ 2248, 2425, false, 0b00},
|
||||
{ 2265, 2525, false, 0b00},
|
||||
{ 2300, 2425, false, 0b00},
|
||||
{ 2320, 2525, false, 0b00},
|
||||
{ 2580, 0, false, 0b00},
|
||||
{ 3000, 2325, false, 0b00},
|
||||
{ 3140, 2375, false, 0b00},
|
||||
{ 3200, 2425, false, 0b00},
|
||||
{ 3280, 2375, false, 0b00},
|
||||
{ 3340, 2425, false, 0b00},
|
||||
{ 3420, 2475, false, 0b00},
|
||||
{ 3480, 2525, false, 0b00},
|
||||
{ 3500, 2475, false, 0b00},
|
||||
{ 3595, 2425, false, 0b00},
|
||||
{ 3625, 2375, false, 0b00},
|
||||
{ 3670, 2475, false, 0b00},
|
||||
{ 3710, 2425, false, 0b00},
|
||||
{ 3760, 2525, false, 0b00},
|
||||
{ 3790, 2475, false, 0b00},
|
||||
{ 3860, 2425, false, 0b00},
|
||||
{ 3915, 2375, false, 0b00},
|
||||
{ 4000, 2425, false, 0b00},
|
||||
{ 4055, 2375, false, 0b00},
|
||||
{ 4125, 2425, false, 0b00},
|
||||
{ 4700, 2375, false, 0b00},
|
||||
{ 4800, 2425, false, 0b00},
|
||||
{ 5000, 2375, false, 0b00},
|
||||
{ 5260, 2475, false, 0b00},
|
||||
{ 5465, 2525, false, 0b00},
|
||||
{ 5560, 2375, false, 0b00},
|
||||
{ 5720, 2425, false, 0b00},
|
||||
{ 5860, 2475, false, 0b00},
|
||||
{ 5970, 2575, false, 0b00},
|
||||
{ 6000, 2375, false, 0b00},
|
||||
{ 6500, 2325, false, 0b00},
|
||||
{ 6750, 2375, false, 0b00},
|
||||
{ 6850, 2425, false, 0b00},
|
||||
{ 6950, 2475, false, 0b00},
|
||||
{ 7000, 2525, false, 0b00},
|
||||
{ 7251, 2575, false, 0b00},
|
||||
{ 0, 0, false, 0b00},
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
/* radio.c select_tune_config(): first entry whose range end is above the
|
||||
* requested frequency. The list is terminated by an all-zero entry, which is
|
||||
* also what a frequency past the end of the table lands on. */
|
||||
const PralineTuneConfig* select_tune_config(const rf::Frequency target_frequency, const bool transmit) {
|
||||
const PralineTuneConfig* entry = transmit ? praline_tune_config_tx : praline_tune_config_rx;
|
||||
const uint32_t freq_mhz = static_cast<uint32_t>(target_frequency / 1'000'000);
|
||||
|
||||
while ((entry->rf_range_end_mhz != 0) || (entry->if_mhz != 0)) {
|
||||
if ((target_frequency == 0) || (entry->rf_range_end_mhz > freq_mhz))
|
||||
break;
|
||||
entry++;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Returns true for high-side injection, false for low-side
|
||||
constexpr bool praline_use_high_side_injection(const rf::Frequency target_frequency) {
|
||||
const uint32_t freq_mhz = target_frequency / 1'000'000;
|
||||
|
||||
// Based on hackrf_usb tune_config_rx table
|
||||
if (freq_mhz < 2100) {
|
||||
// Standard low-band: high-side injection
|
||||
// LO = IF + RF, mixer inverts spectrum
|
||||
return true;
|
||||
} else if (freq_mhz < 2105) {
|
||||
// Narrow transition: still high-side
|
||||
return true;
|
||||
} else if (freq_mhz < 2320) {
|
||||
// Near MAX2831 minimum: use low-side injection
|
||||
// LO = IF - RF, no spectrum inversion
|
||||
return false;
|
||||
} else {
|
||||
// Bypass/high-band - doesn't matter, mixer bypassed
|
||||
return false;
|
||||
}
|
||||
/* radio.c compute_offset(): a quarter of the AFE (ADC) sample rate, or zero if
|
||||
* no shift is in use or the AFE rate isn't known yet. */
|
||||
constexpr uint32_t quarter_shift_offset(const uint8_t shift, const uint32_t afe_rate) {
|
||||
return (shift == 0) ? 0 : (afe_rate / 4);
|
||||
}
|
||||
|
||||
/* radio.c analog_from_digital_rf(). */
|
||||
rf::Frequency analog_from_digital_rf(const rf::Frequency target_frequency, const uint8_t shift, const uint32_t afe_rate) {
|
||||
const rf::Frequency offset = quarter_shift_offset(shift, afe_rate);
|
||||
|
||||
if (shift == 0b11)
|
||||
return target_frequency + offset;
|
||||
|
||||
if (shift == 0b01)
|
||||
return (offset > target_frequency) ? (offset - target_frequency)
|
||||
: (target_frequency - offset);
|
||||
|
||||
return target_frequency;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif // PRALINE
|
||||
|
||||
// Low band <2170 Mhz (HackRF One) or <2320 MHz (PRALINE):
|
||||
constexpr rf::Frequency low_band_second_lo_frequency(const rf::Frequency target_frequency) {
|
||||
Config low_band(const rf::Frequency target_frequency, const uint32_t afe_rate, const bool transmit) {
|
||||
#ifdef PRALINE
|
||||
// Use the tune_config lookup for PRALINE
|
||||
return praline_get_if_frequency(target_frequency);
|
||||
#else
|
||||
return 2650'000'000 - (target_frequency / 7);
|
||||
#endif
|
||||
}
|
||||
const PralineTuneConfig* entry = select_tune_config(target_frequency, transmit);
|
||||
|
||||
Config low_band(const rf::Frequency target_frequency) {
|
||||
const rf::Frequency second_lo_frequency = low_band_second_lo_frequency(target_frequency);
|
||||
/* Past the end of the table: no usable configuration. */
|
||||
if ((entry->rf_range_end_mhz == 0) && (entry->if_mhz == 0))
|
||||
return {};
|
||||
|
||||
#ifdef PRALINE
|
||||
/* afe_rate == 0 means the caller doesn't know the ADC rate, so no LO offset
|
||||
* is applied. The FPGA rotation has to be dropped with it: rotating without
|
||||
* the matching offset moves the wanted signal off DC by afe_rate / 4. */
|
||||
const uint8_t shift = (afe_rate == 0) ? 0 : entry->shift;
|
||||
const rf::Frequency analog_rf = analog_from_digital_rf(target_frequency, shift, afe_rate);
|
||||
|
||||
/* if_mhz == 0 means the mixer is bypassed and the transceiver tunes the RF
|
||||
* directly; there is no first LO in that case. */
|
||||
const rf::Frequency second_lo_frequency =
|
||||
(entry->if_mhz == 0) ? analog_rf : (static_cast<rf::Frequency>(entry->if_mhz) * 1'000'000);
|
||||
|
||||
if (entry->if_mhz == 0)
|
||||
return {0, second_lo_frequency, rf::path::Band::Low, false, shift};
|
||||
|
||||
/* The low band always runs through the low-pass image-reject filter, so
|
||||
* the spectrum is inverted exactly when the first LO ends up above the IF,
|
||||
* i.e. for high-side injection. This is hackrf_usb.c radio_changed():
|
||||
* invert = (img_reject == RF_PATH_FILTER_LOW_PASS) && (freq_lo > freq_if)
|
||||
*/
|
||||
rf::Frequency first_lo_frequency;
|
||||
bool mixer_invert;
|
||||
|
||||
if (praline_use_high_side_injection(target_frequency)) {
|
||||
// High-side injection: LO = IF + RF
|
||||
first_lo_frequency = second_lo_frequency + target_frequency;
|
||||
if (entry->high_lo) {
|
||||
first_lo_frequency = second_lo_frequency + analog_rf;
|
||||
mixer_invert = true;
|
||||
} else {
|
||||
// Low-side injection: LO = IF - RF
|
||||
first_lo_frequency = second_lo_frequency - target_frequency;
|
||||
first_lo_frequency = second_lo_frequency - analog_rf;
|
||||
mixer_invert = false;
|
||||
}
|
||||
|
||||
return {first_lo_frequency, second_lo_frequency, rf::path::Band::Low, mixer_invert};
|
||||
return {first_lo_frequency, second_lo_frequency, rf::path::Band::Low, mixer_invert, shift};
|
||||
#else
|
||||
(void)afe_rate;
|
||||
(void)transmit;
|
||||
const rf::Frequency second_lo_frequency = 2650'000'000 - (target_frequency / 7);
|
||||
const rf::Frequency first_lo_frequency = target_frequency + second_lo_frequency;
|
||||
const bool mixer_invert = true;
|
||||
return {first_lo_frequency, second_lo_frequency, rf::path::Band::Low, mixer_invert};
|
||||
#endif
|
||||
}
|
||||
|
||||
// Mid band 2170-2740 Mhz (HackRF One) or 2320-2580 MHz (PRALINE):
|
||||
Config mid_band(const rf::Frequency target_frequency) {
|
||||
// Mid band 2170-2740 Mhz (HackRF One) or 2320-2740 MHz (PRALINE):
|
||||
Config mid_band(const rf::Frequency target_frequency, const uint32_t afe_rate, const bool transmit) {
|
||||
#ifdef PRALINE
|
||||
// For Praline with MAX2831 (2.3-2.6 GHz range)
|
||||
// Frequencies 2170-2300 MHz need upconversion since they're below MAX2831 minimum
|
||||
if (target_frequency < 2300'000'000) {
|
||||
// Treat as low band - need mixer
|
||||
return low_band(target_frequency);
|
||||
}
|
||||
// Frequencies 2300-2600 MHz can go direct (no RFFC5072)
|
||||
else if (target_frequency <= 2600'000'000) {
|
||||
const rf::Frequency second_lo_frequency = target_frequency;
|
||||
const rf::Frequency first_lo_frequency = 0;
|
||||
const bool mixer_invert = false;
|
||||
return {first_lo_frequency, second_lo_frequency, rf::path::Band::Mid, mixer_invert};
|
||||
}
|
||||
// Frequencies 2600-2740 MHz need downconversion since they're above MAX2831 maximum
|
||||
else {
|
||||
// Treat as high band
|
||||
return high_band(target_frequency);
|
||||
/* radio.c select_img_reject() / tuning.c: on PRALINE the MAX2831 tunes
|
||||
* direct (mixer bypassed) from 2320 to 2580 MHz. band_mid starts at
|
||||
* TRANSITION = 2320 MHz, so everything below that already went to
|
||||
* low_band(). */
|
||||
if (target_frequency <= 2580'000'000) {
|
||||
const PralineTuneConfig* entry = select_tune_config(target_frequency, transmit);
|
||||
const uint8_t shift = (afe_rate == 0) ? 0 : entry->shift;
|
||||
const rf::Frequency analog_rf = analog_from_digital_rf(target_frequency, shift, afe_rate);
|
||||
|
||||
/* Mixer bypassed: no first LO, the MAX2831 tunes the (offset)
|
||||
* analogue RF directly and the FPGA rotates it back. */
|
||||
return {0, analog_rf, rf::path::Band::Mid, false, shift};
|
||||
}
|
||||
|
||||
/* 2580-2740 MHz: above the bypass window, downconvert. */
|
||||
return high_band(target_frequency);
|
||||
#else
|
||||
(void)afe_rate;
|
||||
(void)transmit;
|
||||
const rf::Frequency second_lo_frequency = target_frequency;
|
||||
const rf::Frequency first_lo_frequency = 0;
|
||||
const bool mixer_invert = false;
|
||||
@@ -203,12 +436,12 @@ Config high_band(const rf::Frequency target_frequency) {
|
||||
return {first_lo_frequency, second_lo_frequency, rf::path::Band::High, mixer_invert};
|
||||
}
|
||||
|
||||
Config create(const rf::Frequency target_frequency) {
|
||||
Config create(const rf::Frequency target_frequency, const uint32_t afe_rate, const bool transmit) {
|
||||
/* TODO: This is some lame code. */
|
||||
if (rf::path::band_low.contains(target_frequency)) {
|
||||
return low_band(target_frequency);
|
||||
return low_band(target_frequency, afe_rate, transmit);
|
||||
} else if (rf::path::band_mid.contains(target_frequency)) {
|
||||
return mid_band(target_frequency);
|
||||
return mid_band(target_frequency, afe_rate, transmit);
|
||||
} else if (rf::path::band_high.contains(target_frequency)) {
|
||||
return high_band(target_frequency);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user