diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp new file mode 100644 index 00000000..97814957 --- /dev/null +++ b/Transceiver52M/UHDDevice.cpp @@ -0,0 +1,754 @@ +/* +* Copyright 2008, 2009, 2010 Free Software Foundation, Inc. +* +* This software is distributed under the terms of the GNU Affero Public License. +* See the COPYING file in the main directory for details. +* +* This use of this software may be subject to additional restrictions. +* See the LEGAL file in the main directory for details. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + 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. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +*/ + +#include "radioDevice.h" +#include "Threads.h" +#include "Logger.h" +#include +#include + +/* + use_ext_ref - Enable external 10MHz clock reference + + master_clk_rt - Master clock frequency + + rx_smpl_offset - Timing correction in seconds between receive and + transmit timestamps. This value corrects for delays on + on the RF side of the timestamping point of the device. + + smpl_buf_sz - The receive sample buffer size in bytes. +*/ +const bool use_ext_ref = false; +const double master_clk_rt = 52e6; +const double rx_smpl_offset = .00005; +const size_t smpl_buf_sz = (1 << 20); + +/** Timestamp conversion + @param timestamp a UHD or OpenBTS timestamp + @param rate sample rate + @return the converted timestamp +*/ +uhd::time_spec_t convert_time(TIMESTAMP ticks, double rate) +{ + double secs = (double) ticks / rate; + return uhd::time_spec_t(secs); +} + +TIMESTAMP convert_time(uhd::time_spec_t ts, double rate) +{ + size_t ticks = ts.get_full_secs() * rate; + return ts.get_tick_count(rate) + ticks; +} + +/* + Sample Buffer - Allows reading and writing of timed samples using OpenBTS + or UHD style timestamps. Time conversions are handled + internally or accessable through the static convert calls. +*/ +class smpl_buf { +public: + /** Sample buffer constructor + @param len number of 32-bit samples the buffer should hold + @param rate sample clockrate + @param timestamp + */ + smpl_buf(size_t len, double rate); + ~smpl_buf(); + + /** Query number of samples available for reading + @param timestamp time of first sample + @return number of available samples or error + */ + ssize_t avail_smpls(TIMESTAMP timestamp) const; + ssize_t avail_smpls(uhd::time_spec_t timestamp) const; + + /** Read and write + @param buf pointer to buffer + @param len number of samples desired to read or write + @param timestamp time of first stample + @return number of actual samples read or written or error + */ + ssize_t read(void *buf, size_t len, TIMESTAMP timestamp); + ssize_t read(void *buf, size_t len, uhd::time_spec_t timestamp); + ssize_t write(void *buf, size_t len, TIMESTAMP timestamp); + ssize_t write(void *buf, size_t len, uhd::time_spec_t timestamp); + + /** Buffer status string + @return a formatted string describing internal buffer state + */ + std::string str_status() const; + + /** Formatted error string + @param code an error code + @return a formatted error string + */ + static std::string str_code(ssize_t code); + + enum err_code { + ERROR_TIMESTAMP = -1, + ERROR_READ = -2, + ERROR_WRITE = -3, + ERROR_OVERFLOW = -4 + }; + +private: + uint32_t *data; + size_t buf_len; + + double clk_rt; + + TIMESTAMP time_start; + TIMESTAMP time_end; + + size_t data_start; + size_t data_end; +}; + +/* + uhd_device - UHD implementation of the Device interface. Timestamped samples + are sent to and received from the device. An intermediate buffer + on the receive side collects and aligns packets of samples. + Events and errors such as underruns are reported asynchronously + by the device and received in a separate thread. +*/ +class uhd_device : public RadioDevice { +public: + uhd_device(double rate, bool skip_rx); + ~uhd_device(); + + bool open(); + bool start(); + bool stop(); + void setPriority(); + + int readSamples(short *buf, int len, bool *overrun, + TIMESTAMP timestamp, bool *underrun, unsigned *RSSI); + + int writeSamples(short *buf, int len, bool *underrun, + TIMESTAMP timestamp, bool isControl); + + bool updateAlignment(TIMESTAMP timestamp); + + bool setTxFreq(double wFreq); + bool setRxFreq(double wFreq); + + inline TIMESTAMP initialWriteTimestamp() { return 0; } + inline TIMESTAMP initialReadTimestamp() { return 0; } + + inline double fullScaleInputValue() { return 13500.0; } + inline double fullScaleOutputValue() { return 9450.0; } + + double setRxGain(double dB) { return 0; } + double getRxGain(void) { return 0; } + double maxRxGain(void) { return 0; } + double minRxGain(void) { return 0; } + + double setTxGain(double dB) { return 0; } + double maxTxGain(void) { return 0; } + double minTxGain(void) { return 0; } + + double getTxFreq() { return 0; } + double getRxFreq() { return 0; } + + inline double getSampleRate() { return actual_smpl_rt; } + inline double numberRead() { return rx_pkt_cnt; } + inline double numberWritten() { return 0; } + + /** Receive and process asynchronous message + @return true if message received or false on timeout or error + */ + bool recv_async_msg(); + +private: + uhd::usrp::single_usrp::sptr usrp_dev; + + double desired_smpl_rt; + double actual_smpl_rt; + + size_t tx_spp; + size_t rx_spp; + + bool started; + bool aligned; + bool skip_rx; + + size_t rx_pkt_cnt; + size_t drop_cnt; + uhd::time_spec_t prev_ts; + + TIMESTAMP ts_offset; + smpl_buf *rx_smpl_buf; + + std::string str_code(uhd::rx_metadata_t metadata); + std::string str_code(uhd::async_metadata_t metadata); + + Thread async_event_thrd; +}; + +void *async_event_loop(uhd_device *dev) +{ + while (1) { + dev->recv_async_msg(); + pthread_testcancel(); + } +} + +uhd_device::uhd_device(double rate, bool skip_rx) + : desired_smpl_rt(rate), actual_smpl_rt(0), tx_spp(0), rx_spp(0), + started(false), aligned(true), rx_pkt_cnt(0), drop_cnt(0), + prev_ts(0,0), ts_offset(0), rx_smpl_buf(NULL) +{ + this->skip_rx = skip_rx; +} + +uhd_device::~uhd_device() +{ + stop(); + + if (rx_smpl_buf) + delete rx_smpl_buf; +} + +static double set_usrp_rates(uhd::usrp::single_usrp::sptr dev, double rate) +{ + double actual_rate; + + dev->set_tx_rate(rate); + dev->set_rx_rate(rate); + actual_rate = dev->get_tx_rate(); + + if (actual_rate != rate) { + LOG(ERROR) << "Actual sample rate differs from desired rate"; + return -1.0; + } + if (dev->get_rx_rate() != actual_rate) { + LOG(ERROR) << "Transmit and receive sample rates do not match"; + return -1.0; + } + + return actual_rate; +} + +static void set_usrp_tx_gain(uhd::usrp::single_usrp::sptr dev, double) +{ + uhd::gain_range_t range = dev->get_tx_gain_range(); + dev->set_tx_gain((range.start() + range.stop()) / 2); +} + +static void set_usrp_rx_gain(uhd::usrp::single_usrp::sptr dev, double) +{ + uhd::gain_range_t range = dev->get_rx_gain_range(); + dev->set_rx_gain((range.start() + range.stop()) / 2); +} + +static void set_usrp_ref_clk(uhd::usrp::single_usrp::sptr dev, bool ext_clk) +{ + uhd::clock_config_t clk_cfg; + + clk_cfg.pps_source = uhd::clock_config_t::PPS_SMA; + clk_cfg.pps_polarity = uhd::clock_config_t::PPS_NEG; + + if (ext_clk) + clk_cfg.ref_source = uhd::clock_config_t::REF_SMA; + else + clk_cfg.ref_source = uhd::clock_config_t::REF_INT; + + dev->set_clock_config(clk_cfg); +} + +bool uhd_device::open() +{ + LOG(INFO) << "creating USRP device..."; + + // Use the first available USRP2 / N210 + uhd::device_addr_t dev_addr("type=usrp2"); + try { + usrp_dev = uhd::usrp::single_usrp::make(dev_addr); + } + + catch(...) { + LOG(ERROR) << "USRP make failed"; + return false; + } + + // Set master clock rate + usrp_dev->set_master_clock_rate(master_clk_rt); + + // Number of samples per over-the-wire packet + tx_spp = usrp_dev->get_device()->get_max_send_samps_per_packet(); + rx_spp = usrp_dev->get_device()->get_max_recv_samps_per_packet(); + + // Set rates + actual_smpl_rt = set_usrp_rates(usrp_dev, desired_smpl_rt); + if (actual_smpl_rt < 0) + return false; + + // Create receive buffer + size_t buf_len = smpl_buf_sz / sizeof(uint32_t); + rx_smpl_buf = new smpl_buf(buf_len, actual_smpl_rt); + + // Set receive chain sample offset + ts_offset = (TIMESTAMP)(rx_smpl_offset * actual_smpl_rt); + + // Set gains to midpoint + set_usrp_tx_gain(usrp_dev, 0.0); + + // Set reference clock + set_usrp_ref_clk(usrp_dev, use_ext_ref); + + // Print configuration + LOG(INFO) << usrp_dev->get_pp_string(); + + return true; +} + +bool uhd_device::start() +{ + LOG(INFO) << "Starting USRP..."; + + if (started) { + LOG(ERROR) << "Device already started"; + return false; + } + + setPriority(); + + // Start asynchronous event (underrun check) loop + async_event_thrd.start((void * (*)(void*))async_event_loop, (void*)this); + + // Start streaming + uhd::stream_cmd_t cmd = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS; + cmd.stream_now = true; + usrp_dev->set_time_now(uhd::time_spec_t(0.0)); + + if (!skip_rx) + usrp_dev->issue_stream_cmd(cmd); + + // Display usrp time + double time_now = usrp_dev->get_time_now().get_real_secs(); + LOG(INFO) << "The current time is " << time_now << " seconds"; + + started = true; + return true; +} + +bool uhd_device::stop() +{ + uhd::stream_cmd_t stream_cmd = + uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS; + + usrp_dev->issue_stream_cmd(stream_cmd); + + started = false; + return true; +} + +void uhd_device::setPriority() +{ + uhd::set_thread_priority_safe(); + return; +} + +static int check_rx_md_err(uhd::rx_metadata_t &md, uhd::time_spec_t &prev_ts) +{ + // Missing timestamp + if (!md.has_time_spec) { + LOG(ERROR) << "UHD: Received packet missing timestamp"; + return -1; + } + + // Monotonicity check + if (md.time_spec < prev_ts) { + LOG(ERROR) << "Loss of monotonicity"; + return -1; + } else { + prev_ts = md.time_spec; + } + + return 0; +} + +int uhd_device::readSamples(short *buf, int len, bool *overrun, + TIMESTAMP timestamp, bool *underrun, unsigned *RSSI) +{ + ssize_t rc; + uhd::time_spec_t ts; + uhd::rx_metadata_t metadata; + uint32_t pkt_buf[rx_spp]; + + if (skip_rx) + return 0; + + // Shift read time with respect to transmit clock + timestamp += ts_offset; + + ts = convert_time(timestamp, actual_smpl_rt); + LOG(DEEPDEBUG) << "Requested timestamp = " << ts.get_real_secs(); + + // Check that timestamp is valid + rc = rx_smpl_buf->avail_smpls(timestamp); + if (rc < 0) { + LOG(ERROR) << rx_smpl_buf->str_code(rc); + LOG(ERROR) << rx_smpl_buf->str_status(); + return 0; + } + + // Receive samples from the usrp until we have enough + while (rx_smpl_buf->avail_smpls(timestamp) < len) { + size_t num_smpls = usrp_dev->get_device()->recv( + (void*)pkt_buf, + rx_spp, + metadata, + uhd::io_type_t::COMPLEX_INT16, + uhd::device::RECV_MODE_ONE_PACKET); + + rx_pkt_cnt++; + + // Recv error in UHD + if (!num_smpls) { + LOG(ERROR) << str_code(metadata); + return 0; + } + + // Other metadata timing checks + if (check_rx_md_err(metadata, prev_ts) < 0) + return 0; + + ts = metadata.time_spec; + LOG(DEEPDEBUG) << "Received timestamp = " << ts.get_real_secs(); + + rc = rx_smpl_buf->write(pkt_buf, + num_smpls, + metadata.time_spec); + + // Continue on local overrun, exit on other errors + if ((rc < 0)) { + LOG(ERROR) << rx_smpl_buf->str_code(rc); + LOG(ERROR) << rx_smpl_buf->str_status(); + if (rc != smpl_buf::ERROR_OVERFLOW) + return 0; + } + } + + // We have enough samples + rc = rx_smpl_buf->read(buf, len, timestamp); + if ((rc < 0) || (rc != len)) { + LOG(ERROR) << rx_smpl_buf->str_code(rc); + LOG(ERROR) << rx_smpl_buf->str_status(); + return 0; + } + + return len; +} + +int uhd_device::writeSamples(short *buf, int len, bool *underrun, + unsigned long long timestamp,bool isControl) +{ + uhd::tx_metadata_t metadata; + metadata.has_time_spec = true; + metadata.start_of_burst = false; + metadata.end_of_burst = false; + metadata.time_spec = convert_time(timestamp, actual_smpl_rt); + + // No control packets + if (isControl) { + LOG(ERROR) << "Control packets not supported"; + return 0; + } + + // Drop a fixed number of packets (magic value) + if (!aligned) { + drop_cnt++; + + if (drop_cnt == 1) { + LOG(DEBUG) << "Aligning transmitter: stop burst"; + metadata.end_of_burst = true; + } else if (drop_cnt < 30) { + LOG(DEEPDEBUG) << "Aligning transmitter: packet advance"; + *underrun = true; + return len; + } else { + LOG(DEBUG) << "Aligning transmitter: start burst"; + metadata.start_of_burst = true; + aligned = true; + drop_cnt = 0; + } + } + + size_t num_smpls = usrp_dev->get_device()->send(buf, + len, + metadata, + uhd::io_type_t::COMPLEX_INT16, + uhd::device::SEND_MODE_FULL_BUFF); + + if (num_smpls != (unsigned)len) + LOG(ERROR) << "UHD: Sent fewer samples than requested"; + + return num_smpls; +} + +bool uhd_device::updateAlignment(TIMESTAMP timestamp) +{ + /* NOP */ + return true; +} + +bool uhd_device::setTxFreq(double wFreq) +{ + uhd::tune_result_t tr = usrp_dev->set_tx_freq(wFreq); + LOG(INFO) << tr.to_pp_string(); + return true; +} + +bool uhd_device::setRxFreq(double wFreq) +{ + uhd::tune_result_t tr = usrp_dev->set_rx_freq(wFreq); + LOG(INFO) << tr.to_pp_string(); + return true; +} + +bool uhd_device::recv_async_msg() +{ + uhd::async_metadata_t metadata; + if (!usrp_dev->get_device()->recv_async_msg(metadata)) + return false; + + // Assume that any error requires resynchronization + if (metadata.event_code != uhd::async_metadata_t::EVENT_CODE_BURST_ACK) { + aligned = false; + LOG(INFO) << str_code(metadata); + } + + return true; +} + +std::string uhd_device::str_code(uhd::rx_metadata_t metadata) +{ + std::ostringstream ost("UHD: "); + + switch (metadata.error_code) { + case uhd::rx_metadata_t::ERROR_CODE_NONE: + ost << "No error"; + break; + case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT: + ost << "No packet received, implementation timed-out"; + break; + case uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND: + ost << "A stream command was issued in the past"; + break; + case uhd::rx_metadata_t::ERROR_CODE_BROKEN_CHAIN: + ost << "Expected another stream command"; + break; + case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW: + ost << "An internal receive buffer has filled"; + break; + case uhd::rx_metadata_t::ERROR_CODE_BAD_PACKET: + ost << "The packet could not be parsed"; + break; + default: + ost << "Unknown error " << metadata.error_code; + } + + if (metadata.has_time_spec) + ost << " at " << metadata.time_spec.get_real_secs() << " sec."; + + return ost.str(); +} + +std::string uhd_device::str_code(uhd::async_metadata_t metadata) +{ + std::ostringstream ost("UHD: "); + + switch (metadata.event_code) { + case uhd::async_metadata_t::EVENT_CODE_BURST_ACK: + ost << "A packet was successfully transmitted"; + break; + case uhd::async_metadata_t::EVENT_CODE_UNDERFLOW: + ost << "An internal send buffer has emptied"; + break; + case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR: + ost << "Packet loss between host and device"; + break; + case uhd::async_metadata_t::EVENT_CODE_TIME_ERROR: + ost << "Packet time was too late or too early"; + break; + case uhd::async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET: + ost << "Underflow occurred inside a packet"; + break; + case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST: + ost << "Packet loss within a burst"; + break; + default: + ost << "Unknown error " << metadata.event_code; + } + + if (metadata.has_time_spec) + ost << " at " << metadata.time_spec.get_real_secs() << " sec."; + + return ost.str(); +} + +smpl_buf::smpl_buf(size_t len, double rate) + : buf_len(len), clk_rt(rate), + time_start(0), time_end(0), data_start(0), data_end(0) +{ + data = new uint32_t[len]; +} + +smpl_buf::~smpl_buf() +{ + delete[] data; +} + +ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const +{ + if (timestamp < time_start) + return ERROR_TIMESTAMP; + else if (timestamp >= time_end) + return 0; + else + return time_end - timestamp; +} + +ssize_t smpl_buf::avail_smpls(uhd::time_spec_t timespec) const +{ + return avail_smpls(convert_time(timespec, clk_rt)); +} + +ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp) +{ + // Check for valid read + if (timestamp < time_start) + return ERROR_TIMESTAMP; + if (timestamp >= time_end) + return 0; + if (len >= buf_len) + return ERROR_READ; + + // How many samples should be copied + size_t num_smpls = time_end - timestamp; + if (num_smpls > len); + num_smpls = len; + + // Starting index + size_t read_start = data_start + (timestamp - time_start); + + // Read it + if (read_start + num_smpls < buf_len) { + size_t numBytes = len * 2 * sizeof(short); + memcpy(buf, data + read_start, numBytes); + } else { + size_t first_cp = (buf_len - read_start) * 2 * sizeof(short); + size_t second_cp = len * 2 * sizeof(short) - first_cp; + + memcpy(buf, data + read_start, first_cp); + memcpy((char*) buf + first_cp, data, second_cp); + } + + data_start = (read_start + len) % buf_len; + time_start = timestamp + len; + + if (time_start > time_end) + return ERROR_READ; + else + return num_smpls; +} + +ssize_t smpl_buf::read(void *buf, size_t len, uhd::time_spec_t ts) +{ + return read(buf, len, convert_time(ts, clk_rt)); +} + +ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp) +{ + // Check for valid write + if ((len == 0) || (len >= buf_len)) + return ERROR_WRITE; + if ((timestamp + len) <= time_end) + return ERROR_TIMESTAMP; + + // Starting index + size_t write_start = (data_start + (timestamp - time_start)) % buf_len; + + // Write it + if ((write_start + len) < buf_len) { + size_t numBytes = len * 2 * sizeof(short); + memcpy(data + write_start, buf, numBytes); + } else { + size_t first_cp = (buf_len - write_start) * 2 * sizeof(short); + size_t second_cp = len * 2 * sizeof(short) - first_cp; + + memcpy(data + write_start, buf, first_cp); + memcpy(data, (char*) buf + first_cp, second_cp); + } + + data_end = (write_start + len) % buf_len; + time_end = timestamp + len; + + if (((write_start + len) > buf_len) && (data_end > data_start)) + return ERROR_OVERFLOW; + else if (time_end <= time_start) + return ERROR_WRITE; + else + return len; +} + +ssize_t smpl_buf::write(void *buf, size_t len, uhd::time_spec_t ts) +{ + return write(buf, len, convert_time(ts, clk_rt)); +} + +std::string smpl_buf::str_status() const +{ + std::ostringstream ost("Sample buffer: "); + + ost << "length = " << buf_len; + ost << ", time_start = " << time_start; + ost << ", time_end = " << time_end; + ost << ", data_start = " << data_start; + ost << ", data_end = " << data_end; + + return ost.str(); +} + +std::string smpl_buf::str_code(ssize_t code) +{ + switch (code) { + case ERROR_TIMESTAMP: + return "Sample buffer: Requested timestamp is not valid"; + case ERROR_READ: + return "Sample buffer: Read error"; + case ERROR_WRITE: + return "Sample buffer: Write error"; + case ERROR_OVERFLOW: + return "Sample buffer: Overrun"; + default: + return "Sample buffer: Unknown error"; + } +} + +RadioDevice *RadioDevice::make(double smpl_rt, bool skip_rx) +{ + return new uhd_device(smpl_rt, skip_rx); +} diff --git a/Transceiver52M/USRPDevice.cpp b/Transceiver52M/USRPDevice.cpp index 8455a15d..ad53be79 100644 --- a/Transceiver52M/USRPDevice.cpp +++ b/Transceiver52M/USRPDevice.cpp @@ -51,7 +51,8 @@ enum dboardConfigType { const dboardConfigType dboardConfig = TXA_RXB; const double USRPDevice::masterClockRate = 52.0e6; -USRPDevice::USRPDevice (double _desiredSampleRate) +USRPDevice::USRPDevice (double _desiredSampleRate, bool skipRx) + : skipRx(skipRx) { LOG(INFO) << "creating USRP device..."; decimRate = (unsigned int) round(masterClockRate/_desiredSampleRate); @@ -66,13 +67,11 @@ USRPDevice::USRPDevice (double _desiredSampleRate) #endif } -bool USRPDevice::make(bool wSkipRx) +bool USRPDevice::open() { - skipRx = wSkipRx; - writeLock.unlock(); - LOG(INFO) << "making USRP device.."; + LOG(INFO) << "opening USRP device.."; #ifndef SWLOOPBACK string rbf = "std_inband.rbf"; //string rbf = "inband_1rxhb_1tx.rbf"; @@ -555,3 +554,8 @@ bool USRPDevice::setRxFreq(double wFreq) bool USRPDevice::setTxFreq(double wFreq) { return true;}; bool USRPDevice::setRxFreq(double wFreq) { return true;}; #endif + +RadioDevice *RadioDevice::make(double desiredSampleRate, bool skipRx) +{ + return new USRPDevice(desiredSampleRate, skipRx); +} diff --git a/Transceiver52M/USRPDevice.h b/Transceiver52M/USRPDevice.h index 588ab0ca..9ae6da86 100644 --- a/Transceiver52M/USRPDevice.h +++ b/Transceiver52M/USRPDevice.h @@ -112,10 +112,10 @@ private: public: /** Object constructor */ - USRPDevice (double _desiredSampleRate); + USRPDevice (double _desiredSampleRate, bool skipRx); /** Instantiate the USRP */ - bool make(bool skipRx = false); + bool open(); /** Start the USRP */ bool start(); diff --git a/Transceiver52M/USRPping.cpp b/Transceiver52M/USRPping.cpp index b80e8cb3..62f7de64 100644 --- a/Transceiver52M/USRPping.cpp +++ b/Transceiver52M/USRPping.cpp @@ -28,7 +28,7 @@ #include #include #include -#include "USRPDevice.h" +#include "radioDevice.h" ConfigurationTable gConfig; @@ -41,9 +41,9 @@ int main(int argc, char *argv[]) { else gLogInit("DEBUG"); //if (argc>2) gSetLogFile(argv[2]); - USRPDevice *usrp = new USRPDevice(52.0e6/192.0); + RadioDevice *usrp = RadioDevice::make(52.0e6/192.0); - usrp->make(); + usrp->open(); TIMESTAMP timestamp; diff --git a/Transceiver52M/radioDevice.h b/Transceiver52M/radioDevice.h index 9ca39dad..8835ae51 100644 --- a/Transceiver52M/radioDevice.h +++ b/Transceiver52M/radioDevice.h @@ -27,6 +27,9 @@ typedef unsigned long long TIMESTAMP; class RadioDevice { public: + static RadioDevice *make(double desiredSampleRate, bool skipRx = false); + + virtual bool open()=0; /** Start the USRP */ virtual bool start()=0; @@ -45,9 +48,9 @@ class RadioDevice { @return The number of samples actually read */ virtual int readSamples(short *buf, int len, bool *overrun, - TIMESTAMP timestamp, - bool *underrun, - unsigned *RSSI=NULL)=0; + TIMESTAMP timestamp = 0xffffffff, + bool *underrun = 0, + unsigned *RSSI = 0)=0; /** Write samples to the radio. @param buf Contains the data to be written.