LCOV - code coverage report
Current view: top level - AP_InertialSensor - BatchSampler.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 111 140 79.3 %
Date: 2026-09-09 11:02:08 Functions: 7 7 100.0 %

          Line data    Source code
       1             : #include "AP_InertialSensor.h"
       2             : 
       3             : #if AP_INERTIALSENSOR_BATCHSAMPLER_ENABLED
       4             : #include <GCS_MAVLink/GCS.h>
       5             : #include <AP_Logger/AP_Logger.h>
       6             : 
       7             : // Class level parameters
       8             : const AP_Param::GroupInfo AP_InertialSensor::BatchSampler::var_info[] = {
       9             :     // @Param: BAT_CNT
      10             :     // @DisplayName: sample count per batch
      11             :     // @Description: Number of samples to take when logging streams of IMU sensor readings.  Will be rounded down to a multiple of 32. This option takes effect on the next reboot.
      12             :     // @User: Advanced
      13             :     // @Increment: 32
      14             :     // @RebootRequired: True
      15             :     AP_GROUPINFO("BAT_CNT",  1, AP_InertialSensor::BatchSampler, _required_count,   1024),
      16             : 
      17             :     // @Param: BAT_MASK
      18             :     // @DisplayName: Sensor Bitmask
      19             :     // @Description: Bitmap of which IMUs to log batch data for. This option takes effect on the next reboot.
      20             :     // @User: Advanced
      21             :     // @Bitmask: 0:IMU1,1:IMU2,2:IMU3
      22             :     // @RebootRequired: True
      23             :     AP_GROUPINFO("BAT_MASK",  2, AP_InertialSensor::BatchSampler, _sensor_mask,   DEFAULT_IMU_LOG_BAT_MASK),
      24             : 
      25             :     // @Param: BAT_OPT
      26             :     // @DisplayName: Batch Logging Options Mask
      27             :     // @Description: Options for the BatchSampler.
      28             :     // @Bitmask: 0:Sensor-Rate Logging (sample at full sensor rate seen by AP), 1: Sample post-filtering, 2: Sample pre- and post-filter
      29             :     // @User: Advanced
      30             :     AP_GROUPINFO("BAT_OPT",  3, AP_InertialSensor::BatchSampler, _batch_options_mask, 0),
      31             : 
      32             :     // @Param: BAT_LGIN
      33             :     // @DisplayName: logging interval
      34             :     // @Description: Interval between pushing samples to the AP_Logger log
      35             :     // @Units: ms
      36             :     // @Increment: 10
      37             :     AP_GROUPINFO("BAT_LGIN", 4, AP_InertialSensor::BatchSampler, push_interval_ms,   20),
      38             : 
      39             :     // @Param: BAT_LGCT
      40             :     // @DisplayName: logging count
      41             :     // @Description: Number of samples to push to count every @PREFIX@BAT_LGIN
      42             :     // @Increment: 1
      43             :     AP_GROUPINFO("BAT_LGCT", 5, AP_InertialSensor::BatchSampler, samples_per_msg,   32),
      44             : 
      45             :     AP_GROUPEND
      46             : };
      47             : 
      48             : 
      49             : extern const AP_HAL::HAL& hal;
      50        2088 : void AP_InertialSensor::BatchSampler::init()
      51             : {
      52        2088 :     if (_sensor_mask == 0) {
      53        1767 :         return;
      54             :     }
      55         321 :     if (_required_count <= 0) {
      56           0 :         return;
      57             :     }
      58             : 
      59         321 :     _required_count.set(_required_count - (_required_count % 32)); // round down to nearest multiple of 32
      60             : 
      61         321 :     _real_required_count = _required_count;
      62             : 
      63         321 :     const uint32_t total_allocation = 3*_real_required_count*sizeof(uint16_t);
      64         321 :     GCS_SEND_TEXT(MAV_SEVERITY_DEBUG, "INS: alloc %u bytes for ISB (free=%u)", (unsigned int)total_allocation, (unsigned int)hal.util->available_memory());
      65             : 
      66         321 :     data_x = (int16_t*)calloc(_real_required_count, sizeof(int16_t));
      67         321 :     data_y = (int16_t*)calloc(_real_required_count, sizeof(int16_t));
      68         321 :     data_z = (int16_t*)calloc(_real_required_count, sizeof(int16_t));
      69         321 :     if (data_x == nullptr || data_y == nullptr || data_z == nullptr) {
      70           0 :         free(data_x);
      71           0 :         free(data_y);
      72           0 :         free(data_z);
      73           0 :         data_x = nullptr;
      74           0 :         data_y = nullptr;
      75           0 :         data_z = nullptr;
      76           0 :         GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Failed to allocate %u bytes for IMU batch sampling", (unsigned int)total_allocation);
      77           0 :         return;
      78             :     }
      79             : 
      80         321 :     rotate_to_next_sensor();
      81             : 
      82         321 :     initialised = true;
      83             : }
      84             : 
      85    36043796 : void AP_InertialSensor::BatchSampler::periodic()
      86             : {
      87    36043796 :     if (_sensor_mask == 0) {
      88    33953783 :         return;
      89             :     }
      90             : #if HAL_LOGGING_ENABLED
      91     2090013 :     push_data_to_log();
      92             : #endif
      93             : }
      94             : 
      95       13128 : void AP_InertialSensor::BatchSampler::update_doing_sensor_rate_logging()
      96             : {
      97       13128 :     if (has_option(BATCH_OPT_POST_FILTER)) {
      98         950 :         _doing_post_filter_logging = true;
      99             :     }
     100       13128 :     if (has_option(BATCH_OPT_PRE_POST_FILTER)) {
     101         955 :         _doing_pre_post_filter_logging = true;
     102             :     }
     103       13128 :     if (!has_option(BATCH_OPT_SENSOR_RATE)) {
     104       13128 :         _doing_sensor_rate_logging = false;
     105       13128 :         return;
     106             :     }
     107           0 :     const uint8_t bit = (1<<instance);
     108           0 :     switch (type) {
     109           0 :     case IMU_SENSOR_TYPE_GYRO:
     110           0 :         _doing_sensor_rate_logging = _imu._gyro_sensor_rate_sampling_enabled & bit;
     111           0 :         break;
     112           0 :     case IMU_SENSOR_TYPE_ACCEL:
     113           0 :         _doing_sensor_rate_logging = _imu._accel_sensor_rate_sampling_enabled & bit;
     114           0 :         break;
     115             :     }
     116             : }
     117             : 
     118       13128 : void AP_InertialSensor::BatchSampler::rotate_to_next_sensor()
     119             : {
     120       13128 :     if (_sensor_mask == 0) {
     121             :         // should not have been called
     122           0 :         return;
     123             :     }
     124       13128 :     if ((1U<<instance) > (uint8_t)_sensor_mask) {
     125             :         // should only ever happen if user resets _sensor_mask
     126           0 :         instance = 0;
     127           0 :         post_filter = false;
     128             :     }
     129             : 
     130       13128 :     if (type == IMU_SENSOR_TYPE_ACCEL) {
     131             :         // we have logged accelerometers, now log gyros:
     132        6643 :         type = IMU_SENSOR_TYPE_GYRO;
     133        6643 :         multiplier = _imu._gyro_raw_sampling_multiplier[instance];
     134        6643 :         update_doing_sensor_rate_logging();
     135        6643 :         return;
     136             :     }
     137             : 
     138             :     // log for accel sensor:
     139        6485 :     type = IMU_SENSOR_TYPE_ACCEL;
     140             : 
     141             :     // move to next IMU backend:
     142             : 
     143             :     // we assume the number of gyros and accels is the same, taking
     144             :     // this minimum stops us doing bad things if that isn't true:
     145        6485 :     const uint8_t _count = MIN(_imu._accel_count, _imu._gyro_count);
     146             : 
     147             :     // find next backend instance to log:
     148        6485 :     bool haveinstance = false;
     149        6485 :     for (uint8_t i=instance+1; i<_count; i++) {
     150        3333 :         if (_sensor_mask & (1U<<i)) {
     151        3333 :             instance = i;
     152        3333 :             haveinstance = true;
     153        3333 :             break;
     154             :         }
     155             :     }
     156        6485 :     if (!haveinstance) {
     157        3152 :         for (uint8_t i=0; i<=instance; i++) {
     158        3152 :             if (_sensor_mask & (1U<<i)) {
     159        3152 :                 instance = i;
     160        3152 :                 haveinstance = true;
     161        3152 :                 post_filter = !post_filter;
     162        3152 :                 break;
     163             :             }
     164             :         }
     165             :     }
     166        6485 :     if (!haveinstance) {
     167             :         // should not happen!
     168             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
     169           0 :         abort();
     170             : #endif
     171           0 :         instance = 0;
     172           0 :         post_filter = false;
     173           0 :         return;
     174             :     }
     175             : 
     176        6485 :     multiplier = _imu._accel_raw_sampling_multiplier[instance];
     177        6485 :     update_doing_sensor_rate_logging();
     178             : }
     179             : 
     180             : #if HAL_LOGGING_ENABLED
     181     2090013 : void AP_InertialSensor::BatchSampler::push_data_to_log()
     182             : {
     183     2090013 :     if (!initialised) {
     184        9662 :         return;
     185             :     }
     186     2080351 :     if (_sensor_mask == 0) {
     187           0 :         return;
     188             :     }
     189     2080351 :     if (data_write_offset - data_read_offset < samples_per_msg) {
     190             :         // insuffucient data to pack a packet
     191     1656062 :         return;
     192             :     }
     193      424289 :     if (AP_HAL::millis() - last_sent_ms < (uint16_t)push_interval_ms) {
     194             :         // avoid flooding AP_Logger's buffer
     195         532 :         return;
     196             :     }
     197      423757 :     AP_Logger *logger = AP_Logger::get_singleton();
     198      423757 :     if (logger == nullptr) {
     199             :         // should not have been called
     200           0 :         return;
     201             :     }
     202             : 
     203             :     // possibly send isb header:
     204      423757 :     if (!isbh_sent && data_read_offset == 0) {
     205       17217 :         float sample_rate = 0; // avoid warning about uninitialised values
     206       17217 :         switch(type) {
     207       10676 :         case IMU_SENSOR_TYPE_GYRO:
     208       10676 :             sample_rate = _imu._gyro_raw_sample_rates[instance];
     209       10676 :             if (_doing_sensor_rate_logging) {
     210           0 :                 sample_rate *= _imu._gyro_over_sampling[instance];
     211             :             }
     212       10676 :             break;
     213        6541 :         case IMU_SENSOR_TYPE_ACCEL:
     214        6541 :             sample_rate = _imu._accel_raw_sample_rates[instance];
     215        6541 :             if (_doing_sensor_rate_logging) {
     216           0 :                 sample_rate *= _imu._accel_over_sampling[instance];
     217             :             }
     218        6541 :             break;
     219             :         }
     220       17217 :         if (!Write_ISBH(sample_rate)) {
     221             :             // buffer full?
     222        4128 :             return;
     223             :         }
     224       13089 :         isbh_sent = true;
     225             :     }
     226             :     // pack a nd send a data packet:
     227      419629 :     if (!Write_ISBD()) {
     228             :         // maybe later?!
     229        5225 :         return;
     230             :     }
     231             : 
     232      414404 :     data_read_offset += samples_per_msg;
     233      414404 :     last_sent_ms = AP_HAL::millis();
     234      414404 :     if (data_read_offset >= _real_required_count) {
     235             :         // that was the last one.  Clean up:
     236       12807 :         data_read_offset = 0;
     237       12807 :         isb_seqnum++;
     238       12807 :         isbh_sent = false;
     239             :         // rotate to next instance:
     240       12807 :         rotate_to_next_sensor();
     241       12807 :         data_write_offset = 0; // unlocks writing process
     242             :     }
     243             : }
     244             : 
     245   545430663 : bool AP_InertialSensor::BatchSampler::should_log(uint8_t _instance, IMU_SENSOR_TYPE _type)
     246             : {
     247   545430663 :     if (_sensor_mask == 0) {
     248   486051312 :         return false;
     249             :     }
     250    59379347 :     if (!initialised) {
     251      696806 :         return false;
     252             :     }
     253    58682541 :     if (_instance != instance) {
     254    29507830 :         return false;
     255             :     }
     256    29174711 :     if (_type != type) {
     257    14588750 :         return false;
     258             :     }
     259    14585961 :     if (data_write_offset >= _real_required_count) {
     260      261041 :         return false;
     261             :     }
     262    14324920 :     AP_Logger *logger = AP_Logger::get_singleton();
     263    14324944 :     if (logger == nullptr) {
     264           0 :         return false;
     265             :     }
     266             : #define MASK_LOG_ANY                    0xFFFF
     267    14324944 :     if (!logger->should_log(MASK_LOG_ANY)) {
     268      997875 :         return false;
     269             :     }
     270    13327069 :     return true;
     271             : }
     272             : #endif  // HAL_LOGGING_ENABLED
     273             : 
     274   545430688 : void AP_InertialSensor::BatchSampler::sample(uint8_t _instance, AP_InertialSensor::IMU_SENSOR_TYPE _type, uint64_t sample_us, const Vector3f &_sample)
     275             : {
     276             : #if HAL_LOGGING_ENABLED
     277   545430688 :     if (!should_log(_instance, _type)) {
     278   532103633 :         return;
     279             :     }
     280    13327057 :     if (data_write_offset == 0) {
     281       13121 :         measurement_started_us = sample_us;
     282             :     }
     283             : 
     284    13327057 :     data_x[data_write_offset] = multiplier*_sample.x;
     285    13327057 :     data_y[data_write_offset] = multiplier*_sample.y;
     286    13327057 :     data_z[data_write_offset] = multiplier*_sample.z;
     287             : 
     288    13327057 :     data_write_offset++; // may unblock the reading process
     289             : #endif
     290             : }
     291             : #endif //#if AP_INERTIALSENSOR_BATCHSAMPLER_ENABLED

Generated by: LCOV version 1.14