How-to: Get and Set Paths in UHD and the State Tree

This how-to guide explains how to get and set arbitrary paths in UHD; these are the values that are written to the state tree of the server in your SDR unit for a particular parameter (i.e. gain, IQ balance, FPGA version, etc.). Here we discuss how you would accomplish get or set paths if you want to manually configure these paths from the command line or if you are writing your own UHD program.


IMPORTANT!! It is not recommended that the user directly access the state tree in our SDR devices; this how-to guide should be used with caution.

1. Manually Using the Command Line for Get/Set Paths in UHD of the state tree

  1. Figure out what property in the state tree in the unit you want to change.

  2. Go to the C++ implementation file on your SDR device. For Crimson TNG, this crimson_tng_impl.cpp. On Cyan, this would be the one corresponding to your unit (for example, cyan_4r4t_impl.cpp is a 4R4T 1GSPS SDR unit). For Crimson TNG, this would be located in the following directory on the host system:

    $ uhd/host/lib/usrp/crimson_tng/crimson_tng_impl.cpp
  3. Step 3 is to find the UHD macro that corresponds to the state tree path in the crimson_tng_impl.cpp file or the one corresponding to Cyan. To figure out which UHD path corresponds to the state tree path you want to access, look in the implementation file for instances of the macro TREE_CREATE_ST and TREE_CREATE_RW. The first argument in the macro is the path used within UHD programs, and the second argument is the path it corresponds to on the server. The third and fourth arguments are the datatypes.

    For example, the following line of code:

    TREE_CREATE_RW(mb_path / "clock_source" / "value",      "time/source/ref",  std::string, string);

    is the macro that will create a state tree path. Once again, in this macro, the first argument is the UHD path, the second is the path in the server, and the third and fourth argument are the data types.

  4. To get the value of the state tree, you need to use the following command (you can find out the arguments with the –help flag):

    $ uhd_manual_get

    For example, the following command would get the current state tree value for DSP gain:

    $ uhd_manual_get --path /mboards/0/rx_codecs/A/gains --type int


    The valid data types are string, int and double in the above argument.


    For finding the “–path” argument in the above and below command, you need to go into the crimson_tng_impl.cpp file and locate the TREE_CREATE_RW or TREE_CREATE_ST that create the path binding in the state tree. Then, you will need to find in this file the variables associated with the UHD path argument of the TREE_CREATE_RW or TREE_CREATE_ST, and plug these into the “–path” argument of the uhd_manual_set/get command.

  5. To manually set paths in the state tree, you need to use following command (you can find out the arguments with the –help flag):

    $ uhd_manual_set 

    For instance, to change the DSP gain value in the state tree, use the following command:

    $ uhd_manual_set --path /mboards/0/rx_codecs/A/gains --type int --value 15

2. Get/Set In a UHD Program

  1. Same as Step 1 above.

  2. Same as Step 2 above.

  3. Same as Step 3 above.

  4. If you’re trying to write a program, you will need to include the get/set functions. This is included when you initialize the device; already done in most UHD programs. The code to initialize the usrp device is:

    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(std::string(""));
  5. Step 5 is to use the USRP device created in Step 4 to call the get_tree_value and set_tree_value functions. The code looks like this:

    //gets the old value from the state tree
    std::string old_value;
    usrp->get_tree_value(path, old_value);
    std::cout << "Old value: " << old_value << std::endl;
    std::string = "some path";
    std::string = "some value";
    usrp->set_tree_value(path, value);
    std::cout << "Set to: " << value << std::endl;
    std::string new_value;
    usrp->get_tree_value(path, new_value);
    std::cout << "The value is now: " << new_value << std::endl;
  6. The first argument in the get_tree_value(path,old_value) and set_tree_value(path, new_value) functions is the UHD path you figured out in Step 3 (not the path of the server, i.e. it’s the first argument, not the second). In the case of get_tree_value, the second argument is the current value of the state tree written to that variable, and in the case of set_tree_value, it is the value you are trying to set the state tree to.


IMPORTANT: It is essential that the argument in that tree (the data type), is the same data type as the variable you’re trying to pass to the set/get_tree_value. If you do not adhere to the datatype, this will write a garbage value, and not immediately throw out an error.

3. Persistent Change to the State Tree Default Value

The values in the state tree are set to their default values everytime the SDR boots up, or is updated. The default value may be changed from the Per Vices settings to suit your application, so that the above sets using UHD are not required. This is often useful when operating multiple SDRs with different settings, and as an example may used to change the IP address of the SFP+ on Crimson or QSFP+ on Cyan. (Also relevant to using multiple SDRs is setting a custom IP address for the MGMT port.) Note that UHD programs may change the value in the state tree after the SDR boots up with a custom default value.

  1. Any changes to the default state tree values different than the Per Vices settings are stored on the SDR in the file /etc/crimson/alternate_tree_defaults.cfg for crimson or /etc/cyan/alternate_tree_defaults.cfg for cyan.
  2. To create or edit this file ssh into the SDR, and use sudo -i to gain root permissions.
  3. The format for the configuration file is to have a line for each property for which a default value is being set. One each line the state tree path is written, then =, then the default value. For example to change the SFP+ IP addresses on crimson from and to and the file /etc/crimson/alternate_tree_defaults.cfg would contain:
    fpga/link/sfpa/ip_addr =
    fpga/link/sfpb/ip_addr =
  4. This could be created using a text editor such as vim or using the echo command. As an example echo "fpga/link/sfpa/ip_addr =" > /etc/crimson/alternate_tree_defaults.cfg would create the first line shown in the example above and erase all other lines that already exist in the configuration file. An echo command with >> such as echo "fpga/link/sfpb/ip_addr =" >> /etc/crimson/alternate_tree_defaults.cfg could then be used to add the second line to the configuration file, without erasing all the existing lines in the file.