LCOV - code coverage report
Current view: top level - SITL - SIM_PS_LD06.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 56 61 91.8 %
Date: 2026-09-09 11:02:08 Functions: 3 4 75.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             :   Simulator for the LD06 proximity sensors
      17             : */
      18             : 
      19             : #include "SIM_config.h"
      20             : 
      21             : #if AP_SIM_PS_LD06_ENABLED
      22             : 
      23             : #include "SIM_PS_LD06.h"
      24             : 
      25             : #include <GCS_MAVLink/GCS.h>
      26             : #include <AP_BoardConfig/AP_BoardConfig.h>
      27             : #include <stdio.h>
      28             : #include <errno.h>
      29             : #include <AP_HAL/utility/sparse-endian.h>
      30             : 
      31             : using namespace SITL;
      32             : 
      33           0 : uint32_t PS_LD06::packet_for_location(const Location &location,
      34             :                                       uint8_t *data,
      35             :                                       uint8_t buflen)
      36             : {
      37           0 :     return 0;
      38             : }
      39             : 
      40       52407 : void PS_LD06::update_input()
      41             : {
      42             :     // just discard any input
      43             :     char buffer[256];
      44       52407 :     uint8_t buflen = 0;
      45       52407 :     read_from_autopilot(&buffer[buflen], ARRAY_SIZE(buffer) - buflen - 1);
      46       52407 : }
      47             : 
      48       52407 : void PS_LD06::update_output(const Location &location)
      49             : {
      50       52407 :     const uint32_t now_ms = AP_HAL::millis();
      51       52407 :     if (last_scan_output_time_ms == 0) {
      52           3 :         last_scan_output_time_ms = now_ms;
      53           3 :         return;
      54             :     }
      55       52404 :     const uint32_t time_delta_ms = (now_ms - last_scan_output_time_ms);
      56             : 
      57             :     // the driver and device only send/handle 12 readings at a time at
      58             :     // the moment
      59       52404 :     const uint32_t sample_count = 12;
      60             : 
      61       52404 :     const uint32_t samples_per_second = 4500;
      62       52404 :     const float samples_per_ms = samples_per_second / 1000.0f;
      63             : 
      64       52404 :     const uint32_t required_time_delta_ms = sample_count * samples_per_ms;
      65             : 
      66       52404 :     if (time_delta_ms < required_time_delta_ms) {
      67       30604 :         return;
      68             :     }
      69             :     // sanity check we're being called often enough:
      70       21800 :     if (time_delta_ms / samples_per_ms > sample_count) {
      71           0 :         AP_HAL::panic("Not being called often enough");
      72             :     }
      73             : 
      74       21800 :     const float degrees_per_s = 2152;  // see example datasheet page 8
      75       21800 :     const float degrees_per_ms = degrees_per_s / 1000.0f;
      76       21800 :     const float degrees_per_sample = degrees_per_ms / samples_per_ms;
      77             : 
      78             :     // ::fprintf(stderr, "Packing %u samples in for %ums interval (%f degrees/sample)\n", sample_count, time_delta_ms, degrees_per_sample);
      79             : 
      80       21800 :     last_scan_output_time_ms += sample_count/samples_per_ms;
      81             : 
      82       21800 :     const uint32_t required_send_buffer_size = 11 + 3*sample_count;
      83       21800 :     if (required_send_buffer_size > send_buffer_size) {
      84           1 :         if (send_buffer != nullptr) {
      85           0 :             free(send_buffer);
      86             :         }
      87           1 :         send_buffer = (uint8_t*)malloc(required_send_buffer_size);
      88           1 :         if (send_buffer == nullptr) {
      89           0 :             AP_BoardConfig::allocation_error("LD06 send buffer");
      90             :         }
      91           1 :         send_buffer_size = required_send_buffer_size;
      92             :     }
      93             : 
      94             :     struct PACKED PacketStart {
      95             :         uint8_t preamble;
      96             :         uint8_t length : 5;
      97             :         uint8_t reserved : 3;
      98             :         uint16_t angular_rate;  // degrees/second
      99             :         uint16_t start_angle;  // centidegrees
     100             :     };
     101             :     struct PACKED Measurement {
     102             :         uint16_t distance;
     103             :         uint8_t confidence;
     104             :     };
     105             :     struct PACKED PacketEnd {
     106             :         uint16_t end_angle;
     107             :         uint16_t timestamp;
     108             :         uint8_t crc;
     109             :     };
     110             : 
     111       21800 :     PacketStart &packet_start = *((PacketStart*)send_buffer);
     112             : 
     113       21800 :     packet_start.preamble = 0x54;
     114       21800 :     packet_start.length = sample_count;
     115       21800 :     packet_start.angular_rate = htole16(degrees_per_s);
     116       21800 :     packet_start.start_angle = htole16(last_degrees_bf * 100);
     117             : 
     118       21800 :     uint16_t offset = sizeof(PacketStart);
     119             : 
     120      283400 :     for (uint32_t i=0; i<sample_count; i++) {
     121      261600 :         const float current_degrees_bf = fmod((last_degrees_bf + degrees_per_sample), 360.0f);
     122      261600 :         last_degrees_bf = current_degrees_bf;
     123             : 
     124      261600 :         float distance = measure_distance_at_angle_bf(location, current_degrees_bf);
     125             :         // ::fprintf(stderr, "SIM: %f=%fm\n", current_degrees_bf, distance);
     126             : 
     127      261600 :         uint8_t confidence = 29; // random number; driver checks this
     128      261600 :         if (distance > 12.0) {  // 12 metre max range
     129             :             // return 0 for out-of-range; is this correct?
     130      109672 :             distance = 0.0f;
     131      109672 :             confidence = 0;
     132             :         }
     133             : 
     134      261600 :         Measurement &measurement = *((Measurement*)&send_buffer[offset]);
     135             : 
     136      261600 :         measurement.distance = htole16(distance * 1000);  // m -> mm
     137      261600 :         measurement.confidence = confidence;
     138             : 
     139      261600 :         offset += sizeof(Measurement);
     140             :     }
     141             : 
     142       21800 :     PacketEnd &packet_end = *((PacketEnd*)&send_buffer[offset]);
     143             : 
     144       21800 :     packet_end.end_angle = htole16(last_degrees_bf * 100);  // centidegrees
     145       21800 :     packet_end.timestamp = htole16(0);  // milliseconds
     146       21800 :     offset += sizeof(PacketEnd);
     147             : 
     148       21800 :     packet_end.crc = crc8_generic(&send_buffer[0], offset-1, 0x4D);
     149             : 
     150       21800 :     const ssize_t ret = write_to_autopilot((const char*)send_buffer, offset);
     151       21800 :     if (ret != offset) {
     152             :         // abort();  // there are startup issues with this, we fill things up before the driver is ready
     153             :     }
     154             : }
     155             : 
     156       52407 : void PS_LD06::update(const Location &location)
     157             : {
     158       52407 :     update_input();
     159       52407 :     update_output(location);
     160       52407 : }
     161             : 
     162             : #endif  // AP_SIM_PS_LD06_ENABLED

Generated by: LCOV version 1.14