[USRP-users] Different streaming modes at the same time with same USRP hardware

Michael West michael.west at ettus.com
Fri Jul 7 17:32:40 EDT 2017


Hi Felipe,

If it works, it must be right!  The code looks fine to me.

Regards,
Michael

On Mon, Jul 3, 2017 at 3:58 AM, Felipe Augusto Pereira de Figueiredo <
zz4fap at gmail.com> wrote:

> Dear Michael,
>
> I've followed your suggestion and hacked the rx_samples_c.c example.
> It seems to be working but I'm not sure if that is the right way of doing
> that.
> Could you please have a quick look and tell me if that is the correct way
> of creating 2 different RX streams.
>
> Thanks and Kind Regards,
>
> Felipe Augusto
>
> /*
>  * Copyright 2015 Ettus Research LLC
>  *
>  * This program is free software: you can redistribute it and/or modify
>  * it under the terms of the GNU 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 General Public License for more details.
>  *
>  * You should have received a copy of the GNU General Public License
>  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>  */
>
> #include <uhd.h>
>
> #include "getopt.h"
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> #define EXECUTE_OR_GOTO(label, ...) \
>     if(__VA_ARGS__){ \
>         return_code = EXIT_FAILURE; \
>         goto label; \
>     }
>
> void print_help(void){
>     fprintf(stderr, "rx_samples_c - A simple RX example using UHD's C
> API\n\n"
>
>                     "Options:\n"
>                     "    -a (device args)\n"
>                     "    -f (frequency in Hz)\n"
>                     "    -r (sample rate in Hz)\n"
>                     "    -g (gain)\n"
>                     "    -n (number of samples to receive)\n"
>                     "    -o (output filename, default = \"out.dat\")\n"
>                     "    -v (enable verbose prints)\n"
>                     "    -h (print this help message)\n");
> };
>
> int main(int argc, char* argv[])
> {
>     if(uhd_set_thread_priority(uhd_default_thread_priority, true)){
>         fprintf(stderr, "Unable to set thread priority. Continuing
> anyway.\n");
>     }
>
>     int option = 0;
>     double freq = 2.4e9;
>     double rate = 10e6;
>     double gain = 5.0;
>     char* device_args = "";
>     size_t channel[2] = {0,1};
>     char *filename0 = "out0.dat", *filename1 = "out1.dat";
>     size_t n_samples = 1000000;
>     bool verbose = false;
>     int return_code = EXIT_SUCCESS;
>     bool custom_filename0 = false, custom_filename1 = false;
>     char error_string[512];
>
>     // Process options
>     while((option = getopt(argc, argv, "a:f:r:g:n:o:O:vh")) != -1){
>         switch(option){
>             case 'a':
>                 device_args = strdup(optarg);
>                 break;
>
>             case 'f':
>                 freq = atof(optarg);
>                 break;
>
>             case 'r':
>                 rate = atof(optarg);
>                 break;
>
>             case 'g':
>                 gain = atof(optarg);
>                 break;
>
>             case 'n':
>                 n_samples = atoi(optarg);
>                 break;
>
>             case 'o':
>                 filename0 = strdup(optarg);
>                 custom_filename0 = true;
>                 break;
>
>             case 'O':
>                 filename1 = strdup(optarg);
>                 custom_filename1 = true;
>                 break;
>
>             case 'v':
>                 verbose = true;
>                 break;
>
>             case 'h':
>                 print_help();
>                 goto free_option_strings;
>
>             default:
>                 print_help();
>                 return_code = EXIT_FAILURE;
>                 goto free_option_strings;
>         }
>     }
>
>     // Create USRP
>     uhd_usrp_handle usrp;
>     fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args);
>     EXECUTE_OR_GOTO(free_option_strings,
>         uhd_usrp_make(&usrp, device_args)
>     )
>
>     // Create RX streamer #0.
>     uhd_rx_streamer_handle rx_streamer0;
>     EXECUTE_OR_GOTO(free_usrp,
>         uhd_rx_streamer_make(&rx_streamer0)
>     )
>
>     // Create RX metadata #0.
>     uhd_rx_metadata_handle md0;
>     EXECUTE_OR_GOTO(free_rx_streamer0,
>         uhd_rx_metadata_make(&md0)
>     )
>
>     // Create RX streamer #1.
>     uhd_rx_streamer_handle rx_streamer1;
>     EXECUTE_OR_GOTO(free_usrp,
>         uhd_rx_streamer_make(&rx_streamer1)
>     )
>
>     // Create RX metadata #1.
>     uhd_rx_metadata_handle md1;
>     EXECUTE_OR_GOTO(free_rx_streamer1,
>         uhd_rx_metadata_make(&md1)
>     )
>
>     // Create other necessary structs
>     uhd_tune_request_t tune_request = {
>         .target_freq = freq,
>         .rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
>         .dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
>     };
>     uhd_tune_result_t tune_result;
>
>     uhd_stream_args_t stream_args = {
>         .cpu_format = "fc32",
>         .otw_format = "sc16",
>         .args = "",
>         .channel_list = &channel,
>         .n_channels = 2
>     };
>
>     size_t samps_per_buff0, samps_per_buff1;
>     float *buff0 = NULL, *buff1 = NULL;
>     void **buffs_ptr0 = NULL, **buffs_ptr1 = NULL;
>     FILE *fp0 = NULL, *fp1 = NULL;
>     size_t num_acc_samps0 = 0, num_acc_samps1 = 0;
>
>     // Set rate for stream #0
>     fprintf(stderr, "Setting RX Rate 0: %f...\n", rate);
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_set_rx_rate(usrp, rate, channel[0])
>     )
>
>     // Set rate for stream #1
>     // Stream number 1 should have a different sampling rate.
>     rate = 2*rate;
>     fprintf(stderr, "Setting RX Rate 1: %f...\n", rate);
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_set_rx_rate(usrp, rate, channel[1])
>     )
>
>     // See what rate is actually set for stream #0
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_get_rx_rate(usrp, channel[0], &rate)
>     )
>     fprintf(stderr, "Actual RX Rate 0: %f...\n", rate);
>
>     // See what rate is actually set for stream #1
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_get_rx_rate(usrp, channel[1], &rate)
>     )
>     fprintf(stderr, "Actual RX Rate 1: %f...\n", rate);
>
>     // Set gain for stream #0
>     fprintf(stderr, "Setting RX Gain 0: %f dB...\n", gain);
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_set_rx_gain(usrp, gain, channel[0], "")
>     )
>
>     // Set gain for stream #1
>     fprintf(stderr, "Setting RX Gain 1: %f dB...\n", gain);
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_set_rx_gain(usrp, gain, channel[1], "")
>     )
>
>     // See what gain is actually set for stream #0
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_get_rx_gain(usrp, channel[0], "", &gain)
>     )
>     fprintf(stderr, "Actual RX Gain 0: %f...\n", gain);
>
>     // See what gain is actually set for stream #1
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_get_rx_gain(usrp, channel[1], "", &gain)
>     )
>     fprintf(stderr, "Actual RX Gain 1: %f...\n", gain);
>
>     // Set frequency for stream #0
>     fprintf(stderr, "Setting RX frequency 0: %f MHz...\n", freq/1e6);
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_set_rx_freq(usrp, &tune_request, channel[0],
> &tune_result)
>     )
>
>     // Set frequency for stream #1
>     freq = 3e9;
>     tune_request.target_freq = freq;
>     fprintf(stderr, "Setting RX frequency 1: %f MHz...\n", freq/1e6);
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_set_rx_freq(usrp, &tune_request, channel[1],
> &tune_result)
>     )
>
>     // See what frequency is actually set fro stream #0
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_get_rx_freq(usrp, channel[0], &freq)
>     )
>     fprintf(stderr, "Actual RX frequency 0: %f MHz...\n", freq / 1e6);
>
>     // See what frequency is actually set fro stream #1
>     EXECUTE_OR_GOTO(free_rx_metadata,
>         uhd_usrp_get_rx_freq(usrp, channel[1], &freq)
>     )
>     fprintf(stderr, "Actual RX frequency 1: %f MHz...\n", freq / 1e6);
>
>     // Set up streamer #0.
>     printf("Try to get RX Stream #0\n");
>     stream_args.channel_list = &channel[0];
>     stream_args.n_channels = 1;
>     EXECUTE_OR_GOTO(free_rx_streamer0,
>         uhd_usrp_get_rx_stream(usrp, &stream_args, rx_streamer0)
>     )
>     printf("Got RX Stream #0\n");
>
>     // Set up streamer #1.
>     printf("Try to get RX Stream #1\n");
>     stream_args.channel_list = &channel[1];
>     stream_args.n_channels = 1;
>     EXECUTE_OR_GOTO(free_rx_streamer1,
>         uhd_usrp_get_rx_stream(usrp, &stream_args, rx_streamer1)
>     )
>     printf("Got RX Stream #1\n");
>
>     // Set up buffer for stream #0.
>     EXECUTE_OR_GOTO(free_rx_streamer0,
>        uhd_rx_streamer_max_num_samps(rx_streamer0, &samps_per_buff0)
>     )
>     printf("Buffer size in samples for stream #0: %zu\n", samps
> _per_buff0);
>     buff0 = malloc(samps_per_buff0 * 2 * sizeof(float));
>     buffs_ptr0 = (void**)&buff0;
>
>     // Set up buffer for stream #1.
>     EXECUTE_OR_GOTO(free_rx_streamer1,
>        uhd_rx_streamer_max_num_samps(rx_streamer1, &samps_per_buff1)
>     )
>     printf("Buffer size in samples for stream #1: %zu\n", samps
> _per_buff1);
>     buff1 = malloc(samps_per_buff1 * 2 * sizeof(float));
>     buffs_ptr1 = (void**)&buff1;
>
>     // Stream command for stream #0.
>     uhd_stream_cmd_t stream_cmd0 = {
>         .stream_mode = UHD_STREAM_MODE_NUM_SAMPS_AND_DONE,
>         .num_samps = n_samples,
>         .stream_now = false,
> .time_spec_full_secs = 2,
> .time_spec_frac_secs = 0
>     };
>
>     // Issue stream command for stream #0.
>     fprintf(stderr, "Issuing stream command for stream #0.\n");
>     EXECUTE_OR_GOTO(free_buffer0,
>         uhd_rx_streamer_issue_stream_cmd(rx_streamer0, &stream_cmd0)
>     )
>
>     // Stream command for stream #1.
>     uhd_stream_cmd_t stream_cmd1 = {
>         .stream_mode = UHD_STREAM_MODE_NUM_SAMPS_AND_DONE,
>         .num_samps = n_samples,
>         .stream_now = false,
> .time_spec_full_secs = 4,
> .time_spec_frac_secs = 0
>     };
>
>     // Issue stream command for stream #1.
>     fprintf(stderr, "Issuing stream command for stream #1.\n");
>     EXECUTE_OR_GOTO(free_buffer1,
>         uhd_rx_streamer_issue_stream_cmd(rx_streamer1, &stream_cmd1)
>     )
>
>     // Set up file output for stream #0.
>     fp0 = fopen(filename0, "wb");
>
>     // Set up file output for stream #1.
>     fp1 = fopen(filename1, "wb");
>
>     // Actual streaming
>     while (num_acc_samps0 < n_samples) {
>         size_t num_rx_samps0 = 0;
>         EXECUTE_OR_GOTO(close_file0,
>             uhd_rx_streamer_recv(rx_streamer0, buffs_ptr0, samps_per_buff0,
> &md0, 3.0, false, &num_rx_samps0)
>         )
>
>         size_t num_rx_samps1 = 0;
>         EXECUTE_OR_GOTO(close_file1,
>             uhd_rx_streamer_recv(rx_streamer1, buffs_ptr1, samps_per_buff1,
> &md1, 3.0, false, &num_rx_samps1)
>         )
>
>         uhd_rx_metadata_error_code_t error_code0;
>         EXECUTE_OR_GOTO(close_file0,
>             uhd_rx_metadata_error_code(md0, &error_code0)
>         )
>         if(error_code0 != UHD_RX_METADATA_ERROR_CODE_NONE){
>             fprintf(stderr, "Error code 0x%x was returned during
> streaming. Aborting: 0x%x.\n", return_code,error_code0);
>             goto close_file0;
>         }
>
>         uhd_rx_metadata_error_code_t error_code1;
>         EXECUTE_OR_GOTO(close_file1,
>             uhd_rx_metadata_error_code(md1, &error_code1)
>         )
>         if(error_code1 != UHD_RX_METADATA_ERROR_CODE_NONE){
>             fprintf(stderr, "Error code 0x%x was returned during
> streaming. Aborting: 0x%x.\n", return_code,error_code1);
>             goto close_file1;
>         }
>
>         // Handle data for stream #0.
>         fwrite(buff0, sizeof(float) * 2, num_rx_samps0, fp0);
>         if (verbose) {
>             time_t full_secs;
>             double frac_secs;
>             uhd_rx_metadata_time_spec(md0, &full_secs, &frac_secs);
>             fprintf(stderr, "Received packet: %zu samples, %.f full secs,
> %f frac secs\n",
>                     num_rx_samps0,
>                     difftime(full_secs, (time_t) 0),
>                     frac_secs);
>         }
>
>         num_acc_samps0 += num_rx_samps0;
>
>         // Handle data for stream #1.
>         fwrite(buff1, sizeof(float) * 2, num_rx_samps1, fp1);
>         if (verbose) {
>             time_t full_secs;
>             double frac_secs;
>             uhd_rx_metadata_time_spec(md1, &full_secs, &frac_secs);
>             fprintf(stderr, "Received packet: %zu samples, %.f full secs,
> %f frac secs\n",
>                     num_rx_samps1,
>                     difftime(full_secs, (time_t) 0),
>                     frac_secs);
>         }
>
>         num_acc_samps1 += num_rx_samps1;
>     }
>     printf("Finished.\n");
>
>     // Cleanup
>     close_file0:
>         fclose(fp0);
>
>     close_file1:
>         fclose(fp1);
>
>     free_buffer0:
>         if(buff0){
>             if(verbose){
>                 fprintf(stderr, "Freeing buffer #0.\n");
>             }
>             free(buff0);
>         }
>         buff0 = NULL;
>         buffs_ptr0 = NULL;
>
>     free_buffer1:
>         if(buff1){
>             if(verbose){
>                 fprintf(stderr, "Freeing buffer #1.\n");
>             }
>             free(buff1);
>         }
>         buff1 = NULL;
>         buffs_ptr1 = NULL;
>
>     free_rx_streamer0:
>         if(verbose){
>             fprintf(stderr, "Cleaning up RX streamer #0.\n");
>         }
>         uhd_rx_streamer_free(&rx_streamer0);
>
>     free_rx_streamer1:
>         if(verbose){
>             fprintf(stderr, "Cleaning up RX streamer #1.\n");
>         }
>         uhd_rx_streamer_free(&rx_streamer1);
>
>     free_rx_metadata:
>         if(verbose){
>             fprintf(stderr, "Cleaning up RX metadata.\n");
>         }
>         uhd_rx_metadata_free(&md0);
>
>     free_usrp:
>         if(verbose){
>             fprintf(stderr, "Cleaning up USRP.\n");
>         }
>         if(return_code != EXIT_SUCCESS && usrp != NULL){
>             uhd_usrp_last_error(usrp, error_string, 512);
>             fprintf(stderr, "USRP reported the following error: %s\n",
> error_string);
>         }
>         uhd_usrp_free(&usrp);
>
>     free_option_strings:
>         if(strcmp(device_args,"")){
>             free(device_args);
>         }
>         if(custom_filename0){
>             free(filename0);
>         }
>         if(custom_filename1){
>             free(filename1);
>         }
>
>     fprintf(stderr, (return_code ? "Failure\n" : "Success\n"));
>     return return_code;
> }
>
> On Sat, Jul 1, 2017 at 6:36 PM, Michael West <michael.west at ettus.com>
> wrote:
>
>> Hi Felipe,
>>
>> Both the multi_usrp API and the RFNoC API support it.  And yes, you need
>> to create two different stream objects.
>>
>> Regards,
>> Michael
>>
>> On Sat, Jul 1, 2017 at 2:45 AM, Felipe Augusto Pereira de Figueiredo <
>> zz4fap at gmail.com> wrote:
>>
>>> Dear Michael,
>>>
>>> Some more questions follows inline.
>>>
>>> Thanks and Kind Regards,
>>>
>>> Felipe Augusto
>>>
>>> On Sat, Jul 1, 2017 at 2:16 AM, Michael West <michael.west at ettus.com>
>>> wrote:
>>>
>>>> Hi Felipe,
>>>>
>>>> 1)  Yes, that is supported.
>>>>
>>>
>>> When you say that is supported, do you mean with legacy UHD API or with
>>> RFNoC one? Even though I have a x310 I'm still using the legacy API.
>>>
>>>>
>>>> 2)  There is no example, but it is pretty easy.  Just set the
>>>> uhd::stream_args_t::channels value correctly for each streamer object.
>>>>
>>>
>>> Do I need to create two different stream objects?
>>>
>>>>
>>>> Regards,
>>>> Michael
>>>>
>>>> On Fri, Jun 30, 2017 at 12:00 PM, Felipe Augusto Pereira de Figueiredo
>>>> <zz4fap at gmail.com> wrote:
>>>>
>>>>> Dear Michael,
>>>>>
>>>>> Thanks for the reply.
>>>>>
>>>>> Given your answer, I've got two additional questions:
>>>>>
>>>>> 1) Does it mean I can create a RX stream to read RXed samples from the
>>>>> RF chain 0 (I think you call DSP0) and another RX stream to read samples
>>>>> from RF chain 1 (DSP1)? I'd like to have a SISO physical layer running
>>>>> (TX/RX) on the RF chain 0 at frequency X and sample rate Y and a spectrum
>>>>> sensing module with different sampling rate Z at frequency W on the RF
>>>>> chain 1.
>>>>>
>>>>> 2) Is there any example on how to create different streamers to
>>>>> receive/transmit using different RF Chains?
>>>>>
>>>>> Many Thanks and Kind Regards,
>>>>>
>>>>> Felipe Augusto
>>>>>
>>>>> On Fri, Jun 30, 2017 at 8:32 PM, Michael West <michael.west at ettus.com>
>>>>> wrote:
>>>>>
>>>>>> Hi Felipe,
>>>>>>
>>>>>> Yes.  If you create different streamers, each with a different set of
>>>>>> channels, each streamer can be configured independently.
>>>>>>
>>>>>> Regards,
>>>>>> Michael
>>>>>>
>>>>>> On Tue, Jun 27, 2017 at 7:28 AM, Felipe Augusto Pereira de Figueiredo
>>>>>> via USRP-users <usrp-users at lists.ettus.com> wrote:
>>>>>>
>>>>>>> Dear folks,
>>>>>>>
>>>>>>> I've got a x310 and I'd like to know if it is possible to open two
>>>>>>> streams with different streaming modes at the same time in the same USRP
>>>>>>> hardware.
>>>>>>>
>>>>>>> For example, the first RF chain would be configures as
>>>>>>>
>>>>>>> *UHD_STREAM_MODE_START_CONTINUOUS*
>>>>>>>
>>>>>>> and the second one would be set to
>>>>>>>
>>>>>>> *UHD_STREAM_MODE_NUM_SAMPS_AND_DONE*
>>>>>>>
>>>>>>> Is is possible?
>>>>>>>
>>>>>>> Thanks and Kind regards,
>>>>>>>
>>>>>>> Felipe Augusto
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> USRP-users mailing list
>>>>>>> USRP-users at lists.ettus.com
>>>>>>> http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ettus.com/pipermail/usrp-users_lists.ettus.com/attachments/20170707/81985abb/attachment-0002.html>


More information about the USRP-users mailing list