GCS_MAVLink: set message intervals from config files

This commit is contained in:
Peter Barker 2021-06-02 13:06:13 +10:00 committed by Peter Barker
parent dd9f513aa5
commit 3f37a21aaf
2 changed files with 239 additions and 0 deletions

View File

@ -39,6 +39,10 @@
#define HAL_HIGH_LATENCY2_ENABLED !HAL_MINIMIZE_FEATURES #define HAL_HIGH_LATENCY2_ENABLED !HAL_MINIMIZE_FEATURES
#endif #endif
#ifndef HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
#define HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED (HAVE_FILESYSTEM_SUPPORT && BOARD_FLASH_SIZE > 1024)
#endif
// macros used to determine if a message will fit in the space available. // macros used to determine if a message will fit in the space available.
void gcs_out_of_space_to_send_count(mavlink_channel_t chan); void gcs_out_of_space_to_send_count(mavlink_channel_t chan);
@ -96,6 +100,37 @@ public:
AP_Int16 streamRates[GCS_MAVLINK_NUM_STREAM_RATES]; AP_Int16 streamRates[GCS_MAVLINK_NUM_STREAM_RATES];
}; };
#if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
class DefaultIntervalsFromFiles
{
public:
DefaultIntervalsFromFiles(uint16_t max_num);
~DefaultIntervalsFromFiles();
void set(ap_message id, uint16_t interval);
uint16_t num_intervals() const {
return _num_intervals;
}
bool get_interval_for_ap_message_id(ap_message id, uint16_t &interval) const;
ap_message id_at(uint8_t ofs) const;
uint16_t interval_at(uint8_t ofs) const;
private:
struct from_file_default_interval {
ap_message id;
uint16_t interval;
};
from_file_default_interval *_intervals;
uint16_t _num_intervals;
uint16_t _max_intervals;
};
#endif
/// ///
/// @class GCS_MAVLINK /// @class GCS_MAVLINK
/// @brief MAVLink transport control class /// @brief MAVLink transport control class
@ -682,6 +717,13 @@ private:
// boolean that indicated that message intervals have been set // boolean that indicated that message intervals have been set
// from streamrates: // from streamrates:
bool deferred_messages_initialised; bool deferred_messages_initialised;
#if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
// read configuration files from (e.g.) SD and ROMFS, set
// intervals from same
void initialise_message_intervals_from_config_files();
// read file, set message intervals from it:
void get_intervals_from_filepath(const char *path, DefaultIntervalsFromFiles &);
#endif
// return interval deferred message bucket should be sent after. // return interval deferred message bucket should be sent after.
// When sending parameters and waypoints this may be longer than // When sending parameters and waypoints this may be longer than
// the interval specified in "deferred" // the interval specified in "deferred"
@ -844,6 +886,12 @@ private:
bool signing_enabled(void) const; bool signing_enabled(void) const;
static void save_signing_timestamp(bool force_save_now); static void save_signing_timestamp(bool force_save_now);
#if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
// structure containing default intervals read from files for this
// link:
DefaultIntervalsFromFiles *default_intervals_from_files;
#endif
// alternative protocol handler support // alternative protocol handler support
struct { struct {
GCS_MAVLINK::protocol_handler_fn_t handler; GCS_MAVLINK::protocol_handler_fn_t handler;

View File

@ -49,6 +49,7 @@
#include <AP_OSD/AP_OSD.h> #include <AP_OSD/AP_OSD.h>
#include <AP_RCTelemetry/AP_CRSF_Telem.h> #include <AP_RCTelemetry/AP_CRSF_Telem.h>
#include <AP_AIS/AP_AIS.h> #include <AP_AIS/AP_AIS.h>
#include <AP_Filesystem/AP_Filesystem.h>
#include <stdio.h> #include <stdio.h>
@ -78,6 +79,8 @@
#include <AP_BattMonitor/AP_BattMonitor.h> #include <AP_BattMonitor/AP_BattMonitor.h>
#include <AP_GPS/AP_GPS.h> #include <AP_GPS/AP_GPS.h>
#include <ctype.h>
extern const AP_HAL::HAL& hal; extern const AP_HAL::HAL& hal;
struct GCS_MAVLINK::LastRadioStatus GCS_MAVLINK::last_radio_status; struct GCS_MAVLINK::LastRadioStatus GCS_MAVLINK::last_radio_status;
@ -1117,6 +1120,9 @@ void GCS_MAVLINK::update_send()
if (!deferred_messages_initialised) { if (!deferred_messages_initialised) {
initialise_message_intervals_from_streamrates(); initialise_message_intervals_from_streamrates();
#if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
initialise_message_intervals_from_config_files();
#endif
deferred_messages_initialised = true; deferred_messages_initialised = true;
} }
@ -5259,6 +5265,182 @@ void GCS_MAVLINK::initialise_message_intervals_for_stream(GCS_MAVLINK::streams i
} }
} }
#if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
// open and read contents of path, setting message intervals from each
// line
DefaultIntervalsFromFiles::DefaultIntervalsFromFiles(uint16_t max_num)
{
if (max_num == 0) {
return;
}
_intervals = new from_file_default_interval[max_num];
_max_intervals = max_num;
}
DefaultIntervalsFromFiles::~DefaultIntervalsFromFiles()
{
delete[] (_intervals);
}
void DefaultIntervalsFromFiles::set(ap_message id, uint16_t interval)
{
if (_intervals == nullptr) {
return;
}
// update any existing interval (last-one-in wins)
for (uint8_t i=0; i<_num_intervals; i++) {
if (_intervals[i].id == id) {
_intervals[i].interval = interval;
return;
}
}
// store an interval we've not seen before:
if (_num_intervals == _max_intervals) {
return;
}
_intervals[_num_intervals].id = id;
_intervals[_num_intervals].interval = interval;
_num_intervals++;
}
bool DefaultIntervalsFromFiles::get_interval_for_ap_message_id(ap_message id, uint16_t &interval) const
{
for (uint16_t i=0; i<_num_intervals; i++) {
if (_intervals[i].id == id) {
interval = _intervals[i].interval;
return true;
}
}
return false;
}
ap_message DefaultIntervalsFromFiles::id_at(uint8_t ofs) const
{
if (_intervals == nullptr || ofs >= _num_intervals) {
return MSG_LAST;
}
return _intervals[ofs].id;
}
uint16_t DefaultIntervalsFromFiles::interval_at(uint8_t ofs) const
{
if (_intervals == nullptr || ofs >= _num_intervals) {
return -1; // unsigned-integer wrap
}
return _intervals[ofs].interval;
}
void GCS_MAVLINK::get_intervals_from_filepath(const char *path, DefaultIntervalsFromFiles &intervals)
{
const int f = AP::FS().open(path, O_RDONLY);
if (f == -1) {
return;
}
char line[20];
while (AP::FS().fgets(line, sizeof(line)-1, f)) {
char *saveptr = nullptr;
const char *mavlink_id_str = strtok_r(line, " ", &saveptr);
if (mavlink_id_str == nullptr || strlen(mavlink_id_str) == 0) {
continue;
}
const uint32_t mavlink_id = atoi(mavlink_id_str);
const ap_message msg_id = mavlink_id_to_ap_message_id(mavlink_id);
if (msg_id == MSG_LAST) {
continue;
}
const char *interval_str = strtok_r(nullptr, "\r\n", &saveptr);
if (interval_str == nullptr || strlen(interval_str) == 0) {
continue;
}
const uint16_t interval = atoi(interval_str);
intervals.set(msg_id, interval);
}
AP::FS().close(f);
}
void GCS_MAVLINK::initialise_message_intervals_from_config_files()
{
static const char *path_templates[] {
"@ROMFS/message-intervals-chan%u.txt",
"message-intervals-chan%u.txt"
};
// don't do anything at all if no files exist:
bool exists = false;
for (const char * path_template : path_templates) {
struct stat stats;
char *path;
if (asprintf(&path, path_template, chan) == -1) {
continue;
}
if (AP::FS().stat(path, &stats) < 0) {
free(path);
continue;
}
free(path);
if (stats.st_size == 0) {
continue;
}
exists = true;
break;
}
if (!exists) {
return;
}
// first over-allocate:
DefaultIntervalsFromFiles *overallocated = new DefaultIntervalsFromFiles(128);
if (overallocated == nullptr) {
return;
}
for (const char * path_template : path_templates) {
char *path;
if (asprintf(&path, path_template, chan) == -1) {
continue;
}
get_intervals_from_filepath(path, *overallocated);
free(path);
}
// then allocate just the right number and redo all of the work:
const uint16_t num_required = overallocated->num_intervals();
delete overallocated;
overallocated = nullptr;
default_intervals_from_files = new DefaultIntervalsFromFiles(num_required);
if (default_intervals_from_files == nullptr) {
return;
}
for (const char * path_template : path_templates) {
char *path;
if (asprintf(&path, path_template, chan) == -1) {
continue;
}
get_intervals_from_filepath(path, *default_intervals_from_files);
free(path);
}
// now actually initialise the intervals:
for (uint8_t i=0; i<default_intervals_from_files->num_intervals(); i++) {
const ap_message id = default_intervals_from_files->id_at(i);
if (id == MSG_LAST) {
// internal error
break;
}
const uint16_t interval = default_intervals_from_files->interval_at(i);
set_ap_message_interval(id, interval);
}
}
#endif
void GCS_MAVLINK::initialise_message_intervals_from_streamrates() void GCS_MAVLINK::initialise_message_intervals_from_streamrates()
{ {
// this is O(n^2), but it's once at boot and across a 10-entry list... // this is O(n^2), but it's once at boot and across a 10-entry list...
@ -5276,6 +5458,15 @@ bool GCS_MAVLINK::get_default_interval_for_ap_message(const ap_message id, uint1
return true; return true;
} }
#if HAL_MAVLINK_INTERVALS_FROM_FILES_ENABLED
// a user can specify default rates in files, which are read close
// to vehicle startup
if (default_intervals_from_files != nullptr &&
default_intervals_from_files->get_interval_for_ap_message_id(id, interval)) {
return true;
}
#endif
// find which stream this ap_message is in // find which stream this ap_message is in
for (uint8_t i=0; all_stream_entries[i].ap_message_ids != nullptr; i++) { for (uint8_t i=0; all_stream_entries[i].ap_message_ids != nullptr; i++) {
const GCS_MAVLINK::stream_entries &entries = all_stream_entries[i]; const GCS_MAVLINK::stream_entries &entries = all_stream_entries[i];