| 1 | /**************************************************************************** |
|---|
| 2 | |
|---|
| 3 | Copyright 2005,2006 Virginia Polytechnic Institute and State University |
|---|
| 4 | |
|---|
| 5 | This file is part of the OSSIE USRP_UHD Device. |
|---|
| 6 | |
|---|
| 7 | OSSIE USRP_UHD Device is free software; you can redistribute it and/or modify |
|---|
| 8 | it under the terms of the GNU General Public License as published by |
|---|
| 9 | the Free Software Foundation; either version 2 of the License, or |
|---|
| 10 | (at your option) any later version. |
|---|
| 11 | |
|---|
| 12 | OSSIE USRP_UHD Device 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. See the |
|---|
| 15 | GNU General Public License for more details. |
|---|
| 16 | |
|---|
| 17 | You should have received a copy of the GNU General Public License |
|---|
| 18 | along with OSSIE USRP_UHD Device; if not, write to the Free Software |
|---|
| 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | ****************************************************************************/ |
|---|
| 23 | |
|---|
| 24 | #include <byteswap.h> |
|---|
| 25 | #include <iostream> |
|---|
| 26 | #include <vector> |
|---|
| 27 | #include <complex> |
|---|
| 28 | |
|---|
| 29 | #include "ossie/cf.h" |
|---|
| 30 | #include "ossie/PortTypes.h" |
|---|
| 31 | |
|---|
| 32 | #include "ossie/ossieSupport.h" |
|---|
| 33 | #include "ossie/debug.h" |
|---|
| 34 | |
|---|
| 35 | #include "USRP_UHD.h" |
|---|
| 36 | |
|---|
| 37 | USRP_UHD_i::USRP_UHD_i(char *id, char *label, char *profile) : |
|---|
| 38 | Device_impl(id, label, profile), |
|---|
| 39 | set_rx_packet_count(-1), |
|---|
| 40 | rx_packet_count(1024), |
|---|
| 41 | rx_packet_size(256), |
|---|
| 42 | rx_data_size(2), |
|---|
| 43 | number_of_channels(1), |
|---|
| 44 | complex(true), |
|---|
| 45 | rx_overruns(0), |
|---|
| 46 | rx_active(false), |
|---|
| 47 | tx_active(false), |
|---|
| 48 | full_duplex(false), |
|---|
| 49 | did_rx(false) |
|---|
| 50 | { |
|---|
| 51 | // Create USRP_UHD Control ports for TX and RX |
|---|
| 52 | rx_control_port = new USRP_UHD_RX_Control_i(this, "U2_RX_Control", "DomainName1"); |
|---|
| 53 | tx_control_port = new USRP_UHD_TX_Control_i(this, "U2_TX_Control", "DomainName1"); |
|---|
| 54 | |
|---|
| 55 | // Create the ports for TX data |
|---|
| 56 | tx_data_port = new standardInterfaces_i::complexShort_p("U2_TX_Data", "DomainName1"); |
|---|
| 57 | |
|---|
| 58 | // Create the ports for RX Data |
|---|
| 59 | rx_data_1_port = new standardInterfaces_i::complexShort_u("U2_RX_Data_1", "DomainName1"); |
|---|
| 60 | rx_data_2_port = new standardInterfaces_i::complexShort_u("U2_RX_Data_2", "DomainName1"); |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | void USRP_UHD_i::start() throw (CF::Resource::StartError, CORBA::SystemException) |
|---|
| 64 | { |
|---|
| 65 | DEBUG(3, USRP_UHD, "Start USRP_UHD called") |
|---|
| 66 | } |
|---|
| 67 | |
|---|
| 68 | void USRP_UHD_i::stop() throw (CF::Resource::StopError, CORBA::SystemException) |
|---|
| 69 | { |
|---|
| 70 | DEBUG(3, USRP_UHD, "Stop USRP_UHD called") |
|---|
| 71 | (rx_active)?std::cout<<"Active": std::cout<<"NOT Active"; |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | CORBA::Object_ptr USRP_UHD_i::getPort(const char* portName) |
|---|
| 75 | throw(CF::PortSupplier::UnknownPort, CORBA::SystemException) |
|---|
| 76 | { |
|---|
| 77 | DEBUG(3, USRP_UHD, "USRP_UHD getPort called with : " << portName) |
|---|
| 78 | |
|---|
| 79 | CORBA::Object_var p; |
|---|
| 80 | |
|---|
| 81 | if (!CORBA::is_nil(p = rx_control_port->getPort(portName))) |
|---|
| 82 | return p._retn(); |
|---|
| 83 | else if (!CORBA::is_nil(p = rx_data_1_port->getPort(portName))) |
|---|
| 84 | return p._retn(); |
|---|
| 85 | else if (!CORBA::is_nil(p = rx_data_1_port->getPort(portName))) { |
|---|
| 86 | return p._retn(); |
|---|
| 87 | } else if (!CORBA::is_nil(p = tx_control_port->getPort(portName))) { |
|---|
| 88 | return p._retn(); |
|---|
| 89 | } else if (!CORBA::is_nil(p = tx_data_port->getPort(portName))) { |
|---|
| 90 | return p._retn(); |
|---|
| 91 | } |
|---|
| 92 | std::cerr << "Couldn't find port " << portName << "Throwing exception" << std::endl; |
|---|
| 93 | throw CF::PortSupplier::UnknownPort(); |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | void USRP_UHD_i::initialize() throw (CF::LifeCycle::InitializeError, CORBA::SystemException) |
|---|
| 97 | { |
|---|
| 98 | DEBUG(3, USRP_UHD, "USRP_UHD Initialize called") |
|---|
| 99 | std::string args("addr=192.168.10.2"); |
|---|
| 100 | DEBUG(1, USRP_UHD, "Creating the usrp device with: "<< args) |
|---|
| 101 | sdev = uhd::usrp::single_usrp::make(args); |
|---|
| 102 | dev = sdev->get_device(); |
|---|
| 103 | sdev->set_rx_antenna("RX2"); |
|---|
| 104 | sdev->set_rx_antenna("TX/RX"); |
|---|
| 105 | DEBUG(1, USRP_UHD, "Using Device: "<< sdev->get_pp_string()) |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | void USRP_UHD_i::configure(const CF::Properties &configProperties) |
|---|
| 109 | throw (CORBA::SystemException, CF::PropertySet::InvalidConfiguration, |
|---|
| 110 | CF::PropertySet::PartialConfiguration) |
|---|
| 111 | { |
|---|
| 112 | |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | void USRP_UHD_i::query(CF::Properties &configProperties) |
|---|
| 116 | throw (CORBA::SystemException, CF::UnknownProperties) |
|---|
| 117 | { |
|---|
| 118 | |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | |
|---|
| 122 | void USRP_UHD_i::releaseObject() |
|---|
| 123 | throw (CF::LifeCycle::ReleaseError, CORBA::SystemException) |
|---|
| 124 | { |
|---|
| 125 | |
|---|
| 126 | DEBUG(3, USRP_UHD, "USRP_UHD releaseObject called") |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | |
|---|
| 130 | void USRP_UHD_i::rx_data_process() |
|---|
| 131 | { |
|---|
| 132 | |
|---|
| 133 | ///\TODO assumes one channel operation. Set full_deplex to false to prevent Rx buffering during Tx |
|---|
| 134 | ///Full duplex mode is still broken. we still cannot transmit and receive simultaneously using WBX board |
|---|
| 135 | |
|---|
| 136 | //tells the device to stream samples indefinitely |
|---|
| 137 | uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); |
|---|
| 138 | |
|---|
| 139 | //Use with STREAM_MODE_NUM_SAMPS_AND_DONE/_MORE |
|---|
| 140 | //stream_cmd.num_samps = 65536; |
|---|
| 141 | //stream_cmd.time_spec = uhd::time_spec_t((time_t)0); |
|---|
| 142 | |
|---|
| 143 | //When true, the device will begin streaming ASAP |
|---|
| 144 | stream_cmd.stream_now = true; |
|---|
| 145 | |
|---|
| 146 | sdev->issue_stream_cmd(stream_cmd); |
|---|
| 147 | |
|---|
| 148 | PortTypes::ShortSequence I; |
|---|
| 149 | PortTypes::ShortSequence Q; |
|---|
| 150 | |
|---|
| 151 | ///\TODO Make sure rx_packet_size is >= than USRP_UHD_MIN_RX_SAMPLES!!!!! |
|---|
| 152 | rx_buff.resize(rx_packet_size); |
|---|
| 153 | I.length(rx_packet_size); |
|---|
| 154 | Q.length(rx_packet_size); |
|---|
| 155 | |
|---|
| 156 | DEBUG(3, USRP_UHD, "RX packet count " << rx_packet_count) |
|---|
| 157 | |
|---|
| 158 | while (rx_active && ((rx_packet_count == -1) || (rx_packet_count > 0))) { |
|---|
| 159 | uhd::rx_metadata_t md; |
|---|
| 160 | //if we are running half duplex mode we will need to tell start streaming at the beginning of the loop |
|---|
| 161 | if (full_duplex == false && did_rx == false) { |
|---|
| 162 | uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); |
|---|
| 163 | sdev->issue_stream_cmd(stream_cmd); |
|---|
| 164 | did_rx = true; |
|---|
| 165 | } |
|---|
| 166 | |
|---|
| 167 | |
|---|
| 168 | //TODO get rid of num_rx_samps variable |
|---|
| 169 | size_t num_rx_samps = dev->recv( &rx_buff.front(), rx_packet_size, md, |
|---|
| 170 | uhd::io_type_t::COMPLEX_INT16, |
|---|
| 171 | uhd::device::RECV_MODE_FULL_BUFF); |
|---|
| 172 | |
|---|
| 173 | //Handle UHD error codes |
|---|
| 174 | switch(md.error_code){ |
|---|
| 175 | case uhd::rx_metadata_t::ERROR_CODE_NONE: |
|---|
| 176 | break; |
|---|
| 177 | case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT: |
|---|
| 178 | DEBUG(3, USRP_UHD, "Got timeout before all samples received, possible packet loss") |
|---|
| 179 | break; |
|---|
| 180 | default: |
|---|
| 181 | DEBUG(3, USRP_UHD, "Got error code 0x"<<md.error_code) |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | for (unsigned int i = 0; i < num_rx_samps; i++) { |
|---|
| 185 | I[i] = (CORBA::Short) rx_buff[i].real(); |
|---|
| 186 | Q[i] = (CORBA::Short) rx_buff[i].imag(); |
|---|
| 187 | } |
|---|
| 188 | rx_data_1_port->pushPacket(I, Q); |
|---|
| 189 | |
|---|
| 190 | if (rx_packet_count != -1) |
|---|
| 191 | --rx_packet_count; |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | DEBUG(3, USRP_UHD, "Exiting rx_data_process thread") |
|---|
| 195 | //tells the device to stop streaming samples |
|---|
| 196 | stream_cmd = uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS; |
|---|
| 197 | sdev->issue_stream_cmd(stream_cmd); |
|---|
| 198 | rx_active = false; |
|---|
| 199 | rx_thread->exit(); |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | |
|---|
| 203 | |
|---|
| 204 | // USRP_UHD Expects data in little endian format |
|---|
| 205 | static inline short convertToLE(short s) |
|---|
| 206 | { |
|---|
| 207 | #ifdef __powerpc__ |
|---|
| 208 | s = bswap_16(s); |
|---|
| 209 | #endif |
|---|
| 210 | |
|---|
| 211 | return s; |
|---|
| 212 | } |
|---|
| 213 | |
|---|
| 214 | void USRP_UHD_i::tx_data_process() |
|---|
| 215 | { |
|---|
| 216 | PortTypes::ShortSequence *I_in, *Q_in; |
|---|
| 217 | |
|---|
| 218 | const unsigned int tx_buf_len(USRP_UHD_MAX_TX_SAMPLES); |
|---|
| 219 | |
|---|
| 220 | uhd::tx_metadata_t md3; |
|---|
| 221 | |
|---|
| 222 | //Set start and end of burst flags to help with packet fragmentation if needed |
|---|
| 223 | //Host will send ACK packets when an EOB flag is received |
|---|
| 224 | //SOB true -> first packet in sequence gets SOB flag |
|---|
| 225 | //EOB true -> last packet in sequence gets EOB flag |
|---|
| 226 | md3.start_of_burst = false; |
|---|
| 227 | md3.end_of_burst = false; |
|---|
| 228 | |
|---|
| 229 | //We can send packets in the future if needed |
|---|
| 230 | //md.has_time_spec = 0; //no time |
|---|
| 231 | //md.time_spec = uhd::time_spec_t((time_t)0 ); |
|---|
| 232 | |
|---|
| 233 | std::vector< std::complex<short int> > tx_buff(tx_buf_len); |
|---|
| 234 | |
|---|
| 235 | DEBUG(3, USRP_UHD, "Starting tx_data_process thread.") |
|---|
| 236 | |
|---|
| 237 | tx_active = true; // Cleared to stop TX in USRP_UHD_TX_Control->stop() |
|---|
| 238 | |
|---|
| 239 | while (tx_active) { |
|---|
| 240 | //if running half duplex mode we want to stop Rx streaming while transmitting |
|---|
| 241 | if (full_duplex == false && did_rx == true) { |
|---|
| 242 | did_rx = false; |
|---|
| 243 | uhd::rx_metadata_t md; |
|---|
| 244 | size_t num_rx_samps = dev->recv( &rx_buff.front(), rx_packet_size, md, |
|---|
| 245 | uhd::io_type_t::COMPLEX_INT16, |
|---|
| 246 | uhd::device::RECV_MODE_FULL_BUFF); |
|---|
| 247 | sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); |
|---|
| 248 | |
|---|
| 249 | } |
|---|
| 250 | |
|---|
| 251 | |
|---|
| 252 | tx_data_port->getData(I_in, Q_in); |
|---|
| 253 | size_t samps_to_send = I_in->length(); |
|---|
| 254 | |
|---|
| 255 | if(samps_to_send > tx_buf_len){ |
|---|
| 256 | std::cerr << "USRP_UHD Tx Buffer Overflow. Throwing Exception"<<std::endl; |
|---|
| 257 | throw std::runtime_error("USRP_UHD buffer overflow"); |
|---|
| 258 | } |
|---|
| 259 | |
|---|
| 260 | for (unsigned int i = 0; i < samps_to_send; ++i) { |
|---|
| 261 | tx_buff[i] = std::complex<short int> (convertToLE((*I_in)[i]), |
|---|
| 262 | convertToLE((*Q_in)[i])); |
|---|
| 263 | } |
|---|
| 264 | |
|---|
| 265 | //send the entire packet (driver fragments internally) |
|---|
| 266 | size_t num_tx_samps = dev->send( &tx_buff.front(), samps_to_send, md3, |
|---|
| 267 | uhd::io_type_t::COMPLEX_INT16, |
|---|
| 268 | uhd::device::SEND_MODE_FULL_BUFF); |
|---|
| 269 | tx_data_port->bufferEmptied(); |
|---|
| 270 | |
|---|
| 271 | } |
|---|
| 272 | |
|---|
| 273 | DEBUG(3, USRP_UHD, "Exiting tx_data_process thread.") |
|---|
| 274 | tx_thread->exit(); |
|---|
| 275 | } |
|---|