Newer
Older
MAVLinkDecoder::MAVLinkDecoder(MAVLinkProtocol* protocol) :
QThread(), creationThread(QThread::currentThread())
// We're doing it wrong - because the Qt folks got the API wrong:
// http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
moveToThread(this);
lm
committed
// Fill filter
// Allow system status
// messageFilter.insert(MAVLINK_MSG_ID_HEARTBEAT, false);
// messageFilter.insert(MAVLINK_MSG_ID_SYS_STATUS, false);
lm
committed
messageFilter.insert(MAVLINK_MSG_ID_STATUSTEXT, false);
lm
committed
messageFilter.insert(MAVLINK_MSG_ID_COMMAND_LONG, false);
lm
committed
messageFilter.insert(MAVLINK_MSG_ID_COMMAND_ACK, false);
messageFilter.insert(MAVLINK_MSG_ID_PARAM_SET, false);
messageFilter.insert(MAVLINK_MSG_ID_PARAM_VALUE, false);
messageFilter.insert(MAVLINK_MSG_ID_MISSION_ITEM, false);
messageFilter.insert(MAVLINK_MSG_ID_MISSION_COUNT, false);
messageFilter.insert(MAVLINK_MSG_ID_MISSION_ACK, false);
messageFilter.insert(MAVLINK_MSG_ID_DATA_STREAM, false);
messageFilter.insert(MAVLINK_MSG_ID_GPS_STATUS, false);
messageFilter.insert(MAVLINK_MSG_ID_RC_CHANNELS_RAW, false);
messageFilter.insert(MAVLINK_MSG_ID_LOG_DATA, false);
messageFilter.insert(MAVLINK_MSG_ID_ENCAPSULATED_DATA, false);
#endif
#ifdef MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE
messageFilter.insert(MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, false);
messageFilter.insert(MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, false);
lm
committed
textMessageFilter.insert(MAVLINK_MSG_ID_DEBUG, false);
textMessageFilter.insert(MAVLINK_MSG_ID_DEBUG_VECT, false);
textMessageFilter.insert(MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, false);
textMessageFilter.insert(MAVLINK_MSG_ID_NAMED_VALUE_INT, false);
// textMessageFilter.insert(MAVLINK_MSG_ID_HIGHRES_IMU, false);
connect(protocol, &MAVLinkProtocol::messageReceived, this, &MAVLinkDecoder::receiveMessage);
connect(this, &MAVLinkDecoder::finish, this, &QThread::quit);
}
/**
* @brief Runs the thread
*
**/
void MAVLinkDecoder::run()
{
exec();
moveToThread(creationThread);
}
void MAVLinkDecoder::receiveMessage(LinkInterface* link,mavlink_message_t message)
{
Q_UNUSED(link);
const mavlink_message_info_t* msgInfo = mavlink_get_message_info(&message);
if(!msgInfo) {
qWarning() << "Invalid MAVLink message received. ID:" << msgid;
return;
}
msgDict[message.msgid] = message;
// Store an arrival time for this message. This value ends up being calculated later.
quint64 time = 0;
// The SYSTEM_TIME message is special, in that it's handled here for synchronizing the QGC time with the remote time.
Jessica
committed
if (message.msgid == MAVLINK_MSG_ID_SYSTEM_TIME)
mavlink_system_time_t timebase;
mavlink_msg_system_time_decode(&message, &timebase);
sysDict[msgid].onboardTimeOffset = (timebase.time_unix_usec+500)/1000 - timebase.time_boot_ms;
sysDict[msgid].onboardToGCSUnixTimeOffsetAndDelay = static_cast<qint64>(QGC::groundTimeMilliseconds() - (timebase.time_unix_usec+500)/1000);
// See if first value is a time value and if it is, use that as the arrival time for this data.
uint8_t* m = (uint8_t*)(msgDict[msgid].payload64);
if (QString(msgInfo->fields[fieldid].name) == QString("time_boot_ms") && msgInfo->fields[fieldid].type == MAVLINK_TYPE_UINT32_T)
time = *((quint32*)(m+msgInfo->fields[fieldid].wire_offset));
else if (QString(msgInfo->fields[fieldid].name).contains("usec") && msgInfo->fields[fieldid].type == MAVLINK_TYPE_UINT64_T)
time = *((quint64*)(m+msgInfo->fields[fieldid].wire_offset));
time = (time+500)/1000; // Scale to milliseconds, round up/down correctly
// Align UAS time to global time
time = getUnixTimeFromMs(message.sysid, time);
// Send out all field values for this message
{
emitFieldValue(&message, i, time);
}
// Send out combined math expressions
// FIXME XXX TODO
}
quint64 MAVLinkDecoder::getUnixTimeFromMs(int systemID, quint64 time)
Bryant
committed
{
ret = QGC::groundTimeMilliseconds() - sysDict[systemID].onboardToGCSUnixTimeOffsetAndDelay;
}
// Check if time is smaller than 40 years,
// assuming no system without Unix timestamp
// runs longer than 40 years continuously without
// reboot. In worst case this will add/subtract the
// communication delay between GCS and MAV,
// it will never alter the timestamp in a safety
// critical way.
//
// Calculation:
// 40 years
// 365 days
// 24 hours
// 60 minutes
// 60 seconds
// 1000 milliseconds
// 1000 microseconds
#ifndef _MSC_VER
else if (time < 1261440000000LLU)
#else
else if (time < 1261440000000)
#endif
{
if (sysDict[systemID].onboardTimeOffset == 0 || time < (sysDict[systemID].firstOnboardTime -100))
sysDict[systemID].firstOnboardTime = time;
sysDict[systemID].onboardTimeOffset = QGC::groundTimeMilliseconds() - time;
if (time > sysDict[systemID].firstOnboardTime ) sysDict[systemID].firstOnboardTime = time;
ret = time + sysDict[systemID].onboardTimeOffset;
}
else
{
// Time is not zero and larger than 40 years -> has to be
// a Unix epoch timestamp. Do nothing.
ret = time;
}
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// // Check if the offset estimation likely went wrong
// // and we're talking to a new instance / the system
// // has rebooted. Only reset if this is consistent.
// if (!isNull && lastNonNullTime > ret)
// {
// onboardTimeOffsetInvalidCount++;
// }
// else if (!isNull && lastNonNullTime < ret)
// {
// onboardTimeOffsetInvalidCount = 0;
// }
// // Reset onboard time offset estimation, since it seems to be really off
// if (onboardTimeOffsetInvalidCount > 20)
// {
// onboardTimeOffset = 0;
// onboardTimeOffsetInvalidCount = 0;
// lastNonNullTime = 0;
// qDebug() << "RESETTET ONBOARD TIME OFFSET";
// }
// // If we're progressing in time, set it
// // else wait for the reboot detection to
// // catch the timestamp wrap / reset
// if (!isNull && (lastNonNullTime < ret)) {
// lastNonNullTime = ret;
// }
void MAVLinkDecoder::emitFieldValue(mavlink_message_t* msg, int fieldid, quint64 time)
{
bool multiComponentSourceDetected = false;
const mavlink_message_info_t* msgInfo = mavlink_get_message_info(msg);
uint32_t msgid = msg->msgid;
// create new system data if it wasn't dectected yet
if (!(sysDict.keys().contains(msgid))) {
sysDict[msgid] = SystemData();
}
// Store component ID
sysDict[msgid].componentID = msg->compid;
}
else
{
// Got this message already
if (sysDict[msgid].componentID != msg->compid)
if (sysDict[msgid].componentMulti == true) {
multiComponentSourceDetected = true;
}
if (messageFilter.contains(msgid)) return;
uint8_t* m = (uint8_t*)(msgDict[msgid].payload64);
// Debug vector messages
if (msgid == MAVLINK_MSG_ID_DEBUG_VECT)
{
mavlink_debug_vect_t debug;
mavlink_msg_debug_vect_decode(msg, &debug);
Lorenz Meier
committed
char buf[11];
strncpy(buf, debug.name, 10);
buf[10] = '\0';
name = QString("%1.%2").arg(buf).arg(fieldName);
time = getUnixTimeFromMs(msg->sysid, (debug.time_usec+500)/1000); // Scale to milliseconds, round up/down correctly
else if (msgid == MAVLINK_MSG_ID_DEBUG)
{
mavlink_debug_t debug;
mavlink_msg_debug_decode(msg, &debug);
name = name.arg(QString("debug")).arg(debug.ind);
time = getUnixTimeFromMs(msg->sysid, debug.time_boot_ms);
}
else if (msgid == MAVLINK_MSG_ID_NAMED_VALUE_FLOAT)
{
mavlink_named_value_float_t debug;
mavlink_msg_named_value_float_decode(msg, &debug);
Lorenz Meier
committed
char buf[11];
strncpy(buf, debug.name, 10);
buf[10] = '\0';
name = QString(buf);
time = getUnixTimeFromMs(msg->sysid, debug.time_boot_ms);
}
else if (msgid == MAVLINK_MSG_ID_NAMED_VALUE_INT)
{
mavlink_named_value_int_t debug;
mavlink_msg_named_value_int_decode(msg, &debug);
Lorenz Meier
committed
char buf[11];
strncpy(buf, debug.name, 10);
buf[10] = '\0';
name = QString(buf);
time = getUnixTimeFromMs(msg->sysid, debug.time_boot_ms);
else if (msgid == MAVLINK_MSG_ID_RC_CHANNELS_RAW)
{
// XXX this is really ugly, but we do not know a better way to do this
mavlink_rc_channels_raw_t raw;
mavlink_msg_rc_channels_raw_decode(msg, &raw);
name.prepend(QString("port%1_").arg(raw.port));
}
else if (msgid == MAVLINK_MSG_ID_RC_CHANNELS_SCALED)
{
// XXX this is really ugly, but we do not know a better way to do this
mavlink_rc_channels_scaled_t scaled;
mavlink_msg_rc_channels_scaled_decode(msg, &scaled);
name.prepend(QString("port%1_").arg(scaled.port));
}
else if (msgid == MAVLINK_MSG_ID_SERVO_OUTPUT_RAW)
{
// XXX this is really ugly, but we do not know a better way to do this
mavlink_servo_output_raw_t servo;
mavlink_msg_servo_output_raw_decode(msg, &servo);
name.prepend(QString("port%1_").arg(servo.port));
}
if (multiComponentSourceDetected)
{
name = name.prepend(QString("C%1:").arg(msg->compid));
name = name.prepend(QString("M%1:").arg(msg->sysid));
char* str = (char*)(m+msgInfo->fields[fieldid].wire_offset);
if (!textMessageFilter.contains(msgid)) emit textMessageReceived(msg->sysid, msg->compid, MAV_SEVERITY_INFO, string);
char b = *((char*)(m+msgInfo->fields[fieldid].wire_offset));
unit = QString("char[%1]").arg(msgInfo->fields[fieldid].array_length);
emit valueChanged(msg->sysid, name, unit, b, time);
}
break;
case MAVLINK_TYPE_UINT8_T:
uint8_t* nums = m+msgInfo->fields[fieldid].wire_offset;
fieldType = QString("uint8_t[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
{
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, nums[j], time);
}
}
else
{
// Single value
fieldType = "uint8_t";
emit valueChanged(msg->sysid, name, fieldType, u, time);
}
break;
case MAVLINK_TYPE_INT8_T:
int8_t* nums = (int8_t*)(m+msgInfo->fields[fieldid].wire_offset);
fieldType = QString("int8_t[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
{
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, nums[j], time);
}
}
else
{
// Single value
int8_t n = *((int8_t*)(m+msgInfo->fields[fieldid].wire_offset));
fieldType = "int8_t";
emit valueChanged(msg->sysid, name, fieldType, n, time);
}
break;
case MAVLINK_TYPE_UINT16_T:
uint16_t* nums = (uint16_t*)(m+msgInfo->fields[fieldid].wire_offset);
fieldType = QString("uint16_t[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
{
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, nums[j], time);
}
}
else
{
// Single value
uint16_t n = *((uint16_t*)(m+msgInfo->fields[fieldid].wire_offset));
fieldType = "uint16_t";
emit valueChanged(msg->sysid, name, fieldType, n, time);
}
break;
case MAVLINK_TYPE_INT16_T:
int16_t* nums = (int16_t*)(m+msgInfo->fields[fieldid].wire_offset);
fieldType = QString("int16_t[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
{
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, nums[j], time);
}
}
else
{
// Single value
int16_t n = *((int16_t*)(m+msgInfo->fields[fieldid].wire_offset));
fieldType = "int16_t";
emit valueChanged(msg->sysid, name, fieldType, n, time);
}
break;
case MAVLINK_TYPE_UINT32_T:
uint32_t* nums = (uint32_t*)(m+msgInfo->fields[fieldid].wire_offset);
fieldType = QString("uint32_t[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
{
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, nums[j], time);
}
}
else
{
// Single value
uint32_t n = *((uint32_t*)(m+msgInfo->fields[fieldid].wire_offset));
fieldType = "uint32_t";
emit valueChanged(msg->sysid, name, fieldType, n, time);
}
break;
case MAVLINK_TYPE_INT32_T:
int32_t* nums = (int32_t*)(m+msgInfo->fields[fieldid].wire_offset);
fieldType = QString("int32_t[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
{
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, nums[j], time);
}
}
else
{
// Single value
int32_t n = *((int32_t*)(m+msgInfo->fields[fieldid].wire_offset));
fieldType = "int32_t";
emit valueChanged(msg->sysid, name, fieldType, n, time);
}
break;
case MAVLINK_TYPE_FLOAT:
float* nums = (float*)(m+msgInfo->fields[fieldid].wire_offset);
fieldType = QString("float[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, (float)(nums[j]), time);
float f = *((float*)(m+msgInfo->fields[fieldid].wire_offset));
fieldType = "float";
emit valueChanged(msg->sysid, name, fieldType, f, time);
}
break;
case MAVLINK_TYPE_DOUBLE:
double* nums = (double*)(m+msgInfo->fields[fieldid].wire_offset);
fieldType = QString("double[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
{
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, nums[j], time);
}
}
else
{
// Single value
double f = *((double*)(m+msgInfo->fields[fieldid].wire_offset));
fieldType = "double";
emit valueChanged(msg->sysid, name, fieldType, f, time);
}
break;
case MAVLINK_TYPE_UINT64_T:
uint64_t* nums = (uint64_t*)(m+msgInfo->fields[fieldid].wire_offset);
fieldType = QString("uint64_t[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, (quint64) nums[j], time);
uint64_t n = *((uint64_t*)(m+msgInfo->fields[fieldid].wire_offset));
emit valueChanged(msg->sysid, name, fieldType, (quint64) n, time);
int64_t* nums = (int64_t*)(m+msgInfo->fields[fieldid].wire_offset);
fieldType = QString("int64_t[%1]").arg(msgInfo->fields[fieldid].array_length);
for (unsigned int j = 0; j < msgInfo->fields[fieldid].array_length; ++j)
emit valueChanged(msg->sysid, QString("%1.%2").arg(name).arg(j), fieldType, (qint64) nums[j], time);
int64_t n = *((int64_t*)(m+msgInfo->fields[fieldid].wire_offset));
emit valueChanged(msg->sysid, name, fieldType, (qint64) n, time);
default:
qDebug() << "WARNING: UNKNOWN MAVLINK TYPE";