1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-27 02:09:14 -05:00
sdrangel/plugins/feature/map/beacon.h
Jon Beniston d381568437 Map updates.
Add support for taken and predicted ground tracks.
Support multiple beacons with same callsign at different locations.
Use separate QML for Qt 5.14, as 5.12 doesn't support autoFadeIn, needed
to view satellites at min zoom.
2021-02-26 20:30:59 +00:00

248 lines
9.9 KiB
C++

///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_BEACON_H
#define INCLUDE_BEACON_H
#include <stdio.h>
#include <string.h>
#include <QString>
#include <QList>
#include "util/units.h"
#include "util/maidenhead.h"
#include "../../channelrx/demodadsb/csv.h"
#define IARU_BEACONS_URL "https://iaru-r1-c5-beacons.org/wp-content/uploads/beacons.csv"
struct Beacon {
QString m_callsign;
quint64 m_frequency; // In Hz
QString m_locator;
float m_latitude;
float m_longitude;
float m_altitude; // In metres above sea-level
QString m_power; // In Watts - sometimes a string with extra infos
QString m_polarization; // H or V
QString m_pattern; // Omni or 30deg etc
QString m_key; // F1A, F1B
QString m_mgm; // Machine mode
QString getText()
{
QStringList list;
list.append("Beacon");
list.append(QString("Callsign: %1").arg(m_callsign));
list.append(QString("Frequency: %1").arg(getFrequencyText()));
if (!m_power.isEmpty())
list.append(QString("Power: %1 Watts ERP").arg(m_power));
if (!m_polarization.isEmpty())
list.append(QString("Polarization: %1").arg(m_polarization));
if (!m_pattern.isEmpty())
list.append(QString("Pattern: %1").arg(m_pattern));
if (!m_key.isEmpty())
list.append(QString("Key: %1").arg(m_key));
if (!m_mgm.isEmpty())
list.append(QString("MGM: %1").arg(m_mgm));
list.append(QString("Locator: %1").arg(m_locator));
return list.join("\n");
}
QString getFrequencyText()
{
if (m_frequency > 1000000000)
return QString("%1 GHz").arg(m_frequency/1000000000.0, 0, ',', 6);
else if (m_frequency > 1000000)
return QString("%1 MHz").arg(m_frequency/1000000.0, 0, ',', 3);
else
return QString("%1 kHz").arg(m_frequency/1000.0, 0, ',', 3);
}
QString getFrequencyShortText()
{
if (m_frequency > 1000000000)
return QString("%1G").arg(m_frequency/1000000000.0, 0, ',', 1);
else if (m_frequency > 1000000)
return QString("%1M").arg(std::floor(m_frequency/1000000.0), 0, ',', 0);
else
return QString("%1k").arg(std::floor(m_frequency/1000.0), 0, ',', 0);
}
// Uses ; rather than ,
static QList<Beacon *> *readIARUCSV(const QString &filename)
{
int cnt = 0;
QList<Beacon *> *beacons = nullptr;
// Column numbers used for the data as of 2021/1/20
int callsignCol = 0;
int qrgCol = 1;
int locatorCol = 2;
int heightCol = 5;
int patternCol = 7;
int polarizationCol = 9;
int powerCol = 10;
int keyCol = 11;
int mgmCol = 12;
FILE *file;
QByteArray utfFilename = filename.toUtf8();
if ((file = fopen(utfFilename.constData(), "r")) != nullptr)
{
char row[2048];
if (fgets(row, sizeof(row), file))
{
beacons = new QList<Beacon *>();
// Read header
int idx = 0;
char *p = strtok(row, ";");
while (p != nullptr)
{
if (!strcmp(p, "Callsign"))
callsignCol = idx;
else if (!strcmp(p, "QRG"))
qrgCol = idx;
else if (!strcmp(p, "Locator"))
locatorCol = idx;
else if (!strcmp(p, "Hight ASL") || !strcmp(p, "Height ASL"))
heightCol = idx;
else if (!strcmp(p, "Pattern"))
patternCol = idx;
else if (!strcmp(p, "H/V"))
polarizationCol = idx;
else if (!strcmp(p, "Power"))
powerCol = idx;
else if (!strcmp(p, "Keying"))
keyCol = idx;
else if (!strcmp(p, "MGM"))
mgmCol = idx;
p = strtok(nullptr, ",");
idx++;
}
// Read data
while (fgets(row, sizeof(row), file))
{
char *callsign = nullptr;
size_t callsignLen = 0;
char *frequencyString = nullptr;
quint64 frequency;
char *locator = nullptr;
int height = 0;
char *heightString = nullptr;
char *pattern = nullptr;
char *polarization = nullptr;
char *power = nullptr;
char *key = nullptr;
char *mgm = nullptr;
char *q = row;
idx = 0;
while ((p = csvNext(&q, ';')) != nullptr)
{
// Read strings, stripping quotes
if ((idx == callsignCol) && (p[0] == '\"'))
{
callsign = p+1;
callsignLen = strlen(callsign)-1;
callsign[callsignLen] = '\0';
}
else if ((idx == qrgCol) && (p[0] == '\"'))
{
frequencyString = p+1;
frequencyString[strlen(frequencyString)-1] = '\0';
frequency = QString(frequencyString).toLongLong();
}
else if ((idx == locatorCol) && (p[0] == '\"'))
{
locator = p+1;
locator[strlen(locator)-1] = '\0';
}
else if ((idx == heightCol) && (p[0] == '\"'))
{
heightString = p+1;
heightString[strlen(heightString)-1] = '\0';
height = atoi(heightString);
}
else if ((idx == patternCol) && (p[0] == '\"'))
{
pattern = p+1;
pattern[strlen(pattern)-1] = '\0';
}
else if ((idx == polarizationCol) && (p[0] == '\"'))
{
polarization = p+1;
polarization[strlen(polarization)-1] = '\0';
}
else if ((idx == powerCol) && (p[0] == '\"'))
{
power = p+1;
power[strlen(power)-1] = '\0';
}
else if ((idx == keyCol) && (p[0] == '\"'))
{
key = p+1;
key[strlen(key)-1] = '\0';
}
else if ((idx == mgmCol) && (p[0] == '\"'))
{
mgm = p+1;
mgm[strlen(mgm)-1] = '\0';
}
idx++;
}
float latitude, longitude;
if (callsign && frequencyString && locator && Maidenhead::fromMaidenhead(locator, latitude, longitude))
{
Beacon *beacon = new Beacon();
beacon->m_callsign = callsign;
beacon->m_frequency = frequency * 1000; // kHz to Hz
beacon->m_locator = locator;
beacon->m_latitude = latitude;
beacon->m_longitude = longitude;
beacon->m_altitude = height;
if (!QString("omni").compare(pattern, Qt::CaseInsensitive))
beacon->m_pattern = "Omni"; // Eliminate usage of mixed case
else
beacon->m_pattern = pattern;
beacon->m_polarization = polarization;
beacon->m_power = power;
beacon->m_key = key;
beacon->m_mgm = mgm;
beacons->append(beacon);
cnt++;
}
}
}
fclose(file);
}
else
qDebug() << "Beacon::readIARUCSV: Failed to open " << filename;
qDebug() << "Beacon::readIARUCSV: Read " << cnt << " beacons";
return beacons;
}
};
#endif // INCLUDE_BEACON_H