node_info_retriever.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #if __GNUC__
6 # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
7 #endif
8 
9 #include <memory>
10 #include <gtest/gtest.h>
13 #include "helpers.hpp"
14 
16  uavcan::uint32_t uptime_sec, uavcan::TransferID tid)
17 {
18  uavcan::protocol::NodeStatus msg;
19  msg.health = uavcan::protocol::NodeStatus::HEALTH_OK;
20  msg.mode = uavcan::protocol::NodeStatus::MODE_OPERATIONAL;
21  msg.uptime_sec = uptime_sec;
22  emulateSingleFrameBroadcastTransfer(can, node_id, msg, tid);
23 }
24 
25 
27 {
28  std::unique_ptr<uavcan::protocol::GetNodeInfo::Response> last_node_info;
33 
35  : status_message_cnt(0)
36  , status_change_cnt(0)
37  , info_unavailable_cnt(0)
38  { }
39 
41  const uavcan::protocol::GetNodeInfo::Response& node_info)
42  {
43  last_node_id = node_id;
44  std::cout << node_info << std::endl;
45  last_node_info.reset(new uavcan::protocol::GetNodeInfo::Response(node_info));
46  }
47 
49  {
50  std::cout << "NODE INFO FOR " << int(node_id.get()) << " IS UNAVAILABLE" << std::endl;
51  last_node_id = node_id;
52  info_unavailable_cnt++;
53  }
54 
56  {
57  std::cout << "NODE " << int(event.node_id.get()) << " STATUS CHANGE: "
58  << event.old_status.toString() << " --> " << event.status.toString() << std::endl;
59  status_change_cnt++;
60  }
61 
63  {
64  std::cout << msg << std::endl;
65  status_message_cnt++;
66  }
67 };
68 
69 
70 TEST(NodeInfoRetriever, Basic)
71 {
75 
77 
78  uavcan::NodeInfoRetriever retr(nodes.a);
79  std::cout << "sizeof(uavcan::NodeInfoRetriever): " << sizeof(uavcan::NodeInfoRetriever) << std::endl;
80  std::cout << "sizeof(uavcan::ServiceClient<uavcan::protocol::GetNodeInfo>): "
82 
83  std::unique_ptr<uavcan::NodeStatusProvider> provider(new uavcan::NodeStatusProvider(nodes.b));
84 
85  NodeInfoListener listener;
86 
87  /*
88  * Initialization
89  */
90  ASSERT_LE(0, retr.start());
91 
92  retr.removeListener(&listener); // Does nothing
93  retr.addListener(&listener);
94  retr.addListener(&listener);
95  retr.addListener(&listener);
96  ASSERT_EQ(1, retr.getNumListeners());
97 
98  uavcan::protocol::HardwareVersion hwver;
99  hwver.unique_id[0] = 123;
100  hwver.unique_id[4] = 213;
101  hwver.unique_id[8] = 45;
102 
103  provider->setName("Ivan");
104  provider->setHardwareVersion(hwver);
105 
106  ASSERT_LE(0, provider->startAndPublish());
107 
108  ASSERT_FALSE(retr.isRetrievingInProgress());
109  ASSERT_EQ(0, retr.getNumPendingRequests());
110 
111  EXPECT_EQ(40, retr.getRequestInterval().toMSec()); // Default
112 
113  /*
114  * Waiting for discovery
115  */
117  ASSERT_TRUE(retr.isRetrievingInProgress());
119  ASSERT_FALSE(retr.isRetrievingInProgress());
120 
121  ASSERT_EQ(2, listener.status_message_cnt);
122  ASSERT_EQ(1, listener.status_change_cnt);
123  ASSERT_EQ(0, listener.info_unavailable_cnt);
124  ASSERT_TRUE(listener.last_node_info.get());
125  ASSERT_EQ(uavcan::NodeID(2), listener.last_node_id);
126  ASSERT_EQ("Ivan", listener.last_node_info->name);
127  ASSERT_TRUE(hwver == listener.last_node_info->hardware_version);
128 
129  provider.reset(); // Moving the provider out of the way; its entry will timeout meanwhile
130 
131  /*
132  * Declaring a bunch of different nodes that don't support GetNodeInfo
133  */
134  ASSERT_FALSE(retr.isRetrievingInProgress());
135 
136  retr.setNumRequestAttempts(3);
137 
138  uavcan::TransferID tid;
139 
140  publishNodeStatus(nodes.can_a, uavcan::NodeID(10), 10, tid);
141  publishNodeStatus(nodes.can_a, uavcan::NodeID(11), 10, tid);
142  publishNodeStatus(nodes.can_a, uavcan::NodeID(12), 10, tid);
143 
145  ASSERT_LE(1, retr.getNumPendingRequests());
147  ASSERT_LE(2, retr.getNumPendingRequests());
149  ASSERT_EQ(3, retr.getNumPendingRequests());
151  ASSERT_TRUE(retr.isRetrievingInProgress());
152 
153  tid.increment();
154  publishNodeStatus(nodes.can_a, uavcan::NodeID(10), 11, tid);
155  publishNodeStatus(nodes.can_a, uavcan::NodeID(11), 11, tid);
156  publishNodeStatus(nodes.can_a, uavcan::NodeID(12), 11, tid);
157 
159  ASSERT_LE(1, retr.getNumPendingRequests());
161  ASSERT_LE(2, retr.getNumPendingRequests());
163  ASSERT_EQ(3, retr.getNumPendingRequests());
165  ASSERT_TRUE(retr.isRetrievingInProgress());
166 
167  tid.increment();
168  publishNodeStatus(nodes.can_a, uavcan::NodeID(10), 12, tid);
169  publishNodeStatus(nodes.can_a, uavcan::NodeID(11), 12, tid);
170  publishNodeStatus(nodes.can_a, uavcan::NodeID(12), 10, tid); // Reset
171 
173  ASSERT_LE(1, retr.getNumPendingRequests());
175  ASSERT_LE(2, retr.getNumPendingRequests());
177  ASSERT_EQ(3, retr.getNumPendingRequests());
179  ASSERT_TRUE(retr.isRetrievingInProgress());
180 
181  EXPECT_EQ(11, listener.status_message_cnt);
182  EXPECT_EQ(5, listener.status_change_cnt); // node 2 online/offline + 3 test nodes above
183  EXPECT_EQ(2, listener.info_unavailable_cnt);
184 
185  tid.increment();
186  publishNodeStatus(nodes.can_a, uavcan::NodeID(12), 11, tid);
187 
189  ASSERT_EQ(1, retr.getNumPendingRequests());
191  ASSERT_EQ(1, retr.getNumPendingRequests()); // Still one because two went offline
193  ASSERT_TRUE(retr.isRetrievingInProgress());
194 
195  tid.increment();
196  publishNodeStatus(nodes.can_a, uavcan::NodeID(12), 12, tid);
197 
199  ASSERT_FALSE(retr.isRetrievingInProgress()); // Out of attempts, stopping
200  ASSERT_EQ(0, retr.getNumPendingRequests());
201 
202  EXPECT_EQ(13, listener.status_message_cnt);
203  EXPECT_EQ(7, listener.status_change_cnt); // node 2 online/offline + 2 test nodes above online/offline + 1
204  EXPECT_EQ(3, listener.info_unavailable_cnt);
205 
206  /*
207  * Forcing the class to forget everything
208  */
209  std::cout << "Invalidation" << std::endl;
210 
211  retr.invalidateAll();
212 
213  ASSERT_FALSE(retr.isRetrievingInProgress());
214  ASSERT_EQ(0, retr.getNumPendingRequests());
215 
216  tid.increment();
217  publishNodeStatus(nodes.can_a, uavcan::NodeID(10), 60, tid);
218  publishNodeStatus(nodes.can_a, uavcan::NodeID(11), 60, tid);
219  publishNodeStatus(nodes.can_a, uavcan::NodeID(12), 60, tid);
220 
222 
223  ASSERT_TRUE(retr.isRetrievingInProgress());
224  ASSERT_EQ(3, retr.getNumPendingRequests());
225 }
226 
227 
228 TEST(NodeInfoRetriever, MaxConcurrentRequests)
229 {
233 
235 
236  uavcan::NodeInfoRetriever retr(nodes.a);
237  std::cout << "sizeof(uavcan::NodeInfoRetriever): " << sizeof(uavcan::NodeInfoRetriever) << std::endl;
238  std::cout << "sizeof(uavcan::ServiceClient<uavcan::protocol::GetNodeInfo>): "
240 
241  NodeInfoListener listener;
242 
243  /*
244  * Initialization
245  */
246  ASSERT_LE(0, retr.start());
247 
248  retr.addListener(&listener);
249  ASSERT_EQ(1, retr.getNumListeners());
250 
251  ASSERT_FALSE(retr.isRetrievingInProgress());
252  ASSERT_EQ(0, retr.getNumPendingRequests());
253 
254  ASSERT_EQ(40, retr.getRequestInterval().toMSec());
255 
256  const unsigned MaxPendingRequests = 26; // See class docs
257  const unsigned MinPendingRequestsAtFullLoad = 12;
258 
259  /*
260  * Sending a lot of requests, making sure that the number of concurrent calls does not exceed the specified limit.
261  */
262  for (uint8_t node_id = 1U; node_id <= 127U; node_id++)
263  {
264  publishNodeStatus(nodes.can_a, node_id, 0, uavcan::TransferID());
266  ASSERT_GE(MaxPendingRequests, retr.getNumPendingRequests());
267  ASSERT_TRUE(retr.isRetrievingInProgress());
268  }
269 
270  ASSERT_GE(MaxPendingRequests, retr.getNumPendingRequests());
271  ASSERT_LE(MinPendingRequestsAtFullLoad, retr.getNumPendingRequests());
272 
273  for (int i = 0; i < 8; i++) // Approximate
274  {
276  std::cout << "!!! SPIN " << i << " COMPLETE" << std::endl;
277 
278  ASSERT_GE(MaxPendingRequests, retr.getNumPendingRequests());
279  ASSERT_LE(MinPendingRequestsAtFullLoad, retr.getNumPendingRequests());
280 
281  ASSERT_TRUE(retr.isRetrievingInProgress());
282  }
283 
284  ASSERT_LT(0, retr.getNumPendingRequests());
285  ASSERT_TRUE(retr.isRetrievingInProgress());
286 
288 
289  ASSERT_EQ(0, retr.getNumPendingRequests());
290  ASSERT_FALSE(retr.isRetrievingInProgress());
291 }
std::uint8_t uint8_t
Definition: std.hpp:24
int addListener(INodeInfoListener *listener)
MonotonicDuration getRequestInterval() const
std::unique_ptr< uavcan::protocol::GetNodeInfo::Response > last_node_info
virtual void handleNodeInfoUnavailable(uavcan::NodeID node_id)
virtual void handleNodeInfoRetrieved(uavcan::NodeID node_id, const uavcan::protocol::GetNodeInfo::Response &node_info)
uint8_t get() const
Definition: transfer.hpp:132
int64_t toMSec() const
Definition: time.hpp:44
void removeListener(INodeInfoListener *listener)
PairableCanDriver can_a
Definition: test_node.hpp:153
std::uint32_t uint32_t
Definition: std.hpp:26
static void publishNodeStatus(PairableCanDriver &can, uavcan::NodeID node_id, uavcan::uint32_t uptime_sec, uavcan::TransferID tid)
int start(const TransferPriority priority=TransferPriority::OneHigherThanLowest)
static void emulateSingleFrameBroadcastTransfer(CanDriver &can, uavcan::NodeID node_id, const MessageType &message, uavcan::TransferID tid)
static GlobalDataTypeRegistry & instance()
void setNumRequestAttempts(const uint8_t num)
virtual void handleNodeStatusMessage(const uavcan::ReceivedDataStructure< uavcan::protocol::NodeStatus > &msg)
static MonotonicDuration fromMSec(int64_t ms)
Definition: time.hpp:41
int spinBoth(uavcan::MonotonicDuration duration)
Definition: test_node.hpp:176
TEST(NodeInfoRetriever, Basic)
uavcan::NodeID last_node_id
virtual void handleNodeStatusChange(const uavcan::NodeStatusMonitor::NodeStatusChangeEvent &event)
int
Definition: libstubs.cpp:120


uavcan_communicator
Author(s):
autogenerated on Wed Jan 11 2023 03:59:39