diff --git a/src/algorithms/signal_source/libs/ad9361_manager.cc b/src/algorithms/signal_source/libs/ad9361_manager.cc index 4a7611ef8..a57aadf27 100644 --- a/src/algorithms/signal_source/libs/ad9361_manager.cc +++ b/src/algorithms/signal_source/libs/ad9361_manager.cc @@ -38,6 +38,30 @@ #include #include +#define MIN_ADC_CLK 25000000UL // 25 MHz +#define MAX_ADC_CLK 640000000UL // 640 MHz +#define MIN_DATA_RATE MIN_ADC_CLK / 48 +#define MAX_DATA_RATE 61440000UL // Output of FIR (RX) +#define MAX_DAC_CLK (MAX_ADC_CLK / 2) +#define MIN_DAC_CLK 25000000UL // 25 MHz +#define MAX_RX_HB1 122880000UL +#define MAX_RX_HB2 245760000UL +#define MAX_RX_HB3 320000000UL +#define MAX_TX_HB1 122880000UL +#define MAX_TX_HB2 245760000UL +#define MAX_TX_HB3 320000000UL +#define MAX_FIR MAX_DATA_RATE * 2 +#define MAX_BBPLL_DIV 64 +#define MIN_BBPLL_FREQ 714928500UL // 715 MHz - 100ppm +#define MAX_BBPLL_FREQ 1430143000UL // 1430 MHz + 100ppm +#define check(val, min, max) ((val) <= (max) ? (val) >= (min) : false) + +const uint64_t TX_MAX_PATH_RATES[] = {MAX_DAC_CLK, MAX_TX_HB3, MAX_TX_HB2, MAX_TX_HB1, MAX_FIR}; +const uint64_t TX_MIN_PATH_RATES[] = {MIN_DAC_CLK, 0, 0, 0, 0}; +const uint64_t RX_MAX_PATH_RATES[] = {MAX_ADC_CLK, MAX_RX_HB3, MAX_RX_HB2, MAX_RX_HB1, MAX_FIR}; +const uint64_t RX_MIN_PATH_RATES[] = {MIN_ADC_CLK, 0, 0, 0, 0}; + +uint64_t max_rate_found; /* check return value of attr_write function */ void errchk(int v, const char *what) @@ -71,6 +95,508 @@ struct iio_device *get_ad9361_phy(struct iio_context *ctx) } +void set_max_taps(struct filter_design_parameters *fdpTX, + struct filter_design_parameters *fdpRX) +{ + // RX side + int N, M, K; + if (fdpRX->HB3 == 3) + N = 16 * floor(fdpRX->converter_rate / (fdpRX->Rdata)); + else + N = 16 * floor(fdpRX->converter_rate / (2 * fdpRX->Rdata)); + if (N > 128) + N = 128; + // TX side + if (fdpTX->FIR == 1) + M = 64; + else + M = 128; + K = 16 * floor(fdpTX->converter_rate * fdpTX->DAC_div / (2 * fdpTX->Rdata)); + if (K < M) + M = K; + + // Pick the smallest + if (M > N) + { + fdpTX->maxTaps = N; + fdpRX->maxTaps = N; + } + else + { + fdpTX->maxTaps = M; + fdpRX->maxTaps = M; + } +} + + +double calculate_rfbw(double pll_rate, double caldiv, bool TX, + double *rcaldiv) +{ + double rfbw, min_rfbw, max_rfbw, scale; + if (TX) + { + scale = 1.6; + min_rfbw = 1250000; + max_rfbw = 40000000; + } + else + { + scale = 1.4; + min_rfbw = 400000; + max_rfbw = 56000000; + } + rfbw = + (double)round((pll_rate / caldiv) * (2 / (scale * (2 * M_PI) / log(2)))); + + // If the RF bandwidth is outside the range of acceptable values we modify + // the divider value until it falls into an acceptable range. + while ((rfbw < min_rfbw) || (rfbw > max_rfbw)) + { + if (rfbw < min_rfbw) + caldiv = caldiv - 1; + else + caldiv = caldiv + 1; + + if ((caldiv < 1) || (caldiv > 511)) + { + fprintf(stderr, "Calibration divider out of bounds (1 - 511): %f\n", caldiv); + return -EINVAL; + } + rfbw = calculate_rfbw(pll_rate, caldiv, TX, rcaldiv); + } + *rcaldiv = caldiv; + return rfbw; +} + +void set_rates(uint64_t *rx_path_clks, + uint64_t *tx_path_clks, int DAC_div, uint64_t *rates, + int dec_table_index) +{ + int k; + + // Check if ADC will run faster in config + if (rates[1] > max_rate_found) + max_rate_found = rates[1]; + else + return; + + for (k = 0; k < 6; k++) + { + rx_path_clks[k] = rates[k]; + tx_path_clks[k] = rates[k]; + + if (k > 0) + { // Adjust HB's for DAC divider setting + if ((dec_table_index < 2) && (k < 4)) + tx_path_clks[k] = rates[k] / DAC_div; + else if ((dec_table_index < 4) && (k < 3)) + tx_path_clks[k] = rates[k] / DAC_div; + } + } +} + + +int check_dac_adc_config(uint64_t pll_bb, int PLL_mult, + int dec_table_index) +{ + // Need to determine if DAC divider is required and if ADC and DAC rates + // can be satisfied + uint64_t with_dd, without_dd; + bool a, b, c; + + with_dd = pll_bb / PLL_mult / 2; + without_dd = pll_bb / PLL_mult / 1; + + a = check(with_dd, MIN_DAC_CLK, MAX_DAC_CLK); + b = check(without_dd, MIN_ADC_CLK, MAX_ADC_CLK); + c = check(without_dd, MIN_DAC_CLK, MAX_DAC_CLK); + + if (c && b) + return 1; // Run without dac div + else if (a && b && (dec_table_index < 5)) + return 2; // Run with dac div + else + return -1; +} + + +bool check_rates(int FIR __attribute__((unused)), const int *HB_configs, uint64_t samp_rate, + uint64_t *rates) +{ + int j; + bool c = true; + + rates[5] = samp_rate; + for (j = 4; j > 0; j--) + { + rates[j] = rates[j + 1] * HB_configs[j - 1]; + if (j > 1) + { + c &= check(rates[j], TX_MIN_PATH_RATES[j - 1], TX_MAX_PATH_RATES[j - 1]); + c &= check(rates[j], RX_MIN_PATH_RATES[j - 1], RX_MAX_PATH_RATES[j - 1]); + } + } + return c; +} + + +int determine_pll_div(uint64_t *rates) +{ + // Determine necessary PLL multiplier + uint64_t tmp; + int PLL_mult = MAX_BBPLL_DIV; + while (PLL_mult > 1) + { + tmp = (uint64_t)rates[1] * PLL_mult; + if (check(tmp, MIN_BBPLL_FREQ, MAX_BBPLL_FREQ)) + { + rates[0] = (uint64_t)rates[1] * PLL_mult; + return PLL_mult; + } + PLL_mult >>= 1; + } + return -1; +} + + +int determine_path_rates_with_fir(uint64_t sample_rate, + uint64_t rate_gov, + uint64_t *rx_path_clks, + uint64_t *tx_path_clks, + int FIR) +{ + uint64_t rates[6]; + int PLL_mult, k; + + max_rate_found = 0UL; + + const int HB_configs[][4] = { + {3, 2, 2, FIR}, //12 + {2, 2, 2, FIR}, //8 + {3, 2, 1, FIR}, //6 + {2, 2, 1, FIR}, //4 + {2, 1, 1, FIR}, //2 + {3, 1, 1, FIR}, //3 + {1, 1, 1, FIR}, //1 + }; + + // RX Path: + // BBPLL -> /PLL_div -> /HB3 -> /HB2 -> /HB1 -> /FIR + // TX Path: + // BBPLL -> /(PLL_div*DAC_div) -> /HB3 -> /HB2 -> /HB1 -> /FIR + + // Cycle through possible decimations from highest to lowest + for (k = 0; k < 7; k++) + { + // HB3 cannot be 3 if rate_gov enabled + if ((rate_gov > 0) && HB_configs[k][0] == 3) + continue; + // Check if HB and FIR rates are valid + if (check_rates(FIR, HB_configs[k], sample_rate, rates)) + { + // Calculate PLL divider for configuration + PLL_mult = determine_pll_div(rates); + if (PLL_mult > 0) + { + // Determine DAC divider setting and check ADC/DAC settings + int dac_div = check_dac_adc_config(rates[0], PLL_mult, k); + // printf("dac_div: %d\n",dac_div); + if (dac_div > 0) + set_rates(rx_path_clks, tx_path_clks, dac_div, rates, k); + } + } + } + + if (max_rate_found == 0UL) + return -EINVAL; + else + return 0; +} + + +int ad9361_calculate_rf_clock_chain(uint64_t sample_rate, + uint64_t rate_gov, + uint64_t *rx_path_clks, + uint64_t *tx_path_clks) +{ + int ret, k; + int FIR[] = {4, 2, 1}; + + // Check desired rate within bounds + if (!check(sample_rate, MIN_DATA_RATE, MAX_DATA_RATE)) + return -EINVAL; + + // Rate selection will try to: + // 1. Utilize the maximum decimation in the FIR + // 2. Run the ADC/DAC as fast as possible + // 3. Use the most decimation possible starting with HB3(closest to ADC)->HB1 + + // Cycle through available FIR settings + for (k = 0; k < 3; k++) + { + ret = determine_path_rates_with_fir(sample_rate, rate_gov, rx_path_clks, + tx_path_clks, FIR[k]); + if (ret == 0) + break; + } + return ret; +} + + +int apply_custom_filter(struct iio_device *dev, unsigned dec_tx, + unsigned dec_rx, short *tapsTx, + short *tapsRx, unsigned taps, + uint64_t rate, + int gain_tx, int gain_rx, + uint64_t wnom_tx, uint64_t wnom_rx) +{ + struct iio_channel *chanTX, *chanRX; + long long current_rate; + int ret, i, enable, len = 0; + char *buf; + + chanTX = iio_device_find_channel(dev, "voltage0", true); + if (chanTX == NULL) + return -ENODEV; + + ret = iio_channel_attr_read_longlong(chanTX, "sampling_frequency", ¤t_rate); + if (ret < 0) + return ret; + + ret = ad9361_get_trx_fir_enable(dev, &enable); + if (ret < 0) + return ret; + + if (enable) + { + if (current_rate <= (25000000 / 12)) + iio_channel_attr_write_longlong(chanTX, "sampling_frequency", 3000000); + + ret = ad9361_set_trx_fir_enable(dev, false); + if (ret < 0) + return ret; + } + + buf = (char *)malloc(FIR_BUF_SIZE); + if (!buf) + return -ENOMEM; + + + len += snprintf(buf + len, FIR_BUF_SIZE - len, "RX 3 GAIN %d DEC %d\n", gain_rx, + dec_rx); + len += snprintf(buf + len, FIR_BUF_SIZE - len, "TX 3 GAIN %d INT %d\n", gain_tx, + dec_tx); + + for (i = 0; i < (int)taps; i++) + len += snprintf(buf + len, FIR_BUF_SIZE - len, "%d,%d\n", tapsRx[i], tapsTx[i]); + + len += snprintf(buf + len, FIR_BUF_SIZE - len, "\n"); + + ret = iio_device_attr_write_raw(dev, "filter_fir_config", buf, len); + free(buf); + + if (ret < 0) + return ret; + + if (rate <= (25000000 / 12)) + { + int dacrate, txrate, max; + char readbuf[100]; + ret = iio_device_attr_read(dev, "tx_path_rates", readbuf, sizeof(readbuf)); + if (ret < 0) + return ret; + ret = sscanf(readbuf, "BBPLL:%*d DAC:%d T2:%*d T1:%*d TF:%*d TXSAMP:%d", + &dacrate, &txrate); + if (ret != 2) + return -EFAULT; + if (txrate == 0) + return -EINVAL; + max = (dacrate / txrate) * 16; + if (max < taps) + iio_channel_attr_write_longlong(chanTX, "sampling_frequency", 3000000); + + + ret = ad9361_set_trx_fir_enable(dev, true); + if (ret < 0) + return ret; + ret = iio_channel_attr_write_longlong(chanTX, "sampling_frequency", rate); + if (ret < 0) + return ret; + } + else + { + ret = iio_channel_attr_write_longlong(chanTX, "sampling_frequency", rate); + if (ret < 0) + return ret; + ret = ad9361_set_trx_fir_enable(dev, true); + if (ret < 0) + return ret; + } + + chanRX = iio_device_find_channel(dev, "voltage0", false); + if (chanRX == NULL) + return -ENODEV; + ret = iio_channel_attr_write_longlong(chanTX, "rf_bandwidth", wnom_tx); + if (ret < 0) + return ret; + ret = iio_channel_attr_write_longlong(chanRX, "rf_bandwidth", wnom_rx); + if (ret < 0) + return ret; + + return 0; +} + + +int ad9361_set_bb_rate_custom_filter_auto(struct iio_device *dev, + uint64_t rate) +{ + struct filter_design_parameters fdpTX; + struct filter_design_parameters fdpRX; + short taps_tx[128]; + short taps_rx[128]; + int ret, num_taps_tx, num_taps_rx, gain_tx, gain_rx; + unsigned dec_tx, dec_rx, num_taps; + + ret = ad9361_calculate_rf_clock_chain_fdp(&fdpTX, &fdpRX, rate); + if (ret < 0) + return ret; + + ret = ad9361_generate_fir_taps(&fdpRX, taps_rx, &num_taps_rx, &gain_rx); + if (ret < 0) + return ret; + + ret = ad9361_generate_fir_taps(&fdpTX, taps_tx, &num_taps_tx, &gain_tx); + if (ret < 0) + return ret; + + dec_tx = (unsigned)fdpTX.FIR; + dec_rx = (unsigned)fdpRX.FIR; + num_taps = (unsigned)fdpTX.maxTaps; + ret = apply_custom_filter(dev, dec_tx, dec_rx, taps_tx, taps_rx, num_taps, + rate, gain_tx, gain_rx, fdpTX.wnom, fdpRX.wnom); + if (ret < 0) + return ret; + + return 0; +} + +int build_configuration(struct filter_design_parameters *fdpTX, + struct filter_design_parameters *fdpRX, + uint64_t sample_rate, + uint64_t Fpass, + uint64_t Fstop, + uint64_t wnomTX, + uint64_t wnomRX) +{ + double div, max; + uint64_t rx_path_clk[6]; + uint64_t tx_path_clk[6]; + uint64_t *path_clk; + struct filter_design_parameters *fdp; + int ret, k; + uint64_t rate_gov = 0; + + ret = ad9361_calculate_rf_clock_chain((uint64_t)sample_rate, + rate_gov, rx_path_clk, tx_path_clk); + if (ret < 0) + return -EINVAL; + + for (k = 0; k < 2; k++) + { + if (k > 0) + { + path_clk = tx_path_clk; + fdp = fdpTX; + fdp->RxTx = "Tx"; + fdp->DAC_div = (double)rx_path_clk[1] / tx_path_clk[1]; + } + else + { + path_clk = rx_path_clk; + fdp = fdpRX; + fdp->RxTx = "Rx"; + fdp->DAC_div = 1.0; + } + // Map rates and dividers + fdp->PLL_rate = (double)path_clk[0]; + fdp->converter_rate = (double)path_clk[1]; + fdp->PLL_mult = (double)path_clk[0] / path_clk[1]; + fdp->HB3 = (double)path_clk[1] / path_clk[2]; + fdp->HB2 = (double)path_clk[2] / path_clk[3]; + fdp->HB1 = (double)path_clk[3] / path_clk[4]; + fdp->FIR = (double)path_clk[4] / path_clk[5]; + + // Set default parameters + fdp->Rdata = (double)path_clk[5]; + fdp->Type = "Lowpass"; + fdp->int_FIR = 1; + fdp->Apass = 0.5; + fdp->Astop = 80; + fdp->phEQ = -1; + fdp->FIRdBmin = 0; + // Define filter design specifications + fdp->Fpass = (double)Fpass; + fdp->Fstop = (double)Fstop; + fdp->Fcenter = 0.0; + if (k > 0) + fdp->wnom = (double)wnomTX; + else + fdp->wnom = (double)wnomRX; + // Determine default analog bandwidth + div = ceil((fdp->PLL_rate / fdp->wnom) * (log(2) / (2 * M_PI))); + max = (div > 1) ? div : 1.0; + fdp->caldiv = (max > 511) ? 511.0 : max; + fdp->RFbw = calculate_rfbw(fdp->PLL_rate, fdp->caldiv, k > 0, &(fdp->caldiv)); + + if (fdp->RFbw < 0) + return -EINVAL; + } + set_max_taps(fdpTX, fdpRX); + + return 0; +} + + +int ad9361_set_bb_rate_custom_filter_manual(struct iio_device *dev, + uint64_t rate, uint64_t Fpass, + uint64_t Fstop, uint64_t wnom_tx, uint64_t wnom_rx) +{ + struct filter_design_parameters fdpTX; + struct filter_design_parameters fdpRX; + short taps_tx[128]; + short taps_rx[128]; + int ret, num_taps_tx, num_taps_rx, gain_tx, gain_rx; + unsigned dec_tx, dec_rx, num_taps; + + if (Fpass >= Fstop) + return -EINVAL; + + ret = build_configuration(&fdpTX, &fdpRX, rate, Fpass, Fstop, wnom_tx, + wnom_rx); + if (ret < 0) + return ret; + + ret = ad9361_generate_fir_taps(&fdpRX, taps_rx, &num_taps_rx, &gain_rx); + if (ret < 0) + return ret; + + ret = ad9361_generate_fir_taps(&fdpTX, taps_tx, &num_taps_tx, &gain_tx); + if (ret < 0) + return ret; + + dec_tx = (unsigned)fdpTX.FIR; + dec_rx = (unsigned)fdpRX.FIR; + num_taps = (unsigned)fdpTX.maxTaps; + + ret = apply_custom_filter(dev, dec_tx, dec_rx, taps_tx, taps_rx, num_taps, + rate, gain_tx, gain_rx, wnom_tx, wnom_rx); + if (ret < 0) + return ret; + + return 0; +} + + /* finds AD9361 streaming IIO devices */ bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev) { @@ -195,17 +721,17 @@ bool config_ad9361_rx_local(uint64_t bandwidth_, // RX stream config // Stream configurations struct stream_cfg rxcfg; - rxcfg.bw_hz = bandwidth_; // 2 MHz rf bandwidth - rxcfg.fs_hz = sample_rate_; // 2.5 MS/s rx sample rate - rxcfg.lo_hz = freq_; // 2.5 GHz rf frequency - rxcfg.rfport = rf_port_select_.c_str(); // port A (select for rf freq.) + rxcfg.bw_hz = bandwidth_; + rxcfg.fs_hz = sample_rate_; + rxcfg.lo_hz = freq_; + rxcfg.rfport = rf_port_select_.c_str(); std::cout << "AD9361 Acquiring IIO LOCAL context\n"; struct iio_context *ctx; // Streaming devices struct iio_device *rx; - struct iio_channel *rx0_i; - struct iio_channel *rx0_q; + struct iio_channel *rx_chan1; + struct iio_channel *rx_chan2; ctx = iio_create_default_context(); if (!ctx) @@ -236,21 +762,21 @@ bool config_ad9361_rx_local(uint64_t bandwidth_, } std::cout << "* Initializing AD9361 IIO streaming channels\n"; - if (!get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i)) + if (!get_ad9361_stream_ch(ctx, RX, rx, 0, &rx_chan1)) { - std::cout << "RX chan i not found\n"; - throw std::runtime_error("RX chan i not found"); + std::cout << "RX channel 1 not found\n"; + throw std::runtime_error("RX channel 1 not found"); } - if (!get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q)) + if (!get_ad9361_stream_ch(ctx, RX, rx, 1, &rx_chan2)) { - std::cout << "RX chan q not found\n"; - throw std::runtime_error("RX chan q not found"); + std::cout << "RX channel 2 not found\n"; + throw std::runtime_error("RX channel 2 not found"); } std::cout << "* Enabling IIO streaming channels\n"; - iio_channel_enable(rx0_i); - iio_channel_enable(rx0_q); + iio_channel_enable(rx_chan1); + iio_channel_enable(rx_chan2); struct iio_device *ad9361_phy; ad9361_phy = iio_context_find_device(ctx, "ad9361-phy"); @@ -334,8 +860,8 @@ bool config_ad9361_rx_remote(const std::string &remote_host, struct iio_context *ctx; // Streaming devices struct iio_device *rx; - struct iio_channel *rx0_i; - struct iio_channel *rx0_q; + struct iio_channel *rx_chan1; + struct iio_channel *rx_chan2; ctx = iio_create_network_context(remote_host.c_str()); if (!ctx) @@ -365,13 +891,13 @@ bool config_ad9361_rx_remote(const std::string &remote_host, int ret; std::cout << "* Initializing AD9361 IIO streaming channels\n"; - if (!get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i)) + if (!get_ad9361_stream_ch(ctx, RX, rx, 0, &rx_chan1)) { std::cout << "RX chan i not found\n"; throw std::runtime_error("RX chan i not found"); } - if (!get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q)) + if (!get_ad9361_stream_ch(ctx, RX, rx, 1, &rx_chan2)) { std::cout << "RX chan q not found\n"; throw std::runtime_error("RX chan q not found"); @@ -400,20 +926,18 @@ bool config_ad9361_rx_remote(const std::string &remote_host, // set bw //params.push_back("in_voltage_rf_bandwidth=" + boost::to_string(bandwidth)); } - //wr_ch_str(rx0_i, "rf_port_select", rf_port_select_.c_str()); + //wr_ch_str(rx_chan1, "rf_port_select", rf_port_select_.c_str()); ret = iio_device_attr_write(ad9361_phy, "in_voltage0_rf_port_select", rf_port_select_.c_str()); if (ret) { throw std::runtime_error("Unable to set rf_port_select"); } - wr_ch_lli(rx0_i, "rf_bandwidth", bandwidth_); - - //if (!get_lo_chan(ctx, "RX", &chn)) - // { - // return false; - // } - //wr_ch_lli(chn, "frequency", freq_); - // in_voltage0_rf_port_select + wr_ch_lli(rx_chan1, "rf_bandwidth", bandwidth_); + if (!get_lo_chan(ctx, RX, &rx_chan1)) + { + return false; + } + wr_ch_lli(rx_chan1, "frequency", freq_); } else if (filter_source_ == "File") { @@ -433,13 +957,17 @@ bool config_ad9361_rx_remote(const std::string &remote_host, { throw std::runtime_error("Unable to set rf_port_select"); } - wr_ch_lli(rx0_i, "rf_bandwidth", bandwidth_); - wr_ch_lli(rx0_i, "frequency", freq_); + wr_ch_lli(rx_chan1, "rf_bandwidth", bandwidth_); + if (!get_lo_chan(ctx, RX, &rx_chan1)) + { + return false; + } + wr_ch_lli(rx_chan1, "frequency", freq_); } else if (filter_source_ == "Design") { ret = ad9361_set_bb_rate_custom_filter_manual( - ad9361_phy, sample_rate_, Fpass_, Fstop_, bandwidth_, bandwidth_); + ad9361_phy, sample_rate_, static_cast(Fpass_), static_cast(Fstop_), bandwidth_, bandwidth_); if (ret) { throw std::runtime_error("Unable to set BB rate"); @@ -449,8 +977,12 @@ bool config_ad9361_rx_remote(const std::string &remote_host, { throw std::runtime_error("Unable to set rf_port_select"); } - wr_ch_lli(rx0_i, "rf_bandwidth", bandwidth_); - wr_ch_lli(rx0_i, "frequency", freq_); + wr_ch_lli(rx_chan1, "rf_bandwidth", bandwidth_); + if (!get_lo_chan(ctx, RX, &rx_chan1)) + { + return false; + } + wr_ch_lli(rx_chan1, "frequency", freq_); } else { @@ -468,8 +1000,8 @@ bool config_ad9361_rx_remote(const std::string &remote_host, } std::cout << "* Enabling IIO streaming channels\n"; - iio_channel_enable(rx0_i); - iio_channel_enable(rx0_q); + iio_channel_enable(rx_chan1); + iio_channel_enable(rx_chan2); ret = iio_device_attr_write(ad9361_phy, "trx_rate_governor", "nominal"); if (ret < 0) @@ -528,7 +1060,6 @@ bool config_ad9361_rx_remote(const std::string &remote_host, } } - std::cout << "End of AD9361 RX configuration.\n"; iio_context_destroy(ctx); diff --git a/src/algorithms/signal_source/libs/ad9361_manager.h b/src/algorithms/signal_source/libs/ad9361_manager.h index 10353ac64..e94bfd55b 100644 --- a/src/algorithms/signal_source/libs/ad9361_manager.h +++ b/src/algorithms/signal_source/libs/ad9361_manager.h @@ -37,6 +37,7 @@ #include #include +#define FIR_BUF_SIZE 8192 /* RX is input, TX is output */ enum iodev @@ -48,7 +49,7 @@ enum iodev /* common RX and TX streaming params */ struct stream_cfg { - int64_t bw_hz; // Analog banwidth in Hz + int64_t bw_hz; // Analog bandwidth in Hz int64_t fs_hz; // Baseband sample rate in Hz int64_t lo_hz; // Local oscillator frequency in Hz const char *rfport; // Port name @@ -64,9 +65,6 @@ void wr_ch_lli(struct iio_channel *chn, const char *what, int64_t val); /* write attribute: string */ void wr_ch_str(struct iio_channel *chn, const char *what, const char *str); -/* helper function generating channel names */ -char *get_ch_name(const char *type, int id, char *tmpstr); - /* returns ad9361 phy device */ struct iio_device *get_ad9361_phy(struct iio_context *ctx); @@ -127,11 +125,58 @@ bool config_ad9361_lo_remote(const std::string &remote_host, double scale_dds_dbfs_, double phase_dds_deg_); - bool ad9361_disable_lo_remote(const std::string &remote_host); bool ad9361_disable_lo_local(); bool load_fir_filter(std::string &filter, struct iio_device *phy); +int ad9361_set_bb_rate_custom_filter_manual(struct iio_device *dev, + uint64_t rate, uint64_t Fpass, + uint64_t Fstop, uint64_t wnom_tx, uint64_t wnom_rx); + +int ad9361_set_bb_rate_custom_filter_auto(struct iio_device *dev, + uint64_t rate); + +int apply_custom_filter(struct iio_device *dev, unsigned dec_tx, + unsigned dec_rx, short *tapsTx, + short *tapsRx, unsigned taps, + uint64_t rate, + int gain_tx, int gain_rx, + uint64_t wnom_tx, uint64_t wnom_rx); + +int ad9361_calculate_rf_clock_chain(uint64_t sample_rate, + uint64_t rate_gov, + uint64_t *rx_path_clks, + uint64_t *tx_path_clks); + +int determine_path_rates_with_fir(uint64_t sample_rate, + uint64_t rate_gov, + uint64_t *rx_path_clks, + uint64_t *tx_path_clks, + uint64_t tmp, + int FIR); + +bool check_rates(int FIR, const int *HB_configs, uint64_t samp_rate, + uint64_t *rates); + +int determine_pll_div(uint64_t *rates); + +int check_dac_adc_config(uint64_t pll_bb, int PLL_mult, + int dec_table_index); + +double calculate_rfbw(double pll_rate, double caldiv, bool TX, + double *rcaldiv); + +int build_configuration(struct filter_design_parameters *fdpTX, + struct filter_design_parameters *fdpRX, + uint64_t sample_rate, + uint64_t Fpass, + uint64_t Fstop, + uint64_t wnomTX, + uint64_t wnomRX); + +void set_max_taps(struct filter_design_parameters *fdpTX, + struct filter_design_parameters *fdpRX); + #endif // GNSS_SDR_AD9361_MANAGER_H_