Compare commits

..

1 Commits

Author SHA1 Message Date
Pau Espin Pedrol
223a15c2b2 WIP: lms: Add multi-arfcn support
Change-Id: I2b8c2c6738c494b8d56ebcb073106c864ab191dc
2020-01-13 17:53:44 +01:00
16 changed files with 94 additions and 234 deletions

View File

@@ -666,7 +666,7 @@ For more information on this, and how to apply and follow the GNU AGPL, see
========================================================================= =========================================================================
This marks the end of the AGPLv3 text. The following text is appended to the This marks the end of the AGPLv3 text. The following text is appended to the
same file for convenience but constituting a distinct document, not part of the same file for convience but constituting a distinct document, not part of the
actual AGPL text and not part of an attempt to create a deriviative work based actual AGPL text and not part of an attempt to create a deriviative work based
on the AGPLv3 text. on the AGPLv3 text.

View File

@@ -232,7 +232,7 @@ template <class T> class Vector {
assert(mStart+span<=mEnd); assert(mStart+span<=mEnd);
for (i = 0; i < span; i++, src++, dst++) for (i = 0; i < span; i++, src++, dst++)
*dst = *src; *dst = *src;
/*TODO if not non-trivially copiable type class, optimize: /*TODO if not non-trivially copyable type class, optimize:
memcpy(dst,mStart,span*sizeof(T)); */ memcpy(dst,mStart,span*sizeof(T)); */
} }

View File

@@ -21,17 +21,7 @@
* See the COPYING file in the main directory for details. * See the COPYING file in the main directory for details.
*/ */
#include "config.h" #include <pthread.h>
/* If HAVE_GETTID, then "_GNU_SOURCE" may need to be defined to use gettid() */
#if HAVE_GETTID
#define _GNU_SOURCE
#endif
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "config.h"
#include <osmocom/core/logging.h> #include <osmocom/core/logging.h>
#include <osmocom/core/utils.h> #include <osmocom/core/utils.h>
@@ -87,15 +77,3 @@ const struct log_info log_info = {
.cat = default_categories, .cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories), .num_cat = ARRAY_SIZE(default_categories),
}; };
pid_t my_gettid(void)
{
#if HAVE_GETTID
return gettid();
#elif defined(LINUX) && defined(__NR_gettid)
return (pid_t) syscall(__NR_gettid);
#else
#pragma message ("use pid as tid")
return getpid();
#endif
}

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include <sys/types.h> #include <pthread.h>
#include <osmocom/core/logging.h> #include <osmocom/core/logging.h>
@@ -18,12 +18,10 @@ enum {
DDEVDRV, DDEVDRV,
}; };
pid_t my_gettid(void);
#define CLOGC(category, level, fmt, args...) do { \ #define CLOGC(category, level, fmt, args...) do { \
LOGP(category, level, "[tid=%ld] " fmt, (long int) my_gettid(), ##args); \ LOGP(category, level, "[tid=%lu] " fmt, pthread_self(), ##args); \
} while(0) } while(0)
#define CLOGCHAN(chan, category, level, fmt, args...) do { \ #define CLOGCHAN(chan, category, level, fmt, args...) do { \
LOGP(category, level, "[tid=%ld][chan=%zu] " fmt, (long int) my_gettid(), chan, ##args); \ LOGP(category, level, "[tid=%lu][chan=%lu] " fmt, pthread_self(), chan, ##args); \
} while(0) } while(0)

View File

