LCOV - code coverage report
Current view: top level - AP_Terrain - TerrainUtil.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 67 69 97.1 %
Date: 2026-09-09 11:02:08 Functions: 6 6 100.0 %

          Line data    Source code
       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             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : /*
      16             :   handle disk IO for terrain code
      17             :  */
      18             : 
      19             : #include "AP_Terrain.h"
      20             : 
      21             : #if AP_TERRAIN_AVAILABLE
      22             : 
      23             : #include <AP_HAL/AP_HAL.h>
      24             : #include <AP_Common/AP_Common.h>
      25             : #include <AP_Math/AP_Math.h>
      26             : 
      27             : extern const AP_HAL::HAL& hal;
      28             : 
      29             : /*
      30             :   calculate bit number in grid_block bitmap. This corresponds to a
      31             :   bit representing a 4x4 mavlink transmitted block
      32             : */
      33  3785770030 : uint8_t AP_Terrain::grid_bitnum(uint8_t idx_x, uint8_t idx_y)
      34             : {    
      35             :     ASSERT_RANGE(idx_x,0,27);
      36             :     ASSERT_RANGE(idx_y,0,31);
      37  3785770030 :     uint8_t subgrid_x = idx_x / TERRAIN_GRID_MAVLINK_SIZE;
      38  3785770030 :     uint8_t subgrid_y = idx_y / TERRAIN_GRID_MAVLINK_SIZE;
      39             :     ASSERT_RANGE(subgrid_x,0,TERRAIN_GRID_BLOCK_MUL_X-1);
      40             :     ASSERT_RANGE(subgrid_y,0,TERRAIN_GRID_BLOCK_MUL_Y-1);
      41  3785770030 :     return subgrid_y + TERRAIN_GRID_BLOCK_MUL_Y*subgrid_x;
      42             : }
      43             : 
      44             : /*
      45             :   given a grid_info check that a given idx_x/idx_y is available (set
      46             :   in the bitmap)
      47             :  */
      48  3785770092 : bool AP_Terrain::check_bitmap(const struct grid_block &grid, uint8_t idx_x, uint8_t idx_y)
      49             : {
      50  3785770092 :     uint8_t bitnum = grid_bitnum(idx_x, idx_y);
      51  3785770405 :     return (grid.bitmap & (((uint64_t)1U)<<bitnum)) != 0;
      52             : }
      53             : 
      54             : /*
      55             :   given a location, calculate the 32x28 grid SW corner, plus the
      56             :   grid indices
      57             : */
      58  1008129292 : void AP_Terrain::calculate_grid_info(const Location &loc, struct grid_info &info) const
      59             : {
      60             :     // grids start on integer degrees. This makes storing terrain data
      61             :     // on the SD card a bit easier
      62  1008129292 :     info.lat_degrees = (loc.lat<0?(loc.lat-9999999L):loc.lat) / (10*1000*1000L);
      63  1008129292 :     info.lon_degrees = (loc.lng<0?(loc.lng-9999999L):loc.lng) / (10*1000*1000L);
      64             : 
      65             :     // create reference position for this rounded degree position
      66  1008129292 :     Location ref;
      67  1008129219 :     ref.lat = info.lat_degrees*10*1000*1000L;
      68  1008129219 :     ref.lng = info.lon_degrees*10*1000*1000L;
      69             : 
      70             :     // find offset from reference
      71  1008129219 :     const Vector2f offset = ref.get_distance_NE(loc);
      72             : 
      73             :     // get indices in terms of grid_spacing elements
      74  1008128765 :     uint32_t idx_x = offset.x / grid_spacing;
      75  1008128559 :     uint32_t idx_y = offset.y / grid_spacing;
      76             : 
      77             :     // find indexes into 32*28 grids for this degree reference. Note
      78             :     // the use of TERRAIN_GRID_BLOCK_SPACING_{X,Y} which gives a one square
      79             :     // overlap between grids
      80  1008128469 :     info.grid_idx_x = idx_x / TERRAIN_GRID_BLOCK_SPACING_X;
      81  1008128469 :     info.grid_idx_y = idx_y / TERRAIN_GRID_BLOCK_SPACING_Y;
      82             : 
      83             :     // find the indices within the 32*28 grid
      84  1008128469 :     info.idx_x = idx_x % TERRAIN_GRID_BLOCK_SPACING_X;
      85  1008128469 :     info.idx_y = idx_y % TERRAIN_GRID_BLOCK_SPACING_Y;
      86             : 
      87             :     // find the fraction (0..1) within the square
      88  1008128469 :     info.frac_x = (offset.x - idx_x * grid_spacing) / grid_spacing;
      89  1008128409 :     info.frac_y = (offset.y - idx_y * grid_spacing) / grid_spacing;
      90             : 
      91             :     // calculate lat/lon of SW corner of 32*28 grid_block
      92  1008128333 :     ref.offset(info.grid_idx_x * TERRAIN_GRID_BLOCK_SPACING_X * (float)grid_spacing,
      93  1008128433 :                info.grid_idx_y * TERRAIN_GRID_BLOCK_SPACING_Y * (float)grid_spacing);
      94  1008128257 :     info.grid_lat = ref.lat;
      95  1008128257 :     info.grid_lon = ref.lng;
      96             : 
      97             :     ASSERT_RANGE(info.idx_x,0,TERRAIN_GRID_BLOCK_SPACING_X-1);
      98             :     ASSERT_RANGE(info.idx_y,0,TERRAIN_GRID_BLOCK_SPACING_Y-1);
      99             :     ASSERT_RANGE(info.frac_x,0,1);
     100             :     ASSERT_RANGE(info.frac_y,0,1);
     101  1008128257 : }
     102             : 
     103             : 
     104             : /*
     105             :   find a grid structure given a grid_info
     106             :  */
     107  1008926189 : AP_Terrain::grid_cache &AP_Terrain::find_grid_cache(const struct grid_info &info)
     108             : {
     109  1008926189 :     uint16_t oldest_i = 0;
     110             : 
     111             :     // see if we have that grid
     112  1008926189 :     const auto now_ms = AP_HAL::millis();
     113  1427802942 :     for (uint16_t i=0; i<cache_size; i++) {
     114  1427791413 :         if (TERRAIN_LATLON_EQUAL(cache[i].grid.lat,info.grid_lat) &&
     115  2436708562 :             TERRAIN_LATLON_EQUAL(cache[i].grid.lon,info.grid_lon) &&
     116  1008914189 :             cache[i].grid.spacing == grid_spacing) {
     117  1008917410 :             cache[i].last_access_ms = now_ms;
     118  1008917410 :             return cache[i];
     119             :         }
     120   418877098 :         if (cache[i].last_access_ms < cache[oldest_i].last_access_ms) {
     121    77785620 :             oldest_i = i;
     122             :         }
     123             :     }
     124             : 
     125             :     // Not found. Use the oldest grid and make it this grid,
     126             :     // initially unpopulated
     127       11529 :     struct grid_cache &grid = cache[oldest_i];
     128       11529 :     memset(&grid, 0, sizeof(grid));
     129             : 
     130       11529 :     grid.grid.lat = info.grid_lat;
     131       11529 :     grid.grid.lon = info.grid_lon;
     132       11529 :     grid.grid.spacing = grid_spacing;
     133        9039 :     grid.grid.grid_idx_x = info.grid_idx_x;
     134        9039 :     grid.grid.grid_idx_y = info.grid_idx_y;
     135        9039 :     grid.grid.lat_degrees = info.lat_degrees;
     136        9039 :     grid.grid.lon_degrees = info.lon_degrees;
     137        9039 :     grid.grid.version = TERRAIN_GRID_FORMAT_VERSION;
     138        9039 :     grid.grid.version_minor = TERRAIN_VERSION_MINOR_MIN;
     139        9039 :     grid.last_access_ms = now_ms;
     140             : 
     141             :     // mark as waiting for disk read
     142        9039 :     grid.state = GRID_CACHE_DISKWAIT;
     143             : 
     144        9039 :     return grid;
     145             : }
     146             : 
     147             : /*
     148             :   find cache index of disk_block
     149             :  */
     150        8943 : int16_t AP_Terrain::find_io_idx(enum GridCacheState state)
     151             : {
     152             :     // try first with given state
     153       41940 :     for (uint16_t i=0; i<cache_size; i++) {
     154       41939 :         if (TERRAIN_LATLON_EQUAL(disk_block.block.lat,cache[i].grid.lat) &&
     155       50881 :             TERRAIN_LATLON_EQUAL(disk_block.block.lon,cache[i].grid.lon) &&
     156        8942 :             cache[i].state == state) {
     157        8942 :             return i;
     158             :         }
     159             :     }    
     160             :     // then any state
     161          13 :     for (uint16_t i=0; i<cache_size; i++) {
     162          12 :         if (TERRAIN_LATLON_EQUAL(disk_block.block.lat,cache[i].grid.lat) &&
     163           0 :             TERRAIN_LATLON_EQUAL(disk_block.block.lon,cache[i].grid.lon)) {
     164           0 :             return i;
     165             :         }
     166             :     }    
     167           1 :     return -1;
     168             : }
     169             : 
     170             : /*
     171             :   get CRC for a block
     172             :  */
     173        8369 : uint16_t AP_Terrain::get_block_crc(struct grid_block &block)
     174             : {
     175        8369 :     uint16_t saved_crc = block.crc;
     176        8369 :     block.crc = 0;
     177             :     /*
     178             :       note that we exclude version_minor and any later bytes from the
     179             :       CRC to maintain backwards compatibility so old versions of
     180             :       ArduPilot accept new terrain blocks
     181             :      */
     182        8369 :     uint16_t ret = crc16_ccitt((const uint8_t *)&block, offsetof(struct grid_block, version_minor), 0);
     183        8369 :     block.crc = saved_crc;
     184        8369 :     return ret;
     185             : }
     186             : 
     187             : #endif // AP_TERRAIN_AVAILABLE

Generated by: LCOV version 1.14