uavcan_monitor.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #include <cstdio>
  5. #include <bitset>
  6. #include <unordered_map>
  7. #include <uavcan_linux/uavcan_linux.hpp>
  8. #include <uavcan/protocol/node_status_monitor.hpp>
  9. #include "debug.hpp"
  10. enum class CLIColor : unsigned
  11. {
  12. Red = 31,
  13. Green = 32,
  14. Yellow = 33,
  15. Blue = 34,
  16. Magenta = 35,
  17. Cyan = 36,
  18. White = 37,
  19. Default = 39
  20. };
  21. class CLIColorizer
  22. {
  23. const CLIColor color_;
  24. public:
  25. explicit CLIColorizer(CLIColor c) : color_(c)
  26. {
  27. std::printf("\033[%um", static_cast<unsigned>(color_));
  28. }
  29. ~CLIColorizer()
  30. {
  31. std::printf("\033[%um", static_cast<unsigned>(CLIColor::Default));
  32. }
  33. };
  34. class Monitor : public uavcan::NodeStatusMonitor
  35. {
  36. uavcan_linux::TimerPtr timer_;
  37. std::unordered_map<int, uavcan::protocol::NodeStatus> status_registry_;
  38. void handleNodeStatusMessage(const uavcan::ReceivedDataStructure<uavcan::protocol::NodeStatus>& msg) override
  39. {
  40. status_registry_[msg.getSrcNodeID().get()] = msg;
  41. }
  42. static std::pair<CLIColor, std::string> healthToColoredString(const std::uint8_t health)
  43. {
  44. static const std::unordered_map<std::uint8_t, std::pair<CLIColor, std::string>> map
  45. {
  46. { uavcan::protocol::NodeStatus::HEALTH_OK, { CLIColor(CLIColor::Green), "OK" }},
  47. { uavcan::protocol::NodeStatus::HEALTH_WARNING, { CLIColor(CLIColor::Yellow), "WARNING" }},
  48. { uavcan::protocol::NodeStatus::HEALTH_ERROR, { CLIColor(CLIColor::Magenta), "ERROR" }},
  49. { uavcan::protocol::NodeStatus::HEALTH_CRITICAL, { CLIColor(CLIColor::Red), "CRITICAL" }}
  50. };
  51. try
  52. {
  53. return map.at(health);
  54. }
  55. catch (std::out_of_range&)
  56. {
  57. return { CLIColor(CLIColor::Red), std::to_string(health) };
  58. }
  59. }
  60. static std::pair<CLIColor, std::string> modeToColoredString(const std::uint8_t mode)
  61. {
  62. static const std::unordered_map<std::uint8_t, std::pair<CLIColor, std::string>> map
  63. {
  64. { uavcan::protocol::NodeStatus::MODE_OPERATIONAL, { CLIColor(CLIColor::Green), "OPERATIONAL" }},
  65. { uavcan::protocol::NodeStatus::MODE_INITIALIZATION, { CLIColor(CLIColor::Yellow), "INITIALIZATION" }},
  66. { uavcan::protocol::NodeStatus::MODE_MAINTENANCE, { CLIColor(CLIColor::Cyan), "MAINTENANCE" }},
  67. { uavcan::protocol::NodeStatus::MODE_SOFTWARE_UPDATE, { CLIColor(CLIColor::Magenta), "SOFTWARE_UPDATE" }},
  68. { uavcan::protocol::NodeStatus::MODE_OFFLINE, { CLIColor(CLIColor::Red), "OFFLINE" }}
  69. };
  70. try
  71. {
  72. return map.at(mode);
  73. }
  74. catch (std::out_of_range&)
  75. {
  76. return { CLIColor(CLIColor::Red), std::to_string(mode) };
  77. }
  78. }
  79. void printStatusLine(const uavcan::NodeID nid, const uavcan::NodeStatusMonitor::NodeStatus& status)
  80. {
  81. const auto health_and_color = healthToColoredString(status.health);
  82. const auto mode_and_color = modeToColoredString(status.mode);
  83. const int nid_int = nid.get();
  84. const unsigned long uptime = status_registry_[nid_int].uptime_sec;
  85. const unsigned vendor_code = status_registry_[nid_int].vendor_specific_status_code;
  86. std::printf(" %-3d |", nid_int);
  87. {
  88. CLIColorizer clz(mode_and_color.first);
  89. std::printf(" %-15s ", mode_and_color.second.c_str());
  90. }
  91. std::printf("|");
  92. {
  93. CLIColorizer clz(health_and_color.first);
  94. std::printf(" %-8s ", health_and_color.second.c_str());
  95. }
  96. std::printf("| %-10lu | %04x %s'%s %u\n", uptime, vendor_code,
  97. std::bitset<8>((vendor_code >> 8) & 0xFF).to_string().c_str(),
  98. std::bitset<8>(vendor_code).to_string().c_str(),
  99. vendor_code);
  100. }
  101. void redraw(const uavcan::TimerEvent&)
  102. {
  103. std::printf("\x1b[1J"); // Clear screen from the current cursor position to the beginning
  104. std::printf("\x1b[H"); // Move cursor to the coordinates 1,1
  105. std::printf(" NID | Mode | Health | Uptime [s] | Vendor-specific status code\n");
  106. std::printf("-----+-----------------+----------+------------+-hex---bin----------------dec--\n");
  107. for (unsigned i = 1; i <= uavcan::NodeID::Max; i++)
  108. {
  109. if (isNodeKnown(i))
  110. {
  111. printStatusLine(i, getNodeStatus(i));
  112. }
  113. }
  114. }
  115. public:
  116. explicit Monitor(uavcan_linux::NodePtr node)
  117. : uavcan::NodeStatusMonitor(*node)
  118. , timer_(node->makeTimer(uavcan::MonotonicDuration::fromMSec(500),
  119. std::bind(&Monitor::redraw, this, std::placeholders::_1)))
  120. { }
  121. };
  122. static uavcan_linux::NodePtr initNodeInPassiveMode(const std::vector<std::string>& ifaces, const std::string& node_name)
  123. {
  124. auto node = uavcan_linux::makeNode(ifaces, node_name.c_str(),
  125. uavcan::protocol::SoftwareVersion(), uavcan::protocol::HardwareVersion());
  126. node->setModeOperational();
  127. return node;
  128. }
  129. static void runForever(const uavcan_linux::NodePtr& node)
  130. {
  131. Monitor mon(node);
  132. ENFORCE(0 == mon.start());
  133. while (true)
  134. {
  135. const int res = node->spin(uavcan::MonotonicDuration::getInfinite());
  136. if (res < 0)
  137. {
  138. node->logError("spin", "Error %*", res);
  139. }
  140. }
  141. }
  142. int main(int argc, const char** argv)
  143. {
  144. try
  145. {
  146. if (argc < 2)
  147. {
  148. std::cerr << "Usage:\n\t" << argv[0] << " <can-iface-name-1> [can-iface-name-N...]" << std::endl;
  149. return 1;
  150. }
  151. std::vector<std::string> iface_names;
  152. for (int i = 1; i < argc; i++)
  153. {
  154. iface_names.emplace_back(argv[i]);
  155. }
  156. uavcan_linux::NodePtr node = initNodeInPassiveMode(iface_names, "org.uavcan.linux_app.node_status_monitor");
  157. runForever(node);
  158. return 0;
  159. }
  160. catch (const std::exception& ex)
  161. {
  162. std::cerr << "Error: " << ex.what() << std::endl;
  163. return 1;
  164. }
  165. }