AP_UAVCAN_Servers.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * This file is free software: you can redistribute it and/or modify it
  3. * under the terms of the GNU General Public License as published by the
  4. * Free Software Foundation, either version 3 of the License, or
  5. * (at your option) any later version.
  6. *
  7. * This file is distributed in the hope that it will be useful, but
  8. * WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. * See the GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License along
  13. * with this program. If not, see <http://www.gnu.org/licenses/>.
  14. *
  15. * Author: Siddharth Bharat Purohit
  16. */
  17. #include <AP_HAL/AP_HAL.h>
  18. #if HAL_WITH_UAVCAN
  19. #include "AP_UAVCAN_Servers.h"
  20. #ifdef HAS_UAVCAN_SERVERS
  21. #include <uavcan/protocol/dynamic_node_id_server/event.hpp>
  22. #include <uavcan/protocol/dynamic_node_id_server/storage_backend.hpp>
  23. #include <uavcan/protocol/dynamic_node_id_server/centralized.hpp>
  24. #include <uavcan/protocol/HardwareVersion.hpp>
  25. #include <AP_BoardConfig/AP_BoardConfig.h>
  26. #include <AP_BoardConfig/AP_BoardConfig_CAN.h>
  27. #include <AP_Common/AP_Common.h>
  28. #include <AP_Logger/AP_Logger.h>
  29. #include <AP_Filesystem/AP_Filesystem.h>
  30. #ifndef UAVCAN_NODE_DB_PATH
  31. #define UAVCAN_NODE_DB_PATH HAL_BOARD_STORAGE_DIRECTORY "/UAVCAN"
  32. #endif
  33. #include <AP_HAL/AP_HAL.h>
  34. extern const AP_HAL::HAL& hal;
  35. #define debug_uavcan(fmt, args...) do { hal.console->printf(fmt, ##args); } while (0)
  36. class AP_UAVCAN_CentralizedServer : public uavcan::dynamic_node_id_server::CentralizedServer
  37. {
  38. public:
  39. AP_UAVCAN_CentralizedServer(uavcan::INode& node, uavcan::dynamic_node_id_server::IStorageBackend &storage_backend, uavcan::dynamic_node_id_server::IEventTracer &tracer) :
  40. uavcan::dynamic_node_id_server::CentralizedServer(node, storage_backend, tracer) {}
  41. };
  42. class AP_UAVCAN_FileEventTracer : public uavcan::dynamic_node_id_server::IEventTracer
  43. {
  44. protected:
  45. virtual void onEvent(uavcan::dynamic_node_id_server::TraceCode code, uavcan::int64_t argument) override
  46. {
  47. AP::logger().Write("UCEV", "TimeUS,code,arg", "s--", "F--", "Qhq", AP_HAL::micros64(), code, argument);
  48. }
  49. };
  50. class AP_UAVCAN_RestartRequestHandler : public uavcan::IRestartRequestHandler {
  51. public:
  52. bool handleRestartRequest(uavcan::NodeID request_source) override {
  53. // swiped from reboot handling in GCS_Common.cpp
  54. if (hal.util->get_soft_armed()) {
  55. // refuse reboot when armed
  56. return false;
  57. }
  58. AP_Notify *notify = AP_Notify::get_singleton();
  59. if (notify) {
  60. AP_Notify::flags.firmware_update = 1;
  61. notify->update();
  62. }
  63. // force safety on
  64. hal.rcout->force_safety_on();
  65. // flush pending parameter writes
  66. AP_Param::flush();
  67. hal.scheduler->delay(200);
  68. hal.scheduler->reboot(false);
  69. return true;
  70. }
  71. };
  72. class AP_UAVCAN_FileStorageBackend : public uavcan::dynamic_node_id_server::IStorageBackend
  73. {
  74. /**
  75. * Maximum length of full path including / and key max
  76. */
  77. enum { MaxPathLength = 128 };
  78. enum { MaxNumOpens = 100 };
  79. /**
  80. * This type is used for the path
  81. */
  82. typedef uavcan::MakeString<MaxPathLength>::Type PathString;
  83. PathString base_path;
  84. static uint8_t num_opens;
  85. protected:
  86. virtual String get(const String& key) const override
  87. {
  88. using namespace std;
  89. PathString path = base_path.c_str();
  90. path += key;
  91. String value;
  92. //This is to deter frequent inflight opening and closing of files during an event
  93. //where the device is misbehaving
  94. if (num_opens >= MaxNumOpens) {
  95. return value;
  96. }
  97. num_opens++;
  98. int fd = AP::FS().open(path.c_str(), O_RDONLY);
  99. if (fd >= 0)
  100. {
  101. char buffer[MaxStringLength + 1];
  102. (void)memset(buffer, 0, sizeof(buffer));
  103. ssize_t remaining = MaxStringLength;
  104. ssize_t total_read = 0;
  105. ssize_t nread = 0;
  106. do
  107. {
  108. nread = AP::FS().read(fd, &buffer[total_read], remaining);
  109. if (nread > 0)
  110. {
  111. remaining -= nread,
  112. total_read += nread;
  113. }
  114. }
  115. while (nread > 0 && remaining > 0);
  116. AP::FS().close(fd);
  117. if (total_read > 0)
  118. {
  119. for (int i = 0; i < total_read; i++)
  120. {
  121. if (buffer[i] == ' ' || buffer[i] == '\n' || buffer[i] == '\r')
  122. {
  123. buffer[i] = '\0';
  124. break;
  125. }
  126. }
  127. value = buffer;
  128. }
  129. }
  130. return value;
  131. }
  132. virtual void set(const String& key, const String& value) override
  133. {
  134. using namespace std;
  135. PathString path = base_path.c_str();
  136. path += key;
  137. //This is to deter frequent inflight opening and closing of files during an event
  138. //where the device is misbehaving
  139. if (num_opens >= MaxNumOpens) {
  140. return;
  141. }
  142. num_opens++;
  143. int fd = AP::FS().open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
  144. if (fd >= 0)
  145. {
  146. ssize_t remaining = value.size();
  147. ssize_t total_written = 0;
  148. ssize_t written = 0;
  149. do
  150. {
  151. written = AP::FS().write(fd, &value.c_str()[total_written], remaining);
  152. if (written > 0)
  153. {
  154. total_written += written;
  155. remaining -= written;
  156. }
  157. }
  158. while (written > 0 && remaining > 0);
  159. AP::FS().fsync(fd);
  160. AP::FS().close(fd);
  161. }
  162. }
  163. public:
  164. /**
  165. * Initializes the file based backend storage by passing a path to
  166. * the directory where the key named files will be stored.
  167. * The return value should be 0 on success.
  168. * If it is -ErrInvalidConfiguration then the the path name is too long to
  169. * accommodate the trailing slash and max key length.
  170. */
  171. int init(const PathString& path)
  172. {
  173. using namespace std;
  174. int rv = -uavcan::ErrInvalidParam;
  175. if (path.size() > 0)
  176. {
  177. base_path = path.c_str();
  178. if (base_path.back() == '/')
  179. {
  180. base_path.pop_back();
  181. }
  182. rv = 0;
  183. struct stat sb;
  184. if (AP::FS().stat(base_path.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode))
  185. {
  186. rv = AP::FS().mkdir(base_path.c_str());
  187. }
  188. if (rv >= 0)
  189. {
  190. base_path.push_back('/');
  191. if ((base_path.size() + MaxStringLength) > MaxPathLength)
  192. {
  193. rv = -uavcan::ErrInvalidConfiguration;
  194. }
  195. }
  196. }
  197. return rv;
  198. }
  199. };
  200. uint8_t AP_UAVCAN_FileStorageBackend::num_opens = 0;
  201. bool AP_UAVCAN_Servers::init(uavcan::Node<0> &node)
  202. {
  203. if (_server_instance != nullptr) {
  204. return true;
  205. }
  206. int ret = 0;
  207. _storage_backend = new AP_UAVCAN_FileStorageBackend;
  208. if (_storage_backend == nullptr) {
  209. debug_uavcan("UAVCAN_Servers: Failed to Allocate FileStorageBackend\n");
  210. goto failed;
  211. }
  212. ret = _storage_backend->init(UAVCAN_NODE_DB_PATH);
  213. if (ret < 0) {
  214. debug_uavcan("UAVCAN_Servers: FileStorageBackend init: %d, errno: %d\n", ret, errno);
  215. goto failed;
  216. }
  217. _tracer = new AP_UAVCAN_FileEventTracer;
  218. if (_tracer == nullptr) {
  219. debug_uavcan("UAVCAN_Servers: Failed to Allocate FileEventTracer\n");
  220. goto failed;
  221. }
  222. _server_instance = new AP_UAVCAN_CentralizedServer(node, *_storage_backend, *_tracer);
  223. if (_server_instance == nullptr) {
  224. debug_uavcan("UAVCAN_Servers: Failed to Allocate Server\n");
  225. goto failed;
  226. }
  227. {
  228. uavcan::dynamic_node_id_server::centralized::Storage storage(*_storage_backend);
  229. if (storage.getNodeIDForUniqueID(node.getHardwareVersion().unique_id) != node.getNodeID()) {
  230. //Node ID was changed, reseting database
  231. reset();
  232. }
  233. }
  234. if (_restart_request_handler == nullptr) {
  235. _restart_request_handler = new AP_UAVCAN_RestartRequestHandler();
  236. if (_restart_request_handler == nullptr) {
  237. goto failed;
  238. }
  239. }
  240. node.setRestartRequestHandler(_restart_request_handler);
  241. //Start Dynamic Node Server
  242. ret = _server_instance->init(node.getHardwareVersion().unique_id);
  243. if (ret < 0) {
  244. debug_uavcan("UAVCAN_Server init: %d, errno: %d\n", ret, errno);
  245. goto failed;
  246. }
  247. return true;
  248. failed:
  249. delete _restart_request_handler;
  250. delete _storage_backend;
  251. delete _tracer;
  252. delete _server_instance;
  253. return false;
  254. }
  255. void AP_UAVCAN_Servers::reset()
  256. {
  257. debug_uavcan("UAVCAN_Servers: Resetting Server Database...\n");
  258. DIR* dp;
  259. struct dirent* ep;
  260. dp = AP::FS().opendir(UAVCAN_NODE_DB_PATH);
  261. char abs_filename[100];
  262. if (dp != NULL)
  263. {
  264. while((ep = AP::FS().readdir(dp))) {
  265. snprintf(abs_filename, 100, "%s/%s", UAVCAN_NODE_DB_PATH, ep->d_name);
  266. AP::FS().unlink(abs_filename);
  267. }
  268. }
  269. AP::FS().closedir(dp);
  270. }
  271. #endif
  272. #endif //HAL_WITH_UAVCAN