Hi all,

Thanks a lot Sam and Marcus for replying so quickly.

Le me first include Marcus answer in this email chain for a cleaner
communication:
"*Gnu Radio cannot really misalign samples, unless the DSP logic arranges
for that to happen. If you have a block with a bunch of streams, that
blocks "work" function cannot proceed until there is equal amounts of data
available on all streams. In the absence of the hardware dropping samples,
coherence is maintained in that case. What you are seeing here seems to be
a problem with your network stack  losing things. What type of Ethernet
adapters do you have? What sample rates are you running?*"

*The requested extra info:*
- The sampling rates selected are *1Msps* for the TX and *2Msps* for the RX.
- The SFP connector attached to the USRP-X310s: AVAGO, 1.25GBd, 1000BASE-T,
ABCU-5730ARZ.
- The NIC: Intel Corporation Gigabit CT Desktop Adapter.
- The Ethernet controller: Intel Corporation 82574L Gigabit Network
Connection.

@Marcus,
good thing that the scheduler in each block handles that correctly. I'll
focus on the network setup then.

@Sam,
it seems reasonable to think that the source of error is the poking
timeout, being the misalignment the aftermath.
When you say flow controls, do you mean the ones handled by the UHD fw
functions? I see a couple of D's (packet drops) right before the
misalignment error, after the UHD raises the last poking exception. But
maybe this is just the natural behavior- to drop misaligned packets before
either getting an alignment or timing out and rising the exception.

"*Drop the sample rate (what is it, by the way?) and see if there's a
threshold where things start working [3]*":
Should I drop the samples below 1Msps/2Msps? I think these are pretty low
and having lower sampling rates would rise new problems. I can go ahead and
try it if you still thing this is the issue.
"*Keep the original sample rate and try removing a radio or two from the
system. Does this help things?*"*:*
- 4RX/1TX with simplistic flowgraph (usrp_source connected to file_sinks
and analog signal connected to usrp_sink): OK.
- 6RX/1TX with simplistic flowgraph (usrp_source connected to file_sinks
and analog signal connected to usrp_sink): NOK (error described previously).
- 3RX/1TX with my DSP blocks: OK.
- 4RX/1TX with my DSP blocks: NOK (error described previously).

Regarding an example, I could not find one that sets up a usrp_source AND a
usrp_sink, in the folder {gr_prefix}/gr-uhd/examples/. I created a
simplistic python flowgraph that results in the poking and misalignment
issue, attached in this email. For instance, the 6x1 connections would map
to the input argumments --tx_channels 1 --rx_channels 6.

Thanks a lot for your time and I hope to hear back from you soon.

Best,
Carlos


On Fri, Oct 18, 2019 at 1:05 PM Sam Reiter <sam.rei...@ettus.com> wrote:

