1 //
2 // Copyright 2019 Ettus Research, a National Instruments Brand
3 //
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 //
6 
7 #include "x300_claim.hpp"
8 #include "x300_fw_common.h"
9 #include <uhd/utils/platform.hpp>
10 #include <chrono>
11 #include <thread>
12 
13 using namespace uhd;
14 using namespace uhd::usrp::x300;
15 
16 /***********************************************************************
17  * claimer logic
18  **********************************************************************/
19 
claimer_loop(wb_iface::sptr iface)20 void uhd::usrp::x300::claimer_loop(wb_iface::sptr iface)
21 {
22     claim(iface);
23     std::this_thread::sleep_for(std::chrono::seconds(1));
24 }
25 
claim_status(wb_iface::sptr iface)26 claim_status_t uhd::usrp::x300::claim_status(wb_iface::sptr iface)
27 {
28     claim_status_t claim_status = CLAIMED_BY_OTHER; // Default to most restrictive
29     auto timeout_time = std::chrono::steady_clock::now() + std::chrono::seconds(1);
30     while (std::chrono::steady_clock::now() < timeout_time) {
31         // If timed out, then device is definitely unclaimed
32         if (iface->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_STATUS)) == 0) {
33             claim_status = UNCLAIMED;
34             break;
35         }
36 
37         // otherwise check claim src to determine if another thread with the same src has
38         // claimed the device
39         uint32_t hash = iface->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_SRC));
40         if (hash == 0) {
41             // A non-zero claim status and an empty hash means the claim might
42             // be in the process of being released.  This is possible because
43             // older firmware takes a long time to update the status.  Wait and
44             // check status again.
45             std::this_thread::sleep_for(std::chrono::milliseconds(5));
46             continue;
47         }
48         claim_status = (hash == get_process_hash() ? CLAIMED_BY_US : CLAIMED_BY_OTHER);
49         break;
50     }
51     return claim_status;
52 }
53 
claim(wb_iface::sptr iface)54 void uhd::usrp::x300::claim(wb_iface::sptr iface)
55 {
56     iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_TIME), uint32_t(time(NULL)));
57     iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_SRC), get_process_hash());
58 }
59 
try_to_claim(wb_iface::sptr iface,long timeout_ms)60 bool uhd::usrp::x300::try_to_claim(wb_iface::sptr iface, long timeout_ms)
61 {
62     const auto timeout_time =
63         std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
64     while (1) {
65         claim_status_t status = claim_status(iface);
66         if (status == UNCLAIMED) {
67             claim(iface);
68             // It takes the claimer 10ms to update status, so wait 20ms before verifying
69             // claim
70             std::this_thread::sleep_for(std::chrono::milliseconds(20));
71             continue;
72         }
73         if (status == CLAIMED_BY_US) {
74             break;
75         }
76         if (std::chrono::steady_clock::now() > timeout_time) {
77             // Another process owns the device - give up
78             return false;
79         }
80         std::this_thread::sleep_for(std::chrono::milliseconds(100));
81     }
82     return true;
83 }
84 
release(wb_iface::sptr iface)85 void uhd::usrp::x300::release(wb_iface::sptr iface)
86 {
87     iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_TIME), 0);
88     iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_SRC), 0);
89 }
90