Simple UHD Transceiver Class

I wrote a simple transceiver class for the USRP1 (GNURadio) using the new UHD interface.

The class allows you to send and receive data.  What you fill in for the data is up to you.  Currently, the class performs simple energy detection (sends a 100 sample burst with constant envelope) and works when you hook the RX up to the TX on the Basic RX/TX boards (make sure you have proper attenuation as to not break the daughterboards).  But, with some simple modification, you can have it do more sophisticated processing.

The class creates two queues and three threads.

One queue is the TX queue and the other the RX queue. The TX queue is a vector of pointers to complex float vectors (variable length) and are waveforms to be transmitted. The RX queue is a vector of pointers to complex float vectors (const size) and are the data blocks received from the radio.

The three threads are the TX thread, the RX thread, and the processing thread.

The TX thread wakes up every 100ms and looks at the TX queue and sends any waveforms that are present.  The RX thread runs continuously and receives datablocks from the radio. The processing thread checks the RX queue and processes any blocks that are present on it.  Having an RX queue, RX thread, and processing thread allows the software to continually receive data without dropping packets and leaves the choice up to the software as to which packets to process.  For example, if the processing thread runs slower than the samples coming in (slower than real time), it may choose to intelligently process the remaining blocks instead of dropping data on the floor.  This would allow the processing thread to “catch up.”

The TX thread can be modified as to send the waveforms out immediately instead of on a queue for servicing.

I hope all this makes sense.

The code can be downloaded here.  I used this to compile:

g++ main.cpp SimpleTransceiver.cpp -lboost_thread -luhd -I/opt/uhd/include -L/opt/uhd/lib

Bugs, questions, comments welcomed.

Enjoy!

Tags: , ,

7 Responses to “Simple UHD Transceiver Class”

  1. Johnny Says:

    Great codes! I really like the way you use your comments, they make understanding your code much easier.

    I have a question: I want to extend this program so that I can have transmitter and receiver operating on 2.4GHz band, I have the XCVR2450 daughterboards on them. How should I process?

  2. admin Says:

    Hi Johnny,
    Thanks for the complement. I only have a single daughterboard, but I believe all you need to do is change the rx/tx freqs. In the code,

    //set the rx center frequency
    Float64 freq = 2.4e9;

    There is a usrp mailing list that ettus.com provides. These folks are really helpful and can provide you assistance if my suggestion does not work. I also found the sample code that ettus provides very helpful: http://ettus-apps.sourcerepo.com/redmine/ettus/projects/uhd/repository/revisions/master/show/host/examples

    Good luck,
    Isaac

  3. Johnny Says:

    Thanks a lot for your quick reply. I do have another question: in setupUsrp(), what exactly does this loop do?
    while(m_pDev->recv(&buff.front(), buff.size(), md,uhd::io_type_t::COMPLEX_FLOAT32,uhd::device::RECV_MODE_ONE_PACKET))
    {
    // NOP
    }

    If I’m right the recv function takes in another parameter, timeout, which is default to 0.1s. But if I put in any value for timeout, the loop won’t exit. Can you give me some pointers?

  4. admin Says:

    Hi Johnny,

    This piece of code is supposed to flush the rx buffer. I got the code from the ettus.com repository but I have yet to see it work correctly.

    What you are experiencing wrt to the timeout, I believe, is the fact that your rx buffer has no extraneous samples and thus you are waiting for input, but don’t rx any. One way to check this is to put a cout statment in the while loop to see if you are hanging on the recv() call or the while loop just keeps on looping.

    I would just remove this piece of code. Perhaps it works well for the USRP2, but I havent gotten it to work with the USRP1. I have removed it in my projects.

    Hope that helps,
    Isaac

  5. Johnny Says:

    Actually I’m using USRP2. I’ve also just seen that piece of code in the benchmark_rx_rate example for UHD. I’m still not very sure how it works. The timeout only happens once, in the setupUsrp() routine. Afterward the rxThread seems to be working fine, even though all received data are 0. That fact made me wonder if anything was being transmitted. So I ran the transceiver on 1 USRP2, and fft on another. Strangely enough, I didn’t see any changes in the spectrum. I did set the sleep time in main to 200ms so the bursts should be sent quite frequently.

    Do you have any idea why nothing was being transmitted? And thanks again for your help!

  6. admin Says:

    Hi Johnny,

    There are a couple of things going on here that Im not sure you are aware of (or I need to get straight what it is u exactly are doing).

    1. I expect the setupUsrp() flush to go through the while loop once as there are likely extraneious samples in the rx buffer.
    2. The behaviour regarding rxThread seems fine if the rx and tx daughterboards are not connected together (be careful doing this as you can blow the board out). I used the basix Rx/Tx and you are not so I have no way to understand what’s going on with your setup.
    3. The txThread works by servicing a queue which tx waveforms on it. You have to call one of the tx functions to put a waveform on the queue or nothing will be send. The sleep time is just the time the txthread wakes up to check to see if there are messages to send. If there are none, it sleeps. If there are some, it sends them, and then goes back to sleep.
    4. Since you have 2 usrps, i would pick a path (tx or rx, tx prefered) and start by getting it to work. Once you understand it, then go to the other path.
    5. Use the USRP users listserv. I know that you are using my code, but much of it is from snippets from ettus’s codes. Additionally, there may be others using my code who are using the dboards you are using. My code is best used for someone who understands the flow (the computer science part with queues, etc) and not the RF part. Make sure you understand the computer science stuff first.

    Isaac

  7. Johnny Says:

    Hi Isaac,

    Thank you very much for your time helping me out. I’m not a code guru and have a stronger EE background than CS. But thanks to your well-written code, I think I have a pretty good idea of the flow of the software.

    1. I got your point. The while loop will flush out the rx buffer until there’s nothing left in the buffer, which is when ERR0R_CODE_TIMEOUT is set

    2. In my setup, I have 2 USRPs operating at 2.412GHz. I want to run the transceiver on both of them to create a simple half-duplex communication.

    3. I understand that operation. In your code, a constant complex value (1,1) is sent 100 times every burst. Since I’ve shorten the time interval between bursts, I expect to see a DC component in the transmitting waveform. What puzzled me was that I didn’t see that component. I’ve also tried to generate a complex sine wave in postBurst(), but I didn’t see any peak in the spectrum either. If the complex samples are properly consumed by send() then I should see a tone, right?

    5. Thanks for the suggestion, I’ve been subscribed to USRP-users listserv for a while but haven’t made full use of it. Nevertheless, I think that you would be the best one to answer my questions still they are related to your code. If you prefer I can post questions as follow-ups on your thread on the listserv (just found it out).

    Johnny

Leave a Reply