254 lines
7.6 KiB
C++
254 lines
7.6 KiB
C++
/*
|
|
* Copyright 2018 sysmocom - s.f.m.c. GmbH
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0+
|
|
*
|
|
* This software is distributed under multiple licenses; see the COPYING file in
|
|
* the main directory for licensing information for this specific distribution.
|
|
*
|
|
* This use of this software may be subject to additional restrictions.
|
|
* See the LEGAL file in the main directory for details.
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
#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>
|
|
#include <math.h>
|
|
#include <limits.h>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <lime/LimeSuite.h>
|
|
|
|
extern "C" {
|
|
#include <osmocom/gsm/gsm_utils.h>
|
|
}
|
|
|
|
/* Definition of LIMESDR_TX_AMPL limits maximum amplitude of I and Q
|
|
* channels separately. Hence LIMESDR_TX_AMPL value must be 1/sqrt(2) =
|
|
* 0.7071.... to get an amplitude of 1 of the complex signal:
|
|
* A^2 = I^2 + Q^2
|
|
* A^2 = (1/sqrt(2))^2 + (1/sqrt(2))^2
|
|
* A^2 = 1/2 + 1/2
|
|
* A^2 = 1 */
|
|
#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,
|
|
};
|
|
|
|
struct dev_band_desc {
|
|
/* Maximum LimeSuite Tx Gain which can be set/used without distorting
|
|
the output * signal, and the resulting real output power measured
|
|
when that gain is used.
|
|
*/
|
|
double nom_lms_tx_gain; /* dB */
|
|
double nom_out_tx_power; /* dBm */
|
|
/* Factor used to infer base real RSSI offset on the Rx path based on current
|
|
configured RxGain. The resulting rssiOffset is added to the per burst
|
|
calculated energy in upper layers. These values were empirically
|
|
found and may change based on multiple factors, see OS#4468.
|
|
Correct measured values only provided for LimeSDR-USB so far.
|
|
rssiOffset = rxGain + rxgain2rssioffset_rel;
|
|
*/
|
|
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, public band_manager<power_map_t, dev_map_t> {
|
|
|
|
private:
|
|
lms_device_t *m_lms_dev;
|
|
std::vector<lms_stream_t> m_lms_stream_rx;
|
|
std::vector<lms_stream_t> m_lms_stream_tx;
|
|
|
|
std::vector<smpl_buf *> rx_buffers;
|
|
|
|
double actualSampleRate; ///< the actual USRP sampling rate
|
|
|
|
bool started; ///< flag indicates LMS has started
|
|
bool skipRx; ///< set if LMS is transmit-only.
|
|
|
|
TIMESTAMP ts_initial, ts_offset;
|
|
|
|
std::vector<double> tx_gains, rx_gains;
|
|
|
|
enum lms_dev_type m_dev_type;
|
|
|
|
bool do_calib(size_t chan);
|
|
bool do_filters(size_t chan);
|
|
void log_ant_list(bool dir_tx, size_t chan, std::ostringstream& os);
|
|
int get_ant_idx(const std::string & name, bool dir_tx, size_t chan);
|
|
bool flush_recv(size_t num_pkts);
|
|
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);
|
|
public:
|
|
|
|
/** Object constructor */
|
|
LMSDevice(InterfaceType iface, const struct trx_cfg *cfg);
|
|
~LMSDevice();
|
|
|
|
/** Instantiate the LMS */
|
|
int open();
|
|
|
|
/** Start the LMS */
|
|
bool start();
|
|
|
|
/** Stop the LMS */
|
|
bool stop();
|
|
|
|
enum TxWindowType getWindowType()
|
|
{
|
|
return TX_WINDOW_LMS1;
|
|
}
|
|
|
|
/**
|
|
Read samples from the LMS.
|
|
@param buf preallocated buf to contain read result
|
|
@param len number of samples desired
|
|
@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 underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
|
|
@return The number of samples actually read
|
|
*/
|
|
int readSamples(std::vector < short *>&buf, int len, bool * overrun,
|
|
TIMESTAMP timestamp = 0xffffffff, bool * underrun =
|
|
NULL);
|
|
/**
|
|
Write samples to the LMS.
|
|
@param buf Contains the data to be written.
|
|
@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 timestamp The timestamp of the first sample of the data buffer.
|
|
@return The number of samples actually written
|
|
*/
|
|
int writeSamples(std::vector < short *>&bufs, int len, bool * underrun,
|
|
TIMESTAMP timestamp = 0xffffffff);
|
|
|
|
/** Update the alignment between the read and write timestamps */
|
|
bool updateAlignment(TIMESTAMP timestamp);
|
|
|
|
/** Set the transmitter frequency */
|
|
bool setTxFreq(double wFreq, size_t chan = 0);
|
|
|
|
/** Set the receiver frequency */
|
|
bool setRxFreq(double wFreq, size_t chan = 0);
|
|
|
|
/** Returns the starting write Timestamp*/
|
|
TIMESTAMP initialWriteTimestamp(void) {
|
|
return ts_initial;
|
|
}
|
|
|
|
/** Returns the starting read Timestamp*/
|
|
TIMESTAMP initialReadTimestamp(void) {
|
|
return ts_initial;
|
|
}
|
|
|
|
/** returns the full-scale transmit amplitude **/
|
|
double fullScaleInputValue() {
|
|
return(double) SHRT_MAX * LIMESDR_TX_AMPL;
|
|
}
|
|
|
|
/** returns the full-scale receive amplitude **/
|
|
double fullScaleOutputValue() {
|
|
return (double) SHRT_MAX;
|
|
}
|
|
|
|
/** sets the receive chan gain, returns the gain setting **/
|
|
double setRxGain(double dB, size_t chan = 0);
|
|
|
|
/** get the current receive gain */
|
|
double getRxGain(size_t chan = 0) {
|
|
return rx_gains[chan];
|
|
}
|
|
|
|
/** return maximum Rx Gain **/
|
|
double maxRxGain(void);
|
|
|
|
/** return minimum Rx Gain **/
|
|
double minRxGain(void);
|
|
|
|
double rssiOffset(size_t chan);
|
|
|
|
double setPowerAttenuation(int atten, size_t chan);
|
|
double getPowerAttenuation(size_t chan = 0);
|
|
|
|
int getNominalTxPower(size_t chan = 0);
|
|
|
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
|
bool setRxAntenna(const std::string & ant, size_t chan = 0);
|
|
|
|
/* return the used RX path */
|
|
std::string getRxAntenna(size_t chan = 0);
|
|
|
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
|
bool setTxAntenna(const std::string & ant, size_t chan = 0);
|
|
|
|
/* return the used RX path */
|
|
std::string getTxAntenna(size_t chan = 0);
|
|
|
|
/** return whether user drives synchronization of Tx/Rx of USRP */
|
|
bool requiresRadioAlign();
|
|
|
|
/** return whether user drives synchronization of Tx/Rx of USRP */
|
|
virtual GSM::Time minLatency();
|
|
|
|
/** Return internal status values */
|
|
inline double getTxFreq(size_t chan = 0) {
|
|
return 0;
|
|
}
|
|
inline double getRxFreq(size_t chan = 0) {
|
|
return 0;
|
|
}
|
|
inline double getSampleRate() {
|
|
return actualSampleRate;
|
|
}
|
|
};
|
|
|
|
#endif // _LMS_DEVICE_H_
|