devices: unify band handling
This is basically common, but optional code. Change-Id: I64f5a462451e967d4750d8e4f1d5832cbab41cff
This commit is contained in:
parent
19e134a626
commit
c0f78a37ed
|
@ -47,25 +47,11 @@ extern "C" {
|
||||||
LOGC(DDEV, ERROR) << bladerf_strerror(status); \
|
LOGC(DDEV, ERROR) << bladerf_strerror(status); \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Device Type, Tx-SPS, Rx-SPS */
|
static const dev_map_t dev_param_map{
|
||||||
typedef std::tuple<blade_dev_type, int, int> dev_key;
|
|
||||||
|
|
||||||
/* Device parameter descriptor */
|
|
||||||
struct dev_desc {
|
|
||||||
unsigned channels;
|
|
||||||
double mcr;
|
|
||||||
double rate;
|
|
||||||
double offset;
|
|
||||||
std::string str;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::map<dev_key, dev_desc> dev_param_map{
|
|
||||||
{ std::make_tuple(blade_dev_type::BLADE2, 4, 4), { 1, 26e6, GSMRATE, B2XX_TIMING_4_4SPS, "B200 4 SPS" } },
|
{ std::make_tuple(blade_dev_type::BLADE2, 4, 4), { 1, 26e6, GSMRATE, B2XX_TIMING_4_4SPS, "B200 4 SPS" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::tuple<blade_dev_type, enum gsm_band> dev_band_key;
|
static const power_map_t dev_band_nom_power_param_map{
|
||||||
typedef std::map<dev_band_key, dev_band_desc>::const_iterator dev_band_map_it;
|
|
||||||
static const std::map<dev_band_key, dev_band_desc> dev_band_nom_power_param_map{
|
|
||||||
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_850), { 89.75, 13.3, -7.5 } },
|
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_850), { 89.75, 13.3, -7.5 } },
|
||||||
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_900), { 89.75, 13.3, -7.5 } },
|
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_900), { 89.75, 13.3, -7.5 } },
|
||||||
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_1800), { 89.75, 7.5, -11.0 } },
|
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_1800), { 89.75, 7.5, -11.0 } },
|
||||||
|
@ -85,9 +71,9 @@ static double TxPower2TxGain(const dev_band_desc &desc, double tx_power_dbm)
|
||||||
}
|
}
|
||||||
|
|
||||||
blade_device::blade_device(InterfaceType iface, const struct trx_cfg *cfg)
|
blade_device::blade_device(InterfaceType iface, const struct trx_cfg *cfg)
|
||||||
: RadioDevice(iface, cfg), dev(nullptr), rx_gain_min(0.0), rx_gain_max(0.0), band_ass_curr_sess(false),
|
: RadioDevice(iface, cfg), band_manager(dev_band_nom_power_param_map, dev_param_map), dev(nullptr),
|
||||||
band((enum gsm_band)0), tx_spp(0), rx_spp(0), started(false), aligned(false), drop_cnt(0), prev_ts(0),
|
rx_gain_min(0.0), rx_gain_max(0.0), tx_spp(0), rx_spp(0), started(false), aligned(false), drop_cnt(0),
|
||||||
ts_initial(0), ts_offset(0), async_event_thrd(NULL)
|
prev_ts(0), ts_initial(0), ts_offset(0), async_event_thrd(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,47 +90,6 @@ blade_device::~blade_device()
|
||||||
delete rx_buffers[i];
|
delete rx_buffers[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void blade_device::assign_band_desc(enum gsm_band req_band)
|
|
||||||
{
|
|
||||||
dev_band_map_it it;
|
|
||||||
|
|
||||||
it = dev_band_nom_power_param_map.find(dev_band_key(dev_type, req_band));
|
|
||||||
if (it == dev_band_nom_power_param_map.end()) {
|
|
||||||
dev_desc desc = dev_param_map.at(dev_key(dev_type, tx_sps, rx_sps));
|
|
||||||
LOGC(DDEV, ERROR) << "No Power parameters exist for device " << desc.str << " on band "
|
|
||||||
<< gsm_band_name(req_band) << ", using B210 ones as fallback";
|
|
||||||
it = dev_band_nom_power_param_map.find(dev_band_key(blade_dev_type::BLADE2, req_band));
|
|
||||||
}
|
|
||||||
OSMO_ASSERT(it != dev_band_nom_power_param_map.end())
|
|
||||||
band_desc = it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool blade_device::set_band(enum gsm_band req_band)
|
|
||||||
{
|
|
||||||
if (band_ass_curr_sess && req_band != band) {
|
|
||||||
LOGC(DDEV, ALERT) << "Requesting band " << gsm_band_name(req_band) << " different from previous band "
|
|
||||||
<< gsm_band_name(band);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req_band != band) {
|
|
||||||
band = req_band;
|
|
||||||
assign_band_desc(band);
|
|
||||||
}
|
|
||||||
band_ass_curr_sess = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void blade_device::get_dev_band_desc(dev_band_desc &desc)
|
|
||||||
{
|
|
||||||
if (band == 0) {
|
|
||||||
LOGC(DDEV, ERROR)
|
|
||||||
<< "Power parameters requested before Tx Frequency was set! Providing band 900 by default...";
|
|
||||||
assign_band_desc(GSM_BAND_900);
|
|
||||||
}
|
|
||||||
desc = band_desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void blade_device::init_gains()
|
void blade_device::init_gains()
|
||||||
{
|
{
|
||||||
double tx_gain_min, tx_gain_max;
|
double tx_gain_min, tx_gain_max;
|
||||||
|
@ -457,7 +402,7 @@ bool blade_device::stop()
|
||||||
for (size_t i = 0; i < rx_buffers.size(); i++)
|
for (size_t i = 0; i < rx_buffers.size(); i++)
|
||||||
rx_buffers[i]->reset();
|
rx_buffers[i]->reset();
|
||||||
|
|
||||||
band_ass_curr_sess = false;
|
band_reset();
|
||||||
|
|
||||||
started = false;
|
started = false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -580,27 +525,13 @@ bool blade_device::set_freq(double freq, size_t chan, bool tx)
|
||||||
|
|
||||||
bool blade_device::setTxFreq(double wFreq, size_t chan)
|
bool blade_device::setTxFreq(double wFreq, size_t chan)
|
||||||
{
|
{
|
||||||
uint16_t req_arfcn;
|
|
||||||
enum gsm_band req_band;
|
|
||||||
|
|
||||||
if (chan >= tx_freqs.size()) {
|
if (chan >= tx_freqs.size()) {
|
||||||
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ScopedLock lock(tune_lock);
|
ScopedLock lock(tune_lock);
|
||||||
|
|
||||||
req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100, 0);
|
if (!update_band_from_freq(wFreq, chan, true))
|
||||||
if (req_arfcn == 0xffff) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown ARFCN for Tx Frequency " << wFreq / 1000 << " kHz";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT)
|
|
||||||
<< "Unknown GSM band for Tx Frequency " << wFreq << " Hz (ARFCN " << req_arfcn << " )";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_band(req_band))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!set_freq(wFreq, chan, true))
|
if (!set_freq(wFreq, chan, true))
|
||||||
|
@ -611,27 +542,13 @@ bool blade_device::setTxFreq(double wFreq, size_t chan)
|
||||||
|
|
||||||
bool blade_device::setRxFreq(double wFreq, size_t chan)
|
bool blade_device::setRxFreq(double wFreq, size_t chan)
|
||||||
{
|
{
|
||||||
uint16_t req_arfcn;
|
|
||||||
enum gsm_band req_band;
|
|
||||||
|
|
||||||
if (chan >= rx_freqs.size()) {
|
if (chan >= rx_freqs.size()) {
|
||||||
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ScopedLock lock(tune_lock);
|
ScopedLock lock(tune_lock);
|
||||||
|
|
||||||
req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100, 1);
|
if (!update_band_from_freq(wFreq, chan, false))
|
||||||
if (req_arfcn == 0xffff) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown ARFCN for Rx Frequency " << wFreq / 1000 << " kHz";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT)
|
|
||||||
<< "Unknown GSM band for Rx Frequency " << wFreq << " Hz (ARFCN " << req_arfcn << " )";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_band(req_band))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return set_freq(wFreq, chan, false);
|
return set_freq(wFreq, chan, false);
|
||||||
|
|
|
@ -22,10 +22,12 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "bandmanager.h"
|
||||||
#include "radioDevice.h"
|
#include "radioDevice.h"
|
||||||
#include "smpl_buf.h"
|
#include "smpl_buf.h"
|
||||||
|
|
||||||
|
@ -33,8 +35,6 @@ extern "C" {
|
||||||
#include <osmocom/gsm/gsm_utils.h>
|
#include <osmocom/gsm/gsm_utils.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <bladerf.h>
|
|
||||||
|
|
||||||
enum class blade_dev_type { BLADE1, BLADE2 };
|
enum class blade_dev_type { BLADE1, BLADE2 };
|
||||||
|
|
||||||
struct dev_band_desc {
|
struct dev_band_desc {
|
||||||
|
@ -52,7 +52,21 @@ struct dev_band_desc {
|
||||||
double rxgain2rssioffset_rel; /* dB */
|
double rxgain2rssioffset_rel; /* dB */
|
||||||
};
|
};
|
||||||
|
|
||||||
class blade_device : public RadioDevice {
|
/* Device parameter descriptor */
|
||||||
|
struct dev_desc {
|
||||||
|
unsigned channels;
|
||||||
|
double mcr;
|
||||||
|
double rate;
|
||||||
|
double offset;
|
||||||
|
std::string desc_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
using dev_key = std::tuple<blade_dev_type, int, int>;
|
||||||
|
using dev_band_key = std::tuple<blade_dev_type, enum gsm_band>;
|
||||||
|
using power_map_t = std::map<dev_band_key, dev_band_desc>;
|
||||||
|
using dev_map_t = std::map<dev_key, dev_desc>;
|
||||||
|
|
||||||
|
class blade_device : public RadioDevice, public band_manager<power_map_t, dev_map_t> {
|
||||||
public:
|
public:
|
||||||
blade_device(InterfaceType iface, const struct trx_cfg *cfg);
|
blade_device(InterfaceType iface, const struct trx_cfg *cfg);
|
||||||
~blade_device();
|
~blade_device();
|
||||||
|
@ -153,9 +167,6 @@ class blade_device : public RadioDevice {
|
||||||
|
|
||||||
std::vector<double> tx_gains, rx_gains;
|
std::vector<double> tx_gains, rx_gains;
|
||||||
std::vector<double> tx_freqs, rx_freqs;
|
std::vector<double> tx_freqs, rx_freqs;
|
||||||
bool band_ass_curr_sess; /* true if "band" was set after last POWEROFF */
|
|
||||||
enum gsm_band band;
|
|
||||||
struct dev_band_desc band_desc;
|
|
||||||
size_t tx_spp, rx_spp;
|
size_t tx_spp, rx_spp;
|
||||||
|
|
||||||
bool started;
|
bool started;
|
||||||
|
@ -178,9 +189,6 @@ class blade_device : public RadioDevice {
|
||||||
bool flush_recv(size_t num_pkts);
|
bool flush_recv(size_t num_pkts);
|
||||||
|
|
||||||
bool set_freq(double freq, size_t chan, bool tx);
|
bool set_freq(double freq, size_t chan, bool tx);
|
||||||
void get_dev_band_desc(dev_band_desc &desc);
|
|
||||||
bool set_band(enum gsm_band req_band);
|
|
||||||
void assign_band_desc(enum gsm_band req_band);
|
|
||||||
|
|
||||||
Thread *async_event_thrd;
|
Thread *async_event_thrd;
|
||||||
Mutex tune_lock;
|
Mutex tune_lock;
|
||||||
|
|
|
@ -4,7 +4,7 @@ AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES)
|
||||||
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS)
|
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS)
|
||||||
|
|
||||||
|
|
||||||
noinst_HEADERS = radioDevice.h smpl_buf.h
|
noinst_HEADERS = radioDevice.h smpl_buf.h bandmanager.h
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libdevice_common.la
|
noinst_LTLIBRARIES = libdevice_common.la
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* Author: Eric Wild <ewild@sysmocom.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <osmocom/gsm/gsm_utils.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename powermapt, typename devmapt>
|
||||||
|
class band_manager {
|
||||||
|
using powerkeyt = typename powermapt::key_type;
|
||||||
|
using powermappedt = typename powermapt::mapped_type;
|
||||||
|
using devkeyt = typename devmapt::key_type;
|
||||||
|
const devkeyt &m_dev_type;
|
||||||
|
const powermapt &m_power_map;
|
||||||
|
const devmapt &m_dev_map;
|
||||||
|
powerkeyt m_fallback;
|
||||||
|
enum gsm_band m_band;
|
||||||
|
powermappedt m_band_desc;
|
||||||
|
bool band_ass_curr_sess{}; /* true if "band" was set after last POWEROFF */
|
||||||
|
|
||||||
|
// looks up either first tuple element (->enum) or straight enum
|
||||||
|
template <typename T, typename std::enable_if<std::is_enum<T>::value>::type *dummy = nullptr>
|
||||||
|
auto key_helper(T &t) -> T
|
||||||
|
{
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto key_helper(T t) -> typename std::tuple_element<0, T>::type
|
||||||
|
{
|
||||||
|
return std::get<0>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void assign_band_desc(enum gsm_band req_band)
|
||||||
|
{
|
||||||
|
auto key = key_helper(m_dev_type);
|
||||||
|
auto fallback_key = key_helper(m_fallback);
|
||||||
|
auto it = m_power_map.find({ key, req_band });
|
||||||
|
if (it == m_power_map.end()) {
|
||||||
|
auto desc = m_dev_map.at(m_dev_type);
|
||||||
|
LOGC(DDEV, ERROR) << "No Tx Power measurements exist for device " << desc.desc_str
|
||||||
|
<< " on band " << gsm_band_name(req_band) << ", using fallback..";
|
||||||
|
it = m_power_map.find({ fallback_key, req_band });
|
||||||
|
}
|
||||||
|
OSMO_ASSERT(it != m_power_map.end());
|
||||||
|
m_band_desc = it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_band(enum gsm_band req_band)
|
||||||
|
{
|
||||||
|
if (band_ass_curr_sess && req_band != m_band) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requesting band " << gsm_band_name(req_band)
|
||||||
|
<< " different from previous band " << gsm_band_name(m_band);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req_band != m_band) {
|
||||||
|
m_band = req_band;
|
||||||
|
assign_band_desc(m_band);
|
||||||
|
}
|
||||||
|
band_ass_curr_sess = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
band_manager(const devkeyt &dev_type, const powermapt &power_map, const devmapt &dev_map, powerkeyt fallback)
|
||||||
|
: m_dev_type(dev_type), m_power_map(power_map), m_dev_map(dev_map), m_fallback(fallback),
|
||||||
|
m_band((enum gsm_band)0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
band_manager(const powermapt &power_map, const devmapt &dev_map)
|
||||||
|
: m_dev_type(dev_map.begin()->first), m_power_map(power_map), m_dev_map(dev_map),
|
||||||
|
m_fallback(m_power_map.begin()->first), m_band((enum gsm_band)0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void band_reset()
|
||||||
|
{
|
||||||
|
band_ass_curr_sess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_dev_band_desc(powermappedt &desc)
|
||||||
|
{
|
||||||
|
if (m_band == 0) {
|
||||||
|
LOGC(DDEV, ERROR)
|
||||||
|
<< "Power parameters requested before Tx Frequency was set! Providing band 900 by default...";
|
||||||
|
assign_band_desc(GSM_BAND_900);
|
||||||
|
}
|
||||||
|
desc = m_band_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update_band_from_freq(double wFreq, int chan, bool is_tx)
|
||||||
|
{
|
||||||
|
enum gsm_band req_band;
|
||||||
|
auto dirstr = is_tx ? "Tx" : "Rx";
|
||||||
|
auto req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100, !is_tx);
|
||||||
|
if (req_arfcn == 0xffff) {
|
||||||
|
LOGCHAN(chan, DDEV, ALERT)
|
||||||
|
<< "Unknown ARFCN for " << dirstr << " Frequency " << wFreq / 1000 << " kHz";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) {
|
||||||
|
LOGCHAN(chan, DDEV, ALERT) << "Unknown GSM band for " << dirstr << " Frequency " << wFreq
|
||||||
|
<< " Hz (ARFCN " << req_arfcn << " )";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return set_band(req_band);
|
||||||
|
}
|
||||||
|
};
|
|
@ -52,39 +52,16 @@ extern "C" {
|
||||||
#define LMS_DEV_SDR_MINI_PREFIX_NAME "LimeSDR-Mini"
|
#define LMS_DEV_SDR_MINI_PREFIX_NAME "LimeSDR-Mini"
|
||||||
#define LMS_DEV_NET_MICRO_PREFIX_NAME "LimeNET-Micro"
|
#define LMS_DEV_NET_MICRO_PREFIX_NAME "LimeNET-Micro"
|
||||||
|
|
||||||
/* Device parameter descriptor */
|
|
||||||
struct dev_desc {
|
|
||||||
/* Does LimeSuite allow switching the clock source for this device?
|
|
||||||
* LimeSDR-Mini does not have switches but needs soldering to select
|
|
||||||
* external/internal clock. Any call to LMS_SetClockFreq() will fail.
|
|
||||||
*/
|
|
||||||
bool clock_src_switchable;
|
|
||||||
/* Does LimeSuite allow using REF_INTERNAL for this device?
|
|
||||||
* LimeNET-Micro does not like selecting internal clock
|
|
||||||
*/
|
|
||||||
bool clock_src_int_usable;
|
|
||||||
/* Sample rate coef (without having TX/RX samples per symbol into account) */
|
|
||||||
double rate;
|
|
||||||
/* Sample rate coef (without having TX/RX samples per symbol into account), if multi-arfcn is enabled */
|
|
||||||
double rate_multiarfcn;
|
|
||||||
/* Coefficient multiplied by TX sample rate in order to shift Tx time */
|
|
||||||
double ts_offset_coef;
|
|
||||||
/* Coefficient multiplied by TX sample rate in order to shift Tx time, if multi-arfcn is enabled */
|
|
||||||
double ts_offset_coef_multiarfcn;
|
|
||||||
/* Device Name Prefix as presented by LimeSuite API LMS_GetDeviceInfo() */
|
|
||||||
std::string name_prefix;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::map<enum lms_dev_type, struct dev_desc> dev_param_map {
|
|
||||||
|
static const dev_map_t dev_param_map {
|
||||||
{ LMS_DEV_SDR_USB, { true, true, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_SDR_USB_PREFIX_NAME } },
|
{ LMS_DEV_SDR_USB, { true, true, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_SDR_USB_PREFIX_NAME } },
|
||||||
{ LMS_DEV_SDR_MINI, { false, true, GSMRATE, MCBTS_SPACING, 8.9e-5, 8.2e-5, LMS_DEV_SDR_MINI_PREFIX_NAME } },
|
{ LMS_DEV_SDR_MINI, { false, true, GSMRATE, MCBTS_SPACING, 8.9e-5, 8.2e-5, LMS_DEV_SDR_MINI_PREFIX_NAME } },
|
||||||
{ LMS_DEV_NET_MICRO, { true, false, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_NET_MICRO_PREFIX_NAME } },
|
{ LMS_DEV_NET_MICRO, { true, false, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_NET_MICRO_PREFIX_NAME } },
|
||||||
{ LMS_DEV_UNKNOWN, { true, true, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, "UNKNOWN" } },
|
{ LMS_DEV_UNKNOWN, { true, true, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, "UNKNOWN" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::tuple<lms_dev_type, enum gsm_band> dev_band_key;
|
static const power_map_t dev_band_nom_power_param_map {
|
||||||
typedef std::map<dev_band_key, dev_band_desc>::const_iterator dev_band_map_it;
|
|
||||||
static const std::map<dev_band_key, dev_band_desc> dev_band_nom_power_param_map {
|
|
||||||
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_850), { 73.0, 11.2, -6.0 } },
|
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_850), { 73.0, 11.2, -6.0 } },
|
||||||
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_900), { 73.0, 10.8, -6.0 } },
|
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_900), { 73.0, 10.8, -6.0 } },
|
||||||
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_1800), { 65.0, -3.5, -17.0 } }, /* FIXME: OS#4583: 1800Mhz is failing above TxGain=65, which is around -3.5dBm (already < 0 dBm) */
|
{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_1800), { 65.0, -3.5, -17.0 } }, /* FIXME: OS#4583: 1800Mhz is failing above TxGain=65, which is around -3.5dBm (already < 0 dBm) */
|
||||||
|
@ -122,8 +99,8 @@ static enum lms_dev_type parse_dev_type(lms_device_t *m_lms_dev)
|
||||||
enum lms_dev_type dev_type = it->first;
|
enum lms_dev_type dev_type = it->first;
|
||||||
struct dev_desc desc = it->second;
|
struct dev_desc desc = it->second;
|
||||||
|
|
||||||
if (strncmp(device_info->deviceName, desc.name_prefix.c_str(), desc.name_prefix.length()) == 0) {
|
if (strncmp(device_info->deviceName, desc.desc_str.c_str(), desc.desc_str.length()) == 0) {
|
||||||
LOGC(DDEV, INFO) << "Device identified as " << desc.name_prefix;
|
LOGC(DDEV, INFO) << "Device identified as " << desc.desc_str;
|
||||||
return dev_type;
|
return dev_type;
|
||||||
}
|
}
|
||||||
it++;
|
it++;
|
||||||
|
@ -132,8 +109,9 @@ static enum lms_dev_type parse_dev_type(lms_device_t *m_lms_dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
LMSDevice::LMSDevice(InterfaceType iface, const struct trx_cfg *cfg)
|
LMSDevice::LMSDevice(InterfaceType iface, const struct trx_cfg *cfg)
|
||||||
: RadioDevice(iface, cfg), m_lms_dev(NULL), started(false), band_ass_curr_sess(false), band((enum gsm_band)0),
|
: RadioDevice(iface, cfg),
|
||||||
m_dev_type(LMS_DEV_UNKNOWN)
|
band_manager(m_dev_type, dev_band_nom_power_param_map, dev_param_map, {LMS_DEV_SDR_USB, GSM_BAND_850}), m_lms_dev(NULL),
|
||||||
|
started(false), m_dev_type(LMS_DEV_UNKNOWN)
|
||||||
{
|
{
|
||||||
LOGC(DDEV, INFO) << "creating LMS device...";
|
LOGC(DDEV, INFO) << "creating LMS device...";
|
||||||
|
|
||||||
|
@ -220,47 +198,6 @@ int info_list_find(lms_info_str_t* info_list, unsigned int count, const std::str
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMSDevice::assign_band_desc(enum gsm_band req_band)
|
|
||||||
{
|
|
||||||
dev_band_map_it it;
|
|
||||||
|
|
||||||
it = dev_band_nom_power_param_map.find(dev_band_key(m_dev_type, req_band));
|
|
||||||
if (it == dev_band_nom_power_param_map.end()) {
|
|
||||||
dev_desc desc = dev_param_map.at(m_dev_type);
|
|
||||||
LOGC(DDEV, ERROR) << "No Tx Power measurements exist for device "
|
|
||||||
<< desc.name_prefix << " on band " << gsm_band_name(req_band)
|
|
||||||
<< ", using LimeSDR-USB ones as fallback";
|
|
||||||
it = dev_band_nom_power_param_map.find(dev_band_key(LMS_DEV_SDR_USB, req_band));
|
|
||||||
}
|
|
||||||
OSMO_ASSERT(it != dev_band_nom_power_param_map.end());
|
|
||||||
band_desc = it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LMSDevice::set_band(enum gsm_band req_band)
|
|
||||||
{
|
|
||||||
if (band_ass_curr_sess && req_band != band) {
|
|
||||||
LOGC(DDEV, ALERT) << "Requesting band " << gsm_band_name(req_band)
|
|
||||||
<< " different from previous band " << gsm_band_name(band);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req_band != band) {
|
|
||||||
band = req_band;
|
|
||||||
assign_band_desc(band);
|
|
||||||
}
|
|
||||||
band_ass_curr_sess = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LMSDevice::get_dev_band_desc(dev_band_desc& desc)
|
|
||||||
{
|
|
||||||
if (band == 0) {
|
|
||||||
LOGC(DDEV, ERROR) << "Power parameters requested before Tx Frequency was set! Providing band 900 by default...";
|
|
||||||
assign_band_desc(GSM_BAND_900);
|
|
||||||
}
|
|
||||||
desc = band_desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LMSDevice::open()
|
int LMSDevice::open()
|
||||||
{
|
{
|
||||||
lms_info_str_t* info_list;
|
lms_info_str_t* info_list;
|
||||||
|
@ -466,7 +403,7 @@ bool LMSDevice::stop()
|
||||||
LMS_DestroyStream(m_lms_dev, &m_lms_stream_rx[i]);
|
LMS_DestroyStream(m_lms_dev, &m_lms_stream_rx[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
band_ass_curr_sess = false;
|
band_reset();
|
||||||
|
|
||||||
started = false;
|
started = false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -483,8 +420,8 @@ bool LMSDevice::do_clock_src_freq(enum ReferenceType ref, double freq)
|
||||||
break;
|
break;
|
||||||
case REF_INTERNAL:
|
case REF_INTERNAL:
|
||||||
if (!dev_desc.clock_src_int_usable) {
|
if (!dev_desc.clock_src_int_usable) {
|
||||||
LOGC(DDEV, ERROR) << "Device type " << dev_desc.name_prefix
|
LOGC(DDEV, ERROR)
|
||||||
<< " doesn't support internal reference clock";
|
<< "Device type " << dev_desc.desc_str << " doesn't support internal reference clock";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* According to lms using LMS_CLOCK_EXTREF with a
|
/* According to lms using LMS_CLOCK_EXTREF with a
|
||||||
|
@ -502,8 +439,8 @@ bool LMSDevice::do_clock_src_freq(enum ReferenceType ref, double freq)
|
||||||
if (LMS_SetClockFreq(m_lms_dev, lms_clk_id, freq) < 0)
|
if (LMS_SetClockFreq(m_lms_dev, lms_clk_id, freq) < 0)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
LOGC(DDEV, INFO) << "Device type " << dev_desc.name_prefix
|
LOGC(DDEV, INFO)
|
||||||
<< " doesn't support switching clock source through SW";
|
<< "Device type " << dev_desc.desc_str << " doesn't support switching clock source through SW";
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -996,9 +933,6 @@ bool LMSDevice::updateAlignment(TIMESTAMP timestamp)
|
||||||
|
|
||||||
bool LMSDevice::setTxFreq(double wFreq, size_t chan)
|
bool LMSDevice::setTxFreq(double wFreq, size_t chan)
|
||||||
{
|
{
|
||||||
uint16_t req_arfcn;
|
|
||||||
enum gsm_band req_band;
|
|
||||||
|
|
||||||
if (chan >= chans) {
|
if (chan >= chans) {
|
||||||
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
return false;
|
return false;
|
||||||
|
@ -1006,18 +940,7 @@ bool LMSDevice::setTxFreq(double wFreq, size_t chan)
|
||||||
|
|
||||||
LOGCHAN(chan, DDEV, NOTICE) << "Setting Tx Freq to " << wFreq << " Hz";
|
LOGCHAN(chan, DDEV, NOTICE) << "Setting Tx Freq to " << wFreq << " Hz";
|
||||||
|
|
||||||
req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100 , 0);
|
if (!update_band_from_freq(wFreq, chan, true))
|
||||||
if (req_arfcn == 0xffff) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown ARFCN for Tx Frequency " << wFreq / 1000 << " kHz";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown GSM band for Tx Frequency " << wFreq
|
|
||||||
<< " Hz (ARFCN " << req_arfcn << " )";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_band(req_band))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (LMS_SetLOFrequency(m_lms_dev, LMS_CH_TX, chan, wFreq) < 0) {
|
if (LMS_SetLOFrequency(m_lms_dev, LMS_CH_TX, chan, wFreq) < 0) {
|
||||||
|
@ -1030,23 +953,9 @@ bool LMSDevice::setTxFreq(double wFreq, size_t chan)
|
||||||
|
|
||||||
bool LMSDevice::setRxFreq(double wFreq, size_t chan)
|
bool LMSDevice::setRxFreq(double wFreq, size_t chan)
|
||||||
{
|
{
|
||||||
uint16_t req_arfcn;
|
|
||||||
enum gsm_band req_band;
|
|
||||||
|
|
||||||
LOGCHAN(chan, DDEV, NOTICE) << "Setting Rx Freq to " << wFreq << " Hz";
|
LOGCHAN(chan, DDEV, NOTICE) << "Setting Rx Freq to " << wFreq << " Hz";
|
||||||
|
|
||||||
req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100, 1);
|
if (!update_band_from_freq(wFreq, chan, false))
|
||||||
if (req_arfcn == 0xffff) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown ARFCN for Rx Frequency " << wFreq / 1000 << " kHz";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown GSM band for Rx Frequency " << wFreq
|
|
||||||
<< " Hz (ARFCN " << req_arfcn << " )";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_band(req_band))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (LMS_SetLOFrequency(m_lms_dev, LMS_CH_RX, chan, wFreq) < 0) {
|
if (LMS_SetLOFrequency(m_lms_dev, LMS_CH_RX, chan, wFreq) < 0) {
|
||||||
|
|
|
@ -18,11 +18,13 @@
|
||||||
#ifndef _LMS_DEVICE_H_
|
#ifndef _LMS_DEVICE_H_
|
||||||
#define _LMS_DEVICE_H_
|
#define _LMS_DEVICE_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "radioDevice.h"
|
#include "radioDevice.h"
|
||||||
|
#include "bandmanager.h"
|
||||||
#include "smpl_buf.h"
|
#include "smpl_buf.h"
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -69,8 +71,35 @@ struct dev_band_desc {
|
||||||
double rxgain2rssioffset_rel; /* dB */
|
double rxgain2rssioffset_rel; /* dB */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Device parameter descriptor */
|
||||||
|
struct dev_desc {
|
||||||
|
/* Does LimeSuite allow switching the clock source for this device?
|
||||||
|
* LimeSDR-Mini does not have switches but needs soldering to select
|
||||||
|
* external/internal clock. Any call to LMS_SetClockFreq() will fail.
|
||||||
|
*/
|
||||||
|
bool clock_src_switchable;
|
||||||
|
/* Does LimeSuite allow using REF_INTERNAL for this device?
|
||||||
|
* LimeNET-Micro does not like selecting internal clock
|
||||||
|
*/
|
||||||
|
bool clock_src_int_usable;
|
||||||
|
/* Sample rate coef (without having TX/RX samples per symbol into account) */
|
||||||
|
double rate;
|
||||||
|
/* Sample rate coef (without having TX/RX samples per symbol into account), if multi-arfcn is enabled */
|
||||||
|
double rate_multiarfcn;
|
||||||
|
/* Coefficient multiplied by TX sample rate in order to shift Tx time */
|
||||||
|
double ts_offset_coef;
|
||||||
|
/* Coefficient multiplied by TX sample rate in order to shift Tx time, if multi-arfcn is enabled */
|
||||||
|
double ts_offset_coef_multiarfcn;
|
||||||
|
/* Device Name Prefix as presented by LimeSuite API LMS_GetDeviceInfo() */
|
||||||
|
std::string desc_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
using dev_band_key_t = std::tuple<lms_dev_type, gsm_band>;
|
||||||
|
using power_map_t = std::map<dev_band_key_t, dev_band_desc>;
|
||||||
|
using dev_map_t = std::map<lms_dev_type, struct dev_desc>;
|
||||||
|
|
||||||
/** A class to handle a LimeSuite supported device */
|
/** A class to handle a LimeSuite supported device */
|
||||||
class LMSDevice:public RadioDevice {
|
class LMSDevice:public RadioDevice, public band_manager<power_map_t, dev_map_t> {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
lms_device_t *m_lms_dev;
|
lms_device_t *m_lms_dev;
|
||||||
|
@ -87,9 +116,6 @@ private:
|
||||||
TIMESTAMP ts_initial, ts_offset;
|
TIMESTAMP ts_initial, ts_offset;
|
||||||
|
|
||||||
std::vector<double> tx_gains, rx_gains;
|
std::vector<double> tx_gains, rx_gains;
|
||||||
bool band_ass_curr_sess; /* true if "band" was set after last POWEROFF */
|
|
||||||
enum gsm_band band;
|
|
||||||
struct dev_band_desc band_desc;
|
|
||||||
|
|
||||||
enum lms_dev_type m_dev_type;
|
enum lms_dev_type m_dev_type;
|
||||||
|
|
||||||
|
@ -101,9 +127,6 @@ private:
|
||||||
void update_stream_stats_rx(size_t chan, bool *overrun);
|
void update_stream_stats_rx(size_t chan, bool *overrun);
|
||||||
void update_stream_stats_tx(size_t chan, bool *underrun);
|
void update_stream_stats_tx(size_t chan, bool *underrun);
|
||||||
bool do_clock_src_freq(enum ReferenceType ref, double freq);
|
bool do_clock_src_freq(enum ReferenceType ref, double freq);
|
||||||
void get_dev_band_desc(dev_band_desc& desc);
|
|
||||||
bool set_band(enum gsm_band req_band);
|
|
||||||
void assign_band_desc(enum gsm_band req_band);
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Object constructor */
|
/** Object constructor */
|
||||||
|
|
|
@ -91,19 +91,7 @@ extern "C" {
|
||||||
* USRP1 with timestamps is not supported by UHD.
|
* USRP1 with timestamps is not supported by UHD.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Device Type, Tx-SPS, Rx-SPS */
|
static const dev_map_t dev_param_map {
|
||||||
typedef std::tuple<uhd_dev_type, int, int> dev_key;
|
|
||||||
|
|
||||||
/* Device parameter descriptor */
|
|
||||||
struct dev_desc {
|
|
||||||
unsigned channels;
|
|
||||||
double mcr;
|
|
||||||
double rate;
|
|
||||||
double offset;
|
|
||||||
std::string str;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::map<dev_key, dev_desc> dev_param_map {
|
|
||||||
{ std::make_tuple(USRP2, 1, 1), { 1, 0.0, 390625, 1.2184e-4, "N2XX 1 SPS" } },
|
{ std::make_tuple(USRP2, 1, 1), { 1, 0.0, 390625, 1.2184e-4, "N2XX 1 SPS" } },
|
||||||
{ std::make_tuple(USRP2, 4, 1), { 1, 0.0, 390625, 7.6547e-5, "N2XX 4/1 Tx/Rx SPS" } },
|
{ std::make_tuple(USRP2, 4, 1), { 1, 0.0, 390625, 7.6547e-5, "N2XX 4/1 Tx/Rx SPS" } },
|
||||||
{ std::make_tuple(USRP2, 4, 4), { 1, 0.0, 390625, 4.6080e-5, "N2XX 4 SPS" } },
|
{ std::make_tuple(USRP2, 4, 4), { 1, 0.0, 390625, 4.6080e-5, "N2XX 4 SPS" } },
|
||||||
|
@ -129,9 +117,7 @@ static const std::map<dev_key, dev_desc> dev_param_map {
|
||||||
{ std::make_tuple(B2XX_MCBTS, 4, 4), { 1, 51.2e6, MCBTS_SPACING*4, B2XX_TIMING_MCBTS, "B200/B210 4 SPS Multi-ARFCN" } },
|
{ std::make_tuple(B2XX_MCBTS, 4, 4), { 1, 51.2e6, MCBTS_SPACING*4, B2XX_TIMING_MCBTS, "B200/B210 4 SPS Multi-ARFCN" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::tuple<uhd_dev_type, enum gsm_band> dev_band_key;
|
static const power_map_t dev_band_nom_power_param_map {
|
||||||
typedef std::map<dev_band_key, dev_band_desc>::const_iterator dev_band_map_it;
|
|
||||||
static const std::map<dev_band_key, dev_band_desc> dev_band_nom_power_param_map {
|
|
||||||
{ std::make_tuple(B200, GSM_BAND_850), { 89.75, 13.3, -7.5 } },
|
{ std::make_tuple(B200, GSM_BAND_850), { 89.75, 13.3, -7.5 } },
|
||||||
{ std::make_tuple(B200, GSM_BAND_900), { 89.75, 13.3, -7.5 } },
|
{ std::make_tuple(B200, GSM_BAND_900), { 89.75, 13.3, -7.5 } },
|
||||||
{ std::make_tuple(B200, GSM_BAND_1800), { 89.75, 7.5, -11.0 } },
|
{ std::make_tuple(B200, GSM_BAND_1800), { 89.75, 7.5, -11.0 } },
|
||||||
|
@ -221,8 +207,8 @@ static double TxPower2TxGain(const dev_band_desc &desc, double tx_power_dbm)
|
||||||
}
|
}
|
||||||
|
|
||||||
uhd_device::uhd_device(InterfaceType iface, const struct trx_cfg *cfg)
|
uhd_device::uhd_device(InterfaceType iface, const struct trx_cfg *cfg)
|
||||||
: RadioDevice(iface, cfg), rx_gain_min(0.0), rx_gain_max(0.0), band_ass_curr_sess(false),
|
: RadioDevice(iface, cfg), band_manager(dev_band_nom_power_param_map, dev_param_map), rx_gain_min(0.0),
|
||||||
band((enum gsm_band)0), tx_spp(0), rx_spp(0), started(false), aligned(false), drop_cnt(0), prev_ts(0, 0),
|
rx_gain_max(0.0), tx_spp(0), rx_spp(0), started(false), aligned(false), drop_cnt(0), prev_ts(0, 0),
|
||||||
ts_initial(0), ts_offset(0), async_event_thrd(NULL)
|
ts_initial(0), ts_offset(0), async_event_thrd(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -235,47 +221,6 @@ uhd_device::~uhd_device()
|
||||||
delete rx_buffers[i];
|
delete rx_buffers[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void uhd_device::assign_band_desc(enum gsm_band req_band)
|
|
||||||
{
|
|
||||||
dev_band_map_it it;
|
|
||||||
|
|
||||||
it = dev_band_nom_power_param_map.find(dev_band_key(dev_type, req_band));
|
|
||||||
if (it == dev_band_nom_power_param_map.end()) {
|
|
||||||
dev_desc desc = dev_param_map.at(dev_key(dev_type, tx_sps, rx_sps));
|
|
||||||
LOGC(DDEV, ERROR) << "No Power parameters exist for device "
|
|
||||||
<< desc.str << " on band " << gsm_band_name(req_band)
|
|
||||||
<< ", using B210 ones as fallback";
|
|
||||||
it = dev_band_nom_power_param_map.find(dev_band_key(B210, req_band));
|
|
||||||
}
|
|
||||||
OSMO_ASSERT(it != dev_band_nom_power_param_map.end())
|
|
||||||
band_desc = it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool uhd_device::set_band(enum gsm_band req_band)
|
|
||||||
{
|
|
||||||
if (band_ass_curr_sess && req_band != band) {
|
|
||||||
LOGC(DDEV, ALERT) << "Requesting band " << gsm_band_name(req_band)
|
|
||||||
<< " different from previous band " << gsm_band_name(band);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req_band != band) {
|
|
||||||
band = req_band;
|
|
||||||
assign_band_desc(band);
|
|
||||||
}
|
|
||||||
band_ass_curr_sess = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uhd_device::get_dev_band_desc(dev_band_desc& desc)
|
|
||||||
{
|
|
||||||
if (band == 0) {
|
|
||||||
LOGC(DDEV, ERROR) << "Power parameters requested before Tx Frequency was set! Providing band 900 by default...";
|
|
||||||
assign_band_desc(GSM_BAND_900);
|
|
||||||
}
|
|
||||||
desc = band_desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uhd_device::init_gains()
|
void uhd_device::init_gains()
|
||||||
{
|
{
|
||||||
double tx_gain_min, tx_gain_max;
|
double tx_gain_min, tx_gain_max;
|
||||||
|
@ -340,7 +285,7 @@ void uhd_device::set_rates()
|
||||||
rx_rate = usrp_dev->get_rx_rate();
|
rx_rate = usrp_dev->get_rx_rate();
|
||||||
|
|
||||||
ts_offset = static_cast<TIMESTAMP>(desc.offset * rx_rate);
|
ts_offset = static_cast<TIMESTAMP>(desc.offset * rx_rate);
|
||||||
LOGC(DDEV, INFO) << "Rates configured for " << desc.str;
|
LOGC(DDEV, INFO) << "Rates configured for " << desc.desc_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
double uhd_device::setRxGain(double db, size_t chan)
|
double uhd_device::setRxGain(double db, size_t chan)
|
||||||
|
@ -791,7 +736,7 @@ bool uhd_device::stop()
|
||||||
for (size_t i = 0; i < rx_buffers.size(); i++)
|
for (size_t i = 0; i < rx_buffers.size(); i++)
|
||||||
rx_buffers[i]->reset();
|
rx_buffers[i]->reset();
|
||||||
|
|
||||||
band_ass_curr_sess = false;
|
band_reset();
|
||||||
|
|
||||||
started = false;
|
started = false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -1031,17 +976,19 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx)
|
||||||
{
|
{
|
||||||
std::vector<double> freqs;
|
std::vector<double> freqs;
|
||||||
uhd::tune_result_t tres;
|
uhd::tune_result_t tres;
|
||||||
|
std::string str_dir = tx ? "Tx" : "Rx";
|
||||||
|
|
||||||
|
if (!update_band_from_freq(freq, chan, tx))
|
||||||
|
return false;
|
||||||
|
|
||||||
uhd::tune_request_t treq = select_freq(freq, chan, tx);
|
uhd::tune_request_t treq = select_freq(freq, chan, tx);
|
||||||
std::string str_dir;
|
|
||||||
|
|
||||||
if (tx) {
|
if (tx) {
|
||||||
tres = usrp_dev->set_tx_freq(treq, chan);
|
tres = usrp_dev->set_tx_freq(treq, chan);
|
||||||
tx_freqs[chan] = usrp_dev->get_tx_freq(chan);
|
tx_freqs[chan] = usrp_dev->get_tx_freq(chan);
|
||||||
str_dir = "Tx";
|
|
||||||
} else {
|
} else {
|
||||||
tres = usrp_dev->set_rx_freq(treq, chan);
|
tres = usrp_dev->set_rx_freq(treq, chan);
|
||||||
rx_freqs[chan] = usrp_dev->get_rx_freq(chan);
|
rx_freqs[chan] = usrp_dev->get_rx_freq(chan);
|
||||||
str_dir = "Rx";
|
|
||||||
}
|
}
|
||||||
LOGCHAN(chan, DDEV, INFO) << "set_freq(" << freq << ", " << str_dir << "): " << tres.to_pp_string() << std::endl;
|
LOGCHAN(chan, DDEV, INFO) << "set_freq(" << freq << ", " << str_dir << "): " << tres.to_pp_string() << std::endl;
|
||||||
|
|
||||||
|
@ -1071,59 +1018,20 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx)
|
||||||
|
|
||||||
bool uhd_device::setTxFreq(double wFreq, size_t chan)
|
bool uhd_device::setTxFreq(double wFreq, size_t chan)
|
||||||
{
|
{
|
||||||
uint16_t req_arfcn;
|
|
||||||
enum gsm_band req_band;
|
|
||||||
|
|
||||||
if (chan >= tx_freqs.size()) {
|
if (chan >= tx_freqs.size()) {
|
||||||
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ScopedLock lock(tune_lock);
|
|
||||||
|
|
||||||
req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100 , 0);
|
return set_freq(wFreq, chan, true);
|
||||||
if (req_arfcn == 0xffff) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown ARFCN for Tx Frequency " << wFreq / 1000 << " kHz";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown GSM band for Tx Frequency " << wFreq
|
|
||||||
<< " Hz (ARFCN " << req_arfcn << " )";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_band(req_band))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!set_freq(wFreq, chan, true))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uhd_device::setRxFreq(double wFreq, size_t chan)
|
bool uhd_device::setRxFreq(double wFreq, size_t chan)
|
||||||
{
|
{
|
||||||
uint16_t req_arfcn;
|
|
||||||
enum gsm_band req_band;
|
|
||||||
|
|
||||||
if (chan >= rx_freqs.size()) {
|
if (chan >= rx_freqs.size()) {
|
||||||
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ScopedLock lock(tune_lock);
|
|
||||||
|
|
||||||
req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100, 1);
|
|
||||||
if (req_arfcn == 0xffff) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown ARFCN for Rx Frequency " << wFreq / 1000 << " kHz";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) {
|
|
||||||
LOGCHAN(chan, DDEV, ALERT) << "Unknown GSM band for Rx Frequency " << wFreq
|
|
||||||
<< " Hz (ARFCN " << req_arfcn << " )";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_band(req_band))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return set_freq(wFreq, chan, false);
|
return set_freq(wFreq, chan, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "bandmanager.h"
|
||||||
#include "radioDevice.h"
|
#include "radioDevice.h"
|
||||||
#include "smpl_buf.h"
|
#include "smpl_buf.h"
|
||||||
|
|
||||||
|
@ -71,6 +72,19 @@ struct dev_band_desc {
|
||||||
double rxgain2rssioffset_rel; /* dB */
|
double rxgain2rssioffset_rel; /* dB */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dev_desc {
|
||||||
|
unsigned channels;
|
||||||
|
double mcr;
|
||||||
|
double rate;
|
||||||
|
double offset;
|
||||||
|
std::string desc_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
using dev_key = std::tuple<uhd_dev_type, int, int>;
|
||||||
|
using dev_band_key = std::tuple<uhd_dev_type, enum gsm_band>;
|
||||||
|
using power_map_t = std::map<dev_band_key, dev_band_desc>;
|
||||||
|
using dev_map_t = std::map<dev_key, dev_desc>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
uhd_device - UHD implementation of the Device interface. Timestamped samples
|
uhd_device - UHD implementation of the Device interface. Timestamped samples
|
||||||
are sent to and received from the device. An intermediate buffer
|
are sent to and received from the device. An intermediate buffer
|
||||||
|
@ -78,7 +92,7 @@ struct dev_band_desc {
|
||||||
Events and errors such as underruns are reported asynchronously
|
Events and errors such as underruns are reported asynchronously
|
||||||
by the device and received in a separate thread.
|
by the device and received in a separate thread.
|
||||||
*/
|
*/
|
||||||
class uhd_device : public RadioDevice {
|
class uhd_device : public RadioDevice, public band_manager<power_map_t, dev_map_t> {
|
||||||
public:
|
public:
|
||||||
uhd_device(InterfaceType iface, const struct trx_cfg *cfg);
|
uhd_device(InterfaceType iface, const struct trx_cfg *cfg);
|
||||||
~uhd_device();
|
~uhd_device();
|
||||||
|
@ -160,9 +174,6 @@ protected:
|
||||||
|
|
||||||
std::vector<double> tx_gains, rx_gains;
|
std::vector<double> tx_gains, rx_gains;
|
||||||
std::vector<double> tx_freqs, rx_freqs;
|
std::vector<double> tx_freqs, rx_freqs;
|
||||||
bool band_ass_curr_sess; /* true if "band" was set after last POWEROFF */
|
|
||||||
enum gsm_band band;
|
|
||||||
struct dev_band_desc band_desc;
|
|
||||||
size_t tx_spp, rx_spp;
|
size_t tx_spp, rx_spp;
|
||||||
|
|
||||||
bool started;
|
bool started;
|
||||||
|
@ -191,10 +202,6 @@ protected:
|
||||||
|
|
||||||
uhd::tune_request_t select_freq(double wFreq, size_t chan, bool tx);
|
uhd::tune_request_t select_freq(double wFreq, size_t chan, bool tx);
|
||||||
bool set_freq(double freq, size_t chan, bool tx);
|
bool set_freq(double freq, size_t chan, bool tx);
|
||||||
void get_dev_band_desc(dev_band_desc& desc);
|
|
||||||
bool set_band(enum gsm_band req_band);
|
|
||||||
void assign_band_desc(enum gsm_band req_band);
|
|
||||||
|
|
||||||
Thread *async_event_thrd;
|
Thread *async_event_thrd;
|
||||||
Mutex tune_lock;
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue