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 < zz4...@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.w...@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 < >> zz4...@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.w...@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 >>>> <zz4...@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.w...@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@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@lists.ettus.com >>>>>>> http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com >>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> >
_______________________________________________ USRP-users mailing list USRP-users@lists.ettus.com http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com