> Carlos,
>
> On the host side if you're using a single streamer, it will work to
> time-align samples from every USRP as they come in. The reason you see 1002
> received packets without a timestamp match is because 1000 was the
> threshold for maximum number of alignment failures [1].  This can be
> changed or increased with [2]:
>
> set_alignment_failure_threshold(1000);
>
> But I doubt this will solve the issue for you. Likely just delay it. From the 
> errors you included, I'd say the real problem is:
>
>
>> *ERROR] [X300] 192.168.100.2 <http://192.168.100.2/>: x300 fw
>> communication failure #1EnvironmentError: IOError: x300 fw poke32 - reply
>> timed out*
>>
>
> There is either a backup or a lack of samples coming from the radio. Do
> you see flow control errors leading up to this failure?
>
> I'd say that pulling pieces out of this system would be a good way to
> start troubleshooting:
>
>    - Drop the sample rate (what is it, by the way?) and see if there's a
>    threshold where things start working [3]
>    - Keep the original sample rate and try removing a radio or two from
>    the system. Does this help things?
>
> It sounds like this is something you can reproduce independent of your DSP
> blocks, which helps simplify things a bit. If you could go a bit further
> and find a simple example (i.e. take one of the GNURadio UHD shipping
> examples and expand it to use 3x USRPs) and get it to reproduce the
> behavior, then I'd be happy to set something up on my end try to reproduce
> the behavior you're seeing.
>
> Sam
>
> [1]
> http://lists.ettus.com/pipermail/usrp-users_lists.ettus.com/2017-August/053986.html
> [2]
> http://lists.ettus.com/pipermail/usrp-users_lists.ettus.com/2014-January/036210.html
> [3]
> http://lists.ettus.com/pipermail/usrp-users_lists.ettus.com/2014-November/039561.html
>
>
> On Thu, Oct 17, 2019 at 3:46 PM Carlos Bocanegra via USRP-users <
> usrp-users@lists.ettus.com> wrote:
>
>> Hello community,
>>
>> I am working on a gnuradio application that synchronously retrieves data
>> from a usrp_source, does some DSP on each of the streams and selects the
>> signal to send on a usrp_sink based on some metric computation. The sources
>> and sinks represent 3 USRP X310 devices, each with 2 UBX-160
>> daughterboards, and are synchronized using an Octoclock-G. Thus, creating a
>> 6x1 MISO system. The USRP synchronization is done using the Python API, as
>> well as the flowgraph. The DSP blocks are coded in C++. The flowgraph would
>> be something like:
>>
>> *self.connect((usrp_source, 0), my_dsp_0, (my_switch, 0))*
>> *self.connect((usrp_source, 1), my_dsp_1, (my_switch, 1))*
>> *self.connect((usrp_source, 2), my_dsp_2, (my_switch, 2))*
>> *self.connect((usrp_source, 3), my_dsp_3, (my_switch, 3))*
>> *self.connect(my_switch, another_dsp_0, (usrp_sink, 0))*
>>
>> The application runs for a while until UHD outputs a message saying that
>> the poke32 has timed out on one of the USRP. After that, a misalignment
>> error on the receiver streams is shown and the green lights on the USRP go
>> off.
>>
>> We are under the impression that the DSP blocks working independently may
>> be requesting samples from the source at different times, causing the
>> misalignment. Could this be the case? Is there an issue with my network
>> connection?
>>
>> I have tried to get rid of the misalignment error by increasing the
>> threshold in the file
>> *{uhd_prefix}/host/lib/transport/super_recv_packet_handler.hpp, *through
>> the function *set_alignment_failure_threshold.* That got rid of the
>> misalignment error, but the failure coming from the poke function is still
>> there.
>>
>> Interestingly, the exact same behavior arises when I just connect
>> file_sinks to the outputs from the usrp_source and a simple analog signal
>> to the usrp_sink. Below the flowgraph:
>>
>> *self.connect((usrp_source, 0), file_sink_0)*
>> self.connect((usrp_source, 1), file_sink_1)
>> self.connect((usrp_source, 2), file_sink_2)
>> self.connect((usrp_source, 3), file_sink_3)
>> *self.connect(analog_sig_c, (usrp_sink, 0))*
>>
>> I'd appreciate any help on this since I'm running out of ideas here.
>> Please, find below more details.
>>
>> *The error:*
>>
>> * [ERROR] [X300] 192.168.100.2 <http://192.168.100.2>: x300 fw
>> communication failure #1EnvironmentError: IOError: x300 fw poke32 - reply
>> timed out*
>>
>> * [ERROR] [X300] 192.168.100.2 <http://192.168.100.2>: x300 fw
>> communication failure #1EnvironmentError: IOError: x300 fw poke32 - reply
>> timed out*
>>
>> * [ERROR] [X300] 192.168.100.2 <http://192.168.100.2>: x300 fw
>> communication failure #3EnvironmentError: IOError: x300 fw poke32 - reply
>> timed out*
>>  [ERROR] [UHD] An unexpected exception was caught in a task loop.The task
>> loop will now exit, things may not work.EnvironmentError: IOError:
>> 192.168.100.2: x300 fw communication failure #3
>>
>>
>>
>> * [ERROR] [STREAMER] The receive packet handler failed to time-align
>> packets.1002 received packets were processed by the handler.However, a
>> timestamp match could not be determined.*
>>
>> *Here are some details of my network configuration:*
>> - UHD built from source, tag v3.14.1.1.
>> - Gnuradio built from source, tag 3.7.13.5.
>> - X310 USRP, each equipped with two UBX-160 daughterboards.
>> - The communication is over Ethernet using the 1Gb port on the X310.
>> - Each USRP is connected to a dedicated NIC.
>> - The MTU is set to 1500 for the all interfaces.
>> - The USRPs are synchronized using an Octoclock-G and the parameters
>> tuned in the Python script. The procedure is similar to the one followed in
>> benchmark_rate (uhd), for the usrp_source and usrp_sink.
>> - The NIC ring buffers are set to the maximum for both TX and RX, to
>> 4096, using ethtool.
>> - The OS ring buffers are set as suggested bu Ettus, using the following
>> commands:
>>
>>
>>
>> *>> sudo sysctl -w net.core.rmem_max=33554432   >> sudo sysctl -w
>> net.core.wmem_max=33554432   >> sudo sysctl -w
>> net.core.rmem_default=33554432   >> sudo sysctl -w
>> net.core.wmem_default=33554432*
>>
>> Best,
>> Carlos
>> _______________________________________________
>> USRP-users mailing list
>> USRP-users@lists.ettus.com
>> http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com
>>
>
# Developed by: Carlos Bocanegra

