2017-05-05 14:14:27 +00:00
|
|
|
/*!
|
2018-04-27 18:00:50 +00:00
|
|
|
* \file fpga_acquisition.cc
|
2017-05-05 14:14:27 +00:00
|
|
|
* \brief High optimized FPGA vector correlator class
|
|
|
|
* \authors <ul>
|
2018-04-27 18:00:50 +00:00
|
|
|
* <li> Marc Majoral, 2018. mmajoral(at)cttc.cat
|
|
|
|
* </ul>
|
2017-05-05 14:14:27 +00:00
|
|
|
*
|
2018-04-27 18:00:50 +00:00
|
|
|
* Class that controls and executes a high optimized acquisition HW
|
|
|
|
* accelerator in the FPGA
|
2017-05-05 14:14:27 +00:00
|
|
|
*
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
*
|
2018-05-13 20:49:11 +00:00
|
|
|
* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors)
|
2017-05-05 14:14:27 +00:00
|
|
|
*
|
|
|
|
* 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
|
2018-05-13 20:49:11 +00:00
|
|
|
* along with GNSS-SDR. If not, see <https://www.gnu.org/licenses/>.
|
2017-05-05 14:14:27 +00:00
|
|
|
*
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2018-04-30 09:59:56 +00:00
|
|
|
#include "fpga_acquisition.h"
|
2018-04-30 18:58:53 +00:00
|
|
|
#include "GPS_L1_CA.h"
|
2018-04-30 09:59:56 +00:00
|
|
|
#include "gps_sdr_signal_processing.h"
|
2018-04-30 18:58:53 +00:00
|
|
|
#include <glog/logging.h>
|
2018-08-11 10:56:52 +00:00
|
|
|
#include <iostream>
|
2018-04-30 18:58:53 +00:00
|
|
|
#include <fcntl.h> // libraries used by the GIPO
|
|
|
|
#include <sys/mman.h> // libraries used by the GIPO
|
|
|
|
|
2018-04-30 09:59:56 +00:00
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
#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
|
2018-04-30 09:59:56 +00:00
|
|
|
|
2018-08-01 13:55:40 +00:00
|
|
|
// 12-bits
|
|
|
|
//#define SELECT_LSBits 0x0FFF
|
|
|
|
//#define SELECT_MSBbits 0x00FFF000
|
|
|
|
//#define SELECT_24_BITS 0x00FFFFFF
|
|
|
|
//#define SHL_12_BITS 4096
|
|
|
|
// 16-bits
|
|
|
|
#define SELECT_LSBits 0x0FFFF
|
|
|
|
#define SELECT_MSBbits 0xFFFF0000
|
|
|
|
#define SELECT_32_BITS 0xFFFFFFFF
|
|
|
|
#define SHL_16_BITS 65536
|
|
|
|
|
2017-05-05 14:14:27 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
bool fpga_acquisition::init()
|
2017-05-08 21:03:42 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib init called\n");
|
2017-05-18 15:10:28 +00:00
|
|
|
// configure the acquisition with the main initialization values
|
2018-04-27 18:00:50 +00:00
|
|
|
fpga_acquisition::configure_acquisition();
|
2017-05-18 15:10:28 +00:00
|
|
|
return true;
|
|
|
|
}
|
2017-05-08 21:03:42 +00:00
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-08-11 09:42:07 +00:00
|
|
|
bool fpga_acquisition::set_local_code(uint32_t PRN)
|
2017-05-18 15:10:28 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib set_local_code_called\n");
|
2017-06-08 15:29:45 +00:00
|
|
|
// select the code with the chosen PRN
|
2018-04-27 18:00:50 +00:00
|
|
|
fpga_acquisition::fpga_configure_acquisition_local_code(
|
2018-04-30 18:58:53 +00:00
|
|
|
&d_all_fft_codes[d_nsamples_total * (PRN - 1)]);
|
2018-08-01 13:55:40 +00:00
|
|
|
|
|
|
|
//fpga_acquisition::fpga_configure_acquisition_local_code(
|
|
|
|
// &d_all_fft_codes[0]);
|
|
|
|
|
2017-05-05 14:14:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
fpga_acquisition::fpga_acquisition(std::string device_name,
|
2018-08-11 09:42:07 +00:00
|
|
|
uint32_t nsamples,
|
|
|
|
uint32_t doppler_max,
|
|
|
|
uint32_t nsamples_total, int64_t fs_in,
|
|
|
|
uint32_t sampled_ms, uint32_t select_queue,
|
2018-04-30 18:58:53 +00:00
|
|
|
lv_16sc_t *all_fft_codes)
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib constructor called\n");
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("AAA- sampled_ms = %d\n ", sampled_ms);
|
|
|
|
|
2018-08-11 10:56:52 +00:00
|
|
|
uint32_t vector_length = nsamples_total; // * sampled_ms;
|
2018-08-01 13:55:40 +00:00
|
|
|
|
|
|
|
//printf("AAA- vector_length = %d\n ", vector_length);
|
2017-06-08 15:29:45 +00:00
|
|
|
// initial values
|
|
|
|
d_device_name = device_name;
|
2018-08-07 16:56:54 +00:00
|
|
|
//d_freq = freq;
|
2017-05-18 15:10:28 +00:00
|
|
|
d_fs_in = fs_in;
|
|
|
|
d_vector_length = vector_length;
|
2018-04-30 18:58:53 +00:00
|
|
|
d_nsamples = nsamples; // number of samples not including padding
|
2017-05-18 15:10:28 +00:00
|
|
|
d_select_queue = select_queue;
|
2018-03-02 11:23:10 +00:00
|
|
|
d_nsamples_total = nsamples_total;
|
|
|
|
d_doppler_max = doppler_max;
|
2017-05-18 15:10:28 +00:00
|
|
|
d_doppler_step = 0;
|
2018-04-30 18:58:53 +00:00
|
|
|
d_fd = 0; // driver descriptor
|
|
|
|
d_map_base = nullptr; // driver memory map
|
2018-04-27 18:00:50 +00:00
|
|
|
d_all_fft_codes = all_fft_codes;
|
2017-05-05 14:14:27 +00:00
|
|
|
|
2018-03-02 11:23:10 +00:00
|
|
|
// 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;
|
2018-08-01 13:55:40 +00:00
|
|
|
std::cout << "Acq: cannot open deviceio" << d_device_name << std::endl;
|
2017-06-08 15:29:45 +00:00
|
|
|
}
|
2018-08-29 16:20:41 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
//printf("acq lib DEVICE OPENED CORRECTLY\n");
|
|
|
|
}
|
2018-08-11 09:42:07 +00:00
|
|
|
d_map_base = reinterpret_cast<volatile uint32_t *>(mmap(NULL, PAGE_SIZE,
|
2018-04-30 18:58:53 +00:00
|
|
|
PROT_READ | PROT_WRITE, MAP_SHARED, d_fd, 0));
|
2018-04-27 18:00:50 +00:00
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
if (d_map_base == reinterpret_cast<void *>(-1))
|
2018-03-02 11:23:10 +00:00
|
|
|
{
|
|
|
|
LOG(WARNING) << "Cannot map the FPGA acquisition module into user memory";
|
2018-08-01 13:55:40 +00:00
|
|
|
std::cout << "Acq: cannot map deviceio" << d_device_name << std::endl;
|
2018-03-02 11:23:10 +00:00
|
|
|
}
|
2018-08-29 16:20:41 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
//printf("acq lib MAP BASE MAPPED CORRECTLY\n");
|
|
|
|
}
|
2018-04-27 18:00:50 +00:00
|
|
|
|
2018-03-02 11:23:10 +00:00
|
|
|
// sanity check : check test register
|
2018-08-11 09:42:07 +00:00
|
|
|
uint32_t writeval = TEST_REG_SANITY_CHECK;
|
|
|
|
uint32_t readval;
|
2018-04-27 18:00:50 +00:00
|
|
|
readval = fpga_acquisition::fpga_acquisition_test_register(writeval);
|
2018-03-02 11:23:10 +00:00
|
|
|
if (writeval != readval)
|
|
|
|
{
|
|
|
|
LOG(WARNING) << "Acquisition test register sanity check failed";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-04-30 18:58:53 +00:00
|
|
|
LOG(INFO) << "Acquisition test register sanity check success!";
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib REG SANITY CHECK SUCCESS\n");
|
2018-08-01 13:55:40 +00:00
|
|
|
//std::cout << "Acquisition test register sanity check success!" << std::endl;
|
2018-03-02 11:23:10 +00:00
|
|
|
}
|
2018-04-27 18:00:50 +00:00
|
|
|
fpga_acquisition::reset_acquisition();
|
2018-09-12 14:02:23 +00:00
|
|
|
|
|
|
|
// flag used for testing purposes
|
|
|
|
d_single_doppler_flag = 0;
|
|
|
|
|
2018-03-02 11:23:10 +00:00
|
|
|
DLOG(INFO) << "Acquisition FPGA class created";
|
2018-09-12 14:02:23 +00:00
|
|
|
|
2017-05-05 14:14:27 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
fpga_acquisition::~fpga_acquisition()
|
2017-05-18 15:10:28 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib destructor called\n");
|
2018-03-02 11:23:10 +00:00
|
|
|
close_device();
|
2017-05-18 15:10:28 +00:00
|
|
|
}
|
2017-05-05 14:14:27 +00:00
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
bool fpga_acquisition::free()
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib free called\n");
|
2017-05-05 14:14:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-08-11 09:42:07 +00:00
|
|
|
uint32_t fpga_acquisition::fpga_acquisition_test_register(uint32_t writeval)
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib test register called\n");
|
2018-08-11 09:42:07 +00:00
|
|
|
uint32_t readval;
|
2017-05-08 21:03:42 +00:00
|
|
|
// 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;
|
2017-05-05 14:14:27 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
void fpga_acquisition::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[])
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-11 10:56:52 +00:00
|
|
|
uint32_t local_code;
|
2018-08-11 09:42:07 +00:00
|
|
|
uint32_t k, tmp, tmp2;
|
|
|
|
uint32_t fft_data;
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib fpga_configure_acquisition_local_code_called\n");
|
2017-05-08 21:03:42 +00:00
|
|
|
// clear memory address counter
|
2018-08-01 13:55:40 +00:00
|
|
|
//d_map_base[6] = LOCAL_CODE_CLEAR_MEM;
|
|
|
|
d_map_base[9] = LOCAL_CODE_CLEAR_MEM;
|
2018-03-02 11:23:10 +00:00
|
|
|
// write local code
|
2017-05-18 15:10:28 +00:00
|
|
|
for (k = 0; k < d_vector_length; k++)
|
2017-05-08 21:03:42 +00:00
|
|
|
{
|
|
|
|
tmp = fft_local_code[k].real();
|
|
|
|
tmp2 = fft_local_code[k].imag();
|
2018-08-01 13:55:40 +00:00
|
|
|
//tmp = k;
|
|
|
|
//tmp2 = k;
|
|
|
|
|
|
|
|
//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);
|
|
|
|
//local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_12_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part
|
|
|
|
local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_16_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part
|
|
|
|
//fft_data = MEM_LOCAL_CODE_WR_ENABLE | (local_code & SELECT_24_BITS);
|
|
|
|
fft_data = local_code & SELECT_32_BITS;
|
|
|
|
d_map_base[6] = fft_data;
|
|
|
|
|
|
|
|
|
|
|
|
//printf("debug local code %d real = %d imag = %d local_code = %d fft_data = %d\n", k, tmp, tmp2, local_code, fft_data);
|
|
|
|
//printf("debug local code %d real = 0x%08X imag = 0x%08X local_code = 0x%08X fft_data = 0x%08X\n", k, tmp, tmp2, local_code, fft_data);
|
2017-05-08 21:03:42 +00:00
|
|
|
}
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("d_vector_length = %d\n", d_vector_length);
|
|
|
|
//while(1);
|
2017-05-05 14:14:27 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
void fpga_acquisition::run_acquisition(void)
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib run_acqisition called\n");
|
2017-05-08 21:03:42 +00:00
|
|
|
// enable interrupts
|
2018-08-11 09:42:07 +00:00
|
|
|
int32_t reenable = 1;
|
|
|
|
write(d_fd, reinterpret_cast<void *>(&reenable), sizeof(int32_t));
|
2018-03-02 11:23:10 +00:00
|
|
|
// launch the acquisition process
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib launchin acquisition ...\n");
|
2018-08-01 13:55:40 +00:00
|
|
|
d_map_base[8] = LAUNCH_ACQUISITION; // writing a 1 to reg 8 launches the acquisition process
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib waiting for interrupt ...\n");
|
2018-08-11 09:42:07 +00:00
|
|
|
int32_t irq_count;
|
2017-05-05 14:14:27 +00:00
|
|
|
ssize_t nb;
|
|
|
|
// wait for interrupt
|
2017-06-08 15:29:45 +00:00
|
|
|
nb = read(d_fd, &irq_count, sizeof(irq_count));
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("interrupt received\n");
|
2017-05-05 14:14:27 +00:00
|
|
|
if (nb != sizeof(irq_count))
|
|
|
|
{
|
2018-03-02 11:23:10 +00:00
|
|
|
printf("acquisition module Read failed to retrieve 4 bytes!\n");
|
|
|
|
printf("acquisition module Interrupt number %d\n", irq_count);
|
2017-05-05 14:14:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-08-11 10:56:52 +00:00
|
|
|
void fpga_acquisition::set_doppler_sweep(uint32_t num_sweeps)
|
2018-08-01 13:55:40 +00:00
|
|
|
{
|
2018-09-12 14:02:23 +00:00
|
|
|
if (d_single_doppler_flag == 0)
|
|
|
|
{
|
|
|
|
//printf("acq lib set_doppler_sweep called\n");
|
|
|
|
float phase_step_rad_real;
|
|
|
|
float phase_step_rad_int_temp;
|
|
|
|
int32_t phase_step_rad_int;
|
|
|
|
//int32_t doppler = static_cast<int32_t>(-d_doppler_max) + d_doppler_step * doppler_index;
|
|
|
|
int32_t doppler = static_cast<int32_t>(-d_doppler_max);
|
|
|
|
//float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast<float>(d_fs_in);
|
|
|
|
float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(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)
|
|
|
|
|
|
|
|
//printf("AAA phase_step_rad_real for initial doppler = %f\n", phase_step_rad_real);
|
|
|
|
if (phase_step_rad_real >= 1.0)
|
|
|
|
{
|
|
|
|
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
|
|
|
}
|
|
|
|
//printf("AAA phase_step_rad_real for initial doppler after checking = %f\n", phase_step_rad_real);
|
|
|
|
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
|
|
|
phase_step_rad_int = static_cast<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
|
|
|
|
//printf("AAA writing phase_step_rad_int for initial doppler = %d to d map base 3\n", phase_step_rad_int);
|
|
|
|
d_map_base[3] = phase_step_rad_int;
|
|
|
|
|
|
|
|
// repeat the calculation with the doppler step
|
|
|
|
doppler = static_cast<int32_t>(d_doppler_step);
|
|
|
|
phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(d_fs_in);
|
|
|
|
phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2);
|
|
|
|
//printf("AAA phase_step_rad_real for doppler step = %f\n", phase_step_rad_real);
|
|
|
|
if (phase_step_rad_real >= 1.0)
|
|
|
|
{
|
|
|
|
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
|
|
|
}
|
|
|
|
//printf("AAA phase_step_rad_real for doppler step after checking = %f\n", phase_step_rad_real);
|
|
|
|
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
|
|
|
phase_step_rad_int = static_cast<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
|
|
|
|
//printf("AAA writing phase_step_rad_int for doppler step = %d to d map base 4\n", phase_step_rad_int);
|
|
|
|
d_map_base[4] = phase_step_rad_int;
|
|
|
|
//printf("AAA writing num sweeps to d map base 5 = %d\n", num_sweeps);
|
|
|
|
d_map_base[5] = num_sweeps;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//printf("acq lib set_doppler_sweep called\n");
|
|
|
|
float phase_step_rad_real;
|
|
|
|
float phase_step_rad_int_temp;
|
|
|
|
int32_t phase_step_rad_int;
|
|
|
|
//int32_t doppler = static_cast<int32_t>(-d_doppler_max) + d_doppler_step * doppler_index;
|
|
|
|
int32_t doppler = static_cast<int32_t>(d_doppler_max);
|
|
|
|
//float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast<float>(d_fs_in);
|
|
|
|
float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(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)
|
|
|
|
|
|
|
|
//printf("AAA phase_step_rad_real for initial doppler = %f\n", phase_step_rad_real);
|
|
|
|
if (phase_step_rad_real >= 1.0)
|
|
|
|
{
|
|
|
|
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
|
|
|
}
|
|
|
|
//printf("AAA phase_step_rad_real for initial doppler after checking = %f\n", phase_step_rad_real);
|
|
|
|
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
|
|
|
phase_step_rad_int = static_cast<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
|
|
|
|
//printf("AAA writing phase_step_rad_int for initial doppler = %d to d map base 3\n", phase_step_rad_int);
|
|
|
|
d_map_base[3] = phase_step_rad_int;
|
|
|
|
|
|
|
|
// repeat the calculation with the doppler step
|
2018-10-04 15:49:09 +00:00
|
|
|
doppler = static_cast<int32_t>(d_doppler_step);
|
2018-09-12 14:02:23 +00:00
|
|
|
phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(d_fs_in);
|
|
|
|
phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2);
|
|
|
|
//printf("AAA phase_step_rad_real for doppler step = %f\n", phase_step_rad_real);
|
|
|
|
if (phase_step_rad_real >= 1.0)
|
|
|
|
{
|
|
|
|
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
|
|
|
}
|
|
|
|
//printf("AAA phase_step_rad_real for doppler step after checking = %f\n", phase_step_rad_real);
|
|
|
|
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
|
|
|
phase_step_rad_int = static_cast<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
|
|
|
|
//printf("AAA writing phase_step_rad_int for doppler step = %d to d map base 4\n", phase_step_rad_int);
|
|
|
|
d_map_base[4] = phase_step_rad_int;
|
|
|
|
//printf("AAA writing num sweeps to d map base 5 = %d\n", num_sweeps);
|
|
|
|
d_map_base[5] = 1; // 1 sweep
|
|
|
|
|
|
|
|
}
|
2018-08-01 13:55:40 +00:00
|
|
|
|
|
|
|
}
|
2018-09-12 14:02:23 +00:00
|
|
|
/*
|
2018-08-11 10:56:52 +00:00
|
|
|
void fpga_acquisition::set_doppler_sweep_debug(uint32_t num_sweeps, uint32_t doppler_index)
|
2018-08-01 13:55:40 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib set_doppler_sweep_debug called\n");
|
2018-08-01 13:55:40 +00:00
|
|
|
float phase_step_rad_real;
|
|
|
|
float phase_step_rad_int_temp;
|
|
|
|
int32_t phase_step_rad_int;
|
2018-08-11 10:56:52 +00:00
|
|
|
int32_t doppler = -static_cast<int32_t>(d_doppler_max) + d_doppler_step * doppler_index;
|
|
|
|
//int32_t doppler = static_cast<int32_t>(-d_doppler_max);
|
2018-08-07 16:56:54 +00:00
|
|
|
//float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast<float>(d_fs_in);
|
|
|
|
float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(d_fs_in);
|
2018-08-01 13:55:40 +00:00
|
|
|
// 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)
|
|
|
|
|
|
|
|
//printf("AAAh phase_step_rad_real for initial doppler = %f\n", phase_step_rad_real);
|
|
|
|
if (phase_step_rad_real >= 1.0)
|
|
|
|
{
|
|
|
|
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
|
|
|
}
|
|
|
|
//printf("AAAh phase_step_rad_real for initial doppler after checking = %f\n", phase_step_rad_real);
|
2018-08-11 10:56:52 +00:00
|
|
|
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
|
|
|
phase_step_rad_int = static_cast<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
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("AAAh writing phase_step_rad_int for initial doppler = %d to d map base 3\n", phase_step_rad_int);
|
|
|
|
d_map_base[3] = phase_step_rad_int;
|
|
|
|
|
|
|
|
// repeat the calculation with the doppler step
|
2018-08-11 10:56:52 +00:00
|
|
|
doppler = static_cast<int32_t>(d_doppler_step);
|
2018-08-01 13:55:40 +00:00
|
|
|
phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(d_fs_in);
|
|
|
|
phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2);
|
|
|
|
//printf("AAAh phase_step_rad_real for doppler step = %f\n", phase_step_rad_real);
|
|
|
|
if (phase_step_rad_real >= 1.0)
|
|
|
|
{
|
|
|
|
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
|
|
|
}
|
|
|
|
//printf("AAAh phase_step_rad_real for doppler step after checking = %f\n", phase_step_rad_real);
|
2018-08-11 10:56:52 +00:00
|
|
|
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
|
|
|
phase_step_rad_int = static_cast<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
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("AAAh writing phase_step_rad_int for doppler step = %d to d map base 4\n", phase_step_rad_int);
|
|
|
|
d_map_base[4] = phase_step_rad_int;
|
|
|
|
//printf("AAAh writing num sweeps to d map base 5 = %d\n", num_sweeps);
|
|
|
|
d_map_base[5] = num_sweeps;
|
|
|
|
}
|
2018-09-12 14:02:23 +00:00
|
|
|
*/
|
2018-08-01 13:55:40 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
void fpga_acquisition::configure_acquisition()
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib configure acquisition called\n");
|
2018-08-11 10:56:52 +00:00
|
|
|
//printf("AAA d_select_queue = %d\n", d_select_queue);
|
2017-05-08 21:03:42 +00:00
|
|
|
d_map_base[0] = d_select_queue;
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("AAA writing d_vector_length = %d to d map base 1\n ", d_vector_length);
|
2017-05-18 15:10:28 +00:00
|
|
|
d_map_base[1] = d_vector_length;
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("AAA writing d_nsamples = %d to d map base 2\n ", d_nsamples);
|
2017-05-08 21:03:42 +00:00
|
|
|
d_map_base[2] = d_nsamples;
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("AAA writing LOG2 d_vector_length = %d to d map base 7\n ", (int)log2((float)d_vector_length));
|
2018-08-11 10:56:52 +00:00
|
|
|
d_map_base[7] = static_cast<int32_t>(log2(static_cast<float>(d_vector_length))); // log2 FFTlength
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("acquisition debug vector length = %d\n", d_vector_length);
|
|
|
|
//printf("acquisition debug vector length = %d\n", (int)log2((float)d_vector_length));
|
2017-05-05 14:14:27 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-08-11 09:42:07 +00:00
|
|
|
void fpga_acquisition::set_phase_step(uint32_t doppler_index)
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib set phase step called\n");
|
2017-05-08 21:03:42 +00:00
|
|
|
float phase_step_rad_real;
|
|
|
|
float phase_step_rad_int_temp;
|
|
|
|
int32_t phase_step_rad_int;
|
2018-08-11 10:56:52 +00:00
|
|
|
int32_t doppler = -static_cast<int32_t>(d_doppler_max) + d_doppler_step * doppler_index;
|
2018-08-07 16:56:54 +00:00
|
|
|
//float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast<float>(d_fs_in);
|
|
|
|
float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(d_fs_in);
|
2017-05-18 15:10:28 +00:00
|
|
|
// 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)
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("AAA+ phase_step_rad_real = %f\n", phase_step_rad_real);
|
2018-03-02 11:23:10 +00:00
|
|
|
if (phase_step_rad_real >= 1.0)
|
2017-05-18 15:10:28 +00:00
|
|
|
{
|
2017-06-08 15:29:45 +00:00
|
|
|
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
2017-05-18 15:10:28 +00:00
|
|
|
}
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("AAA+ phase_step_rad_real after checking = %f\n", phase_step_rad_real);
|
2018-08-11 10:56:52 +00:00
|
|
|
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
|
|
|
phase_step_rad_int = static_cast<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
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("writing phase_step_rad_int = %d to d_map_base 3\n", phase_step_rad_int);
|
2017-05-08 21:03:42 +00:00
|
|
|
d_map_base[3] = phase_step_rad_int;
|
2017-05-05 14:14:27 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
|
|
|
void fpga_acquisition::read_acquisition_results(uint32_t *max_index,
|
2018-08-11 10:56:52 +00:00
|
|
|
float *max_magnitude, uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index)
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib read_acquisition_results_called\n");
|
2018-08-11 10:56:52 +00:00
|
|
|
uint64_t initial_sample_tmp = 0;
|
2018-08-10 11:12:06 +00:00
|
|
|
|
2018-08-11 09:42:07 +00:00
|
|
|
uint32_t readval = 0;
|
2018-08-11 10:56:52 +00:00
|
|
|
uint64_t readval_long = 0;
|
|
|
|
uint64_t readval_long_shifted = 0;
|
2017-05-08 21:03:42 +00:00
|
|
|
readval = d_map_base[1];
|
2018-08-10 11:12:06 +00:00
|
|
|
initial_sample_tmp = readval;
|
|
|
|
readval_long = d_map_base[2];
|
2018-08-11 10:56:52 +00:00
|
|
|
readval_long_shifted = readval_long << 32; // 2^32
|
|
|
|
initial_sample_tmp = initial_sample_tmp + readval_long_shifted; // 2^32
|
2018-08-10 14:42:53 +00:00
|
|
|
//printf("----------------------------------------------------------------> acq initial sample TOTAL = %llu\n", initial_sample_tmp);
|
2018-08-10 11:12:06 +00:00
|
|
|
*initial_sample = initial_sample_tmp;
|
|
|
|
readval = d_map_base[6];
|
2017-08-18 10:45:47 +00:00
|
|
|
*max_magnitude = static_cast<float>(readval);
|
2018-09-12 14:02:23 +00:00
|
|
|
//printf("acq lib read max_magnitude dmap 2 = %d = %f\n", readval, *max_magnitude);
|
2017-05-08 21:03:42 +00:00
|
|
|
readval = d_map_base[4];
|
2017-08-18 10:45:47 +00:00
|
|
|
*power_sum = static_cast<float>(readval);
|
2018-09-12 14:02:23 +00:00
|
|
|
//printf("acq lib read power sum dmap 4 = %d = %f\n", readval, *power_sum);
|
2018-08-11 10:56:52 +00:00
|
|
|
readval = d_map_base[5]; // read doppler index
|
2018-08-01 13:55:40 +00:00
|
|
|
*doppler_index = readval;
|
|
|
|
//printf("read doppler_index dmap 5 = %d\n", readval);
|
2017-05-08 21:03:42 +00:00
|
|
|
readval = d_map_base[3];
|
|
|
|
*max_index = readval;
|
2018-08-01 13:55:40 +00:00
|
|
|
//printf("read max index dmap 3 = %d\n", readval);
|
2017-05-05 14:14:27 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
void fpga_acquisition::block_samples()
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib block samples called\n");
|
2018-04-30 18:58:53 +00:00
|
|
|
d_map_base[14] = 1; // block the samples
|
2017-05-05 14:14:27 +00:00
|
|
|
}
|
|
|
|
|
2017-08-18 10:45:47 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
void fpga_acquisition::unblock_samples()
|
2017-05-05 14:14:27 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib unblock samples called\n");
|
2018-04-30 18:58:53 +00:00
|
|
|
d_map_base[14] = 0; // unblock the samples
|
2017-05-05 14:14:27 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
void fpga_acquisition::close_device()
|
2017-05-18 15:10:28 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib close device called\n");
|
2018-08-11 09:42:07 +00:00
|
|
|
uint32_t *aux = const_cast<uint32_t *>(d_map_base);
|
2018-04-30 18:58:53 +00:00
|
|
|
if (munmap(static_cast<void *>(aux), PAGE_SIZE) == -1)
|
2017-05-18 15:10:28 +00:00
|
|
|
{
|
|
|
|
printf("Failed to unmap memory uio\n");
|
|
|
|
}
|
|
|
|
close(d_fd);
|
|
|
|
}
|
|
|
|
|
2018-04-30 18:58:53 +00:00
|
|
|
|
2018-04-27 18:00:50 +00:00
|
|
|
void fpga_acquisition::reset_acquisition(void)
|
2018-03-02 11:23:10 +00:00
|
|
|
{
|
2018-08-29 16:20:41 +00:00
|
|
|
//printf("acq lib reset acquisition called\n");
|
2018-08-01 13:55:40 +00:00
|
|
|
d_map_base[8] = RESET_ACQUISITION; // writing a 2 to d_map_base[8] resets the multicorrelator
|
2018-03-02 11:23:10 +00:00
|
|
|
}
|
2018-09-12 14:02:23 +00:00
|
|
|
|
|
|
|
// this function is only used for the unit tests
|
|
|
|
void fpga_acquisition::set_single_doppler_flag(unsigned int single_doppler_flag)
|
|
|
|
{
|
|
|
|
d_single_doppler_flag = single_doppler_flag;
|
|
|
|
}
|
|
|
|
|
2018-09-18 09:36:12 +00:00
|
|
|
// this function is only used for the unit tests
|
|
|
|
void fpga_acquisition::read_fpga_total_scale_factor(uint32_t *total_scale_factor, uint32_t *fw_scale_factor)
|
|
|
|
{
|
|
|
|
uint32_t readval = 0;
|
|
|
|
readval = d_map_base[7];
|
|
|
|
*total_scale_factor = readval;
|
|
|
|
readval = d_map_base[8];
|
|
|
|
*fw_scale_factor = readval;
|
|
|
|
}
|