diff options
| author | Martin Braun <martin.braun@ettus.com> | 2017-06-12 16:04:33 -0700 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2017-12-22 15:04:00 -0800 | 
| commit | c2bd35ef11076a7a75f028d9c329c721312d20fc (patch) | |
| tree | 49d06c585394199ae9bf9d8cbc5533fe0f277481 /host | |
| parent | 8e1dec25f21046ede7fffd65c6e8c82055141607 (diff) | |
| download | uhd-c2bd35ef11076a7a75f028d9c329c721312d20fc.tar.gz uhd-c2bd35ef11076a7a75f028d9c329c721312d20fc.tar.bz2 uhd-c2bd35ef11076a7a75f028d9c329c721312d20fc.zip | |
mpmd: Added time_sync procedure
Diffstat (limited to 'host')
| -rw-r--r-- | host/lib/usrp/mpmd/mpmd_impl.cpp | 76 | 
1 files changed, 73 insertions, 3 deletions
| diff --git a/host/lib/usrp/mpmd/mpmd_impl.cpp b/host/lib/usrp/mpmd/mpmd_impl.cpp index ec48138a6..c8c860c00 100644 --- a/host/lib/usrp/mpmd/mpmd_impl.cpp +++ b/host/lib/usrp/mpmd/mpmd_impl.cpp @@ -44,6 +44,8 @@ namespace {      const size_t MPMD_CROSSBAR_MAX_LADDR = 255;      //! How long we wait for discovery responses (in seconds)      const double MPMD_FIND_TIMEOUT = 0.5; +    //! Most pessimistic time for a CHDR query to go to device and back +    const double MPMD_CHDR_MAX_RTT = 0.02;      /*************************************************************************       * Helper functions @@ -112,6 +114,61 @@ namespace {              })          ;      } + +    void reset_time_synchronized(uhd::property_tree::sptr tree) +    { +        const size_t n_mboards = tree->list("/mboards").size(); +        UHD_LOGGER_DEBUG("MPMD") +            << "Synchronizing " << n_mboards <<" timekeepers..."; +        auto get_time_last_pps = [tree](){ +            return tree->access<time_spec_t>( +                fs_path("/mboards/0/time/pps") +            ).get(); +        }; +        auto end_time = std::chrono::steady_clock::now() +                            + std::chrono::milliseconds(1100); +        auto time_last_pps = get_time_last_pps(); +        UHD_LOG_DEBUG("MPMD", "Waiting for PPS clock edge..."); +        while (time_last_pps == get_time_last_pps()) +        { +            if (std::chrono::steady_clock::now() > end_time) { +                throw uhd::runtime_error( +                    "Board 0 may not be getting a PPS signal!\n" +                    "No PPS detected within the time interval.\n" +                    "See the application notes for your device.\n" +                ); +            } +            std::this_thread::sleep_for(std::chrono::milliseconds(10)); +        } +        UHD_LOG_DEBUG("MPMD", "Setting all timekeepers to 0..."); +        for (size_t mboard_idx = 0; mboard_idx < n_mboards; mboard_idx++) { +            tree->access<time_spec_t>( +                fs_path("/mboards") / mboard_idx / "time" / "pps" +            ).set(time_spec_t(0.0)); +        } + +        UHD_LOG_DEBUG("MPMD", "Waiting for next PPS edge..."); +        std::this_thread::sleep_for(std::chrono::seconds(1)); + +        UHD_LOG_DEBUG("MPMD", "Verifying all timekeepers are aligned..."); +        auto get_time_now = [tree](const size_t mb_index){ +            return tree->access<time_spec_t>( +                fs_path("/mboards") / mb_index / "time/now" +            ).get(); +        }; +        for (size_t m = 1; m < n_mboards; m++){ +            time_spec_t time_0 = get_time_now(0); +            time_spec_t time_i = get_time_now(m); +            if (time_i < time_0 +                    or (time_i - time_0) > time_spec_t(MPMD_CHDR_MAX_RTT)) { +                UHD_LOGGER_WARNING("MULTI_USRP") << boost::format( +                    "Detected time deviation between board %d and board 0.\n" +                    "Board 0 time is %f seconds.\n" +                    "Board %d time is %f seconds.\n" +                ) % m % time_0.get_real_secs() % m % time_i.get_real_secs(); +            } +        } +    }  }  /***************************************************************************** @@ -144,17 +201,30 @@ mpmd_impl::mpmd_impl(const device_addr_t& device_args)          _mb.push_back(setup_mb(mb_i, mb_args[mb_i]));      } -    //! This might be parallelized. std::tasks would probably be a good way to +    // Init the prop tree before the blocks get set up -- they might need access +    // to some of the properties. This also means that the prop tree is pristine +    // at this point in time. +    for (size_t mb_i = 0; mb_i < mb_args.size(); ++mb_i) { +        init_property_tree(_tree, fs_path("/mboards") / mb_i, _mb[mb_i].get()); +    } + +    // This might be parallelized. std::tasks would probably be a good way to      // do that if we want to.      for (size_t mb_i = 0; mb_i < mb_args.size(); ++mb_i) {          setup_rfnoc_blocks(mb_i, mb_args[mb_i]);      } -    for (size_t mb_i = 0; mb_i < mb_args.size(); ++mb_i) { -        init_property_tree(_tree, fs_path("/mboards") / mb_i, _mb[mb_i].get()); +    // FIXME this section only makes sense for when the time source is external. +    // So, check for that, or something similar. +    // This section of code assumes that the prop tree is set and we have access +    // to the timekeepers. So don't move it anywhere else. +    if (device_args.has_key("sync_time")) { +        reset_time_synchronized(_tree);      }      auto filtered_block_args = device_args; // TODO actually filter +    // Blocks will finalize their own setup in this function. They have (and +    // might need) full access to the prop tree, the timekeepers, etc.      setup_rpc_blocks(filtered_block_args);  } | 