from gnuradio import gr, uhd, blocks, analog
import time
import sys
import os
import optparse
from gnuradio.uhd.uhd_swig import time_spec_t
import signal



class reader_top_block(gr.top_block):
    
    def init_multi_usrp(self, options):
        self.sink = uhd.usrp_sink(
          device_addr=options.usrp_address_sink,
          stream_args=uhd.stream_args(
            cpu_format="fc32",
            channels=options.tx_channels,
            dboard_clock_rate=20e6,
            skip_dram=1,  # faster
            ignore_cal_file="",
        ),
        )
        self.source = uhd.usrp_source(
          device_addr=options.usrp_address_source,
          stream_args=uhd.stream_args(
            cpu_format="fc32",
            channels=options.rx_channels,
            dboard_clock_rate=20e6,
            skip_dram=1,  # faster
            ignore_cal_file="",
        ),
        )

    def setup_multi_usrp(self, options):
        # *** USEFUL PARAMS
        sink_n_Mboards = self.sink.get_num_mboards()
        source_n_Mboards = self.source.get_num_mboards()
        n_db_per_Mboard = 2;
        # *** EXTERNAL REF
        print "[UHD] Setting External Ref + PPS sources..."
        for mb_idx in range(source_n_Mboards):
            self.source.set_clock_source("external", mb_idx)  # Mboard=0 default
            self.source.set_time_source("external", mb_idx)  # Mboard=0 default
            if len(options.rx_channels)/((mb_idx+1)*n_db_per_Mboard)>=1:
                self.source.set_subdev_spec("A:0 B:0", mb_idx)  # Mboard=0 default
            else:
                self.source.set_subdev_spec("A:0", mb_idx)  # Mboard=0 default
        for mb_idx in range(sink_n_Mboards):
            self.sink.set_clock_source("external", mb_idx)  # Mboard=0 default
            self.sink.set_time_source("external", mb_idx)  # Mboard=0 default
            if len(options.tx_channels)/((mb_idx+1)*n_db_per_Mboard)>=1:
                self.sink.set_subdev_spec("A:0 B:0", mb_idx)  # Mboard=0 default
            else:
                self.sink.set_subdev_spec("A:0", mb_idx)  # Mboard=0 default
        # *** WAIT
        time.sleep(2.0)
        print "[UHD] Checking if the USRPs see the Reference signal..."
        for mb_idx in range(sink_n_Mboards):
            print "[UHD_TX] Mboard {0} locked: to external reference? {1}".format(mb_idx,self.sink.get_mboard_sensor("ref_locked", mb_idx).to_bool())
        for mb_idx in range(source_n_Mboards):
            print "[UHD_RX] Mboard {0} locked: to external reference? {1}".format(mb_idx,self.source.get_mboard_sensor("ref_locked", mb_idx).to_bool()) 
        # *** SYNCHRONIZING DEVICES
        print "[PPS] PPS set to unknown source (SMA connection)"
        self.sink.set_time_unknown_pps(uhd.time_spec())  # No Mboard spec
        self.source.set_time_unknown_pps(uhd.time_spec())  # No Mboard spec
        # *** WAIT 
        time.sleep(2.0)
        # *** SEE PPS SYNCHRONIZATION LEVEL
        curr_hw_time = self.sink.get_time_last_pps()
        while curr_hw_time==self.sink.get_time_last_pps():
            pass
        time.sleep(0.05)  # Sleep for 50ms
        print "[PPS] Re-set all PPS initial values to 0"
        self.sink.set_time_next_pps(uhd.time_spec_t(0.0))  # Need to put everything a zero for time alignment
        self.source.set_time_next_pps(uhd.time_spec_t(0.0))  # Need to put everything a zero for time alignment
        # *** WAIT 
        time.sleep(1.0)  # Sleep for 2s
        # *** SAMPLE RATE + ANTENNA CONFIG
        print "[UHD] Setting Sample Rate and Antenna configuration..."
        self.sink.set_samp_rate(options.dac_rate)  # No Mboard spec
        self.source.set_samp_rate(options.adc_rate)  # No Mboard spec
        for db_idx in options.tx_channels:
            self.sink.set_gain(options.tx_gain, db_idx)  # Dboard=0 default
            self.sink.set_antenna("TX/RX", db_idx)  # Dboard=0 default
            print "[UHD_TX] Channel {0}: Using antenna TX/RX, Gain {1}".format(db_idx,options.rx_gain)
        for db_idx in options.rx_channels:
            self.source.set_gain(options.rx_gain, db_idx)  # Dboard=0 default
            self.source.set_antenna("RX2", db_idx)  # Dboard=0 default
            self.source.set_auto_dc_offset(False, db_idx)  # Dboard - Uncomment this line for SBX daughterboard
            print "[UHD_RX] Channel {0}: Using antenna RX2, Gain {1}, DC-offset {2}".format(db_idx,options.rx_gain,False)
        # *** WAIT
        time.sleep(1.0)
        # *** GET TIMES
        now_sink          = self.source.get_time_now()
        cmd_time_sink     = now_sink + uhd.time_spec(0.2)  # after 200ms
        cmd_time_source   = now_sink + uhd.time_spec(0.2)  # after 200ms
        # *** SET COMMAND TIME
        try:
            for mb_idx in range(source_n_Mboards):
                self.source.set_command_time(cmd_time_sink, mb_idx)
            for mb_idx in range(sink_n_Mboards):
                self.sink.set_command_time(cmd_time_source, mb_idx)
        except RuntimeError:
            sys.stderr.write('[UHD] [WARNING] Failed to set command times on USRPs.\n')
        # *** SET CENTER FREQUENCIES
        print "[UHD_FREQ] Creating tune request"
        treq = uhd.tune_request(options.freq)
        for db_idx in options.tx_channels:
            res_sink = self.sink.set_center_freq(treq, db_idx)  # Dboard=0 default
        for db_idx in options.rx_channels:
            res_source = self.source.set_center_freq(treq, db_idx)  # Dboard=0 default
        while not self.sink.get_sensor("lo_locked").to_bool():
            print "waiting"
            pass
        while not self.source.get_sensor("lo_locked").to_bool():
            print "waiting"
            pass
        # *** WAIT
        time.sleep(2.0)  # after 1s, give time to the hardware to set the tuning freq
        # *** CLEAR COMMAND TIMES
        for mb_idx in range(sink_n_Mboards):
            self.sink.clear_command_time(mb_idx)
        for mb_idx in range(source_n_Mboards):
            self.source.clear_command_time(mb_idx)


    def __init__(self):
        gr.top_block.__init__(self)
        rt = gr.enable_realtime_scheduling()
        
        ##################################################
        # Variables
        ##################################################
        options.dac_rate = 1e6  # DAC rate
        options.adc_rate = 2e6  # ADC rate
        options.tx_channels = range(TXCHANNELS)
        options.rx_channels = range(RXCHANNELS)
        options.ampl = 0.5
        options.tx_gain = 20
        options.rx_gain = 20
        options.freq = 910e6

        ##################################################
        # Blocks 
        ##################################################
        self.file_sink_source = ["" for x in options.rx_channels]
        self.null_sink_c = ["" for x in options.rx_channels]
        self.null_sink_f = ["" for x in options.rx_channels]
        fileNameRoot = "/tmp/source"
        for i in options.rx_channels:
            fileName = fileNameRoot + str(i)
            self.file_sink_source[i] = blocks.file_sink(gr.sizeof_gr_complex * 1, fileName, False)
            self.null_sink_c[i] = blocks.null_sink(gr.sizeof_gr_complex * 1)
            self.null_sink_f[i] = blocks.null_sink(gr.sizeof_float * 1)
        self.an_sig_source = analog.sig_source_f(options.dac_rate, analog.GR_SIN_WAVE, 350e3, 1, 0)
        self.to_complex = blocks.float_to_complex()

        ##################################################
        # USRP SETUP (SINKS AND SOURCES)
        ##################################################
        if len(options.rx_channels)<=2:
            options.usrp_address_source = "addr0=192.168.60.2,recv_frame_size=1472, send_frame_size=1472"  # one USRP
            options.usrp_address_sink   = "addr=192.168.60.2,recv_frame_size=1472, send_frame_size=1472"  # one USRP
        elif len(options.rx_channels)<=4:
            options.usrp_address_source = "addr0=192.168.60.2, addr1=192.168.50.2,recv_frame_size=1472"
            options.usrp_address_sink   = "addr0=192.168.60.2, addr1=192.168.50.2,send_frame_size=1472"
        elif len(options.rx_channels)<=6:
            options.usrp_address_source = "addr0=192.168.60.2,addr1=192.168.50.2,addr2=192.168.100.2,recv_frame_size=1472"
            options.usrp_address_sink   = "addr0=192.168.60.2,addr1=192.168.50.2,addr2=192.168.100.2,send_frame_size=1472"

        ######## SOURCES and SINKS #########
        self.init_multi_usrp(options)
        self.setup_multi_usrp(options)

        ##################################################
        # Connections
        ##################################################
        for i in options.rx_channels:
