QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
TerrainProtocolHandler.cc
Go to the documentation of this file.
2#include "TerrainFactGroup.h"
3#include "TerrainQuery.h"
4#include "Vehicle.h"
6#include "MAVLinkProtocol.h"
8
9#include <QtCore/QTimer>
10
11QGC_LOGGING_CATEGORY(TerrainProtocolHandlerLog, "Vehicle.TerrainProtocolHandler")
12
13TerrainProtocolHandler::TerrainProtocolHandler(Vehicle *vehicle, TerrainFactGroup *terrainFactGroup, QObject *parent)
14 : QObject(parent)
15 , _vehicle(vehicle)
16 , _terrainFactGroup(terrainFactGroup)
17 , _terrainDataSendTimer(new QTimer(this))
18{
19 // qCDebug(TerrainProtocolHandlerLog) << Q_FUNC_INFO << this;
20
21 _terrainDataSendTimer->setSingleShot(false);
22 _terrainDataSendTimer->setInterval(1000.0/12.0);
23 (void) connect(_terrainDataSendTimer, &QTimer::timeout, this, &TerrainProtocolHandler::_sendNextTerrainData);
24}
25
27{
28 // qCDebug(TerrainProtocolHandlerLog) << Q_FUNC_INFO << this;
29}
30
32{
33 switch (message.msgid) {
34 case MAVLINK_MSG_ID_TERRAIN_REQUEST:
35 _handleTerrainRequest(message);
36 return false;
37 case MAVLINK_MSG_ID_TERRAIN_REPORT:
38 _handleTerrainReport(message);
39 return false;
40 default:
41 return true;
42 }
43}
44
45void TerrainProtocolHandler::_handleTerrainRequest(const mavlink_message_t &message)
46{
47 _terrainRequestActive = true;
48 mavlink_msg_terrain_request_decode(&message, &_currentTerrainRequest);
49 _sendNextTerrainData();
50}
51
52void TerrainProtocolHandler::_handleTerrainReport(const mavlink_message_t &message)
53{
54 mavlink_terrain_report_t terrainReport;
55 mavlink_msg_terrain_report_decode(&message, &terrainReport);
56
57 _terrainFactGroup->blocksPending()->setRawValue(terrainReport.pending);
58 _terrainFactGroup->blocksLoaded()->setRawValue(terrainReport.loaded);
59
60 if (TerrainProtocolHandlerLog().isDebugEnabled()) {
61 bool error;
62 QList<double> altitudes;
63 QList<QGeoCoordinate> coordinates;
64 QGeoCoordinate coord(static_cast<double>(terrainReport.lat) / 1e7, static_cast<double>(terrainReport.lon) / 1e7);
65 (void) coordinates.append(coord);
66 const bool altAvailable = TerrainAtCoordinateQuery::getAltitudesForCoordinates(coordinates, altitudes, error);
67 const QString vehicleAlt = terrainReport.spacing ? QStringLiteral("%1").arg(terrainReport.terrain_height) : QStringLiteral("n/a");
68 QString qgcAlt;
69 if (error) {
70 qgcAlt = QStringLiteral("Error");
71 } else if (altAvailable && !altitudes.isEmpty()) {
72 qgcAlt = QStringLiteral("%1").arg(altitudes[0]);
73 } else {
74 qgcAlt = QStringLiteral("N/A");
75 }
76 qCDebug(TerrainProtocolHandlerLog) << "TERRAIN_REPORT" << coord << QStringLiteral("Vehicle(%1) QGC(%2)").arg(vehicleAlt).arg(qgcAlt);
77 }
78}
79
80void TerrainProtocolHandler::_sendNextTerrainData()
81{
82 if (!_terrainRequestActive) {
83 return;
84 }
85
86 QGeoCoordinate terrainRequestCoordSWCorner(static_cast<double>(_currentTerrainRequest.lat) / 1e7, static_cast<double>(_currentTerrainRequest.lon) / 1e7);
87 const int spacingBetweenGrids = _currentTerrainRequest.grid_spacing * 4;
88
89 // Each TERRAIN_DATA sent to vehicle contains a 4x4 grid of heights
90 // TERRAIN_REQUEST.mask has a bit for each entry in an 8x7 grid
91 // gridBit = 0 refers to the the sw corner of the 8x7 grid
92
93 bool bitFound = false;
94 for (int rowIndex=0; rowIndex<7; rowIndex++) {
95 for (int colIndex=0; colIndex<8; colIndex++) {
96 const uint8_t gridBit = (rowIndex * 8) + colIndex;
97 const uint64_t checkBit = 1ull << gridBit;
98 if (_currentTerrainRequest.mask & checkBit) {
99 // Move east and then north to generate the coordinate for sw corner of the specific gridBit
100 QGeoCoordinate swCorner = terrainRequestCoordSWCorner.atDistanceAndAzimuth(spacingBetweenGrids * colIndex, 90);
101 swCorner = swCorner.atDistanceAndAzimuth(spacingBetweenGrids * rowIndex, 0);
102 _sendTerrainData(swCorner, gridBit);
103 bitFound = true;
104 break;
105 }
106 }
107
108 if (bitFound) {
109 break;
110 }
111 }
112
113 if (bitFound) {
114 // Kick timer to send next possible TERRAIN_DATA to vehicle
115 _terrainDataSendTimer->start();
116 } else {
117 _terrainRequestActive = false;
118 }
119}
120
121void TerrainProtocolHandler::_sendTerrainData(const QGeoCoordinate &swCorner, uint8_t gridBit)
122{
123 QList<QGeoCoordinate> coordinates;
124 for (int rowIndex=0; rowIndex<4; rowIndex++) {
125 for (int colIndex=0; colIndex<4; colIndex++) {
126 // Move east and then north to generate the coordinate for grid point
127 QGeoCoordinate coord = swCorner.atDistanceAndAzimuth(_currentTerrainRequest.grid_spacing * colIndex, 90);
128 coord = coord.atDistanceAndAzimuth(_currentTerrainRequest.grid_spacing * rowIndex, 0);
129 coordinates.append(coord);
130 }
131 }
132
133 // Query terrain system for altitudes. If it has them available it will return them. If not they will be queued for download.
134 bool error = false;
135 QList<double> altitudes;
136 if (!TerrainAtCoordinateQuery::getAltitudesForCoordinates(coordinates, altitudes, error)) {
137 return;
138 }
139
140 if (error) {
141 qCWarning(TerrainProtocolHandlerLog) << Q_FUNC_INFO << "TerrainAtCoordinateQuery::getAltitudesForCoordinates failed";
142 return;
143 }
144
145 // Only clear the bit if the query succeeds. Otherwise just let it try again on the next timer tick
146 const uint64_t removeBit = ~(1ull << gridBit);
147 _currentTerrainRequest.mask &= removeBit;
148 int altIndex = 0;
149 int16_t terrainData[16];
150 for (const double& altitude : altitudes) {
151 terrainData[altIndex++] = static_cast<int16_t>(altitude);
152 }
153
154 SharedLinkInterfacePtr sharedLink = _vehicle->vehicleLinkManager()->primaryLink().lock();
155 if (sharedLink) {
157 (void) mavlink_msg_terrain_data_pack_chan(
160 sharedLink->mavlinkChannel(),
161 &msg,
162 _currentTerrainRequest.lat,
163 _currentTerrainRequest.lon,
164 _currentTerrainRequest.grid_spacing,
165 gridBit,
166 terrainData
167 );
168
169 _vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
170 }
171}
std::shared_ptr< LinkInterface > SharedLinkInterfacePtr
Error error
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void setRawValue(const QVariant &value)
Definition Fact.cc:128
static int getComponentId()
static MAVLinkProtocol * instance()
int getSystemId() const
static bool getAltitudesForCoordinates(const QList< QGeoCoordinate > &coordinates, QList< double > &altitudes, bool &error)
bool mavlinkMessageReceived(const mavlink_message_t &message)
WeakLinkInterfacePtr primaryLink() const
VehicleLinkManager * vehicleLinkManager()
Definition Vehicle.h:575
bool sendMessageOnLinkThreadSafe(LinkInterface *link, mavlink_message_t message)
Definition Vehicle.cc:1389