uavcan_nodetool.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #include <iostream>
6 #include <iomanip>
7 #include <thread>
8 #include <mutex>
9 #include <map>
10 #include <algorithm>
11 #include <iterator>
14 #include "debug.hpp"
15 
16 #include <uavcan/protocol/param/GetSet.hpp>
17 #include <uavcan/protocol/param/ExecuteOpcode.hpp>
18 #include <uavcan/equipment/hardpoint/Command.hpp>
19 
20 namespace
21 {
22 
23 class StdinLineReader
24 {
25  mutable std::mutex mutex_;
26  std::thread thread_;
27  std::queue<std::string> queue_;
28 
29  void worker()
30  {
31  while (true)
32  {
33  std::string input;
34  std::getline(std::cin, input);
35  std::lock_guard<std::mutex> lock(mutex_);
36  queue_.push(input);
37  }
38  }
39 
40 public:
41  StdinLineReader()
42  : thread_(&StdinLineReader::worker, this)
43  {
44  thread_.detach();
45  }
46 
47  bool hasPendingInput() const
48  {
49  std::lock_guard<std::mutex> lock(mutex_);
50  return !queue_.empty();
51  }
52 
53  std::string getLine()
54  {
55  std::lock_guard<std::mutex> lock(mutex_);
56  if (queue_.empty())
57  {
58  throw std::runtime_error("Input queue is empty");
59  }
60  auto ret = queue_.front();
61  queue_.pop();
62  return ret;
63  }
64 
65  std::vector<std::string> getSplitLine()
66  {
67  std::istringstream iss(getLine());
68  std::vector<std::string> out;
69  std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(),
70  std::back_inserter(out));
71  return out;
72  }
73 };
74 
75 uavcan_linux::NodePtr initNode(const std::vector<std::string>& ifaces, uavcan::NodeID nid, const std::string& name)
76 {
77  auto node = uavcan_linux::makeNode(ifaces, name.c_str(),
78  uavcan::protocol::SoftwareVersion(), uavcan::protocol::HardwareVersion(),
79  nid);
80  node->setModeOperational();
81  return node;
82 }
83 
84 template <typename DataType>
85 typename DataType::Response call(uavcan_linux::BlockingServiceClient<DataType>& client,
86  uavcan::NodeID server_node_id, const typename DataType::Request& request)
87 {
88  const int res = client.blockingCall(server_node_id, request, uavcan::MonotonicDuration::fromMSec(100));
89  ENFORCE(res >= 0);
90  ENFORCE(client.wasSuccessful());
91  return client.getResponse();
92 }
93 
94 /*
95  * Command table.
96  * The structure is:
97  * command_name : (command_usage_info, command_entry_point)
98  * This code was written while listening to some bad dubstep so I'm not sure about its quality.
99  */
100 const std::map<std::string,
101  std::pair<std::string,
102  std::function<void(const uavcan_linux::NodePtr&, const uavcan::NodeID,
103  const std::vector<std::string>&)>
104  >
105  > commands =
106 {
107  {
108  "param",
109  {
110  "No arguments supplied - requests all params from a remote node\n"
111  "<param_name> <param_value> - assigns parameter <param_name> to value <param_value>",
112  [](const uavcan_linux::NodePtr& node, const uavcan::NodeID node_id, const std::vector<std::string>& args)
113  {
114  auto client = node->makeBlockingServiceClient<uavcan::protocol::param::GetSet>();
115  uavcan::protocol::param::GetSet::Request request;
116  if (args.empty())
117  {
118  while (true)
119  {
120  auto response = call(*client, node_id, request);
121  if (response.name.empty())
122  {
123  break;
124  }
125  std::cout
126  << response
127  << "\n" << std::string(80, '-')
128  << std::endl;
129  request.index++;
130  }
131  }
132  else
133  {
134  request.name = args.at(0).c_str();
135  // TODO: add support for string parameters
136  request.value.to<uavcan::protocol::param::Value::Tag::real_value>() = std::stof(args.at(1));
137  std::cout << call(*client, node_id, request) << std::endl;
138  }
139  }
140  }
141  },
142  {
143  "param_save",
144  {
145  "Calls uavcan.protocol.param.ExecuteOpcode on a remote node with OPCODE_SAVE",
146  [](const uavcan_linux::NodePtr& node, const uavcan::NodeID node_id, const std::vector<std::string>&)
147  {
148  auto client = node->makeBlockingServiceClient<uavcan::protocol::param::ExecuteOpcode>();
149  uavcan::protocol::param::ExecuteOpcode::Request request;
150  request.opcode = request.OPCODE_SAVE;
151  std::cout << call(*client, node_id, request) << std::endl;
152  }
153  }
154  },
155  {
156  "param_erase",
157  {
158  "Calls uavcan.protocol.param.ExecuteOpcode on a remote node with OPCODE_ERASE",
159  [](const uavcan_linux::NodePtr& node, const uavcan::NodeID node_id, const std::vector<std::string>&)
160  {
161  auto client = node->makeBlockingServiceClient<uavcan::protocol::param::ExecuteOpcode>();
162  uavcan::protocol::param::ExecuteOpcode::Request request;
163  request.opcode = request.OPCODE_ERASE;
164  std::cout << call(*client, node_id, request) << std::endl;
165  }
166  }
167  },
168  {
169  "restart",
170  {
171  "Restarts a remote node using uavcan.protocol.RestartNode",
172  [](const uavcan_linux::NodePtr& node, const uavcan::NodeID node_id, const std::vector<std::string>&)
173  {
174  auto client = node->makeBlockingServiceClient<uavcan::protocol::RestartNode>();
175  uavcan::protocol::RestartNode::Request request;
176  request.magic_number = request.MAGIC_NUMBER;
177  (void)client->blockingCall(node_id, request);
178  if (client->wasSuccessful())
179  {
180  std::cout << client->getResponse() << std::endl;
181  }
182  else
183  {
184  std::cout << "<NO RESPONSE>" << std::endl;
185  }
186  }
187  }
188  },
189  {
190  "info",
191  {
192  "Calls uavcan.protocol.GetNodeInfo on a remote node",
193  [](const uavcan_linux::NodePtr& node, const uavcan::NodeID node_id, const std::vector<std::string>&)
194  {
195  auto client = node->makeBlockingServiceClient<uavcan::protocol::GetNodeInfo>();
196  std::cout << call(*client, node_id, uavcan::protocol::GetNodeInfo::Request()) << std::endl;
197  }
198  }
199  },
200  {
201  "transport_stats",
202  {
203  "Calls uavcan.protocol.GetTransportStats on a remote node",
204  [](const uavcan_linux::NodePtr& node, const uavcan::NodeID node_id, const std::vector<std::string>&)
205  {
206  auto client = node->makeBlockingServiceClient<uavcan::protocol::GetTransportStats>();
207  std::cout << call(*client, node_id, uavcan::protocol::GetTransportStats::Request()) << std::endl;
208  }
209  }
210  },
211  {
212  "hardpoint",
213  {
214  "Publishes uavcan.equipment.hardpoint.Command\n"
215  "Expected argument: command",
216  [](const uavcan_linux::NodePtr& node, const uavcan::NodeID, const std::vector<std::string>& args)
217  {
218  uavcan::equipment::hardpoint::Command msg;
219  msg.command = std::stoi(args.at(0));
220  auto pub = node->makePublisher<uavcan::equipment::hardpoint::Command>();
221  (void)pub->broadcast(msg);
222  }
223  }
224  }
225 };
226 
228 {
229  StdinLineReader stdin_reader;
230  std::cout << "> " << std::flush;
231  while (true)
232  {
234  if (!stdin_reader.hasPendingInput())
235  {
236  continue;
237  }
238  const auto words = stdin_reader.getSplitLine();
239  bool command_is_known = false;
240 
241  try
242  {
243  if (words.size() >= 2)
244  {
245  const auto cmd = words.at(0);
246  const uavcan::NodeID node_id(std::stoi(words.at(1)));
247  auto it = commands.find(cmd);
248  if (it != std::end(commands))
249  {
250  command_is_known = true;
251  it->second.second(node, node_id, std::vector<std::string>(words.begin() + 2, words.end()));
252  }
253  }
254  }
255  catch (std::exception& ex)
256  {
257  std::cout << "FAILURE\n" << ex.what() << std::endl;
258  }
259 
260  if (!command_is_known)
261  {
262  std::cout << "<command> <remote node id> [args...]\n";
263  std::cout << "Say 'help' to get help.\n"; // I'll show myself out.
264 
265  if (!words.empty() && words.at(0) == "help")
266  {
267  std::cout << "Usage:\n\n";
268  for (auto& cmd : commands)
269  {
270  std::cout << cmd.first << "\n" << cmd.second.first << "\n\n";
271  }
272  }
273  }
274  std::cout << "> " << std::flush;
275  }
276 }
277 
278 }
279 
280 int main(int argc, const char** argv)
281 {
282  try
283  {
284  if (argc < 3)
285  {
286  std::cerr << "Usage:\n\t" << argv[0] << " <node-id> <can-iface-name-1> [can-iface-name-N...]" << std::endl;
287  return 1;
288  }
289  const int self_node_id = std::stoi(argv[1]);
290  const std::vector<std::string> iface_names(argv + 2, argv + argc);
291  uavcan_linux::NodePtr node = initNode(iface_names, self_node_id, "org.uavcan.linux_app.nodetool");
292  runForever(node);
293  return 0;
294  }
295  catch (const std::exception& ex)
296  {
297  std::cerr << "Error: " << ex.what() << std::endl;
298  return 1;
299  }
300 }
response
const std::string response
uavcan_linux::BlockingServiceClient::wasSuccessful
bool wasSuccessful() const
Definition: platform_specific_components/linux/libuavcan/include/uavcan_linux/helpers.hpp:104
call
bool call(const std::string &service_name, MReq &req, MRes &res)
uavcan::NodeID
Definition: transfer.hpp:112
uavcan_linux::BlockingServiceClient::blockingCall
int blockingCall(uavcan::NodeID server_node_id, const typename DataType::Request &request)
Definition: platform_specific_components/linux/libuavcan/include/uavcan_linux/helpers.hpp:70
uavcan::DurationBase< MonotonicDuration >::fromMSec
static MonotonicDuration fromMSec(int64_t ms)
Definition: time.hpp:41
runForever
static void runForever(const uavcan_linux::NodePtr &node)
Definition: test_node.cpp:42
initNode
static uavcan_linux::NodePtr initNode(const std::vector< std::string > &ifaces, uavcan::NodeID nid, const std::string &name)
Definition: test_node.cpp:10
ENFORCE
#define ENFORCE(x)
Definition: platform_specific_components/linux/libuavcan/apps/debug.hpp:13
node_status_monitor.hpp
uavcan_linux::BlockingServiceClient
Definition: platform_specific_components/linux/libuavcan/include/uavcan_linux/helpers.hpp:37
setup.args
args
Definition: pyuavcan/setup.py:22
uavcan_linux.hpp
debug.hpp
uavcan_linux::NodePtr
std::shared_ptr< Node > NodePtr
Definition: platform_specific_components/linux/libuavcan/include/uavcan_linux/helpers.hpp:354
main
int main(int argc, const char **argv)
Definition: uavcan_nodetool.cpp:280
pyuavcan_v0.introspect.node
node
Definition: introspect.py:398
uavcan_linux::BlockingServiceClient::getResponse
const DataType::Response & getResponse() const
Definition: platform_specific_components/linux/libuavcan/include/uavcan_linux/helpers.hpp:110
uavcan::copy
UAVCAN_EXPORT OutputIt copy(InputIt first, InputIt last, OutputIt result)
Definition: templates.hpp:238
uavcan_linux::makeNode
static NodePtr makeNode(const std::vector< std::string > &iface_names, ClockAdjustmentMode clock_adjustment_mode=SystemClock::detectPreferredClockAdjustmentMode())
Definition: platform_specific_components/linux/libuavcan/include/uavcan_linux/helpers.hpp:363


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:03