#                 self.connect((self.source, i),               self.null_sink_c[i])  # (Do not comment this line)
            self.connect((self.source, i),               self.file_sink_source[i])  # passive mode - store samples
        self.connect(self.an_sig_source, self.to_complex)
        for j in options.tx_channels:
            self.connect(self.to_complex, (self.sink, j))
                    


if __name__ == '__main__':
    
    def signal_handler(sig, frame):
        print('Signal captured, ending execution')

    parser = optparse.OptionParser()    
    parser.add_option('-x', '--tx_channels', type="int", dest="TXCHANNELS", help="Specify the number of Tx channels", default=1)
    parser.add_option('-y', '--rx_channels', type="int", dest="RXCHANNELS", help="Specify the number of Rx channels", default=1)

    options, args = parser.parse_args()

    TXCHANNELS = options.TXCHANNELS
    RXCHANNELS = options.RXCHANNELS

    print('Initializing Flowgraph. Press Ctrl+C to stop the Execution')
    print('')
    main_block = reader_top_block()
    print "Starting flow..."
    print('')
    main_block.start()
            
    signal.signal(signal.SIGINT, signal_handler)
    signal.pause()

    main_block.stop()
_______________________________________________
USRP-users mailing list
USRP-users@lists.ettus.com
http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com

Reply via email to