diff --git a/CMakeLists.txt b/CMakeLists.txt index 789a19974..22ad70e01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ option(ENABLE_ARRAY "Enable the use of CTTC's antenna array front-end as signal option(ENABLE_GN3S "Enable the use of the GN3S dongle as signal source (experimental)" OFF) option(ENABLE_PLUTOSDR "Enable the use of ADALM-PLUTO Evaluation Boards (Analog Devices Inc.), requires gr-iio" OFF) option(ENABLE_FMCOMMS2 "Enable the use of FMCOMMS4-EBZ + ZedBoard hardware, requires gr-iio" OFF) +option(ENABLE_AD9361 "Enable the use of AD9361 directo to FPGA hardware, requires gr-iio" OFF) # Performance analysis tools option(ENABLE_GPERFTOOLS "Enable linking to Gperftools libraries (tcmalloc and profiler)" OFF) diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc index c1a037c11..d9ef75ae3 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc @@ -1,14 +1,17 @@ /*! * \file gps_l1_ca_pcps_acquisition_fpga.cc - * \brief Adapts a PCPS acquisition block to an FPGA Acquisition Interface for - * GPS L1 C/A signals. This file is based on the file gps_l1_ca_pcps_acquisition.cc + * \brief Adapts a PCPS acquisition block to an FPGA AcquisitionInterface + * for GPS L1 C/A signals * \authors * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,13 +34,17 @@ * ------------------------------------------------------------------------- */ -#include "gps_l1_ca_pcps_acquisition_fpga.h" -#include -#include -#include -#include "GPS_L1_CA.h" #include "configuration_interface.h" #include "gnss_sdr_flags.h" +#include "gps_l1_ca_pcps_acquisition_fpga.h" +#include "gps_sdr_signal_processing.h" +#include "GPS_L1_CA.h" +#include +#include +#include + + +#define NUM_PRNs 32 using google::LogMessage; @@ -45,87 +52,90 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( ConfigurationInterface* configuration, std::string role, unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { - unsigned int code_length; - bool bit_transition_flag; - bool use_CFAR_algorithm_flag; - unsigned int sampled_ms; - long fs_in; - long ifreq; - bool dump; - std::string dump_filename; - unsigned int nsamples_total; - unsigned int select_queue_Fpga; - std::string device_name; - + pcpsconf_fpga_t acq_parameters; configuration_ = configuration; - - std::string default_item_type = "cshort"; - std::string default_dump_filename = "./data/acquisition.dat"; + std::string default_item_type = "gr_complex"; DLOG(INFO) << "role " << role; - item_type_ = configuration_->property(role + ".item_type", default_item_type); - long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); - fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); - ifreq = configuration_->property(role + ".if", 0); - dump = configuration_->property(role + ".dump", false); + long fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters.fs_in = fs_in; + long ifreq = configuration_->property(role + ".if", 0); + acq_parameters.freq = ifreq; doppler_max_ = configuration_->property(role + ".doppler_max", 5000); if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; - sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); - - // note : the FPGA is implemented according to bit transition flag = 0. Setting bit transition flag to 1 has no effect. - bit_transition_flag = configuration_->property(role + ".bit_transition_flag", false); - - // note : the FPGA is implemented according to use_CFAR_algorithm = 0. Setting use_CFAR_algorithm to 1 has no effect. - use_CFAR_algorithm_flag = configuration_->property(role + ".use_CFAR_algorithm", false); - - // note : the FPGA does not use the max_dwells variable. - max_dwells_ = configuration_->property(role + ".max_dwells", 1); - - dump_filename = configuration_->property(role + ".dump_filename", default_dump_filename); - - //--- Find number of samples per spreading code ------------------------- - code_length = round( - fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); - - // code length has the same value as d_fft_size - float nbits; - nbits = ceilf(log2f(code_length)); - nsamples_total = pow(2, nbits); - - //vector_length_ = code_length_ * sampled_ms_; - vector_length_ = nsamples_total * sampled_ms; - - // if( bit_transition_flag_ ) - // { - // vector_length_ *= 2; - // } - - select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 0); + acq_parameters.doppler_max = doppler_max_; + unsigned int sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); + acq_parameters.sampled_ms = sampled_ms; + unsigned int code_length = static_cast(std::round(static_cast(fs_in) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + // The FPGA can only use FFT lengths that are a power of two. + float nbits = ceilf(log2f((float)code_length)); + unsigned int nsamples_total = pow(2, nbits); + unsigned int vector_length = nsamples_total * sampled_ms; + unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 0); + acq_parameters.select_queue_Fpga = select_queue_Fpga; std::string default_device_name = "/dev/uio0"; - device_name = configuration_->property(role + ".devicename", default_device_name); + std::string device_name = configuration_->property(role + ".devicename", default_device_name); + acq_parameters.device_name = device_name; + acq_parameters.samples_per_ms = nsamples_total; + acq_parameters.samples_per_code = nsamples_total; - if (item_type_.compare("cshort") == 0) + // compute all the GPS L1 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time + // a channel is assigned) + + gr::fft::fft_complex* fft_if = new gr::fft::fft_complex(vector_length, true); // Direct FFT + // allocate memory to compute all the PRNs and compute all the possible codes + std::complex* code = new std::complex[nsamples_total]; // buffer for the local code + gr_complex* fft_codes_padded = static_cast(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + d_all_fft_codes_ = new lv_16sc_t[nsamples_total * NUM_PRNs]; // memory containing all the possible fft codes for PRN 0 to 32 + float max; // temporary maxima search + + for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) { - item_size_ = sizeof(lv_16sc_t); - gps_acquisition_fpga_sc_ = gps_pcps_make_acquisition_fpga_sc( - sampled_ms, max_dwells_, doppler_max_, ifreq, fs_in, - code_length, code_length, vector_length_, nsamples_total, - bit_transition_flag, use_CFAR_algorithm_flag, - select_queue_Fpga, device_name, dump, dump_filename); - DLOG(INFO) << "acquisition(" - << gps_acquisition_fpga_sc_->unique_id() << ")"; - } - else - { - LOG(WARNING) << "item_type configured to " << item_type_ << "but FPGA implementation only accepts cshort"; - throw std::invalid_argument("Wrong input_type configuration. Should be cshort"); + gps_l1_ca_code_gen_complex_sampled(code, PRN, fs_in, 0); // generate PRN code + // fill in zero padding + for (int s = code_length; s < nsamples_total; s++) + { + code[s] = 0; + } + int offset = 0; + memcpy(fft_if->get_inbuf() + offset, code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer + fft_if->execute(); // Run the FFT of local code + volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values + max = 0; // initialize maximum value + for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + { + if (std::abs(fft_codes_padded[i].real()) > max) + { + max = std::abs(fft_codes_padded[i].real()); + } + if (std::abs(fft_codes_padded[i].imag()) > max) + { + max = std::abs(fft_codes_padded[i].imag()); + } + } + for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + { + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); + } } + //acq_parameters + + acq_parameters.all_fft_codes = d_all_fft_codes_; + + // temporary buffers that we can delete + delete[] code; + delete fft_if; + delete[] fft_codes_padded; + + acquisition_fpga_ = pcps_make_acquisition(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + channel_ = 0; - threshold_ = 0.0; doppler_step_ = 0; gnss_synchro_ = 0; } @@ -133,125 +143,93 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( GpsL1CaPcpsAcquisitionFpga::~GpsL1CaPcpsAcquisitionFpga() { + delete[] d_all_fft_codes_; } void GpsL1CaPcpsAcquisitionFpga::set_channel(unsigned int channel) { channel_ = channel; - gps_acquisition_fpga_sc_->set_channel(channel_); + acquisition_fpga_->set_channel(channel_); } void GpsL1CaPcpsAcquisitionFpga::set_threshold(float threshold) { - float pfa = configuration_->property(role_ + ".pfa", 0.0); - - if (pfa == 0.0) - { - threshold_ = threshold; - } - else - { - threshold_ = calculate_threshold(pfa); - } - - DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - gps_acquisition_fpga_sc_->set_threshold(threshold_); + DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold; + acquisition_fpga_->set_threshold(threshold); } void GpsL1CaPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max) { doppler_max_ = doppler_max; - gps_acquisition_fpga_sc_->set_doppler_max(doppler_max_); + acquisition_fpga_->set_doppler_max(doppler_max_); } void GpsL1CaPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - gps_acquisition_fpga_sc_->set_doppler_step(doppler_step_); + acquisition_fpga_->set_doppler_step(doppler_step_); } void GpsL1CaPcpsAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - gps_acquisition_fpga_sc_->set_gnss_synchro(gnss_synchro_); + acquisition_fpga_->set_gnss_synchro(gnss_synchro_); } signed int GpsL1CaPcpsAcquisitionFpga::mag() { - return gps_acquisition_fpga_sc_->mag(); + return acquisition_fpga_->mag(); } void GpsL1CaPcpsAcquisitionFpga::init() { - gps_acquisition_fpga_sc_->init(); - set_local_code(); + acquisition_fpga_->init(); } void GpsL1CaPcpsAcquisitionFpga::set_local_code() { - gps_acquisition_fpga_sc_->set_local_code(); + acquisition_fpga_->set_local_code(); } void GpsL1CaPcpsAcquisitionFpga::reset() { - gps_acquisition_fpga_sc_->set_active(true); + acquisition_fpga_->set_active(true); } void GpsL1CaPcpsAcquisitionFpga::set_state(int state) { - gps_acquisition_fpga_sc_->set_state(state); -} - - -float GpsL1CaPcpsAcquisitionFpga::calculate_threshold(float pfa) -{ - //Calculate the threshold - unsigned int frequency_bins = 0; - for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); - doppler += doppler_step_) - { - frequency_bins++; - } - DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; - unsigned int ncells = vector_length_ * frequency_bins; - double exponent = 1 / static_cast(ncells); - double val = pow(1.0 - pfa, exponent); - double lambda = double(vector_length_); - boost::math::exponential_distribution mydist(lambda); - float threshold = static_cast(quantile(mydist, val)); - - return threshold; + acquisition_fpga_->set_state(state); } void GpsL1CaPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block) { - //nothing to connect + // nothing to connect } void GpsL1CaPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block) { - //nothing to disconnect + // nothing to disconnect } gr::basic_block_sptr GpsL1CaPcpsAcquisitionFpga::get_left_block() { - return gps_acquisition_fpga_sc_; + return acquisition_fpga_; } gr::basic_block_sptr GpsL1CaPcpsAcquisitionFpga::get_right_block() { - return gps_acquisition_fpga_sc_; + return acquisition_fpga_; } diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h index 2c8f9eed4..f070e8818 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h @@ -1,14 +1,17 @@ /*! * \file gps_l1_ca_pcps_acquisition_fpga.h - * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for - * GPS L1 C/A signals. This file is based on the file gps_l1_ca_pcps_acquisition.h + * \brief Adapts a PCPS acquisition block that uses the FPGA to + * an AcquisitionInterface for GPS L1 C/A signals * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Marc Majoral, 2018. mmajoral(at)cttc.es + *
  • Javier Arribas, 2011. jarribas(at)cttc.es + *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
  • Marc Molina, 2013. marc.molina.pena(at)gmail.com *
* * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -34,14 +37,11 @@ #ifndef GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_ #define GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_ -#include -#include -#include -#include "gnss_synchro.h" #include "acquisition_interface.h" -#include "gps_pcps_acquisition_fpga_sc.h" -#include "complex_byte_to_float_x2.h" +#include "gnss_synchro.h" +#include "pcps_acquisition_fpga.h" #include +#include class ConfigurationInterface; @@ -68,12 +68,13 @@ public: */ inline std::string implementation() override { - return "GPS_L1_CA_PCPS_Acquisition_Fpga"; + return "GPS_L1_CA_PCPS_Acquisition"; } inline size_t item_size() override { - return item_size_; + size_t item_size = sizeof(lv_16sc_t); + return item_size; } void connect(gr::top_block_sptr top_block) override; @@ -135,21 +136,15 @@ public: private: ConfigurationInterface* configuration_; - gps_pcps_acquisition_fpga_sc_sptr gps_acquisition_fpga_sc_; - size_t item_size_; - std::string item_type_; - unsigned int vector_length_; + pcps_acquisition_fpga_sptr acquisition_fpga_; unsigned int channel_; - float threshold_; unsigned int doppler_max_; unsigned int doppler_step_; - unsigned int max_dwells_; Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; - - float calculate_threshold(float pfa); + lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts }; -#endif /* GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_H_ */ +#endif /* GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_ */ diff --git a/src/algorithms/acquisition/gnuradio_blocks/CMakeLists.txt b/src/algorithms/acquisition/gnuradio_blocks/CMakeLists.txt index ca02bb952..9bfd4fc73 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/acquisition/gnuradio_blocks/CMakeLists.txt @@ -29,7 +29,7 @@ set(ACQ_GR_BLOCKS_SOURCES ) if(ENABLE_FPGA) - set(ACQ_GR_BLOCKS_SOURCES ${ACQ_GR_BLOCKS_SOURCES} gps_pcps_acquisition_fpga_sc.cc) + set(ACQ_GR_BLOCKS_SOURCES ${ACQ_GR_BLOCKS_SOURCES} pcps_acquisition_fpga.cc) endif(ENABLE_FPGA) if(OPENCL_FOUND) diff --git a/src/algorithms/acquisition/gnuradio_blocks/gps_pcps_acquisition_fpga_sc.cc b/src/algorithms/acquisition/gnuradio_blocks/gps_pcps_acquisition_fpga_sc.cc deleted file mode 100644 index d0f2baaf1..000000000 --- a/src/algorithms/acquisition/gnuradio_blocks/gps_pcps_acquisition_fpga_sc.cc +++ /dev/null @@ -1,315 +0,0 @@ -/*! - * \file gps_pcps_acquisition_fpga_sc.cc - * \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA. - * This file is based on the file gps_pcps_acquisition_sc.cc - * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat - *
- * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR 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. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "gps_pcps_acquisition_fpga_sc.h" -#include -#include -#include -#include -#include -#include -#include "control_message_factory.h" -#include "GPS_L1_CA.h" //GPS_TWO_PI -using google::LogMessage; - -void wait3(int seconds) -{ - boost::this_thread::sleep_for(boost::chrono::seconds{seconds}); -} - - -gps_pcps_acquisition_fpga_sc_sptr gps_pcps_make_acquisition_fpga_sc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, int samples_per_ms, - int samples_per_code, int vector_length, unsigned int nsamples_total, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - unsigned int select_queue_Fpga, std::string device_name, bool dump, - std::string dump_filename) -{ - return gps_pcps_acquisition_fpga_sc_sptr( - new gps_pcps_acquisition_fpga_sc(sampled_ms, max_dwells, - doppler_max, freq, fs_in, samples_per_ms, samples_per_code, - vector_length, nsamples_total, bit_transition_flag, - use_CFAR_algorithm_flag, select_queue_Fpga, device_name, - dump, dump_filename)); -} - - -gps_pcps_acquisition_fpga_sc::gps_pcps_acquisition_fpga_sc( - unsigned int sampled_ms, unsigned int max_dwells, - unsigned int doppler_max, long freq, long fs_in, int samples_per_ms, - int samples_per_code, int vector_length, unsigned int nsamples_total, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - unsigned int select_queue_Fpga, std::string device_name, bool dump, - std::string dump_filename) : gr::block("pcps_acquisition_fpga_sc", - gr::io_signature::make(0, 0, sizeof(lv_16sc_t)), - gr::io_signature::make(0, 0, 0)) -{ - this->message_port_register_out(pmt::mp("events")); - d_sample_counter = 0; // SAMPLE COUNTER - d_active = false; - d_state = 0; - d_samples_per_code = samples_per_code; - d_max_dwells = max_dwells; // Note : d_max_dwells is not used in the FPGA implementation - d_well_count = 0; - d_doppler_max = doppler_max; - d_fft_size = sampled_ms * samples_per_ms; - d_mag = 0; - d_num_doppler_bins = 0; - d_bit_transition_flag = bit_transition_flag; // Note : bit transition flag is ignored and assumed 0 in the FPGA implementation - d_use_CFAR_algorithm_flag = use_CFAR_algorithm_flag; // Note : user CFAR algorithm flag is ignored and assumed 0 in the FPGA implementation - d_threshold = 0.0; - d_doppler_step = 250; - d_channel = 0; - - // For dumping samples into a file - d_dump = dump; - d_dump_filename = dump_filename; - - d_gnss_synchro = 0; - - // instantiate HW accelerator class - acquisition_fpga_8sc = std::make_shared(device_name, vector_length, d_fft_size, nsamples_total, fs_in, freq, sampled_ms, select_queue_Fpga); -} - - -gps_pcps_acquisition_fpga_sc::~gps_pcps_acquisition_fpga_sc() -{ - if (d_dump) - { - d_dump_file.close(); - } - - acquisition_fpga_8sc->free(); -} - - -void gps_pcps_acquisition_fpga_sc::set_local_code() -{ - acquisition_fpga_8sc->set_local_code(d_gnss_synchro->PRN); -} - - -void gps_pcps_acquisition_fpga_sc::init() -{ - d_gnss_synchro->Flag_valid_acquisition = false; - d_gnss_synchro->Flag_valid_symbol_output = false; - d_gnss_synchro->Flag_valid_pseudorange = false; - d_gnss_synchro->Flag_valid_word = false; - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_mag = 0.0; - - d_num_doppler_bins = ceil( - static_cast(static_cast(d_doppler_max) - static_cast(-d_doppler_max)) / static_cast(d_doppler_step)); - - acquisition_fpga_8sc->open_device(); - - acquisition_fpga_8sc->init(); -} - - -void gps_pcps_acquisition_fpga_sc::set_state(int state) -{ - d_state = state; - if (d_state == 1) - { - d_gnss_synchro->Acq_delay_samples = 0.0; - d_gnss_synchro->Acq_doppler_hz = 0.0; - d_gnss_synchro->Acq_samplestamp_samples = 0; - d_well_count = 0; - d_mag = 0.0; - } - else if (d_state == 0) - { - } - else - { - LOG(ERROR) << "State can only be set to 0 or 1"; - } -} - - -void gps_pcps_acquisition_fpga_sc::set_active(bool active) -{ - float temp_peak_to_noise_level = 0.0; - float peak_to_noise_level = 0.0; - float input_power; - float test_statistics = 0.0; - acquisition_fpga_8sc->block_samples(); // block the samples to run the acquisition this is only necessary for the tests - - d_active = active; - - int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL - - d_state = 1; - - // initialize acquisition algorithm - int doppler; - uint32_t indext = 0; - float magt = 0.0; - //int effective_fft_size = ( d_bit_transition_flag ? d_fft_size/2 : d_fft_size ); - int effective_fft_size = d_fft_size; - //float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); - - d_mag = 0.0; - - unsigned int initial_sample; - - d_well_count++; - - DLOG(INFO) << "Channel: " << d_channel - << " , doing acquisition of satellite: " << d_gnss_synchro->System - << " " << d_gnss_synchro->PRN << " ,sample stamp: " - << d_sample_counter << ", threshold: " - << ", threshold: " - << d_threshold << ", doppler_max: " << d_doppler_max - << ", doppler_step: " << d_doppler_step; - - // Doppler frequency search loop - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; - doppler_index++) - { - doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - - acquisition_fpga_8sc->set_phase_step(doppler_index); - acquisition_fpga_8sc->run_acquisition(); // runs acquisition and waits until it is finished - - acquisition_fpga_8sc->read_acquisition_results(&indext, &magt, - &initial_sample, &input_power); - - d_sample_counter = initial_sample; - - temp_peak_to_noise_level = static_cast(magt) / static_cast(input_power); - if (peak_to_noise_level < temp_peak_to_noise_level) - { - peak_to_noise_level = temp_peak_to_noise_level; - d_mag = magt; - - input_power = (input_power - d_mag) / (effective_fft_size - 1); - - d_gnss_synchro->Acq_delay_samples = - static_cast(indext % d_samples_per_code); - d_gnss_synchro->Acq_doppler_hz = - static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; - test_statistics = d_mag / input_power; - } - - // Record results to file if required - if (d_dump) - { - std::stringstream filename; - //std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write - filename.str(""); - - boost::filesystem::path p = d_dump_filename; - filename << p.parent_path().string() - << boost::filesystem::path::preferred_separator - << p.stem().string() << "_" - << d_gnss_synchro->System << "_" - << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << doppler - << p.extension().string(); - - DLOG(INFO) << "Writing ACQ out to " << filename.str(); - - d_dump_file.open(filename.str().c_str(), - std::ios::out | std::ios::binary); - d_dump_file.close(); - } - } - - if (test_statistics > d_threshold) - { - d_state = 2; // Positive acquisition - - // 6.1- Declare positive acquisition using a message port - DLOG(INFO) << "positive acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " - << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << input_power; - - d_active = false; - d_state = 0; - - acquisition_message = 1; - this->message_port_pub(pmt::mp("events"), - pmt::from_long(acquisition_message)); - } - else - { - d_state = 3; // Negative acquisition - - // 6.2- Declare negative acquisition using a message port - DLOG(INFO) << "negative acquisition"; - DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " - << d_gnss_synchro->PRN; - DLOG(INFO) << "sample_stamp " << d_sample_counter; - DLOG(INFO) << "test statistics value " << test_statistics; - DLOG(INFO) << "test statistics threshold " << d_threshold; - DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; - DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "magnitude " << d_mag; - DLOG(INFO) << "input signal power " << input_power; - - d_active = false; - d_state = 0; - - acquisition_message = 2; - this->message_port_pub(pmt::mp("events"), - pmt::from_long(acquisition_message)); - } - - acquisition_fpga_8sc->unblock_samples(); - - acquisition_fpga_8sc->close_device(); - - DLOG(INFO) << "Done. Consumed 1 item."; -} - - -int gps_pcps_acquisition_fpga_sc::general_work(int noutput_items, - gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items __attribute__((unused))) -{ - // general work not used with the acquisition - return noutput_items; -} diff --git a/src/algorithms/acquisition/gnuradio_blocks/gps_pcps_acquisition_fpga_sc.h b/src/algorithms/acquisition/gnuradio_blocks/gps_pcps_acquisition_fpga_sc.h deleted file mode 100644 index c5de39c69..000000000 --- a/src/algorithms/acquisition/gnuradio_blocks/gps_pcps_acquisition_fpga_sc.h +++ /dev/null @@ -1,218 +0,0 @@ -/*! - * \file gps_pcps_acquisition_fpga_sc.h - * \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA. - * This file is based on the file gps_pcps_acquisition_sc.h - * - * Acquisition strategy (Kay Borre book + CFAR threshold). - *
    - *
  1. Compute the input signal power estimation - *
  2. Doppler serial search loop - *
  3. Perform the FFT-based circular convolution (parallel time search) - *
  4. Record the maximum peak and the associated synchronization parameters - *
  5. Compute the test statistics and compare to the threshold - *
  6. Declare positive or negative acquisition using a message port - *
- * - * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach", Birkhauser, 2007. pp 81-84 - * - * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat - *
- * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR 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. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_PCPS_ACQUISITION_FPGA_SC_H_ -#define GNSS_SDR_PCPS_ACQUISITION_FPGA_SC_H_ - -#include -#include -#include -#include -#include -#include "gnss_synchro.h" -#include "gps_fpga_acquisition_8sc.h" - -class gps_pcps_acquisition_fpga_sc; - -typedef boost::shared_ptr gps_pcps_acquisition_fpga_sc_sptr; - -gps_pcps_acquisition_fpga_sc_sptr -gps_pcps_make_acquisition_fpga_sc(unsigned int sampled_ms, - unsigned int max_dwells, unsigned int doppler_max, long freq, - long fs_in, int samples_per_ms, int samples_per_code, - int vector_length_, unsigned int nsamples_total_, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - unsigned int select_queue_Fpga, std::string device_name, bool dump, - std::string dump_filename); - -/*! - * \brief This class implements a Parallel Code Phase Search Acquisition. - * - * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", - * Algorithm 1, for a pseudocode description of this implementation. - */ -class gps_pcps_acquisition_fpga_sc : public gr::block -{ -private: - friend gps_pcps_acquisition_fpga_sc_sptr - gps_pcps_make_acquisition_fpga_sc(unsigned int sampled_ms, - unsigned int max_dwells, unsigned int doppler_max, long freq, - long fs_in, int samples_per_ms, int samples_per_code, - int vector_length, unsigned int nsamples_total, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - unsigned int select_queue_Fpga, std::string device_name, bool dump, - std::string dump_filename); - - gps_pcps_acquisition_fpga_sc(unsigned int sampled_ms, - unsigned int max_dwells, unsigned int doppler_max, long freq, - long fs_in, int samples_per_ms, int samples_per_code, - int vector_length, unsigned int nsamples_total, - bool bit_transition_flag, bool use_CFAR_algorithm_flag, - unsigned int select_queue_Fpga, std::string device_name, bool dump, - std::string dump_filename); - - int d_samples_per_code; - float d_threshold; - unsigned int d_doppler_max; - unsigned int d_doppler_step; - unsigned int d_max_dwells; - unsigned int d_well_count; - unsigned int d_fft_size; - unsigned long int d_sample_counter; - unsigned int d_num_doppler_bins; - - Gnss_Synchro *d_gnss_synchro; - float d_mag; - bool d_bit_transition_flag; - bool d_use_CFAR_algorithm_flag; - std::ofstream d_dump_file; - bool d_active; - int d_state; - bool d_dump; - unsigned int d_channel; - std::string d_dump_filename; - - std::shared_ptr acquisition_fpga_8sc; - -public: - /*! - * \brief Default destructor. - */ - ~gps_pcps_acquisition_fpga_sc(); - - /*! - * \brief Set acquisition/tracking common Gnss_Synchro object pointer - * to exchange synchronization data between acquisition and tracking blocks. - * \param p_gnss_synchro Satellite information shared by the processing blocks. - */ - inline void set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) - { - d_gnss_synchro = p_gnss_synchro; - } - - /*! - * \brief Returns the maximum peak of grid search. - */ - inline unsigned int mag() const - { - return d_mag; - } - - /*! - * \brief Initializes acquisition algorithm. - */ - void init(); - - /*! - * \brief Sets local code for PCPS acquisition algorithm. - * \param code - Pointer to the PRN code. - */ - void set_local_code(); - - /*! - * \brief Starts acquisition algorithm, turning from standby mode to - * active mode - * \param active - bool that activates/deactivates the block. - */ - void set_active(bool active); - - /*! - * \brief If set to 1, ensures that acquisition starts at the - * first available sample. - * \param state - int=1 forces start of acquisition - */ - void set_state(int state); - - /*! - * \brief Set acquisition channel unique ID - * \param channel - receiver channel. - */ - inline void set_channel(unsigned int channel) - { - d_channel = channel; - } - - /*! - * \brief Set statistics threshold of PCPS algorithm. - * \param threshold - Threshold for signal detection (check \ref Navitec2012, - * Algorithm 1, for a definition of this threshold). - */ - inline void set_threshold(float threshold) - { - d_threshold = threshold; - } - - /*! - * \brief Set maximum Doppler grid search - * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. - */ - inline void set_doppler_max(unsigned int doppler_max) - { - d_doppler_max = doppler_max; - acquisition_fpga_8sc->set_doppler_max(doppler_max); - } - - /*! - * \brief Set Doppler steps for the grid search - * \param doppler_step - Frequency bin of the search grid [Hz]. - */ - inline void set_doppler_step(unsigned int doppler_step) - { - d_doppler_step = doppler_step; - acquisition_fpga_8sc->set_doppler_step(doppler_step); - } - - /*! - * \brief Parallel Code Phase Search Acquisition signal processing. - */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* GNSS_SDR_PCPS_ACQUISITION_SC_H_*/ diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc new file mode 100644 index 000000000..6a337925e --- /dev/null +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc @@ -0,0 +1,244 @@ +/*! + * \file pcps_acquisition_fpga.cc + * \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA + * + * Note: The CFAR algorithm is not implemented in the FPGA. + * Note 2: The bit transition flag is not implemented in the FPGA + * + * \authors
    + *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Javier Arribas, 2011. jarribas(at)cttc.es + *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
  • Marc Molina, 2013. marc.molina.pena@gmail.com + *
  • Cillian O'Driscoll, 2017. cillian(at)ieee.org + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include +#include +#include "pcps_acquisition_fpga.h" + +using google::LogMessage; + +pcps_acquisition_fpga_sptr pcps_make_acquisition(pcpsconf_fpga_t conf_) +{ + return pcps_acquisition_fpga_sptr(new pcps_acquisition_fpga(conf_)); +} + + +pcps_acquisition_fpga::pcps_acquisition_fpga(pcpsconf_fpga_t conf_) : gr::block("pcps_acquisition_fpga", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_out(pmt::mp("events")); + + acq_parameters = conf_; + d_sample_counter = 0; // SAMPLE COUNTER + d_active = false; + d_state = 0; + d_fft_size = acq_parameters.sampled_ms * acq_parameters.samples_per_ms; + d_mag = 0; + d_input_power = 0.0; + d_num_doppler_bins = 0; + d_threshold = 0.0; + d_doppler_step = 0; + d_test_statistics = 0.0; + d_channel = 0; + d_gnss_synchro = 0; + + acquisition_fpga = std::make_shared + (acq_parameters.device_name, d_fft_size, acq_parameters.doppler_max, acq_parameters.samples_per_ms, + acq_parameters.fs_in, acq_parameters.freq, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes); + +} + + +pcps_acquisition_fpga::~pcps_acquisition_fpga() +{ + acquisition_fpga->free(); +} + + +void pcps_acquisition_fpga::set_local_code() +{ + acquisition_fpga->set_local_code(d_gnss_synchro->PRN); +} + + +void pcps_acquisition_fpga::init() +{ + d_gnss_synchro->Flag_valid_acquisition = false; + d_gnss_synchro->Flag_valid_symbol_output = false; + d_gnss_synchro->Flag_valid_pseudorange = false; + d_gnss_synchro->Flag_valid_word = false; + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_num_doppler_bins = static_cast(std::ceil(static_cast(static_cast(acq_parameters.doppler_max) - static_cast(-acq_parameters.doppler_max)) / static_cast(d_doppler_step))); + + acquisition_fpga->init(); +} + + +void pcps_acquisition_fpga::set_state(int state) +{ + d_state = state; + if (d_state == 1) + { + d_gnss_synchro->Acq_delay_samples = 0.0; + d_gnss_synchro->Acq_doppler_hz = 0.0; + d_gnss_synchro->Acq_samplestamp_samples = 0; + //d_well_count = 0; + d_mag = 0.0; + d_input_power = 0.0; + d_test_statistics = 0.0; + d_active = true; + } + else if (d_state == 0) + { + } + else + { + LOG(ERROR) << "State can only be set to 0 or 1"; + } +} + + +void pcps_acquisition_fpga::send_positive_acquisition() +{ + // 6.1- Declare positive acquisition using a message port + //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + DLOG(INFO) << "positive acquisition" + << ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << ", sample_stamp " << d_sample_counter + << ", test statistics value " << d_test_statistics + << ", test statistics threshold " << d_threshold + << ", code phase " << d_gnss_synchro->Acq_delay_samples + << ", doppler " << d_gnss_synchro->Acq_doppler_hz + << ", magnitude " << d_mag + << ", input signal power " << d_input_power; + + this->message_port_pub(pmt::mp("events"), pmt::from_long(1)); +} + + +void pcps_acquisition_fpga::send_negative_acquisition() +{ + // 6.2- Declare negative acquisition using a message port + //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + DLOG(INFO) << "negative acquisition" + << ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << ", sample_stamp " << d_sample_counter + << ", test statistics value " << d_test_statistics + << ", test statistics threshold " << d_threshold + << ", code phase " << d_gnss_synchro->Acq_delay_samples + << ", doppler " << d_gnss_synchro->Acq_doppler_hz + << ", magnitude " << d_mag + << ", input signal power " << d_input_power; + + this->message_port_pub(pmt::mp("events"), pmt::from_long(2)); +} + + +void pcps_acquisition_fpga::set_active(bool active) +{ + d_active = active; + + // initialize acquisition algorithm + uint32_t indext = 0; + float magt = 0.0; + float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); + + d_input_power = 0.0; + d_mag = 0.0; + + DLOG(INFO) << "Channel: " << d_channel + << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN + << " ,sample stamp: " << d_sample_counter << ", threshold: " + << d_threshold << ", doppler_max: " << acq_parameters.doppler_max + << ", doppler_step: " << d_doppler_step + // no CFAR algorithm in the FPGA + << ", use_CFAR_algorithm_flag: false"; + + unsigned int initial_sample; + float input_power_all = 0.0; + float input_power_computed = 0.0; + for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) + { + // doppler search steps + int doppler = -static_cast(acq_parameters.doppler_max) + d_doppler_step * doppler_index; + + acquisition_fpga->set_phase_step(doppler_index); + acquisition_fpga->run_acquisition(); // runs acquisition and waits until it is finished + acquisition_fpga->read_acquisition_results(&indext, &magt, + &initial_sample, &d_input_power); + d_sample_counter = initial_sample; + + if (d_mag < magt) + { + d_mag = magt; + + input_power_all = d_input_power / (d_fft_size - 1); + input_power_computed = (d_input_power - d_mag) / (d_fft_size - 1); + d_input_power = (d_input_power - d_mag) / (d_fft_size - 1); + + d_gnss_synchro->Acq_delay_samples = static_cast(indext % acq_parameters.samples_per_code); + d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; + + d_test_statistics = (d_mag / d_input_power); //* correction_factor; + } + + // In the case of the FPGA the option of dumping the results of the acquisition to a file is not available + // because the IFFT vector is not available + } + + if (d_test_statistics > d_threshold) + { + d_active = false; + send_positive_acquisition(); + d_state = 0; // Positive acquisition + } + else + { + d_state = 0; + d_active = false; + send_negative_acquisition(); + } +} + + +int pcps_acquisition_fpga::general_work(int noutput_items __attribute__((unused)), + gr_vector_int& ninput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items __attribute__((unused))) +{ + // the general work is not used with the acquisition that uses the FPGA + return noutput_items; +} diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h new file mode 100644 index 000000000..e758904e3 --- /dev/null +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h @@ -0,0 +1,213 @@ +/*! + * \file pcps_acquisition_fpga.h + * \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA. + * + * Note: The CFAR algorithm is not implemented in the FPGA. + * Note 2: The bit transition flag is not implemented in the FPGA + * + * Acquisition strategy (Kay Borre book + CFAR threshold). + *
    + *
  1. Compute the input signal power estimation + *
  2. Doppler serial search loop + *
  3. Perform the FFT-based circular convolution (parallel time search) + *
  4. Record the maximum peak and the associated synchronization parameters + *
  5. Compute the test statistics and compare to the threshold + *
  6. Declare positive or negative acquisition using a message queue + *
+ * + * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach", Birkhauser, 2007. pp 81-84 + * + * \authors
    + *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Javier Arribas, 2011. jarribas(at)cttc.es + *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com + *
  • Marc Molina, 2013. marc.molina.pena@gmail.com + *
  • Cillian O'Driscoll, 2017. cillian(at)ieee.org + *
  • Antonio Ramos, 2017. antonio.ramos@cttc.es + *
+ * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_PCPS_ACQUISITION_FPGA_H_ +#define GNSS_SDR_PCPS_ACQUISITION_FPGA_H_ + + +#include "fpga_acquisition.h" +#include "gnss_synchro.h" +#include + +typedef struct +{ + /* pcps acquisition configuration */ + unsigned int sampled_ms; + unsigned int doppler_max; + long freq; + long fs_in; + int samples_per_ms; + int samples_per_code; + unsigned int select_queue_Fpga; + std::string device_name; + lv_16sc_t* all_fft_codes; // memory that contains all the code ffts + +} pcpsconf_fpga_t; + +class pcps_acquisition_fpga; + +typedef boost::shared_ptr pcps_acquisition_fpga_sptr; + +pcps_acquisition_fpga_sptr +pcps_make_acquisition(pcpsconf_fpga_t conf_); + +/*! + * \brief This class implements a Parallel Code Phase Search Acquisition that uses the FPGA. + * + * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", + * Algorithm 1, for a pseudocode description of this implementation. + */ +class pcps_acquisition_fpga : public gr::block +{ +private: + friend pcps_acquisition_fpga_sptr + + pcps_make_acquisition(pcpsconf_fpga_t conf_); + + pcps_acquisition_fpga(pcpsconf_fpga_t conf_); + + void send_negative_acquisition(); + + void send_positive_acquisition(); + + pcpsconf_fpga_t acq_parameters; + bool d_active; + float d_threshold; + float d_mag; + float d_input_power; + float d_test_statistics; + int d_state; + unsigned int d_channel; + unsigned int d_doppler_step; + unsigned int d_fft_size; + unsigned int d_num_doppler_bins; + unsigned long int d_sample_counter; + Gnss_Synchro* d_gnss_synchro; + std::shared_ptr acquisition_fpga; + +public: + ~pcps_acquisition_fpga(); + + /*! + * \brief Set acquisition/tracking common Gnss_Synchro object pointer + * to exchange synchronization data between acquisition and tracking blocks. + * \param p_gnss_synchro Satellite information shared by the processing blocks. + */ + inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) + { + d_gnss_synchro = p_gnss_synchro; + } + + /*! + * \brief Returns the maximum peak of grid search. + */ + inline unsigned int mag() const + { + return d_mag; + } + + /*! + * \brief Initializes acquisition algorithm. + */ + void init(); + + /*! + * \brief Sets local code for PCPS acquisition algorithm. + * \param code - Pointer to the PRN code. + */ + void set_local_code(); + + /*! + * \brief If set to 1, ensures that acquisition starts at the + * first available sample. + * \param state - int=1 forces start of acquisition + */ + void set_state(int state); + + /*! + * \brief Starts acquisition algorithm, turning from standby mode to + * active mode + * \param active - bool that activates/deactivates the block. + */ + void set_active(bool active); + + /*! + * \brief Set acquisition channel unique ID + * \param channel - receiver channel. + */ + inline void set_channel(unsigned int channel) + { + d_channel = channel; + } + + /*! + * \brief Set statistics threshold of PCPS algorithm. + * \param threshold - Threshold for signal detection (check \ref Navitec2012, + * Algorithm 1, for a definition of this threshold). + */ + inline void set_threshold(float threshold) + { + d_threshold = threshold; + } + + /*! + * \brief Set maximum Doppler grid search + * \param doppler_max - Maximum Doppler shift considered in the grid search [Hz]. + */ + inline void set_doppler_max(unsigned int doppler_max) + { + acq_parameters.doppler_max = doppler_max; + acquisition_fpga->set_doppler_max(doppler_max); + } + + /*! + * \brief Set Doppler steps for the grid search + * \param doppler_step - Frequency bin of the search grid [Hz]. + */ + inline void set_doppler_step(unsigned int doppler_step) + { + d_doppler_step = doppler_step; + acquisition_fpga->set_doppler_step(doppler_step); + } + + /*! + * \brief Parallel Code Phase Search Acquisition signal processing. + */ + int general_work(int noutput_items, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; + +#endif /* GNSS_SDR_PCPS_ACQUISITION_FPGA_H_*/ diff --git a/src/algorithms/acquisition/libs/CMakeLists.txt b/src/algorithms/acquisition/libs/CMakeLists.txt index 53feb9366..f4adf131c 100644 --- a/src/algorithms/acquisition/libs/CMakeLists.txt +++ b/src/algorithms/acquisition/libs/CMakeLists.txt @@ -18,7 +18,7 @@ set(ACQUISITION_LIB_SOURCES - gps_fpga_acquisition_8sc.cc + fpga_acquisition.cc ) include_directories( diff --git a/src/algorithms/acquisition/libs/fpga_acquisition.cc b/src/algorithms/acquisition/libs/fpga_acquisition.cc new file mode 100644 index 000000000..81995faab --- /dev/null +++ b/src/algorithms/acquisition/libs/fpga_acquisition.cc @@ -0,0 +1,265 @@ +/*! + * \file fpga_acquisition.cc + * \brief High optimized FPGA vector correlator class + * \authors
    + *
  • Marc Majoral, 2018. mmajoral(at)cttc.cat + *
+ * + * Class that controls and executes a high optimized acquisition HW + * accelerator in the FPGA + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "fpga_acquisition.h" +#include "GPS_L1_CA.h" +#include "gps_sdr_signal_processing.h" +#include +#include // libraries used by the GIPO +#include // libraries used by the GIPO + + +#define PAGE_SIZE 0x10000 // default page size for the multicorrelator memory map +#define MAX_PHASE_STEP_RAD 0.999999999534339 // 1 - pow(2,-31); +#define RESET_ACQUISITION 2 // command to reset the multicorrelator +#define LAUNCH_ACQUISITION 1 // command to launch the multicorrelator +#define TEST_REG_SANITY_CHECK 0x55AA // value to check the presence of the test register (to detect the hw) +#define LOCAL_CODE_CLEAR_MEM 0x10000000 // command to clear the internal memory of the multicorrelator +#define MEM_LOCAL_CODE_WR_ENABLE 0x0C000000 // command to enable the ENA and WR pins of the internal memory of the multicorrelator +#define POW_2_2 4 // 2^2 (used for the conversion of floating point numbers to integers) +#define POW_2_29 536870912 // 2^29 (used for the conversion of floating point numbers to integers) +#define SELECT_LSB 0x00FF // value to select the least significant byte +#define SELECT_MSB 0XFF00 // value to select the most significant byte +#define SELECT_16_BITS 0xFFFF // value to select 16 bits +#define SHL_8_BITS 256 // value used to shift a value 8 bits to the left + + +bool fpga_acquisition::init() +{ + // configure the acquisition with the main initialization values + fpga_acquisition::configure_acquisition(); + return true; +} + + +bool fpga_acquisition::set_local_code(unsigned int PRN) +{ + // select the code with the chosen PRN + fpga_acquisition::fpga_configure_acquisition_local_code( + &d_all_fft_codes[d_nsamples_total * (PRN - 1)]); + return true; +} + + +fpga_acquisition::fpga_acquisition(std::string device_name, + unsigned int nsamples, + unsigned int doppler_max, + unsigned int nsamples_total, long fs_in, long freq, + unsigned int sampled_ms, unsigned select_queue, + lv_16sc_t *all_fft_codes) +{ + unsigned int vector_length = nsamples_total * sampled_ms; + // initial values + d_device_name = device_name; + d_freq = freq; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_nsamples = nsamples; // number of samples not including padding + d_select_queue = select_queue; + d_nsamples_total = nsamples_total; + d_doppler_max = doppler_max; + d_doppler_step = 0; + d_fd = 0; // driver descriptor + d_map_base = nullptr; // driver memory map + d_all_fft_codes = all_fft_codes; + + // open communication with HW accelerator + if ((d_fd = open(d_device_name.c_str(), O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" << d_device_name; + } + d_map_base = reinterpret_cast(mmap(NULL, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, d_fd, 0)); + + if (d_map_base == reinterpret_cast(-1)) + { + LOG(WARNING) << "Cannot map the FPGA acquisition module into user memory"; + } + + // sanity check : check test register + unsigned writeval = TEST_REG_SANITY_CHECK; + unsigned readval; + readval = fpga_acquisition::fpga_acquisition_test_register(writeval); + if (writeval != readval) + { + LOG(WARNING) << "Acquisition test register sanity check failed"; + } + else + { + LOG(INFO) << "Acquisition test register sanity check success!"; + } + fpga_acquisition::reset_acquisition(); + DLOG(INFO) << "Acquisition FPGA class created"; +} + + +fpga_acquisition::~fpga_acquisition() +{ + close_device(); +} + + +bool fpga_acquisition::free() +{ + return true; +} + + +unsigned fpga_acquisition::fpga_acquisition_test_register(unsigned writeval) +{ + unsigned readval; + // write value to test register + d_map_base[15] = writeval; + // read value from test register + readval = d_map_base[15]; + // return read value + return readval; +} + + +void fpga_acquisition::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]) +{ + unsigned short local_code; + unsigned int k, tmp, tmp2; + unsigned int fft_data; + // clear memory address counter + d_map_base[4] = LOCAL_CODE_CLEAR_MEM; + // write local code + for (k = 0; k < d_vector_length; k++) + { + tmp = fft_local_code[k].real(); + tmp2 = fft_local_code[k].imag(); + local_code = (tmp & SELECT_LSB) | ((tmp2 * SHL_8_BITS) & SELECT_MSB); // put together the real part and the imaginary part + fft_data = MEM_LOCAL_CODE_WR_ENABLE | (local_code & SELECT_16_BITS); + d_map_base[4] = fft_data; + } +} + + +void fpga_acquisition::run_acquisition(void) +{ + // enable interrupts + int reenable = 1; + write(d_fd, reinterpret_cast(&reenable), sizeof(int)); + // launch the acquisition process + d_map_base[6] = LAUNCH_ACQUISITION; // writing anything to reg 6 launches the acquisition process + + int irq_count; + ssize_t nb; + // wait for interrupt + nb = read(d_fd, &irq_count, sizeof(irq_count)); + if (nb != sizeof(irq_count)) + { + printf("acquisition module Read failed to retrieve 4 bytes!\n"); + printf("acquisition module Interrupt number %d\n", irq_count); + } +} + + +void fpga_acquisition::configure_acquisition() +{ + d_map_base[0] = d_select_queue; + d_map_base[1] = d_vector_length; + d_map_base[2] = d_nsamples; + d_map_base[5] = (int)log2((float)d_vector_length); // log2 FFTlength +} + + +void fpga_acquisition::set_phase_step(unsigned int doppler_index) +{ + float phase_step_rad_real; + float phase_step_rad_int_temp; + int32_t phase_step_rad_int; + int doppler = static_cast(-d_doppler_max) + d_doppler_step * doppler_index; + float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); + // The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing + // The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi) + // The FPGA also expects the phase to be negative since it produces cos(x) -j*sin(x) + // while the gnss-sdr software (volk_gnsssdr_s32f_sincos_32fc) generates cos(x) + j*sin(x) + phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); + // avoid saturation of the fixed point representation in the fpga + // (only the positive value can saturate due to the 2's complement representation) + if (phase_step_rad_real >= 1.0) + { + phase_step_rad_real = MAX_PHASE_STEP_RAD; + } + phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 + phase_step_rad_int = (int32_t)(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings + d_map_base[3] = phase_step_rad_int; +} + + +void fpga_acquisition::read_acquisition_results(uint32_t *max_index, + float *max_magnitude, unsigned *initial_sample, float *power_sum) +{ + unsigned readval = 0; + readval = d_map_base[1]; + *initial_sample = readval; + readval = d_map_base[2]; + *max_magnitude = static_cast(readval); + readval = d_map_base[4]; + *power_sum = static_cast(readval); + readval = d_map_base[3]; + *max_index = readval; +} + + +void fpga_acquisition::block_samples() +{ + d_map_base[14] = 1; // block the samples +} + + +void fpga_acquisition::unblock_samples() +{ + d_map_base[14] = 0; // unblock the samples +} + + +void fpga_acquisition::close_device() +{ + unsigned *aux = const_cast(d_map_base); + if (munmap(static_cast(aux), PAGE_SIZE) == -1) + { + printf("Failed to unmap memory uio\n"); + } + close(d_fd); +} + + +void fpga_acquisition::reset_acquisition(void) +{ + d_map_base[6] = RESET_ACQUISITION; // writing a 2 to d_map_base[6] resets the multicorrelator +} diff --git a/src/algorithms/acquisition/libs/gps_fpga_acquisition_8sc.h b/src/algorithms/acquisition/libs/fpga_acquisition.h similarity index 76% rename from src/algorithms/acquisition/libs/gps_fpga_acquisition_8sc.h rename to src/algorithms/acquisition/libs/fpga_acquisition.h index 40f8f37f2..00641e1cd 100644 --- a/src/algorithms/acquisition/libs/gps_fpga_acquisition_8sc.h +++ b/src/algorithms/acquisition/libs/fpga_acquisition.h @@ -1,12 +1,12 @@ /*! - * \file fpga_acquisition_8sc.h - * \brief High optimized FPGA vector correlator class for lv_16sc_t (short int complex). + * \file fpga_acquisition.h + * \brief High optimized FPGA vector correlator class * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Marc Majoral, 2018. mmajoral(at)cttc.cat *
* - * Class that controls and executes a high optimized vector correlator - * class in the FPGA + * Class that controls and executes a high optimized acquisition HW + * accelerator in the FPGA * * ------------------------------------------------------------------------- * @@ -33,28 +33,28 @@ * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_FPGA_ACQUISITION_8SC_H_ -#define GNSS_SDR_FPGA_ACQUISITION_8SC_H_ +#ifndef GNSS_SDR_FPGA_ACQUISITION_H_ +#define GNSS_SDR_FPGA_ACQUISITION_H_ -#include - -#include #include +#include /*! * \brief Class that implements carrier wipe-off and correlators. */ -class gps_fpga_acquisition_8sc +class fpga_acquisition { public: - gps_fpga_acquisition_8sc(std::string device_name, - unsigned int vector_length, unsigned int nsamples, + fpga_acquisition(std::string device_name, + unsigned int nsamples, + unsigned int doppler_max, unsigned int nsamples_total, long fs_in, long freq, - unsigned int sampled_ms, unsigned select_queue); - ~gps_fpga_acquisition_8sc(); + unsigned int sampled_ms, unsigned select_queue, + lv_16sc_t *all_fft_codes); + ~fpga_acquisition(); bool init(); bool set_local_code( - unsigned int PRN); //int code_length_chips, const lv_16sc_t* local_code_in, float *shifts_chips); + unsigned int PRN); bool free(); void run_acquisition(void); void set_phase_step(unsigned int doppler_index); @@ -62,8 +62,6 @@ public: unsigned *initial_sample, float *power_sum); void block_samples(); void unblock_samples(); - void open_device(); - void close_device(); /*! * \brief Set maximum Doppler grid search @@ -87,22 +85,23 @@ private: long d_freq; long d_fs_in; gr::fft::fft_complex *d_fft_if; // function used to run the fft of the local codes - // data related to the hardware module and the driver int d_fd; // driver descriptor volatile unsigned *d_map_base; // driver memory map lv_16sc_t *d_all_fft_codes; // memory that contains all the code ffts - unsigned int d_vector_length; // number of samples including padding and number of ms + unsigned int d_vector_length; // number of samples incluing padding and number of ms + unsigned int d_nsamples_total; // number of samples including padding unsigned int d_nsamples; // number of samples not including padding unsigned int d_select_queue; // queue selection std::string d_device_name; // HW device name unsigned int d_doppler_max; // max doppler unsigned int d_doppler_step; // doppler step - // FPGA private functions unsigned fpga_acquisition_test_register(unsigned writeval); void fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]); void configure_acquisition(); + void reset_acquisition(void); + void close_device(); }; -#endif /* GNSS_SDR_FPGA_MULTICORRELATOR_H_ */ +#endif /* GNSS_SDR_FPGA_ACQUISITION_H_ */ diff --git a/src/algorithms/acquisition/libs/gps_fpga_acquisition_8sc.cc b/src/algorithms/acquisition/libs/gps_fpga_acquisition_8sc.cc deleted file mode 100644 index b1a855a11..000000000 --- a/src/algorithms/acquisition/libs/gps_fpga_acquisition_8sc.cc +++ /dev/null @@ -1,332 +0,0 @@ -/*! - * \file gps_fpga_acquisition_8sc.cc - * \brief High optimized FPGA vector correlator class - * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat - *
- * - * Class that controls and executes a high optimized vector correlator - * class in the FPGA - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR 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. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "gps_fpga_acquisition_8sc.h" -#include "gps_sdr_signal_processing.h" -#include "GPS_L1_CA.h" -#include -#include - -// allocate memory dynamically -#include - -// libraries used by DMA test code and GIPO test code -#include -#include -#include -#include - -// libraries used by DMA test code -#include -#include -#include - -// libraries used by GPIO test code -#include -#include -#include - -// logging -#include - - -#define PAGE_SIZE 0x10000 -#define MAX_PHASE_STEP_RAD 0.999999999534339 // 1 - pow(2,-31); -#define NUM_PRNs 32 -#define TEST_REGISTER_ACQ_WRITEVAL 0x55AA - -bool gps_fpga_acquisition_8sc::init() -{ - // configure the acquisition with the main initialization values - gps_fpga_acquisition_8sc::configure_acquisition(); - return true; -} - -bool gps_fpga_acquisition_8sc::set_local_code(unsigned int PRN) -{ - // select the code with the chosen PRN - gps_fpga_acquisition_8sc::fpga_configure_acquisition_local_code( - &d_all_fft_codes[d_vector_length * PRN]); - return true; -} - -gps_fpga_acquisition_8sc::gps_fpga_acquisition_8sc(std::string device_name, - unsigned int vector_length, unsigned int nsamples, - unsigned int nsamples_total, long fs_in, long freq, - unsigned int sampled_ms, unsigned select_queue) -{ - // initial values - d_device_name = device_name; - d_freq = freq; - d_fs_in = fs_in; - d_vector_length = vector_length; - d_nsamples = nsamples; // number of samples not including padding - d_select_queue = select_queue; - - d_doppler_max = 0; - d_doppler_step = 0; - d_fd = 0; // driver descriptor - d_map_base = nullptr; // driver memory map - - // compute all the possible code ffts - - // Direct FFT - d_fft_if = new gr::fft::fft_complex(vector_length, true); - - // allocate memory to compute all the PRNs - // and compute all the possible codes - std::complex* code = new std::complex[nsamples_total]; // buffer for the local code - std::complex* code_total = new gr_complex[vector_length]; // buffer for the local code repeat every number of ms - - gr_complex* d_fft_codes_padded = static_cast(volk_gnsssdr_malloc(vector_length * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - - d_all_fft_codes = new lv_16sc_t[vector_length * NUM_PRNs]; // memory containing all the possible fft codes for PRN 0 to 32 - - float max; // temporary maxima search - - for (unsigned int PRN = 0; PRN < NUM_PRNs; PRN++) - { - gps_l1_ca_code_gen_complex_sampled(code, PRN, fs_in, 0); // generate PRN code - - for (unsigned int i = 0; i < sampled_ms; i++) - { - memcpy(&(code_total[i * nsamples_total]), code, sizeof(gr_complex) * nsamples_total); // repeat for each ms - } - - int offset = 0; - - memcpy(d_fft_if->get_inbuf() + offset, code_total, sizeof(gr_complex) * vector_length); // copy to FFT buffer - - d_fft_if->execute(); // Run the FFT of local code - - volk_32fc_conjugate_32fc(d_fft_codes_padded, d_fft_if->get_outbuf(), vector_length); // conjugate values - - max = 0; // initialize maximum value - - for (unsigned int i = 0; i < vector_length; i++) // search for maxima - { - if (std::abs(d_fft_codes_padded[i].real()) > max) - { - max = std::abs(d_fft_codes_padded[i].real()); - } - if (std::abs(d_fft_codes_padded[i].imag()) > max) - { - max = std::abs(d_fft_codes_padded[i].imag()); - } - } - - for (unsigned int i = 0; i < vector_length; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs - { - d_all_fft_codes[i + vector_length * PRN] = lv_16sc_t(static_cast(d_fft_codes_padded[i].real() * (pow(2, 7) - 1) / max), - static_cast(d_fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max)); - } - } - - // temporary buffers that we can delete - delete[] code; - delete[] code_total; - delete d_fft_if; - delete[] d_fft_codes_padded; -} - - -gps_fpga_acquisition_8sc::~gps_fpga_acquisition_8sc() -{ - delete[] d_all_fft_codes; -} - - -bool gps_fpga_acquisition_8sc::free() -{ - return true; -} - - -unsigned gps_fpga_acquisition_8sc::fpga_acquisition_test_register(unsigned writeval) -{ - unsigned readval; - // write value to test register - d_map_base[15] = writeval; - // read value from test register - readval = d_map_base[15]; - // return read value - return readval; -} - - -void gps_fpga_acquisition_8sc::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]) -{ - short int local_code; - unsigned int k, tmp, tmp2; - - // clear memory address counter - d_map_base[4] = 0x10000000; - for (k = 0; k < d_vector_length; k++) - { - tmp = fft_local_code[k].real(); - tmp2 = fft_local_code[k].imag(); - local_code = (tmp & 0xFF) | ((tmp2 * 256) & 0xFF00); // put together the real part and the imaginary part - d_map_base[4] = 0x0C000000 | (local_code & 0xFFFF); - } -} - - -void gps_fpga_acquisition_8sc::run_acquisition(void) -{ - // enable interrupts - int reenable = 1; - write(d_fd, reinterpret_cast(&reenable), sizeof(int)); - - d_map_base[5] = 0; // writing anything to reg 4 launches the acquisition process - - int irq_count; - ssize_t nb; - // wait for interrupt - nb = read(d_fd, &irq_count, sizeof(irq_count)); - if (nb != sizeof(irq_count)) - { - printf("Tracking_module Read failed to retrieve 4 bytes!\n"); - printf("Tracking_module Interrupt number %d\n", irq_count); - } -} - - -void gps_fpga_acquisition_8sc::configure_acquisition() -{ - d_map_base[0] = d_select_queue; - d_map_base[1] = d_vector_length; - d_map_base[2] = d_nsamples; -} - - -void gps_fpga_acquisition_8sc::set_phase_step(unsigned int doppler_index) -{ - float phase_step_rad_real; - float phase_step_rad_int_temp; - int32_t phase_step_rad_int; - - int doppler = static_cast(-d_doppler_max) + d_doppler_step * doppler_index; - float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); - // The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing - // The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi) - // The FPGA also expects the phase to be negative since it produces cos(x) -j*sin(x) - // while the gnss-sdr software (volk_gnsssdr_s32f_sincos_32fc) generates cos(x) + j*sin(x) - phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); - // avoid saturation of the fixed point representation in the fpga - // (only the positive value can saturate due to the 2's complement representation) - if (phase_step_rad_real == 1.0) - { - phase_step_rad_real = MAX_PHASE_STEP_RAD; - } - phase_step_rad_int_temp = phase_step_rad_real * 4; // * 2^2 - phase_step_rad_int = static_cast(phase_step_rad_int_temp * (536870912)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings - - d_map_base[3] = phase_step_rad_int; -} - - -void gps_fpga_acquisition_8sc::read_acquisition_results(uint32_t* max_index, - float* max_magnitude, unsigned* initial_sample, float* power_sum) -{ - unsigned readval = 0; - readval = d_map_base[0]; - readval = d_map_base[1]; - *initial_sample = readval; - readval = d_map_base[2]; - *max_magnitude = static_cast(readval); - readval = d_map_base[4]; - *power_sum = static_cast(readval); - readval = d_map_base[3]; - *max_index = readval; -} - - -void gps_fpga_acquisition_8sc::block_samples() -{ - d_map_base[14] = 1; // block the samples -} - - -void gps_fpga_acquisition_8sc::unblock_samples() -{ - d_map_base[14] = 0; // unblock the samples -} - - -void gps_fpga_acquisition_8sc::open_device() -{ - if ((d_fd = open(d_device_name.c_str(), O_RDWR | O_SYNC)) == -1) - { - LOG(WARNING) << "Cannot open deviceio" << d_device_name; - } - - d_map_base = reinterpret_cast(mmap(NULL, PAGE_SIZE, - PROT_READ | PROT_WRITE, MAP_SHARED, d_fd, 0)); - - if (d_map_base == reinterpret_cast(-1)) - { - LOG(WARNING) << "Cannot map the FPGA acquisition module into user memory"; - } - - // sanity check : check test register - // we only nee to do this when the class is created - // but the device is not opened yet when the class is create - // because we need to open and close the device every time we run an acquisition - // since the same device may be used by more than one class (gps acquisition, galileo - // acquisition, etc ..) - unsigned writeval = TEST_REGISTER_ACQ_WRITEVAL; - unsigned readval; - readval = gps_fpga_acquisition_8sc::fpga_acquisition_test_register(writeval); - - if (writeval != readval) - { - LOG(WARNING) << "Acquisition test register sanity check failed"; - } - else - { - LOG(INFO) << "Acquisition test register sanity check success !"; - } -} - - -void gps_fpga_acquisition_8sc::close_device() -{ - unsigned* aux = const_cast(d_map_base); - if (munmap(static_cast(aux), PAGE_SIZE) == -1) - { - printf("Failed to unmap memory uio\n"); - } - close(d_fd); -} diff --git a/src/algorithms/libs/CMakeLists.txt b/src/algorithms/libs/CMakeLists.txt index ac182801e..775ac6358 100644 --- a/src/algorithms/libs/CMakeLists.txt +++ b/src/algorithms/libs/CMakeLists.txt @@ -18,56 +18,81 @@ add_subdirectory(rtklib) -set(GNSS_SPLIBS_SOURCES - gps_l2c_signal.cc - gps_l5_signal.cc - galileo_e1_signal_processing.cc - gnss_sdr_valve.cc - gnss_sdr_sample_counter.cc - gnss_signal_processing.cc - gps_sdr_signal_processing.cc - glonass_l1_signal_processing.cc - glonass_l2_signal_processing.cc - pass_through.cc - galileo_e5_signal_processing.cc - complex_byte_to_float_x2.cc - byte_x2_to_complex_byte.cc - cshort_to_float_x2.cc - short_x2_to_cshort.cc - complex_float_to_complex_byte.cc - conjugate_cc.cc - conjugate_sc.cc - conjugate_ic.cc -) +if(ENABLE_FPGA) + set(GNSS_SPLIBS_SOURCES + gps_l2c_signal.cc + gps_l5_signal.cc + galileo_e1_signal_processing.cc + gnss_sdr_valve.cc + gnss_sdr_sample_counter.cc + gnss_sdr_time_counter.cc + gnss_signal_processing.cc + gps_sdr_signal_processing.cc + glonass_l1_signal_processing.cc + glonass_l2_signal_processing.cc + pass_through.cc + galileo_e5_signal_processing.cc + complex_byte_to_float_x2.cc + byte_x2_to_complex_byte.cc + cshort_to_float_x2.cc + short_x2_to_cshort.cc + complex_float_to_complex_byte.cc + conjugate_cc.cc + conjugate_sc.cc + conjugate_ic.cc + ) +else(ENABLE_FPGA) + set(GNSS_SPLIBS_SOURCES + gps_l2c_signal.cc + gps_l5_signal.cc + galileo_e1_signal_processing.cc + gnss_sdr_valve.cc + gnss_sdr_sample_counter.cc + gnss_signal_processing.cc + gps_sdr_signal_processing.cc + glonass_l1_signal_processing.cc + glonass_l2_signal_processing.cc + pass_through.cc + galileo_e5_signal_processing.cc + complex_byte_to_float_x2.cc + byte_x2_to_complex_byte.cc + cshort_to_float_x2.cc + short_x2_to_cshort.cc + complex_float_to_complex_byte.cc + conjugate_cc.cc + conjugate_sc.cc + conjugate_ic.cc + ) +endif(ENABLE_FPGA) if(OPENCL_FOUND) set(GNSS_SPLIBS_SOURCES ${GNSS_SPLIBS_SOURCES} - opencl/fft_execute.cc # Needs OpenCL - opencl/fft_setup.cc # Needs OpenCL - opencl/fft_kernelstring.cc # Needs OpenCL - ) + opencl/fft_execute.cc # Needs OpenCL + opencl/fft_setup.cc # Needs OpenCL + opencl/fft_kernelstring.cc # Needs OpenCL + ) endif(OPENCL_FOUND) include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/src/core/system_parameters - ${CMAKE_SOURCE_DIR}/src/core/receiver - ${CMAKE_SOURCE_DIR}/src/core/interfaces - ${Boost_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${GNURADIO_RUNTIME_INCLUDE_DIRS} - ${GNURADIO_BLOCKS_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} - ${VOLK_GNSSSDR_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/core/interfaces + ${Boost_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${GNURADIO_BLOCKS_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} + ${VOLK_GNSSSDR_INCLUDE_DIRS} ) if(OPENCL_FOUND) include_directories( ${OPENCL_INCLUDE_DIRS} ) if(OS_IS_MACOSX) - set(OPT_LIBRARIES ${OPT_LIBRARIES} "-framework OpenCL") + set(OPT_LIBRARIES ${OPT_LIBRARIES} "-framework OpenCL") else(OS_IS_MACOSX) - set(OPT_LIBRARIES ${OPT_LIBRARIES} ${OPENCL_LIBRARIES}) + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${OPENCL_LIBRARIES}) endif(OS_IS_MACOSX) endif(OPENCL_FOUND) @@ -80,14 +105,14 @@ add_library(gnss_sp_libs ${GNSS_SPLIBS_SOURCES} ${GNSS_SPLIBS_HEADERS}) source_group(Headers FILES ${GNSS_SPLIBS_HEADERS}) target_link_libraries(gnss_sp_libs ${GNURADIO_RUNTIME_LIBRARIES} - ${VOLK_LIBRARIES} ${ORC_LIBRARIES} - ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} - ${GFlags_LIBS} - ${GNURADIO_BLOCKS_LIBRARIES} - ${GNURADIO_FFT_LIBRARIES} - ${GNURADIO_FILTER_LIBRARIES} - ${OPT_LIBRARIES} - gnss_rx + ${VOLK_LIBRARIES} ${ORC_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} + ${GFlags_LIBS} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FFT_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${OPT_LIBRARIES} + gnss_rx ) if(NOT VOLK_GNSSSDR_FOUND) @@ -95,9 +120,9 @@ if(NOT VOLK_GNSSSDR_FOUND) endif(NOT VOLK_GNSSSDR_FOUND) if(${GFLAGS_GREATER_20}) - add_definitions(-DGFLAGS_GREATER_2_0=1) + add_definitions(-DGFLAGS_GREATER_2_0=1) endif(${GFLAGS_GREATER_20}) add_library(gnss_sdr_flags gnss_sdr_flags.cc gnss_sdr_flags.h) source_group(Headers FILES gnss_sdr_flags.h) -target_link_libraries(gnss_sdr_flags ${GFlags_LIBS}) \ No newline at end of file +target_link_libraries(gnss_sdr_flags ${GFlags_LIBS}) diff --git a/src/algorithms/libs/gnss_sdr_time_counter.cc b/src/algorithms/libs/gnss_sdr_time_counter.cc new file mode 100644 index 000000000..614501f36 --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_time_counter.cc @@ -0,0 +1,126 @@ +/*! + * \file gnss_sdr_time_counter.cc + * \brief Simple block to report the current receiver time based on the output of the tracking or telemetry blocks + * \author Antonio Ramos 2018. antonio.ramos(at)gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gnss_sdr_time_counter.h" +#include "gnss_synchro.h" +#include +#include +#include +#include + +gnss_sdr_time_counter::gnss_sdr_time_counter() : gr::block("time_counter", + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + set_max_noutput_items(1); + current_T_rx_ms = 0; + current_s = 0; + current_m = 0; + current_h = 0; + current_days = 0; + report_interval_ms = 1000; // default reporting 1 second + flag_m = false; + flag_h = false; + flag_days = false; +} + + +gnss_sdr_time_counter_sptr gnss_sdr_make_time_counter() +{ + gnss_sdr_time_counter_sptr counter_(new gnss_sdr_time_counter()); + return counter_; +} + + +int gnss_sdr_time_counter::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items __attribute__((unused)), gr_vector_void_star &output_items) +{ + Gnss_Synchro *out = reinterpret_cast(output_items[0]); + const Gnss_Synchro *in = reinterpret_cast(input_items[0]); + out[0] = in[0]; + if ((current_T_rx_ms % report_interval_ms) == 0) + { + current_s++; + if ((current_s % 60) == 0) + { + current_s = 0; + current_m++; + flag_m = true; + if ((current_m % 60) == 0) + { + current_m = 0; + current_h++; + flag_h = true; + if ((current_h % 24) == 0) + { + current_h = 0; + current_days++; + flag_days = true; + } + } + } + + if (flag_days) + { + std::string day; + if (current_days == 1) + { + day = " day "; + } + else + { + day = " days "; + } + std::cout << "Current receiver time: " << current_days << day << current_h << " h " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + if (flag_h) + { + std::cout << "Current receiver time: " << current_h << " h " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + if (flag_m) + { + std::cout << "Current receiver time: " << current_m << " min " << current_s << " s" << std::endl; + } + else + { + std::cout << "Current receiver time: " << current_s << " s" << std::endl; + } + } + } + } + current_T_rx_ms++; + consume_each(1); + return 1; +} diff --git a/src/algorithms/libs/gnss_sdr_time_counter.h b/src/algorithms/libs/gnss_sdr_time_counter.h new file mode 100644 index 000000000..4a424ce12 --- /dev/null +++ b/src/algorithms/libs/gnss_sdr_time_counter.h @@ -0,0 +1,64 @@ +/*! + * \file gnss_sdr_time_counter.h + * \brief Simple block to report the current receiver time based on the output of the tracking or telemetry blocks + * \author Antonio Ramos 2018. antonio.ramosdet(at)gmail.com + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ +#ifndef GNSS_SDR_TIME_COUNTER_H_ +#define GNSS_SDR_TIME_COUNTER_H_ + +#include +#include + + +class gnss_sdr_time_counter; + +typedef boost::shared_ptr gnss_sdr_time_counter_sptr; + +gnss_sdr_time_counter_sptr gnss_sdr_make_time_counter(); + +class gnss_sdr_time_counter : public gr::block +{ +private: + gnss_sdr_time_counter(); + long long int current_T_rx_ms; // Receiver time in ms since the beginning of the run + unsigned int current_s; // Receiver time in seconds, modulo 60 + bool flag_m; // True if the receiver has been running for at least 1 minute + unsigned int current_m; // Receiver time in minutes, modulo 60 + bool flag_h; // True if the receiver has been running for at least 1 hour + unsigned int current_h; // Receiver time in hours, modulo 24 + bool flag_days; // True if the receiver has been running for at least 1 day + unsigned int current_days; // Receiver time in days since the beginning of the run + int report_interval_ms; + +public: + friend gnss_sdr_time_counter_sptr gnss_sdr_make_time_counter(); + int general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items __attribute__((unused)), gr_vector_void_star &output_items); +}; + +#endif /*GNSS_SDR_SAMPLE_COUNTER_H_*/ diff --git a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.cc b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.cc index 06f0efdcd..159d5f1fb 100644 --- a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.cc +++ b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_cc.cc @@ -64,7 +64,7 @@ hybrid_observables_cc::hybrid_observables_cc(unsigned int nchannels_in, T_rx_s = 0.0; T_rx_step_s = 0.001; // 1 ms max_delta = 1.5; // 1.5 s - d_latency = 0.3; // 300 ms + d_latency = 0.5; // 300 ms valid_channels.resize(d_nchannels, false); d_num_valid_channels = 0; d_gnss_synchro_history = new Gnss_circular_deque(static_cast(max_delta * 1000.0), d_nchannels); diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index 2fb8f4be8..ededc5dc7 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -35,6 +35,20 @@ if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${IIO_INCLUDE_DIRS}) endif(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) +if(ENABLE_AD9361) + find_package(libiio REQUIRED) + if(NOT LIBIIO_FOUND) + message(STATUS "gnuradio-iio not found, its installation is required.") + message(STATUS "Please build and install the following projects:") + message(STATUS " * libiio from https://github.com/analogdevicesinc/libiio") + message(STATUS " * libad9361-iio from https://github.com/analogdevicesinc/libad9361-iio") + message(STATUS " * gnuradio-iio from https://github.com/analogdevicesinc/gr-iio") + message(FATAL_ERROR "gnuradio-iio required for building gnss-sdr with this option enabled") + endif(NOT LIBIIO_FOUND) + set(OPT_LIBRARIES ${OPT_LIBRARIES} ${LIBIIO_LIBRARIES}) + set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${LIBIIO_INCLUDE_DIRS}) +endif(ENABLE_AD9361) + if(ENABLE_PLUTOSDR) ############################################## @@ -55,6 +69,16 @@ if(ENABLE_FMCOMMS2) endif(IIO_FOUND) endif(ENABLE_FMCOMMS2) +if(ENABLE_AD9361) + ############################################### + # AD9361 DIRECT TO FPGA Hardware + ############################################### + if(LIBIIO_FOUND) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad9361_fpga_signal_source.cc) + endif(LIBIIO_FOUND) +endif(ENABLE_AD9361) + + if(ENABLE_GN3S) ############################################## diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc new file mode 100644 index 000000000..cba4e5439 --- /dev/null +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc @@ -0,0 +1,160 @@ +/*! + * \file ad9361_fpga_signal_source.cc + * \brief signal source for Analog Devices front-end AD9361 connected directly to FPGA accelerators. + * This source implements only the AD9361 control. It is NOT compatible with conventional SDR acquisition and tracking blocks. + * Please use the fmcomms2 source if conventional SDR acquisition and tracking is selected in the configuration file. + * \author Javier Arribas, jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "ad9361_fpga_signal_source.h" +#include "configuration_interface.h" +#include "ad9361_manager.h" +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" +#include +#include +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(ConfigurationInterface* configuration, + std::string role, unsigned int in_stream, unsigned int out_stream, + boost::shared_ptr queue) : + role_(role), in_stream_(in_stream), out_stream_(out_stream), + queue_(queue) +{ + std::string default_item_type = "gr_complex"; + std::string default_dump_file = "./data/signal_source.dat"; + freq_ = configuration->property(role + ".freq", GPS_L1_FREQ_HZ); + sample_rate_ = configuration->property(role + ".sampling_frequency", 2600000); + bandwidth_ = configuration->property(role + ".bandwidth", 2000000); + rx1_en_ = configuration->property(role + ".rx1_enable", true); + rx2_en_ = configuration->property(role + ".rx2_enable", false); + buffer_size_ = configuration->property(role + ".buffer_size", 0xA0000); + quadrature_ = configuration->property(role + ".quadrature", true); + rf_dc_ = configuration->property(role + ".rf_dc", true); + bb_dc_ = configuration->property(role + ".bb_dc", true); + gain_mode_rx1_ = configuration->property(role + ".gain_mode_rx1", std::string("manual")); + gain_mode_rx2_ = configuration->property(role + ".gain_mode_rx2", std::string("manual")); + rf_gain_rx1_ = configuration->property(role + ".gain_rx1", 64.0); + rf_gain_rx2_ = configuration->property(role + ".gain_rx2", 64.0); + rf_port_select_ = configuration->property(role + ".rf_port_select", std::string("A_BALANCED")); + filter_file_ = configuration->property(role + ".filter_file", std::string("")); + filter_auto_ = configuration->property(role + ".filter_auto", true); + item_type_ = configuration->property(role + ".item_type", default_item_type); + samples_ = configuration->property(role + ".samples", 0); + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", default_dump_file); + + enable_dds_lo_=configuration->property(role + ".enable_dds_lo", false); + freq_rf_tx_hz_=configuration->property(role + ".freq_rf_tx_hz", GPS_L1_FREQ_HZ-GPS_L2_FREQ_HZ-1000); + freq_dds_tx_hz_=configuration->property(role + ".freq_dds_tx_hz", 1000); + scale_dds_dbfs_=configuration->property(role + ".scale_dds_dbfs", -3.0); + phase_dds_deg_=configuration->property(role + ".phase_dds_deg", 0.0); + tx_attenuation_db_=configuration->property(role + ".tx_attenuation_db", 0.0); + + item_size_ = sizeof(gr_complex); + + std::cout << "device address: " << uri_ << std::endl; + std::cout << "LO frequency : " << freq_ << " Hz" << std::endl; + std::cout << "sample rate: " << sample_rate_ << " Hz" << std::endl; + + config_ad9361_rx_local(bandwidth_, + sample_rate_, + freq_, + rf_port_select_, + gain_mode_rx1_, + gain_mode_rx2_, + rf_gain_rx1_, + rf_gain_rx2_); + + //LOCAL OSCILLATOR DDS GENERATOR FOR DUAL FREQUENCY OPERATION + if (enable_dds_lo_==true) + { + config_ad9361_lo_local(bandwidth_, + sample_rate_, + freq_rf_tx_hz_, + tx_attenuation_db_, + freq_dds_tx_hz_, + scale_dds_dbfs_); + } + + // turn switch to A/D position + std::string default_device_name = "/dev/uio13"; + std::string device_name = configuration->property(role + ".devicename", default_device_name); + int switch_position = configuration->property(role + ".switch_position", 0); + switch_fpga = std::make_shared (device_name); + switch_fpga->set_switch_position(switch_position); +} + + +Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource() +{ + /* cleanup and exit */ + //std::cout<<"* AD9361 Disabling streaming channels\n"; + //if (rx0_i) { iio_channel_disable(rx0_i); } + //if (rx0_q) { iio_channel_disable(rx0_q); } + + if (enable_dds_lo_) + { + ad9361_disable_lo_local(); + } + + // std::cout<<"* AD9361 Destroying context\n"; + //if (ctx) { iio_context_destroy(ctx); } +} + + +void Ad9361FpgaSignalSource::connect(gr::top_block_sptr top_block) +{ + DLOG(INFO) << "AD9361 FPGA source nothing to connect"; +} + + +void Ad9361FpgaSignalSource::disconnect(gr::top_block_sptr top_block) +{ + DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; +} + + +gr::basic_block_sptr Ad9361FpgaSignalSource::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return gr::basic_block_sptr(); +} + + +gr::basic_block_sptr Ad9361FpgaSignalSource::get_right_block() +{ + LOG(WARNING) << "Trying to get AD9361 FPGA signal source right block."; + return gr::basic_block_sptr(); +} diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h new file mode 100644 index 000000000..6110a63c3 --- /dev/null +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h @@ -0,0 +1,120 @@ +/*! + * \file ad9361_fpga_signal_source.h + * \brief signal source for Analog Devices front-end AD9361 connected directly to FPGA accelerators. + * This source implements only the AD9361 control. It is NOT compatible with conventional SDR acquisition and tracking blocks. + * Please use the fmcomms2 source if conventional SDR acquisition and tracking is selected in the configuration file. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H_ +#define GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H_ + +#include "gnss_block_interface.h" +#include "fpga_switch.h" + +#include +#include +#include + +class ConfigurationInterface; + +class Ad9361FpgaSignalSource: public GNSSBlockInterface +{ +public: + Ad9361FpgaSignalSource(ConfigurationInterface* configuration, + std::string role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue); + + virtual ~Ad9361FpgaSignalSource(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "Ad9361_Fpga_Signal_Source" + */ + inline std::string implementation() override + { + return "Ad9361_Fpga_Signal_Source"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + std::string role_; + + // Front-end settings + std::string uri_;//device direction + unsigned long freq_; //frequency of local oscilator + unsigned long sample_rate_; + unsigned long bandwidth_; + unsigned long buffer_size_; //reception buffer + bool rx1_en_; + bool rx2_en_; + bool quadrature_; + bool rf_dc_; + bool bb_dc_; + std::string gain_mode_rx1_; + std::string gain_mode_rx2_; + double rf_gain_rx1_; + double rf_gain_rx2_; + std::string rf_port_select_; + std::string filter_file_; + bool filter_auto_; + + //DDS configuration for LO generation for external mixer + bool enable_dds_lo_; + unsigned long freq_rf_tx_hz_; + unsigned long freq_dds_tx_hz_; + double scale_dds_dbfs_; + double phase_dds_deg_; + double tx_attenuation_db_; + + unsigned int in_stream_; + unsigned int out_stream_; + + std::string item_type_; + size_t item_size_; + long samples_; + bool dump_; + std::string dump_filename_; + + boost::shared_ptr queue_; + + std::shared_ptr switch_fpga; +}; + +#endif /*GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H_*/ diff --git a/src/algorithms/signal_source/libs/CMakeLists.txt b/src/algorithms/signal_source/libs/CMakeLists.txt index 5a35a7992..c8f676b49 100644 --- a/src/algorithms/signal_source/libs/CMakeLists.txt +++ b/src/algorithms/signal_source/libs/CMakeLists.txt @@ -28,7 +28,10 @@ if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) endif(NOT IIO_FOUND) set(OPT_LIBRARIES ${OPT_LIBRARIES} ${IIO_LIBRARIES}) set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${IIO_INCLUDE_DIRS}) - + +endif(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) + +if(ENABLE_FMCOMMS2 OR ENABLE_AD9361) find_package(libiio REQUIRED) if(NOT LIBIIO_FOUND) message(STATUS "gnuradio-iio not found, its installation is required.") @@ -40,37 +43,38 @@ if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) endif(NOT LIBIIO_FOUND) set(OPT_LIBRARIES ${OPT_LIBRARIES} ${LIBIIO_LIBRARIES}) set(OPT_DRIVER_INCLUDE_DIRS ${OPT_DRIVER_INCLUDE_DIRS} ${LIBIIO_INCLUDE_DIRS}) - -endif(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) -if(ENABLE_FMCOMMS2) - ############################################### + ############################################### # FMCOMMS2 based SDR Hardware ############################################### if(IIO_FOUND) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ad9361_manager.cc) endif(IIO_FOUND) -endif(ENABLE_FMCOMMS2) + +endif(ENABLE_FMCOMMS2 OR ENABLE_AD9361) + +if(ENABLE_AD9361) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ad9361_manager.cc) +endif(ENABLE_AD9361) + +if(ENABLE_FPGA) + SET(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_switch.cc) +endif(ENABLE_FPGA) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${Boost_INCLUDE_DIRS} + ${OPT_DRIVER_INCLUDE_DIRS} +) set (SIGNAL_SOURCE_LIB_SOURCES rtl_tcp_commands.cc rtl_tcp_dongle_info.cc ${OPT_SIGNAL_SOURCE_LIB_SOURCES}) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${Boost_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} - ${GFlags_INCLUDE_DIRS} - ${OPT_DRIVER_INCLUDE_DIRS} -) - - file(GLOB SIGNAL_SOURCE_LIB_HEADERS "*.h") list(SORT SIGNAL_SOURCE_LIB_HEADERS) -list(SORT SIGNAL_SOURCE_LIB_SOURCES) add_library(signal_source_lib ${SIGNAL_SOURCE_LIB_SOURCES} ${SIGNAL_SOURCE_LIB_HEADERS}) source_group(Headers FILES ${SIGNAL_SOURCE_LIB_HEADERS}) -add_dependencies(signal_source_lib glog-${glog_RELEASE}) -target_link_libraries(signal_source_lib ${OPT_LIBRARIES}) +target_link_libraries(signal_source_lib ${OPT_LIBRARIES}) diff --git a/src/algorithms/signal_source/libs/fpga_switch.cc b/src/algorithms/signal_source/libs/fpga_switch.cc new file mode 100644 index 000000000..aae7da979 --- /dev/null +++ b/src/algorithms/signal_source/libs/fpga_switch.cc @@ -0,0 +1,137 @@ +/*! + * \file fpga_switch.cc + * \brief Switch that connects the HW accelerator queues to the analog front end or the DMA. + * \authors
    + *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Javier Arribas, 2015. jarribas(at)cttc.es + *
+ * + * Class that controls a switch in the FPGA + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "fpga_switch.h" +#include + +// FPGA stuff +#include + +// libraries used by DMA test code and GIPO test code +#include +#include +#include +#include + +// libraries used by DMA test code +#include +#include +#include +#include + +// libraries used by GPIO test code +#include +#include +#include + +// logging +#include + +// string manipulation +#include + +// constants +#define PAGE_SIZE 0x10000 +#define TEST_REGISTER_TRACK_WRITEVAL 0x55AA + +fpga_switch::fpga_switch(std::string device_name) +{ + if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" << device_name; + printf("switch memory successfully mapped\n"); + } + d_map_base = reinterpret_cast(mmap(NULL, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0)); + + if (d_map_base == reinterpret_cast(-1)) + { + LOG(WARNING) << "Cannot map the FPGA switch module into tracking memory"; + printf("could not map switch memory\n"); + } + + // sanity check : check test register + unsigned writeval = TEST_REGISTER_TRACK_WRITEVAL; + unsigned readval; + readval = fpga_switch::fpga_switch_test_register(writeval); + if (writeval != readval) + { + LOG(WARNING) << "Test register sanity check failed"; + } + else + { + LOG(INFO) << "Test register sanity check success !"; + } + + DLOG(INFO) << "Switch FPGA class created"; +} + + +fpga_switch::~fpga_switch() +{ + close_device(); +} + + +void fpga_switch::set_switch_position(int switch_position) +{ + d_map_base[0] = switch_position; +} + + +unsigned fpga_switch::fpga_switch_test_register( + unsigned writeval) +{ + unsigned readval; + // write value to test register + d_map_base[3] = writeval; + // read value from test register + readval = d_map_base[3]; + // return read value + return readval; +} + + +void fpga_switch::close_device() +{ + unsigned *aux = const_cast(d_map_base); + if (munmap(static_cast(aux), PAGE_SIZE) == -1) + { + printf("Failed to unmap memory uio\n"); + } + + close(d_device_descriptor); +} diff --git a/src/algorithms/signal_source/libs/fpga_switch.h b/src/algorithms/signal_source/libs/fpga_switch.h new file mode 100644 index 000000000..395aff425 --- /dev/null +++ b/src/algorithms/signal_source/libs/fpga_switch.h @@ -0,0 +1,60 @@ +/*! + * \file fpga_switch.h + * \brief Switch that connects the HW accelerator queues to the analog front end or the DMA. + * \authors
    + *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Javier Arribas, 2016. jarribas(at)cttc.es + *
+ * + * Class that controls a switch in the FPGA + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_FPGA_SWITCH_H_ +#define GNSS_SDR_FPGA_SWITCH_H_ + +#include + +#define MAX_LENGTH_DEVICEIO_NAME 50 + +class fpga_switch +{ +public: + fpga_switch(std::string device_name); + ~fpga_switch(); + void set_switch_position(int switch_position); + +private: + int d_device_descriptor; // driver descriptor + volatile unsigned *d_map_base; // driver memory map + + // private functions + unsigned fpga_switch_test_register(unsigned writeval); + void close_device(void); +}; + +#endif /* GNSS_SDR_FPGA_SWITCH_H_ */ diff --git a/src/algorithms/tracking/adapters/CMakeLists.txt b/src/algorithms/tracking/adapters/CMakeLists.txt index 044e3287a..6b60f35b1 100644 --- a/src/algorithms/tracking/adapters/CMakeLists.txt +++ b/src/algorithms/tracking/adapters/CMakeLists.txt @@ -22,7 +22,7 @@ if(ENABLE_CUDA) endif(ENABLE_CUDA) if(ENABLE_FPGA) - SET(OPT_TRACKING_ADAPTERS ${OPT_TRACKING_ADAPTERS} gps_l1_ca_dll_pll_c_aid_tracking_fpga.cc) + SET(OPT_TRACKING_ADAPTERS ${OPT_TRACKING_ADAPTERS} gps_l1_ca_dll_pll_tracking_fpga.cc) endif(ENABLE_FPGA) set(TRACKING_ADAPTER_SOURCES diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking_fpga.cc b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking_fpga.cc deleted file mode 100644 index 8f6f5972c..000000000 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking_fpga.cc +++ /dev/null @@ -1,225 +0,0 @@ -/*! - * \file gps_l1_ca_dll_pll_c_aid_tracking_fpga.cc - * \brief Implementation of an adapter of a DLL+PLL tracking loop block - * for GPS L1 C/A to a TrackingInterface - * \author Marc Majoral, 2017. mmajoral(at)cttc.cat - * Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com - * Javier Arribas, 2011. jarribas(at)cttc.es - * - * Code DLL + carrier PLL according to the algorithms described in: - * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * A Software-Defined GPS and Galileo Receiver. A Single-Frequency - * Approach, Birkhauser, 2007 - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR 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. - * - * GNSS-SDR 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 GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "gps_l1_ca_dll_pll_c_aid_tracking_fpga.h" -#include -#include "GPS_L1_CA.h" -#include "configuration_interface.h" -#include "gnss_sdr_flags.h" - - -using google::LogMessage; - -GpsL1CaDllPllCAidTrackingFpga::GpsL1CaDllPllCAidTrackingFpga( - ConfigurationInterface* configuration, std::string role, - unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) -{ - DLOG(INFO) << "role " << role; - //################# CONFIGURATION PARAMETERS ######################## - int fs_in; - int vector_length; - int f_if; - bool dump; - std::string dump_filename; - std::string default_item_type = "cshort"; - float pll_bw_hz; - float pll_bw_narrow_hz; - float dll_bw_hz; - float dll_bw_narrow_hz; - float early_late_space_chips; - std::string device_name; - unsigned int device_base; - - item_type_ = configuration->property(role + ".item_type", default_item_type); - int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); - f_if = configuration->property(role + ".if", 0); - dump = configuration->property(role + ".dump", false); - pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); - if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast(FLAGS_pll_bw_hz); - dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); - if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast(FLAGS_dll_bw_hz); - pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 20.0); - dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0); - int extend_correlation_ms; - extend_correlation_ms = configuration->property(role + ".extend_correlation_ms", 1); - - early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); - std::string default_dump_filename = "./track_ch"; - dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); - std::string default_device_name = "/dev/uio"; - device_name = configuration->property(role + ".devicename", default_device_name); - device_base = configuration->property(role + ".device_base", 1); - vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); - - //################# MAKE TRACKING GNURadio object ################### - - if (item_type_.compare("cshort") == 0) - { - item_size_ = sizeof(lv_16sc_t); - tracking_fpga_sc = gps_l1_ca_dll_pll_c_aid_make_tracking_fpga_sc( - f_if, fs_in, vector_length, dump, dump_filename, pll_bw_hz, - dll_bw_hz, pll_bw_narrow_hz, dll_bw_narrow_hz, - extend_correlation_ms, early_late_space_chips, device_name, - device_base); - DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() << ")"; - } - else - { - item_size_ = sizeof(lv_16sc_t); - // LOG(WARNING) << item_type_ << " unknown tracking item type"; - LOG(WARNING) << item_type_ - << " the tracking item type for the FPGA tracking test has to be cshort"; - } - - channel_ = 0; -} - - -GpsL1CaDllPllCAidTrackingFpga::~GpsL1CaDllPllCAidTrackingFpga() -{ - LOG(INFO) << "gspl1cadllpllcaidtrackingfpga destructor called"; -} - - -void GpsL1CaDllPllCAidTrackingFpga::start_tracking() -{ - if (item_type_.compare("cshort") == 0) - { - tracking_fpga_sc->start_tracking(); - } - else - { - // LOG(WARNING) << item_type_ << " unknown tracking item type"; - LOG(WARNING) << item_type_ - << " the tracking item type for the FPGA tracking test has to be cshort"; - } -} - - -/* - * Set tracking channel unique ID - */ -void GpsL1CaDllPllCAidTrackingFpga::set_channel(unsigned int channel) -{ - channel_ = channel; - - if (item_type_.compare("cshort") == 0) - { - tracking_fpga_sc->set_channel(channel); - } - else - { - // LOG(WARNING) << item_type_ << " unknown tracking item type"; - LOG(WARNING) << item_type_ - << " the tracking item type for the FPGA tracking test has to be cshort"; - } -} - - -void GpsL1CaDllPllCAidTrackingFpga::set_gnss_synchro( - Gnss_Synchro* p_gnss_synchro) -{ - if (item_type_.compare("cshort") == 0) - { - tracking_fpga_sc->set_gnss_synchro(p_gnss_synchro); - } - else - { - // LOG(WARNING) << item_type_ << " unknown tracking item type"; - LOG(WARNING) << item_type_ - << " the tracking item type for the FPGA tracking test has to be cshort"; - } -} - - -void GpsL1CaDllPllCAidTrackingFpga::connect(gr::top_block_sptr top_block) -{ - if (top_block) - { /* top_block is not null */ - }; - //nothing to connect, now the tracking uses gr_sync_decimator -} - - -void GpsL1CaDllPllCAidTrackingFpga::disconnect(gr::top_block_sptr top_block) -{ - if (top_block) - { /* top_block is not null */ - }; - //nothing to disconnect, now the tracking uses gr_sync_decimator -} - - -// CONVERT TO SOURCE -gr::basic_block_sptr GpsL1CaDllPllCAidTrackingFpga::get_left_block() -{ - if (item_type_.compare("cshort") == 0) - { - return tracking_fpga_sc; - } - else - { - //LOG(WARNING) << item_type_ << " unknown tracking item type"; - LOG(WARNING) << item_type_ - << " the tracking item type for the FPGA tracking test has to be cshort"; - return nullptr; - } -} - - -gr::basic_block_sptr GpsL1CaDllPllCAidTrackingFpga::get_right_block() -{ - if (item_type_.compare("cshort") == 0) - { - return tracking_fpga_sc; - } - else - { - //LOG(WARNING) << item_type_ << " unknown tracking item type"; - LOG(WARNING) << item_type_ - << " the tracking item type for the FPGA tracking test has to be cshort"; - return nullptr; - } -} - - -void GpsL1CaDllPllCAidTrackingFpga::reset(void) -{ - tracking_fpga_sc->reset(); -} diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc new file mode 100644 index 000000000..77f667407 --- /dev/null +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc @@ -0,0 +1,162 @@ +/*! + * \file gps_l1_ca_dll_pll_tracking.cc + * \brief Implementation of an adapter of a DLL+PLL tracking loop block + * for GPS L1 C/A to a TrackingInterface + * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com + * Javier Arribas, 2011. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "gps_l1_ca_dll_pll_tracking_fpga.h" +#include "configuration_interface.h" +#include "GPS_L1_CA.h" +#include + + +using google::LogMessage; + +GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga( + ConfigurationInterface* configuration, std::string role, + unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) +{ + DLOG(INFO) << "role " << role; + //################# CONFIGURATION PARAMETERS ######################## + int fs_in; + int vector_length; + int f_if; + bool dump; + std::string dump_filename; + std::string item_type; + //std::string default_item_type = "gr_complex"; + std::string default_item_type = "cshort"; + float pll_bw_hz; + float dll_bw_hz; + float early_late_space_chips; + item_type = configuration->property(role + ".item_type", default_item_type); + int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + std::string device_name; + unsigned int device_base; + std::string default_device_name = "/dev/uio"; + device_name = configuration->property(role + ".devicename", default_device_name); + device_base = configuration->property(role + ".device_base", 1); + fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + f_if = configuration->property(role + ".if", 0); + dump = configuration->property(role + ".dump", false); + pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0); + dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0); + early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); + std::string default_dump_filename = "./track_ch"; + dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); //unused! + vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + if (item_type.compare("cshort") == 0) + { + item_size_ = sizeof(lv_16sc_t); + tracking_fpga_sc = gps_l1_ca_dll_pll_make_tracking_fpga_sc( + f_if, fs_in, vector_length, dump, dump_filename, pll_bw_hz, + dll_bw_hz, early_late_space_chips, device_name, + device_base); + DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() + << ")"; + } + else + { + item_size_ = sizeof(lv_16sc_t); + // LOG(WARNING) << item_type_ << " unknown tracking item type"; + LOG(WARNING) << item_type + << " the tracking item type for the FPGA tracking test has to be cshort"; + } + channel_ = 0; + DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() << ")"; +} + + +GpsL1CaDllPllTrackingFpga::~GpsL1CaDllPllTrackingFpga() +{ +} + + +void GpsL1CaDllPllTrackingFpga::start_tracking() +{ + tracking_fpga_sc->start_tracking(); +} + + +/* + * Set tracking channel unique ID + */ +void GpsL1CaDllPllTrackingFpga::set_channel(unsigned int channel) +{ + channel_ = channel; + tracking_fpga_sc->set_channel(channel); +} + + +void GpsL1CaDllPllTrackingFpga::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) +{ + tracking_fpga_sc->set_gnss_synchro(p_gnss_synchro); +} + + +void GpsL1CaDllPllTrackingFpga::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to connect, now the tracking uses gr_sync_decimator +} + + +void GpsL1CaDllPllTrackingFpga::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + //nothing to disconnect, now the tracking uses gr_sync_decimator +} + + +gr::basic_block_sptr GpsL1CaDllPllTrackingFpga::get_left_block() +{ + return tracking_fpga_sc; +} + + +gr::basic_block_sptr GpsL1CaDllPllTrackingFpga::get_right_block() +{ + return tracking_fpga_sc; +} + + +void GpsL1CaDllPllTrackingFpga::reset(void) +{ + // tracking_fpga_sc->reset(); +} diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h similarity index 73% rename from src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking_fpga.h rename to src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h index e61c7c57b..0abb88220 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_c_aid_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h @@ -1,9 +1,8 @@ /*! - * \file gps_l1_ca_dll_pll_c_aid_tracking_fpga.h + * \file gps_l1_ca_dll_pll_tracking.h * \brief Interface of an adapter of a DLL+PLL tracking loop block * for GPS L1 C/A to a TrackingInterface - * \author Marc Majoral, 2017. mmajoral(at)cttc.cat - * Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com + * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * Javier Arribas, 2011. jarribas(at)cttc.es * * Code DLL + carrier PLL according to the algorithms described in: @@ -13,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -36,36 +35,38 @@ * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_FPGA__H_ -#define GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_FPGA__H_ +#ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_H_ +#define GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_H_ + -#include #include "tracking_interface.h" -#include "gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc.h" +#include "gps_l1_ca_dll_pll_tracking_fpga_sc.h" +#include class ConfigurationInterface; /*! * \brief This class implements a code DLL + carrier PLL tracking loop */ -class GpsL1CaDllPllCAidTrackingFpga : public TrackingInterface +class GpsL1CaDllPllTrackingFpga : public TrackingInterface { public: - GpsL1CaDllPllCAidTrackingFpga(ConfigurationInterface* configuration, - std::string role, unsigned int in_streams, + GpsL1CaDllPllTrackingFpga(ConfigurationInterface* configuration, + std::string role, + unsigned int in_streams, unsigned int out_streams); - virtual ~GpsL1CaDllPllCAidTrackingFpga(); + virtual ~GpsL1CaDllPllTrackingFpga(); inline std::string role() override { return role_; } - //! Returns "GPS_L1_CA_DLL_PLL_C_Aid_Tracking_Fpga" + //! Returns "GPS_L1_CA_DLL_PLL_Tracking_Fpga" inline std::string implementation() override { - return "GPS_L1_CA_DLL_PLL_C_Aid_Tracking_Fpga"; + return "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; } inline size_t item_size() override @@ -75,7 +76,6 @@ public: void connect(gr::top_block_sptr top_block) override; void disconnect(gr::top_block_sptr top_block) override; - // CONVERT TO SOURCE gr::basic_block_sptr get_left_block() override; gr::basic_block_sptr get_right_block() override; @@ -95,13 +95,13 @@ public: void reset(void); private: - gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc_sptr tracking_fpga_sc; + //gps_l1_ca_dll_pll_tracking_cc_sptr tracking_; + gps_l1_ca_dll_pll_tracking_fpga_sc_sptr tracking_fpga_sc; size_t item_size_; - std::string item_type_; unsigned int channel_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; }; -#endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_FPGA__H_ +#endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_H_ diff --git a/src/algorithms/tracking/gnuradio_blocks/CMakeLists.txt b/src/algorithms/tracking/gnuradio_blocks/CMakeLists.txt index 535a38663..4cb869a79 100644 --- a/src/algorithms/tracking/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/tracking/gnuradio_blocks/CMakeLists.txt @@ -23,7 +23,7 @@ if(ENABLE_CUDA) endif(ENABLE_CUDA) if(ENABLE_FPGA) - set(OPT_TRACKING_BLOCKS ${OPT_TRACKING_BLOCKS} gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc.cc) + set(OPT_TRACKING_BLOCKS ${OPT_TRACKING_BLOCKS} gps_l1_ca_dll_pll_tracking_fpga_sc.cc) endif(ENABLE_FPGA) set(TRACKING_GR_BLOCKS_SOURCES diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_fpga_sc.cc b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_fpga_sc.cc new file mode 100644 index 000000000..30a99b5d5 --- /dev/null +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_fpga_sc.cc @@ -0,0 +1,540 @@ +/*! + * \file gps_l1_ca_dll_pll_tracking_cc.cc + * \brief Implementation of a code DLL + carrier PLL tracking block + * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com + * Javier Arribas, 2011. jarribas(at)cttc.es + * + * Code DLL + carrier PLL according to the algorithms described in: + * [1] K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, + * A Software-Defined GPS and Galileo Receiver. A Single-Frequency + * Approach, Birkhauser, 2007 + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gps_l1_ca_dll_pll_tracking_fpga_sc.h" +#include "control_message_factory.h" +#include "gnss_sdr_flags.h" +#include "GPS_L1_CA.h" +#include "gps_sdr_signal_processing.h" +#include "lock_detectors.h" +#include "tracking_discriminators.h" +#include +#include +#include +#include +#include +#include +#include + + +using google::LogMessage; + +gps_l1_ca_dll_pll_tracking_fpga_sc_sptr +gps_l1_ca_dll_pll_make_tracking_fpga_sc( + long if_freq, + long fs_in, + unsigned int vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips, + std::string device_name, + unsigned int device_base) +{ + return gps_l1_ca_dll_pll_tracking_fpga_sc_sptr(new Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc(if_freq, + fs_in, vector_length, dump, dump_filename, pll_bw_hz, dll_bw_hz, early_late_space_chips, device_name, device_base)); +} + + +Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc::Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc( + long if_freq, + long fs_in, + unsigned int vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips, + std::string device_name, + unsigned int device_base) : gr::block("Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc", gr::io_signature::make(0, 0, sizeof(lv_16sc_t)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Telemetry bit synchronization message port input + this->message_port_register_out(pmt::mp("events")); + + // initialize internal vars + d_dump = dump; + d_if_freq = if_freq; + d_fs_in = fs_in; + d_vector_length = vector_length; + d_dump_filename = dump_filename; + d_current_prn_length_samples = static_cast(d_vector_length); + d_correlation_length_samples = static_cast(d_vector_length); + + // Initialize tracking ========================================== + d_code_loop_filter.set_DLL_BW(dll_bw_hz); + d_carrier_loop_filter.set_PLL_BW(pll_bw_hz); + + //--- DLL variables -------------------------------------------------------- + d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips) + + // Initialization of local code replica + // Get space for a vector with the C/A code replica sampled 1x/chip + //d_ca_code = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(float), volk_gnsssdr_get_alignment())); + //d_ca_code_16sc = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment())); + //d_ca_code_16sc = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(int), volk_gnsssdr_get_alignment())); + + // correlator outputs (scalar) + d_n_correlator_taps = 3; // Early, Prompt, and Late + d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + for (int n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); + + // Set TAPs delay values [chips] + d_local_code_shift_chips[0] = -d_early_late_spc_chips; + d_local_code_shift_chips[1] = 0.0; + d_local_code_shift_chips[2] = d_early_late_spc_chips; + + // create multicorrelator class + multicorrelator_fpga_8sc = std::make_shared(d_n_correlator_taps, device_name, device_base); + + //--- Perform initializations ------------------------------ + // define initial code frequency basis of NCO + d_code_freq_chips = GPS_L1_CA_CODE_RATE_HZ; + // define residual code phase (in chips) + d_rem_code_phase_samples = 0.0; + // define residual carrier phase + d_rem_carr_phase_rad = 0.0; + + // sample synchronization + d_sample_counter = 0; + d_acq_sample_stamp = 0; + + d_enable_tracking = false; + d_pull_in = false; + + // CN0 estimation and lock detector buffers + d_cn0_estimation_counter = 0; + d_Prompt_buffer = new gr_complex[FLAGS_cn0_samples]; + d_carrier_lock_test = 1; + d_CN0_SNV_dB_Hz = 0; + d_carrier_lock_fail_counter = 0; + d_carrier_lock_threshold = FLAGS_carrier_lock_th; + + systemName["G"] = std::string("GPS"); + systemName["S"] = std::string("SBAS"); + + d_acquisition_gnss_synchro = 0; + d_channel = 0; + d_acq_code_phase_samples = 0.0; + d_acq_carrier_doppler_hz = 0.0; + d_carrier_doppler_hz = 0.0; + d_acc_carrier_phase_rad = 0.0; + d_code_phase_samples = 0.0; + d_rem_code_phase_chips = 0.0; + d_code_phase_step_chips = 0.0; + d_carrier_phase_step_rad = 0.0; + + set_relative_rate(1.0 / static_cast(d_vector_length)); + + multicorrelator_fpga_8sc->set_output_vectors(d_correlator_outs); +} + + +void Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc::start_tracking() +{ + /* + * correct the code phase according to the delay between acq and trk + */ + //printf("TRK : start tracking for satellite %d\n", d_acquisition_gnss_synchro->PRN); + d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples; + d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; + d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; + long int acq_trk_diff_samples; + double acq_trk_diff_seconds; + acq_trk_diff_samples = static_cast(d_sample_counter) - static_cast(d_acq_sample_stamp); //-d_vector_length; + DLOG(INFO) << "Number of samples between Acquisition and Tracking = " << acq_trk_diff_samples; + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / static_cast(d_fs_in); + // Doppler effect + // Fd=(C/(C+Vr))*F + double radial_velocity = (GPS_L1_FREQ_HZ + d_acq_carrier_doppler_hz) / GPS_L1_FREQ_HZ; + // new chip and prn sequence periods based on acq Doppler + double T_chip_mod_seconds; + double T_prn_mod_seconds; + double T_prn_mod_samples; + d_code_freq_chips = radial_velocity * GPS_L1_CA_CODE_RATE_HZ; + d_code_phase_step_chips = static_cast(d_code_freq_chips) / static_cast(d_fs_in); + T_chip_mod_seconds = 1 / d_code_freq_chips; + T_prn_mod_seconds = T_chip_mod_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; + T_prn_mod_samples = T_prn_mod_seconds * static_cast(d_fs_in); + d_current_prn_length_samples = round(T_prn_mod_samples); + double T_prn_true_seconds = GPS_L1_CA_CODE_LENGTH_CHIPS / GPS_L1_CA_CODE_RATE_HZ; + double T_prn_true_samples = T_prn_true_seconds * static_cast(d_fs_in); + double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; + double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; + double corrected_acq_phase_samples, delay_correction_samples; + corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * static_cast(d_fs_in)), T_prn_true_samples); + if (corrected_acq_phase_samples < 0) + { + corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples; + } + delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; + d_acq_code_phase_samples = corrected_acq_phase_samples; + d_carrier_doppler_hz = d_acq_carrier_doppler_hz; + d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + // DLL/PLL filter initialization + d_carrier_loop_filter.initialize(); // initialize the carrier filter + d_code_loop_filter.initialize(); // initialize the code filter + // generate local reference ALWAYS starting at chip 1 (1 sample per chip) + //gps_l1_ca_code_gen_float(d_ca_code, d_acquisition_gnss_synchro->PRN, 0); + //gps_l1_ca_code_gen_int(d_ca_code_16sc, d_acquisition_gnss_synchro->PRN, 0); + /* for (int n = 0; n < static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS); n++) + { + d_ca_code_16sc[n] = d_ca_code[n]; + } */ + //multicorrelator_fpga_8sc->set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code_16sc, d_local_code_shift_chips, d_acquisition_gnss_synchro->PRN); + multicorrelator_fpga_8sc->set_local_code_and_taps(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS), d_local_code_shift_chips, d_acquisition_gnss_synchro->PRN); + for (int n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + d_carrier_lock_fail_counter = 0; + d_rem_code_phase_samples = 0; + d_rem_carr_phase_rad = 0.0; + d_rem_code_phase_chips = 0.0; + d_acc_carrier_phase_rad = 0.0; + d_code_phase_samples = d_acq_code_phase_samples; + std::string sys_ = &d_acquisition_gnss_synchro->System; + sys = sys_.substr(0, 1); + std::cout << "Tracking of GPS L1 C/A signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl; + LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + // enable tracking + d_pull_in = true; + d_enable_tracking = true; //do it in the end to avoid starting running tracking before finishing this function + LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz + << " Code Phase correction [samples]=" << delay_correction_samples + << " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples; +} + + +Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc::~Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc() +{ + if (d_dump_file.is_open()) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } + } + try + { + volk_gnsssdr_free(d_local_code_shift_chips); + volk_gnsssdr_free(d_correlator_outs); + delete[] d_Prompt_buffer; + multicorrelator_fpga_8sc->free(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor " << ex.what(); + } +} + + +int Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + unsigned absolute_samples_offset; + // process vars + double carr_error_hz = 0.0; + double carr_error_filt_hz = 0.0; + double code_error_chips = 0.0; + double code_error_filt_chips = 0.0; + + int next_prn_length_samples = d_current_prn_length_samples; + + // Block input data and block output stream pointers + Gnss_Synchro **out = reinterpret_cast(&output_items[0]); + + // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder + Gnss_Synchro current_synchro_data = Gnss_Synchro(); + + if (d_enable_tracking == true) + { + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; + // Receiver signal alignment + if (d_pull_in == true) + { + d_pull_in = false; + multicorrelator_fpga_8sc->lock_channel(); + unsigned counter_value = multicorrelator_fpga_8sc->read_sample_counter(); + unsigned num_frames = ceil((counter_value - current_synchro_data.Acq_samplestamp_samples - current_synchro_data.Acq_delay_samples) / d_correlation_length_samples); + absolute_samples_offset = current_synchro_data.Acq_delay_samples + current_synchro_data.Acq_samplestamp_samples + num_frames * d_correlation_length_samples; + multicorrelator_fpga_8sc->set_initial_sample(absolute_samples_offset); + d_sample_counter = absolute_samples_offset; + current_synchro_data.Tracking_sample_counter = absolute_samples_offset; + } + else + { + // continue as from the previous point + d_sample_counter = d_sample_counter_next; + } + d_sample_counter_next = d_sample_counter + d_current_prn_length_samples; + + // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + // perform carrier wipe-off and compute Early, Prompt and Late correlation + multicorrelator_fpga_8sc->Carrier_wipeoff_multicorrelator_resampler( + d_rem_carr_phase_rad, d_carrier_phase_step_rad, + d_rem_code_phase_chips, d_code_phase_step_chips, + d_current_prn_length_samples); + + // ################## PLL ########################################################## + // PLL discriminator + // Update PLL discriminator [rads/Ti -> Secs/Ti] + carr_error_hz = pll_cloop_two_quadrant_atan(d_correlator_outs[1]) / GPS_TWO_PI; // prompt output + // Carrier discriminator filter + carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(carr_error_hz); + // New carrier Doppler frequency estimation + d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_error_filt_hz; + // New code Doppler frequency estimation + d_code_freq_chips = GPS_L1_CA_CODE_RATE_HZ + ((d_carrier_doppler_hz * GPS_L1_CA_CODE_RATE_HZ) / GPS_L1_FREQ_HZ); + + // ################## DLL ########################################################## + // DLL discriminator + code_error_chips = dll_nc_e_minus_l_normalized(d_correlator_outs[0], d_correlator_outs[2]); // [chips/Ti] //early and late + // Code discriminator filter + code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); // [chips/second] + double T_chip_seconds = 1.0 / static_cast(d_code_freq_chips); + double T_prn_seconds = T_chip_seconds * GPS_L1_CA_CODE_LENGTH_CHIPS; + double code_error_filt_secs = (T_prn_seconds * code_error_filt_chips * T_chip_seconds); //[seconds] + + // ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT ####################### + // keep alignment parameters for the next input buffer + // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation + double T_prn_samples = T_prn_seconds * static_cast(d_fs_in); + double K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * static_cast(d_fs_in); + next_prn_length_samples = round(K_blk_samples); + + //################### PLL COMMANDS ################################################# + // carrier phase step (NCO phase increment per sample) [rads/sample] + d_carrier_phase_step_rad = GPS_TWO_PI * d_carrier_doppler_hz / static_cast(d_fs_in); + // remnant carrier phase to prevent overflow in the code NCO + d_rem_carr_phase_rad = d_rem_carr_phase_rad + d_carrier_phase_step_rad * d_current_prn_length_samples; + d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, GPS_TWO_PI); + // carrier phase accumulator + d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * d_current_prn_length_samples; + + //################### DLL COMMANDS ################################################# + // code phase step (Code resampler phase increment per sample) [chips/sample] + d_code_phase_step_chips = d_code_freq_chips / static_cast(d_fs_in); + // remnant code phase [chips] + d_rem_code_phase_samples = K_blk_samples - next_prn_length_samples; // rounding error < 1 sample + d_rem_code_phase_chips = d_code_freq_chips * (d_rem_code_phase_samples / static_cast(d_fs_in)); + + // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### + if (d_cn0_estimation_counter < FLAGS_cn0_samples) + { + // fill buffer with prompt correlator output values + d_Prompt_buffer[d_cn0_estimation_counter] = d_correlator_outs[1]; //prompt + d_cn0_estimation_counter++; + } + else + { + d_cn0_estimation_counter = 0; + // Code lock indicator + d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, FLAGS_cn0_samples, GPS_L1_CA_CODE_PERIOD); + // Carrier lock indicator + d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, FLAGS_cn0_samples); + // Loss of lock detection + if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < FLAGS_cn0_min) + { + d_carrier_lock_fail_counter++; + } + else + { + if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--; + } + if (d_carrier_lock_fail_counter > FLAGS_max_lock_fail) + { + std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl; + LOG(INFO) << "Loss of lock in channel " << d_channel << "!"; + this->message_port_pub(pmt::mp("events"), pmt::from_long(3)); // 3 -> loss of lock + d_carrier_lock_fail_counter = 0; + d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine + multicorrelator_fpga_8sc->unlock_channel(); + } + } + + // ########### Output the tracking data to navigation and PVT ########## + current_synchro_data.Prompt_I = static_cast((d_correlator_outs[1]).real()); + current_synchro_data.Prompt_Q = static_cast((d_correlator_outs[1]).imag()); + current_synchro_data.Tracking_sample_counter = d_sample_counter + d_current_prn_length_samples; + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = 1; + } + else + { + for (int n = 0; n < d_n_correlator_taps; n++) + { + d_correlator_outs[n] = gr_complex(0, 0); + } + + current_synchro_data.Tracking_sample_counter = d_sample_counter + d_current_prn_length_samples; + current_synchro_data.System = {'G'}; + current_synchro_data.correlation_length_ms = 1; + } + + //assign the GNURadio block output data + current_synchro_data.fs = d_fs_in; + *out[0] = current_synchro_data; + if (d_enable_tracking == true) // in the FPGA case dump data only when tracking is enabled, otherwise the dumped data is useless + { + if (d_dump) + { + // MULTIPLEXED FILE RECORDING - Record results to file + float prompt_I; + float prompt_Q; + float tmp_E, tmp_P, tmp_L; + double tmp_double; + unsigned long int tmp_long; + prompt_I = d_correlator_outs[1].real(); + prompt_Q = d_correlator_outs[1].imag(); + tmp_E = std::abs(d_correlator_outs[0]); + tmp_P = std::abs(d_correlator_outs[1]); + tmp_L = std::abs(d_correlator_outs[2]); + try + { + // EPR + d_dump_file.write(reinterpret_cast(&tmp_E), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_P), sizeof(float)); + d_dump_file.write(reinterpret_cast(&tmp_L), sizeof(float)); + // PROMPT I and Q (to analyze navigation symbols) + d_dump_file.write(reinterpret_cast(&prompt_I), sizeof(float)); + d_dump_file.write(reinterpret_cast(&prompt_Q), sizeof(float)); + // PRN start sample stamp + tmp_long = d_sample_counter + d_current_prn_length_samples; + d_dump_file.write(reinterpret_cast(&tmp_long), sizeof(unsigned long int)); + // accumulated carrier phase + d_dump_file.write(reinterpret_cast(&d_acc_carrier_phase_rad), sizeof(double)); + + // carrier and code frequency + d_dump_file.write(reinterpret_cast(&d_carrier_doppler_hz), sizeof(double)); + d_dump_file.write(reinterpret_cast(&d_code_freq_chips), sizeof(double)); + + // PLL commands + d_dump_file.write(reinterpret_cast(&carr_error_hz), sizeof(double)); + d_dump_file.write(reinterpret_cast(&carr_error_filt_hz), sizeof(double)); + + // DLL commands + d_dump_file.write(reinterpret_cast(&code_error_chips), sizeof(double)); + d_dump_file.write(reinterpret_cast(&code_error_filt_chips), sizeof(double)); + + // CN0 and carrier lock test + d_dump_file.write(reinterpret_cast(&d_CN0_SNV_dB_Hz), sizeof(double)); + d_dump_file.write(reinterpret_cast(&d_carrier_lock_test), sizeof(double)); + + // AUX vars (for debug purposes) + tmp_double = d_rem_code_phase_samples; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = static_cast(d_sample_counter); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + + // PRN + unsigned int prn_ = d_acquisition_gnss_synchro->PRN; + d_dump_file.write(reinterpret_cast(&prn_), sizeof(unsigned int)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing trk dump file " << e.what(); + } + } + } + + + d_current_prn_length_samples = next_prn_length_samples; + d_sample_counter += d_current_prn_length_samples; // count for the processed samples + + if (d_enable_tracking == true) + { + return 1; + } + else + { + return 0; + } +} + + +void Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc::set_channel(unsigned int channel) +{ + d_channel = channel; + multicorrelator_fpga_8sc->set_channel(d_channel); + LOG(INFO) << "Tracking Channel set to " << d_channel; + + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename.append(boost::lexical_cast(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +void Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) +{ + d_acquisition_gnss_synchro = p_gnss_synchro; +} + + +void Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc::reset(void) +{ + multicorrelator_fpga_8sc->unlock_channel(); +} diff --git a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc.h b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_fpga_sc.h similarity index 54% rename from src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc.h rename to src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_fpga_sc.h index 1bd8bb0c1..295c3f177 100644 --- a/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc.h +++ b/src/algorithms/tracking/gnuradio_blocks/gps_l1_ca_dll_pll_tracking_fpga_sc.h @@ -1,9 +1,9 @@ /*! - * \file gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc.h + * \file gps_l1_ca_dll_pll_tracking_cc.h * \brief Interface of a code DLL + carrier PLL tracking block - * \author Marc Majoral, 2017. mmajoral(at)cttc.cat - * Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com + * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * Javier Arribas, 2011. jarribas(at)cttc.es + * Cillian O'Driscoll, 2017. cillian.odriscoll(at)gmail.com * * Code DLL + carrier PLL according to the algorithms described in: * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -35,13 +35,14 @@ * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_FPGA_SC_H -#define GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_FPGA_SC_H +#ifndef GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_SC_H +#define GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_SC_H + #include "gps_sdr_signal_processing.h" #include "gnss_synchro.h" #include "tracking_2nd_DLL_filter.h" -#include "tracking_FLL_PLL_filter.h" +#include "tracking_2nd_PLL_filter.h" #include "fpga_multicorrelator_8sc.h" #include #include @@ -51,47 +52,62 @@ #include #include -class gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc; -typedef boost::shared_ptr gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc_sptr; +class Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc; + +typedef boost::shared_ptr + gps_l1_ca_dll_pll_tracking_fpga_sc_sptr; + +gps_l1_ca_dll_pll_tracking_fpga_sc_sptr +gps_l1_ca_dll_pll_make_tracking_fpga_sc(long if_freq, + long fs_in, unsigned int vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips, + std::string device_name, + unsigned int device_base); -gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc_sptr -gps_l1_ca_dll_pll_c_aid_make_tracking_fpga_sc(long if_freq, long fs_in, unsigned int vector_length, bool dump, std::string dump_filename, float pll_bw_hz, - float dll_bw_hz, float pll_bw_narrow_hz, float dll_bw_narrow_hz, - int extend_correlation_ms, float early_late_space_chips, - std::string device_name, unsigned int device_base); /*! * \brief This class implements a DLL + PLL tracking loop block */ -class gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc : public gr::block +class Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc : public gr::block { public: - ~gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc(); + ~Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc(); void set_channel(unsigned int channel); void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro); void start_tracking(); int general_work(int noutput_items, gr_vector_int& ninput_items, - gr_vector_const_void_star& input_items, - gr_vector_void_star& output_items); + gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); void reset(void); private: - friend gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc_sptr - gps_l1_ca_dll_pll_c_aid_make_tracking_fpga_sc(long if_freq, long fs_in, - unsigned int vector_length, bool dump, std::string dump_filename, - float pll_bw_hz, float dll_bw_hz, float pll_bw_narrow_hz, - float dll_bw_narrow_hz, int extend_correlation_ms, - float early_late_space_chips, std::string device_name, + friend gps_l1_ca_dll_pll_tracking_fpga_sc_sptr + gps_l1_ca_dll_pll_make_tracking_fpga_sc(long if_freq, + long fs_in, unsigned int vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips, + std::string device_name, unsigned int device_base); - gps_l1_ca_dll_pll_c_aid_tracking_fpga_sc(long if_freq, long fs_in, unsigned int vector_length, bool dump, std::string dump_filename, float pll_bw_hz, - float dll_bw_hz, float pll_bw_narrow_hz, float dll_bw_narrow_hz, - int extend_correlation_ms, float early_late_space_chips, - std::string device_name, unsigned int device_base); + Gps_L1_Ca_Dll_Pll_Tracking_fpga_sc(long if_freq, + long fs_in, unsigned int vector_length, + bool dump, + std::string dump_filename, + float pll_bw_hz, + float dll_bw_hz, + float early_late_space_chips, + std::string device_name, + unsigned int device_base); // tracking configuration vars unsigned int d_vector_length; @@ -104,58 +120,38 @@ private: long d_fs_in; double d_early_late_spc_chips; - int d_n_correlator_taps; - - gr_complex* d_ca_code; - lv_16sc_t* d_ca_code_16sc; - float* d_local_code_shift_chips; - lv_16sc_t* d_correlator_outs_16sc; - //fpga_multicorrelator_8sc multicorrelator_fpga_8sc; - std::shared_ptr multicorrelator_fpga_8sc; // remaining code phase and carrier phase between tracking loops double d_rem_code_phase_samples; double d_rem_code_phase_chips; - double d_rem_carrier_phase_rad; - int d_rem_code_phase_integer_samples; + double d_rem_carr_phase_rad; // PLL and DLL filter library Tracking_2nd_DLL_filter d_code_loop_filter; - Tracking_FLL_PLL_filter d_carrier_loop_filter; + Tracking_2nd_PLL_filter d_carrier_loop_filter; // acquisition double d_acq_code_phase_samples; double d_acq_carrier_doppler_hz; + // correlator + int d_n_correlator_taps; + //float* d_ca_code; + //int* d_ca_code_16sc; + + float* d_local_code_shift_chips; + gr_complex* d_correlator_outs; + std::shared_ptr multicorrelator_fpga_8sc; // tracking vars - float d_dll_bw_hz; - float d_pll_bw_hz; - float d_dll_bw_narrow_hz; - float d_pll_bw_narrow_hz; double d_code_freq_chips; double d_code_phase_step_chips; double d_carrier_doppler_hz; double d_carrier_phase_step_rad; - double d_acc_carrier_phase_cycles; + double d_acc_carrier_phase_rad; double d_code_phase_samples; - double d_pll_to_dll_assist_secs_Ti; - double d_carr_phase_error_secs_Ti; - double d_code_error_chips_Ti; - double d_preamble_timestamp_s; - int d_extend_correlation_ms; - bool d_enable_extended_integration; - bool d_preamble_synchronized; - double d_code_error_filt_chips_s; - double d_code_error_filt_chips_Ti; - void msg_handler_preamble_index(pmt::pmt_t msg); - // symbol history to detect bit transition - std::deque d_E_history; - std::deque d_P_history; - std::deque d_L_history; - - //Integration period in samples - int d_correlation_length_samples; + //PRN period in samples + int d_current_prn_length_samples; //processing samples counters unsigned long int d_sample_counter; @@ -180,7 +176,13 @@ private: std::map systemName; std::string sys; - int save_matfile(); + // extra + int d_correlation_length_samples; + unsigned long int d_sample_counter_next; + double d_rem_carrier_phase_rad; + + double d_K_blk_samples_previous; + int d_offset_sample_previous; }; -#endif //GNSS_SDR_GPS_L1_CA_DLL_PLL_C_AID_TRACKING_FPGA_SC_H +#endif //GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_SC_H diff --git a/src/algorithms/tracking/libs/CMakeLists.txt b/src/algorithms/tracking/libs/CMakeLists.txt index 5c5ce7a2a..88c4eb2a5 100644 --- a/src/algorithms/tracking/libs/CMakeLists.txt +++ b/src/algorithms/tracking/libs/CMakeLists.txt @@ -54,6 +54,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/core/system_parameters ${CMAKE_SOURCE_DIR}/src/core/interfaces ${CMAKE_SOURCE_DIR}/src/core/receiver + ${CMAKE_SOURCE_DIR}/src/algorithms/libs ${VOLK_INCLUDE_DIRS} ${GLOG_INCLUDE_DIRS} ${GFlags_INCLUDE_DIRS} diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator_8sc.cc b/src/algorithms/tracking/libs/fpga_multicorrelator_8sc.cc index 9af959232..737e414d9 100644 --- a/src/algorithms/tracking/libs/fpga_multicorrelator_8sc.cc +++ b/src/algorithms/tracking/libs/fpga_multicorrelator_8sc.cc @@ -36,7 +36,6 @@ #include "fpga_multicorrelator_8sc.h" #include - // FPGA stuff #include @@ -63,6 +62,12 @@ // string manipulation #include +// constants +#include "GPS_L1_CA.h" + +#include "gps_sdr_signal_processing.h" + +#define NUM_PRNs 32 #define PAGE_SIZE 0x10000 #define MAX_LENGTH_DEVICEIO_NAME 50 #define CODE_RESAMPLER_NUM_BITS_PRECISION 20 @@ -77,72 +82,59 @@ #define LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY 0x0C000000 #define TEST_REGISTER_TRACK_WRITEVAL 0x55AA +int fpga_multicorrelator_8sc::read_sample_counter() +{ + return d_map_base[7]; +} + void fpga_multicorrelator_8sc::set_initial_sample(int samples_offset) { d_initial_sample_counter = samples_offset; + d_map_base[13] = d_initial_sample_counter; } - -bool fpga_multicorrelator_8sc::set_local_code_and_taps(int code_length_chips, - const lv_16sc_t* local_code_in, float* shifts_chips) +void fpga_multicorrelator_8sc::set_local_code_and_taps(int code_length_chips, + float *shifts_chips, int PRN) { - d_local_code_in = local_code_in; d_shifts_chips = shifts_chips; d_code_length_chips = code_length_chips; - - fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(); - - return true; + fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(PRN); } - -bool fpga_multicorrelator_8sc::set_output_vectors(lv_16sc_t* corr_out) +void fpga_multicorrelator_8sc::set_output_vectors(gr_complex *corr_out) { - // Save CPU pointers d_corr_out = corr_out; - - return true; } - void fpga_multicorrelator_8sc::update_local_code(float rem_code_phase_chips) { d_rem_code_phase_chips = rem_code_phase_chips; - fpga_multicorrelator_8sc::fpga_compute_code_shift_parameters(); fpga_multicorrelator_8sc::fpga_configure_code_parameters_in_fpga(); } - -bool fpga_multicorrelator_8sc::Carrier_wipeoff_multicorrelator_resampler( +void fpga_multicorrelator_8sc::Carrier_wipeoff_multicorrelator_resampler( float rem_carrier_phase_in_rad, float phase_step_rad, float rem_code_phase_chips, float code_phase_step_chips, int signal_length_samples) { update_local_code(rem_code_phase_chips); - d_rem_carrier_phase_in_rad = rem_carrier_phase_in_rad; d_code_phase_step_chips = code_phase_step_chips; d_phase_step_rad = phase_step_rad; d_correlator_length_samples = signal_length_samples; - fpga_multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(); fpga_multicorrelator_8sc::fpga_configure_signal_parameters_in_fpga(); fpga_multicorrelator_8sc::fpga_launch_multicorrelator_fpga(); - int irq_count; ssize_t nb; - // wait for interrupt nb = read(d_device_descriptor, &irq_count, sizeof(irq_count)); if (nb != sizeof(irq_count)) { printf("Tracking_module Read failed to retrieve 4 bytes!\n"); printf("Tracking_module Interrupt number %d\n", irq_count); } - fpga_multicorrelator_8sc::read_tracking_gps_results(); - - return true; } @@ -156,12 +148,12 @@ fpga_multicorrelator_8sc::fpga_multicorrelator_8sc(int n_correlators, d_map_base = nullptr; // instantiate variable length vectors - d_initial_index = static_cast(volk_gnsssdr_malloc( + d_initial_index = static_cast(volk_gnsssdr_malloc( n_correlators * sizeof(unsigned), volk_gnsssdr_get_alignment())); - d_initial_interp_counter = static_cast(volk_gnsssdr_malloc( + d_initial_interp_counter = static_cast(volk_gnsssdr_malloc( n_correlators * sizeof(unsigned), volk_gnsssdr_get_alignment())); - d_local_code_in = nullptr; + //d_local_code_in = nullptr; d_shifts_chips = nullptr; d_corr_out = nullptr; d_code_length_chips = 0; @@ -172,22 +164,30 @@ fpga_multicorrelator_8sc::fpga_multicorrelator_8sc(int n_correlators, d_rem_carr_phase_rad_int = 0; d_phase_step_rad_int = 0; d_initial_sample_counter = 0; - d_channel = 0; d_correlator_length_samples = 0; + + // pre-compute all the codes + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS * NUM_PRNs) * sizeof(int), volk_gnsssdr_get_alignment())); + for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + { + gps_l1_ca_code_gen_int(&d_ca_codes[(int(GPS_L1_CA_CODE_LENGTH_CHIPS)) * (PRN - 1)], PRN, 0); + } + DLOG(INFO) << "TRACKING FPGA CLASS CREATED"; } fpga_multicorrelator_8sc::~fpga_multicorrelator_8sc() { - close(d_device_descriptor); + delete[] d_ca_codes; + close_device(); } bool fpga_multicorrelator_8sc::free() { - // unlock the hardware - fpga_multicorrelator_8sc::unlock_channel(); // unlock the channel + // unlock the channel + fpga_multicorrelator_8sc::unlock_channel(); // free the FPGA dynamically created variables if (d_initial_index != nullptr) @@ -209,27 +209,23 @@ bool fpga_multicorrelator_8sc::free() void fpga_multicorrelator_8sc::set_channel(unsigned int channel) { char device_io_name[MAX_LENGTH_DEVICEIO_NAME]; // driver io name - d_channel = channel; // open the device corresponding to the assigned channel std::string mergedname; std::stringstream devicebasetemp; - int numdevice = d_device_base + d_channel; devicebasetemp << numdevice; mergedname = d_device_name + devicebasetemp.str(); strcpy(device_io_name, mergedname.c_str()); - printf("Opening Device Name : %s\n", device_io_name); if ((d_device_descriptor = open(device_io_name, O_RDWR | O_SYNC)) == -1) { LOG(WARNING) << "Cannot open deviceio" << device_io_name; } - - d_map_base = reinterpret_cast(mmap(NULL, PAGE_SIZE, + d_map_base = reinterpret_cast(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0)); - if (d_map_base == reinterpret_cast(-1)) + if (d_map_base == reinterpret_cast(-1)) { LOG(WARNING) << "Cannot map the FPGA tracking module " << d_channel << "into user memory"; @@ -263,12 +259,11 @@ unsigned fpga_multicorrelator_8sc::fpga_acquisition_test_register( } -void fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(void) +void fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(int PRN) { int k, s; unsigned code_chip; unsigned select_fpga_correlator; - select_fpga_correlator = 0; for (s = 0; s < d_n_correlators; s++) @@ -276,7 +271,8 @@ void fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(void) d_map_base[11] = LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER; for (k = 0; k < d_code_length_chips; k++) { - if (lv_creal(d_local_code_in[k]) == 1) + //if (d_local_code_in[k] == 1) + if (d_ca_codes[((int(GPS_L1_CA_CODE_LENGTH_CHIPS)) * (PRN - 1)) + k] == 1) { code_chip = 1; } @@ -299,17 +295,15 @@ void fpga_multicorrelator_8sc::fpga_compute_code_shift_parameters(void) for (i = 0; i < d_n_correlators; i++) { - // initial index calculation temp_calculation = floor( - d_shifts_chips[i] + d_rem_code_phase_chips); + d_shifts_chips[i] - d_rem_code_phase_chips); + if (temp_calculation < 0) { temp_calculation = temp_calculation + d_code_length_chips; // % operator does not work as in Matlab with negative numbers } d_initial_index[i] = static_cast((static_cast(temp_calculation)) % d_code_length_chips); - - // initial interpolator counter calculation - temp_calculation = fmod(d_shifts_chips[i] + d_rem_code_phase_chips, + temp_calculation = fmod(d_shifts_chips[i] - d_rem_code_phase_chips, 1.0); if (temp_calculation < 0) { @@ -337,7 +331,6 @@ void fpga_multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(void) float d_rem_carrier_phase_in_rad_temp; d_code_phase_step_chips_num = static_cast(roundf(MAX_CODE_RESAMPLER_COUNTER * d_code_phase_step_chips)); - if (d_rem_carrier_phase_in_rad > M_PI) { d_rem_carrier_phase_in_rad_temp = -2 * M_PI + d_rem_carrier_phase_in_rad; @@ -350,10 +343,8 @@ void fpga_multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(void) { d_rem_carrier_phase_in_rad_temp = d_rem_carrier_phase_in_rad; } - d_rem_carr_phase_rad_int = static_cast(roundf( (fabs(d_rem_carrier_phase_in_rad_temp) / M_PI) * pow(2, PHASE_CARR_NBITS_FRAC))); - if (d_rem_carrier_phase_in_rad_temp < 0) { d_rem_carr_phase_rad_int = -d_rem_carr_phase_rad_int; @@ -374,7 +365,6 @@ void fpga_multicorrelator_8sc::fpga_configure_signal_parameters_in_fpga(void) d_map_base[7] = d_correlator_length_samples - 1; d_map_base[9] = d_rem_carr_phase_rad_int; d_map_base[10] = d_phase_step_rad_int; - d_map_base[13] = d_initial_sample_counter; } @@ -382,9 +372,10 @@ void fpga_multicorrelator_8sc::fpga_launch_multicorrelator_fpga(void) { // enable interrupts int reenable = 1; - write(d_device_descriptor, reinterpret_cast(&reenable), sizeof(int)); + write(d_device_descriptor, reinterpret_cast(&reenable), sizeof(int)); - d_map_base[14] = 0; // writing anything to reg 14 launches the tracking + // writing 1 to reg 14 launches the tracking + d_map_base[14] = 1; } @@ -401,16 +392,13 @@ void fpga_multicorrelator_8sc::read_tracking_gps_results(void) { readval_real = -2097152 + readval_real; } - readval_real = readval_real * 2; // the results are shifted two bits to the left due to the complex multiplier in the FPGA readval_imag = d_map_base[1 + d_n_correlators + k]; if (readval_imag >= 1048576) // 0x100000 (21 bits two's complement) { readval_imag = -2097152 + readval_imag; } - readval_imag = readval_imag * 2; // the results are shifted two bits to the left due to the complex multiplier in the FPGA - - d_corr_out[k] = lv_cmake(readval_real, readval_imag); + d_corr_out[k] = gr_complex(readval_real, readval_imag); } } @@ -422,8 +410,38 @@ void fpga_multicorrelator_8sc::unlock_channel(void) } +void fpga_multicorrelator_8sc::close_device() +{ + unsigned *aux = const_cast(d_map_base); + if (munmap(static_cast(aux), PAGE_SIZE) == -1) + { + printf("Failed to unmap memory uio\n"); + } + /* else + { + printf("memory uio unmapped\n"); + } */ + close(d_device_descriptor); +} + + void fpga_multicorrelator_8sc::lock_channel(void) { // lock the channel for processing d_map_base[12] = 0; // lock the channel } + + +void fpga_multicorrelator_8sc::read_sample_counters(int *sample_counter, int *secondary_sample_counter, int *counter_corr_0_in, int *counter_corr_0_out) +{ + *sample_counter = d_map_base[11]; + *secondary_sample_counter = d_map_base[8]; + *counter_corr_0_in = d_map_base[10]; + *counter_corr_0_out = d_map_base[9]; +} + + +void fpga_multicorrelator_8sc::reset_multicorrelator(void) +{ + d_map_base[14] = 2; // writing a 2 to d_map_base[14] resets the multicorrelator +} diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator_8sc.h b/src/algorithms/tracking/libs/fpga_multicorrelator_8sc.h index 9608a487c..1eceb1936 100644 --- a/src/algorithms/tracking/libs/fpga_multicorrelator_8sc.h +++ b/src/algorithms/tracking/libs/fpga_multicorrelator_8sc.h @@ -37,6 +37,7 @@ #ifndef GNSS_SDR_FPGA_MULTICORRELATOR_8SC_H_ #define GNSS_SDR_FPGA_MULTICORRELATOR_8SC_H_ +#include #include #define MAX_LENGTH_DEVICEIO_NAME 50 @@ -50,25 +51,33 @@ public: fpga_multicorrelator_8sc(int n_correlators, std::string device_name, unsigned int device_base); ~fpga_multicorrelator_8sc(); - bool set_local_code_and_taps( - int code_length_chips, const lv_16sc_t *local_code_in, - float *shifts_chips); - bool set_output_vectors(lv_16sc_t *corr_out); + //bool set_output_vectors(gr_complex* corr_out); + void set_output_vectors(gr_complex *corr_out); + // bool set_local_code_and_taps( + // int code_length_chips, const int* local_code_in, + // float *shifts_chips, int PRN); + //bool set_local_code_and_taps( + void set_local_code_and_taps( + int code_length_chips, + float *shifts_chips, int PRN); + //bool set_output_vectors(lv_16sc_t* corr_out); void update_local_code(float rem_code_phase_chips); - bool Carrier_wipeoff_multicorrelator_resampler( + //bool Carrier_wipeoff_multicorrelator_resampler( + void Carrier_wipeoff_multicorrelator_resampler( float rem_carrier_phase_in_rad, float phase_step_rad, float rem_code_phase_chips, float code_phase_step_chips, int signal_length_samples); bool free(); - void set_channel(unsigned int channel); void set_initial_sample(int samples_offset); + int read_sample_counter(); void lock_channel(void); void unlock_channel(void); + void read_sample_counters(int *sample_counter, int *secondary_sample_counter, int *counter_corr_0_in, int *counter_corr_0_out); // debug private: - const lv_16sc_t *d_local_code_in; - lv_16sc_t *d_corr_out; + //const int *d_local_code_in; + gr_complex *d_corr_out; float *d_shifts_chips; int d_code_length_chips; int d_n_correlators; @@ -98,20 +107,19 @@ private: std::string d_device_name; unsigned int d_device_base; - // results - //int *d_readval_real; - //int *d_readval_imag; - // FPGA private functions + int *d_ca_codes; + + // private functions unsigned fpga_acquisition_test_register(unsigned writeval); - void fpga_configure_tracking_gps_local_code(void); + void fpga_configure_tracking_gps_local_code(int PRN); void fpga_compute_code_shift_parameters(void); void fpga_configure_code_parameters_in_fpga(void); void fpga_compute_signal_parameters_in_fpga(void); void fpga_configure_signal_parameters_in_fpga(void); void fpga_launch_multicorrelator_fpga(void); void read_tracking_gps_results(void); - - //void unlock_channel(void); + void reset_multicorrelator(void); + void close_device(void); }; #endif /* GNSS_SDR_FPGA_MULTICORRELATOR_H_ */ diff --git a/src/core/receiver/CMakeLists.txt b/src/core/receiver/CMakeLists.txt index e632d6833..9d276e786 100644 --- a/src/core/receiver/CMakeLists.txt +++ b/src/core/receiver/CMakeLists.txt @@ -90,6 +90,11 @@ if(ENABLE_FMCOMMS2) set(OPT_RECEIVER_INCLUDE_DIRS ${OPT_RECEIVER_INCLUDE_DIRS} ${IIO_INCLUDE_DIRS}) endif(ENABLE_FMCOMMS2) +if(ENABLE_AD9361) + add_definitions(-DAD9361_DRIVER=1) + set(OPT_RECEIVER_INCLUDE_DIRS ${OPT_RECEIVER_INCLUDE_DIRS} ${IIO_INCLUDE_DIRS}) +endif(ENABLE_AD9361) + if(${PC_GNURADIO_RUNTIME_VERSION} VERSION_GREATER "3.7.15" ) add_definitions( -DGR_GREATER_38=1 ) endif(${PC_GNURADIO_RUNTIME_VERSION} VERSION_GREATER "3.7.15" ) diff --git a/src/core/receiver/control_thread.cc b/src/core/receiver/control_thread.cc index b2d1838f4..9121d7fa7 100644 --- a/src/core/receiver/control_thread.cc +++ b/src/core/receiver/control_thread.cc @@ -138,6 +138,13 @@ void ControlThread::run() keyboard_thread_ = boost::thread(&ControlThread::keyboard_listener, this); sysv_queue_thread_ = boost::thread(&ControlThread::sysv_queue_listener, this); + bool enable_FPGA = configuration_->property("Channel.enable_FPGA", false); + + if (enable_FPGA == true) + { + flowgraph_->start_acquisition_helper(); + } + // Main loop to read and process the control messages while (flowgraph_->running() && !stop_) { diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index bbc88df91..09d396b36 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -104,8 +104,8 @@ #include "rtklib_pvt.h" #if ENABLE_FPGA -#include "gps_l1_ca_dll_pll_c_aid_tracking_fpga.h" #include "gps_l1_ca_pcps_acquisition_fpga.h" +#include "gps_l1_ca_dll_pll_tracking_fpga.h" #endif #if OPENCL_BLOCKS @@ -136,6 +136,10 @@ #include "fmcomms2_signal_source.h" #endif +#if AD9361_DRIVER +#include "ad9361_fpga_signal_source.h" +#endif + #if FLEXIBAND_DRIVER #include "flexiband_signal_source.h" #endif @@ -273,7 +277,6 @@ std::unique_ptr GNSSBlockFactory::GetPVT(std::shared_ptrproperty("Channels_2S.count", 0); GPS_channels += configuration->property("Channels_L5.count", 0); unsigned int Glonass_channels = configuration->property("Channels_1G.count", 0); - Glonass_channels += configuration->property("Channels_2G.count", 0); return GetBlock(configuration, "PVT", implementation, Galileo_channels + GPS_channels + Glonass_channels, 0); } @@ -1186,6 +1189,15 @@ std::unique_ptr GNSSBlockFactory::GetBlock( } #endif +#if AD9361_DRIVER + else if (implementation.compare("Ad9361_Fpga_Signal_Source") == 0) + { + std::unique_ptr block_(new Ad9361FpgaSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } +#endif + #if FLEXIBAND_DRIVER else if (implementation.compare("Flexiband_Signal_Source") == 0) { @@ -1416,9 +1428,9 @@ std::unique_ptr GNSSBlockFactory::GetBlock( block = std::move(block_); } #if ENABLE_FPGA - else if (implementation.compare("GPS_L1_CA_DLL_PLL_C_Aid_Tracking_Fpga") == 0) + else if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking_Fpga") == 0) { - std::unique_ptr block_(new GpsL1CaDllPllCAidTrackingFpga(configuration.get(), role, in_streams, + std::unique_ptr block_(new GpsL1CaDllPllTrackingFpga(configuration.get(), role, in_streams, out_streams)); block = std::move(block_); } @@ -1727,9 +1739,9 @@ std::unique_ptr GNSSBlockFactory::GetTrkBlock( block = std::move(block_); } #if ENABLE_FPGA - else if (implementation.compare("GPS_L1_CA_DLL_PLL_C_Aid_Tracking_Fpga") == 0) + else if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking_Fpga") == 0) { - std::unique_ptr block_(new GpsL1CaDllPllCAidTrackingFpga(configuration.get(), role, in_streams, + std::unique_ptr block_(new GpsL1CaDllPllTrackingFpga(configuration.get(), role, in_streams, out_streams)); block = std::move(block_); } diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 3303d15b6..7085f9394 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -31,6 +31,7 @@ */ #include "gnss_flowgraph.h" +#include "gnss_synchro.h" #include "configuration_interface.h" #include "gnss_block_interface.h" #include "channel_interface.h" @@ -111,32 +112,38 @@ void GNSSFlowgraph::connect() for (int i = 0; i < sources_count_; i++) { - try + if (configuration_->property(sig_source_.at(i)->role() + ".enable_FPGA", false) == false) { - sig_source_.at(i)->connect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't connect signal source block " << i << " internally"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; + try + { + sig_source_.at(i)->connect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't connect signal source block " << i << " internally"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } } } // Signal Source > Signal conditioner > for (unsigned int i = 0; i < sig_conditioner_.size(); i++) { - try + if (configuration_->property(sig_conditioner_.at(i)->role() + ".enable_FPGA", false) == false) { - sig_conditioner_.at(i)->connect(top_block_); - } - catch (const std::exception& e) - { - LOG(INFO) << "Can't connect signal conditioner block " << i << " internally"; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; + try + { + sig_conditioner_.at(i)->connect(top_block_); + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't connect signal conditioner block " << i << " internally"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } } } @@ -187,68 +194,124 @@ void GNSSFlowgraph::connect() for (int i = 0; i < sources_count_; i++) { - try + //FPGA Accelerators do not need signal sources or conditioners + //as the samples are feed directly to the FPGA fabric, so, if enabled, do not connect any source + if (configuration_->property(sig_source_.at(i)->role() + ".enable_FPGA", false) == false) { - // TODO: Remove this array implementation and create generic multistream connector - // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) - if (sig_source_.at(i)->implementation().compare("Raw_Array_Signal_Source") == 0) + try { - //Multichannel Array - std::cout << "ARRAY MODE" << std::endl; - for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) + //TODO: Remove this array implementation and create generic multistream connector + //(if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) + if (sig_source_.at(i)->implementation().compare("Raw_Array_Signal_Source") == 0) { - std::cout << "connecting ch " << j << std::endl; - top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); - } - } - else - { - // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - // Include GetRFChannels in the interface to avoid read config parameters here - // read the number of RF channels for each front-end - RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); - - for (int j = 0; j < RF_Channels; j++) - { - // Connect the multichannel signal source to multiple signal conditioners - // GNURADIO max_streams=-1 means infinite ports! - LOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); - LOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); - - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) + //Multichannel Array + std::cout << "ARRAY MODE" << std::endl; + for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) { - LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + std::cout << "connecting ch " << j << std::endl; + top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); } - else + } + else + { + //TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + //Include GetRFChannels in the interface to avoid read config parameters here + //read the number of RF channels for each front-end + RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); + + for (int j = 0; j < RF_Channels; j++) { - if (j == 0) + //Connect the multichannel signal source to multiple signal conditioners + // GNURADIO max_streams=-1 means infinite ports! + LOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); + LOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); + + if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) { - // RF_channel 0 backward compatibility with single channel sources - LOG(INFO) << "connecting sig_source_ " << i << " stream " << 0 << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); } else { - // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) - LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + if (j == 0) + { + // RF_channel 0 backward compatibility with single channel sources + LOG(INFO) << "connecting sig_source_ " << i << " stream " << 0 << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) + LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } } + signal_conditioner_ID++; } - signal_conditioner_ID++; } } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect signal source " << i << " to signal conditioner " << i; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } + } + DLOG(INFO) << "Signal source connected to signal conditioner"; + bool FPGA_enabled = configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false); + +#if ENABLE_FPGA + if (FPGA_enabled == false) + { + //connect the signal source to sample counter + //connect the sample counter to Observables + try + { + double fs = static_cast(configuration_->property("GNSS-SDR.internal_fs_sps", 0)); + if (fs == 0.0) + { + LOG(WARNING) << "Set GNSS-SDR.internal_fs_sps in configuration file"; + std::cout << "Set GNSS-SDR.internal_fs_sps in configuration file" << std::endl; + throw(std::invalid_argument("Set GNSS-SDR.internal_fs_sps in configuration")); + } + ch_out_sample_counter = gnss_sdr_make_sample_counter(fs, sig_conditioner_.at(0)->get_right_block()->output_signature()->sizeof_stream_item(0)); + top_block_->connect(sig_conditioner_.at(0)->get_right_block(), 0, ch_out_sample_counter, 0); + top_block_->connect(ch_out_sample_counter, 0, observables_->get_left_block(), channels_count_); //extra port for the sample counter pulse } catch (const std::exception& e) { - LOG(WARNING) << "Can't connect signal source " << i << " to signal conditioner " << i; + LOG(WARNING) << "Can't connect sample counter"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } + else + { + //create a software-defined 1kHz gnss_synchro pulse for the observables block + try + { + //null source + null_source_ = gr::blocks::null_source::make(sizeof(Gnss_Synchro)); + //throttle 1kHz + throttle_ = gr::blocks::throttle::make(sizeof(Gnss_Synchro), 1000); // 1000 samples per second (1kHz) + time_counter_ = gnss_sdr_make_time_counter(); + top_block_->connect(null_source_, 0, throttle_, 0); + top_block_->connect(throttle_, 0, time_counter_, 0); + top_block_->connect(time_counter_, 0, observables_->get_left_block(), channels_count_); + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect sample counter"; LOG(ERROR) << e.what(); top_block_->disconnect_all(); return; } } - DLOG(INFO) << "Signal source connected to signal conditioner"; +#else // connect the signal source to sample counter // connect the sample counter to Observables try @@ -271,27 +334,29 @@ void GNSSFlowgraph::connect() top_block_->disconnect_all(); return; } - +#endif // Signal conditioner (selected_signal_source) >> channels (i) (dependent of their associated SignalSource_ID) int selected_signal_conditioner_ID; for (unsigned int i = 0; i < channels_count_; i++) { - selected_signal_conditioner_ID = configuration_->property("Channel" + boost::lexical_cast(i) + ".RF_channel_ID", 0); - try + if (FPGA_enabled == false) { - top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, - channels_.at(i)->get_left_block(), 0); - } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect signal conditioner " << selected_signal_conditioner_ID << " to channel " << i; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } - - DLOG(INFO) << "signal conditioner " << selected_signal_conditioner_ID << " connected to channel " << i; + selected_signal_conditioner_ID = configuration_->property("Channel" + boost::lexical_cast(i) + ".RF_channel_ID", 0); + try + { + top_block_->connect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, + channels_.at(i)->get_left_block(), 0); + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect signal conditioner " << selected_signal_conditioner_ID << " to channel " << i; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + DLOG(INFO) << "signal conditioner " << selected_signal_conditioner_ID << " connected to channel " << i; + } // Signal Source > Signal conditioner >> Channels >> Observables try { @@ -367,7 +432,10 @@ void GNSSFlowgraph::connect() LOG(INFO) << "Channel " << i << " assigned to " << channels_.at(i)->get_signal(); if (channels_state_[i] == 1) { - channels_.at(i)->start_acquisition(); + if (FPGA_enabled == false) + { + channels_.at(i)->start_acquisition(); + } LOG(INFO) << "Channel " << i << " connected to observables and ready for acquisition"; } else @@ -674,6 +742,18 @@ void GNSSFlowgraph::set_configuration(std::shared_ptr co } +void GNSSFlowgraph::start_acquisition_helper() +{ + for (unsigned int i = 0; i < channels_count_; i++) + { + if (channels_state_[i] == 1) + { + channels_.at(i)->start_acquisition(); + } + } +} + + void GNSSFlowgraph::init() { /* @@ -748,7 +828,7 @@ void GNSSFlowgraph::init() std::cout << "Please update your configuration file." << std::endl; } - std::shared_ptr>> channels = block_factory_->GetChannels(configuration_, queue_); + std::shared_ptr > > channels = block_factory_->GetChannels(configuration_, queue_); channels_count_ = channels->size(); for (unsigned int i = 0; i < channels_count_; i++) @@ -772,15 +852,6 @@ void GNSSFlowgraph::set_signals_list() // Set a sequential list of GNSS satellites std::set::const_iterator available_gnss_prn_iter; - // Read GNSS systems and signals - unsigned int total_channels = configuration_->property("Channels_1C.count", 0) + - configuration_->property("Channels_1B.count", 0) + - configuration_->property("Channels_1G.count", 0) + - configuration_->property("Channels_2S.count", 0) + - configuration_->property("Channels_2G.count", 0) + - configuration_->property("Channels_5X.count", 0) + - configuration_->property("Channels_L5.count", 0); - // Create the lists of GNSS satellites std::set available_gps_prn = {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, diff --git a/src/core/receiver/gnss_flowgraph.h b/src/core/receiver/gnss_flowgraph.h index a6915e97e..c17ecb827 100644 --- a/src/core/receiver/gnss_flowgraph.h +++ b/src/core/receiver/gnss_flowgraph.h @@ -41,6 +41,8 @@ #include "gnss_sdr_sample_counter.h" #include #include +#include +#include #include #include #include @@ -48,6 +50,9 @@ #include #include +#if ENABLE_FPGA +#include "gnss_sdr_time_counter.h" +#endif class GNSSBlockInterface; class ChannelInterface; @@ -89,6 +94,8 @@ public: void wait(); + void start_acquisition_helper(); + /*! * \brief Applies an action to the flow graph * @@ -146,6 +153,11 @@ private: std::vector> channels_; gnss_sdr_sample_counter_sptr ch_out_sample_counter; +#if ENABLE_FPGA + gnss_sdr_time_counter_sptr time_counter_; +#endif + gr::blocks::null_source::sptr null_source_; + gr::blocks::throttle::sptr throttle_; gr::top_block_sptr top_block_; gr::msg_queue::sptr queue_; std::list available_GNSS_signals_; diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc index 5cb24b330..797f2c3d9 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc @@ -33,6 +33,7 @@ #include #include +#include #include #include #include // to test the FPGA we have to create a simultaneous task to send the samples using the DMA and stop the test @@ -53,7 +54,8 @@ #include "tracking_interface.h" #include "in_memory_configuration.h" #include "gnss_synchro.h" -#include "gps_l1_ca_dll_pll_c_aid_tracking_fpga.h" +//#include "gps_l1_ca_dll_pll_c_aid_tracking_fpga.h" +#include "gps_l1_ca_dll_pll_tracking_fpga.h" #include "tracking_true_obs_reader.h" #include "tracking_dump_reader.h" #include "signal_generator_flags.h" @@ -308,8 +310,10 @@ void GpsL1CADllPllTrackingTestFpga::configure_receiver() config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); // Set Tracking + //config->set_property("Tracking_1C.implementation", + // "GPS_L1_CA_DLL_PLL_C_Aid_Tracking_Fpga"); config->set_property("Tracking_1C.implementation", - "GPS_L1_CA_DLL_PLL_C_Aid_Tracking_Fpga"); + "GPS_L1_CA_DLL_PLL_Tracking_Fpga"); config->set_property("Tracking_1C.item_type", "cshort"); config->set_property("Tracking_1C.if", "0"); config->set_property("Tracking_1C.dump", "true"); @@ -466,7 +470,8 @@ TEST_F(GpsL1CADllPllTrackingTestFpga, ValidationOfResultsFpga) << "Failure opening true observables file"; top_block = gr::make_top_block("Tracking test"); - std::shared_ptr tracking = std::make_shared(config.get(), "Tracking_1C", 1, 1); + //std::shared_ptr tracking = std::make_shared (config.get(), "Tracking_1C", 1, 1); + std::shared_ptr tracking = std::make_shared(config.get(), "Tracking_1C", 1, 1); boost::shared_ptr msg_rx = GpsL1CADllPllTrackingTestFpga_msg_rx_make();