LCOV - code coverage report
Current view: top level - AP_RangeFinder - AP_RangeFinder_LightWareSerial.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 65 68 95.6 %
Date: 2026-09-09 11:02:08 Functions: 2 2 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             : #include "AP_RangeFinder_LightWareSerial.h"
      17             : 
      18             : #if AP_RANGEFINDER_LIGHTWARE_SERIAL_ENABLED
      19             : 
      20             : #include <AP_HAL/AP_HAL.h>
      21             : #include <ctype.h>
      22             : 
      23             : extern const AP_HAL::HAL& hal;
      24             : 
      25             : #define LIGHTWARE_DIST_MAX_CM           10000
      26             : #define LIGHTWARE_OUT_OF_RANGE_ADD_CM   100
      27             : 
      28             : // read - return last value measured by sensor
      29        5572 : bool AP_RangeFinder_LightWareSerial::get_reading(float &reading_m)
      30             : {
      31        5572 :     if (uart == nullptr) {
      32           0 :         return false;
      33             :     }
      34             : 
      35        5572 :     float sum = 0;              // sum of all readings taken
      36        5572 :     uint16_t valid_count = 0;   // number of valid readings
      37        5572 :     uint16_t invalid_count = 0; // number of invalid readings
      38             : 
      39             :     // max distance the sensor can reliably measure - read from parameters
      40        5572 :     const auto distance_cm_max = max_distance()*100;
      41             : 
      42             :     // read any available lines from the lidar
      43       12392 :     for (auto i=0; i<8192; i++) {
      44             :         uint8_t c;
      45       12392 :         if (!uart->read(c)) {
      46        5572 :             break;
      47             :         }
      48             :         // use legacy protocol
      49        6820 :         if (protocol_state == ProtocolState::UNKNOWN || protocol_state == ProtocolState::LEGACY) {
      50        6152 :             if (c == '\r') {
      51        1056 :                 linebuf[linebuf_len] = 0;
      52        1056 :                 const float dist = strtof(linebuf, nullptr);
      53        1056 :                 if (!is_negative(dist) && !is_lost_signal_distance(dist * 100, distance_cm_max)) {
      54         676 :                     sum += dist;
      55         676 :                     valid_count++;
      56             :                     // if still determining protocol update legacy valid count
      57         676 :                     if (protocol_state == ProtocolState::UNKNOWN) {
      58          22 :                         legacy_valid_count++;
      59             :                     }
      60             :                 } else {
      61         380 :                     invalid_count++;
      62             :                 }
      63        1056 :                 linebuf_len = 0;
      64        5096 :             } else if (isdigit(c) || c == '.' || c == '-') {
      65        5074 :                 linebuf[linebuf_len++] = c;
      66        5074 :                 if (linebuf_len == sizeof(linebuf)) {
      67             :                     // too long, discard the line
      68           0 :                     linebuf_len = 0;
      69             :                 }
      70             :             }
      71             :         }
      72             : 
      73             :         // use binary protocol
      74        6820 :         if (protocol_state == ProtocolState::UNKNOWN || protocol_state == ProtocolState::BINARY) {
      75         800 :             bool msb_set = BIT_IS_SET(c, 7);
      76         800 :             if (msb_set) {
      77             :                 // received the high byte
      78         345 :                 high_byte = c;
      79         345 :                 high_byte_received = true;
      80             :             } else {
      81             :                 // received the low byte which should be second
      82         455 :                 if (high_byte_received) {
      83         345 :                     const int16_t dist = (high_byte & 0x7f) << 7 | (c & 0x7f);
      84         345 :                     if (dist >= 0 && !is_lost_signal_distance(dist, distance_cm_max)) {
      85         345 :                         sum += dist * 0.01f;
      86         345 :                         valid_count++;
      87             :                         // if still determining protocol update binary valid count
      88         345 :                         if (protocol_state == ProtocolState::UNKNOWN) {
      89          11 :                             binary_valid_count++;
      90             :                         }
      91             :                     } else {
      92           0 :                         invalid_count++;
      93             :                     }
      94             :                 }
      95         455 :                 high_byte_received = false;
      96             :             }
      97             :         }
      98             :     }
      99             : 
     100             :     // protocol set after 10 successful reads
     101        5572 :     if (protocol_state == ProtocolState::UNKNOWN) {
     102         116 :         if (binary_valid_count > 10) {
     103           1 :             protocol_state = ProtocolState::BINARY;
     104         115 :         } else if (legacy_valid_count > 10) {
     105           2 :             protocol_state = ProtocolState::LEGACY;
     106             :         }
     107             :     }
     108             : 
     109        5572 :     uint32_t now = AP_HAL::millis();
     110        5572 :     if (last_init_ms == 0 ||
     111        5569 :         (now - last_init_ms > 1000 &&
     112        5509 :          now - state.last_reading_ms > 1000)) {
     113             :         // send enough serial transitions to trigger LW20 into serial
     114             :         // mode. It starts in dual I2C/serial mode, and wants to see
     115             :         // enough transitions to switch into serial mode.
     116           3 :         uart->write("www\r\n");
     117           3 :         last_init_ms = now;
     118             :     } else {
     119        5569 :         uart->write('d');
     120             :     }
     121             : 
     122             :     // return average of all valid readings
     123        5572 :     if (valid_count > 0) {
     124        1015 :         reading_m = sum / valid_count;
     125        1015 :         no_signal = false;
     126        1015 :         return true;
     127             :     }
     128             : 
     129             :     // all readings were invalid so return out-of-range-high value
     130        4557 :     if (invalid_count > 0) {
     131         380 :         reading_m = MAX(LIGHTWARE_DIST_MAX_CM, distance_cm_max + LIGHTWARE_OUT_OF_RANGE_ADD_CM);
     132         380 :         no_signal = true;
     133         380 :         return true;
     134             :     }
     135             : 
     136             :     // no readings so return false
     137        4177 :     return false;
     138             : }
     139             : 
     140             : // check to see if distance returned by the LiDAR is a known lost-signal distance flag
     141        1401 : bool AP_RangeFinder_LightWareSerial::is_lost_signal_distance(int16_t distance_cm, int16_t distance_cm_max)
     142             : {
     143        1401 :     if (distance_cm < distance_cm_max + LIGHTWARE_OUT_OF_RANGE_ADD_CM) {
     144             :         // in-range
     145         928 :         return false;
     146             :     }
     147         473 :     const int16_t bad_distances[] { 13000, 16000, 23000, 25000 };
     148         845 :     for (const auto bad_distance_cm : bad_distances) {
     149         752 :         if (distance_cm == bad_distance_cm) {
     150         380 :             return true;
     151             :         }
     152             :     }
     153          93 :     return false;
     154             : }
     155             : 
     156             : #endif

Generated by: LCOV version 1.14