blob: 7f73f43627dadd03b59bac6cdc210523838d5a31 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009 Free Software Foundation, Inc.
3*
4* This software is distributed under the terms of the GNU Affero Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
19
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23*/
24
25
26/*
27 Compilation Flags
28
29 SWLOOPBACK compile for software loopback testing
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +010030*/
dburgessb3a0ca42011-10-12 07:44:40 +000031
32
33#include <stdint.h>
34#include <string.h>
35#include <stdlib.h>
Alexander Huemer6fafd332018-01-12 15:04:02 +010036#include "Logger.h"
dburgessb3a0ca42011-10-12 07:44:40 +000037#include "Threads.h"
38#include "USRPDevice.h"
39
kurtis.heimerl3758b162011-11-26 03:19:22 +000040#ifdef HAVE_CONFIG_H
41#include "config.h"
42#endif
dburgessb3a0ca42011-10-12 07:44:40 +000043
44using namespace std;
45
kurtis.heimerl79e71c92011-11-26 03:16:48 +000046enum dboardConfigType {
47 TXA_RXB,
48 TXB_RXA,
49 TXA_RXA,
50 TXB_RXB
51};
dburgessb3a0ca42011-10-12 07:44:40 +000052
kurtis.heimerl3758b162011-11-26 03:19:22 +000053#ifdef SINGLEDB
54const dboardConfigType dboardConfig = TXA_RXA;
55#else
kurtis.heimerl79e71c92011-11-26 03:16:48 +000056const dboardConfigType dboardConfig = TXA_RXB;
kurtis.heimerl3758b162011-11-26 03:19:22 +000057#endif
58
kurtis.heimerl79e71c92011-11-26 03:16:48 +000059const double USRPDevice::masterClockRate = 52.0e6;
dburgessb3a0ca42011-10-12 07:44:40 +000060
Tom Tsou5cd70dc2016-03-06 01:28:40 -080061USRPDevice::USRPDevice(size_t sps)
dburgessb3a0ca42011-10-12 07:44:40 +000062{
63 LOG(INFO) << "creating USRP device...";
Thomas Tsouc1f7c422013-10-11 13:49:55 -040064
65 this->sps = sps;
Thomas Tsoucb69f082013-04-08 14:18:26 -040066 decimRate = (unsigned int) round(masterClockRate/((GSMRATE) * (double) sps));
dburgessb3a0ca42011-10-12 07:44:40 +000067 actualSampleRate = masterClockRate/decimRate;
68 rxGain = 0;
69
Thomas Tsouc1f7c422013-10-11 13:49:55 -040070 /*
71 * Undetermined delay b/w ping response timestamp and true
72 * receive timestamp. Values are empirically measured. With
73 * split sample rate Tx/Rx - 4/1 sps we need to need to
74 * compensate for advance rather than delay.
75 */
76 if (sps == 1)
77 pingOffset = 272;
78 else if (sps == 4)
79 pingOffset = 269 - 7500;
80 else
81 pingOffset = 0;
82
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +010083#ifdef SWLOOPBACK
dburgessb3a0ca42011-10-12 07:44:40 +000084 samplePeriod = 1.0e6/actualSampleRate;
85 loopbackBufferSize = 0;
86 gettimeofday(&lastReadTime,NULL);
87 firstRead = false;
88#endif
89}
90
Tom Tsou2f3e60b2016-07-17 19:29:08 -070091int USRPDevice::open(const std::string &, int, bool)
dburgessb3a0ca42011-10-12 07:44:40 +000092{
dburgessb3a0ca42011-10-12 07:44:40 +000093 writeLock.unlock();
94
kurtis.heimerl965e7572011-11-26 03:16:54 +000095 LOG(INFO) << "opening USRP device..";
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +010096#ifndef SWLOOPBACK
dburgessb3a0ca42011-10-12 07:44:40 +000097 string rbf = "std_inband.rbf";
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +010098 //string rbf = "inband_1rxhb_1tx.rbf";
dburgessb3a0ca42011-10-12 07:44:40 +000099 m_uRx.reset();
100 if (!skipRx) {
101 try {
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400102 m_uRx = usrp_standard_rx_sptr(usrp_standard_rx::make(
103 0, decimRate * sps, 1, -1,
104 usrp_standard_rx::FPGA_MODE_NORMAL,
105 1024, 16 * 8, rbf));
dburgessb3a0ca42011-10-12 07:44:40 +0000106 m_uRx->set_fpga_master_clock_freq(masterClockRate);
dburgessb3a0ca42011-10-12 07:44:40 +0000107 }
Thomas Tsouc0641242013-10-11 14:55:31 -0400108
dburgessb3a0ca42011-10-12 07:44:40 +0000109 catch(...) {
110 LOG(ALERT) << "make failed on Rx";
111 m_uRx.reset();
Thomas Tsoucb69f082013-04-08 14:18:26 -0400112 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000113 }
114
115 if (m_uRx->fpga_master_clock_freq() != masterClockRate)
116 {
117 LOG(ALERT) << "WRONG FPGA clock freq = " << m_uRx->fpga_master_clock_freq()
118 << ", desired clock freq = " << masterClockRate;
119 m_uRx.reset();
Thomas Tsoucb69f082013-04-08 14:18:26 -0400120 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000121 }
122 }
123
124 try {
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400125 m_uTx = usrp_standard_tx_sptr(usrp_standard_tx::make(
126 0, decimRate * 2, 1, -1,
127 1024, 16 * 8, rbf));
dburgessb3a0ca42011-10-12 07:44:40 +0000128 m_uTx->set_fpga_master_clock_freq(masterClockRate);
dburgessb3a0ca42011-10-12 07:44:40 +0000129 }
Thomas Tsouc0641242013-10-11 14:55:31 -0400130
dburgessb3a0ca42011-10-12 07:44:40 +0000131 catch(...) {
132 LOG(ALERT) << "make failed on Tx";
133 m_uTx.reset();
Thomas Tsoucb69f082013-04-08 14:18:26 -0400134 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000135 }
136
137 if (m_uTx->fpga_master_clock_freq() != masterClockRate)
138 {
139 LOG(ALERT) << "WRONG FPGA clock freq = " << m_uTx->fpga_master_clock_freq()
140 << ", desired clock freq = " << masterClockRate;
141 m_uTx.reset();
Thomas Tsoucb69f082013-04-08 14:18:26 -0400142 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000143 }
144
145 if (!skipRx) m_uRx->stop();
146 m_uTx->stop();
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100147
dburgessb3a0ca42011-10-12 07:44:40 +0000148#endif
149
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000150 switch (dboardConfig) {
151 case TXA_RXB:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000152 txSubdevSpec = usrp_subdev_spec(0,0);
153 rxSubdevSpec = usrp_subdev_spec(1,0);
154 break;
155 case TXB_RXA:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000156 txSubdevSpec = usrp_subdev_spec(1,0);
157 rxSubdevSpec = usrp_subdev_spec(0,0);
158 break;
159 case TXA_RXA:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000160 txSubdevSpec = usrp_subdev_spec(0,0);
161 rxSubdevSpec = usrp_subdev_spec(0,0);
162 break;
163 case TXB_RXB:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000164 txSubdevSpec = usrp_subdev_spec(1,0);
165 rxSubdevSpec = usrp_subdev_spec(1,0);
166 break;
167 default:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000168 txSubdevSpec = usrp_subdev_spec(0,0);
169 rxSubdevSpec = usrp_subdev_spec(1,0);
170 }
171
kurtis.heimerlb9e237e2011-11-26 03:17:59 +0000172 m_dbTx = m_uTx->selected_subdev(txSubdevSpec);
173 m_dbRx = m_uRx->selected_subdev(rxSubdevSpec);
174
dburgessb3a0ca42011-10-12 07:44:40 +0000175 samplesRead = 0;
176 samplesWritten = 0;
177 started = false;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100178
Thomas Tsoucb69f082013-04-08 14:18:26 -0400179 return NORMAL;
dburgessb3a0ca42011-10-12 07:44:40 +0000180}
181
182
183
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100184bool USRPDevice::start()
dburgessb3a0ca42011-10-12 07:44:40 +0000185{
186 LOG(INFO) << "starting USRP...";
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100187#ifndef SWLOOPBACK
dburgessb3a0ca42011-10-12 07:44:40 +0000188 if (!m_uRx && !skipRx) return false;
189 if (!m_uTx) return false;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100190
dburgessb3a0ca42011-10-12 07:44:40 +0000191 if (!skipRx) m_uRx->stop();
192 m_uTx->stop();
193
194 writeLock.lock();
195 // power up and configure daughterboards
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000196 m_dbTx->set_enable(true);
197 m_uTx->set_mux(m_uTx->determine_tx_mux_value(txSubdevSpec));
198 m_uRx->set_mux(m_uRx->determine_rx_mux_value(rxSubdevSpec));
199
200 if (!m_dbRx->select_rx_antenna(1))
201 m_dbRx->select_rx_antenna(0);
202
dburgessb3a0ca42011-10-12 07:44:40 +0000203 writeLock.unlock();
204
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000205 // Set gains to midpoint
206 setTxGain((minTxGain() + maxTxGain()) / 2);
207 setRxGain((minRxGain() + maxRxGain()) / 2);
dburgessb3a0ca42011-10-12 07:44:40 +0000208
209 data = new short[currDataSize];
210 dataStart = 0;
211 dataEnd = 0;
212 timeStart = 0;
213 timeEnd = 0;
214 timestampOffset = 0;
215 latestWriteTimestamp = 0;
216 lastPktTimestamp = 0;
217 hi32Timestamp = 0;
218 isAligned = false;
219
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100220
221 if (!skipRx)
dburgessb3a0ca42011-10-12 07:44:40 +0000222 started = (m_uRx->start() && m_uTx->start());
223 else
224 started = m_uTx->start();
225 return started;
226#else
227 gettimeofday(&lastReadTime,NULL);
228 return true;
229#endif
230}
231
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100232bool USRPDevice::stop()
dburgessb3a0ca42011-10-12 07:44:40 +0000233{
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100234#ifndef SWLOOPBACK
dburgessb3a0ca42011-10-12 07:44:40 +0000235 if (!m_uRx) return false;
236 if (!m_uTx) return false;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100237
dburgessb3a0ca42011-10-12 07:44:40 +0000238 delete[] currData;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100239
dburgessb3a0ca42011-10-12 07:44:40 +0000240 started = !(m_uRx->stop() && m_uTx->stop());
241 return !started;
242#else
243 return true;
244#endif
245}
246
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000247double USRPDevice::maxTxGain()
248{
249 return m_dbTx->gain_max();
250}
251
252double USRPDevice::minTxGain()
253{
254 return m_dbTx->gain_min();
255}
256
257double USRPDevice::maxRxGain()
258{
259 return m_dbRx->gain_max();
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100260}
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000261
262double USRPDevice::minRxGain()
263{
264 return m_dbRx->gain_min();
265}
266
Thomas Tsou204a9f12013-10-29 18:34:16 -0400267double USRPDevice::setTxGain(double dB, size_t chan)
268{
269 if (chan) {
270 LOG(ALERT) << "Invalid channel " << chan;
271 return 0.0;
272 }
dburgessb3a0ca42011-10-12 07:44:40 +0000273
Thomas Tsou204a9f12013-10-29 18:34:16 -0400274 writeLock.lock();
275 if (dB > maxTxGain())
276 dB = maxTxGain();
277 if (dB < minTxGain())
278 dB = minTxGain();
dburgessb3a0ca42011-10-12 07:44:40 +0000279
Thomas Tsou204a9f12013-10-29 18:34:16 -0400280 LOG(NOTICE) << "Setting TX gain to " << dB << " dB.";
dburgessb3a0ca42011-10-12 07:44:40 +0000281
Thomas Tsou204a9f12013-10-29 18:34:16 -0400282 if (!m_dbTx->set_gain(dB))
283 LOG(ERR) << "Error setting TX gain";
284
285 writeLock.unlock();
286
287 return dB;
dburgessb3a0ca42011-10-12 07:44:40 +0000288}
289
290
Thomas Tsou204a9f12013-10-29 18:34:16 -0400291double USRPDevice::setRxGain(double dB, size_t chan)
292{
293 if (chan) {
294 LOG(ALERT) << "Invalid channel " << chan;
295 return 0.0;
296 }
dburgessb3a0ca42011-10-12 07:44:40 +0000297
Thomas Tsou204a9f12013-10-29 18:34:16 -0400298 dB = 47.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000299
Thomas Tsou204a9f12013-10-29 18:34:16 -0400300 writeLock.lock();
301 if (dB > maxRxGain())
302 dB = maxRxGain();
303 if (dB < minRxGain())
304 dB = minRxGain();
305
306 LOG(NOTICE) << "Setting RX gain to " << dB << " dB.";
307
308 if (!m_dbRx->set_gain(dB))
309 LOG(ERR) << "Error setting RX gain";
310
311 writeLock.unlock();
312
313 return dB;
dburgessb3a0ca42011-10-12 07:44:40 +0000314}
315
Pau Espin Pedrol77ce99a2018-02-05 13:05:06 +0100316bool USRPDevice::setRxAntenna(const std::string &ant, size_t chan)
317{
318 if (chan >= rx_paths.size()) {
319 LOG(ALERT) << "Requested non-existent channel " << chan;
320 return false;
321 }
322 LOG(ALERT) << "Not implemented";
323 return true;
324}
325
326std::string USRPDevice::getRxAntenna(size_t chan)
327{
328 if (chan >= rx_paths.size()) {
329 LOG(ALERT) << "Requested non-existent channel " << chan;
330 return "";
331 }
332 LOG(ALERT) << "Not implemented";
333 return "";
334}
335
336bool USRPDevice::setTxAntenna(const std::string &ant, size_t chan)
337{
338 if (chan >= tx_paths.size()) {
339 LOG(ALERT) << "Requested non-existent channel " << chan;
340 return false;
341 }
342 LOG(ALERT) << "Not implemented";
343 return true;
344}
345
346std::string USRPDevice::getTxAntenna(size_t chan)
347{
348 if (chan >= tx_paths.size()) {
349 LOG(ALERT) << "Requested non-existent channel " << chan;
350 return "";
351 }
352 LOG(ALERT) << "Not implemented";
353 return "";
354}
355
Pau Espin Pedrol0fc20d12018-04-24 17:48:52 +0200356bool USRPDevice::requiresRadioAlign()
357{
358 return true;
359}
dburgessb3a0ca42011-10-12 07:44:40 +0000360
Pau Espin Pedrole564f0f2018-04-24 18:43:51 +0200361GSM::Time USRPDevice::minLatency() {
362 return GSM::Time(1,1);
363}
364
dburgessb3a0ca42011-10-12 07:44:40 +0000365// NOTE: Assumes sequential reads
Thomas Tsou204a9f12013-10-29 18:34:16 -0400366int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
367 TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
dburgessb3a0ca42011-10-12 07:44:40 +0000368{
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100369#ifndef SWLOOPBACK
Thomas Tsou204a9f12013-10-29 18:34:16 -0400370 if (!m_uRx)
371 return 0;
372
373 short *buf = bufs[0];
374
dburgessb3a0ca42011-10-12 07:44:40 +0000375 timestamp += timestampOffset;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100376
dburgessb3a0ca42011-10-12 07:44:40 +0000377 if (timestamp + len < timeStart) {
378 memset(buf,0,len*2*sizeof(short));
379 return len;
380 }
381
382 if (underrun) *underrun = false;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100383
dburgessb3a0ca42011-10-12 07:44:40 +0000384 uint32_t readBuf[2000];
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100385
dburgessb3a0ca42011-10-12 07:44:40 +0000386 while (1) {
387 //guestimate USB read size
388 int readLen=0;
389 {
390 int numSamplesNeeded = timestamp + len - timeEnd;
391 if (numSamplesNeeded <=0) break;
392 readLen = 512 * ((int) ceil((float) numSamplesNeeded/126.0));
393 if (readLen > 8000) readLen= (8000/512)*512;
394 }
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100395
dburgessb3a0ca42011-10-12 07:44:40 +0000396 // read USRP packets, parse and save A/D data as needed
397 readLen = m_uRx->read((void *)readBuf,readLen,overrun);
398 for(int pktNum = 0; pktNum < (readLen/512); pktNum++) {
399 // tmpBuf points to start of a USB packet
400 uint32_t* tmpBuf = (uint32_t *) (readBuf+pktNum*512/4);
401 TIMESTAMP pktTimestamp = usrp_to_host_u32(tmpBuf[1]);
402 uint32_t word0 = usrp_to_host_u32(tmpBuf[0]);
403 uint32_t chan = (word0 >> 16) & 0x1f;
404 unsigned payloadSz = word0 & 0x1ff;
405 LOG(DEBUG) << "first two bytes: " << hex << word0 << " " << dec << pktTimestamp;
406
407 bool incrementHi32 = ((lastPktTimestamp & 0x0ffffffffll) > pktTimestamp);
408 if (incrementHi32 && (timeStart!=0)) {
409 LOG(DEBUG) << "high 32 increment!!!";
410 hi32Timestamp++;
411 }
412 pktTimestamp = (((TIMESTAMP) hi32Timestamp) << 32) | pktTimestamp;
413 lastPktTimestamp = pktTimestamp;
414
415 if (chan == 0x01f) {
416 // control reply, check to see if its ping reply
417 uint32_t word2 = usrp_to_host_u32(tmpBuf[2]);
418 if ((word2 >> 16) == ((0x01 << 8) | 0x02)) {
419 timestamp -= timestampOffset;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400420 timestampOffset = pktTimestamp - pingTimestamp + pingOffset;
dburgessb3a0ca42011-10-12 07:44:40 +0000421 LOG(DEBUG) << "updating timestamp offset to: " << timestampOffset;
422 timestamp += timestampOffset;
423 isAligned = true;
424 }
425 continue;
426 }
427 if (chan != 0) {
428 LOG(DEBUG) << "chan: " << chan << ", timestamp: " << pktTimestamp << ", sz:" << payloadSz;
429 continue;
430 }
431 if ((word0 >> 28) & 0x04) {
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100432 if (underrun) *underrun = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000433 LOG(DEBUG) << "UNDERRUN in TRX->USRP interface";
434 }
435 if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100436
dburgessb3a0ca42011-10-12 07:44:40 +0000437 if (!isAligned) continue;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100438
dburgessb3a0ca42011-10-12 07:44:40 +0000439 unsigned cursorStart = pktTimestamp - timeStart + dataStart;
440 while (cursorStart*2 > currDataSize) {
441 cursorStart -= currDataSize/2;
442 }
443 if (cursorStart*2 + payloadSz/2 > currDataSize) {
444 // need to circle around buffer
445 memcpy(data+cursorStart*2,tmpBuf+2,(currDataSize-cursorStart*2)*sizeof(short));
446 memcpy(data,tmpBuf+2+(currDataSize/2-cursorStart),payloadSz-(currDataSize-cursorStart*2)*sizeof(short));
447 }
448 else {
449 memcpy(data+cursorStart*2,tmpBuf+2,payloadSz);
450 }
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100451 if (pktTimestamp + payloadSz/2/sizeof(short) > timeEnd)
dburgessb3a0ca42011-10-12 07:44:40 +0000452 timeEnd = pktTimestamp+payloadSz/2/sizeof(short);
453
454 LOG(DEBUG) << "timeStart: " << timeStart << ", timeEnd: " << timeEnd << ", pktTimestamp: " << pktTimestamp;
455
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100456 }
457 }
458
dburgessb3a0ca42011-10-12 07:44:40 +0000459 // copy desired data to buf
460 unsigned bufStart = dataStart+(timestamp-timeStart);
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100461 if (bufStart + len < currDataSize/2) {
dburgessb3a0ca42011-10-12 07:44:40 +0000462 LOG(DEBUG) << "bufStart: " << bufStart;
463 memcpy(buf,data+bufStart*2,len*2*sizeof(short));
464 memset(data+bufStart*2,0,len*2*sizeof(short));
465 }
466 else {
467 LOG(DEBUG) << "len: " << len << ", currDataSize/2: " << currDataSize/2 << ", bufStart: " << bufStart;
468 unsigned firstLength = (currDataSize/2-bufStart);
469 LOG(DEBUG) << "firstLength: " << firstLength;
470 memcpy(buf,data+bufStart*2,firstLength*2*sizeof(short));
471 memset(data+bufStart*2,0,firstLength*2*sizeof(short));
472 memcpy(buf+firstLength*2,data,(len-firstLength)*2*sizeof(short));
473 memset(data,0,(len-firstLength)*2*sizeof(short));
474 }
475 dataStart = (bufStart + len) % (currDataSize/2);
476 timeStart = timestamp + len;
477
dburgessb3a0ca42011-10-12 07:44:40 +0000478 return len;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100479
dburgessb3a0ca42011-10-12 07:44:40 +0000480#else
481 if (loopbackBufferSize < 2) return 0;
482 int numSamples = 0;
483 struct timeval currTime;
484 gettimeofday(&currTime,NULL);
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100485 double timeElapsed = (currTime.tv_sec - lastReadTime.tv_sec)*1.0e6 +
dburgessb3a0ca42011-10-12 07:44:40 +0000486 (currTime.tv_usec - lastReadTime.tv_usec);
487 if (timeElapsed < samplePeriod) {return 0;}
488 int numSamplesToRead = (int) floor(timeElapsed/samplePeriod);
489 if (numSamplesToRead < len) return 0;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100490
dburgessb3a0ca42011-10-12 07:44:40 +0000491 if (numSamplesToRead > len) numSamplesToRead = len;
492 if (numSamplesToRead > loopbackBufferSize/2) {
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100493 firstRead =false;
dburgessb3a0ca42011-10-12 07:44:40 +0000494 numSamplesToRead = loopbackBufferSize/2;
495 }
496 memcpy(buf,loopbackBuffer,sizeof(short)*2*numSamplesToRead);
497 loopbackBufferSize -= 2*numSamplesToRead;
498 memcpy(loopbackBuffer,loopbackBuffer+2*numSamplesToRead,
499 sizeof(short)*loopbackBufferSize);
500 numSamples = numSamplesToRead;
501 if (firstRead) {
502 int new_usec = lastReadTime.tv_usec + (int) round((double) numSamplesToRead * samplePeriod);
503 lastReadTime.tv_sec = lastReadTime.tv_sec + new_usec/1000000;
504 lastReadTime.tv_usec = new_usec % 1000000;
505 }
506 else {
507 gettimeofday(&lastReadTime,NULL);
508 firstRead = true;
509 }
510 samplesRead += numSamples;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100511
dburgessb3a0ca42011-10-12 07:44:40 +0000512 return numSamples;
513#endif
514}
515
Thomas Tsou204a9f12013-10-29 18:34:16 -0400516int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
517 bool *underrun, unsigned long long timestamp,
518 bool isControl)
dburgessb3a0ca42011-10-12 07:44:40 +0000519{
520 writeLock.lock();
521
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100522#ifndef SWLOOPBACK
Thomas Tsou204a9f12013-10-29 18:34:16 -0400523 if (!m_uTx)
524 return 0;
525
526 short *buf = bufs[0];
527
kurtis.heimerlc8739b82011-11-02 00:06:34 +0000528 static uint32_t outData[128*20];
Thomas Tsou204a9f12013-10-29 18:34:16 -0400529
dburgessb3a0ca42011-10-12 07:44:40 +0000530 for (int i = 0; i < len*2; i++) {
531 buf[i] = host_to_usrp_short(buf[i]);
532 }
533
534 int numWritten = 0;
535 unsigned isStart = 1;
536 unsigned RSSI = 0;
537 unsigned CHAN = (isControl) ? 0x01f : 0x00;
538 len = len*2*sizeof(short);
539 int numPkts = (int) ceil((float)len/(float)504);
540 unsigned isEnd = (numPkts < 2);
541 uint32_t *outPkt = outData;
542 int pktNum = 0;
543 while (numWritten < len) {
544 // pkt is pointer to start of a USB packet
545 uint32_t *pkt = outPkt + pktNum*128;
546 isEnd = (len - numWritten <= 504);
547 unsigned payloadLen = ((len - numWritten) < 504) ? (len-numWritten) : 504;
548 pkt[0] = (isStart << 12 | isEnd << 11 | (RSSI & 0x3f) << 5 | CHAN) << 16 | payloadLen;
549 pkt[1] = timestamp & 0x0ffffffffll;
550 memcpy(pkt+2,buf+(numWritten/sizeof(short)),payloadLen);
551 numWritten += payloadLen;
552 timestamp += payloadLen/2/sizeof(short);
553 isStart = 0;
554 pkt[0] = host_to_usrp_u32(pkt[0]);
555 pkt[1] = host_to_usrp_u32(pkt[1]);
556 pktNum++;
557 }
558 m_uTx->write((const void*) outPkt,sizeof(uint32_t)*128*numPkts,NULL);
559
560 samplesWritten += len/2/sizeof(short);
561 writeLock.unlock();
562
563 return len/2/sizeof(short);
564#else
565 int retVal = len;
566 memcpy(loopbackBuffer+loopbackBufferSize,buf,sizeof(short)*2*len);
567 samplesWritten += retVal;
568 loopbackBufferSize += retVal*2;
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100569
dburgessb3a0ca42011-10-12 07:44:40 +0000570 return retVal;
571#endif
572}
573
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100574bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
dburgessb3a0ca42011-10-12 07:44:40 +0000575{
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100576#ifndef SWLOOPBACK
dburgessb3a0ca42011-10-12 07:44:40 +0000577 short data[] = {0x00,0x02,0x00,0x00};
578 uint32_t *wordPtr = (uint32_t *) data;
kurtis.heimerlc8739b82011-11-02 00:06:34 +0000579 *wordPtr = host_to_usrp_u32(*wordPtr);
dburgessb3a0ca42011-10-12 07:44:40 +0000580 bool tmpUnderrun;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400581
582 std::vector<short *> buf(1, data);
583 if (writeSamples(buf, 1, &tmpUnderrun, timestamp & 0x0ffffffffll, true)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000584 pingTimestamp = timestamp;
585 return true;
586 }
587 return false;
588#else
589 return true;
590#endif
591}
592
Pau Espin Pedrolf58cd8a2018-02-05 13:04:41 +0100593#ifndef SWLOOPBACK
Thomas Tsou204a9f12013-10-29 18:34:16 -0400594bool USRPDevice::setTxFreq(double wFreq, size_t chan)
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000595{
596 usrp_tune_result result;
dburgessb3a0ca42011-10-12 07:44:40 +0000597
Thomas Tsou204a9f12013-10-29 18:34:16 -0400598 if (chan) {
599 LOG(ALERT) << "Invalid channel " << chan;
600 return false;
601 }
602
kurtis.heimerlb9e237e2011-11-26 03:17:59 +0000603 if (m_uTx->tune(txSubdevSpec.side, m_dbTx, wFreq, &result)) {
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000604 LOG(INFO) << "set TX: " << wFreq << std::endl
605 << " baseband freq: " << result.baseband_freq << std::endl
606 << " DDC freq: " << result.dxc_freq << std::endl
607 << " residual freq: " << result.residual_freq;
608 return true;
609 }
610 else {
kurtis.heimerle3320322011-11-28 06:26:08 +0000611 LOG(ALERT) << "set TX: " << wFreq << "failed" << std::endl
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000612 << " baseband freq: " << result.baseband_freq << std::endl
613 << " DDC freq: " << result.dxc_freq << std::endl
614 << " residual freq: " << result.residual_freq;
615 return false;
616 }
617}
618
Thomas Tsou204a9f12013-10-29 18:34:16 -0400619bool USRPDevice::setRxFreq(double wFreq, size_t chan)
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000620{
621 usrp_tune_result result;
622
Thomas Tsou204a9f12013-10-29 18:34:16 -0400623 if (chan) {
624 LOG(ALERT) << "Invalid channel " << chan;
625 return false;
626 }
627
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000628 if (m_uRx->tune(0, m_dbRx, wFreq, &result)) {
629 LOG(INFO) << "set RX: " << wFreq << std::endl
630 << " baseband freq: " << result.baseband_freq << std::endl
631 << " DDC freq: " << result.dxc_freq << std::endl
632 << " residual freq: " << result.residual_freq;
633 return true;
634 }
635 else {
kurtis.heimerle3320322011-11-28 06:26:08 +0000636 LOG(ALERT) << "set RX: " << wFreq << "failed" << std::endl
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000637 << " baseband freq: " << result.baseband_freq << std::endl
638 << " DDC freq: " << result.dxc_freq << std::endl
639 << " residual freq: " << result.residual_freq;
640 return false;
641 }
642
643}
dburgessb3a0ca42011-10-12 07:44:40 +0000644
645#else
646bool USRPDevice::setTxFreq(double wFreq) { return true;};
647bool USRPDevice::setRxFreq(double wFreq) { return true;};
648#endif
kurtis.heimerl965e7572011-11-26 03:16:54 +0000649
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800650RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
Pau Espin Pedrol77ce99a2018-02-05 13:05:06 +0100651 InterfaceType iface, size_t chans, double offset,
652 const std::vector<std::string>& tx_paths,
653 const std::vector<std::string>& rx_paths)
kurtis.heimerl965e7572011-11-26 03:16:54 +0000654{
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800655 return new USRPDevice(tx_sps);
kurtis.heimerl965e7572011-11-26 03:16:54 +0000656}