@@ -42,7 +42,7 @@
static struct trx_ctx* g_trx_ctx; static struct trx_ctx* g_trx_ctx;
const struct value_string clock_ref_names[] = { static const struct value_string clock_ref_names[] = {
{ REF_INTERNAL, "internal" }, { REF_INTERNAL, "internal" },
{ REF_EXTERNAL, "external" }, { REF_EXTERNAL, "external" },
{ REF_GPS, "gpsdo" }, { REF_GPS, "gpsdo" },

View File

@@ -5,7 +5,6 @@
#include "config_defs.h" #include "config_defs.h"
extern struct vty_app_info g_vty_info; extern struct vty_app_info g_vty_info;
extern const struct value_string clock_ref_names[];
extern const struct value_string filler_names[]; extern const struct value_string filler_names[];
/* Maximum number of physical RF channels */ /* Maximum number of physical RF channels */

View File

@@ -77,20 +77,23 @@ class RadioDevice {
@param overrun Set if read buffer has been overrun, e.g. data not being read fast enough @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
@param timestamp The timestamp of the first samples to be read @param timestamp The timestamp of the first samples to be read
@param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough @param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough
@param RSSI The received signal strength of the read result
@return The number of samples actually read @return The number of samples actually read
*/ */
virtual int readSamples(std::vector<short *> &bufs, int len, bool *overrun, virtual int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0) = 0; TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0,
unsigned *RSSI = 0) = 0;
/** /**
Write samples to the radio. Write samples to the radio.
@param buf Contains the data to be written. @param buf Contains the data to be written.
@param len number of samples to write. @param len number of samples to write.
@param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough @param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough
@param timestamp The timestamp of the first sample of the data buffer. @param timestamp The timestamp of the first sample of the data buffer.
@param isControl Set if data is a control packet, e.g. a ping command
@return The number of samples actually written @return The number of samples actually written
*/ */
virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun, virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp) = 0; TIMESTAMP timestamp, bool isControl = false) = 0;
/** Update the alignment between the read and write timestamps */ /** Update the alignment between the read and write timestamps */
virtual bool updateAlignment(TIMESTAMP timestamp)=0; virtual bool updateAlignment(TIMESTAMP timestamp)=0;

View File

