diff options
author | Eric <ewild@sysmocom.de> | 2023-05-12 13:00:14 +0200 |
---|---|---|
committer | Eric <ewild@sysmocom.de> | 2023-07-25 18:25:49 +0200 |
commit | c0f78a37ed6fcb900c232eeba41f22f2dffa48d1 (patch) | |
tree | 521ab93b0038f0f4d218a1f8e50d8323cea5e8aa | |
parent | 19e134a626abdb99435d96b0bfcc46b0804715e5 (diff) |
devices: unify band handling
This is basically common, but optional code.
Change-Id: I64f5a462451e967d4750d8e4f1d5832cbab41cff
-rw-r--r-- | Transceiver52M/device/bladerf/bladerf.cpp | 99 | ||||
-rw-r--r-- | Transceiver52M/device/bladerf/bladerf.h | 26 | ||||
-rw-r--r-- | Transceiver52M/device/common/Makefile.am | 2 | ||||
-rw-r--r-- | Transceiver52M/device/common/bandmanager.h | 133 | ||||
-rw-r--r-- | Transceiver52M/device/lms/LMSDevice.cpp | 121 | ||||
-rw-r--r-- | Transceiver52M/device/lms/LMSDevice.h | 37 | ||||
-rw-r--r-- | Transceiver52M/device/uhd/UHDDevice.cpp | 116 | ||||
-rw-r--r-- | Transceiver52M/device/uhd/UHDDevice.h | 23 |
8 files changed, 231 insertions, 326 deletions
diff --git a/Transceiver52M/device/bladerf/bladerf.cpp b/Transceiver52M/device/bladerf/bladerf.cpp index 3d9aab9..3e830b1 100644 --- a/Transceiver52M/device/bladerf/bladerf.cpp +++ b/Transceiver52M/device/bladerf/bladerf.cpp @@ -47,25 +47,11 @@ extern "C" { LOGC(DDEV, ERROR) << bladerf_strerror(status); \ } -/* Device Type, Tx-SPS, Rx-SPS */ -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{ +static const dev_map_t dev_param_map{ { 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; -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{ +static const power_map_t 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_900), { 89.75, 13.3, -7.5 } }, { 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) - : RadioDevice(iface, cfg), dev(nullptr), rx_gain_min(0.0), rx_gain_max(0.0), band_ass_curr_sess(false), - band((enum gsm_band)0), tx_spp(0), rx_spp(0), started(false), aligned(false), drop_cnt(0), prev_ts(0), - ts_initial(0), ts_offset(0), async_event_thrd(NULL) + : RadioDevice(iface, cfg), band_manager(dev_band_nom_power_param_map, dev_param_map), dev(nullptr), + rx_gain_min(0.0), rx_gain_max(0.0), tx_spp(0), rx_spp(0), started(false), aligned(false), drop_cnt(0), + 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]; } -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() { 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++) rx_buffers[i]->reset(); - band_ass_curr_sess = false; + band_reset(); started = false; 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) { - uint16_t req_arfcn; - enum gsm_band req_band; - if (chan >= tx_freqs.size()) { LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan; return false; } ScopedLock lock(tune_lock); - req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100, 0); - 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)) + if (!update_band_from_freq(wFreq, chan, true)) return false; 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) { - uint16_t req_arfcn; - enum gsm_band req_band; - if (chan >= rx_freqs.size()) { LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan; 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)) + if (!update_band_from_freq(wFreq, chan, false)) return false; return set_freq(wFreq, chan, false); diff --git a/Transceiver52M/device/bladerf/bladerf.h b/Transceiver52M/device/bladerf/bladerf.h index 4db2569..e32581e 100644 --- a/Transceiver52M/device/bladerf/bladerf.h +++ b/Transceiver52M/device/bladerf/bladerf.h @@ -22,10 +22,12 @@ #pragma once +#include <map> #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include "bandmanager.h" #include "radioDevice.h" #include "smpl_buf.h" @@ -33,8 +35,6 @@ extern "C" { #include <osmocom/gsm/gsm_utils.h> } -#include <bladerf.h> - enum class blade_dev_type { BLADE1, BLADE2 }; struct dev_band_desc { @@ -52,7 +52,21 @@ struct dev_band_desc { 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: blade_device(InterfaceType iface, const struct trx_cfg *cfg); ~blade_device(); @@ -153,9 +167,6 @@ class blade_device : public RadioDevice { std::vector<double> tx_gains, rx_gains; 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; bool started; @@ -178,9 +189,6 @@ class blade_device : public RadioDevice { bool flush_recv(size_t num_pkts); 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; Mutex tune_lock; diff --git a/Transceiver52M/device/common/Makefile.am b/Transceiver52M/device/common/Makefile.am index 4d29e98..1a33592 100644 --- a/Transceiver52M/device/common/Makefile.am +++ b/Transceiver52M/device/common/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) 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 diff --git a/Transceiver52M/device/common/bandmanager.h b/Transceiver52M/device/common/bandmanager.h new file mode 100644 index 0000000..a198937 --- /dev/null +++ b/Transceiver52M/device/common/bandmanager.h @@ -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); + } +};
\ No newline at end of file diff --git a/Transceiver52M/device/lms/LMSDevice.cpp b/Transceiver52M/device/lms/LMSDevice.cpp index e336e77..451d2b9 100644 --- a/Transceiver52M/device/lms/LMSDevice.cpp +++ b/Transceiver52M/device/lms/LMSDevice.cpp @@ -52,39 +52,16 @@ extern "C" { #define LMS_DEV_SDR_MINI_PREFIX_NAME "LimeSDR-Mini" #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_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_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; -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 { +static const power_map_t 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_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) */ @@ -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; struct dev_desc desc = it->second; - if (strncmp(device_info->deviceName, desc.name_prefix.c_str(), desc.name_prefix.length()) == 0) { - LOGC(DDEV, INFO) << "Device identified as " << desc.name_prefix; + if (strncmp(device_info->deviceName, desc.desc_str.c_str(), desc.desc_str.length()) == 0) { + LOGC(DDEV, INFO) << "Device identified as " << desc.desc_str; return dev_type; } 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) - : RadioDevice(iface, cfg), m_lms_dev(NULL), started(false), band_ass_curr_sess(false), band((enum gsm_band)0), - m_dev_type(LMS_DEV_UNKNOWN) + : RadioDevice(iface, cfg), + 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..."; @@ -220,47 +198,6 @@ int info_list_find(lms_info_str_t* info_list, unsigned int count, const std::str 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() { lms_info_str_t* info_list; @@ -466,7 +403,7 @@ bool LMSDevice::stop() LMS_DestroyStream(m_lms_dev, &m_lms_stream_rx[i]); } - band_ass_curr_sess = false; + band_reset(); started = false; return true; @@ -483,8 +420,8 @@ bool LMSDevice::do_clock_src_freq(enum ReferenceType ref, double freq) break; case REF_INTERNAL: if (!dev_desc.clock_src_int_usable) { - LOGC(DDEV, ERROR) << "Device type " << dev_desc.name_prefix - << " doesn't support internal reference clock"; + LOGC(DDEV, ERROR) + << "Device type " << dev_desc.desc_str << " doesn't support internal reference clock"; return false; } /* 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) return false; } else { - LOGC(DDEV, INFO) << "Device type " << dev_desc.name_prefix - << " doesn't support switching clock source through SW"; + LOGC(DDEV, INFO) + << "Device type " << dev_desc.desc_str << " doesn't support switching clock source through SW"; } return true; @@ -996,9 +933,6 @@ bool LMSDevice::updateAlignment(TIMESTAMP timestamp) bool LMSDevice::setTxFreq(double wFreq, size_t chan) { - uint16_t req_arfcn; - enum gsm_band req_band; - if (chan >= chans) { LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan; return false; @@ -1006,18 +940,7 @@ bool LMSDevice::setTxFreq(double wFreq, size_t chan) LOGCHAN(chan, DDEV, NOTICE) << "Setting Tx Freq to " << wFreq << " Hz"; - req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100 , 0); - 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)) + if (!update_band_from_freq(wFreq, chan, true)) return false; 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) { - uint16_t req_arfcn; - enum gsm_band req_band; - LOGCHAN(chan, DDEV, NOTICE) << "Setting Rx Freq to " << wFreq << " Hz"; - 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)) + if (!update_band_from_freq(wFreq, chan, false)) return false; if (LMS_SetLOFrequency(m_lms_dev, LMS_CH_RX, chan, wFreq) < 0) { diff --git a/Transceiver52M/device/lms/LMSDevice.h b/Transceiver52M/device/lms/LMSDevice.h index 75d11cf..2e5ca4c 100644 --- a/Transceiver52M/device/lms/LMSDevice.h +++ b/Transceiver52M/device/lms/LMSDevice.h @@ -18,11 +18,13 @@ #ifndef _LMS_DEVICE_H_ #define _LMS_DEVICE_H_ +#include <map> #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "radioDevice.h" +#include "bandmanager.h" #include "smpl_buf.h" #include <sys/time.h> @@ -69,8 +71,35 @@ struct dev_band_desc { 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 */ -class LMSDevice:public RadioDevice { +class LMSDevice:public RadioDevice, public band_manager<power_map_t, dev_map_t> { private: lms_device_t *m_lms_dev; @@ -87,9 +116,6 @@ private: TIMESTAMP ts_initial, ts_offset; 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; @@ -101,9 +127,6 @@ private: void update_stream_stats_rx(size_t chan, bool *overrun); void update_stream_stats_tx(size_t chan, bool *underrun); 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: /** Object constructor */ diff --git a/Transceiver52M/device/uhd/UHDDevice.cpp b/Transceiver52M/device/uhd/UHDDevice.cpp index a0021db..95ea8e7 100644 --- a/Transceiver52M/device/uhd/UHDDevice.cpp +++ b/Transceiver52M/device/uhd/UHDDevice.cpp @@ -91,19 +91,7 @@ extern "C" { * USRP1 with timestamps is not supported by UHD. */ -/* Device Type, Tx-SPS, Rx-SPS */ -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 { +static const dev_map_t dev_param_map { { 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, 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" } }, }; -typedef std::tuple<uhd_dev_type, enum gsm_band> dev_band_key; -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 { +static const power_map_t 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_900), { 89.75, 13.3, -7.5 } }, { 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) - : RadioDevice(iface, cfg), rx_gain_min(0.0), rx_gain_max(0.0), band_ass_curr_sess(false), - band((enum gsm_band)0), tx_spp(0), rx_spp(0), started(false), aligned(false), drop_cnt(0), prev_ts(0, 0), + : RadioDevice(iface, cfg), band_manager(dev_band_nom_power_param_map, dev_param_map), rx_gain_min(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) { } @@ -235,47 +221,6 @@ uhd_device::~uhd_device() 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() { double tx_gain_min, tx_gain_max; @@ -340,7 +285,7 @@ void uhd_device::set_rates() rx_rate = usrp_dev->get_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) @@ -791,7 +736,7 @@ bool uhd_device::stop() for (size_t i = 0; i < rx_buffers.size(); i++) rx_buffers[i]->reset(); - band_ass_curr_sess = false; + band_reset(); started = false; return true; @@ -1031,17 +976,19 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx) { std::vector<double> freqs; 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); - std::string str_dir; if (tx) { tres = usrp_dev->set_tx_freq(treq, chan); tx_freqs[chan] = usrp_dev->get_tx_freq(chan); - str_dir = "Tx"; } else { tres = usrp_dev->set_rx_freq(treq, 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; @@ -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) { - uint16_t req_arfcn; - enum gsm_band req_band; - if (chan >= tx_freqs.size()) { LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan; return false; } - ScopedLock lock(tune_lock); - - req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100 , 0); - 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; + return set_freq(wFreq, chan, true); } bool uhd_device::setRxFreq(double wFreq, size_t chan) { - uint16_t req_arfcn; - enum gsm_band req_band; - if (chan >= rx_freqs.size()) { LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan; 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); } diff --git a/Transceiver52M/device/uhd/UHDDevice.h b/Transceiver52M/device/uhd/UHDDevice.h index 299d98c..f5e5232 100644 --- a/Transceiver52M/device/uhd/UHDDevice.h +++ b/Transceiver52M/device/uhd/UHDDevice.h @@ -30,6 +30,7 @@ #include "config.h" #endif +#include "bandmanager.h" #include "radioDevice.h" #include "smpl_buf.h" @@ -71,6 +72,19 @@ struct dev_band_desc { 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 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 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: uhd_device(InterfaceType iface, const struct trx_cfg *cfg); ~uhd_device(); @@ -160,9 +174,6 @@ protected: std::vector<double> tx_gains, rx_gains; 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; bool started; @@ -191,10 +202,6 @@ protected: uhd::tune_request_t select_freq(double wFreq, 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; - Mutex tune_lock; }; |