diff --git a/doc/img/Map_plugin_ibp_beacon_dialog.png b/doc/img/Map_plugin_ibp_beacon_dialog.png new file mode 100644 index 000000000..bab8287b1 Binary files /dev/null and b/doc/img/Map_plugin_ibp_beacon_dialog.png differ diff --git a/plugins/feature/map/CMakeLists.txt b/plugins/feature/map/CMakeLists.txt index 6f04e0e39..26b8103c6 100644 --- a/plugins/feature/map/CMakeLists.txt +++ b/plugins/feature/map/CMakeLists.txt @@ -6,6 +6,7 @@ set(map_SOURCES mapplugin.cpp mapwebapiadapter.cpp osmtemplateserver.cpp + ibpbeacon.cpp ) set(map_HEADERS @@ -16,6 +17,7 @@ set(map_HEADERS mapwebapiadapter.h osmtemplateserver.h beacon.h + ibpbeacon.h ) include_directories( @@ -35,6 +37,8 @@ if(NOT SERVER_MODE) mapsettingsdialog.ui mapbeacondialog.cpp mapbeacondialog.ui + mapibpbeacondialog.cpp + mapibpbeacondialog.ui mapradiotimedialog.cpp mapradiotimedialog.ui map.qrc @@ -47,6 +51,7 @@ if(NOT SERVER_MODE) mapmaidenheaddialog.h mapsettingsdialog.h mapbeacondialog.h + mapibpbeacon.h mapradiotimedialog.h ) diff --git a/plugins/feature/map/ibpbeacon.cpp b/plugins/feature/map/ibpbeacon.cpp new file mode 100644 index 000000000..883c217bb --- /dev/null +++ b/plugins/feature/map/ibpbeacon.cpp @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "ibpbeacon.h" + +QList IBPBeacon::m_beacons = { + IBPBeacon("4U1UN", "United Nations NY", "FN30AS", 0), + IBPBeacon("VE8AT", "North Canada", "EQ79AX", 10), + IBPBeacon("W6WX", "USA (CA)", "CM97BD", 20), + IBPBeacon("KH6WO", "Hawaii", "BL10TS", 30), + IBPBeacon("ZL6B", "New Zealand", "RE78TW", 40), + IBPBeacon("VK6RBP", "West Australia", "OF87AV", 50), + IBPBeacon("JA2IGY", "Japan", "PM84JK", 60), + IBPBeacon("RR9O", "Siberia", "NO14KX", 70), + IBPBeacon("VR2HK", "China", "OL72CQ", 80), + IBPBeacon("4S7B", "Sri Lanka", "NJ06CR", 90), + IBPBeacon("ZS6DN", "South Africa", "KG44DC", 100), + IBPBeacon("5Z4B", "Kenya", "KI88MX", 110), + IBPBeacon("4X6TU", "Israel", "KM72JB", 120), + IBPBeacon("OH2B", "Finland", "KP20BM", 130), + IBPBeacon("CS3B", "Madeira", "IM12OR", 140), + IBPBeacon("LU4AA", "Argentina", "GF05TJ", 150), + IBPBeacon("OA4B", "Peru", "FH17MW", 160), + IBPBeacon("YV5B", "Venezuela", "FJ69CC", 170) +}; + +// The frequencies in MHz through which the IBP beacons rotate +QList IBPBeacon::m_frequencies = { + 14.1, 18.11, 21.150, 24.93, 28.2 +}; + diff --git a/plugins/feature/map/ibpbeacon.h b/plugins/feature/map/ibpbeacon.h new file mode 100644 index 000000000..7fe6a3140 --- /dev/null +++ b/plugins/feature/map/ibpbeacon.h @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_IBP_BEACON_H +#define INCLUDE_IBP_BEACON_H + +#include +#include + +#include "util/maidenhead.h" + +// International Beacon Project beacons +// https://www.ncdxf.org/beacon/ + +struct IBPBeacon { + + QString m_callsign; + QString m_location; + QString m_locator; + int m_offset; // Time offset in seconds + float m_latitude; + float m_longitude; + + IBPBeacon(const QString& callsign, const QString& location, const QString& locator, int offset) : + m_callsign(callsign), + m_location(location), + m_locator(locator), + m_offset(offset) + { + Maidenhead::fromMaidenhead(locator, m_latitude, m_longitude); + } + + QString getText() const + { + QStringList list; + list.append("IBP Beacon"); + list.append(QString("Callsign: %1").arg(m_callsign)); + list.append(QString("Frequency: 14.1, 18.11, 21.15, 24.92, 28.2MHz")); + list.append(QString("Power: 100 Watts ERP")); + list.append(QString("Polarization: V")); + list.append(QString("Pattern: Omni")); + list.append(QString("Key: A1")); + list.append(QString("Locator: %1").arg(m_locator)); + return list.join("\n"); + } + + static QList m_beacons; + static QList m_frequencies; + static const int m_period = 10; // Beacons rotate every 10 seconds +}; + +#endif // INCLUDE_IBP_BEACON_H diff --git a/plugins/feature/map/icons.qrc b/plugins/feature/map/icons.qrc index ba855ff49..9cfa49cfd 100644 --- a/plugins/feature/map/icons.qrc +++ b/plugins/feature/map/icons.qrc @@ -2,5 +2,6 @@ icons/groundtracks.png icons/clock.png + icons/ibp.png diff --git a/plugins/feature/map/icons/ibp.png b/plugins/feature/map/icons/ibp.png new file mode 100644 index 000000000..d023af515 Binary files /dev/null and b/plugins/feature/map/icons/ibp.png differ diff --git a/plugins/feature/map/mapgui.cpp b/plugins/feature/map/mapgui.cpp index 8d1220c82..056909715 100644 --- a/plugins/feature/map/mapgui.cpp +++ b/plugins/feature/map/mapgui.cpp @@ -38,6 +38,7 @@ #include "maplocationdialog.h" #include "mapmaidenheaddialog.h" #include "mapsettingsdialog.h" +#include "ibpbeacon.h" #include "ui_mapgui.h" #include "map.h" @@ -683,6 +684,7 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur m_mapModel(this), m_beacons(nullptr), m_beaconDialog(this), + m_ibpBeaconDialog(this), m_radioTimeDialog(this) { ui->setupUi(this); @@ -748,8 +750,10 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur QList *beacons = Beacon::readIARUCSV(MapGUI::getBeaconFilename()); if (beacons != nullptr) setBeacons(beacons); + addIBPBeacons(); addRadioTimeTransmitters(); + addRadar(); } MapGUI::~MapGUI() @@ -787,6 +791,24 @@ void MapGUI::setBeacons(QList *beacons) } } +void MapGUI::addIBPBeacons() +{ + // Add to Map + for (const auto beacon : IBPBeacon::m_beacons) + { + SWGSDRangel::SWGMapItem beaconMapItem; + beaconMapItem.setName(new QString(beacon.m_callsign)); + beaconMapItem.setLatitude(beacon.m_latitude); + beaconMapItem.setLongitude(beacon.m_longitude); + beaconMapItem.setAltitude(0); + beaconMapItem.setImage(new QString("antenna.png")); + beaconMapItem.setImageRotation(0); + beaconMapItem.setImageMinZoom(8); + beaconMapItem.setText(new QString(beacon.getText())); + m_mapModel.update(m_map, &beaconMapItem, MapSettings::SOURCE_BEACONS); + } +} + const QList MapGUI::m_radioTimeTransmitters = { {"MSF", 60000, 54.9075f, -3.27333f, 17}, {"DCF77", 77500, 50.01611111f, 9.00805556f, 50}, @@ -818,6 +840,23 @@ void MapGUI::addRadioTimeTransmitters() } } +void MapGUI::addRadar() +{ + SWGSDRangel::SWGMapItem radarMapItem; + radarMapItem.setName(new QString("GRAVES")); + radarMapItem.setLatitude(47.3480); + radarMapItem.setLongitude(5.5151); + radarMapItem.setAltitude(0.0); + radarMapItem.setImage(new QString("antenna.png")); + radarMapItem.setImageRotation(0); + radarMapItem.setImageMinZoom(8); + QString text = QString("Radar\nCallsign: %1\nFrequency: %2 MHz") + .arg("GRAVES") + .arg("143.050"); + radarMapItem.setText(new QString(text)); + m_mapModel.update(m_map, &radarMapItem, MapSettings::SOURCE_RADAR); +} + static QString arrayToString(QJsonArray array) { QString s; @@ -1300,6 +1339,11 @@ void MapGUI::on_beacons_clicked() m_beaconDialog.show(); } +void MapGUI::on_ibpBeacons_clicked() +{ + m_ibpBeaconDialog.show(); +} + void MapGUI::on_radiotime_clicked() { m_radioTimeDialog.updateTable(); diff --git a/plugins/feature/map/mapgui.h b/plugins/feature/map/mapgui.h index f88304cec..317a66b40 100644 --- a/plugins/feature/map/mapgui.h +++ b/plugins/feature/map/mapgui.h @@ -31,6 +31,7 @@ #include "mapsettings.h" #include "SWGMapItem.h" #include "mapbeacondialog.h" +#include "mapibpbeacondialog.h" #include "mapradiotimedialog.h" #include "osmtemplateserver.h" @@ -481,8 +482,10 @@ public: static QString getBeaconFilename(); QList *getBeacons() { return m_beacons; } void setBeacons(QList *beacons); + void addIBPBeacons(); QList getRadioTimeTransmitters() { return m_radioTimeTransmitters; } void addRadioTimeTransmitters(); + void addRadar(); void addDAB(); void find(const QString& target); Q_INVOKABLE void supportedMapsChanged(); @@ -501,6 +504,7 @@ private: AzEl m_azEl; // Position of station QList *m_beacons; MapBeaconDialog m_beaconDialog; + MapIBPBeaconDialog m_ibpBeaconDialog; MapRadioTimeDialog m_radioTimeDialog; quint16 m_osmPort; OSMTemplateServer *m_templateServer; @@ -536,6 +540,7 @@ private slots: void on_displaySettings_clicked(); void on_mapTypes_currentIndexChanged(int index); void on_beacons_clicked(); + void on_ibpBeacons_clicked(); void on_radiotime_clicked(); }; diff --git a/plugins/feature/map/mapgui.ui b/plugins/feature/map/mapgui.ui index 8a5a5b39b..36b6256cd 100644 --- a/plugins/feature/map/mapgui.ui +++ b/plugins/feature/map/mapgui.ui @@ -140,6 +140,20 @@ + + + + Display IBP Beacon dialog + + + IBP + + + + :/map/icons/ibp.png:/map/icons/ibp.png + + + diff --git a/plugins/feature/map/mapibpbeacondialog.cpp b/plugins/feature/map/mapibpbeacondialog.cpp new file mode 100644 index 000000000..be2b96ed0 --- /dev/null +++ b/plugins/feature/map/mapibpbeacondialog.cpp @@ -0,0 +1,106 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "mapibpbeacondialog.h" + +#include + +#include "channel/channelwebapiutils.h" +#include "mapgui.h" + +MapIBPBeaconDialog::MapIBPBeaconDialog(MapGUI *gui, QWidget* parent) : + QDialog(parent), + m_gui(gui), + m_timer(this), + ui(new Ui::MapIBPBeaconDialog) +{ + ui->setupUi(this); + connect(&m_timer, &QTimer::timeout, this, &MapIBPBeaconDialog::updateTime); + m_timer.setInterval(1000); + m_timer.start(); + ui->beacons->setRowCount(IBPBeacon::m_frequencies.size()); + for (int row = 0; row < IBPBeacon::m_frequencies.size(); row++) + { + ui->beacons->setItem(row, IBP_BEACON_COL_FREQUENCY, new QTableWidgetItem(QString::number(IBPBeacon::m_frequencies[row], 'f', 3))); + ui->beacons->setItem(row, IBP_BEACON_COL_CALLSIGN, new QTableWidgetItem("")); + ui->beacons->setItem(row, IBP_BEACON_COL_LOCATION, new QTableWidgetItem("")); + ui->beacons->setItem(row, IBP_BEACON_COL_AZIMUTH, new QTableWidgetItem("")); + ui->beacons->setItem(row, IBP_BEACON_COL_DISTANCE, new QTableWidgetItem("")); + } + updateTable(QTime::currentTime()); +} + +MapIBPBeaconDialog::~MapIBPBeaconDialog() +{ + delete ui; +} + +void MapIBPBeaconDialog::updateTable(QTime time) +{ + AzEl azEl = *m_gui->getAzEl(); + + // Repeat from begining every 3 minutes + int index = ((time.minute() * 60 + time.second()) % 180) / IBPBeacon::m_period; + + for (int row = 0; row < IBPBeacon::m_frequencies.size(); row++) + { + ui->beacons->item(row, IBP_BEACON_COL_CALLSIGN)->setText(IBPBeacon::m_beacons[index].m_callsign); + ui->beacons->item(row, IBP_BEACON_COL_LOCATION)->setText(IBPBeacon::m_beacons[index].m_location); + + // Calculate azimuth and distance to beacon + azEl.setTarget(IBPBeacon::m_beacons[index].m_latitude, IBPBeacon::m_beacons[index].m_longitude, 0.0); + azEl.calculate(); + ui->beacons->item(row, IBP_BEACON_COL_AZIMUTH)->setData(Qt::DisplayRole, round(azEl.getAzimuth())); + int km = round(azEl.getDistance()/1000); + ui->beacons->item(row, IBP_BEACON_COL_DISTANCE)->setData(Qt::DisplayRole, km); + + index--; + if (index < 0) { + index = IBPBeacon::m_beacons.size() - 1; + } + } +} + +void MapIBPBeaconDialog::accept() +{ + QDialog::accept(); +} + +void MapIBPBeaconDialog::on_beacons_cellDoubleClicked(int row, int column) +{ + if (column == IBP_BEACON_COL_CALLSIGN) + { + // Find beacon on map + QString location = ui->beacons->item(row, column)->text(); + m_gui->find(location); + } + else if (column == IBP_BEACON_COL_FREQUENCY) + { + // Tune to beacon freq + ChannelWebAPIUtils::setCenterFrequency(0, ui->beacons->item(row, column)->text().toDouble() * 1e6); + } +} + +void MapIBPBeaconDialog::updateTime() +{ + QTime t = QTime::currentTime(); + ui->time->setTime(t); + // Beacons rotate every 10 seconds + if ((t.second() % IBPBeacon::m_period) == 0) { + updateTable(t); + } +} diff --git a/plugins/feature/map/mapibpbeacondialog.h b/plugins/feature/map/mapibpbeacondialog.h new file mode 100644 index 000000000..4496d8d0d --- /dev/null +++ b/plugins/feature/map/mapibpbeacondialog.h @@ -0,0 +1,57 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_MAPIBPBEACONDIALOG_H +#define INCLUDE_FEATURE_MAPIBPBEACONDIALOG_H + +#include "ui_mapibpbeacondialog.h" + +#include +#include + +#include "ibpbeacon.h" + +class MapGUI; + +class MapIBPBeaconDialog : public QDialog { + Q_OBJECT + +public: + explicit MapIBPBeaconDialog(MapGUI *gui, QWidget* parent = 0); + ~MapIBPBeaconDialog(); + void updateTable(QTime time); + +private slots: + void accept(); + void on_beacons_cellDoubleClicked(int row, int column); + void updateTime(); + +private: + MapGUI *m_gui; + QTimer m_timer; + Ui::MapIBPBeaconDialog* ui; + + enum BeaconCol { + IBP_BEACON_COL_FREQUENCY, + IBP_BEACON_COL_CALLSIGN, + IBP_BEACON_COL_LOCATION, + IBP_BEACON_COL_AZIMUTH, + IBP_BEACON_COL_DISTANCE + }; +}; + +#endif // INCLUDE_FEATURE_MAPIBPBEACONDIALOG_H diff --git a/plugins/feature/map/mapibpbeacondialog.ui b/plugins/feature/map/mapibpbeacondialog.ui new file mode 100644 index 000000000..038ab63ea --- /dev/null +++ b/plugins/feature/map/mapibpbeacondialog.ui @@ -0,0 +1,160 @@ + + + MapIBPBeaconDialog + + + + 0 + 0 + 584 + 311 + + + + + Liberation Sans + 9 + + + + IBP Beacons + + + + + + + 0 + + + + + + + Time + + + + + + + Current time + + + true + + + QAbstractSpinBox::NoButtons + + + QDateTimeEdit::HourSection + + + HH:mm:ss + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Displays which IBP beacon is transmitting on which frequency + + + + Frequency (MHz) + + + + + Callsign + + + + + Location + + + + + Azimuth (°) + + + + + Distance (km) + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + beacons + time + + + + + + + buttonBox + accepted() + MapIBPBeaconDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + MapIBPBeaconDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/plugins/feature/map/mapsettings.h b/plugins/feature/map/mapsettings.h index 31d5e0cc9..0db5886ec 100644 --- a/plugins/feature/map/mapsettings.h +++ b/plugins/feature/map/mapsettings.h @@ -68,9 +68,10 @@ struct MapSettings static const quint32 SOURCE_SATELLITE_TRACKER = 0x10; static const quint32 SOURCE_BEACONS = 0x20; static const quint32 SOURCE_RADIO_TIME = 0x40; - static const quint32 SOURCE_AM = 0x80; - static const quint32 SOURCE_FM = 0x100; - static const quint32 SOURCE_DAB = 0x200; + static const quint32 SOURCE_RADAR = 0x80; + static const quint32 SOURCE_AM = 0x100; + static const quint32 SOURCE_FM = 0x200; + static const quint32 SOURCE_DAB = 0x400; static const quint32 SOURCE_STATION = 0x400; // Antenna at "My Position" }; diff --git a/plugins/feature/map/mapsettingsdialog.ui b/plugins/feature/map/mapsettingsdialog.ui index ec5fb8b9f..b07e64e74 100644 --- a/plugins/feature/map/mapsettingsdialog.ui +++ b/plugins/feature/map/mapsettingsdialog.ui @@ -97,6 +97,14 @@ Checked + + + Radar + + + Checked + + diff --git a/plugins/feature/map/readme.md b/plugins/feature/map/readme.md index 94d1fa860..b41006662 100644 --- a/plugins/feature/map/readme.md +++ b/plugins/feature/map/readme.md @@ -10,8 +10,9 @@ On top of this, it can plot data from other plugins, such as: * Ships from the AIS Demodulator, * Satellites from the Satellite Tracker, * The Sun, Moon and Stars from the Star Tracker, -* Beacons based on the IARU Region 1 beacon database. -* Radio time transmitters. +* Beacons based on the IARU Region 1 beacon database and International Beacon Project, +* Radio time transmitters, +* GRAVES radar. It can also create tracks showing the path aircraft, ships and APRS objects have taken, as well as predicted paths for satellites. @@ -49,7 +50,20 @@ The beacons will then be displayed in the table and on the map. ![Beacon dialog](../../../doc/img/Map_plugin_beacon_dialog.png) -

5: Display Radio Time Transmitters dialog

+

5: Display IBP Beacon Project Dialog

+ +When clicked, opens the International Beacon Project dialog. The IBP consists of 18 HF beacons around the world, +that each transmit once on each of the frequencies 14.100, 18.110, 21.150, 24.930 and 28.200MHz every 3 minutes, for 10 seconds. +The IBP dialog shows which of the beacons should currently be transmitting. + +![IBP beacon dialog](../../../doc/img/Map_plugin_ibp_beacon_dialog.png) + +* Double clicking in a cell in the Callsign column will centre the map on that beacon. +* Double clicking in a cell in the Frequency column will set the Device center frequency. + +More details of the IBP can be found at: https://www.ncdxf.org/beacon/beaconfaq.html + +

6: Display Radio Time Transmitters dialog

When clicked, opens the Radio Time Transmitters dialog. @@ -58,23 +72,23 @@ When clicked, opens the Radio Time Transmitters dialog. ![Radio Time transmitters dialog](../../../doc/img/Map_plugin_radiotime_dialog.png) -

6: Display Names

+

7: Display Names

When checked, names of objects are displayed in a bubble next to each object. -

7: Display tracks for selected object

+

8: Display tracks for selected object

When checked, displays the track (taken or predicted) for the selected object. -

8: Display tracks for all objects

+

9: Display tracks for all objects

When checked, displays the track (taken or predicted) for the all objects. -

9: Delete

+

10: Delete

When clicked, all items will be deleted from the map. -

10: Display settings

+

11: Display settings

When clicked, opens the Map Display Settings dialog, which allows setting: