blob: 1fff124ed39ab05a72732d7e81c7725254db1b9d [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
30*/
31
32
33#include <stdint.h>
34#include <string.h>
35#include <stdlib.h>
36#include "Threads.h"
37#include "USRPDevice.h"
38
39#include <Logger.h>
40
kurtis.heimerl3758b162011-11-26 03:19:22 +000041#ifdef HAVE_CONFIG_H
42#include "config.h"
43#endif
dburgessb3a0ca42011-10-12 07:44:40 +000044
45using namespace std;
46
kurtis.heimerl79e71c92011-11-26 03:16:48 +000047enum dboardConfigType {
48 TXA_RXB,
49 TXB_RXA,
50 TXA_RXA,
51 TXB_RXB
52};
dburgessb3a0ca42011-10-12 07:44:40 +000053
kurtis.heimerl3758b162011-11-26 03:19:22 +000054#ifdef SINGLEDB
55const dboardConfigType dboardConfig = TXA_RXA;
56#else
kurtis.heimerl79e71c92011-11-26 03:16:48 +000057const dboardConfigType dboardConfig = TXA_RXB;
kurtis.heimerl3758b162011-11-26 03:19:22 +000058#endif
59
kurtis.heimerl79e71c92011-11-26 03:16:48 +000060const double USRPDevice::masterClockRate = 52.0e6;
dburgessb3a0ca42011-10-12 07:44:40 +000061
Thomas Tsoucb69f082013-04-08 14:18:26 -040062USRPDevice::USRPDevice(int sps, bool skipRx)
kurtis.heimerl965e7572011-11-26 03:16:54 +000063 : skipRx(skipRx)
dburgessb3a0ca42011-10-12 07:44:40 +000064{
65 LOG(INFO) << "creating USRP device...";
Thomas Tsouc1f7c422013-10-11 13:49:55 -040066
67 this->sps = sps;
Thomas Tsoucb69f082013-04-08 14:18:26 -040068 decimRate = (unsigned int) round(masterClockRate/((GSMRATE) * (double) sps));
dburgessb3a0ca42011-10-12 07:44:40 +000069 actualSampleRate = masterClockRate/decimRate;
70 rxGain = 0;
71
Thomas Tsouc1f7c422013-10-11 13:49:55 -040072 /*
73 * Undetermined delay b/w ping response timestamp and true
74 * receive timestamp. Values are empirically measured. With
75 * split sample rate Tx/Rx - 4/1 sps we need to need to
76 * compensate for advance rather than delay.
77 */
78 if (sps == 1)
79 pingOffset = 272;
80 else if (sps == 4)
81 pingOffset = 269 - 7500;
82 else
83 pingOffset = 0;
84
dburgessb3a0ca42011-10-12 07:44:40 +000085#ifdef SWLOOPBACK
86 samplePeriod = 1.0e6/actualSampleRate;
87 loopbackBufferSize = 0;
88 gettimeofday(&lastReadTime,NULL);
89 firstRead = false;
90#endif
91}
92
Thomas Tsou010fff72013-10-16 00:31:18 -040093int USRPDevice::open(const std::string &, bool)
dburgessb3a0ca42011-10-12 07:44:40 +000094{
dburgessb3a0ca42011-10-12 07:44:40 +000095 writeLock.unlock();
96
kurtis.heimerl965e7572011-11-26 03:16:54 +000097 LOG(INFO) << "opening USRP device..";
dburgessb3a0ca42011-10-12 07:44:40 +000098#ifndef SWLOOPBACK
99 string rbf = "std_inband.rbf";
100 //string rbf = "inband_1rxhb_1tx.rbf";
101 m_uRx.reset();
102 if (!skipRx) {
103 try {
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400104 m_uRx = usrp_standard_rx_sptr(usrp_standard_rx::make(
105 0, decimRate * sps, 1, -1,
106 usrp_standard_rx::FPGA_MODE_NORMAL,
107 1024, 16 * 8, rbf));
dburgessb3a0ca42011-10-12 07:44:40 +0000108 m_uRx->set_fpga_master_clock_freq(masterClockRate);
dburgessb3a0ca42011-10-12 07:44:40 +0000109 }
Thomas Tsouc0641242013-10-11 14:55:31 -0400110
dburgessb3a0ca42011-10-12 07:44:40 +0000111 catch(...) {
112 LOG(ALERT) << "make failed on Rx";
113 m_uRx.reset();
Thomas Tsoucb69f082013-04-08 14:18:26 -0400114 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000115 }
116
117 if (m_uRx->fpga_master_clock_freq() != masterClockRate)
118 {
119 LOG(ALERT) << "WRONG FPGA clock freq = " << m_uRx->fpga_master_clock_freq()
120 << ", desired clock freq = " << masterClockRate;
121 m_uRx.reset();
Thomas Tsoucb69f082013-04-08 14:18:26 -0400122 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000123 }
124 }
125
126 try {
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400127 m_uTx = usrp_standard_tx_sptr(usrp_standard_tx::make(
128 0, decimRate * 2, 1, -1,
129 1024, 16 * 8, rbf));
dburgessb3a0ca42011-10-12 07:44:40 +0000130 m_uTx->set_fpga_master_clock_freq(masterClockRate);
dburgessb3a0ca42011-10-12 07:44:40 +0000131 }
Thomas Tsouc0641242013-10-11 14:55:31 -0400132
dburgessb3a0ca42011-10-12 07:44:40 +0000133 catch(...) {
134 LOG(ALERT) << "make failed on Tx";
135 m_uTx.reset();
Thomas Tsoucb69f082013-04-08 14:18:26 -0400136 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000137 }
138
139 if (m_uTx->fpga_master_clock_freq() != masterClockRate)
140 {
141 LOG(ALERT) << "WRONG FPGA clock freq = " << m_uTx->fpga_master_clock_freq()
142 << ", desired clock freq = " << masterClockRate;
143 m_uTx.reset();
Thomas Tsoucb69f082013-04-08 14:18:26 -0400144 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000145 }
146
147 if (!skipRx) m_uRx->stop();
148 m_uTx->stop();
149
150#endif
151
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000152 switch (dboardConfig) {
153 case TXA_RXB:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000154 txSubdevSpec = usrp_subdev_spec(0,0);
155 rxSubdevSpec = usrp_subdev_spec(1,0);
156 break;
157 case TXB_RXA:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000158 txSubdevSpec = usrp_subdev_spec(1,0);
159 rxSubdevSpec = usrp_subdev_spec(0,0);
160 break;
161 case TXA_RXA:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000162 txSubdevSpec = usrp_subdev_spec(0,0);
163 rxSubdevSpec = usrp_subdev_spec(0,0);
164 break;
165 case TXB_RXB:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000166 txSubdevSpec = usrp_subdev_spec(1,0);
167 rxSubdevSpec = usrp_subdev_spec(1,0);
168 break;
169 default:
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000170 txSubdevSpec = usrp_subdev_spec(0,0);
171 rxSubdevSpec = usrp_subdev_spec(1,0);
172 }
173
kurtis.heimerlb9e237e2011-11-26 03:17:59 +0000174 m_dbTx = m_uTx->selected_subdev(txSubdevSpec);
175 m_dbRx = m_uRx->selected_subdev(rxSubdevSpec);
176
dburgessb3a0ca42011-10-12 07:44:40 +0000177 samplesRead = 0;
178 samplesWritten = 0;
179 started = false;
180
Thomas Tsoucb69f082013-04-08 14:18:26 -0400181 return NORMAL;
dburgessb3a0ca42011-10-12 07:44:40 +0000182}
183
184
185
186bool USRPDevice::start()
187{
188 LOG(INFO) << "starting USRP...";
189#ifndef SWLOOPBACK
190 if (!m_uRx && !skipRx) return false;
191 if (!m_uTx) return false;
192
193 if (!skipRx) m_uRx->stop();
194 m_uTx->stop();
195
196 writeLock.lock();
197 // power up and configure daughterboards
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000198 m_dbTx->set_enable(true);
199 m_uTx->set_mux(m_uTx->determine_tx_mux_value(txSubdevSpec));
200 m_uRx->set_mux(m_uRx->determine_rx_mux_value(rxSubdevSpec));
201
202 if (!m_dbRx->select_rx_antenna(1))
203 m_dbRx->select_rx_antenna(0);
204
dburgessb3a0ca42011-10-12 07:44:40 +0000205 writeLock.unlock();
206
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000207 // Set gains to midpoint
208 setTxGain((minTxGain() + maxTxGain()) / 2);
209 setRxGain((minRxGain() + maxRxGain()) / 2);
dburgessb3a0ca42011-10-12 07:44:40 +0000210
211 data = new short[currDataSize];
212 dataStart = 0;
213 dataEnd = 0;
214 timeStart = 0;
215 timeEnd = 0;
216 timestampOffset = 0;
217 latestWriteTimestamp = 0;
218 lastPktTimestamp = 0;
219 hi32Timestamp = 0;
220 isAligned = false;
221
222
223 if (!skipRx)
224 started = (m_uRx->start() && m_uTx->start());
225 else
226 started = m_uTx->start();
227 return started;
228#else
229 gettimeofday(&lastReadTime,NULL);
230 return true;
231#endif
232}
233
234bool USRPDevice::stop()
235{
236#ifndef SWLOOPBACK
237 if (!m_uRx) return false;
238 if (!m_uTx) return false;
239
dburgessb3a0ca42011-10-12 07:44:40 +0000240 delete[] currData;
241
242 started = !(m_uRx->stop() && m_uTx->stop());
243 return !started;
244#else
245 return true;
246#endif
247}
248
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000249double USRPDevice::maxTxGain()
250{
251 return m_dbTx->gain_max();
252}
253
254double USRPDevice::minTxGain()
255{
256 return m_dbTx->gain_min();
257}
258
259double USRPDevice::maxRxGain()
260{
261 return m_dbRx->gain_max();
262}
263
264double USRPDevice::minRxGain()
265{
266 return m_dbRx->gain_min();
267}
268
dburgessb3a0ca42011-10-12 07:44:40 +0000269double USRPDevice::setTxGain(double dB) {
270
271 writeLock.lock();
272 if (dB > maxTxGain()) dB = maxTxGain();
273 if (dB < minTxGain()) dB = minTxGain();
274
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000275 LOG(NOTICE) << "Setting TX gain to " << dB << " dB.";
dburgessb3a0ca42011-10-12 07:44:40 +0000276
ttsou711fdf62012-03-13 04:05:30 +0000277 if (!m_dbTx->set_gain(dB))
kurtis.heimerl4e59d662011-11-26 03:19:11 +0000278 LOG(ERR) << "Error setting TX gain";
dburgessb3a0ca42011-10-12 07:44:40 +0000279
280 writeLock.unlock();
281
282 return dB;
283}
284
285
286double USRPDevice::setRxGain(double dB) {
287
288 writeLock.lock();
289 if (dB > maxRxGain()) dB = maxRxGain();
290 if (dB < minRxGain()) dB = minRxGain();
291
kurtis.heimerlc3c7c3e2011-11-26 03:17:57 +0000292 LOG(NOTICE) << "Setting RX gain to " << dB << " dB.";
dburgessb3a0ca42011-10-12 07:44:40 +0000293
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000294 if (!m_dbRx->set_gain(dB))
kurtis.heimerl4e59d662011-11-26 03:19:11 +0000295 LOG(ERR) << "Error setting RX gain";
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000296
dburgessb3a0ca42011-10-12 07:44:40 +0000297 writeLock.unlock();
298
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000299 return dB;
dburgessb3a0ca42011-10-12 07:44:40 +0000300}
301
302
303// NOTE: Assumes sequential reads
304int USRPDevice::readSamples(short *buf, int len, bool *overrun,
305 TIMESTAMP timestamp,
306 bool *underrun,
307 unsigned *RSSI)
308{
309#ifndef SWLOOPBACK
310 if (!m_uRx) return 0;
311
312 timestamp += timestampOffset;
313
314 if (timestamp + len < timeStart) {
315 memset(buf,0,len*2*sizeof(short));
316 return len;
317 }
318
319 if (underrun) *underrun = false;
320
321 uint32_t readBuf[2000];
322
323 while (1) {
324 //guestimate USB read size
325 int readLen=0;
326 {
327 int numSamplesNeeded = timestamp + len - timeEnd;
328 if (numSamplesNeeded <=0) break;
329 readLen = 512 * ((int) ceil((float) numSamplesNeeded/126.0));
330 if (readLen > 8000) readLen= (8000/512)*512;
331 }
332
333 // read USRP packets, parse and save A/D data as needed
334 readLen = m_uRx->read((void *)readBuf,readLen,overrun);
335 for(int pktNum = 0; pktNum < (readLen/512); pktNum++) {
336 // tmpBuf points to start of a USB packet
337 uint32_t* tmpBuf = (uint32_t *) (readBuf+pktNum*512/4);
338 TIMESTAMP pktTimestamp = usrp_to_host_u32(tmpBuf[1]);
339 uint32_t word0 = usrp_to_host_u32(tmpBuf[0]);
340 uint32_t chan = (word0 >> 16) & 0x1f;
341 unsigned payloadSz = word0 & 0x1ff;
342 LOG(DEBUG) << "first two bytes: " << hex << word0 << " " << dec << pktTimestamp;
343
344 bool incrementHi32 = ((lastPktTimestamp & 0x0ffffffffll) > pktTimestamp);
345 if (incrementHi32 && (timeStart!=0)) {
346 LOG(DEBUG) << "high 32 increment!!!";
347 hi32Timestamp++;
348 }
349 pktTimestamp = (((TIMESTAMP) hi32Timestamp) << 32) | pktTimestamp;
350 lastPktTimestamp = pktTimestamp;
351
352 if (chan == 0x01f) {
353 // control reply, check to see if its ping reply
354 uint32_t word2 = usrp_to_host_u32(tmpBuf[2]);
355 if ((word2 >> 16) == ((0x01 << 8) | 0x02)) {
356 timestamp -= timestampOffset;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400357 timestampOffset = pktTimestamp - pingTimestamp + pingOffset;
dburgessb3a0ca42011-10-12 07:44:40 +0000358 LOG(DEBUG) << "updating timestamp offset to: " << timestampOffset;
359 timestamp += timestampOffset;
360 isAligned = true;
361 }
362 continue;
363 }
364 if (chan != 0) {
365 LOG(DEBUG) << "chan: " << chan << ", timestamp: " << pktTimestamp << ", sz:" << payloadSz;
366 continue;
367 }
368 if ((word0 >> 28) & 0x04) {
369 if (underrun) *underrun = true;
370 LOG(DEBUG) << "UNDERRUN in TRX->USRP interface";
371 }
372 if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
373
374 if (!isAligned) continue;
375
376 unsigned cursorStart = pktTimestamp - timeStart + dataStart;
377 while (cursorStart*2 > currDataSize) {
378 cursorStart -= currDataSize/2;
379 }
380 if (cursorStart*2 + payloadSz/2 > currDataSize) {
381 // need to circle around buffer
382 memcpy(data+cursorStart*2,tmpBuf+2,(currDataSize-cursorStart*2)*sizeof(short));
383 memcpy(data,tmpBuf+2+(currDataSize/2-cursorStart),payloadSz-(currDataSize-cursorStart*2)*sizeof(short));
384 }
385 else {
386 memcpy(data+cursorStart*2,tmpBuf+2,payloadSz);
387 }
388 if (pktTimestamp + payloadSz/2/sizeof(short) > timeEnd)
389 timeEnd = pktTimestamp+payloadSz/2/sizeof(short);
390
391 LOG(DEBUG) << "timeStart: " << timeStart << ", timeEnd: " << timeEnd << ", pktTimestamp: " << pktTimestamp;
392
393 }
394 }
395
396 // copy desired data to buf
397 unsigned bufStart = dataStart+(timestamp-timeStart);
398 if (bufStart + len < currDataSize/2) {
399 LOG(DEBUG) << "bufStart: " << bufStart;
400 memcpy(buf,data+bufStart*2,len*2*sizeof(short));
401 memset(data+bufStart*2,0,len*2*sizeof(short));
402 }
403 else {
404 LOG(DEBUG) << "len: " << len << ", currDataSize/2: " << currDataSize/2 << ", bufStart: " << bufStart;
405 unsigned firstLength = (currDataSize/2-bufStart);
406 LOG(DEBUG) << "firstLength: " << firstLength;
407 memcpy(buf,data+bufStart*2,firstLength*2*sizeof(short));
408 memset(data+bufStart*2,0,firstLength*2*sizeof(short));
409 memcpy(buf+firstLength*2,data,(len-firstLength)*2*sizeof(short));
410 memset(data,0,(len-firstLength)*2*sizeof(short));
411 }
412 dataStart = (bufStart + len) % (currDataSize/2);
413 timeStart = timestamp + len;
414
dburgessb3a0ca42011-10-12 07:44:40 +0000415 return len;
416
417#else
418 if (loopbackBufferSize < 2) return 0;
419 int numSamples = 0;
420 struct timeval currTime;
421 gettimeofday(&currTime,NULL);
422 double timeElapsed = (currTime.tv_sec - lastReadTime.tv_sec)*1.0e6 +
423 (currTime.tv_usec - lastReadTime.tv_usec);
424 if (timeElapsed < samplePeriod) {return 0;}
425 int numSamplesToRead = (int) floor(timeElapsed/samplePeriod);
426 if (numSamplesToRead < len) return 0;
427
428 if (numSamplesToRead > len) numSamplesToRead = len;
429 if (numSamplesToRead > loopbackBufferSize/2) {
430 firstRead =false;
431 numSamplesToRead = loopbackBufferSize/2;
432 }
433 memcpy(buf,loopbackBuffer,sizeof(short)*2*numSamplesToRead);
434 loopbackBufferSize -= 2*numSamplesToRead;
435 memcpy(loopbackBuffer,loopbackBuffer+2*numSamplesToRead,
436 sizeof(short)*loopbackBufferSize);
437 numSamples = numSamplesToRead;
438 if (firstRead) {
439 int new_usec = lastReadTime.tv_usec + (int) round((double) numSamplesToRead * samplePeriod);
440 lastReadTime.tv_sec = lastReadTime.tv_sec + new_usec/1000000;
441 lastReadTime.tv_usec = new_usec % 1000000;
442 }
443 else {
444 gettimeofday(&lastReadTime,NULL);
445 firstRead = true;
446 }
447 samplesRead += numSamples;
448
449 return numSamples;
450#endif
451}
452
453int USRPDevice::writeSamples(short *buf, int len, bool *underrun,
454 unsigned long long timestamp,
455 bool isControl)
456{
457 writeLock.lock();
458
459#ifndef SWLOOPBACK
460 if (!m_uTx) return 0;
461
kurtis.heimerlc8739b82011-11-02 00:06:34 +0000462 static uint32_t outData[128*20];
dburgessb3a0ca42011-10-12 07:44:40 +0000463
464 for (int i = 0; i < len*2; i++) {
465 buf[i] = host_to_usrp_short(buf[i]);
466 }
467
468 int numWritten = 0;
469 unsigned isStart = 1;
470 unsigned RSSI = 0;
471 unsigned CHAN = (isControl) ? 0x01f : 0x00;
472 len = len*2*sizeof(short);
473 int numPkts = (int) ceil((float)len/(float)504);
474 unsigned isEnd = (numPkts < 2);
475 uint32_t *outPkt = outData;
476 int pktNum = 0;
477 while (numWritten < len) {
478 // pkt is pointer to start of a USB packet
479 uint32_t *pkt = outPkt + pktNum*128;
480 isEnd = (len - numWritten <= 504);
481 unsigned payloadLen = ((len - numWritten) < 504) ? (len-numWritten) : 504;
482 pkt[0] = (isStart << 12 | isEnd << 11 | (RSSI & 0x3f) << 5 | CHAN) << 16 | payloadLen;
483 pkt[1] = timestamp & 0x0ffffffffll;
484 memcpy(pkt+2,buf+(numWritten/sizeof(short)),payloadLen);
485 numWritten += payloadLen;
486 timestamp += payloadLen/2/sizeof(short);
487 isStart = 0;
488 pkt[0] = host_to_usrp_u32(pkt[0]);
489 pkt[1] = host_to_usrp_u32(pkt[1]);
490 pktNum++;
491 }
492 m_uTx->write((const void*) outPkt,sizeof(uint32_t)*128*numPkts,NULL);
493
494 samplesWritten += len/2/sizeof(short);
495 writeLock.unlock();
496
497 return len/2/sizeof(short);
498#else
499 int retVal = len;
500 memcpy(loopbackBuffer+loopbackBufferSize,buf,sizeof(short)*2*len);
501 samplesWritten += retVal;
502 loopbackBufferSize += retVal*2;
503
504 return retVal;
505#endif
506}
507
508bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
509{
510#ifndef SWLOOPBACK
511 short data[] = {0x00,0x02,0x00,0x00};
512 uint32_t *wordPtr = (uint32_t *) data;
kurtis.heimerlc8739b82011-11-02 00:06:34 +0000513 *wordPtr = host_to_usrp_u32(*wordPtr);
dburgessb3a0ca42011-10-12 07:44:40 +0000514 bool tmpUnderrun;
515 if (writeSamples((short *) data,1,&tmpUnderrun,timestamp & 0x0ffffffffll,true)) {
516 pingTimestamp = timestamp;
517 return true;
518 }
519 return false;
520#else
521 return true;
522#endif
523}
524
525#ifndef SWLOOPBACK
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000526bool USRPDevice::setTxFreq(double wFreq)
527{
528 usrp_tune_result result;
dburgessb3a0ca42011-10-12 07:44:40 +0000529
kurtis.heimerlb9e237e2011-11-26 03:17:59 +0000530 if (m_uTx->tune(txSubdevSpec.side, m_dbTx, wFreq, &result)) {
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000531 LOG(INFO) << "set TX: " << wFreq << std::endl
532 << " baseband freq: " << result.baseband_freq << std::endl
533 << " DDC freq: " << result.dxc_freq << std::endl
534 << " residual freq: " << result.residual_freq;
535 return true;
536 }
537 else {
kurtis.heimerle3320322011-11-28 06:26:08 +0000538 LOG(ALERT) << "set TX: " << wFreq << "failed" << std::endl
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000539 << " baseband freq: " << result.baseband_freq << std::endl
540 << " DDC freq: " << result.dxc_freq << std::endl
541 << " residual freq: " << result.residual_freq;
542 return false;
543 }
544}
545
546bool USRPDevice::setRxFreq(double wFreq)
547{
548 usrp_tune_result result;
549
550 if (m_uRx->tune(0, m_dbRx, wFreq, &result)) {
551 LOG(INFO) << "set RX: " << wFreq << std::endl
552 << " baseband freq: " << result.baseband_freq << std::endl
553 << " DDC freq: " << result.dxc_freq << std::endl
554 << " residual freq: " << result.residual_freq;
555 return true;
556 }
557 else {
kurtis.heimerle3320322011-11-28 06:26:08 +0000558 LOG(ALERT) << "set RX: " << wFreq << "failed" << std::endl
kurtis.heimerl79e71c92011-11-26 03:16:48 +0000559 << " baseband freq: " << result.baseband_freq << std::endl
560 << " DDC freq: " << result.dxc_freq << std::endl
561 << " residual freq: " << result.residual_freq;
562 return false;
563 }
564
565}
dburgessb3a0ca42011-10-12 07:44:40 +0000566
567#else
568bool USRPDevice::setTxFreq(double wFreq) { return true;};
569bool USRPDevice::setRxFreq(double wFreq) { return true;};
570#endif
kurtis.heimerl965e7572011-11-26 03:16:54 +0000571
Thomas Tsoucb69f082013-04-08 14:18:26 -0400572RadioDevice *RadioDevice::make(int sps, bool skipRx)
kurtis.heimerl965e7572011-11-26 03:16:54 +0000573{
Thomas Tsoucb69f082013-04-08 14:18:26 -0400574 return new USRPDevice(sps, skipRx);
kurtis.heimerl965e7572011-11-26 03:16:54 +0000575}