15#define MAVLINK_UNKNOWN_METERS -1000.0f
16#define MAVLINK_UNKNOWN_LAT 0
17#define MAVLINK_UNKNOWN_LON 0
18#define SENDING_RATE_MSEC 1000
19#define ALLOWED_GPS_DELAY 5000
20#define RID_TIMEOUT 2500
22const uint8_t* RemoteIDManager::_id_or_mac_unknown =
new uint8_t[MAVLINK_MSG_OPEN_DRONE_ID_OPERATOR_ID_FIELD_ID_OR_MAC_LEN]();
28 , _armStatusGoodToArm (false)
29 , _ridDeviceCommsGood (false)
30 , _gcsPositionUsable (false)
31 , _vehicleReportsBasicIDMissing(false)
32 , _emergencyDeclared (false)
34 , _targetComponent (0)
35 , _enforceSendingSelfID (false)
40 _odidTimeoutTimer.setSingleShot(
true);
42 connect(&_odidTimeoutTimer, &QTimer::timeout,
this, &RemoteIDManager::_odidTimeout);
46 connect(&_sendMessagesTimer, &QTimer::timeout,
this, &RemoteIDManager::_sendMessages);
49 _targetSystem = _vehicle->
id();
50 _targetComponent = _vehicle->
compId();
55 switch (message.msgid) {
57 case MAVLINK_MSG_ID_OPEN_DRONE_ID_ARM_STATUS:
58 _handleArmStatus(message);
65void RemoteIDManager::_odidTimeout()
67 _ridDeviceCommsGood =
false;
68 _sendMessagesTimer.stop();
70 qCDebug(RemoteIDManagerLog) <<
"We stopped receiving heartbeat from RID device.";
77 if ( (message.compid < MAV_COMP_ID_ODID_TXRX_1) || (message.compid > MAV_COMP_ID_ODID_TXRX_3) ) {
79 if (message.compid != MAV_COMP_ID_AUTOPILOT1) {
85 if (_vehicle->
id() != message.sysid) {
92 qCDebug(RemoteIDManagerLog) <<
"Receiving ODID_ARM_STATUS for first time. Mavlink Open Drone ID support is available.";
96 if (_targetSystem != message.sysid) {
97 _targetSystem = message.sysid;
98 qCDebug(RemoteIDManagerLog) <<
"Subscribing to ODID messages coming from system " << _targetSystem;
101 if (!_ridDeviceCommsGood) {
102 _ridDeviceCommsGood =
true;
103 _sendMessagesTimer.start();
105 qCDebug(RemoteIDManagerLog) <<
"Receiving ODID_ARM_STATUS from RID device";
109 _odidTimeoutTimer.start();
112 mavlink_open_drone_id_arm_status_t armStatus;
113 mavlink_msg_open_drone_id_arm_status_decode(&message, &armStatus);
115 if (armStatus.status == MAV_ODID_ARM_STATUS_GOOD_TO_ARM) {
117 if (_vehicleReportsBasicIDMissing) {
118 _vehicleReportsBasicIDMissing =
false;
122 if (!_armStatusError.isEmpty()) {
123 _armStatusError.clear();
126 if (!_armStatusGoodToArm) {
127 _armStatusGoodToArm =
true;
129 qCDebug(RemoteIDManagerLog) <<
"Arm status GOOD TO ARM.";
133 if (armStatus.status == MAV_ODID_ARM_STATUS_PRE_ARM_FAIL_GENERIC) {
134 if (_armStatusGoodToArm) {
135 _armStatusGoodToArm =
false;
139 const QString
armStatusError = QString::fromUtf8(armStatus.error, qstrnlen(armStatus.error,
sizeof(armStatus.error)));
142 const bool basicIDMissing = (
armStatusError == QStringLiteral(
"missing basic_id message"));
143 if (_vehicleReportsBasicIDMissing != basicIDMissing) {
144 _vehicleReportsBasicIDMissing = basicIDMissing;
145 if (basicIDMissing) {
146 qCDebug(RemoteIDManagerLog) <<
"Arm status error, basic_id is not set in RID device nor in GCS!";
153 qCDebug(RemoteIDManagerLog) <<
"Arm status error:" << _armStatusError;
159void RemoteIDManager::_sendMessages()
165 if (_settings->
basicIDValid() && _settings->sendBasicID()->rawValue().toBool()) {
171 if (_settings->sendSelfID()->rawValue().toBool() || _emergencyDeclared || _enforceSendingSelfID) {
183void RemoteIDManager::_sendSelfIDMsg()
190 const QByteArray selfIdDescription = _getSelfIDDescription();
194 sharedLink->mavlinkChannel(),
199 _emergencyDeclared ? 1 : _settings->selfIDType()->rawValue().toInt(),
200 selfIdDescription.constData());
206QByteArray RemoteIDManager::_getSelfIDDescription()
const
208 QString descriptionToSend;
210 if (_emergencyDeclared) {
212 descriptionToSend = _settings->selfIDEmergency()->rawValue().toString();
214 switch (_settings->selfIDType()->rawValue().toInt()) {
216 descriptionToSend = _settings->selfIDFree()->rawValue().toString();
219 descriptionToSend = _settings->selfIDEmergency()->rawValue().toString();
222 descriptionToSend = _settings->selfIDExtended()->rawValue().toString();
225 descriptionToSend = _settings->selfIDEmergency()->rawValue().toString();
229 QByteArray descriptionBuffer = descriptionToSend.toLocal8Bit();
230 descriptionBuffer.resize(MAVLINK_MSG_OPEN_DRONE_ID_SELF_ID_FIELD_DESCRIPTION_LEN,
'\0');
231 return descriptionBuffer;
234void RemoteIDManager::_sendOperatorID()
244 Fact*
const operatorIDFact = isEURegion ? _settings->operatorIDEU() : _settings->operatorIDFAA();
245 QByteArray bytesOperatorID = operatorIDFact->
rawValue().toString().toLocal8Bit();
246 bytesOperatorID.resize(MAVLINK_MSG_OPEN_DRONE_ID_OPERATOR_ID_FIELD_OPERATOR_ID_LEN,
'\0');
248 mavlink_msg_open_drone_id_operator_id_pack_chan(
251 sharedLink->mavlinkChannel(),
256 _settings->operatorIDType()->rawValue().toInt(),
257 bytesOperatorID.constData());
263void RemoteIDManager::_updateGcsPositionStatus(
bool usable,
const QString&
error)
265 if (!
error.isEmpty() && _gcsPositionError !=
error) {
266 _gcsPositionError =
error;
267 qCWarning(RemoteIDManagerLog) <<
"GCS GPS error:" <<
error;
269 if (_gcsPositionUsable != usable) {
270 _gcsPositionUsable = usable;
272 _gcsPositionError.clear();
278void RemoteIDManager::_sendSystem()
280 QGeoCoordinate gcsPosition(0, 0, 0);
281 const uint32_t locationType = _settings->locationType()->rawValue().toUInt();
287 const double lat = _settings->latitudeFixed()->rawValue().toDouble();
288 const double lon = _settings->longitudeFixed()->rawValue().toDouble();
289 const double alt = _settings->altitudeFixed()->rawValue().toDouble();
292 if (lat >= -90.0 && lat <= 90.0 && lon >= -180.0 && lon <= 180.0) {
293 gcsPosition = QGeoCoordinate(lat, lon, alt);
294 _updateGcsPositionStatus(
true);
296 _updateGcsPositionStatus(
false,
"The provided coordinates for FIXED position are invalid.");
309 const QGeoCoordinate fixCoordinate = geoPositionInfo.coordinate();
310 if (fixCoordinate.type() == QGeoCoordinate::Coordinate3D) {
311 gcsPosition.setAltitude(fixCoordinate.altitude());
314 if (!geoPositionInfo.isValid()) {
317 _updateGcsPositionStatus(
false, gcsPositionTimestamp.isValid()
318 ? QStringLiteral(
"GCS GPS data is not valid.")
321 _updateGcsPositionStatus(
false, QString(
"GCS GPS data error: %1").arg(positionManager->
gcsPositioningError()));
322 }
else if (!gcsPosition.isValid() || gcsPosition.type() == QGeoCoordinate::InvalidCoordinate) {
323 _updateGcsPositionStatus(
false,
"GCS GPS data error: Invalid coordinate type.");
326 _updateGcsPositionStatus(
false,
"GCS GPS data error: Altitude data is mandatory for FAA regions.");
327 }
else if (!gcsPositionTimestamp.isValid() || (gcsPositionTimestamp.msecsTo(QDateTime::currentDateTimeUtc()) >
ALLOWED_GPS_DELAY)) {
328 _updateGcsPositionStatus(
false,
"GCS GPS data is older than 5 seconds");
330 _updateGcsPositionStatus(
true);
342 sharedLink->mavlinkChannel(),
347 _settings->locationType()->rawValue().toUInt(),
348 _settings->classificationType()->rawValue().toUInt(),
355 _settings->categoryEU()->rawValue().toUInt(),
356 _settings->classEU()->rawValue().toUInt(),
359 _vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
364uint32_t RemoteIDManager::_timestamp2019()
366 uint32_t secsSinceEpoch2019 = 1546300800;
368 return ((QDateTime::currentDateTime().currentSecsSinceEpoch()) - secsSinceEpoch2019);
371void RemoteIDManager::_sendBasicID()
379 QString basicIDTemp = _settings->basicID()->rawValue().toString();
380 QByteArray ba = basicIDTemp.toLocal8Bit();
382 ba.resize(MAVLINK_MSG_OPEN_DRONE_ID_BASIC_ID_FIELD_UAS_ID_LEN,
'\0');
386 sharedLink->mavlinkChannel(),
391 _settings->basicIDType()->rawValue().toUInt(),
392 _settings->basicIDUaType()->rawValue().toUInt(),
393 reinterpret_cast<const unsigned char*
>(ba.constData())),
401 _emergencyDeclared = declare;
406 _enforceSendingSelfID =
true;
408 qCDebug(RemoteIDManagerLog) << ( declare ?
"Emergency declared." :
"Emergency cleared.");
std::shared_ptr< LinkInterface > SharedLinkInterfacePtr
std::weak_ptr< LinkInterface > WeakLinkInterfacePtr
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
#define MAVLINK_UNKNOWN_LAT
#define SENDING_RATE_MSEC
#define MAVLINK_UNKNOWN_METERS
#define ALLOWED_GPS_DELAY
#define MAVLINK_UNKNOWN_LON
A Fact is used to hold a single value within the system.
QVariant rawValue() const
static int getComponentId()
static MAVLinkProtocol * instance()
QGeoPositionInfo geoPositionInfo() const
static QGCPositionManager * instance()
QDateTime gcsPositionTimestamp() const
QGeoCoordinate gcsPosition() const
QGeoPositionInfoSource::Error gcsPositioningError() const
void mavlinkMessageReceived(mavlink_message_t &message)
void vehicleReportsBasicIDMissingChanged()
Q_INVOKABLE void setEmergency(bool declare)
void armStatusErrorChanged()
QString armStatusError(void) const
void ridDeviceCommsGoodChanged()
void armStatusGoodToArmChanged()
void emergencyDeclaredChanged()
RemoteIDManager(Vehicle *vehicle)
true: RID device reports MAV_ODID_ARM_STATUS_GOOD_TO_ARM
void gcsPositionUsableChanged()
bool operatorIDValidForRegion() const
bool basicIDValid() const
true: the basic ID entered in settings is complete enough to broadcast
static SettingsManager * instance()
RemoteIDSettings * remoteIDSettings() const
WeakLinkInterfacePtr primaryLink() const
VehicleLinkManager * vehicleLinkManager()
bool sendMessageOnLinkThreadSafe(LinkInterface *link, mavlink_message_t message)