Files
ardupilot/libraries/AP_ADSB/AP_ADSB_Backend.cpp
T
Peter Barker de411b3818 AP_ADSB: bound Sagetech GPS message field widths
The GPS message is a run of fixed-width ASCII fields, each exactly as
wide as the value it holds, with the terminating nul landing on the
first byte of the field which follows it.  Nothing bounded the
formatted values, so an out-of-range input would overflow its field and
shift everything after it, and gcc-16 rejects the latitude outright:

  AP_ADSB_Sagetech.cpp:497: error: 'snprintf' output may be truncated
  before the last format character [-Werror=format-truncation=]

Bound each component to the widest value its field can represent, and
share the formatting between the two Sagetech drivers rather than
duplicating it.

The seconds of the time of fix are now formatted as an integer rather
than as a float so that the width of the field is known; the
milliseconds are rounded and carried into the seconds, which gives
output identical to the previous "%06.3f" except on exact
half-millisecond ties.  The MXS driver converted its epoch to seconds
through a double, which can round up to the following second at
present-day epoch values; it now uses integer division.

Built for sparknavi-blue, which master does not currently build.
2026-09-15 11:13:23 +10:00

95 lines
3.1 KiB
C++

/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AP_ADSB_Backend.h"
#if HAL_ADSB_ENABLED
#include <AP_Math/AP_Math.h>
#include <stdio.h>
#include <time.h>
/*
base class constructor.
*/
AP_ADSB_Backend::AP_ADSB_Backend(AP_ADSB &frontend, uint8_t instance) :
_instance(instance),
_frontend(frontend)
{
}
#if HAL_ADSB_SAGETECH_ENABLED || HAL_ADSB_SAGETECH_MXS_ENABLED
// NOTE: the coordinate maths MUST be done in double or else we get
// roundoff in the maths
void AP_ADSB_Backend::format_longitude(char *buf, size_t buflen, int32_t lng_1e7)
{
const double deg = lng_1e7 * (double)1.0e-7 * (lng_1e7 < 0 ? -1 : 1);
const double minutes = (deg - int(deg)) * 60;
snprintf(buf, buflen, "%03u%02u.%05u",
MIN(unsigned(deg), 180U),
MIN(unsigned(minutes), 59U),
MIN(unsigned((minutes - (int)minutes) * 1.0E5), 99999U));
}
void AP_ADSB_Backend::format_latitude(char *buf, size_t buflen, int32_t lat_1e7)
{
const double deg = lat_1e7 * (double)1.0e-7 * (lat_1e7 < 0 ? -1 : 1);
const double minutes = (deg - int(deg)) * 60;
snprintf(buf, buflen, "%02u%02u.%05u",
MIN(unsigned(deg), 90U),
MIN(unsigned(minutes), 59U),
MIN(unsigned((minutes - (int)minutes) * 1.0E5), 99999U));
}
void AP_ADSB_Backend::format_speed_knots(char *buf, size_t buflen, float knots)
{
snprintf(buf, buflen, "%03u.%02u",
MIN(unsigned(knots), 999U),
MIN(unsigned((knots - (int)knots) * 1.0E2), 99U));
}
void AP_ADSB_Backend::format_track_deg(char *buf, size_t buflen, float track_deg)
{
snprintf(buf, buflen, "%03u.%04u",
MIN(unsigned(track_deg), 359U),
MIN(unsigned((track_deg - (int)track_deg) * 1.0E4), 9999U));
}
void AP_ADSB_Backend::format_time_of_day(char *buf, size_t buflen, uint64_t time_usec)
{
const time_t time_sec = time_usec / 1000000;
struct tm tmd {};
gmtime_r(&time_sec, &tmd);
// the seconds are formatted as an integer rather than as a float so
// that the width of the field is known; the milliseconds are rounded
// and carried into the seconds to match the "%06.3f" this replaced
const unsigned msec = unsigned((time_usec % 1000000 + 500) / 1000);
const unsigned sec = unsigned(tmd.tm_sec) + msec / 1000;
snprintf(buf, buflen, "%02u%02u%02u.%03u",
MIN(unsigned(tmd.tm_hour), 23U),
MIN(unsigned(tmd.tm_min), 59U),
MIN(sec, 61U),
msec % 1000);
}
#endif // HAL_ADSB_SAGETECH_ENABLED || HAL_ADSB_SAGETECH_MXS_ENABLED
#endif // HAL_ADSB_ENABLED