@@ -20,10 +20,6 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <map>
#include "trx_vty.h"
#include "Logger.h" #include "Logger.h"
#include "Threads.h" #include "Threads.h"
#include "LMSDevice.h" #include "LMSDevice.h"
@@ -48,69 +44,11 @@ using namespace std;
#define LMS_CALIBRATE_BW_HZ OSMO_MAX(GSM_CARRIER_BW, LMS_MIN_BW_SUPPORTED) #define LMS_CALIBRATE_BW_HZ OSMO_MAX(GSM_CARRIER_BW, LMS_MIN_BW_SUPPORTED)
#define SAMPLE_BUF_SZ (1 << 20) /* Size of Rx timestamp based Ring buffer, in bytes */ #define SAMPLE_BUF_SZ (1 << 20) /* Size of Rx timestamp based Ring buffer, in bytes */
/* Device Name Prefixes as presented by LimeSuite API LMS_GetDeviceInfo(): */
#define LMS_DEV_SDR_USB_PREFIX_NAME "LimeSDR-USB"
#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;
/* Device specific maximum tx levels selected by phasenoise measurements, in dB */
double max_tx_gain;
/* 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 {
{ LMS_DEV_SDR_USB, { true, true, 73.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_SDR_USB_PREFIX_NAME } },
{ LMS_DEV_SDR_MINI, { false, true, 66.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 8.2e-5, LMS_DEV_SDR_MINI_PREFIX_NAME } },
{ LMS_DEV_NET_MICRO, { true, false, 71.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_NET_MICRO_PREFIX_NAME } },
{ LMS_DEV_UNKNOWN, { true, true, 73.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, "UNKNOWN" } },
};
static enum lms_dev_type parse_dev_type(lms_device_t *m_lms_dev)
{
std::map<enum lms_dev_type, struct dev_desc>::const_iterator it = dev_param_map.begin();
const lms_dev_info_t* device_info = LMS_GetDeviceInfo(m_lms_dev);
while (it != dev_param_map.end())
{
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;
return dev_type;
}
it++;
}
return LMS_DEV_UNKNOWN;
}
LMSDevice::LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset, LMSDevice::LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
const std::vector<std::string>& tx_paths, const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths): const std::vector<std::string>& rx_paths):
RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths), RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths),
m_lms_dev(NULL), started(false), m_dev_type(LMS_DEV_UNKNOWN) m_lms_dev(NULL), started(false)
{ {
LOGC(DDEV, INFO) << "creating LMS device..."; LOGC(DDEV, INFO) << "creating LMS device...";
@@ -120,11 +58,6 @@ LMSDevice::LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t c
tx_gains.resize(chans); tx_gains.resize(chans);
rx_buffers.resize(chans); rx_buffers.resize(chans);
/* Set up per-channel Rx timestamp based Ring buffers */
for (size_t i = 0; i < rx_buffers.size(); i++)
rx_buffers[i] = new smpl_buf(SAMPLE_BUF_SZ / sizeof(uint32_t));
} }
LMSDevice::~LMSDevice() LMSDevice::~LMSDevice()
@@ -176,7 +109,7 @@ static void print_range(const char* name, lms_range_t *range)
int info_list_find(lms_info_str_t* info_list, unsigned int count, const std::string &args) int info_list_find(lms_info_str_t* info_list, unsigned int count, const std::string &args)
{ {
unsigned int i, j; unsigned int i, j;
std::vector<string> filters; vector<string> filters;
filters = comma_delimited_to_vector(args.c_str()); filters = comma_delimited_to_vector(args.c_str());
@@ -200,11 +133,12 @@ int info_list_find(lms_info_str_t* info_list, unsigned int count, const std::str
int LMSDevice::open(const std::string &args, int ref, bool swap_channels) int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
{ {
lms_info_str_t* info_list; lms_info_str_t* info_list;
const lms_dev_info_t* device_info;
lms_range_t range_sr; lms_range_t range_sr;
float_type sr_host, sr_rf; float_type sr_host, sr_rf;
unsigned int i, n; unsigned int i, n;
int rc, dev_id; int rc, dev_id;
struct dev_desc dev_desc; int sample_rate;
LOGC(DDEV, INFO) << "Opening LMS device.."; LOGC(DDEV, INFO) << "Opening LMS device..";
@@ -241,20 +175,19 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
delete [] info_list; delete [] info_list;
m_dev_type = parse_dev_type(m_lms_dev); device_info = LMS_GetDeviceInfo(m_lms_dev);
dev_desc = dev_param_map.at(m_dev_type);
if ((ref != REF_EXTERNAL) && (ref != REF_INTERNAL)){ if ((ref != REF_EXTERNAL) && (ref != REF_INTERNAL)){
LOGC(DDEV, ERROR) << "Invalid reference type"; LOGC(DDEV, ERROR) << "Invalid reference type";
goto out_close; goto out_close;
} }
/* if reference clock is external, setup must happen _before_ calling LMS_Init */ /* if reference clock is external setup must happen _before_ calling LMS_Init */
/* FIXME make external reference frequency configurable */
if (ref == REF_EXTERNAL) { if (ref == REF_EXTERNAL) {
LOGC(DDEV, INFO) << "Setting External clock reference to 10MHz"; LOGC(DDEV, INFO) << "Setting External clock reference to 10MHz";
/* FIXME: Assume an external 10 MHz reference clock. make /* Assume an external 10 MHz reference clock */
external reference frequency configurable */ if (LMS_SetClockFreq(m_lms_dev, LMS_CLOCK_EXTREF, 10000000.0) < 0)
if (!do_clock_src_freq(REF_EXTERNAL, 10000000.0))
goto out_close; goto out_close;
} }
@@ -264,13 +197,22 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
goto out_close; goto out_close;
} }
/* if reference clock is internal, setup must happen _after_ calling LMS_Init */ /* LimeSDR-Mini does not have switches but needs soldering to select external/internal clock */
if (ref == REF_INTERNAL) { /* LimeNET-Micro also does not like selecting internal clock*/
LOGC(DDEV, INFO) << "Setting Internal clock reference"; /* also set device specific maximum tx levels selected by phasenoise measurements*/
/* Internal freq param is not used */ if (strncmp(device_info->deviceName,"LimeSDR-USB",11) == 0){
if (!do_clock_src_freq(REF_INTERNAL, 0)) /* if reference clock is internal setup must happen _after_ calling LMS_Init */
goto out_close; /* according to lms using LMS_CLOCK_EXTREF with a frequency <= 0 is the correct way to set clock to internal reference*/
} if (ref == REF_INTERNAL) {
LOGC(DDEV, INFO) << "Setting Internal clock reference";
if (LMS_SetClockFreq(m_lms_dev, LMS_CLOCK_EXTREF, -1) < 0)
goto out_close;
}
maxTxGainClamp = 73.0;
} else if (strncmp(device_info->deviceName,"LimeSDR-Mini",12) == 0)
maxTxGainClamp = 66.0;
else
maxTxGainClamp = 71.0; /* "LimeNET-Micro", etc FIXME pciE based LMS boards?*/
/* enable all used channels */ /* enable all used channels */
for (i=0; i<chans; i++) { for (i=0; i<chans; i++) {
@@ -285,22 +227,18 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
goto out_close; goto out_close;
print_range("Sample Rate", &range_sr); print_range("Sample Rate", &range_sr);
if (iface == MULTI_ARFCN) sample_rate = (iface == MULTI_ARFCN ? MCBTS_SPACING : GSMRATE) * tx_sps;
sr_host = dev_desc.rate_multiarfcn * tx_sps;
else LOGC(DDEV, INFO) << "Setting sample rate to " << sample_rate << " " << tx_sps;
sr_host = dev_desc.rate * tx_sps; if (LMS_SetSampleRate(m_lms_dev, sample_rate, 32) < 0)
LOGC(DDEV, INFO) << "Setting sample rate to " << sr_host << " " << tx_sps;
if (LMS_SetSampleRate(m_lms_dev, sr_host, 32) < 0)
goto out_close; goto out_close;
if (LMS_GetSampleRate(m_lms_dev, LMS_CH_RX, 0, &sr_host, &sr_rf)) if (LMS_GetSampleRate(m_lms_dev, LMS_CH_RX, 0, &sr_host, &sr_rf))
goto out_close; goto out_close;
LOGC(DDEV, INFO) << "Sample Rate: Host=" << sr_host << " RF=" << sr_rf; LOGC(DDEV, INFO) << "Sample Rate: Host=" << sr_host << " RF=" << sr_rf;
if (iface == MULTI_ARFCN) /* FIXME: make this device/model dependent, like UHDDevice:dev_param_map! */
ts_offset = static_cast<TIMESTAMP>(dev_desc.ts_offset_coef_multiarfcn * sr_host); ts_offset = static_cast<TIMESTAMP>(8.9e-5 * sample_rate);
else
ts_offset = static_cast<TIMESTAMP>(dev_desc.ts_offset_coef * sr_host);
/* configure antennas */ /* configure antennas */
if (!set_antennas()) { if (!set_antennas()) {
@@ -308,6 +246,10 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
goto out_close; goto out_close;
} }
/* Set up per-channel Rx timestamp based Ring buffers */
for (size_t i = 0; i < rx_buffers.size(); i++)
rx_buffers[i] = new smpl_buf(SAMPLE_BUF_SZ / sizeof(uint32_t));
return iface == MULTI_ARFCN ? MULTI_ARFCN : NORMAL; return iface == MULTI_ARFCN ? MULTI_ARFCN : NORMAL;
out_close: out_close:
@@ -402,43 +344,6 @@ bool LMSDevice::stop()
return true; return true;
} }
bool LMSDevice::do_clock_src_freq(enum ReferenceType ref, double freq)
{
struct dev_desc dev_desc = dev_param_map.at(m_dev_type);
size_t lms_clk_id;
switch (ref) {
case REF_EXTERNAL:
lms_clk_id = LMS_CLOCK_EXTREF;
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";
return false;
}
/* According to lms using LMS_CLOCK_EXTREF with a
frequency <= 0 is the correct way to set clock to
internal reference */
lms_clk_id = LMS_CLOCK_EXTREF;
freq = -1;
break;
default:
LOGC(DDEV, ERROR) << "Invalid reference type " << get_value_string(clock_ref_names, ref);
return false;
}
if (dev_desc.clock_src_switchable) {
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";
}
return true;
}
/* do rx/tx calibration - depends on gain, freq and bw */ /* do rx/tx calibration - depends on gain, freq and bw */
bool LMSDevice::do_calib(size_t chan) bool LMSDevice::do_calib(size_t chan)
{ {
@@ -480,7 +385,7 @@ bool LMSDevice::do_filters(size_t chan)
double LMSDevice::maxTxGain() double LMSDevice::maxTxGain()
{ {
return dev_param_map.at(m_dev_type).max_tx_gain; return maxTxGainClamp;
} }
double LMSDevice::minTxGain() double LMSDevice::minTxGain()
@@ -739,7 +644,7 @@ void LMSDevice::update_stream_stats_rx(size_t chan, bool *overrun)
// NOTE: Assumes sequential reads // NOTE: Assumes sequential reads
int LMSDevice::readSamples(std::vector < short *>&bufs, int len, bool * overrun, int LMSDevice::readSamples(std::vector < short *>&bufs, int len, bool * overrun,
TIMESTAMP timestamp, bool * underrun) TIMESTAMP timestamp, bool * underrun, unsigned *RSSI)
{ {
int rc, num_smpls, expect_smpls; int rc, num_smpls, expect_smpls;
ssize_t avail_smpls; ssize_t avail_smpls;
@@ -858,7 +763,8 @@ void LMSDevice::update_stream_stats_tx(size_t chan, bool *underrun)
} }
int LMSDevice::writeSamples(std::vector < short *>&bufs, int len, int LMSDevice::writeSamples(std::vector < short *>&bufs, int len,
bool * underrun, unsigned long long timestamp) bool * underrun, unsigned long long timestamp,
bool isControl)
{ {
int rc = 0; int rc = 0;
unsigned int i; unsigned int i;
@@ -867,6 +773,11 @@ int LMSDevice::writeSamples(std::vector < short *>&bufs, int len,
tx_metadata.waitForTimestamp = true; tx_metadata.waitForTimestamp = true;
tx_metadata.timestamp = timestamp - ts_offset; /* Shift Tx time by offset */ tx_metadata.timestamp = timestamp - ts_offset; /* Shift Tx time by offset */
if (isControl) {
LOGC(DDEV, ERROR) << "Control packets not supported";
return 0;
}
if (bufs.size() != chans) { if (bufs.size() != chans) {
LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size(); LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();
return -1; return -1;

View File

@@ -41,13 +41,6 @@
* A^2 = 1 */ * A^2 = 1 */
#define LIMESDR_TX_AMPL 0.707 #define LIMESDR_TX_AMPL 0.707
enum lms_dev_type {
LMS_DEV_SDR_USB, /* LimeSDR-USB */
LMS_DEV_SDR_MINI, /* LimeSDR-Mini */
LMS_DEV_NET_MICRO, /* LimeNet-micro */
LMS_DEV_UNKNOWN,
};
/** A class to handle a LimeSuite supported device */ /** A class to handle a LimeSuite supported device */
class LMSDevice:public RadioDevice { class LMSDevice:public RadioDevice {
@@ -66,8 +59,7 @@ 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;
double maxTxGainClamp;
enum lms_dev_type m_dev_type;
bool do_calib(size_t chan); bool do_calib(size_t chan);
bool do_filters(size_t chan); bool do_filters(size_t chan);
@@ -76,7 +68,6 @@ private:
bool flush_recv(size_t num_pkts); bool flush_recv(size_t num_pkts);
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);
public: public:
@@ -106,21 +97,24 @@ public:
@param overrun Set if read buffer has been overrun, e.g. data not being read fast enough @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
@param timestamp The timestamp of the first samples to be read @param timestamp The timestamp of the first samples to be read
@param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough @param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
@param RSSI The received signal strength of the read result
@return The number of samples actually read @return The number of samples actually read
*/ */
int readSamples(std::vector < short *>&buf, int len, bool * overrun, int readSamples(std::vector < short *>&buf, int len, bool * overrun,
TIMESTAMP timestamp = 0xffffffff, bool * underrun = TIMESTAMP timestamp = 0xffffffff, bool * underrun =
NULL); NULL, unsigned *RSSI = NULL);
/** /**
Write samples to the LMS. Write samples to the LMS.
@param buf Contains the data to be written. @param buf Contains the data to be written.
@param len number of samples to write. @param len number of samples to write.
@param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough @param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
@param timestamp The timestamp of the first sample of the data buffer. @param timestamp The timestamp of the first sample of the data buffer.
@param isControl Set if data is a control packet, e.g. a ping command
@return The number of samples actually written @return The number of samples actually written
*/ */
int writeSamples(std::vector < short *>&bufs, int len, bool * underrun, int writeSamples(std::vector < short *>&bufs, int len, bool * underrun,
TIMESTAMP timestamp = 0xffffffff); TIMESTAMP timestamp = 0xffffffff, bool isControl =
false);
/** Update the alignment between the read and write timestamps */ /** Update the alignment between the read and write timestamps */
bool updateAlignment(TIMESTAMP timestamp); bool updateAlignment(TIMESTAMP timestamp);

View File

@@ -121,8 +121,6 @@ static const std::map<dev_key, dev_desc> dev_param_map {
{ std::make_tuple(UMTRX, 4, 4), { 2, 0.0, GSMRATE, 5.1503e-5, "UmTRX 4 SPS" } }, { std::make_tuple(UMTRX, 4, 4), { 2, 0.0, GSMRATE, 5.1503e-5, "UmTRX 4 SPS" } },
{ std::make_tuple(LIMESDR, 4, 4), { 1, GSMRATE*32, GSMRATE, 8.9e-5, "LimeSDR 4 SPS" } }, { std::make_tuple(LIMESDR, 4, 4), { 1, GSMRATE*32, GSMRATE, 8.9e-5, "LimeSDR 4 SPS" } },
{ 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" } },
{ std::make_tuple(OCR01, 4, 1), { 2, 26e6, GSMRATE, B2XX_TIMING_4SPS, "OCR01 4/1 Tx/Rx SPS"} },
{ std::make_tuple(OCR01, 4, 4), { 2, 26e6, GSMRATE, B2XX_TIMING_4_4SPS, "OCR01 4/4 Tx/Rx SPS"} },
}; };
void *async_event_loop(uhd_device *dev) void *async_event_loop(uhd_device *dev)
@@ -370,7 +368,6 @@ bool uhd_device::parse_dev_type()
{ "USRP2", { USRP2, TX_WINDOW_FIXED } }, { "USRP2", { USRP2, TX_WINDOW_FIXED } },
{ "UmTRX", { UMTRX, TX_WINDOW_FIXED } }, { "UmTRX", { UMTRX, TX_WINDOW_FIXED } },
{ "LimeSDR", { LIMESDR, TX_WINDOW_FIXED } }, { "LimeSDR", { LIMESDR, TX_WINDOW_FIXED } },
{ "OCR01", { OCR01, TX_WINDOW_USRP1 } },
}; };
// Compare UHD motherboard and device strings */ // Compare UHD motherboard and device strings */
@@ -412,7 +409,7 @@ static bool uhd_e3xx_version_chk()
void uhd_device::set_channels(bool swap) void uhd_device::set_channels(bool swap)
{ {
if (iface == MULTI_ARFCN) { if (iface == MULTI_ARFCN) {
if (dev_type != B200 && dev_type != B210 && dev_type != OCR01) if (dev_type != B200 && dev_type != B210)
throw std::invalid_argument("Device does not support MCBTS"); throw std::invalid_argument("Device does not support MCBTS");
dev_type = B2XX_MCBTS; dev_type = B2XX_MCBTS;
} }
@@ -424,7 +421,6 @@ void uhd_device::set_channels(bool swap)
switch (dev_type) { switch (dev_type) {
case B210: case B210:
case E3XX: case E3XX:
case OCR01:
if (chans == 1) if (chans == 1)
subdev_string = swap ? "A:B" : "A:A"; subdev_string = swap ? "A:B" : "A:A";
else if (chans == 2) else if (chans == 2)
@@ -586,7 +582,6 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
case E1XX: case E1XX:
case E3XX: case E3XX:
case LIMESDR: case LIMESDR:
case OCR01:
default: default:
break; break;
} }
@@ -726,7 +721,7 @@ int uhd_device::check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls)
} }
int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun, int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun) TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
{ {
ssize_t rc; ssize_t rc;
uhd::time_spec_t ts; uhd::time_spec_t ts;
@@ -809,7 +804,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
} }
int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun, int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
unsigned long long timestamp) unsigned long long timestamp,bool isControl)
{ {
uhd::tx_metadata_t metadata; uhd::tx_metadata_t metadata;
metadata.has_time_spec = true; metadata.has_time_spec = true;
@@ -819,6 +814,12 @@ int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun
*underrun = false; *underrun = false;
// No control packets
if (isControl) {
LOGC(DDEV, ERROR) << "Control packets not supported";
return 0;
}
if (bufs.size() != chans) { if (bufs.size() != chans) {
LOGC(DDEV, ALERT) << "Invalid channel combination " << bufs.size(); LOGC(DDEV, ALERT) << "Invalid channel combination " << bufs.size();
return -1; return -1;

View File

@@ -50,7 +50,6 @@ enum uhd_dev_type {
X3XX, X3XX,
UMTRX, UMTRX,
LIMESDR, LIMESDR,
OCR01,
}; };
/* /*
@@ -75,10 +74,10 @@ public:
enum TxWindowType getWindowType() { return tx_window; } enum TxWindowType getWindowType() { return tx_window; }
int readSamples(std::vector<short *> &bufs, int len, bool *overrun, int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun); TIMESTAMP timestamp, bool *underrun, unsigned *RSSI);
int writeSamples(std::vector<short *> &bufs, int len, bool *underrun, int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp); TIMESTAMP timestamp, bool isControl);
bool updateAlignment(TIMESTAMP timestamp); bool updateAlignment(TIMESTAMP timestamp);

View File

@@ -365,7 +365,7 @@ GSM::Time USRPDevice::minLatency() {
// NOTE: Assumes sequential reads // NOTE: Assumes sequential reads
int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun, int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun) TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
{ {
#ifndef SWLOOPBACK #ifndef SWLOOPBACK
if (!m_uRx) if (!m_uRx)
@@ -433,10 +433,8 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
*underrun = true; *underrun = true;
LOGC(DDEV, DEBUG) << "UNDERRUN in TRX->USRP interface"; LOGC(DDEV, DEBUG) << "UNDERRUN in TRX->USRP interface";
} }
#if 0 if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
/* FIXME: Do something with this ? */
unsigned RSSI = (word0 >> 21) & 0x3f;
#endif
if (!isAligned) continue; if (!isAligned) continue;
unsigned cursorStart = pktTimestamp - timeStart + dataStart; unsigned cursorStart = pktTimestamp - timeStart + dataStart;
@@ -515,8 +513,9 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
#endif #endif
} }
int USRPDevice::writeSamplesControl(std::vector<short *> &bufs, int len, int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
bool *underrun, unsigned long long timestamp, bool isControl) bool *underrun, unsigned long long timestamp,
bool isControl)
{ {
writeLock.lock(); writeLock.lock();
@@ -570,12 +569,6 @@ int USRPDevice::writeSamplesControl(std::vector<short *> &bufs, int len,
#endif #endif
} }
int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
bool *underrun, unsigned long long timestamp)
{
return writeSamplesControl(bufs, len, underrun, timestamp, false);
}
bool USRPDevice::updateAlignment(TIMESTAMP timestamp) bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
{ {
#ifndef SWLOOPBACK #ifndef SWLOOPBACK
@@ -585,7 +578,7 @@ bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
bool tmpUnderrun; bool tmpUnderrun;
std::vector<short *> buf(1, data); std::vector<short *> buf(1, data);
if (writeSamplesControl(buf, 1, &tmpUnderrun, timestamp & 0x0ffffffffll, true)) { if (writeSamples(buf, 1, &tmpUnderrun, timestamp & 0x0ffffffffll, true)) {
pingTimestamp = timestamp; pingTimestamp = timestamp;
return true; return true;
} }

View File

@@ -82,9 +82,6 @@ private:
double rxGain; double rxGain;
double txGain; double txGain;
int writeSamplesControl(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp = 0xffffffff, bool isControl = false);
#ifdef SWLOOPBACK #ifdef SWLOOPBACK
short loopbackBuffer[1000000]; short loopbackBuffer[1000000];
int loopbackBufferSize; int loopbackBufferSize;
@@ -120,20 +117,23 @@ private:
@param overrun Set if read buffer has been overrun, e.g. data not being read fast enough @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
@param timestamp The timestamp of the first samples to be read @param timestamp The timestamp of the first samples to be read
@param underrun Set if USRP does not have data to transmit, e.g. data not being sent fast enough @param underrun Set if USRP does not have data to transmit, e.g. data not being sent fast enough
@param RSSI The received signal strength of the read result
@return The number of samples actually read @return The number of samples actually read
*/ */
int readSamples(std::vector<short *> &buf, int len, bool *overrun, int readSamples(std::vector<short *> &buf, int len, bool *overrun,
TIMESTAMP timestamp = 0xffffffff, bool *underrun = NULL); TIMESTAMP timestamp = 0xffffffff, bool *underrun = NULL,
unsigned *RSSI = NULL);
/** /**
Write samples to the USRP. Write samples to the USRP.
@param buf Contains the data to be written. @param buf Contains the data to be written.
@param len number of samples to write. @param len number of samples to write.
@param underrun Set if USRP does not have data to transmit, e.g. data not being sent fast enough @param underrun Set if USRP does not have data to transmit, e.g. data not being sent fast enough
@param timestamp The timestamp of the first sample of the data buffer. @param timestamp The timestamp of the first sample of the data buffer.
@param isControl Set if data is a control packet, e.g. a ping command
@return The number of samples actually written @return The number of samples actually written
*/ */
int writeSamples(std::vector<short *> &bufs, int len, bool *underrun, int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp = 0xffffffff); TIMESTAMP timestamp = 0xffffffff, bool isControl = false);
/** Update the alignment between the read and write timestamps */ /** Update the alignment between the read and write timestamps */
bool updateAlignment(TIMESTAMP timestamp); bool updateAlignment(TIMESTAMP timestamp);

View File

@@ -47,7 +47,7 @@ void signalVector::operator=(const signalVector& vector)
complex *src = vector.mData; complex *src = vector.mData;
for (i = 0; i < size(); i++, src++, dst++) for (i = 0; i < size(); i++, src++, dst++)
*dst = *src; *dst = *src;
/* TODO: optimize for non non-trivially copiable types: */ /* TODO: optimize for non non-trivially copyable types: */
/*memcpy(mData, vector.mData, bytes()); */ /*memcpy(mData, vector.mData, bytes()); */
mStart = mData + vector.getStart(); mStart = mData + vector.getStart();
} }
@@ -70,7 +70,7 @@ size_t signalVector::updateHistory()
complex *src = mStart + this->size() - num; complex *src = mStart + this->size() - num;
for (i = 0; i < num; i++, src++, dst++) for (i = 0; i < num; i++, src++, dst++)
*dst = *src; *dst = *src;
/* TODO: optimize for non non-trivially copiable types: */ /* TODO: optimize for non non-trivially copyable types: */
/*memmove(mData, mStart + this->size() - num, num * sizeof(complex)); */ /*memmove(mData, mStart + this->size() - num, num * sizeof(complex)); */
return num; return num;

View File

@@ -75,15 +75,6 @@ AC_TYPE_SIZE_T
AC_HEADER_TIME AC_HEADER_TIME
AC_C_BIGENDIAN AC_C_BIGENDIAN
# Check if gettid is available (despite not being documented in glibc doc, it requires __USE_GNU on some systems)
# C compiler is used since __USE_GNU seems to be always defined for g++.
save_CPPFLAGS=$CPPFLAGS
AC_LANG_PUSH(C)
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
AC_CHECK_FUNCS([gettid])
AC_LANG_POP(C)
CPPFLAGS=$save_CPPFLAGS
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.3.0) PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.3.0) PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.3.0) PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.3.0)

