blob: 2e5ca4c0bdd60743bb8560e888570b25403b8b45 [file] [log] [blame]
Harald Welte940738e2018-03-07 07:50:57 +01001/*
2* Copyright 2018 sysmocom - s.f.m.c. GmbH
3*
Pau Espin Pedrol21d03d32019-07-22 12:05:52 +02004* SPDX-License-Identifier: AGPL-3.0+
5*
6* This software is distributed under multiple licenses; see the COPYING file in
Martin Hauke066fd042019-10-13 19:08:00 +02007* the main directory for licensing information for this specific distribution.
Harald Welte940738e2018-03-07 07:50:57 +01008*
9* This use of this software may be subject to additional restrictions.
10* See the LEGAL file in the main directory for details.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
16*/
17
18#ifndef _LMS_DEVICE_H_
19#define _LMS_DEVICE_H_
20
Ericc0f78a32023-05-12 13:00:14 +020021#include <map>
Harald Welte940738e2018-03-07 07:50:57 +010022#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include "radioDevice.h"
Ericc0f78a32023-05-12 13:00:14 +020027#include "bandmanager.h"
Pau Espin Pedroldcbcfa52019-05-03 16:15:06 +020028#include "smpl_buf.h"
Harald Welte940738e2018-03-07 07:50:57 +010029
Harald Welte940738e2018-03-07 07:50:57 +010030#include <sys/time.h>
31#include <math.h>
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +020032#include <limits.h>
Harald Welte940738e2018-03-07 07:50:57 +010033#include <string>
34#include <iostream>
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +020035#include <lime/LimeSuite.h>
36
Pau Espin Pedrolf68f19b2020-06-19 14:48:09 +020037extern "C" {
38#include <osmocom/gsm/gsm_utils.h>
39}
40
Harald Welte0277b582018-11-26 19:17:00 +010041/* Definition of LIMESDR_TX_AMPL limits maximum amplitude of I and Q
42 * channels separately. Hence LIMESDR_TX_AMPL value must be 1/sqrt(2) =
43 * 0.7071.... to get an amplitude of 1 of the complex signal:
44 * A^2 = I^2 + Q^2
45 * A^2 = (1/sqrt(2))^2 + (1/sqrt(2))^2
46 * A^2 = 1/2 + 1/2
47 * A^2 = 1 */
48#define LIMESDR_TX_AMPL 0.707
Harald Welte940738e2018-03-07 07:50:57 +010049
Pau Espin Pedrola7bf6cd2020-01-14 17:52:15 +010050enum lms_dev_type {
51 LMS_DEV_SDR_USB, /* LimeSDR-USB */
52 LMS_DEV_SDR_MINI, /* LimeSDR-Mini */
53 LMS_DEV_NET_MICRO, /* LimeNet-micro */
54 LMS_DEV_UNKNOWN,
55};
56
Pau Espin Pedrole91544d2020-10-13 17:03:37 +020057struct dev_band_desc {
58 /* Maximum LimeSuite Tx Gain which can be set/used without distorting
59 the output * signal, and the resulting real output power measured
60 when that gain is used.
61 */
62 double nom_lms_tx_gain; /* dB */
63 double nom_out_tx_power; /* dBm */
64 /* Factor used to infer base real RSSI offset on the Rx path based on current
65 configured RxGain. The resulting rssiOffset is added to the per burst
66 calculated energy in upper layers. These values were empirically
67 found and may change based on multiple factors, see OS#4468.
68 Correct measured values only provided for LimeSDR-USB so far.
69 rssiOffset = rxGain + rxgain2rssioffset_rel;
70 */
71 double rxgain2rssioffset_rel; /* dB */
72};
Pau Espin Pedrolf68f19b2020-06-19 14:48:09 +020073
Ericc0f78a32023-05-12 13:00:14 +020074/* Device parameter descriptor */
75struct dev_desc {
76 /* Does LimeSuite allow switching the clock source for this device?
77 * LimeSDR-Mini does not have switches but needs soldering to select
78 * external/internal clock. Any call to LMS_SetClockFreq() will fail.
79 */
80 bool clock_src_switchable;
81 /* Does LimeSuite allow using REF_INTERNAL for this device?
82 * LimeNET-Micro does not like selecting internal clock
83 */
84 bool clock_src_int_usable;
85 /* Sample rate coef (without having TX/RX samples per symbol into account) */
86 double rate;
87 /* Sample rate coef (without having TX/RX samples per symbol into account), if multi-arfcn is enabled */
88 double rate_multiarfcn;
89 /* Coefficient multiplied by TX sample rate in order to shift Tx time */
90 double ts_offset_coef;
91 /* Coefficient multiplied by TX sample rate in order to shift Tx time, if multi-arfcn is enabled */
92 double ts_offset_coef_multiarfcn;
93 /* Device Name Prefix as presented by LimeSuite API LMS_GetDeviceInfo() */
94 std::string desc_str;
95};
96
97using dev_band_key_t = std::tuple<lms_dev_type, gsm_band>;
98using power_map_t = std::map<dev_band_key_t, dev_band_desc>;
99using dev_map_t = std::map<lms_dev_type, struct dev_desc>;
100
Harald Welte940738e2018-03-07 07:50:57 +0100101/** A class to handle a LimeSuite supported device */
Ericc0f78a32023-05-12 13:00:14 +0200102class LMSDevice:public RadioDevice, public band_manager<power_map_t, dev_map_t> {
Harald Welte940738e2018-03-07 07:50:57 +0100103
104private:
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200105 lms_device_t *m_lms_dev;
106 std::vector<lms_stream_t> m_lms_stream_rx;
107 std::vector<lms_stream_t> m_lms_stream_tx;
108
Pau Espin Pedroldcbcfa52019-05-03 16:15:06 +0200109 std::vector<smpl_buf *> rx_buffers;
110
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200111 double actualSampleRate; ///< the actual USRP sampling rate
Harald Welte940738e2018-03-07 07:50:57 +0100112
Harald Welte940738e2018-03-07 07:50:57 +0100113 bool started; ///< flag indicates LMS has started
114 bool skipRx; ///< set if LMS is transmit-only.
115
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200116 TIMESTAMP ts_initial, ts_offset;
117
Pau Espin Pedrol705a3482019-09-13 16:51:48 +0200118 std::vector<double> tx_gains, rx_gains;
Pau Espin Pedrola7bf6cd2020-01-14 17:52:15 +0100119
120 enum lms_dev_type m_dev_type;
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200121
Joachim Steiger4ce45552019-04-16 16:35:53 +0200122 bool do_calib(size_t chan);
123 bool do_filters(size_t chan);
Pau Espin Pedrole0010fa2019-08-26 17:10:27 +0200124 void log_ant_list(bool dir_tx, size_t chan, std::ostringstream& os);
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200125 int get_ant_idx(const std::string & name, bool dir_tx, size_t chan);
126 bool flush_recv(size_t num_pkts);
Pau Espin Pedrol68a78092019-07-29 20:11:25 +0200127 void update_stream_stats_rx(size_t chan, bool *overrun);
128 void update_stream_stats_tx(size_t chan, bool *underrun);
Pau Espin Pedrola7bf6cd2020-01-14 17:52:15 +0100129 bool do_clock_src_freq(enum ReferenceType ref, double freq);
Harald Welte940738e2018-03-07 07:50:57 +0100130public:
131
132 /** Object constructor */
Eric19e134a2023-05-10 23:50:38 +0200133 LMSDevice(InterfaceType iface, const struct trx_cfg *cfg);
134 ~LMSDevice();
Harald Welte940738e2018-03-07 07:50:57 +0100135
Eric19e134a2023-05-10 23:50:38 +0200136 /** Instantiate the LMS */
137 int open();
Harald Welte940738e2018-03-07 07:50:57 +0100138
Eric19e134a2023-05-10 23:50:38 +0200139 /** Start the LMS */
140 bool start();
Harald Welte940738e2018-03-07 07:50:57 +0100141
Eric19e134a2023-05-10 23:50:38 +0200142 /** Stop the LMS */
143 bool stop();
Harald Welte940738e2018-03-07 07:50:57 +0100144
Eric19e134a2023-05-10 23:50:38 +0200145 enum TxWindowType getWindowType()
146 {
147 return TX_WINDOW_LMS1;
148 }
Harald Welte940738e2018-03-07 07:50:57 +0100149
150 /**
151 Read samples from the LMS.
152 @param buf preallocated buf to contain read result
153 @param len number of samples desired
154 @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
155 @param timestamp The timestamp of the first samples to be read
156 @param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
Harald Welte940738e2018-03-07 07:50:57 +0100157 @return The number of samples actually read
158 */
159 int readSamples(std::vector < short *>&buf, int len, bool * overrun,
160 TIMESTAMP timestamp = 0xffffffff, bool * underrun =
Pau Espin Pedrolf8c0c462020-03-12 19:08:46 +0100161 NULL);
Harald Welte940738e2018-03-07 07:50:57 +0100162 /**
163 Write samples to the LMS.
164 @param buf Contains the data to be written.
165 @param len number of samples to write.
166 @param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
167 @param timestamp The timestamp of the first sample of the data buffer.
Harald Welte940738e2018-03-07 07:50:57 +0100168 @return The number of samples actually written
169 */
170 int writeSamples(std::vector < short *>&bufs, int len, bool * underrun,
Pau Espin Pedroldfc6e5f2020-03-12 19:35:33 +0100171 TIMESTAMP timestamp = 0xffffffff);
Harald Welte940738e2018-03-07 07:50:57 +0100172
173 /** Update the alignment between the read and write timestamps */
174 bool updateAlignment(TIMESTAMP timestamp);
175
176 /** Set the transmitter frequency */
177 bool setTxFreq(double wFreq, size_t chan = 0);
178
179 /** Set the receiver frequency */
180 bool setRxFreq(double wFreq, size_t chan = 0);
181
182 /** Returns the starting write Timestamp*/
183 TIMESTAMP initialWriteTimestamp(void) {
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200184 return ts_initial;
Harald Welte940738e2018-03-07 07:50:57 +0100185 }
186
187 /** Returns the starting read Timestamp*/
188 TIMESTAMP initialReadTimestamp(void) {
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200189 return ts_initial;
Harald Welte940738e2018-03-07 07:50:57 +0100190 }
191
192 /** returns the full-scale transmit amplitude **/
193 double fullScaleInputValue() {
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200194 return(double) SHRT_MAX * LIMESDR_TX_AMPL;
Harald Welte940738e2018-03-07 07:50:57 +0100195 }
196
197 /** returns the full-scale receive amplitude **/
198 double fullScaleOutputValue() {
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200199 return (double) SHRT_MAX;
Harald Welte940738e2018-03-07 07:50:57 +0100200 }
201
202 /** sets the receive chan gain, returns the gain setting **/
203 double setRxGain(double dB, size_t chan = 0);
204
205 /** get the current receive gain */
206 double getRxGain(size_t chan = 0) {
Pau Espin Pedrol705a3482019-09-13 16:51:48 +0200207 return rx_gains[chan];
Harald Welte940738e2018-03-07 07:50:57 +0100208 }
209
210 /** return maximum Rx Gain **/
211 double maxRxGain(void);
212
213 /** return minimum Rx Gain **/
214 double minRxGain(void);
215
Pau Espin Pedrole91544d2020-10-13 17:03:37 +0200216 double rssiOffset(size_t chan);
Pau Espin Pedrolf68f19b2020-06-19 14:48:09 +0200217
218 double setPowerAttenuation(int atten, size_t chan);
219 double getPowerAttenuation(size_t chan = 0);
220
Pau Espin Pedrol0e09e7c2020-05-29 16:39:07 +0200221 int getNominalTxPower(size_t chan = 0);
222
Harald Welte940738e2018-03-07 07:50:57 +0100223 /** sets the RX path to use, returns true if successful and false otherwise */
224 bool setRxAntenna(const std::string & ant, size_t chan = 0);
225
226 /* return the used RX path */
227 std::string getRxAntenna(size_t chan = 0);
228
229 /** sets the RX path to use, returns true if successful and false otherwise */
230 bool setTxAntenna(const std::string & ant, size_t chan = 0);
231
232 /* return the used RX path */
233 std::string getTxAntenna(size_t chan = 0);
234
Pau Espin Pedrolc7a0bf12018-04-25 12:17:10 +0200235 /** return whether user drives synchronization of Tx/Rx of USRP */
236 bool requiresRadioAlign();
237
238 /** return whether user drives synchronization of Tx/Rx of USRP */
239 virtual GSM::Time minLatency();
240
Harald Welte940738e2018-03-07 07:50:57 +0100241 /** Return internal status values */
242 inline double getTxFreq(size_t chan = 0) {
243 return 0;
244 }
245 inline double getRxFreq(size_t chan = 0) {
246 return 0;
247 }
248 inline double getSampleRate() {
249 return actualSampleRate;
250 }
Harald Welte940738e2018-03-07 07:50:57 +0100251};
252
253#endif // _LMS_DEVICE_H_