From cd504da84ed6f926300ac2c41efb8e77b4efbd58 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Fri, 26 Feb 2021 20:27:35 +0000 Subject: [PATCH] Add min and max limits for azimuth and elevation in GS-232 controller. Add satellite tracker support --- .../gs232controller/gs232controller.cpp | 43 ++++++ .../gs232controller/gs232controllergui.cpp | 28 ++++ .../gs232controller/gs232controllergui.h | 4 + .../gs232controller/gs232controllergui.ui | 133 ++++++++++++------ .../gs232controllersettings.cpp | 18 ++- .../gs232controller/gs232controllersettings.h | 4 + .../gs232controller/gs232controllerworker.cpp | 87 +++++++----- .../gs232controller/gs232controllerworker.h | 8 +- plugins/feature/gs232controller/readme.md | 17 +++ 9 files changed, 257 insertions(+), 85 deletions(-) diff --git a/plugins/feature/gs232controller/gs232controller.cpp b/plugins/feature/gs232controller/gs232controller.cpp index 0ea28d684..6e83a841e 100644 --- a/plugins/feature/gs232controller/gs232controller.cpp +++ b/plugins/feature/gs232controller/gs232controller.cpp @@ -210,6 +210,12 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, boo qDebug() << "GS232Controller::applySettings:" << " m_azimuth: " << settings.m_azimuth << " m_elevation: " << settings.m_elevation + << " m_azimuthOffset: " << settings.m_azimuthOffset + << " m_elevationOffset: " << settings.m_elevationOffset + << " m_azimuthMin: " << settings.m_azimuthMin + << " m_azimuthMax: " << settings.m_azimuthMax + << " m_elevationMin: " << settings.m_elevationMin + << " m_elevationMax: " << settings.m_elevationMax << " m_serialPort: " << settings.m_serialPort << " m_baudRate: " << settings.m_baudRate << " m_track: " << settings.m_track @@ -259,6 +265,15 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, boo if ((m_settings.m_elevationOffset != settings.m_elevationOffset) || force) { reverseAPIKeys.append("elevationOffset"); } + if ((m_settings.m_azimuthMin != settings.m_azimuthMin) || force) { + reverseAPIKeys.append("azimuthMin"); + } + if ((m_settings.m_azimuthMax != settings.m_azimuthMax) || force) { + reverseAPIKeys.append("azimuthMax"); + } + if ((m_settings.m_elevationMin != settings.m_elevationMin) || force) { + reverseAPIKeys.append("elevationMin"); + } if ((m_settings.m_title != settings.m_title) || force) { reverseAPIKeys.append("title"); } @@ -341,6 +356,10 @@ void GS232Controller::webapiFormatFeatureSettings( response.getGs232ControllerSettings()->setTrack(settings.m_track); response.getGs232ControllerSettings()->setAzimuthOffset(settings.m_azimuthOffset); response.getGs232ControllerSettings()->setElevationOffset(settings.m_elevationOffset); + response.getGs232ControllerSettings()->setAzimuthMin(settings.m_azimuthMin); + response.getGs232ControllerSettings()->setAzimuthMax(settings.m_azimuthMax); + response.getGs232ControllerSettings()->setElevationMin(settings.m_elevationMin); + response.getGs232ControllerSettings()->setElevationMax(settings.m_elevationMax); if (response.getGs232ControllerSettings()->getTitle()) { *response.getGs232ControllerSettings()->getTitle() = settings.m_title; @@ -389,6 +408,18 @@ void GS232Controller::webapiUpdateFeatureSettings( if (featureSettingsKeys.contains("elevationOffset")) { settings.m_elevationOffset = response.getGs232ControllerSettings()->getElevationOffset(); } + if (featureSettingsKeys.contains("azimuthMin")) { + settings.m_azimuthMin = response.getGs232ControllerSettings()->getAzimuthMin(); + } + if (featureSettingsKeys.contains("azimuthMax")) { + settings.m_azimuthMax = response.getGs232ControllerSettings()->getAzimuthMax(); + } + if (featureSettingsKeys.contains("elevationMin")) { + settings.m_elevationMin = response.getGs232ControllerSettings()->getElevationMin(); + } + if (featureSettingsKeys.contains("elevationMax")) { + settings.m_elevationMax = response.getGs232ControllerSettings()->getElevationMax(); + } if (featureSettingsKeys.contains("title")) { settings.m_title = *response.getGs232ControllerSettings()->getTitle(); } @@ -441,6 +472,18 @@ void GS232Controller::webapiReverseSendSettings(QList& featureSettingsK if (featureSettingsKeys.contains("elevationOffset") || force) { swgGS232ControllerSettings->setElevationOffset(settings.m_elevationOffset); } + if (featureSettingsKeys.contains("azimuthMin") || force) { + swgGS232ControllerSettings->setAzimuthMin(settings.m_azimuthMin); + } + if (featureSettingsKeys.contains("azimuthMax") || force) { + swgGS232ControllerSettings->setAzimuthMax(settings.m_azimuthMax); + } + if (featureSettingsKeys.contains("elevationMin") || force) { + swgGS232ControllerSettings->setElevationMin(settings.m_elevationMin); + } + if (featureSettingsKeys.contains("elevationMax") || force) { + swgGS232ControllerSettings->setElevationMax(settings.m_elevationMax); + } if (featureSettingsKeys.contains("title") || force) { swgGS232ControllerSettings->setTitle(new QString(settings.m_title)); } diff --git a/plugins/feature/gs232controller/gs232controllergui.cpp b/plugins/feature/gs232controller/gs232controllergui.cpp index 9ed62c6f0..f53445912 100644 --- a/plugins/feature/gs232controller/gs232controllergui.cpp +++ b/plugins/feature/gs232controller/gs232controllergui.cpp @@ -182,6 +182,10 @@ void GS232ControllerGUI::displaySettings() ui->targets->setCurrentIndex(ui->targets->findText(m_settings.m_target)); ui->azimuthOffset->setValue(m_settings.m_azimuthOffset); ui->elevationOffset->setValue(m_settings.m_elevationOffset); + ui->azimuthMin->setValue(m_settings.m_azimuthMin); + ui->azimuthMax->setValue(m_settings.m_azimuthMax); + ui->elevationMin->setValue(m_settings.m_elevationMin); + ui->elevationMax->setValue(m_settings.m_elevationMax); blockApplySettings(false); } @@ -317,6 +321,30 @@ void GS232ControllerGUI::on_elevationOffset_valueChanged(int value) applySettings(); } +void GS232ControllerGUI::on_azimuthMin_valueChanged(int value) +{ + m_settings.m_azimuthMin = value; + applySettings(); +} + +void GS232ControllerGUI::on_azimuthMax_valueChanged(int value) +{ + m_settings.m_azimuthMax = value; + applySettings(); +} + +void GS232ControllerGUI::on_elevationMin_valueChanged(int value) +{ + m_settings.m_elevationMin = value; + applySettings(); +} + +void GS232ControllerGUI::on_elevationMax_valueChanged(int value) +{ + m_settings.m_elevationMax = value; + applySettings(); +} + void GS232ControllerGUI::on_track_stateChanged(int state) { m_settings.m_track = state == Qt::Checked; diff --git a/plugins/feature/gs232controller/gs232controllergui.h b/plugins/feature/gs232controller/gs232controllergui.h index b43356a3d..8d46300e2 100644 --- a/plugins/feature/gs232controller/gs232controllergui.h +++ b/plugins/feature/gs232controller/gs232controllergui.h @@ -84,6 +84,10 @@ private slots: void on_targets_currentTextChanged(const QString& text); void on_azimuthOffset_valueChanged(int value); void on_elevationOffset_valueChanged(int value); + void on_azimuthMin_valueChanged(int value); + void on_azimuthMax_valueChanged(int value); + void on_elevationMin_valueChanged(int value); + void on_elevationMax_valueChanged(int value); void updateStatus(); }; diff --git a/plugins/feature/gs232controller/gs232controllergui.ui b/plugins/feature/gs232controller/gs232controllergui.ui index 71b594c3c..0feb96f4d 100644 --- a/plugins/feature/gs232controller/gs232controllergui.ui +++ b/plugins/feature/gs232controller/gs232controllergui.ui @@ -6,8 +6,8 @@ 0 0 - 320 - 175 + 350 + 223 @@ -42,8 +42,8 @@ 10 10 - 301 - 161 + 331 + 191 @@ -248,45 +248,50 @@ - - - - - Serial Port - - - - - - - Name of serial port to use to connect to the GS-232 controller - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + Baud rate - + + + + 180 + + + + + + + Elevation min + + + + + + + Azimuth min + + + + + + + Elevation max + + + + + + + 180 + + + + Serial port baud rate for the GS-232 controller @@ -336,18 +341,52 @@ - - - - - + + + + 450 + + + + + + + 450 + + + + + + + Name of serial port to use to connect to the GS-232 controller + + + true + + + + + + + Serial Port + + + + + + + Azimuth max + + + + Azimuth offset - + Specify an offset angel in degrees that will be added to the target azimuth to correct for misalignment @@ -360,14 +399,14 @@ - + Elevation offset - + Specify an offset angle in degrees that will be added to the target elevation to correct for misalignment @@ -412,6 +451,10 @@ baudRate azimuthOffset elevationOffset + azimuthMin + azimuthMax + elevationMin + elevationMax diff --git a/plugins/feature/gs232controller/gs232controllersettings.cpp b/plugins/feature/gs232controller/gs232controllersettings.cpp index 29e616b5d..298f296e0 100644 --- a/plugins/feature/gs232controller/gs232controllersettings.cpp +++ b/plugins/feature/gs232controller/gs232controllersettings.cpp @@ -26,13 +26,15 @@ const QStringList GS232ControllerSettings::m_pipeTypes = { QStringLiteral("ADSBDemod"), QStringLiteral("Map"), - QStringLiteral("StarTracker") + QStringLiteral("StarTracker"), + QStringLiteral("SatelliteTracker") }; const QStringList GS232ControllerSettings::m_pipeURIs = { QStringLiteral("sdrangel.channel.adsbdemod"), QStringLiteral("sdrangel.feature.map"), - QStringLiteral("sdrangel.feature.startracker") + QStringLiteral("sdrangel.feature.startracker"), + QStringLiteral("sdrangel.feature.satellitetracker") }; GS232ControllerSettings::GS232ControllerSettings() @@ -57,6 +59,10 @@ void GS232ControllerSettings::resetToDefaults() m_reverseAPIFeatureIndex = 0; m_azimuthOffset = 0; m_elevationOffset = 0; + m_azimuthMin = 0; + m_azimuthMax = 450; + m_elevationMin = 0; + m_elevationMax = 180; } QByteArray GS232ControllerSettings::serialize() const @@ -78,6 +84,10 @@ QByteArray GS232ControllerSettings::serialize() const s.writeU32(14, m_reverseAPIFeatureIndex); s.writeS32(15, m_azimuthOffset); s.writeS32(16, m_elevationOffset); + s.writeS32(17, m_azimuthMin); + s.writeS32(18, m_azimuthMax); + s.writeS32(19, m_elevationMin); + s.writeS32(20, m_elevationMax); return s.final(); } @@ -122,6 +132,10 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data) m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp; d.readS32(15, &m_azimuthOffset, 0); d.readS32(16, &m_elevationOffset, 0); + d.readS32(17, &m_azimuthMin, 0); + d.readS32(18, &m_azimuthMax, 450); + d.readS32(19, &m_elevationMin, 0); + d.readS32(20, &m_elevationMax, 180); return true; } diff --git a/plugins/feature/gs232controller/gs232controllersettings.h b/plugins/feature/gs232controller/gs232controllersettings.h index 271f11239..83dd8b787 100644 --- a/plugins/feature/gs232controller/gs232controllersettings.h +++ b/plugins/feature/gs232controller/gs232controllersettings.h @@ -36,6 +36,10 @@ struct GS232ControllerSettings QString m_target; // Plugin to get az/el from. E.g: "R0:0 ADSBDemod". Use a string, so can be set via WebAPI int m_azimuthOffset; int m_elevationOffset; + int m_azimuthMin; + int m_azimuthMax; + int m_elevationMin; + int m_elevationMax; QString m_title; quint32 m_rgbColor; bool m_useReverseAPI; diff --git a/plugins/feature/gs232controller/gs232controllerworker.cpp b/plugins/feature/gs232controller/gs232controllerworker.cpp index 15a6ae453..5bfdaa6a4 100644 --- a/plugins/feature/gs232controller/gs232controllerworker.cpp +++ b/plugins/feature/gs232controller/gs232controllerworker.cpp @@ -16,6 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include + #include #include #include @@ -35,7 +37,9 @@ GS232ControllerWorker::GS232ControllerWorker() : m_msgQueueToFeature(nullptr), m_msgQueueToGUI(nullptr), m_running(false), - m_mutex(QMutex::Recursive) + m_mutex(QMutex::Recursive), + m_lastAzimuth(-1), + m_lastElevation(-1) { connect(&m_pollTimer, SIGNAL(timeout()), this, SLOT(update())); m_pollTimer.start(1000); @@ -57,6 +61,7 @@ bool GS232ControllerWorker::startWork() QMutexLocker mutexLocker(&m_mutex); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); connect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData); + openSerialPort(m_settings); m_running = true; return m_running; } @@ -64,6 +69,9 @@ bool GS232ControllerWorker::startWork() void GS232ControllerWorker::stopWork() { QMutexLocker mutexLocker(&m_mutex); + // Close serial port as USB/controller activity can create RFI + if (m_serialPort.isOpen()) + m_serialPort.close(); disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); disconnect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData); m_running = false; @@ -104,71 +112,78 @@ void GS232ControllerWorker::applySettings(const GS232ControllerSettings& setting << " m_elevation: " << settings.m_elevation << " m_azimuthOffset: " << settings.m_azimuthOffset << " m_elevationOffset: " << settings.m_elevationOffset + << " m_azimuthMin: " << settings.m_azimuthMin + << " m_azimuthMax: " << settings.m_azimuthMax + << " m_elevationMin: " << settings.m_elevationMin + << " m_elevationMax: " << settings.m_elevationMax << " m_serialPort: " << settings.m_serialPort << " m_baudRate: " << settings.m_baudRate << " force: " << force; if ((settings.m_serialPort != m_settings.m_serialPort) || force) { - if (m_serialPort.isOpen()) - m_serialPort.close(); - m_serialPort.setPortName(settings.m_serialPort); - m_serialPort.setBaudRate(settings.m_baudRate); - if (!m_serialPort.open(QIODevice::ReadWrite)) - { - qCritical() << "GS232ControllerWorker::applySettings: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error(); - if (m_msgQueueToFeature) - m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Failed to open serial port %1: %2").arg(settings.m_serialPort).arg(m_serialPort.error()))); - } + openSerialPort(settings); } else if ((settings.m_baudRate != m_settings.m_baudRate) || force) { m_serialPort.setBaudRate(settings.m_baudRate); } - if ((settings.m_elevation != m_settings.m_elevation) - || (settings.m_elevationOffset != m_settings.m_elevationOffset) - || force) + // Apply offset then clamp + + int azimuth = settings.m_azimuth; + azimuth += settings.m_azimuthOffset; + azimuth = std::max(azimuth, settings.m_azimuthMin); + azimuth = std::min(azimuth, settings.m_azimuthMax); + + int elevation = settings.m_elevation; + elevation += settings.m_elevationOffset; + elevation = std::max(elevation, settings.m_elevationMin); + elevation = std::min(elevation, settings.m_elevationMax); + + if (((elevation != m_lastElevation) || force) && (settings.m_elevationMax != 0)) { - setAzimuthElevation(settings.m_azimuth, settings.m_elevation, settings.m_azimuthOffset, settings.m_elevationOffset); + setAzimuthElevation(azimuth, elevation); } - else if ((settings.m_azimuth != m_settings.m_azimuth) - || (settings.m_azimuthOffset != m_settings.m_azimuthOffset) - || force) + else if ((azimuth != m_lastAzimuth) || force) { - setAzimuth(settings.m_azimuth, settings.m_azimuthOffset); + setAzimuth(azimuth); } m_settings = settings; } -void GS232ControllerWorker::setAzimuth(int azimuth, int azimuthOffset) +void GS232ControllerWorker::openSerialPort(const GS232ControllerSettings& settings) +{ + if (m_serialPort.isOpen()) + m_serialPort.close(); + m_serialPort.setPortName(settings.m_serialPort); + m_serialPort.setBaudRate(settings.m_baudRate); + if (!m_serialPort.open(QIODevice::ReadWrite)) + { + qCritical() << "GS232ControllerWorker::openSerialPort: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error(); + if (m_msgQueueToFeature) + m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Failed to open serial port %1: %2").arg(settings.m_serialPort).arg(m_serialPort.error()))); + } + m_lastAzimuth = -1; + m_lastElevation = -1; +} + +void GS232ControllerWorker::setAzimuth(int azimuth) { - azimuth += azimuthOffset; - if (azimuth < 0) - azimuth = 0; - else if (azimuth > 450) - azimuth = 450; QString cmd = QString("M%1\r\n").arg(azimuth, 3, 10, QLatin1Char('0')); QByteArray data = cmd.toLatin1(); m_serialPort.write(data); + m_lastAzimuth = azimuth; } -void GS232ControllerWorker::setAzimuthElevation(int azimuth, int elevation, int azimuthOffset, int elevationOffset) +void GS232ControllerWorker::setAzimuthElevation(int azimuth, int elevation) { - azimuth += azimuthOffset; - if (azimuth < 0) - azimuth = 0; - else if (azimuth > 450) - azimuth = 450; - elevation += elevationOffset; - if (elevation < 0) - elevation = 0; - else if (elevation > 180) - elevation = 180; QString cmd = QString("W%1 %2\r\n").arg(azimuth, 3, 10, QLatin1Char('0')).arg(elevation, 3, 10, QLatin1Char('0')); QByteArray data = cmd.toLatin1(); m_serialPort.write(data); + m_lastAzimuth = azimuth; + m_lastElevation = elevation; } void GS232ControllerWorker::readSerialData() diff --git a/plugins/feature/gs232controller/gs232controllerworker.h b/plugins/feature/gs232controller/gs232controllerworker.h index 3be417fe2..0bf22cace 100644 --- a/plugins/feature/gs232controller/gs232controllerworker.h +++ b/plugins/feature/gs232controller/gs232controllerworker.h @@ -76,11 +76,15 @@ private: QSerialPort m_serialPort; QTimer m_pollTimer; + int m_lastAzimuth; + int m_lastElevation; + bool handleMessage(const Message& cmd); void applySettings(const GS232ControllerSettings& settings, bool force = false); MessageQueue *getMessageQueueToGUI() { return m_msgQueueToGUI; } - void setAzimuth(int azimuth, int azimuthOffset); - void setAzimuthElevation(int azimuth, int elevation, int azimuthOffset, int elevationOffset); + void openSerialPort(const GS232ControllerSettings& settings); + void setAzimuth(int azimuth); + void setAzimuthElevation(int azimuth, int elevation); private slots: void handleInputMessages(); diff --git a/plugins/feature/gs232controller/readme.md b/plugins/feature/gs232controller/readme.md index 8432cc5a6..854a336c9 100644 --- a/plugins/feature/gs232controller/readme.md +++ b/plugins/feature/gs232controller/readme.md @@ -54,6 +54,23 @@ The azimuth offset specifies an angle in degrees that is added to the target azi The elevation offset specifies an angle in degrees that is added to the target elevation before sending to the controller. This allows for a misalignment of the rotator to be corrected. +

11 and 12: Azimuth Min and Max

+ +The azimuth min and max values specify the minimum and maximum azimuth values (after offset has been applied), that will be sent to the rotator. +These values can be used to prevent the rotator from rotating an antenna in to an obstable. + +

13 and 14: Elevation Min and Max

+ +The elevation min and max values specify the minimum and maximum elevation values (after offset has been applied), that will be sent to the rotator. +These values can be used to prevent the rotator from rotating an antenna in to an obstable. +If the maximum elevation is set to 0, the controller will only use the M GS-232 command, rather than M and W. + +

GS-232 Protocol Implementation

+ +The controller uses the Waaa eee command when elevation needs to be set. +When only azimuth needs to be set, the Maaa command is used. +The C2 command is used to read current azimuth and elevation. A response of AZ=aaaEL=eee is expected. +

API

Full details of the API can be found in the Swagger documentation. Here is a quick example of how to set the azimuth and elevation from the command line: