TerrainGCS.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. /*
  14. handle vehicle <-> GCS communications for terrain library
  15. */
  16. #include "AP_Terrain.h"
  17. #include <AP_AHRS/AP_AHRS.h>
  18. #include <AP_HAL/AP_HAL.h>
  19. #include <AP_Common/AP_Common.h>
  20. #include <AP_Math/AP_Math.h>
  21. #include <GCS_MAVLink/GCS_MAVLink.h>
  22. #include <GCS_MAVLink/GCS.h>
  23. #if AP_TERRAIN_AVAILABLE
  24. #include <assert.h>
  25. #include <stdio.h>
  26. extern const AP_HAL::HAL& hal;
  27. /*
  28. request any missing 4x4 grids from a block, given a grid_cache
  29. */
  30. bool AP_Terrain::request_missing(mavlink_channel_t chan, struct grid_cache &gcache)
  31. {
  32. struct grid_block &grid = gcache.grid;
  33. if (grid.spacing != grid_spacing) {
  34. // an invalid grid
  35. return false;
  36. }
  37. // see if we are waiting for disk read
  38. if (gcache.state == GRID_CACHE_DISKWAIT) {
  39. // don't request data from the GCS till we know it's not on disk
  40. return false;
  41. }
  42. // see if it is fully populated
  43. if ((grid.bitmap & bitmap_mask) == bitmap_mask) {
  44. // it is fully populated, nothing to do
  45. return false;
  46. }
  47. if (!HAVE_PAYLOAD_SPACE(chan, TERRAIN_REQUEST)) {
  48. // not enough buffer space
  49. return false;
  50. }
  51. /*
  52. ask the GCS to send a set of 4x4 grids
  53. */
  54. mavlink_msg_terrain_request_send(chan, grid.lat, grid.lon, grid_spacing, bitmap_mask & ~grid.bitmap);
  55. last_request_time_ms[chan] = AP_HAL::millis();
  56. return true;
  57. }
  58. /*
  59. request any missing 4x4 grids from a block
  60. */
  61. bool AP_Terrain::request_missing(mavlink_channel_t chan, const struct grid_info &info)
  62. {
  63. // find the grid
  64. struct grid_cache &gcache = find_grid_cache(info);
  65. return request_missing(chan, gcache);
  66. }
  67. /*
  68. send any pending terrain request to the GCS
  69. */
  70. void AP_Terrain::send_request(mavlink_channel_t chan)
  71. {
  72. if (!allocate()) {
  73. // not enabled
  74. return;
  75. }
  76. // see if we need to schedule some disk IO
  77. schedule_disk_io();
  78. Location loc;
  79. if (!AP::ahrs().get_position(loc)) {
  80. // we don't know where we are
  81. return;
  82. }
  83. // always send a terrain report
  84. send_terrain_report(chan, loc, true);
  85. // did we request recently?
  86. if (AP_HAL::millis() - last_request_time_ms[chan] < 2000) {
  87. // too soon to request again
  88. return;
  89. }
  90. // request any missing 4x4 blocks in the current grid
  91. struct grid_info info;
  92. calculate_grid_info(loc, info);
  93. if (request_missing(chan, info)) {
  94. return;
  95. }
  96. // also request a larger set of up to 9 grids
  97. for (int8_t x=-1; x<=1; x++) {
  98. for (int8_t y=-1; y<=1; y++) {
  99. Location loc2 = loc;
  100. loc2.offset(x*TERRAIN_GRID_BLOCK_SIZE_X*0.7f*grid_spacing,
  101. y*TERRAIN_GRID_BLOCK_SIZE_Y*0.7f*grid_spacing);
  102. struct grid_info info2;
  103. calculate_grid_info(loc2, info2);
  104. if (request_missing(chan, info2)) {
  105. return;
  106. }
  107. }
  108. }
  109. // check cache blocks that may have been setup by a TERRAIN_CHECK
  110. for (uint16_t i=0; i<cache_size; i++) {
  111. if (cache[i].state >= GRID_CACHE_VALID) {
  112. if (request_missing(chan, cache[i])) {
  113. return;
  114. }
  115. }
  116. }
  117. // request the current loc last to ensure it has highest last
  118. // access time
  119. if (request_missing(chan, info)) {
  120. return;
  121. }
  122. }
  123. /*
  124. count bits in a uint64_t
  125. */
  126. uint8_t AP_Terrain::bitcount64(uint64_t b)
  127. {
  128. return __builtin_popcount((unsigned)(b&0xFFFFFFFF)) + __builtin_popcount((unsigned)(b>>32));
  129. }
  130. /*
  131. get some statistics for TERRAIN_REPORT
  132. */
  133. void AP_Terrain::get_statistics(uint16_t &pending, uint16_t &loaded)
  134. {
  135. pending = 0;
  136. loaded = 0;
  137. for (uint16_t i=0; i<cache_size; i++) {
  138. if (cache[i].grid.spacing != grid_spacing) {
  139. continue;
  140. }
  141. if (cache[i].state == GRID_CACHE_INVALID) {
  142. continue;
  143. }
  144. uint8_t maskbits = TERRAIN_GRID_BLOCK_MUL_X*TERRAIN_GRID_BLOCK_MUL_Y;
  145. if (cache[i].state == GRID_CACHE_DISKWAIT) {
  146. pending += maskbits;
  147. continue;
  148. }
  149. if (cache[i].state == GRID_CACHE_DIRTY) {
  150. // count dirty grids as a pending, so we know where there
  151. // are disk writes pending
  152. pending++;
  153. }
  154. uint8_t bitcount = bitcount64(cache[i].grid.bitmap);
  155. pending += maskbits - bitcount;
  156. loaded += bitcount;
  157. }
  158. }
  159. /*
  160. handle terrain messages from GCS
  161. */
  162. void AP_Terrain::handle_data(mavlink_channel_t chan, const mavlink_message_t &msg)
  163. {
  164. if (msg.msgid == MAVLINK_MSG_ID_TERRAIN_DATA) {
  165. handle_terrain_data(msg);
  166. } else if (msg.msgid == MAVLINK_MSG_ID_TERRAIN_CHECK) {
  167. handle_terrain_check(chan, msg);
  168. }
  169. }
  170. /*
  171. send a TERRAIN_REPORT for a location
  172. */
  173. void AP_Terrain::send_terrain_report(mavlink_channel_t chan, const Location &loc, bool extrapolate)
  174. {
  175. float terrain_height = 0;
  176. float home_terrain_height = 0;
  177. uint16_t spacing = 0;
  178. Location current_loc;
  179. const AP_AHRS &ahrs = AP::ahrs();
  180. if (ahrs.get_position(current_loc) &&
  181. height_amsl(ahrs.get_home(), home_terrain_height, false) &&
  182. height_amsl(loc, terrain_height, false)) {
  183. // non-zero spacing indicates we have data
  184. spacing = grid_spacing;
  185. } else if (extrapolate && have_current_loc_height) {
  186. // show the extrapolated height, so logs show what height is
  187. // being used for navigation
  188. terrain_height = last_current_loc_height;
  189. }
  190. uint16_t pending, loaded;
  191. get_statistics(pending, loaded);
  192. float current_height;
  193. if (spacing == 0 && !(extrapolate && have_current_loc_height)) {
  194. current_height = 0;
  195. } else {
  196. if (current_loc.relative_alt) {
  197. current_height = current_loc.alt*0.01f;
  198. } else {
  199. current_height = (current_loc.alt - ahrs.get_home().alt)*0.01f;
  200. }
  201. }
  202. current_height += home_terrain_height - terrain_height;
  203. if (HAVE_PAYLOAD_SPACE(chan, TERRAIN_REPORT)) {
  204. mavlink_msg_terrain_report_send(chan, loc.lat, loc.lng, spacing,
  205. terrain_height, current_height,
  206. pending, loaded);
  207. }
  208. }
  209. /*
  210. handle TERRAIN_CHECK messages from GCS
  211. */
  212. void AP_Terrain::handle_terrain_check(mavlink_channel_t chan, const mavlink_message_t &msg)
  213. {
  214. mavlink_terrain_check_t packet;
  215. mavlink_msg_terrain_check_decode(&msg, &packet);
  216. Location loc;
  217. loc.lat = packet.lat;
  218. loc.lng = packet.lon;
  219. send_terrain_report(chan, loc, false);
  220. }
  221. /*
  222. handle TERRAIN_DATA messages from GCS
  223. */
  224. void AP_Terrain::handle_terrain_data(const mavlink_message_t &msg)
  225. {
  226. mavlink_terrain_data_t packet;
  227. mavlink_msg_terrain_data_decode(&msg, &packet);
  228. uint16_t i;
  229. for (i=0; i<cache_size; i++) {
  230. if (cache[i].grid.lat == packet.lat &&
  231. cache[i].grid.lon == packet.lon &&
  232. cache[i].grid.spacing == packet.grid_spacing &&
  233. grid_spacing == packet.grid_spacing &&
  234. packet.gridbit < 56) {
  235. break;
  236. }
  237. }
  238. if (i == cache_size) {
  239. // we don't have that grid, ignore data
  240. return;
  241. }
  242. struct grid_cache &gcache = cache[i];
  243. struct grid_block &grid = gcache.grid;
  244. uint8_t idx_x = (packet.gridbit / TERRAIN_GRID_BLOCK_MUL_Y) * TERRAIN_GRID_MAVLINK_SIZE;
  245. uint8_t idx_y = (packet.gridbit % TERRAIN_GRID_BLOCK_MUL_Y) * TERRAIN_GRID_MAVLINK_SIZE;
  246. ASSERT_RANGE(idx_x,0,(TERRAIN_GRID_BLOCK_MUL_X-1)*TERRAIN_GRID_MAVLINK_SIZE);
  247. ASSERT_RANGE(idx_y,0,(TERRAIN_GRID_BLOCK_MUL_Y-1)*TERRAIN_GRID_MAVLINK_SIZE);
  248. for (uint8_t x=0; x<TERRAIN_GRID_MAVLINK_SIZE; x++) {
  249. for (uint8_t y=0; y<TERRAIN_GRID_MAVLINK_SIZE; y++) {
  250. grid.height[idx_x+x][idx_y+y] = packet.data[x*TERRAIN_GRID_MAVLINK_SIZE+y];
  251. }
  252. }
  253. gcache.grid.bitmap |= ((uint64_t)1) << packet.gridbit;
  254. // mark dirty for disk IO
  255. gcache.state = GRID_CACHE_DIRTY;
  256. #if TERRAIN_DEBUG
  257. hal.console->printf("Filled bit %u idx_x=%u idx_y=%u\n",
  258. (unsigned)packet.gridbit, (unsigned)idx_x, (unsigned)idx_y);
  259. if (gcache.grid.bitmap == bitmap_mask) {
  260. hal.console->printf("--lat=%12.7f --lon=%12.7f %u\n",
  261. grid.lat*1.0e-7f,
  262. grid.lon*1.0e-7f,
  263. grid.height[0][0]);
  264. Location loc2;
  265. loc2.lat = grid.lat;
  266. loc2.lng = grid.lon;
  267. loc2.offset(28*grid_spacing, 32*grid_spacing);
  268. hal.console->printf("--lat=%12.7f --lon=%12.7f %u\n",
  269. loc2.lat*1.0e-7f,
  270. loc2.lng*1.0e-7f,
  271. grid.height[27][31]);
  272. }
  273. #endif
  274. // see if we need to schedule some disk IO
  275. update();
  276. }
  277. #endif // AP_TERRAIN_AVAILABLE