View File

@@ -23,8 +23,15 @@ mychroot() {
mychroot_nocwd -w / "$@" mychroot_nocwd -w / "$@"
} }
base="$PWD"
deps="$base/deps"
inst="$deps/install"
export deps inst
if [ -z "${INSIDE_CHROOT}" ]; then if [ -z "${INSIDE_CHROOT}" ]; then
osmo-clean-workspace.sh
# Only use ARM chroot if host is not ARM and the target is ARM: # Only use ARM chroot if host is not ARM and the target is ARM:
if ! $(substr "arm" "$(uname -m)") && [ "x${INSTR}" = "x--with-neon" -o "x${INSTR}" = "x--with-neon-vfpv4" ]; then if ! $(substr "arm" "$(uname -m)") && [ "x${INSTR}" = "x--with-neon" -o "x${INSTR}" = "x--with-neon-vfpv4" ]; then
@@ -62,20 +69,6 @@ if [ -z "${INSIDE_CHROOT}" ]; then
fi fi
fi fi
set -ex
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
exit 2
fi
base="$PWD"
deps="$base/deps"
inst="$deps/install"
export deps inst
osmo-clean-workspace.sh
mkdir "$deps" || true mkdir "$deps" || true
osmo-build-dep.sh libosmocore "" "--enable-sanitize --disable-doxygen --disable-pcsc" osmo-build-dep.sh libosmocore "" "--enable-sanitize --disable-doxygen --disable-pcsc"