/* * 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_ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "radioDevice.h" #include "smpl_buf.h" #include #include #include #include #include #include /* 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, }; /** A class to handle a LimeSuite supported device */ class LMSDevice:public RadioDevice { private: lms_device_t *m_lms_dev; std::vector m_lms_stream_rx; std::vector m_lms_stream_tx; std::vector 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 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(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset, const std::vector& tx_paths, const std::vector& rx_paths); ~LMSDevice(); /** Instantiate the LMS */ int open(const std::string &args, int ref, bool swap_channels); /** 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. @param isControl Set if data is a control packet, e.g. a ping command @return The number of samples actually written */ int writeSamples(std::vector < short *>&bufs, int len, bool * underrun, TIMESTAMP timestamp = 0xffffffff, bool isControl = false); /** 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); /** sets the transmit chan gain, returns the gain setting **/ double setTxGain(double dB, size_t chan = 0); /** get transmit gain */ double getTxGain(size_t chan = 0) { return tx_gains[chan]; } /** return maximum Tx Gain **/ double maxTxGain(void); /** return minimum Rx Gain **/ double minTxGain(void); /** 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_