LCOV - code coverage report
Current view: top level - AP_RangeFinder - AP_RangeFinder_PulsedLightLRF.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 74 0.0 %
Date: 2026-09-09 11:02:08 Functions: 0 4 0.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             : #include "AP_RangeFinder_PulsedLightLRF.h"
      16             : 
      17             : #if AP_RANGEFINDER_PULSEDLIGHTLRF_ENABLED
      18             : 
      19             : #include <stdio.h>
      20             : 
      21             : #include <AP_HAL/AP_HAL.h>
      22             : #include <AP_HAL/utility/sparse-endian.h>
      23             : 
      24             : extern const AP_HAL::HAL& hal;
      25             : 
      26             : /* LL40LS Registers addresses */
      27             : #define LL40LS_MEASURE_REG        0x00        /* Measure range register */
      28             : #define LL40LS_SIG_COUNT_VAL      0x02
      29             : #define LL40LS_DISTHIGH_REG       0x0F        /* High byte of distance register, auto increment */
      30             : #define LL40LS_COUNT              0x11
      31             : #define LL40LS_HW_VERSION         0x41
      32             : #define LL40LS_INTERVAL           0x45
      33             : #define LL40LS_SW_VERSION         0x4f
      34             : 
      35             : // bit values
      36             : #define LL40LS_MSRREG_RESET       0x00        /* reset to power on defaults */
      37             : #define LL40LS_AUTO_INCREMENT     0x80
      38             : #define LL40LS_COUNT_CONTINUOUS   0xff
      39             : #define LL40LS_MSRREG_ACQUIRE     0x04        /* Value to initiate a measurement, varies based on sensor revision */
      40             : 
      41             : // i2c address
      42             : #define LL40LS_ADDR   0x62
      43             : 
      44           0 : AP_RangeFinder_PulsedLightLRF::AP_RangeFinder_PulsedLightLRF(uint8_t bus,
      45             :                                                              RangeFinder::RangeFinder_State &_state,
      46             :                                                              AP_RangeFinder_Params &_params,
      47           0 :                                                                  RangeFinder::Type _rftype)
      48             :     : AP_RangeFinder_Backend(_state, _params)
      49           0 :     , _dev(hal.i2c_mgr->get_device(bus, LL40LS_ADDR))
      50           0 :     , rftype(_rftype)
      51             : {
      52           0 : }
      53             : 
      54             : /*
      55             :    detect if a PulsedLight rangefinder is connected. We'll detect by
      56             :    look for the version registers
      57             : */
      58           0 : AP_RangeFinder_Backend *AP_RangeFinder_PulsedLightLRF::detect(uint8_t bus,
      59             :                                                               RangeFinder::RangeFinder_State &_state,
      60             :                                                                                                                           AP_RangeFinder_Params &_params,
      61             :                                                                   RangeFinder::Type rftype)
      62             : {
      63             :     AP_RangeFinder_PulsedLightLRF *sensor
      64           0 :         = NEW_NOTHROW AP_RangeFinder_PulsedLightLRF(bus, _state, _params, rftype);
      65           0 :     if (!sensor ||
      66           0 :         !sensor->init()) {
      67           0 :         delete sensor;
      68           0 :         return nullptr;
      69             :     }
      70           0 :     return sensor;
      71             : }
      72             : 
      73             : /*
      74             :   called at 50Hz
      75             :  */
      76           0 : void AP_RangeFinder_PulsedLightLRF::timer(void)
      77             : {
      78           0 :     if (check_reg_counter++ == 10) {
      79           0 :         check_reg_counter = 0;
      80           0 :         if (!_dev->check_next_register()) {
      81             :             // re-send the acquire. this handles the case of power
      82             :             // cycling while running in continuous mode
      83           0 :             _dev->write_register(LL40LS_MEASURE_REG, LL40LS_MSRREG_ACQUIRE);            
      84             :         }
      85             :     }
      86             : 
      87           0 :     switch (phase) {
      88           0 :     case PHASE_COLLECT: {
      89             :         be16_t val;
      90             :         // read the high and low byte distance registers
      91           0 :         if (_dev->read_registers(LL40LS_DISTHIGH_REG | LL40LS_AUTO_INCREMENT, (uint8_t*)&val, sizeof(val))) {
      92           0 :             uint16_t _distance_cm = be16toh(val);
      93             :             // remove momentary spikes
      94           0 :             if (abs(_distance_cm - last_distance_cm) < 100) {
      95           0 :                 state.distance_m = _distance_cm * 0.01f;
      96           0 :                 state.last_reading_ms = AP_HAL::millis();
      97           0 :                 update_status();                
      98             :             }
      99           0 :             last_distance_cm = _distance_cm;
     100             :         } else {
     101           0 :             set_status(RangeFinder::Status::NoData);
     102             :         }
     103           0 :         if (!v2_hardware) {
     104             :             // for v2 hw we use continuous mode
     105           0 :             phase = PHASE_MEASURE;
     106             :         }
     107           0 :         if (!v3hp_hardware) {
     108             :             // for v3hp hw we start PHASE_MEASURE immediately after PHASE_COLLECT 
     109           0 :             break;
     110             :         }
     111             :     }
     112             :     FALLTHROUGH;
     113             :     case PHASE_MEASURE:
     114           0 :         if (_dev->write_register(LL40LS_MEASURE_REG, LL40LS_MSRREG_ACQUIRE)) {
     115           0 :             phase = PHASE_COLLECT;
     116             :         }
     117           0 :         break;
     118             :     }
     119           0 : }
     120             : 
     121             : 
     122             : /*
     123             :   a table of settings for a lidar
     124             :  */
     125             : struct settings_table {
     126             :     uint8_t reg;
     127             :     uint8_t value;
     128             : };
     129             : 
     130             : /*
     131             :   register setup table for V1 Lidar
     132             :  */
     133             : static const struct settings_table settings_v1[] = {
     134             :     { LL40LS_MEASURE_REG, LL40LS_MSRREG_RESET },
     135             : };
     136             : 
     137             : /*
     138             :   register setup table for V2 Lidar
     139             :  */
     140             : static const struct settings_table settings_v2[] = {
     141             :     { LL40LS_INTERVAL, 0x28 }, // 0x28 == 50Hz
     142             :     { LL40LS_COUNT, LL40LS_COUNT_CONTINUOUS },
     143             :     { LL40LS_MEASURE_REG, LL40LS_MSRREG_ACQUIRE },
     144             : };
     145             : 
     146             : /*
     147             :   register setup table for V3HP Lidar
     148             :  */
     149             : static const struct settings_table settings_v3hp[] = {
     150             :     { LL40LS_SIG_COUNT_VAL, 0x80 }, // 0x80 = 128 acquisitions
     151             : };
     152             : 
     153             : /*
     154             :   initialise the sensor to required settings
     155             :  */
     156           0 : bool AP_RangeFinder_PulsedLightLRF::init(void)
     157             : {
     158           0 :     if (!_dev) {
     159           0 :         return false;
     160             :     }
     161           0 :     _dev->get_semaphore()->take_blocking();
     162           0 :     _dev->set_retries(3);
     163             : 
     164             :     // LidarLite needs split transfers
     165           0 :     _dev->set_split_transfers(true);
     166             : 
     167           0 :     if (rftype == RangeFinder::Type::PLI2CV3) {
     168           0 :         v2_hardware = true;
     169           0 :     } else if (rftype == RangeFinder::Type::PLI2CV3HP) {
     170           0 :         v3hp_hardware = true;
     171             :     } else {
     172             :         // auto-detect v1 vs v2
     173           0 :         if (!(_dev->read_registers(LL40LS_HW_VERSION, &hw_version, 1) &&
     174           0 :               hw_version > 0 &&
     175           0 :               _dev->read_registers(LL40LS_SW_VERSION, &sw_version, 1) &&
     176           0 :               sw_version > 0)) {
     177           0 :             printf("PulsedLightI2C: bad version 0x%02x 0x%02x\n", (unsigned)hw_version, (unsigned)sw_version);
     178             :             // invalid version information
     179           0 :             goto failed;
     180             :         }
     181           0 :         v2_hardware = (hw_version >= 0x15);
     182             :     }
     183             :     
     184             :     const struct settings_table *table;
     185             :     uint8_t num_settings;
     186             : 
     187           0 :     if (v2_hardware) {
     188           0 :         table = settings_v2;
     189           0 :         num_settings = sizeof(settings_v2) / sizeof(settings_table);
     190           0 :         phase = PHASE_COLLECT;
     191           0 :     } else if (v3hp_hardware) {
     192           0 :         table = settings_v3hp;
     193           0 :         num_settings = sizeof(settings_v3hp) / sizeof(settings_table);
     194           0 :         phase = PHASE_MEASURE;
     195             :     } else {
     196           0 :         table = settings_v1;
     197           0 :         num_settings = sizeof(settings_v1) / sizeof(settings_table);
     198           0 :         phase = PHASE_MEASURE;    
     199             :     }
     200             : 
     201           0 :     _dev->setup_checked_registers(num_settings);
     202             : 
     203           0 :     for (uint8_t i = 0; i < num_settings; i++) {
     204           0 :         if (!_dev->write_register(table[i].reg, table[i].value, true)) {
     205           0 :             goto failed;
     206             :         }
     207             :     }
     208             : 
     209           0 :     printf("Found LidarLite device=0x%x v2=%d v3hp=%d\n", unsigned(_dev->get_bus_id()), (int)v2_hardware, (int)v3hp_hardware);
     210             :     
     211           0 :     _dev->get_semaphore()->give();
     212             : 
     213           0 :     _dev->register_periodic_callback(20000,
     214             :                                      FUNCTOR_BIND_MEMBER(&AP_RangeFinder_PulsedLightLRF::timer, void));
     215           0 :     return true;
     216             : 
     217           0 : failed:
     218           0 :     _dev->get_semaphore()->give();
     219           0 :     return false;
     220             : }
     221             : 
     222             : #endif  // AP_RANGEFINDER_PULSEDLIGHTLRF_ENABLED

Generated by: LCOV version 1.14