AP_Logger_MAVLinkLogTransfer.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. MAVLink logfile transfer functions
  3. */
  4. /*
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <AP_HAL/AP_HAL.h>
  17. #include <AP_Logger/AP_Logger.h>
  18. #include <GCS_MAVLink/GCS.h> // for LOG_ENTRY
  19. extern const AP_HAL::HAL& hal;
  20. // We avoid doing log messages when timing is critical:
  21. bool AP_Logger::should_handle_log_message()
  22. {
  23. if (!WritesEnabled()) {
  24. // this is currently used as a proxy for "in_mavlink_delay"
  25. return false;
  26. }
  27. if (vehicle_is_armed()) {
  28. return false;
  29. }
  30. return true;
  31. }
  32. /**
  33. handle all types of log download requests from the GCS
  34. */
  35. void AP_Logger::handle_log_message(GCS_MAVLINK &link, const mavlink_message_t &msg)
  36. {
  37. if (!should_handle_log_message()) {
  38. return;
  39. }
  40. switch (msg.msgid) {
  41. case MAVLINK_MSG_ID_LOG_REQUEST_LIST:
  42. handle_log_request_list(link, msg);
  43. break;
  44. case MAVLINK_MSG_ID_LOG_REQUEST_DATA:
  45. handle_log_request_data(link, msg);
  46. break;
  47. case MAVLINK_MSG_ID_LOG_ERASE:
  48. handle_log_request_erase(link, msg);
  49. break;
  50. case MAVLINK_MSG_ID_LOG_REQUEST_END:
  51. handle_log_request_end(link, msg);
  52. break;
  53. }
  54. }
  55. /**
  56. handle all types of log download requests from the GCS
  57. */
  58. void AP_Logger::handle_log_request_list(GCS_MAVLINK &link, const mavlink_message_t &msg)
  59. {
  60. WITH_SEMAPHORE(_log_send_sem);
  61. if (_log_sending_link != nullptr) {
  62. link.send_text(MAV_SEVERITY_INFO, "Log download in progress");
  63. return;
  64. }
  65. mavlink_log_request_list_t packet;
  66. mavlink_msg_log_request_list_decode(&msg, &packet);
  67. _log_num_logs = get_num_logs();
  68. if (_log_num_logs == 0) {
  69. _log_next_list_entry = 0;
  70. _log_last_list_entry = 0;
  71. } else {
  72. _log_next_list_entry = packet.start;
  73. _log_last_list_entry = packet.end;
  74. if (_log_last_list_entry > _log_num_logs) {
  75. _log_last_list_entry = _log_num_logs;
  76. }
  77. if (_log_next_list_entry < 1) {
  78. _log_next_list_entry = 1;
  79. }
  80. }
  81. transfer_activity = LISTING;
  82. _log_sending_link = &link;
  83. handle_log_send_listing();
  84. }
  85. /**
  86. handle request for log data
  87. */
  88. void AP_Logger::handle_log_request_data(GCS_MAVLINK &link, const mavlink_message_t &msg)
  89. {
  90. WITH_SEMAPHORE(_log_send_sem);
  91. if (_log_sending_link != nullptr) {
  92. // some GCS (e.g. MAVProxy) attempt to stream request_data
  93. // messages when they're filling gaps in the downloaded logs.
  94. // This channel check avoids complaining to them, at the cost
  95. // of silently dropping any repeated attempts to start logging
  96. if (_log_sending_link->get_chan() != link.get_chan()) {
  97. link.send_text(MAV_SEVERITY_INFO, "Log download in progress");
  98. }
  99. return;
  100. }
  101. mavlink_log_request_data_t packet;
  102. mavlink_msg_log_request_data_decode(&msg, &packet);
  103. // consider opening or switching logs:
  104. if (transfer_activity != SENDING || _log_num_data != packet.id) {
  105. uint16_t num_logs = get_num_logs();
  106. if (packet.id > num_logs || packet.id < 1) {
  107. // request for an invalid log; cancel any current download
  108. transfer_activity = IDLE;
  109. return;
  110. }
  111. uint32_t time_utc, size;
  112. get_log_info(packet.id, size, time_utc);
  113. _log_num_data = packet.id;
  114. _log_data_size = size;
  115. uint32_t end;
  116. get_log_boundaries(packet.id, _log_data_page, end);
  117. }
  118. _log_data_offset = packet.ofs;
  119. if (_log_data_offset >= _log_data_size) {
  120. _log_data_remaining = 0;
  121. } else {
  122. _log_data_remaining = _log_data_size - _log_data_offset;
  123. }
  124. if (_log_data_remaining > packet.count) {
  125. _log_data_remaining = packet.count;
  126. }
  127. transfer_activity = SENDING;
  128. _log_sending_link = &link;
  129. handle_log_send();
  130. }
  131. /**
  132. handle request to erase log data
  133. */
  134. void AP_Logger::handle_log_request_erase(GCS_MAVLINK &link, const mavlink_message_t &msg)
  135. {
  136. // mavlink_log_erase_t packet;
  137. // mavlink_msg_log_erase_decode(&msg, &packet);
  138. EraseAll();
  139. }
  140. /**
  141. handle request to stop transfer and resume normal logging
  142. */
  143. void AP_Logger::handle_log_request_end(GCS_MAVLINK &link, const mavlink_message_t &msg)
  144. {
  145. WITH_SEMAPHORE(_log_send_sem);
  146. mavlink_log_request_end_t packet;
  147. mavlink_msg_log_request_end_decode(&msg, &packet);
  148. transfer_activity = IDLE;
  149. _log_sending_link = nullptr;
  150. }
  151. /**
  152. trigger sending of log messages if there are some pending
  153. */
  154. void AP_Logger::handle_log_send()
  155. {
  156. WITH_SEMAPHORE(_log_send_sem);
  157. if (_log_sending_link == nullptr) {
  158. return;
  159. }
  160. if (hal.util->get_soft_armed()) {
  161. // might be flying
  162. return;
  163. }
  164. switch (transfer_activity) {
  165. case IDLE:
  166. break;
  167. case LISTING:
  168. handle_log_send_listing();
  169. break;
  170. case SENDING:
  171. handle_log_sending();
  172. break;
  173. }
  174. }
  175. void AP_Logger::handle_log_sending()
  176. {
  177. WITH_SEMAPHORE(_log_send_sem);
  178. #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
  179. // assume USB speeds in SITL for the purposes of log download
  180. const uint8_t num_sends = 40;
  181. #else
  182. uint8_t num_sends = 1;
  183. if (_log_sending_link->is_high_bandwidth() && hal.gpio->usb_connected()) {
  184. // when on USB we can send a lot more data
  185. num_sends = 250;
  186. } else if (_log_sending_link->have_flow_control()) {
  187. #if CONFIG_HAL_BOARD == HAL_BOARD_LINUX
  188. num_sends = 80;
  189. #else
  190. num_sends = 10;
  191. #endif
  192. }
  193. #endif
  194. for (uint8_t i=0; i<num_sends; i++) {
  195. if (transfer_activity != SENDING) {
  196. // may have completed sending data
  197. break;
  198. }
  199. if (!handle_log_send_data()) {
  200. break;
  201. }
  202. }
  203. }
  204. /**
  205. trigger sending of log messages if there are some pending
  206. */
  207. void AP_Logger::handle_log_send_listing()
  208. {
  209. WITH_SEMAPHORE(_log_send_sem);
  210. if (!HAVE_PAYLOAD_SPACE(_log_sending_link->get_chan(), LOG_ENTRY)) {
  211. // no space
  212. return;
  213. }
  214. if (AP_HAL::millis() - _log_sending_link->get_last_heartbeat_time() > 3000) {
  215. // give a heartbeat a chance
  216. return;
  217. }
  218. uint32_t size, time_utc;
  219. if (_log_next_list_entry == 0) {
  220. size = 0;
  221. time_utc = 0;
  222. } else {
  223. get_log_info(_log_next_list_entry, size, time_utc);
  224. }
  225. mavlink_msg_log_entry_send(_log_sending_link->get_chan(),
  226. _log_next_list_entry,
  227. _log_num_logs,
  228. _log_last_list_entry,
  229. time_utc,
  230. size);
  231. if (_log_next_list_entry == _log_last_list_entry) {
  232. transfer_activity = IDLE;
  233. _log_sending_link = nullptr;
  234. } else {
  235. _log_next_list_entry++;
  236. }
  237. }
  238. /**
  239. trigger sending of log data if there are some pending
  240. */
  241. bool AP_Logger::handle_log_send_data()
  242. {
  243. WITH_SEMAPHORE(_log_send_sem);
  244. if (!HAVE_PAYLOAD_SPACE(_log_sending_link->get_chan(), LOG_DATA)) {
  245. // no space
  246. return false;
  247. }
  248. if (AP_HAL::millis() - _log_sending_link->get_last_heartbeat_time() > 3000) {
  249. // give a heartbeat a chance
  250. return false;
  251. }
  252. int16_t ret = 0;
  253. uint32_t len = _log_data_remaining;
  254. mavlink_log_data_t packet;
  255. if (len > MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN) {
  256. len = MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN;
  257. }
  258. ret = get_log_data(_log_num_data, _log_data_page, _log_data_offset, len, packet.data);
  259. if (ret < 0) {
  260. // report as EOF on error
  261. ret = 0;
  262. }
  263. if (ret < MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN) {
  264. memset(&packet.data[ret], 0, MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN-ret);
  265. }
  266. packet.ofs = _log_data_offset;
  267. packet.id = _log_num_data;
  268. packet.count = ret;
  269. _mav_finalize_message_chan_send(_log_sending_link->get_chan(),
  270. MAVLINK_MSG_ID_LOG_DATA,
  271. (const char *)&packet,
  272. MAVLINK_MSG_ID_LOG_DATA_MIN_LEN,
  273. MAVLINK_MSG_ID_LOG_DATA_LEN,
  274. MAVLINK_MSG_ID_LOG_DATA_CRC);
  275. _log_data_offset += len;
  276. _log_data_remaining -= len;
  277. if (ret < MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN || _log_data_remaining == 0) {
  278. transfer_activity = IDLE;
  279. _log_sending_link = nullptr;
  280. }
  281. return true;
  282. }