mirror of https://github.com/gnss-sdr/gnss-sdr
260 lines
9.3 KiB
C++
260 lines
9.3 KiB
C++
/*!
|
|
* \file fpga_buffer_monitor.cc
|
|
* \brief Check receiver buffer overflow and monitor the status of the receiver
|
|
* buffers.
|
|
* \authors
|
|
* <ul>
|
|
* <li> Marc Majoral, 2021. mmajoral(at)cttc.es
|
|
* </ul>
|
|
*
|
|
* Class that checks the receiver buffer overflow flags and monitors the status
|
|
* of the receiver buffers.
|
|
*
|
|
*
|
|
* -----------------------------------------------------------------------------
|
|
*
|
|
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
|
* This file is part of GNSS-SDR.
|
|
*
|
|
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* -----------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "fpga_buffer_monitor.h"
|
|
#include "gnss_sdr_create_directory.h"
|
|
#include "gnss_sdr_filesystem.h"
|
|
#include <glog/logging.h>
|
|
#include <ctime> // for time, localtime
|
|
#include <fcntl.h> // for open, O_RDWR, O_SYNC
|
|
#include <fstream> // for string, ofstream
|
|
#include <iostream> // for cout
|
|
#include <sys/mman.h> // for mmap
|
|
#include <unistd.h> // for close
|
|
#include <utility> // for move
|
|
|
|
|
|
Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name,
|
|
uint32_t num_freq_bands,
|
|
bool dump,
|
|
std::string dump_filename)
|
|
: d_dump_filename(std::move(dump_filename)),
|
|
d_num_freq_bands(num_freq_bands),
|
|
d_max_buff_occ_freq_band_0(0),
|
|
d_max_buff_occ_freq_band_1(0),
|
|
d_dump(dump)
|
|
{
|
|
// open device descriptor
|
|
if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1)
|
|
{
|
|
LOG(WARNING) << "Cannot open deviceio" << device_name;
|
|
}
|
|
|
|
// device memory map
|
|
d_map_base = reinterpret_cast<volatile unsigned *>(mmap(nullptr, FPGA_PAGE_SIZE,
|
|
PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0));
|
|
|
|
if (d_map_base == reinterpret_cast<void *>(-1))
|
|
{
|
|
LOG(WARNING) << "Cannot map the FPGA buffer monitor module";
|
|
std::cout << "Could not map the FPGA buffer monitor \n";
|
|
}
|
|
|
|
// sanity check: check test register
|
|
if (buffer_monitor_test_register() < 0)
|
|
{
|
|
LOG(WARNING) << "FPGA buffer monitor test register sanity check failed";
|
|
std::cout << "FPGA buffer monitor test register sanity check failed\n";
|
|
}
|
|
else
|
|
{
|
|
LOG(INFO) << "FPGA buffer monitor test register sanity check success !";
|
|
}
|
|
|
|
DLOG(INFO) << "FPGA buffer monitor class created";
|
|
|
|
if (d_dump)
|
|
{
|
|
std::string dump_path;
|
|
// Get path
|
|
if (d_dump_filename.find_last_of('/') != std::string::npos)
|
|
{
|
|
const std::string dump_filename_ = d_dump_filename.substr(d_dump_filename.find_last_of('/') + 1);
|
|
dump_path = d_dump_filename.substr(0, d_dump_filename.find_last_of('/'));
|
|
d_dump_filename = dump_filename_;
|
|
}
|
|
else
|
|
{
|
|
dump_path = std::string(".");
|
|
}
|
|
if (d_dump_filename.empty())
|
|
{
|
|
d_dump_filename = "FPGA_buffer_monitor_dump";
|
|
}
|
|
// remove extension if any
|
|
if (d_dump_filename.substr(1).find_last_of('.') != std::string::npos)
|
|
{
|
|
d_dump_filename = d_dump_filename.substr(0, d_dump_filename.find_last_of('.'));
|
|
}
|
|
d_dump_filename = dump_path + fs::path::preferred_separator + d_dump_filename;
|
|
// create directory
|
|
if (!gnss_sdr_create_directory(dump_path))
|
|
{
|
|
std::cerr << "GNSS-SDR cannot create dump file for the Buffer Monitor block. Wrong permissions?\n";
|
|
d_dump = false;
|
|
}
|
|
|
|
std::string dump_filename_ = d_dump_filename;
|
|
dump_filename_.append(".dat");
|
|
|
|
if (!d_dump_file.is_open())
|
|
{
|
|
try
|
|
{
|
|
d_dump_file.exceptions(std::ofstream::failbit | std::ofstream::badbit);
|
|
d_dump_file.open(dump_filename_.c_str(), std::ios::out | std::ios::binary);
|
|
LOG(INFO) << "FPGA buffer monitor dump enabled. Log file: " << dump_filename_.c_str();
|
|
}
|
|
catch (const std::ofstream::failure &e)
|
|
{
|
|
LOG(WARNING) << "Exception opening FPGA buffer monitor dump file " << e.what();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Fpga_buffer_monitor::~Fpga_buffer_monitor()
|
|
{
|
|
close_device();
|
|
|
|
if (d_dump)
|
|
{
|
|
if (d_dump_file.is_open())
|
|
{
|
|
try
|
|
{
|
|
d_dump_file.close();
|
|
}
|
|
catch (const std::exception &ex)
|
|
{
|
|
LOG(WARNING) << "Exception in FPGA buffer monitor destructor: " << ex.what();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Fpga_buffer_monitor::check_buffer_overflow_and_monitor_buffer_status()
|
|
{
|
|
// check buffer overflow flags
|
|
uint32_t buffer_overflow_status = d_map_base[overflow_flags_reg_addr];
|
|
|
|
if ((buffer_overflow_status & overflow_freq_band_0_bit_pos) != 0)
|
|
{
|
|
if (d_num_freq_bands > 1)
|
|
{
|
|
LOG(ERROR) << "FPGA Buffer overflow in frequency band 0";
|
|
}
|
|
else
|
|
{
|
|
LOG(ERROR) << "FPGA Buffer overflow";
|
|
}
|
|
}
|
|
|
|
if (d_num_freq_bands > 1)
|
|
{
|
|
if ((buffer_overflow_status & overflow_freq_band_1_bit_pos) != 0)
|
|
{
|
|
LOG(ERROR) << "FPGA Buffer overflow in frequency band 1";
|
|
}
|
|
}
|
|
|
|
// buffer monitor
|
|
if (d_dump == 1)
|
|
{
|
|
uint32_t current_buff_occ_freq_band_0 = d_map_base[current_buff_occ_freq_band_0_reg_addr] * num_sapmples_per_buffer_element;
|
|
uint32_t temp_max_buff_occ_freq_band_0 = d_map_base[max_buff_occ_freq_band_0_reg_addr] * num_sapmples_per_buffer_element;
|
|
if (temp_max_buff_occ_freq_band_0 > d_max_buff_occ_freq_band_0)
|
|
{
|
|
d_max_buff_occ_freq_band_0 = temp_max_buff_occ_freq_band_0;
|
|
}
|
|
|
|
time_t rawtime;
|
|
struct tm *timeinfo;
|
|
char buff_time_ch[80];
|
|
|
|
time(&rawtime);
|
|
timeinfo = localtime(&rawtime);
|
|
|
|
strftime(buff_time_ch, sizeof(buff_time_ch), "%d-%m-%Y %H:%M:%S", timeinfo);
|
|
std::string buffer_time(buff_time_ch);
|
|
d_dump_file << buffer_time << " ";
|
|
|
|
std::string buffer_txt;
|
|
// current buffer occupancy frequency band 0 (number of samples)
|
|
buffer_txt = std::to_string(current_buff_occ_freq_band_0);
|
|
d_dump_file << buffer_txt << " ";
|
|
// temporary maximum buffer occupancy frequency band 0 (number of samples)
|
|
buffer_txt = std::to_string(temp_max_buff_occ_freq_band_0);
|
|
d_dump_file << buffer_txt << " ";
|
|
// maximum buffer occupancy frequency band 0 (number of samples)
|
|
buffer_txt = std::to_string(d_max_buff_occ_freq_band_0);
|
|
d_dump_file << buffer_txt;
|
|
|
|
if (d_num_freq_bands > 1)
|
|
{
|
|
d_dump_file << " ";
|
|
uint32_t current_buff_occ_freq_band_1 = d_map_base[current_buff_occ_freq_band_1_reg_addr] * num_sapmples_per_buffer_element;
|
|
uint32_t temp_max_buff_occ_freq_band_1 = d_map_base[max_buff_occ_freq_band_1_reg_addr] * num_sapmples_per_buffer_element;
|
|
if (temp_max_buff_occ_freq_band_1 > d_max_buff_occ_freq_band_1)
|
|
{
|
|
d_max_buff_occ_freq_band_1 = temp_max_buff_occ_freq_band_1;
|
|
}
|
|
|
|
// current buffer occupancy frequency band 1 (number of samples)
|
|
buffer_txt = std::to_string(current_buff_occ_freq_band_1);
|
|
d_dump_file << buffer_txt << " ";
|
|
// temporary maximum buffer occupancy frequency band 1 (number of samples)
|
|
buffer_txt = std::to_string(temp_max_buff_occ_freq_band_1);
|
|
d_dump_file << buffer_txt << " ";
|
|
// maximum buffer occupancy frequency band 1 (number of samples)
|
|
buffer_txt = std::to_string(d_max_buff_occ_freq_band_1);
|
|
d_dump_file << buffer_txt << std::endl;
|
|
}
|
|
else
|
|
{
|
|
d_dump_file << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int32_t Fpga_buffer_monitor::buffer_monitor_test_register()
|
|
{
|
|
// write value to test register
|
|
d_map_base[test_reg_addr] = test_register_writeval;
|
|
// read value from test register
|
|
uint32_t readval = d_map_base[test_reg_addr];
|
|
|
|
if (test_register_writeval != readval)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void Fpga_buffer_monitor::close_device()
|
|
{
|
|
auto *aux = const_cast<unsigned *>(d_map_base);
|
|
if (munmap(static_cast<void *>(aux), FPGA_PAGE_SIZE) == -1)
|
|
{
|
|
std::cout << "Failed to unmap memory uio\n";
|
|
}
|
|
|
|
close(d_device_descriptor);
|
|
}
|