File indexing completed on 2024-04-28 03:50:06
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2012 Ralf Habacker <ralf.habacker@freenet.de> 0004 // 0005 0006 #include "FlightGearPositionProviderPlugin.h" 0007 0008 #include "MarbleDebug.h" 0009 #include <cmath> 0010 0011 #include <QUdpSocket> 0012 #include <QIcon> 0013 0014 using namespace Marble; 0015 /* TRANSLATOR Marble::FlightGearPositionProviderPlugin */ 0016 0017 using namespace std; 0018 0019 FlightGearPositionProviderPlugin::FlightGearPositionProviderPlugin() 0020 : m_socket(nullptr), m_speed( 0.0 ), m_track( 0.0 ) 0021 { 0022 } 0023 0024 FlightGearPositionProviderPlugin::~FlightGearPositionProviderPlugin() 0025 { 0026 delete m_socket; 0027 } 0028 0029 QString FlightGearPositionProviderPlugin::name() const 0030 { 0031 return tr( "FlightGear position provider Plugin" ); 0032 } 0033 0034 QString FlightGearPositionProviderPlugin::nameId() const 0035 { 0036 return QStringLiteral("flightgear"); 0037 } 0038 0039 QString FlightGearPositionProviderPlugin::guiString() const 0040 { 0041 return tr( "FlightGear" ); 0042 } 0043 0044 QString FlightGearPositionProviderPlugin::version() const 0045 { 0046 return QStringLiteral("1.0"); 0047 } 0048 0049 QString FlightGearPositionProviderPlugin::description() const 0050 { 0051 return tr( "Reports the position of running flightgear application." ); 0052 } 0053 0054 QString FlightGearPositionProviderPlugin::copyrightYears() const 0055 { 0056 return QStringLiteral("2012"); 0057 } 0058 0059 QVector<PluginAuthor> FlightGearPositionProviderPlugin::pluginAuthors() const 0060 { 0061 return QVector<PluginAuthor>() 0062 << PluginAuthor(QStringLiteral("Ralf Habacker"), QStringLiteral("ralf.habacker@freenet.de")); 0063 0064 } 0065 0066 QIcon FlightGearPositionProviderPlugin::icon() const 0067 { 0068 return QIcon(); 0069 } 0070 0071 void FlightGearPositionProviderPlugin::initialize() 0072 { 0073 m_status = PositionProviderStatusAcquiring; 0074 emit statusChanged( m_status ); 0075 0076 m_socket = new QUdpSocket(this); 0077 m_socket->bind(QHostAddress::Any, 5500); 0078 0079 connect(m_socket, SIGNAL(readyRead()), 0080 this, SLOT(readPendingDatagrams())); 0081 } 0082 0083 /** 0084 fixed case where wrong date format is used '2404112' instead of '240412' 0085 */ 0086 bool fixBadGPRMC(QByteArray &line) 0087 { 0088 if (!line.startsWith("$GPRMC")) 0089 return false; 0090 0091 QStringList parts = QString(line).split(QLatin1Char(',')); 0092 if (parts[9].size() == 7) { 0093 parts[9].remove(4,1); 0094 line = parts.join(QLatin1Char(',')).toLatin1(); 0095 // update crc 0096 int crc = 0; 0097 for(int i=1; i < line.size()-3; i++) { 0098 crc ^= (int) line[i]; 0099 } 0100 parts[11] = parts[11][0] + parts[11][1] + QString::number(crc, 16).toUpper(); 0101 0102 line = parts.join(QLatin1Char(',')).toLatin1(); 0103 return true; 0104 } 0105 return false; 0106 } 0107 0108 void FlightGearPositionProviderPlugin::readPendingDatagrams() 0109 { 0110 while (m_socket->hasPendingDatagrams()) { 0111 QByteArray datagram; 0112 datagram.resize(m_socket->pendingDatagramSize()); 0113 QHostAddress sender; 0114 quint16 senderPort; 0115 0116 m_socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); 0117 using Iterator = QList<QByteArray>::Iterator; 0118 QList<QByteArray> split = datagram.split('\n'); 0119 for (Iterator i = split.begin(); i != split.end(); i++) { 0120 fixBadGPRMC(*i); 0121 i->append( "\n" ); 0122 parseNmeaSentence( *i ); 0123 } 0124 } 0125 } 0126 0127 void FlightGearPositionProviderPlugin::parseNmeaSentence( const QString &sentence ) 0128 { 0129 PositionProviderStatus oldStatus = m_status; 0130 GeoDataCoordinates oldPosition = m_position; 0131 0132 if ( sentence.startsWith( QLatin1String( "$GPRMC" ) ) ) { 0133 QStringList const values = sentence.split(QLatin1Char(',')); 0134 if ( values.size() > 9 ) { 0135 if (values[2] == QLatin1String("A")) { 0136 m_speed = values[7].toDouble() * 0.514444; // knots => m/s 0137 m_track = values[8].toDouble(); 0138 QString const date = values[9] + QLatin1Char(' ') + values[1]; 0139 m_timestamp = QDateTime::fromString( date, "ddMMyy HHmmss" ); 0140 if (m_timestamp.date().year() <= 1930 && m_timestamp.date().year() >= 1900 ) { 0141 m_timestamp = m_timestamp.addYears( 100 ); // Qt range is 1900-1999 for two-digits 0142 } 0143 } 0144 // Flightgear submits geoposition twice in one datagram, once 0145 // in GPRMC and once in GPGGA. Parsing one is sufficient 0146 } 0147 } else if ( sentence.startsWith( QLatin1String( "$GPGGA" ) ) ) { 0148 QStringList const values = sentence.split(QLatin1Char(',')); 0149 if ( values.size() > 10 ) { 0150 if ( values[6] == nullptr ) { 0151 m_status = PositionProviderStatusAcquiring; // no fix 0152 } else { 0153 double const lat = parsePosition(values[2], values[3] == QLatin1String("S")); 0154 double const lon = parsePosition(values[4], values[5] == QLatin1String("W")); 0155 double const unitFactor = values[10] == QLatin1String("F") ? FT2M : 1.0; 0156 double const alt = unitFactor * values[9].toDouble(); 0157 m_position.set( lon, lat, alt, GeoDataCoordinates::Degree ); 0158 m_accuracy.level = GeoDataAccuracy::Detailed; 0159 m_status = PositionProviderStatusAvailable; 0160 } 0161 } 0162 } else { 0163 return; 0164 } 0165 0166 if ( m_status != oldStatus ) { 0167 emit statusChanged( m_status ); 0168 } 0169 if ( m_position != oldPosition && m_status == PositionProviderStatusAvailable ) { 0170 emit positionChanged( m_position, m_accuracy ); 0171 } 0172 } 0173 0174 double FlightGearPositionProviderPlugin::parsePosition( const QString &value, bool isNegative ) 0175 { 0176 double pos = value.toDouble(); 0177 pos = int( pos / 100.0 ) + ( pos - 100.0 * int( pos / 100.0 ) ) / 60.0; 0178 return isNegative ? -qAbs( pos ) : pos; 0179 } 0180 0181 bool FlightGearPositionProviderPlugin::isInitialized() const 0182 { 0183 return m_socket; 0184 } 0185 0186 PositionProviderPlugin* FlightGearPositionProviderPlugin::newInstance() const 0187 { 0188 return new FlightGearPositionProviderPlugin; 0189 } 0190 0191 PositionProviderStatus FlightGearPositionProviderPlugin::status() const 0192 { 0193 return m_status; 0194 } 0195 0196 GeoDataCoordinates FlightGearPositionProviderPlugin::position() const 0197 { 0198 return m_position; 0199 } 0200 0201 GeoDataAccuracy FlightGearPositionProviderPlugin::accuracy() const 0202 { 0203 return m_accuracy; 0204 } 0205 0206 qreal FlightGearPositionProviderPlugin::speed() const 0207 { 0208 return m_speed; 0209 } 0210 0211 qreal FlightGearPositionProviderPlugin::direction() const 0212 { 0213 return m_track; 0214 } 0215 0216 QDateTime FlightGearPositionProviderPlugin::timestamp() const 0217 { 0218 return m_timestamp; 0219 } 0220 0221 QString FlightGearPositionProviderPlugin::error() const 0222 { 0223 return QString(); 0224 } 0225 0226 #include "moc_FlightGearPositionProviderPlugin.cpp"