From 4ac5e729ffbd90c672967a03b0f0e90eb70ede0b Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Mon, 3 Apr 2023 16:47:13 +0100 Subject: [PATCH] Rotator Controller Updates Add support for X/Y coordinates. Add coordinate precision setting. Automatically scan for serial port changes. Refactor so each protocol is implemented in a separate class. Add start of DFM protocol. --- .../feature/gs232controller/CMakeLists.txt | 13 + .../gs232controller/controllerprotocol.cpp | 157 ++++++ .../gs232controller/controllerprotocol.h | 57 +++ .../feature/gs232controller/dfmprotocol.cpp | 239 ++++++++++ plugins/feature/gs232controller/dfmprotocol.h | 120 +++++ .../gs232controller/dfmstatusdialog.cpp | 69 +++ .../feature/gs232controller/dfmstatusdialog.h | 40 ++ .../gs232controller/dfmstatusdialog.ui | 413 ++++++++++++++++ .../gs232controller/gs232controller.cpp | 71 ++- .../feature/gs232controller/gs232controller.h | 24 + .../gs232controller/gs232controllergui.cpp | 272 +++++++++-- .../gs232controller/gs232controllergui.h | 21 +- .../gs232controller/gs232controllergui.ui | 447 ++++++++++++------ .../gs232controllersettings.cpp | 161 ++++--- .../gs232controller/gs232controllersettings.h | 10 +- .../gs232controller/gs232controllerworker.cpp | 271 ++--------- .../gs232controller/gs232controllerworker.h | 9 +- .../feature/gs232controller/gs232protocol.cpp | 86 ++++ .../feature/gs232controller/gs232protocol.h | 34 ++ plugins/feature/gs232controller/readme.md | 15 + .../gs232controller/rotctrldprotocol.cpp | 118 +++++ .../gs232controller/rotctrldprotocol.h | 36 ++ .../feature/gs232controller/spidprotocol.cpp | 124 +++++ .../feature/gs232controller/spidprotocol.h | 37 ++ sdrbase/channel/channelwebapiutils.cpp | 233 ++++++++- sdrbase/channel/channelwebapiutils.h | 16 +- sdrbase/util/astronomy.cpp | 178 +++++++ sdrbase/util/astronomy.h | 5 + .../api/swagger/include/GS232Controller.yaml | 8 +- .../qt5/client/SWGGS232ControllerSettings.cpp | 46 ++ .../qt5/client/SWGGS232ControllerSettings.h | 12 + 31 files changed, 2859 insertions(+), 483 deletions(-) create mode 100644 plugins/feature/gs232controller/controllerprotocol.cpp create mode 100644 plugins/feature/gs232controller/controllerprotocol.h create mode 100644 plugins/feature/gs232controller/dfmprotocol.cpp create mode 100644 plugins/feature/gs232controller/dfmprotocol.h create mode 100644 plugins/feature/gs232controller/dfmstatusdialog.cpp create mode 100644 plugins/feature/gs232controller/dfmstatusdialog.h create mode 100644 plugins/feature/gs232controller/dfmstatusdialog.ui create mode 100644 plugins/feature/gs232controller/gs232protocol.cpp create mode 100644 plugins/feature/gs232controller/gs232protocol.h create mode 100644 plugins/feature/gs232controller/rotctrldprotocol.cpp create mode 100644 plugins/feature/gs232controller/rotctrldprotocol.h create mode 100644 plugins/feature/gs232controller/spidprotocol.cpp create mode 100644 plugins/feature/gs232controller/spidprotocol.h diff --git a/plugins/feature/gs232controller/CMakeLists.txt b/plugins/feature/gs232controller/CMakeLists.txt index ccc58673f..cfab468b1 100644 --- a/plugins/feature/gs232controller/CMakeLists.txt +++ b/plugins/feature/gs232controller/CMakeLists.txt @@ -6,6 +6,11 @@ set(gs232controller_SOURCES gs232controllerplugin.cpp gs232controllerworker.cpp gs232controllerwebapiadapter.cpp + controllerprotocol.cpp + gs232protocol.cpp + spidprotocol.cpp + rotctrldprotocol.cpp + dfmprotocol.cpp ) set(gs232controller_HEADERS @@ -15,6 +20,11 @@ set(gs232controller_HEADERS gs232controllerreport.h gs232controllerworker.h gs232controllerwebapiadapter.h + controllerprotocol.h + gs232protocol.h + spidprotocol.h + rotctrldprotocol.h + dfmprotocol.h ) include_directories( @@ -26,10 +36,13 @@ if(NOT SERVER_MODE) ${gs232controller_SOURCES} gs232controllergui.cpp gs232controllergui.ui + dfmstatusdialog.cpp + dfmstatusdialog.ui ) set(gs232controller_HEADERS ${gs232controller_HEADERS} gs232controllergui.h + dfmstatusdialog.h ) set(TARGET_NAME featuregs232controller) diff --git a/plugins/feature/gs232controller/controllerprotocol.cpp b/plugins/feature/gs232controller/controllerprotocol.cpp new file mode 100644 index 000000000..29baace01 --- /dev/null +++ b/plugins/feature/gs232controller/controllerprotocol.cpp @@ -0,0 +1,157 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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 + +#include "maincore.h" +#include "channel/channelwebapiutils.h" + +#include "gs232controllerreport.h" +#include "controllerprotocol.h" +#include "gs232protocol.h" +#include "spidprotocol.h" +#include "rotctrldprotocol.h" +#include "dfmprotocol.h" + +ControllerProtocol::ControllerProtocol() : + m_device(nullptr), + m_lastAzimuth(-1.0f), + m_lastElevation(-1.0f), + m_msgQueueToFeature(nullptr) +{ +} + +ControllerProtocol::~ControllerProtocol() +{ +} + +void ControllerProtocol::setAzimuth(float azimuth) +{ + setAzimuthElevation(azimuth, m_lastElevation); + m_lastAzimuth = azimuth; +} + +void ControllerProtocol::setAzimuthElevation(float azimuth, float elevation) +{ + m_lastAzimuth = azimuth; + m_lastElevation = elevation; +} + +void ControllerProtocol::applySettings(const GS232ControllerSettings& settings, const QList& settingsKeys, bool force) +{ + if (force) { + m_settings = settings; + } else { + m_settings.applySettings(settingsKeys, settings); + } +} + +void ControllerProtocol::sendMessage(Message *message) +{ + m_msgQueueToFeature->push(message); +} + +void ControllerProtocol::reportAzEl(float az, float el) +{ + m_msgQueueToFeature->push(GS232ControllerReport::MsgReportAzAl::create(az, el)); +} + +void ControllerProtocol::reportError(const QString &message) +{ + m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(message)); +} + +void ControllerProtocol::getPosition(float& latitude, float& longitude) +{ + if (!m_settings.m_track) + { + // When not tracking, use My Position from preferences + // although this precludes having different antennas at different positions + latitude = MainCore::instance()->getSettings().getLatitude(); + longitude = MainCore::instance()->getSettings().getLongitude(); + } + else + { + // When tracking, get position from Star Tracker / Sat Tracker + QRegularExpression re("([FTR])(\\d+):(\\d+)"); + QRegularExpressionMatch match = re.match(m_settings.m_source); + if (match.hasMatch()) + { + QString kind = match.captured(1); + int setIndex = match.captured(2).toInt(); + int index = match.captured(3).toInt(); + if (kind == 'F') + { + double lat, lon; + bool latOk = ChannelWebAPIUtils::getFeatureSetting(setIndex, index, "latitude", lat); + bool lonOk = ChannelWebAPIUtils::getFeatureSetting(setIndex, index, "longitude", lon); + if (latOk && lonOk) + { + latitude = (float)lat; + longitude = (float)lon; + } + else + { + qDebug() << "ControllerProtocol::getPosition - Failed to get position from source: " << m_settings.m_source; + } + } + else + { + double lat, lon; + bool latOk = ChannelWebAPIUtils::getChannelSetting(setIndex, index, "latitude", lat); + bool lonOk = ChannelWebAPIUtils::getChannelSetting(setIndex, index, "longitude", lon); + if (latOk && lonOk) + { + latitude = (float)lat; + longitude = (float)lon; + } + else + { + qDebug() << "ControllerProtocol::getPosition - Failed to get position from source: " << m_settings.m_source; + } + } + } + else + { + qDebug() << "ControllerProtocol::getPosition - Couldn't parse source: " << m_settings.m_source; + } + } + //qDebug() << "ControllerProtocol::getPosition: " << latitude << longitude; +} + +ControllerProtocol *ControllerProtocol::create(GS232ControllerSettings::Protocol protocol) +{ + switch (protocol) + { + case GS232ControllerSettings::GS232: + return new GS232Protocol(); + break; + case GS232ControllerSettings::SPID: + return new SPIDProtocol(); + break; + case GS232ControllerSettings::ROTCTLD: + return new RotCtrlDProtocol(); + break; + case GS232ControllerSettings::DFM: + return new DFMProtocol(); + break; + default: + return nullptr; + } +} + + diff --git a/plugins/feature/gs232controller/controllerprotocol.h b/plugins/feature/gs232controller/controllerprotocol.h new file mode 100644 index 000000000..9bc82269b --- /dev/null +++ b/plugins/feature/gs232controller/controllerprotocol.h @@ -0,0 +1,57 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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_CONTROLLERPROTOCOL_H_ +#define INCLUDE_FEATURE_CONTROLLERPROTOCOL_H_ + +#include + +#include "util/messagequeue.h" +#include "gs232controllersettings.h" +#include "gs232controller.h" + +class ControllerProtocol +{ +public: + ControllerProtocol(); + virtual ~ControllerProtocol(); + virtual void setAzimuth(float azimuth); + virtual void setAzimuthElevation(float azimuth, float elevation) = 0; + virtual void readData() = 0; + virtual void update() = 0; + void setDevice(QIODevice *device) { m_device = device; } + virtual void applySettings(const GS232ControllerSettings& settings, const QList& settingsKeys, bool force); + void setMessageQueue(MessageQueue *messageQueue) { m_msgQueueToFeature = messageQueue; } + void sendMessage(Message *message); + void reportAzEl(float az, float el); + void reportError(const QString &message); + void getPosition(float& latitude, float& longitude); + + static ControllerProtocol *create(GS232ControllerSettings::Protocol protocol); + +protected: + QIODevice *m_device; + GS232ControllerSettings m_settings; + float m_lastAzimuth; + float m_lastElevation; + +private: + MessageQueue *m_msgQueueToFeature; +}; + +#endif // INCLUDE_FEATURE_CONTROLLERPROTOCOL_H_ + diff --git a/plugins/feature/gs232controller/dfmprotocol.cpp b/plugins/feature/gs232controller/dfmprotocol.cpp new file mode 100644 index 000000000..63b65826b --- /dev/null +++ b/plugins/feature/gs232controller/dfmprotocol.cpp @@ -0,0 +1,239 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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 + +#include "util/astronomy.h" + +#include "dfmprotocol.h" + +MESSAGE_CLASS_DEFINITION(DFMProtocol::MsgReportDFMStatus, Message) + +DFMProtocol::DFMProtocol() : + m_packetCnt(0) +{ + // Call periodicTask() every 500ms + connect(&m_timer, &QTimer::timeout, this, &DFMProtocol::periodicTask); + m_timer.start(500); +} + +DFMProtocol::~DFMProtocol() +{ + m_timer.stop(); +} + +void DFMProtocol::setAzimuthElevation(float azimuth, float elevation) +{ + // This gets position from source plugin in track is enabled (E.g. Star Tracker / Satellite tracker) + // or My Position preference, if not tracking + float latitude, longitude; + getPosition(latitude, longitude); + + // Convert az/el to RA/Dec + AzAlt aa; + aa.az = azimuth; + aa.alt = elevation; + QDateTime dt = QDateTime::currentDateTime(); + RADec rd = Astronomy::azAltToRaDec(aa, latitude, longitude, dt); + // Save as target + m_targetRA = rd.ra; + m_targetDec = rd.dec; + + // Call parent method to save m_lastAzimuth and m_lastElevation + ControllerProtocol::setAzimuthElevation(azimuth, elevation); +} + +// Handle data received from LCU +// Packets are of the form #L,L,f,f,..,f; +void DFMProtocol::readData() +{ + char c; + while (m_device->getChar(&c)) + { + if (c == '#') + { + // Start packet + m_rxBuffer = QString(c); + } + else if (c == ';') + { + // End packet + m_rxBuffer.append(c); + + // Only process if we have valid packet + if (m_rxBuffer.startsWith('#')) + { + parseLCUResponse(m_rxBuffer); + m_rxBuffer = ""; + } + else + { + qDebug() << "DFMProtocol::readData - Ignoring partial packet: " << m_rxBuffer; + } + } + else + { + m_rxBuffer.append(c); + } + } +} + +void DFMProtocol::parseLCUResponse(const QString& packet) +{ + qDebug() << "DFMProtocol::parseLCUResponse - " << packet; + + // Check packet starts with expected header + if (!packet.startsWith("#L,L,")) + { + qDebug() << "DFMProtocol::readData - Ignoring non LCU packet: " << m_rxBuffer; + return; + } + + // Strip off header and footer + QString strippedPacket = packet.mid(5, packet.length() - 6); + + // Convert packet to list of strings + QStringList dataStrings = strippedPacket.split(","); + + // Extract values we are interested in + DFMStatus status; + + int statl = (int)dataStrings[1].toFloat(); + status.m_initialized = statl & 1; + status.m_brakesOn = (statl >> 1) & 1; + status.m_trackOn = (statl >> 2) & 1; + status.m_slewEnabled = (statl >> 3) & 1; + status.m_lubePumpsOn = (statl >> 4) & 1; + status.m_approachingSWLimit = (statl >> 5) & 1; + status.m_finalSWLimit = (statl >> 6) & 1; + status.m_slewing = (statl >> 7) & 1; + + int stath = (int)dataStrings[2].toFloat(); + status.m_setting = stath & 1; + status.m_haltMotorsIn = (stath >> 1) & 1; + status.m_excomSwitchOn = (stath >> 2) & 1; + status.m_servoPackAlarm = (stath >> 3) & 1; + status.m_targetOutOfRange = (stath >> 4) & 1; + status.m_cosdecOn = (stath >> 5) & 1; + status.m_rateCorrOn = (stath >> 6) & 1; + status.m_drivesOn = (stath >> 7) & 1; + + int statlh = (int)dataStrings[3].toFloat(); + status.m_pumpsReady = statlh & 1; + // Bit 1 unknown + status.m_minorPlus = (statlh >> 2) & 1; + status.m_minorMinus = (statlh >> 3) & 1; + status.m_majorPlus = (statlh >> 4) & 1; + status.m_majorMinus = (statlh >> 5) & 1; + status.m_nextObjectActive = (statlh >> 6) & 1; + status.m_auxTrackRate = (statlh >> 7) & 1; + + status.m_siderealTime = dataStrings[5].toFloat(); + status.m_universalTime = dataStrings[6].toFloat(); + + status.m_currentHA = dataStrings[7].toFloat(); + status.m_currentRA = dataStrings[8].toFloat(); + status.m_currentDec = dataStrings[9].toFloat(); + + status.m_currentX = dataStrings[20].toFloat(); + status.m_currentY = dataStrings[21].toFloat(); + + status.m_siderealRateX = dataStrings[30].toFloat(); + status.m_siderealRateY = dataStrings[31].toFloat(); + + status.m_torqueX = dataStrings[34].toFloat(); + status.m_torqueY = dataStrings[35].toFloat(); + + status.m_controller = (DFMStatus::Controller)dataStrings[38].toInt(); + + status.m_rateX = dataStrings[39].toFloat(); + status.m_rateY = dataStrings[40].toFloat(); + + // Display status in GUI + sendMessage(MsgReportDFMStatus::create(status)); + + // Convert current X/Y to Az/El + AzAlt aa = Astronomy::xy85ToAzAlt(status.m_currentX, status.m_currentY); + float az = aa.az; + float el = aa.alt; + reportAzEl(az, el); + + // If this is the second LCU packet, we send a commmand + m_packetCnt++; + if (m_packetCnt == 2) + { + m_packetCnt = 0; + sendCommand(); + } +} + +void DFMProtocol::sendCommand() +{ + // TODO: Use m_lastAzimuth/m_lastElevation or m_targetRA/m_targetDec to calculate position commands + + // Send a command to the LCU + int cmdId = 98; + int handPaddle = 0; + int frontPanel = (m_settings.m_dfmDrivesOn << 2) + | (m_settings.m_dfmTrackOn << 3) + | (m_settings.m_dfmLubePumpsOn << 4) + | (m_settings.m_dfmBrakesOn << 7); + + QString cmd = QString("#M,R,%1,%2.000000,%3.000000;").arg(cmdId).arg(handPaddle).arg(frontPanel); + m_device->write(cmd.toLatin1()); + + qDebug() << "DFMProtocol::sendCommand - " << cmd; +} + +// Request current Az/El +void DFMProtocol::update() +{ + // This is called periodically for protocols that need to send a command to get current az/el + // However, for this protocol, we might not need to do anything here, + // if we're continually calling reportAzEl() in response to packets received from the LCU. + //sendCommand(); +} + +void DFMProtocol::periodicTask() +{ + // Just as an example, this will be called every 500ms. Can be removed if not needed +} + +// This is called when new settings are available from GUI (or API). +void DFMProtocol::applySettings(const GS232ControllerSettings& settings, const QList& settingsKeys, bool force) +{ + if (settingsKeys.contains("dfmTrackOn") || force) + { + // Do something with settings.m_dfmTrackOn if needed + } + if (settingsKeys.contains("dfmLubePumpsOn") || force) + { + // Do something with settings.m_dfmLubePumpsOn if needed + } + if (settingsKeys.contains("dfmBrakesOn") || force) + { + // Do something with settings.m_dfmBreaksOn if needed + } + if (settingsKeys.contains("dfmDrivesOn") || force) + { + // Do something with settings.m_dfmDrivesOn if needed + } + + // Call parent method to set m_settings to settings + ControllerProtocol::applySettings(settings, settingsKeys, force); +} + diff --git a/plugins/feature/gs232controller/dfmprotocol.h b/plugins/feature/gs232controller/dfmprotocol.h new file mode 100644 index 000000000..ad0704db3 --- /dev/null +++ b/plugins/feature/gs232controller/dfmprotocol.h @@ -0,0 +1,120 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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_DFMPROTOCOL_H_ +#define INCLUDE_FEATURE_DFMPROTOCOL_H_ + +#include + +#include "util/message.h" +#include "controllerprotocol.h" + +class DFMProtocol : public QObject, public ControllerProtocol +{ + Q_OBJECT +public: + + struct DFMStatus { + // STATL + bool m_initialized; + bool m_brakesOn; + bool m_trackOn; + bool m_slewEnabled; + bool m_lubePumpsOn; + bool m_approachingSWLimit; + bool m_finalSWLimit; + bool m_slewing; + // STATH + bool m_setting; + bool m_haltMotorsIn; + bool m_excomSwitchOn; + bool m_servoPackAlarm; + bool m_targetOutOfRange; + bool m_cosdecOn; + bool m_rateCorrOn; + bool m_drivesOn; + // STATLH + bool m_pumpsReady; + bool m_minorPlus; + bool m_minorMinus; + bool m_majorPlus; + bool m_majorMinus; + bool m_nextObjectActive; + bool m_auxTrackRate; + // Other status information + float m_currentHA; + float m_currentRA; + float m_currentDec; + float m_currentX; + float m_currentY; + enum Controller {NONE, OCU, LCU, MCU} m_controller; + float m_torqueX; + float m_torqueY; + float m_rateX; + float m_rateY; + float m_siderealRateX; + float m_siderealRateY; + float m_siderealTime; + float m_universalTime; + }; + + // Message from DFMProtocol to the GUI, with status information to display + class MsgReportDFMStatus : public Message { + MESSAGE_CLASS_DECLARATION + + public: + DFMStatus getDFMStatus() const { return m_dfmStatus; } + + static MsgReportDFMStatus* create(const DFMStatus& dfmStatus) + { + return new MsgReportDFMStatus(dfmStatus); + } + private: + DFMStatus m_dfmStatus; + + MsgReportDFMStatus(const DFMStatus& dfmStatus) : + Message(), + m_dfmStatus(dfmStatus) + { + } + }; + + DFMProtocol(); + ~DFMProtocol(); + void setAzimuthElevation(float azimuth, float elevation) override; + void readData() override; + void update() override; + void applySettings(const GS232ControllerSettings& settings, const QList& settingsKeys, bool force) override; + +private: + void parseLCUResponse(const QString& packet); + void sendCommand(); + + QTimer m_timer; + + QString m_rxBuffer; + int m_packetCnt; + + float m_targetRA; + float m_targetDec; + +private slots: + void periodicTask(); +}; + +#endif // INCLUDE_FEATURE_DFMPROTOCOL_H_ + diff --git a/plugins/feature/gs232controller/dfmstatusdialog.cpp b/plugins/feature/gs232controller/dfmstatusdialog.cpp new file mode 100644 index 000000000..7e7c07c8f --- /dev/null +++ b/plugins/feature/gs232controller/dfmstatusdialog.cpp @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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 "util/units.h" + +#include "dfmstatusdialog.h" + +DFMStatusDialog::DFMStatusDialog(QWidget* parent) : + QDialog(parent), + ui(new Ui::DFMStatusDialog) +{ + ui->setupUi(this); + // Make checkboxes read-only + ui->trackOn->setAttribute(Qt::WA_TransparentForMouseEvents); + ui->driveOn->setAttribute(Qt::WA_TransparentForMouseEvents); + ui->brakesOn->setAttribute(Qt::WA_TransparentForMouseEvents); + ui->pumpsOn->setAttribute(Qt::WA_TransparentForMouseEvents); + ui->controller->setAttribute(Qt::WA_TransparentForMouseEvents); +} + +void DFMStatusDialog::displayStatus(const DFMProtocol::DFMStatus& dfmStatus) +{ + ui->currentHA->setText(QString::number(dfmStatus.m_currentHA, 'f')); + ui->currentRA->setText(QString::number(dfmStatus.m_currentRA, 'f')); + ui->currentDec->setText(QString::number(dfmStatus.m_currentDec, 'f')); + + ui->st->setText(Units::decimalHoursToHoursMinutesAndSeconds(dfmStatus.m_siderealTime)); + ui->ut->setText(Units::decimalHoursToHoursMinutesAndSeconds(dfmStatus.m_universalTime)); + + ui->currentX->setText(QString::number(dfmStatus.m_currentX, 'f')); + ui->currentY->setText(QString::number(dfmStatus.m_currentY, 'f')); + ui->siderealRateX->setText(QString::number(dfmStatus.m_siderealRateX, 'f')); + ui->siderealRateY->setText(QString::number(dfmStatus.m_siderealRateY, 'f')); + ui->rateX->setText(QString::number(dfmStatus.m_rateX, 'f')); + ui->rateY->setText(QString::number(dfmStatus.m_rateY, 'f')); + ui->torqueX->setText(QString::number(dfmStatus.m_torqueX, 'f')); + ui->torqueY->setText(QString::number(dfmStatus.m_torqueY, 'f')); + + ui->trackOn->setChecked(dfmStatus.m_trackOn); + ui->driveOn->setChecked(dfmStatus.m_drivesOn); + ui->brakesOn->setChecked(dfmStatus.m_brakesOn); + ui->pumpsOn->setChecked(dfmStatus.m_pumpsReady); // ? + ui->controller->setCurrentIndex((int)dfmStatus.m_controller); +} + +DFMStatusDialog::~DFMStatusDialog() +{ + delete ui; +} + +void DFMStatusDialog::accept() +{ + QDialog::accept(); +} + diff --git a/plugins/feature/gs232controller/dfmstatusdialog.h b/plugins/feature/gs232controller/dfmstatusdialog.h new file mode 100644 index 000000000..93340f065 --- /dev/null +++ b/plugins/feature/gs232controller/dfmstatusdialog.h @@ -0,0 +1,40 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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_DFMSTATUSSDIALOG_H +#define INCLUDE_DFMSTATUSSDIALOG_H + +#include "ui_dfmstatusdialog.h" +#include "dfmprotocol.h" + +class DFMStatusDialog : public QDialog { + Q_OBJECT + +public: + explicit DFMStatusDialog(QWidget* parent = 0); + ~DFMStatusDialog(); + void displayStatus(const DFMProtocol::DFMStatus& dfmStatus); + +private slots: + void accept(); + +private: + Ui::DFMStatusDialog* ui; +}; + +#endif // INCLUDE_DFMSTATUSSDIALOG_H + diff --git a/plugins/feature/gs232controller/dfmstatusdialog.ui b/plugins/feature/gs232controller/dfmstatusdialog.ui new file mode 100644 index 000000000..89179dd62 --- /dev/null +++ b/plugins/feature/gs232controller/dfmstatusdialog.ui @@ -0,0 +1,413 @@ + + + DFMStatusDialog + + + + 0 + 0 + 474 + 488 + + + + + Liberation Sans + 9 + + + + DFM Status + + + + + + + + + Status + + + + + + Track + + + + + + + Qt::NoFocus + + + + + + true + + + + + + + Drives + + + + + + + Qt::NoFocus + + + + + + true + + + + + + + Brakes + + + + + + + Qt::NoFocus + + + + + + true + + + + + + + Pumps + + + + + + + true + + + Qt::NoFocus + + + + + + true + + + + + + + + None + + + + + OCU + + + + + LCU + + + + + MCU + + + + + + + + Controller + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Antenna Position + + + + + + true + + + + + + + RA + + + + + + + Dec + + + + + + + true + + + + + + + HA + + + + + + + true + + + + + + + + + + Date/Time + + + + + + ST + + + + + + + UT + + + + + + + true + + + + + + + true + + + + + + + + + + X/Y Status + + + + + + true + + + + + + + true + + + + + + + Torque + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + Rate + + + + + + + X + + + Qt::AlignCenter + + + + + + + Antenna + + + + + + + Y + + + Qt::AlignCenter + + + + + + + true + + + + + + + Sidereal Rate + + + + + + + true + + + + + + + true + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + DFMStatusDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DFMStatusDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/plugins/feature/gs232controller/gs232controller.cpp b/plugins/feature/gs232controller/gs232controller.cpp index 31387826b..6f58478be 100644 --- a/plugins/feature/gs232controller/gs232controller.cpp +++ b/plugins/feature/gs232controller/gs232controller.cpp @@ -39,12 +39,14 @@ #include "gs232controller.h" #include "gs232controllerworker.h" #include "gs232controllerreport.h" +#include "dfmprotocol.h" MESSAGE_CLASS_DEFINITION(GS232Controller::MsgConfigureGS232Controller, Message) MESSAGE_CLASS_DEFINITION(GS232Controller::MsgStartStop, Message) MESSAGE_CLASS_DEFINITION(GS232Controller::MsgReportWorker, Message) MESSAGE_CLASS_DEFINITION(GS232Controller::MsgReportAvailableChannelOrFeatures, Message) MESSAGE_CLASS_DEFINITION(GS232Controller::MsgScanAvailableChannelOrFeatures, Message) +MESSAGE_CLASS_DEFINITION(GS232Controller::MsgReportSerialPorts, Message) const char* const GS232Controller::m_featureIdURI = "sdrangel.feature.gs232controller"; const char* const GS232Controller::m_featureId = "GS232Controller"; @@ -52,7 +54,9 @@ const char* const GS232Controller::m_featureId = "GS232Controller"; GS232Controller::GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface) : Feature(m_featureIdURI, webAPIAdapterInterface), m_thread(nullptr), - m_worker(nullptr) + m_worker(nullptr), + m_currentAzimuth(0.0f), + m_currentElevation(0.0f) { qDebug("GS232Controller::GS232Controller: webAPIAdapterInterface: %p", webAPIAdapterInterface); setObjectName(m_featureId); @@ -90,10 +94,14 @@ GS232Controller::GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface) this, &GS232Controller::handleChannelRemoved ); + connect(&m_timer, &QTimer::timeout, this, &GS232Controller::scanSerialPorts); + m_timer.start(5000); } GS232Controller::~GS232Controller() { + m_timer.stop(); + disconnect(&m_timer, &QTimer::timeout, this, &GS232Controller::scanSerialPorts); QObject::disconnect( MainCore::instance(), &MainCore::channelRemoved, @@ -244,6 +252,16 @@ bool GS232Controller::handleMessage(const Message& cmd) } return true; } + else if (DFMProtocol::MsgReportDFMStatus::match(cmd)) + { + // Forward to GUI + if (getMessageQueueToGUI()) + { + DFMProtocol::MsgReportDFMStatus& report = (DFMProtocol::MsgReportDFMStatus&) cmd; + getMessageQueueToGUI()->push(new DFMProtocol::MsgReportDFMStatus(report)); + } + return true; + } else { return false; @@ -256,8 +274,8 @@ bool GS232Controller::getOnTarget() const float targetAziumth, targetElevation; m_settings.calcTargetAzEl(targetAziumth, targetElevation); float readTolerance = m_settings.m_tolerance + 0.0f; - bool onTarget = (std::fabs(m_currentAzimuth - targetAziumth) < readTolerance) - && (std::fabs(m_currentElevation - targetElevation) < readTolerance); + bool onTarget = (std::fabs(m_currentAzimuth - targetAziumth) <= readTolerance) + && (std::fabs(m_currentElevation - targetElevation) <= readTolerance); return onTarget; } @@ -471,6 +489,8 @@ void GS232Controller::webapiFormatFeatureSettings( response.getGs232ControllerSettings()->setElevationMax(settings.m_elevationMax); response.getGs232ControllerSettings()->setTolerance(settings.m_tolerance); response.getGs232ControllerSettings()->setProtocol(settings.m_protocol); + response.getGs232ControllerSettings()->setPrecision(settings.m_precision); + response.getGs232ControllerSettings()->setCoordinates((int)settings.m_coordinates); if (response.getGs232ControllerSettings()->getTitle()) { *response.getGs232ControllerSettings()->getTitle() = settings.m_title; @@ -559,6 +579,12 @@ void GS232Controller::webapiUpdateFeatureSettings( if (featureSettingsKeys.contains("protocol")) { settings.m_protocol = (GS232ControllerSettings::Protocol)response.getGs232ControllerSettings()->getProtocol(); } + if (featureSettingsKeys.contains("precision")) { + settings.m_precision = response.getGs232ControllerSettings()->getPrecision(); + } + if (featureSettingsKeys.contains("coordinates")) { + settings.m_coordinates = (GS232ControllerSettings::Coordinates)response.getGs232ControllerSettings()->getCoordinates(); + } if (featureSettingsKeys.contains("title")) { settings.m_title = *response.getGs232ControllerSettings()->getTitle(); } @@ -644,6 +670,12 @@ void GS232Controller::webapiReverseSendSettings(const QList& featureSet if (featureSettingsKeys.contains("protocol") || force) { swgGS232ControllerSettings->setProtocol((int)settings.m_protocol); } + if (featureSettingsKeys.contains("precision") || force) { + swgGS232ControllerSettings->setPrecision(settings.m_precision); + } + if (featureSettingsKeys.contains("coordinates") || force) { + swgGS232ControllerSettings->setCoordinates(settings.m_coordinates); + } if (featureSettingsKeys.contains("title") || force) { swgGS232ControllerSettings->setTitle(new QString(settings.m_title)); } @@ -686,14 +718,9 @@ void GS232Controller::webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& r response.getGs232ControllerReport()->getSources()->append(new QString(itemText)); } - QList serialPorts = QSerialPortInfo::availablePorts(); - QListIterator i(serialPorts); response.getGs232ControllerReport()->setSerialPorts(new QList()); - - while (i.hasNext()) - { - QSerialPortInfo info = i.next(); - response.getGs232ControllerReport()->getSerialPorts()->append(new QString(info.portName())); + for (const auto& serialPort : m_serialPorts) { + response.getGs232ControllerReport()->getSerialPorts()->append(new QString(serialPort)); } float azimuth, elevation; @@ -895,3 +922,27 @@ void GS232Controller::handlePipeMessageQueue(MessageQueue* messageQueue) } } } + +void GS232Controller::scanSerialPorts() +{ + // This can take 4ms on Windows, so we don't want to have it in webapiFormatFeatureReport + // as polling of target az/el by other plugins will be slowed down + QList serialPortInfos = QSerialPortInfo::availablePorts(); + QListIterator i(serialPortInfos); + QStringList serialPorts; + while (i.hasNext()) + { + QSerialPortInfo info = i.next(); + serialPorts.append(info.portName()); + } + if (m_serialPorts != serialPorts) + { + if (getMessageQueueToGUI()) + { + MsgReportSerialPorts *msg = MsgReportSerialPorts::create(serialPorts); + getMessageQueueToGUI()->push(msg); + } + m_serialPorts = serialPorts; + } +} + diff --git a/plugins/feature/gs232controller/gs232controller.h b/plugins/feature/gs232controller/gs232controller.h index e5662c61a..e8e507d58 100644 --- a/plugins/feature/gs232controller/gs232controller.h +++ b/plugins/feature/gs232controller/gs232controller.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "feature/feature.h" #include "util/message.h" @@ -138,6 +139,25 @@ public: { } }; + class MsgReportSerialPorts : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const QStringList& getSerialPorts() const { return m_serialPorts; } + + static MsgReportSerialPorts* create(QStringList serialPorts) { + return new MsgReportSerialPorts(serialPorts); + } + + private: + QStringList m_serialPorts; + + MsgReportSerialPorts(QStringList serialPorts) : + Message(), + m_serialPorts(serialPorts) + {} + }; + GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface); virtual ~GS232Controller(); virtual void destroy() { delete this; } @@ -194,6 +214,9 @@ private: QHash m_availableChannelOrFeatures; QObject *m_selectedPipe; + QTimer m_timer; + QStringList m_serialPorts; + QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; @@ -217,6 +240,7 @@ private slots: void handleChannelRemoved(int deviceSetIndex, ChannelAPI *feature); void handleMessagePipeToBeDeleted(int reason, QObject* object); void handlePipeMessageQueue(MessageQueue* messageQueue); + void scanSerialPorts(); }; #endif // INCLUDE_FEATURE_GS232CONTROLLER_H_ diff --git a/plugins/feature/gs232controller/gs232controllergui.cpp b/plugins/feature/gs232controller/gs232controllergui.cpp index 86ffe3268..3cb42e692 100644 --- a/plugins/feature/gs232controller/gs232controllergui.cpp +++ b/plugins/feature/gs232controller/gs232controllergui.cpp @@ -27,11 +27,13 @@ #include "gui/dialogpositioner.h" #include "mainwindow.h" #include "device/deviceuiset.h" +#include "util/astronomy.h" #include "ui_gs232controllergui.h" #include "gs232controller.h" #include "gs232controllergui.h" #include "gs232controllerreport.h" +#include "dfmprotocol.h" GS232ControllerGUI* GS232ControllerGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature) { @@ -72,6 +74,57 @@ bool GS232ControllerGUI::deserialize(const QByteArray& data) } } +void GS232ControllerGUI::azElToDisplay(float az, float el, float& coord1, float& coord2) const +{ + AzAlt aa; + double c1, c2; + if (m_settings.m_coordinates == GS232ControllerSettings::X_Y_85) + { + aa.az = az; + aa.alt = el; + Astronomy::azAltToXY85(aa, c1, c2); + coord1 = (float)c1; + coord2 = (float)c2; + } + else if (m_settings.m_coordinates == GS232ControllerSettings::X_Y_30) + { + aa.az = az; + aa.alt = el; + Astronomy::azAltToXY30(aa, c1, c2); + coord1 = (float)c1; + coord2 = (float)c2; + } + else + { + coord1 = az; + coord2 = el; + } +} + +void GS232ControllerGUI::displayToAzEl(float coord1, float coord2) +{ + if (m_settings.m_coordinates == GS232ControllerSettings::X_Y_85) + { + AzAlt aa = Astronomy::xy85ToAzAlt(coord1, coord2); + m_settings.m_azimuth = aa.az; + m_settings.m_elevation = aa.alt; + } + else if (m_settings.m_coordinates == GS232ControllerSettings::X_Y_30) + { + AzAlt aa = Astronomy::xy30ToAzAlt(coord1, coord2); + m_settings.m_azimuth = aa.az; + m_settings.m_elevation = aa.alt; + } + else + { + m_settings.m_azimuth = coord1; + m_settings.m_elevation = coord2; + } + m_settingsKeys.append("azimuth"); + m_settingsKeys.append("elevation"); + applySettings(); +} + bool GS232ControllerGUI::handleMessage(const Message& message) { if (GS232Controller::MsgConfigureGS232Controller::match(message)) @@ -101,20 +154,35 @@ bool GS232ControllerGUI::handleMessage(const Message& message) else if (GS232ControllerReport::MsgReportAzAl::match(message)) { GS232ControllerReport::MsgReportAzAl& azAl = (GS232ControllerReport::MsgReportAzAl&) message; - ui->azimuthCurrentText->setText(QString("%1").arg(azAl.getAzimuth())); - ui->elevationCurrentText->setText(QString("%1").arg(azAl.getElevation())); + float coord1, coord2; + azElToDisplay(azAl.getAzimuth(), azAl.getElevation(), coord1, coord2); + ui->coord1CurrentText->setText(QString::number(coord1, 'f', m_settings.m_precision)); + ui->coord2CurrentText->setText(QString::number(coord2, 'f', m_settings.m_precision)); return true; } else if (MainCore::MsgTargetAzimuthElevation::match(message)) { MainCore::MsgTargetAzimuthElevation& msg = (MainCore::MsgTargetAzimuthElevation&) message; SWGSDRangel::SWGTargetAzimuthElevation *swgTarget = msg.getSWGTargetAzimuthElevation(); - - ui->azimuth->setValue(swgTarget->getAzimuth()); - ui->elevation->setValue(swgTarget->getElevation()); + float coord1, coord2; + azElToDisplay(swgTarget->getAzimuth(), swgTarget->getElevation(), coord1, coord2); + ui->coord1->setValue(coord1); + ui->coord2->setValue(coord2); ui->targetName->setText(*swgTarget->getName()); return true; } + else if (GS232Controller::MsgReportSerialPorts::match(message)) + { + GS232Controller::MsgReportSerialPorts& msg = (GS232Controller::MsgReportSerialPorts&) message; + updateSerialPortList(msg.getSerialPorts()); + return true; + } + else if (DFMProtocol::MsgReportDFMStatus::match(message)) + { + DFMProtocol::MsgReportDFMStatus& report = (DFMProtocol::MsgReportDFMStatus&) message; + m_dfmStatusDialog.displayStatus(report.getDFMStatus()); + return true; + } return false; } @@ -147,7 +215,8 @@ GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featu m_featureUISet(featureUISet), m_doApplySettings(true), m_lastFeatureState(0), - m_lastOnTarget(false) + m_lastOnTarget(false), + m_dfmStatusDialog() { m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); @@ -166,8 +235,9 @@ GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featu connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(250); - ui->azimuthCurrentText->setText("-"); - ui->elevationCurrentText->setText("-"); + ui->coord1CurrentText->setText("-"); + ui->coord2CurrentText->setText("-"); + setProtocol(m_settings.m_protocol); // Hide DFM buttons updateSerialPortList(); if (ui->serialPort->currentIndex() >= 0) { @@ -182,10 +252,13 @@ GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featu // Get pre-existing pipes m_gs232Controller->getInputMessageQueue()->push(GS232Controller::MsgScanAvailableChannelOrFeatures::create()); + + new DialogPositioner(&m_dfmStatusDialog, true); } GS232ControllerGUI::~GS232ControllerGUI() { + m_dfmStatusDialog.close(); delete ui; } @@ -206,11 +279,14 @@ void GS232ControllerGUI::displaySettings() setWindowTitle(m_settings.m_title); setTitle(m_settings.m_title); blockApplySettings(true); - ui->azimuth->setValue(m_settings.m_azimuth); - ui->elevation->setValue(m_settings.m_elevation); + ui->precision->setValue(m_settings.m_precision); // Must set before protocol and az/el ui->protocol->setCurrentIndex((int)m_settings.m_protocol); + ui->coordinates->setCurrentIndex((int)m_settings.m_coordinates); + float coord1, coord2; + azElToDisplay(m_settings.m_azimuth, m_settings.m_elevation, coord1, coord2); + ui->coord1->setValue(coord1); + ui->coord2->setValue(coord2); ui->connection->setCurrentIndex((int)m_settings.m_connection); - updateDecimals(m_settings.m_protocol); if (m_settings.m_serialPort.length() > 0) { ui->serialPort->lineEdit()->setText(m_settings.m_serialPort); } @@ -226,6 +302,10 @@ void GS232ControllerGUI::displaySettings() ui->elevationMin->setValue(m_settings.m_elevationMin); ui->elevationMax->setValue(m_settings.m_elevationMax); ui->tolerance->setValue(m_settings.m_tolerance); + ui->dfmTrack->setChecked(m_settings.m_dfmTrackOn); + ui->dfmLubePumps->setChecked(m_settings.m_dfmLubePumpsOn); + ui->dfmBrakes->setChecked(m_settings.m_dfmBrakesOn); + ui->dfmDrives->setChecked(m_settings.m_dfmDrivesOn); getRollupContents()->restoreState(m_rollupState); updateConnectionWidgets(); blockApplySettings(false); @@ -256,6 +336,19 @@ void GS232ControllerGUI::updateSerialPortList() } } +void GS232ControllerGUI::updateSerialPortList(const QStringList& serialPorts) +{ + ui->serialPort->blockSignals(true); + ui->serialPort->clear(); + for (const auto& serialPort : serialPorts) { + ui->serialPort->addItem(serialPort); + } + if (!m_settings.m_serialPort.isEmpty()) { + ui->serialPort->setCurrentText(m_settings.m_serialPort); + } + ui->serialPort->blockSignals(false); +} + void GS232ControllerGUI::updatePipeList(const QList& sources) { QString currentText = ui->sources->currentText(); @@ -359,24 +452,53 @@ void GS232ControllerGUI::on_startStop_toggled(bool checked) } } -void GS232ControllerGUI::updateDecimals(GS232ControllerSettings::Protocol protocol) +void GS232ControllerGUI::setProtocol(GS232ControllerSettings::Protocol protocol) { if (protocol == GS232ControllerSettings::GS232) { - ui->azimuth->setDecimals(0); - ui->elevation->setDecimals(0); + ui->precision->setValue(0); + ui->precision->setEnabled(false); + ui->precisionLabel->setEnabled(false); + } + else if (protocol == GS232ControllerSettings::SPID) +ÿ  + ui->precision->setValue(1); + ui->precision->setEnabled(false); + ui->precisionLabel->setEnabled(false); } else { - ui->azimuth->setDecimals(1); - ui->elevation->setDecimals(1); + ui->precision->setEnabled(true); + ui->precisionLabel->setEnabled(true); } + bool dfm = protocol == GS232ControllerSettings::DFM; + ui->dfmLine->setVisible(dfm); + ui->dfmTrack->setVisible(dfm); + ui->dfmLubePumps->setVisible(dfm); + ui->dfmBrakes->setVisible(dfm); + ui->dfmDrives->setVisible(dfm); + ui->dfmShowStatus->setVisible(dfm); + + // See RemoteControlGUI::createGUI() for additional weirdness in trying + // to resize a window after widgets are changed + getRollupContents()->arrangeRollups(); + layout()->activate(); // Recalculate sizeHint + setMinimumSize(sizeHint()); + setMaximumSize(sizeHint()); + resize(sizeHint()); +} + +void GS232ControllerGUI::setPrecision() +{ + ui->coord1->setDecimals(m_settings.m_precision); + ui->coord2->setDecimals(m_settings.m_precision); + ui->tolerance->setDecimals(m_settings.m_precision); } void GS232ControllerGUI::on_protocol_currentIndexChanged(int index) { m_settings.m_protocol = (GS232ControllerSettings::Protocol)index; - updateDecimals(m_settings.m_protocol); + setProtocol(m_settings.m_protocol); m_settingsKeys.append("protocol"); applySettings(); } @@ -419,20 +541,16 @@ void GS232ControllerGUI::on_port_valueChanged(int value) applySettings(); } -void GS232ControllerGUI::on_azimuth_valueChanged(double value) +void GS232ControllerGUI::on_coord1_valueChanged(double value) { - m_settings.m_azimuth = (float)value; + displayToAzEl(value, ui->coord2->value()); ui->targetName->setText(""); - m_settingsKeys.append("azimuth"); - applySettings(); } -void GS232ControllerGUI::on_elevation_valueChanged(double value) +void GS232ControllerGUI::on_coord2_valueChanged(double value) { - m_settings.m_elevation = (float)value; + displayToAzEl(ui->coord1->value(), value); ui->targetName->setText(""); - m_settingsKeys.append("elevation"); - applySettings(); } void GS232ControllerGUI::on_azimuthOffset_valueChanged(int value) @@ -484,6 +602,63 @@ void GS232ControllerGUI::on_tolerance_valueChanged(double value) applySettings(); } +void GS232ControllerGUI::on_precision_valueChanged(int value) +{ + m_settings.m_precision = value; + setPrecision(); + m_settingsKeys.append("precision"); + applySettings(); +} + +void GS232ControllerGUI::on_coordinates_currentIndexChanged(int index) +{ + m_settings.m_coordinates = (GS232ControllerSettings::Coordinates)index; + m_settingsKeys.append("coordinates"); + applySettings(); + + float coord1, coord2; + azElToDisplay(m_settings.m_azimuth, m_settings.m_elevation, coord1, coord2); + + ui->coord1->blockSignals(true); + if (m_settings.m_coordinates == GS232ControllerSettings::AZ_EL) + { + ui->coord1->setMinimum(0.0); + ui->coord1->setMaximum(450.0); + ui->coord1->setToolTip("Target azimuth in degrees"); + ui->coord1Label->setText("Azimuth"); + ui->coord1CurrentText->setToolTip("Current azimuth in degrees"); + } + else + { + ui->coord1->setMinimum(-90.0); + ui->coord1->setMaximum(90.0); + ui->coord1->setToolTip("Target X in degrees"); + ui->coord1Label->setText("X"); + ui->coord1CurrentText->setToolTip("Current X coordinate in degrees"); + } + ui->coord1->setValue(coord1); + ui->coord1->blockSignals(false); + ui->coord2->blockSignals(true); + if (m_settings.m_coordinates == GS232ControllerSettings::AZ_EL) + { + ui->coord2->setMinimum(0.0); + ui->coord2->setMaximum(180.0); + ui->coord2->setToolTip("Target elevation in degrees"); + ui->coord2Label->setText("Elevation"); + ui->coord2CurrentText->setToolTip("Current elevation in degrees"); + } + else + { + ui->coord2->setMinimum(-90.0); + ui->coord2->setMaximum(90.0); + ui->coord2->setToolTip("Target Y in degrees"); + ui->coord2Label->setText("Y"); + ui->coord2CurrentText->setToolTip("Current Y coordinate in degrees"); + } + ui->coord2->setValue(coord2); + ui->coord2->blockSignals(false); +} + void GS232ControllerGUI::on_track_stateChanged(int state) { m_settings.m_track = state == Qt::Checked; @@ -507,6 +682,41 @@ void GS232ControllerGUI::on_sources_currentTextChanged(const QString& text) applySettings(); } +void GS232ControllerGUI::on_dfmTrack_clicked(bool checked) +{ + m_settings.m_dfmTrackOn = checked; + m_settingsKeys.append("dfmTrackOn"); + applySettings(); +} + +void GS232ControllerGUI::on_dfmLubePumps_clicked(bool checked) +{ + m_settings.m_dfmLubePumpsOn = checked; + m_settingsKeys.append("dfmLubePumpsOn"); + applySettings(); +} + +void GS232ControllerGUI::on_dfmBrakes_clicked(bool checked) +{ + m_settings.m_dfmBrakesOn = checked; + m_settingsKeys.append("dfmBrakesOn"); + applySettings(); +} + +void GS232ControllerGUI::on_dfmDrives_clicked(bool checked) +{ + m_settings.m_dfmDrivesOn = checked; + m_settingsKeys.append("dfmDrivesOn"); + applySettings(); +} + +void GS232ControllerGUI::on_dfmShowStatus_clicked() +{ + m_dfmStatusDialog.show(); + m_dfmStatusDialog.raise(); + m_dfmStatusDialog.activateWindow(); +} + void GS232ControllerGUI::updateStatus() { int state = m_gs232Controller->getState(); @@ -583,8 +793,8 @@ void GS232ControllerGUI::makeUIConnections() QObject::connect(ui->port, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_port_valueChanged); QObject::connect(ui->baudRate, qOverload(&QComboBox::currentIndexChanged), this, &GS232ControllerGUI::on_baudRate_currentIndexChanged); QObject::connect(ui->track, &QCheckBox::stateChanged, this, &GS232ControllerGUI::on_track_stateChanged); - QObject::connect(ui->azimuth, qOverload(&QDoubleSpinBox::valueChanged), this, &GS232ControllerGUI::on_azimuth_valueChanged); - QObject::connect(ui->elevation, qOverload(&QDoubleSpinBox::valueChanged), this, &GS232ControllerGUI::on_elevation_valueChanged); + QObject::connect(ui->coord1, qOverload(&QDoubleSpinBox::valueChanged), this, &GS232ControllerGUI::on_coord1_valueChanged); + QObject::connect(ui->coord2, qOverload(&QDoubleSpinBox::valueChanged), this, &GS232ControllerGUI::on_coord2_valueChanged); QObject::connect(ui->sources, &QComboBox::currentTextChanged, this, &GS232ControllerGUI::on_sources_currentTextChanged); QObject::connect(ui->azimuthOffset, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_azimuthOffset_valueChanged); QObject::connect(ui->elevationOffset, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_elevationOffset_valueChanged); @@ -593,4 +803,12 @@ void GS232ControllerGUI::makeUIConnections() QObject::connect(ui->elevationMin, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_elevationMin_valueChanged); QObject::connect(ui->elevationMax, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_elevationMax_valueChanged); QObject::connect(ui->tolerance, qOverload(&QDoubleSpinBox::valueChanged), this, &GS232ControllerGUI::on_tolerance_valueChanged); + QObject::connect(ui->precision, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_precision_valueChanged); + QObject::connect(ui->coordinates, qOverload(&QComboBox::currentIndexChanged), this, &GS232ControllerGUI::on_coordinates_currentIndexChanged); + QObject::connect(ui->dfmTrack, &QToolButton::toggled, this, &GS232ControllerGUI::on_dfmTrack_clicked); + QObject::connect(ui->dfmLubePumps, &QToolButton::toggled, this, &GS232ControllerGUI::on_dfmLubePumps_clicked); + QObject::connect(ui->dfmBrakes, &QToolButton::toggled, this, &GS232ControllerGUI::on_dfmBrakes_clicked); + QObject::connect(ui->dfmDrives, &QToolButton::toggled, this, &GS232ControllerGUI::on_dfmDrives_clicked); + QObject::connect(ui->dfmShowStatus, &QToolButton::clicked, this, &GS232ControllerGUI::on_dfmShowStatus_clicked); } + diff --git a/plugins/feature/gs232controller/gs232controllergui.h b/plugins/feature/gs232controller/gs232controllergui.h index 5d2426e52..2005d363b 100644 --- a/plugins/feature/gs232controller/gs232controllergui.h +++ b/plugins/feature/gs232controller/gs232controllergui.h @@ -26,6 +26,7 @@ #include "settings/rollupstate.h" #include "gs232controllersettings.h" +#include "dfmstatusdialog.h" class PluginAPI; class FeatureUISet; @@ -65,18 +66,24 @@ private: int m_lastFeatureState; bool m_lastOnTarget; + DFMStatusDialog m_dfmStatusDialog; + explicit GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); virtual ~GS232ControllerGUI(); void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); + void setProtocol(GS232ControllerSettings::Protocol protocol); + void setPrecision(); void updateConnectionWidgets(); - void updateDecimals(GS232ControllerSettings::Protocol protocol); void updatePipeList(const QList& sources); void updateSerialPortList(); + void updateSerialPortList(const QStringList& serialPorts); bool handleMessage(const Message& message); void makeUIConnections(); + void azElToDisplay(float az, float el, float& coord1, float& coord2) const; + void displayToAzEl(float coord1, float coord2); private slots: void onMenuDialogCalled(const QPoint &p); @@ -90,8 +97,8 @@ private slots: void on_port_valueChanged(int value); void on_baudRate_currentIndexChanged(int index); void on_track_stateChanged(int state); - void on_azimuth_valueChanged(double value); - void on_elevation_valueChanged(double value); + void on_coord1_valueChanged(double value); + void on_coord2_valueChanged(double value); void on_sources_currentTextChanged(const QString& text); void on_azimuthOffset_valueChanged(int value); void on_elevationOffset_valueChanged(int value); @@ -100,7 +107,15 @@ private slots: void on_elevationMin_valueChanged(int value); void on_elevationMax_valueChanged(int value); void on_tolerance_valueChanged(double value); + void on_precision_valueChanged(int value); + void on_coordinates_currentIndexChanged(int index); + void on_dfmTrack_clicked(bool checked=false); + void on_dfmLubePumps_clicked(bool checked=false); + void on_dfmBrakes_clicked(bool checked=false); + void on_dfmDrives_clicked(bool checked=false); + void on_dfmShowStatus_clicked(); void updateStatus(); }; #endif // INCLUDE_FEATURE_GS232CONTROLLERGUI_H_ + diff --git a/plugins/feature/gs232controller/gs232controllergui.ui b/plugins/feature/gs232controller/gs232controllergui.ui index b697bc9eb..4a26a83c6 100644 --- a/plugins/feature/gs232controller/gs232controllergui.ui +++ b/plugins/feature/gs232controller/gs232controllergui.ui @@ -7,7 +7,7 @@ 0 0 360 - 281 + 378 @@ -43,7 +43,7 @@ 10 10 341 - 81 + 101 @@ -96,19 +96,28 @@ - + + + + 54 + 0 + + Azimuth + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + - + Target azimuth in degrees - 1 + 0 450.000000000000000 @@ -119,10 +128,10 @@ - + - 32 + 40 0 @@ -130,7 +139,7 @@ Current azimuth in degrees - 360.0 + 360.00 @@ -142,19 +151,28 @@ - + + + + 54 + 0 + + Elevation + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + - + Target elevation in degrees - 1 + 0 180.000000000000000 @@ -165,10 +183,10 @@ - + - 32 + 40 0 @@ -176,7 +194,7 @@ Current elevation in degrees - 180.0 + 180.00 @@ -219,15 +237,76 @@ + + + + Qt::Horizontal + + + + + + + + + Track + + + true + + + + + + + Pumps + + + true + + + + + + + Brakes + + + true + + + + + + + Drives + + + true + + + + + + + Show the DFM status dialog + + + Status + + + + + 10 - 110 + 140 341 - 161 + 191 @@ -258,31 +337,26 @@ - - - - Azimuth min + + + + false + + + Precision (number of decimal places) of azimuth, elevation and tolerance values + + + - - - - - 450 + 5 - - - - Protocol - - - - - - - Elevation max + + + + Hostname / IP address of computer to connect to @@ -293,6 +367,43 @@ + + + + Tolerance + + + + + + + Name of serial port to use to connect to the rotator + + + true + + + + + + + Specify an offset angel in degrees that will be added to the target azimuth to correct for misalignment + + + -360 + + + 360 + + + + + + + Azimuth max + + + @@ -300,34 +411,20 @@ - - - - 180 - - - - - - - Port - - - - - + + - Tolerance in degrees + TCP port number to connect to - - 1 + + 65535 - - + + - Serial Port + Baud rate @@ -348,17 +445,48 @@ - - + + - Tolerance + Serial Port - - + + + + Tolerance in degrees + + + 0 + + + + + + + 450 + + + + + - Elevation offset + Host + + + + + + + Port + + + + + + + Elevation max @@ -369,70 +497,29 @@ - - - - Specify an offset angle in degrees that will be added to the target elevation to correct for misalignment - - - -180 - + + 180 - - 1 - - - - - Hostname / IP address of computer to connect to - - - - - - - Name of serial port to use to connect to the rotator - - - true - - - - - - - Command protocol - - - - GS-232 - - - - - SPID - - - - - rotctld - - - - - - + + - Host + Azimuth min - - + + + + Elevation offset + + + + + 180 @@ -498,40 +585,92 @@ - - + + + + false + - Azimuth max + Precision - - + + - Specify an offset angel in degrees that will be added to the target azimuth to correct for misalignment + Command protocol + + + + GS-232 + + + + + SPID + + + + + rotctld + + + + + DFM + + + + + + + + Specify an offset angle in degrees that will be added to the target elevation to correct for misalignment - -360 + -180 - 360 + 180 + + + 1 - - - - TCP port number to connect to - - - 65535 - - - - - + + - Baud rate + Protocol + + + + + + + Coordinate system + + + + Az/El + + + + + X/Y 85' + + + + + X/Y 30' + + + + + + + + Coordinates @@ -541,24 +680,38 @@ + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
RollupContents QWidget
gui/rollupcontents.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
startStop - azimuth - elevation + coord1 + coord2 track sources + targetName + protocol + connection + serialPort + baudRate + host + port + azimuthOffset + elevationOffset + azimuthMin + azimuthMax + elevationMin + elevationMax + tolerance diff --git a/plugins/feature/gs232controller/gs232controllersettings.cpp b/plugins/feature/gs232controller/gs232controllersettings.cpp index e7aafabdb..8311a957b 100644 --- a/plugins/feature/gs232controller/gs232controllersettings.cpp +++ b/plugins/feature/gs232controller/gs232controllersettings.cpp @@ -49,15 +49,10 @@ void GS232ControllerSettings::resetToDefaults() m_elevation = 0.0f; m_serialPort = ""; m_baudRate = 9600; + m_host = "127.0.0.1"; + m_port = 4533; m_track = false; m_source = ""; - m_title = "Rotator Controller"; - m_rgbColor = QColor(225, 25, 99).rgb(); - m_useReverseAPI = false; - m_reverseAPIAddress = "127.0.0.1"; - m_reverseAPIPort = 8888; - m_reverseAPIFeatureSetIndex = 0; - m_reverseAPIFeatureIndex = 0; m_azimuthOffset = 0; m_elevationOffset = 0; m_azimuthMin = 0; @@ -67,8 +62,19 @@ void GS232ControllerSettings::resetToDefaults() m_tolerance = 1.0f; m_protocol = GS232; m_connection = SERIAL; - m_host = "127.0.0.1"; - m_port = 4533; + m_precision = 0; + m_coordinates = AZ_EL; + m_dfmTrackOn = false; + m_dfmLubePumpsOn = false; + m_dfmBrakesOn = false; + m_dfmDrivesOn = false; + m_title = "Rotator Controller"; + m_rgbColor = QColor(225, 25, 99).rgb(); + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIFeatureSetIndex = 0; + m_reverseAPIFeatureIndex = 0; m_workspaceIndex = 0; } @@ -107,6 +113,12 @@ QByteArray GS232ControllerSettings::serialize() const s.writeS32(27, m_workspaceIndex); s.writeBlob(28, m_geometryBytes); + s.writeS32(29, m_precision); + s.writeS32(30, (int)m_coordinates); + s.writeBool(31, m_dfmTrackOn); + s.writeBool(32, m_dfmLubePumpsOn); + s.writeBool(33, m_dfmBrakesOn); + s.writeBool(34, m_dfmDrivesOn); return s.final(); } @@ -169,6 +181,12 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data) d.readS32(27, &m_workspaceIndex, 0); d.readBlob(28, &m_geometryBytes); + d.readS32(29, &m_precision, 0); + d.readS32(30, (int *)&m_coordinates, (int)AZ_EL); + d.readBool(31, &m_dfmTrackOn); + d.readBool(32, &m_dfmLubePumpsOn); + d.readBool(33, &m_dfmBrakesOn); + d.readBool(34, &m_dfmDrivesOn); return true; } @@ -208,33 +226,18 @@ void GS232ControllerSettings::applySettings(const QStringList& settingsKeys, con if (settingsKeys.contains("baudRate")) { m_baudRate = settings.m_baudRate; } + if (settingsKeys.contains("host")) { + m_host = settings.m_host; + } + if (settingsKeys.contains("port")) { + m_port = settings.m_port; + } if (settingsKeys.contains("track")) { m_track = settings.m_track; } if (settingsKeys.contains("source")) { m_source = settings.m_source; } - if (settingsKeys.contains("title")) { - m_title = settings.m_title; - } - if (settingsKeys.contains("rgbColor")) { - m_rgbColor = settings.m_rgbColor; - } - if (settingsKeys.contains("useReverseAPI")) { - m_useReverseAPI = settings.m_useReverseAPI; - } - if (settingsKeys.contains("reverseAPIAddress")) { - m_reverseAPIAddress = settings.m_reverseAPIAddress; - } - if (settingsKeys.contains("reverseAPIPort")) { - m_reverseAPIPort = settings.m_reverseAPIPort; - } - if (settingsKeys.contains("reverseAPIFeatureSetIndex")) { - m_reverseAPIFeatureSetIndex = settings.m_reverseAPIFeatureSetIndex; - } - if (settingsKeys.contains("reverseAPIFeatureIndex")) { - m_reverseAPIFeatureIndex = settings.m_reverseAPIFeatureIndex; - } if (settingsKeys.contains("azimuthOffset")) { m_azimuthOffset = settings.m_azimuthOffset; } @@ -262,11 +265,44 @@ void GS232ControllerSettings::applySettings(const QStringList& settingsKeys, con if (settingsKeys.contains("connection")) { m_connection = settings.m_connection; } - if (settingsKeys.contains("host")) { - m_host = settings.m_host; + if (settingsKeys.contains("precision")) { + m_precision = settings.m_precision; } - if (settingsKeys.contains("port")) { - m_port = settings.m_port; + if (settingsKeys.contains("coordinates")) { + m_coordinates = settings.m_coordinates; + } + if (settingsKeys.contains("dfmTrackOn")) { + m_dfmTrackOn = settings.m_dfmTrackOn; + } + if (settingsKeys.contains("dfmLubePumpsOn")) { + m_dfmLubePumpsOn = settings.m_dfmLubePumpsOn; + } + if (settingsKeys.contains("dfmBrakesOn")) { + m_dfmBrakesOn = settings.m_dfmBrakesOn; + } + if (settingsKeys.contains("dfmDrivesOn")) { + m_dfmDrivesOn = settings.m_dfmDrivesOn; + } + if (settingsKeys.contains("title")) { + m_title = settings.m_title; + } + if (settingsKeys.contains("rgbColor")) { + m_rgbColor = settings.m_rgbColor; + } + if (settingsKeys.contains("useReverseAPI")) { + m_useReverseAPI = settings.m_useReverseAPI; + } + if (settingsKeys.contains("reverseAPIAddress")) { + m_reverseAPIAddress = settings.m_reverseAPIAddress; + } + if (settingsKeys.contains("reverseAPIPort")) { + m_reverseAPIPort = settings.m_reverseAPIPort; + } + if (settingsKeys.contains("reverseAPIFeatureSetIndex")) { + m_reverseAPIFeatureSetIndex = settings.m_reverseAPIFeatureSetIndex; + } + if (settingsKeys.contains("reverseAPIFeatureIndex")) { + m_reverseAPIFeatureIndex = settings.m_reverseAPIFeatureIndex; } if (settingsKeys.contains("workspaceIndex")) { m_workspaceIndex = settings.m_workspaceIndex; @@ -289,33 +325,18 @@ QString GS232ControllerSettings::getDebugString(const QStringList& settingsKeys, if (settingsKeys.contains("baudRate") || force) { ostr << " m_baudRate: " << m_baudRate; } + if (settingsKeys.contains("host") || force) { + ostr << " m_host: " << m_host.toStdString(); + } + if (settingsKeys.contains("port") || force) { + ostr << " m_port: " << m_port; + } if (settingsKeys.contains("track") || force) { ostr << " m_track: " << m_track; } if (settingsKeys.contains("source") || force) { ostr << " m_source: " << m_source.toStdString(); } - if (settingsKeys.contains("title") || force) { - ostr << " m_title: " << m_title.toStdString(); - } - if (settingsKeys.contains("rgbColor") || force) { - ostr << " m_rgbColor: " << m_rgbColor; - } - if (settingsKeys.contains("useReverseAPI") || force) { - ostr << " m_useReverseAPI: " << m_useReverseAPI; - } - if (settingsKeys.contains("azimuth") || force) { - ostr << " m_reverseAPIAddress: " << m_reverseAPIAddress.toStdString(); - } - if (settingsKeys.contains("reverseAPIPort") || force) { - ostr << " m_reverseAPIPort: " << m_reverseAPIPort; - } - if (settingsKeys.contains("reverseAPIFeatureSetIndex") || force) { - ostr << " m_reverseAPIFeatureSetIndex: " << m_reverseAPIFeatureSetIndex; - } - if (settingsKeys.contains("reverseAPIFeatureIndex") || force) { - ostr << " m_reverseAPIFeatureIndex: " << m_reverseAPIFeatureIndex; - } if (settingsKeys.contains("azimuthOffset") || force) { ostr << " m_azimuthOffset: " << m_azimuthOffset; } @@ -343,11 +364,32 @@ QString GS232ControllerSettings::getDebugString(const QStringList& settingsKeys, if (settingsKeys.contains("connection") || force) { ostr << " m_connection: " << m_connection; } - if (settingsKeys.contains("host") || force) { - ostr << " m_host: " << m_host.toStdString(); + if (settingsKeys.contains("precision") || force) { + ostr << " m_precision: " << m_precision; } - if (settingsKeys.contains("port") || force) { - ostr << " m_port: " << m_port; + if (settingsKeys.contains("coordinates") || force) { + ostr << " m_coordinates: " << m_precision; + } + if (settingsKeys.contains("title") || force) { + ostr << " m_title: " << m_title.toStdString(); + } + if (settingsKeys.contains("rgbColor") || force) { + ostr << " m_rgbColor: " << m_rgbColor; + } + if (settingsKeys.contains("useReverseAPI") || force) { + ostr << " m_useReverseAPI: " << m_useReverseAPI; + } + if (settingsKeys.contains("azimuth") || force) { + ostr << " m_reverseAPIAddress: " << m_reverseAPIAddress.toStdString(); + } + if (settingsKeys.contains("reverseAPIPort") || force) { + ostr << " m_reverseAPIPort: " << m_reverseAPIPort; + } + if (settingsKeys.contains("reverseAPIFeatureSetIndex") || force) { + ostr << " m_reverseAPIFeatureSetIndex: " << m_reverseAPIFeatureSetIndex; + } + if (settingsKeys.contains("reverseAPIFeatureIndex") || force) { + ostr << " m_reverseAPIFeatureIndex: " << m_reverseAPIFeatureIndex; } if (settingsKeys.contains("workspaceIndex") || force) { ostr << " m_workspaceIndex: " << m_workspaceIndex; @@ -355,3 +397,4 @@ QString GS232ControllerSettings::getDebugString(const QStringList& settingsKeys, return QString(ostr.str().c_str()); } + diff --git a/plugins/feature/gs232controller/gs232controllersettings.h b/plugins/feature/gs232controller/gs232controllersettings.h index 7bc4ec97e..eff7863f1 100644 --- a/plugins/feature/gs232controller/gs232controllersettings.h +++ b/plugins/feature/gs232controller/gs232controllersettings.h @@ -58,8 +58,16 @@ struct GS232ControllerSettings int m_elevationMin; int m_elevationMax; float m_tolerance; - enum Protocol { GS232, SPID, ROTCTLD } m_protocol; + enum Protocol { GS232, SPID, ROTCTLD, DFM } m_protocol; enum Connection { SERIAL, TCP } m_connection; + int m_precision; + enum Coordinates { AZ_EL, X_Y_85, X_Y_30 } m_coordinates; + + bool m_dfmTrackOn; + bool m_dfmLubePumpsOn; + bool m_dfmBrakesOn; + bool m_dfmDrivesOn; + Serializable *m_rollupState; QString m_title; quint32 m_rgbColor; diff --git a/plugins/feature/gs232controller/gs232controllerworker.cpp b/plugins/feature/gs232controller/gs232controllerworker.cpp index 1b18b705b..13b9f308d 100644 --- a/plugins/feature/gs232controller/gs232controllerworker.cpp +++ b/plugins/feature/gs232controller/gs232controllerworker.cpp @@ -38,10 +38,11 @@ GS232ControllerWorker::GS232ControllerWorker() : m_pollTimer(this), m_lastAzimuth(-1.0f), m_lastElevation(-1.0f), - m_spidSetOutstanding(false), - m_spidSetSent(false), - m_spidStatusSent(false), - m_rotCtlDReadAz(false) + m_controllerProtocol(nullptr) +// m_spidSetOutstanding(false), +// m_spidSetSent(false), +// m_spidStatusSent(false), +// m_rotCtlDReadAz(false) { } @@ -50,6 +51,7 @@ GS232ControllerWorker::~GS232ControllerWorker() qDebug() << "GS232ControllerWorker::~GS232ControllerWorker"; stopWork(); m_inputMessageQueue.clear(); + delete m_controllerProtocol; } void GS232ControllerWorker::startWork() @@ -115,6 +117,17 @@ void GS232ControllerWorker::applySettings(const GS232ControllerSettings& setting { qDebug() << "GS232ControllerWorker::applySettings:" << settings.getDebugString(settingsKeys, force) << " force: " << force; + if ((settingsKeys.contains("protocol") && (settings.m_protocol != m_settings.m_protocol)) || force) + { + delete m_controllerProtocol; + m_controllerProtocol = ControllerProtocol::create(settings.m_protocol); + if (m_controllerProtocol) + { + m_controllerProtocol->setMessageQueue(m_msgQueueToFeature); + m_controllerProtocol->setDevice(m_device); + } + } + if (settingsKeys.contains("connection") ) { if (m_device && m_device->isOpen()) @@ -126,26 +139,39 @@ void GS232ControllerWorker::applySettings(const GS232ControllerSettings& setting if (settings.m_connection == GS232ControllerSettings::TCP) { - if (settingsKeys.contains("host") || settingsKeys.contains("port") || force) { + if (settingsKeys.contains("host") || settingsKeys.contains("port") || force) + { m_device = openSocket(settings); + if (m_controllerProtocol) { + m_controllerProtocol->setDevice(m_device); + } } } else { - if (settingsKeys.contains("serialPort") || force) { + if (settingsKeys.contains("serialPort") || force) + { m_device = openSerialPort(settings); - } else if (settingsKeys.contains("baudRate") || force) { + if (m_controllerProtocol) { + m_controllerProtocol->setDevice(m_device); + } + } + else if (settingsKeys.contains("baudRate") || force) + { m_serialPort.setBaudRate(settings.m_baudRate); } } - // Must update m_settings before calling setAzimuthElevation, so m_settings.m_protocol is correct if (force) { m_settings = settings; } else { m_settings.applySettings(settingsKeys, settings); } + if (m_controllerProtocol) { + m_controllerProtocol->applySettings(settings, settingsKeys, force); + } + if (m_device != nullptr) { // Apply offset then clamp @@ -220,244 +246,35 @@ QIODevice *GS232ControllerWorker::openSocket(const GS232ControllerSettings& sett void GS232ControllerWorker::setAzimuth(float azimuth) { - if (m_settings.m_protocol == GS232ControllerSettings::GS232) - { - QString cmd = QString("M%1\r\n").arg((int)std::round(azimuth), 3, 10, QLatin1Char('0')); - QByteArray data = cmd.toLatin1(); - m_device->write(data); - } - else - { - setAzimuthElevation(azimuth, m_lastElevation); + if (m_device && m_device->isOpen() && m_controllerProtocol) { + m_controllerProtocol->setAzimuth(azimuth); } + m_lastAzimuth = azimuth; } void GS232ControllerWorker::setAzimuthElevation(float azimuth, float elevation) { - if (m_settings.m_protocol == GS232ControllerSettings::GS232) - { - QString cmd = QString("W%1 %2\r\n").arg((int)std::round(azimuth), 3, 10, QLatin1Char('0')).arg((int)std::round(elevation), 3, 10, QLatin1Char('0')); - QByteArray data = cmd.toLatin1(); - m_device->write(data); + if (m_device && m_device->isOpen() && m_controllerProtocol) { + m_controllerProtocol->setAzimuthElevation(azimuth, elevation); } - else if (m_settings.m_protocol == GS232ControllerSettings::SPID) - { - if (!m_spidSetSent && !m_spidStatusSent) - { - QByteArray cmd(13, (char)0); - cmd[0] = 0x57; // Start - int h = std::round((azimuth + 360.0f) * 2.0f); - cmd[1] = 0x30 | (h / 1000); - cmd[2] = 0x30 | ((h % 1000) / 100); - cmd[3] = 0x30 | ((h % 100) / 10); - cmd[4] = 0x30 | (h % 10); - cmd[5] = 2; // 2 degree per impulse - int v = std::round((elevation + 360.0f) * 2.0f); - cmd[6] = 0x30 | (v / 1000); - cmd[7] = 0x30 | ((v % 1000) / 100); - cmd[8] = 0x30 | ((v % 100) / 10); - cmd[9] = 0x30 | (v % 10); - cmd[10] = 2; // 2 degree per impulse - cmd[11] = 0x2f; // Set cmd - cmd[12] = 0x20; // End - - m_device->write(cmd); - - m_spidSetSent = true; - } - else - { - qDebug() << "GS232ControllerWorker::setAzimuthElevation: Not sent, waiting for status reply"; - m_spidSetOutstanding = true; - } - } - else - { - QString cmd = QString("P %1 %2\n").arg(azimuth).arg(elevation); - QByteArray data = cmd.toLatin1(); - m_device->write(data); - } m_lastAzimuth = azimuth; m_lastElevation = elevation; } void GS232ControllerWorker::readData() { - char buf[1024]; - qint64 len; - - if (m_settings.m_protocol == GS232ControllerSettings::GS232) - { - while (m_device->canReadLine()) - { - len = m_device->readLine(buf, sizeof(buf)); - if (len != -1) - { - QString response = QString::fromUtf8(buf, len); - // MD-02 can return AZ=-00 EL=-00 and other negative angles - QRegularExpression re("AZ=([-\\d]\\d\\d) *EL=([-\\d]\\d\\d)"); - QRegularExpressionMatch match = re.match(response); - if (match.hasMatch()) - { - QString az = match.captured(1); - QString el = match.captured(2); - //qDebug() << "GS232ControllerWorker::readData read Az " << az << " El " << el; - m_msgQueueToFeature->push(GS232ControllerReport::MsgReportAzAl::create(az.toFloat(), el.toFloat())); - } - else if (response == "\r\n") - { - // Ignore - } - else - { - qWarning() << "GS232ControllerWorker::readData - unexpected GS-232 response \"" << response << "\""; - m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Unexpected GS-232 response: %1").arg(response))); - } - } - } - } - else if (m_settings.m_protocol == GS232ControllerSettings::SPID) - { - while (m_device->bytesAvailable() >= 12) - { - len = m_device->read(buf, 12); - if ((len == 12) && (buf[0] == 0x57)) - { - double az; - double el; - az = buf[1] * 100.0 + buf[2] * 10.0 + buf[3] + buf[4] / 10.0 - 360.0; - el = buf[6] * 100.0 + buf[7] * 10.0 + buf[8] + buf[9] / 10.0 - 360.0; - //qDebug() << "GS232ControllerWorker::readData read Az " << az << " El " << el; - m_msgQueueToFeature->push(GS232ControllerReport::MsgReportAzAl::create(az, el)); - if (m_spidStatusSent && m_spidSetSent) { - qDebug() << "GS232ControllerWorker::readData - m_spidStatusSent and m_spidSetSent set simultaneously"; - } - if (m_spidStatusSent) { - m_spidStatusSent = false; - } - if (m_spidSetSent) { - m_spidSetSent = false; - } - if (m_spidSetOutstanding) - { - m_spidSetOutstanding = false; - setAzimuthElevation(m_lastAzimuth, m_lastElevation); - } - } - else - { - QByteArray bytes(buf, (int)len); - qWarning() << "GS232ControllerWorker::readData - unexpected SPID rot2prog response \"" << bytes.toHex() << "\""; - m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Unexpected SPID rot2prog response: %1").arg(bytes.toHex().data()))); - } - } - } - else - { - while (m_device->canReadLine()) - { - len = m_device->readLine(buf, sizeof(buf)); - if (len != -1) - { - QString response = QString::fromUtf8(buf, len).trimmed(); - QRegularExpression rprt("RPRT (-?\\d+)"); - QRegularExpressionMatch matchRprt = rprt.match(response); - QRegularExpression decimal("(-?\\d+.\\d+)"); - QRegularExpressionMatch matchDecimal = decimal.match(response); - if (matchRprt.hasMatch()) - { - // See rig_errcode_e in hamlib rig.h - const QStringList errors = { - "OK", - "Invalid parameter", - "Invalid configuration", - "No memory", - "Not implemented", - "Timeout", - "IO error", - "Internal error", - "Protocol error", - "Command rejected", - "Arg truncated", - "Not available", - "VFO not targetable", - "Bus error", - "Collision on bus", - "NULL rig handled or invalid pointer parameter", - "Invalid VFO", - "Argument out of domain of function" - }; - int rprt = matchRprt.captured(1).toInt(); - if (rprt != 0) - { - qWarning() << "GS232ControllerWorker::readData - rotctld error: " << errors[-rprt]; - // Seem to get a lot of EPROTO errors from rotctld due to extra 00 char in response to GS232 C2 command - // E.g: ./rotctld.exe -m 603 -r com7 -vvvvv - // read_string(): RX 16 characters - // 0000 00 41 5a 3d 31 37 35 20 20 45 4c 3d 30 33 38 0d .AZ=175 EL=038. - // So don't pass these to GUI for now - if (rprt != -8) { - m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("rotctld error: %1").arg(errors[-rprt]))); - } - } - m_rotCtlDReadAz = false; - } - else if (matchDecimal.hasMatch() && !m_rotCtlDReadAz) - { - m_rotCtlDAz = response; - m_rotCtlDReadAz = true; - } - else if (matchDecimal.hasMatch() && m_rotCtlDReadAz) - { - QString az = m_rotCtlDAz; - QString el = response; - m_rotCtlDReadAz = false; - //qDebug() << "GS232ControllerWorker::readData read Az " << az << " El " << el; - m_msgQueueToFeature->push(GS232ControllerReport::MsgReportAzAl::create(az.toFloat(), el.toFloat())); - } - else - { - qWarning() << "GS232ControllerWorker::readData - Unexpected rotctld response \"" << response << "\""; - m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Unexpected rotctld response: %1").arg(response))); - } - } - } + if (m_controllerProtocol) { + m_controllerProtocol->readData(); } } void GS232ControllerWorker::update() { // Request current Az/El from controller - if (m_device && m_device->isOpen()) - { - if (m_settings.m_protocol == GS232ControllerSettings::GS232) - { - QByteArray cmd("C2\r\n"); - m_device->write(cmd); - } - else if (m_settings.m_protocol == GS232ControllerSettings::SPID) - { - // Don't send a new status command, if waiting for a previous reply - if (!m_spidSetSent && !m_spidStatusSent) - { - // Status - QByteArray cmd; - cmd.append((char)0x57); // Start - for (int i = 0; i < 10; i++) { - cmd.append((char)0x0); - } - cmd.append((char)0x1f); // Status - cmd.append((char)0x20); // End - m_device->write(cmd); - m_spidStatusSent = true; - } - } - else - { - QByteArray cmd("p\n"); - m_device->write(cmd); - } + if (m_device && m_device->isOpen() && m_controllerProtocol) { + m_controllerProtocol->update(); } } + diff --git a/plugins/feature/gs232controller/gs232controllerworker.h b/plugins/feature/gs232controller/gs232controllerworker.h index 67041a3fc..263fd6ac0 100644 --- a/plugins/feature/gs232controller/gs232controllerworker.h +++ b/plugins/feature/gs232controller/gs232controllerworker.h @@ -28,6 +28,7 @@ #include "util/messagequeue.h" #include "gs232controllersettings.h" +#include "controllerprotocol.h" class GS232ControllerWorker : public QObject { @@ -81,12 +82,7 @@ private: float m_lastAzimuth; float m_lastElevation; - bool m_spidSetOutstanding; - bool m_spidSetSent; - bool m_spidStatusSent; - - bool m_rotCtlDReadAz; //!< rotctrld returns 'p' responses over two lines - QString m_rotCtlDAz; + ControllerProtocol *m_controllerProtocol; bool handleMessage(const Message& cmd); void applySettings(const GS232ControllerSettings& settings, const QList& settingsKeys, bool force = false); @@ -102,3 +98,4 @@ private slots: }; #endif // INCLUDE_FEATURE_GS232CONTROLLERWORKER_H_ + diff --git a/plugins/feature/gs232controller/gs232protocol.cpp b/plugins/feature/gs232controller/gs232protocol.cpp new file mode 100644 index 000000000..f5f982f78 --- /dev/null +++ b/plugins/feature/gs232controller/gs232protocol.cpp @@ -0,0 +1,86 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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 + +#include +#include + +#include "gs232protocol.h" + +GS232Protocol::GS232Protocol() +{ +} + +void GS232Protocol::setAzimuth(float azimuth) +{ + QString cmd = QString("M%1\r\n").arg((int)std::round(azimuth), 3, 10, QLatin1Char('0')); + QByteArray data = cmd.toLatin1(); + m_device->write(data); + m_lastAzimuth = azimuth; +} + +void GS232Protocol::setAzimuthElevation(float azimuth, float elevation) +{ + QString cmd = QString("W%1 %2\r\n").arg((int)std::round(azimuth), 3, 10, QLatin1Char('0')).arg((int)std::round(elevation), 3, 10, QLatin1Char('0')); + QByteArray data = cmd.toLatin1(); + m_device->write(data); + ControllerProtocol::setAzimuthElevation(azimuth, elevation); +} + +// Handle data received from controller +void GS232Protocol::readData() +{ + char buf[1024]; + qint64 len; + + while (m_device->canReadLine()) + { + len = m_device->readLine(buf, sizeof(buf)); + if (len != -1) + { + QString response = QString::fromUtf8(buf, len); + // MD-02 can return AZ=-00 EL=-00 and other negative angles + QRegularExpression re("AZ=([-\\d]\\d\\d) *EL=([-\\d]\\d\\d)"); + QRegularExpressionMatch match = re.match(response); + if (match.hasMatch()) + { + QString az = match.captured(1); + QString el = match.captured(2); + //qDebug() << "SPIDProtocol::readData read Az " << az << " El " << el; + reportAzEl(az.toFloat(), el.toFloat()); + } + else if (response == "\r\n") + { + // Ignore + } + else + { + qWarning() << "SPIDProtocol::readData - unexpected GS-232 response \"" << response << "\""; + reportError(QString("Unexpected GS-232 response: %1").arg(response)); + } + } + } +} + +// Request current Az/El from controller +void GS232Protocol::update() +{ + QByteArray cmd("C2\r\n"); + m_device->write(cmd); +} + diff --git a/plugins/feature/gs232controller/gs232protocol.h b/plugins/feature/gs232controller/gs232protocol.h new file mode 100644 index 000000000..499c8db30 --- /dev/null +++ b/plugins/feature/gs232controller/gs232protocol.h @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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_GS232PROTOCOL_H_ +#define INCLUDE_FEATURE_GS232PROTOCOL_H_ + +#include "controllerprotocol.h" + +class GS232Protocol : public ControllerProtocol +{ +public: + GS232Protocol(); + void setAzimuth(float azimuth) override; + void setAzimuthElevation(float azimuth, float elevation) override; + void readData() override; + void update() override; +}; + +#endif // INCLUDE_FEATURE_GS232PROTOCOL_H_ + diff --git a/plugins/feature/gs232controller/readme.md b/plugins/feature/gs232controller/readme.md index a023daea1..34cd7794f 100644 --- a/plugins/feature/gs232controller/readme.md +++ b/plugins/feature/gs232controller/readme.md @@ -92,6 +92,21 @@ This can prevent some rotators that have a limited accuracy from making unbenefi If this set to 0, every target azimuth and elevation received by the controller will be send to the rotator. If it is set to 2, then a change in azimuth of +-1 degree from the previous azimuth, would not be sent to the rotator. +

20: Precision

+ +Specifies the number of decimal places used for coordinates and the tolerance setting. +For GS-232 this is fixed to 0. For SPID it is fixed to 1. + +

21: Coordinates

+ +Specifies the coordinate system used by the GUI for entry and display of the position of the rotator. This can be: + +* Az/El - For azimuth and elevation in degrees. +* X/Y 85' - For X/Y coordinates in degrees. 0,0 is zenith. X is positive Southward. Y is positive Eastward. +* X/Y 30' - For X/Y coordinates in degrees. 0,0 is zenith. X is positivie Eastward. Y is positive Northward. + +Equations for translating between these coordinate systems can be found [here](https://ntrs.nasa.gov/citations/19670030005). +

Protocol Implementations

GS-232 Protocol Implementation Notes

diff --git a/plugins/feature/gs232controller/rotctrldprotocol.cpp b/plugins/feature/gs232controller/rotctrldprotocol.cpp new file mode 100644 index 000000000..058a65b0a --- /dev/null +++ b/plugins/feature/gs232controller/rotctrldprotocol.cpp @@ -0,0 +1,118 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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 +#include + +#include "rotctrldprotocol.h" + +RotCtrlDProtocol::RotCtrlDProtocol() : + m_rotCtlDReadAz(false) +{ +} + +void RotCtrlDProtocol::setAzimuthElevation(float azimuth, float elevation) +{ + QString cmd = QString("P %1 %2\n").arg(azimuth).arg(elevation); + QByteArray data = cmd.toLatin1(); + m_device->write(data); + ControllerProtocol::setAzimuthElevation(azimuth, elevation); +} + +// Handle data received from rotctrld +void RotCtrlDProtocol::readData() +{ + char buf[1024]; + qint64 len; + + while (m_device->canReadLine()) + { + len = m_device->readLine(buf, sizeof(buf)); + if (len != -1) + { + QString response = QString::fromUtf8(buf, len).trimmed(); + QRegularExpression rprt("RPRT (-?\\d+)"); + QRegularExpressionMatch matchRprt = rprt.match(response); + QRegularExpression decimal("(-?\\d+.\\d+)"); + QRegularExpressionMatch matchDecimal = decimal.match(response); + if (matchRprt.hasMatch()) + { + // See rig_errcode_e in hamlib rig.h + const QStringList errors = { + "OK", + "Invalid parameter", + "Invalid configuration", + "No memory", + "Not implemented", + "Timeout", + "IO error", + "Internal error", + "Protocol error", + "Command rejected", + "Arg truncated", + "Not available", + "VFO not targetable", + "Bus error", + "Collision on bus", + "NULL rig handled or invalid pointer parameter", + "Invalid VFO", + "Argument out of domain of function" + }; + int rprt = matchRprt.captured(1).toInt(); + if (rprt != 0) + { + qWarning() << "GS232ControllerWorker::readData - rotctld error: " << errors[-rprt]; + // Seem to get a lot of EPROTO errors from rotctld due to extra 00 char in response to GS232 C2 command + // E.g: ./rotctld.exe -m 603 -r com7 -vvvvv + // read_string(): RX 16 characters + // 0000 00 41 5a 3d 31 37 35 20 20 45 4c 3d 30 33 38 0d .AZ=175 EL=038. + // So don't pass these to GUI for now + if (rprt != -8) { + reportError(QString("rotctld error: %1").arg(errors[-rprt])); + } + } + m_rotCtlDReadAz = false; + } + else if (matchDecimal.hasMatch() && !m_rotCtlDReadAz) + { + m_rotCtlDAz = response; + m_rotCtlDReadAz = true; + } + else if (matchDecimal.hasMatch() && m_rotCtlDReadAz) + { + QString az = m_rotCtlDAz; + QString el = response; + m_rotCtlDReadAz = false; + //qDebug() << "GS232ControllerWorker::readData read Az " << az << " El " << el; + reportAzEl(az.toFloat(), el.toFloat()); + } + else + { + qWarning() << "GS232ControllerWorker::readData - Unexpected rotctld response \"" << response << "\""; + reportError(QString("Unexpected rotctld response: %1").arg(response)); + } + } + } +} + +// Request current Az/El from rotctrld +void RotCtrlDProtocol::update() +{ + QByteArray cmd("p\n"); + m_device->write(cmd); +} + diff --git a/plugins/feature/gs232controller/rotctrldprotocol.h b/plugins/feature/gs232controller/rotctrldprotocol.h new file mode 100644 index 000000000..0f9eaffe8 --- /dev/null +++ b/plugins/feature/gs232controller/rotctrldprotocol.h @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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_ROTCTRLDPROTOCOL_H_ +#define INCLUDE_FEATURE_ROTCTRLDPROTOCOL_H_ + +#include "controllerprotocol.h" + +class RotCtrlDProtocol : public ControllerProtocol +{ +public: + RotCtrlDProtocol(); + void setAzimuthElevation(float azimuth, float elevation) override; + void readData() override; + void update() override; +private: + bool m_rotCtlDReadAz; //!< rotctrld returns 'p' responses over two lines + QString m_rotCtlDAz; +}; + +#endif // INCLUDE_FEATURE_ROTCTRLDPROTOCOL_H_ + diff --git a/plugins/feature/gs232controller/spidprotocol.cpp b/plugins/feature/gs232controller/spidprotocol.cpp new file mode 100644 index 000000000..2b31eefb8 --- /dev/null +++ b/plugins/feature/gs232controller/spidprotocol.cpp @@ -0,0 +1,124 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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 + +#include + +#include "spidprotocol.h" + +SPIDProtocol::SPIDProtocol() : + m_spidStatusSent(false), + m_spidSetSent(false), + m_spidSetOutstanding(false) +{ +} + +void SPIDProtocol::setAzimuthElevation(float azimuth, float elevation) +{ + if (!m_spidSetSent && !m_spidStatusSent) + { + QByteArray cmd(13, (char)0); + + cmd[0] = 0x57; // Start + int h = std::round((azimuth + 360.0f) * 2.0f); + cmd[1] = 0x30 | (h / 1000); + cmd[2] = 0x30 | ((h % 1000) / 100); + cmd[3] = 0x30 | ((h % 100) / 10); + cmd[4] = 0x30 | (h % 10); + cmd[5] = 2; // 2 degree per impulse + int v = std::round((elevation + 360.0f) * 2.0f); + cmd[6] = 0x30 | (v / 1000); + cmd[7] = 0x30 | ((v % 1000) / 100); + cmd[8] = 0x30 | ((v % 100) / 10); + cmd[9] = 0x30 | (v % 10); + cmd[10] = 2; // 2 degree per impulse + cmd[11] = 0x2f; // Set cmd + cmd[12] = 0x20; // End + + m_device->write(cmd); + + m_spidSetSent = true; + } + else + { + qDebug() << "SPIDProtocol::setAzimuthElevation: Not sent, waiting for status reply"; + m_spidSetOutstanding = true; + } + ControllerProtocol::setAzimuthElevation(azimuth, elevation); +} + +// Handle data received from controller +void SPIDProtocol::readData() +{ + char buf[1024]; + qint64 len; + + while (m_device->bytesAvailable() >= 12) + { + len = m_device->read(buf, 12); + if ((len == 12) && (buf[0] == 0x57)) + { + double az; + double el; + az = buf[1] * 100.0 + buf[2] * 10.0 + buf[3] + buf[4] / 10.0 - 360.0; + el = buf[6] * 100.0 + buf[7] * 10.0 + buf[8] + buf[9] / 10.0 - 360.0; + //qDebug() << "SPIDProtocol::readData read Az " << az << " El " << el; + reportAzEl(az, el); + if (m_spidStatusSent && m_spidSetSent) { + qDebug() << "SPIDProtocol::readData - m_spidStatusSent and m_spidSetSent set simultaneously"; + } + if (m_spidStatusSent) { + m_spidStatusSent = false; + } + if (m_spidSetSent) { + m_spidSetSent = false; + } + if (m_spidSetOutstanding) + { + m_spidSetOutstanding = false; + setAzimuthElevation(m_lastAzimuth, m_lastElevation); + } + } + else + { + QByteArray bytes(buf, (int)len); + qWarning() << "SPIDProtocol::readData - unexpected SPID rot2prog response \"" << bytes.toHex() << "\""; + reportError(QString("Unexpected SPID rot2prog response: %1").arg(bytes.toHex().data())); + } + } +} + +// Request current Az/El from controller +void SPIDProtocol::update() +{ + // Don't send a new status command, if waiting for a previous reply + if (!m_spidSetSent && !m_spidStatusSent) + { + // Status + QByteArray cmd; + cmd.append((char)0x57); // Start + for (int i = 0; i < 10; i++) { + cmd.append((char)0x0); + } + cmd.append((char)0x1f); // Status + cmd.append((char)0x20); // End + m_device->write(cmd); + m_spidStatusSent = true; + } +} + diff --git a/plugins/feature/gs232controller/spidprotocol.h b/plugins/feature/gs232controller/spidprotocol.h new file mode 100644 index 000000000..17b8a82df --- /dev/null +++ b/plugins/feature/gs232controller/spidprotocol.h @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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_SPIDPROTOCOL_H_ +#define INCLUDE_FEATURE_SPIDPROTOCOL_H_ + +#include "controllerprotocol.h" + +class SPIDProtocol : public ControllerProtocol +{ +public: + SPIDProtocol(); + void setAzimuthElevation(float azimuth, float elevation) override; + void readData() override; + void update() override; +private: + bool m_spidStatusSent; + bool m_spidSetSent; + bool m_spidSetOutstanding; +}; + +#endif // INCLUDE_FEATURE_SPIDPROTOCOL_H_ + diff --git a/sdrbase/channel/channelwebapiutils.cpp b/sdrbase/channel/channelwebapiutils.cpp index bfdc3e257..685c0371f 100644 --- a/sdrbase/channel/channelwebapiutils.cpp +++ b/sdrbase/channel/channelwebapiutils.cpp @@ -34,6 +34,7 @@ #include "maincore.h" #include "device/deviceset.h" #include "device/deviceapi.h" +#include "channel/channelapi.h" #include "channel/channelutils.h" #include "dsp/devicesamplesource.h" #include "dsp/devicesamplesink.h" @@ -219,7 +220,83 @@ bool ChannelWebAPIUtils::getFeatureReport(unsigned int featureSetIndex, unsigned if (httpRC/100 != 2) { - qWarning("ChannelWebAPIUtils::getFeatureReport: get feature settings error %d: %s", + qWarning("ChannelWebAPIUtils::getFeatureReport: get feature report error %d: %s", + httpRC, qPrintable(errorResponse)); + return false; + } + + return true; +} + +bool ChannelWebAPIUtils::getChannelSettings(unsigned int deviceIndex, unsigned int channelIndex, SWGSDRangel::SWGChannelSettings &channelSettingsResponse, ChannelAPI *&channel) +{ + QString errorResponse; + int httpRC; + DeviceSet *deviceSet; + + // Get current channel settings + std::vector deviceSets = MainCore::instance()->getDeviceSets(); + if (deviceIndex < deviceSets.size()) + { + deviceSet = deviceSets[deviceIndex]; + if (channelIndex < (unsigned int) deviceSet->getNumberOfChannels()) + { + channel = deviceSet->getChannelAt(channelIndex); + httpRC = channel->webapiSettingsGet(channelSettingsResponse, errorResponse); + } + else + { + qDebug() << "ChannelWebAPIUtils::getChannelSettings: no channel " << deviceIndex << ":" << channelIndex; + return false; + } + } + else + { + qDebug() << "ChannelWebAPIUtils::getChannelSettings: no device " << deviceIndex; + return false; + } + + if (httpRC/100 != 2) + { + qWarning("ChannelWebAPIUtils::getChannelSettings: get channel settings error %d: %s", + httpRC, qPrintable(errorResponse)); + return false; + } + + return true; +} + +bool ChannelWebAPIUtils::getChannelReport(unsigned int deviceIndex, unsigned int channelIndex, SWGSDRangel::SWGChannelReport &channelReport) +{ + QString errorResponse; + int httpRC; + DeviceSet *deviceSet; + + // Get channel report + std::vector deviceSets = MainCore::instance()->getDeviceSets(); + if (deviceIndex < deviceSets.size()) + { + deviceSet = deviceSets[deviceIndex]; + if (channelIndex < (unsigned int) deviceSet->getNumberOfChannels()) + { + ChannelAPI *channel = deviceSet->getChannelAt(channelIndex); + httpRC = channel->webapiReportGet(channelReport, errorResponse); + } + else + { + qDebug() << "ChannelWebAPIUtils::getChannelReport: no channel " << deviceIndex << ":" << channelIndex; + return false; + } + } + else + { + qDebug() << "ChannelWebAPIUtils::getChannelReport: no device set " << deviceIndex; + return false; + } + + if (httpRC/100 != 2) + { + qWarning("ChannelWebAPIUtils::getChannelReport: get channel report error %d: %s", httpRC, qPrintable(errorResponse)); return false; } @@ -1193,6 +1270,22 @@ bool ChannelWebAPIUtils::getFeatureSetting(unsigned int featureSetIndex, unsign } } +bool ChannelWebAPIUtils::getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, double &value) +{ + SWGSDRangel::SWGFeatureSettings featureSettingsResponse; + Feature *feature; + + if (getFeatureSettings(featureSetIndex, featureIndex, featureSettingsResponse, feature)) + { + QJsonObject *jsonObj = featureSettingsResponse.asJsonObject(); + return WebAPIUtils::getSubObjectDouble(*jsonObj, setting, value); + } + else + { + return false; + } +} + bool ChannelWebAPIUtils::getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, QString &value) { SWGSDRangel::SWGFeatureSettings featureSettingsResponse; @@ -1209,6 +1302,54 @@ bool ChannelWebAPIUtils::getFeatureSetting(unsigned int featureSetIndex, unsign } } +bool ChannelWebAPIUtils::getChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, int &value) +{ + SWGSDRangel::SWGChannelSettings channelSettingsResponse; + ChannelAPI *channel; + + if (getChannelSettings(deviceSetIndex, channelIndex, channelSettingsResponse, channel)) + { + QJsonObject *jsonObj = channelSettingsResponse.asJsonObject(); + return WebAPIUtils::getSubObjectInt(*jsonObj, setting, value); + } + else + { + return false; + } +} + +bool ChannelWebAPIUtils::getChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, double &value) +{ + SWGSDRangel::SWGChannelSettings channelSettingsResponse; + ChannelAPI *channel; + + if (getChannelSettings(deviceSetIndex, channelIndex, channelSettingsResponse, channel)) + { + QJsonObject *jsonObj = channelSettingsResponse.asJsonObject(); + return WebAPIUtils::getSubObjectDouble(*jsonObj, setting, value); + } + else + { + return false; + } +} + +bool ChannelWebAPIUtils::getChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, QString &value) +{ + SWGSDRangel::SWGChannelSettings channelSettingsResponse; + ChannelAPI *channel; + + if (getChannelSettings(deviceSetIndex, channelIndex, channelSettingsResponse, channel)) + { + QJsonObject *jsonObj = channelSettingsResponse.asJsonObject(); + return WebAPIUtils::getSubObjectString(*jsonObj, setting, value); + } + else + { + return false; + } +} + bool ChannelWebAPIUtils::getFeatureReportValue(unsigned int featureSetIndex, unsigned int featureIndex, const QString &key, int &value) { SWGSDRangel::SWGFeatureReport featureReport; @@ -1231,6 +1372,28 @@ bool ChannelWebAPIUtils::getFeatureReportValue(unsigned int featureSetIndex, uns return false; } +bool ChannelWebAPIUtils::getFeatureReportValue(unsigned int featureSetIndex, unsigned int featureIndex, const QString &key, double &value) +{ + SWGSDRangel::SWGFeatureReport featureReport; + + if (getFeatureReport(featureSetIndex, featureIndex, featureReport)) + { + // Get value of requested key + QJsonObject *jsonObj = featureReport.asJsonObject(); + if (WebAPIUtils::getSubObjectDouble(*jsonObj, key, value)) + { + // Done + return true; + } + else + { + qWarning("ChannelWebAPIUtils::getFeatureReportValue: no key %s in feature report", qPrintable(key)); + return false; + } + } + return false; +} + bool ChannelWebAPIUtils::getFeatureReportValue(unsigned int featureSetIndex, unsigned int featureIndex, const QString &key, QString &value) { SWGSDRangel::SWGFeatureReport featureReport; @@ -1252,3 +1415,71 @@ bool ChannelWebAPIUtils::getFeatureReportValue(unsigned int featureSetIndex, uns } return false; } + + +bool ChannelWebAPIUtils::getChannelReportValue(unsigned int deviceIndex, unsigned int channelIndex, const QString &key, int &value) +{ + SWGSDRangel::SWGChannelReport channelReport; + + if (getChannelReport(deviceIndex, channelIndex, channelReport)) + { + // Get value of requested key + QJsonObject *jsonObj = channelReport.asJsonObject(); + if (WebAPIUtils::getSubObjectInt(*jsonObj, key, value)) + { + // Done + return true; + } + else + { + qWarning("ChannelWebAPIUtils::getChannelReportValue: no key %s in channel report", qPrintable(key)); + return false; + } + } + return false; +} + +bool ChannelWebAPIUtils::getChannelReportValue(unsigned int deviceIndex, unsigned int channelIndex, const QString &key, double &value) +{ + SWGSDRangel::SWGChannelReport channelReport; + + if (getChannelReport(deviceIndex, channelIndex, channelReport)) + { + // Get value of requested key + QJsonObject *jsonObj = channelReport.asJsonObject(); + if (WebAPIUtils::getSubObjectDouble(*jsonObj, key, value)) + { + // Done + return true; + } + else + { + qWarning("ChannelWebAPIUtils::getChannelReportValue: no key %s in channel report", qPrintable(key)); + return false; + } + } + return false; +} + +bool ChannelWebAPIUtils::getChannelReportValue(unsigned int deviceIndex, unsigned int channelIndex, const QString &key, QString &value) +{ + SWGSDRangel::SWGChannelReport channelReport; + + if (getChannelReport(deviceIndex, channelIndex, channelReport)) + { + // Get value of requested key + QJsonObject *jsonObj = channelReport.asJsonObject(); + if (WebAPIUtils::getSubObjectString(*jsonObj, key, value)) + { + // Done + return true; + } + else + { + qWarning("ChannelWebAPIUtils::getChannelReportValue: no key %s in channel report", qPrintable(key)); + return false; + } + } + return false; +} + diff --git a/sdrbase/channel/channelwebapiutils.h b/sdrbase/channel/channelwebapiutils.h index ee95f21d4..1f2f8f9b4 100644 --- a/sdrbase/channel/channelwebapiutils.h +++ b/sdrbase/channel/channelwebapiutils.h @@ -24,11 +24,14 @@ #include "SWGDeviceReport.h" #include "SWGFeatureSettings.h" #include "SWGFeatureReport.h" +#include "SWGChannelSettings.h" +#include "SWGChannelReport.h" #include "export.h" class DeviceSet; class Feature; +class ChannelAPI; class SDRBASE_API ChannelWebAPIUtils { @@ -67,15 +70,26 @@ public: static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, const QString &value); static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, double value); static bool getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, int &value); + static bool getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, double &value); static bool getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, QString &value); + static bool getChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, int &value); + static bool getChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, double &value); + static bool getChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, QString &value); static bool getFeatureReportValue(unsigned int featureSetIndex, unsigned int featureIndex, const QString &key, int &value); - static bool getFeatureReportValue(unsigned int featureSetIndex, unsigned int featureIndex, const QString &key, QString &value); + static bool getFeatureReportValue(unsigned int featureSetIndex, unsigned int featureIndex, const QString &key, double &value); + static bool getFeatureReportValue(unsigned int featureSetIndex, unsigned int featureIndex, const QString &key, QString &value); + static bool getChannelReportValue(unsigned int deviceIndex, unsigned int channelIndex, const QString &key, int &value); + static bool getChannelReportValue(unsigned int deviceIndex, unsigned int channelIndex, const QString &key, double &value); + static bool getChannelReportValue(unsigned int deviceIndex, unsigned int channelIndex, const QString &key, QString &value); protected: static bool getDeviceSettings(unsigned int deviceIndex, SWGSDRangel::SWGDeviceSettings &deviceSettingsResponse, DeviceSet *&deviceSet); static bool getDeviceReport(unsigned int deviceIndex, SWGSDRangel::SWGDeviceReport &deviceReport); static bool getFeatureSettings(unsigned int featureSetIndex, unsigned int featureIndex, SWGSDRangel::SWGFeatureSettings &featureSettingsResponse, Feature *&feature); static bool getFeatureReport(unsigned int featureSetIndex, unsigned int featureIndex, SWGSDRangel::SWGFeatureReport &featureReport); + static bool getChannelSettings(unsigned int deviceIndex, unsigned int channelIndex, SWGSDRangel::SWGChannelSettings &channelSettingsResponse, ChannelAPI *&channel); + static bool getChannelReport(unsigned int deviceIndex, unsigned int channelIndex, SWGSDRangel::SWGChannelReport &channelReport); static QString getDeviceHardwareId(unsigned int deviceIndex); }; #endif // SDRBASE_CHANNEL_CHANNELWEBAPIUTILS_H_ + diff --git a/sdrbase/util/astronomy.cpp b/sdrbase/util/astronomy.cpp index c3d26e051..0c1ac131b 100644 --- a/sdrbase/util/astronomy.cpp +++ b/sdrbase/util/astronomy.cpp @@ -286,6 +286,183 @@ RADec Astronomy::azAltToRaDec(AzAlt aa, double latitude, double longitude, QDate return rd; } +// https://ntrs.nasa.gov/api/citations/19670030005/downloads/19670030005.pdf +// X85 is positive Southward +// Y85 is positive Eastward +// X30 is positive Eastward +// Y30 is positive Northward +// atan2 range is (-pi,pi], we want az (0,360], so need to add pi +void Astronomy::azAltToXY85(AzAlt aa, double& x, double& y) +{ + if (aa.alt == 90.0) + { + x = 0.0; + y = 0.0; + //qDebug() << "azAltToXY85" << aa.az << aa.alt << x << y; + return; + } + double az = aa.az; + double el = aa.alt; + if (az >= 360.0) { + az -= 360.0; + } + if (el > 90.0) + { + el = 180.0 - el; + if (az >= 180.0) { + az = az - 180.0; + } else { + az = az + 180.0; + } + } + double azr = Units::degreesToRadians(az); + double elr = Units::degreesToRadians(el); + y = Units::radiansToDegrees(asin(cos(elr) * sin(azr))); + if (az == 0.0) + { + // cot(0) == Inf + if ((az == 90.0) || (az == 270.0)) { + x = 0.0; + } else if ((az > 90.0f) && (az < 270.0)) { + x = 90.0; + } else { + x = -90.0; + } + } + else + { + // cot(x)=1/tan(x)=cos(x)/sin(x) + x = Units::radiansToDegrees(atan(-(cos(elr)/sin(elr)) * cos(azr))); + } + + //qDebug() << "azAltToXY85" << aa.az << aa.alt << x << y; +} + +void Astronomy::azAltToXY30(AzAlt aa, double& x, double& y) +{ + if (aa.alt == 90.0) + { + x = 0.0; + y = 0.0; + //qDebug() << "azAltToXY30" << aa.az << aa.alt << x << y; + return; + } + double az = aa.az; + double el = aa.alt; + if (az >= 360.0) { + az -= 360.0; + } + if (el > 90.0) + { + el = 180.0 - el; + if (az >= 180.0) { + az = az - 180.0; + } else { + az = az + 180.0; + } + } + double azr = Units::degreesToRadians(az); + double elr = Units::degreesToRadians(el); + y = Units::radiansToDegrees(asin(cos(elr) * cos(azr))); + if (el == 0.0) + { + if ((az == 0.0) || (az == 180.0)) { + x = 0.0; + } else if ((az >= 0.0f) && (az <= 180.0)) { + x = 90.0; + } else { + x = -90.0; + } + } + else + { + x = Units::radiansToDegrees(atan((cos(elr)/sin(elr)) * sin(azr))); + } + //qDebug() << "azAltToXY30" << aa.az << aa.alt << x << y; +} + +AzAlt Astronomy::xy85ToAzAlt(double x, double y) +{ + AzAlt aa; + if ((x == 0.0) && (y == 0.0)) + { + aa.az = 0.0; + aa.alt = 90.0; + //qDebug() << "xy85ToAzAlt" << x << y << aa.az << aa.alt; + return aa; + } + double xr = Units::degreesToRadians(x); + double yr = Units::degreesToRadians(y); + double elr = asin(cos(yr) * cos(xr)); + double azr; + if (x == 0.0) + { + // 1/sin(x) == Inf + azr = y >= 0.0 ? M_PI/2.0 : 2.0*M_PI*3.0/4.0; + } + else if (y == 90.0) + { + // tan(90) == Inf + azr = M_PI/2.0; + } + else if (y == -90.0) + { + // tan(-90) == Inf + azr = 2.0*M_PI*3.0/4.0; + } + else + { + // atan2(y,x) = atan(y/x) + azr = atan2(-tan(yr), sin(xr)) + M_PI; + } + aa.az = Units::radiansToDegrees(azr); + aa.alt = Units::radiansToDegrees(elr); + //qDebug() << "xy85ToAzAlt" << x << y << aa.az << aa.alt; + return aa; +} + +AzAlt Astronomy::xy30ToAzAlt(double x, double y) +{ + AzAlt aa; + if ((x == 0.0) && (y == 0.0)) + { + aa.az = 0.0; + aa.alt = 90.0; + //qDebug() << "xy30ToAzAlt" << x << y << aa.az << aa.alt; + return aa; + } + double xr = Units::degreesToRadians(x); + double yr = Units::degreesToRadians(y); + double elr = asin(cos(yr) * cos(xr)); + double azr; + if (y == 0.0) + { + // cot(0) == Inf + azr = x >= 0.0 ? M_PI/2.0 : 2.0*M_PI*3.0/4.0; + } + else if (y == 90.0) + { + // tan(90) == Inf + azr = 0.0; + } + else if (y == -90.0) + { + // tan(-90) == Inf + azr = M_PI; + } + else + { + azr = atan2(sin(xr), tan(yr)); + if (azr < 0.0) { + azr += 2.0*M_PI; + } + } + aa.az = Units::radiansToDegrees(azr); + aa.alt = Units::radiansToDegrees(elr); + //qDebug() << "xy30ToAzAlt" << x << y << aa.az << aa.alt; + return aa; +} + // Needs to work for negative a double Astronomy::modulo(double a, double b) { @@ -3707,3 +3884,4 @@ static int eraEpv00(double date1, double date2, /* Finished. */ } + diff --git a/sdrbase/util/astronomy.h b/sdrbase/util/astronomy.h index 2fcf10d16..5d26cbfc0 100644 --- a/sdrbase/util/astronomy.h +++ b/sdrbase/util/astronomy.h @@ -49,6 +49,11 @@ public: static AzAlt raDecToAzAlt(RADec rd, double latitude, double longitude, QDateTime dt, bool j2000=true); static RADec azAltToRaDec(AzAlt aa, double latitude, double longitude, QDateTime dt); + static void azAltToXY85(AzAlt aa, double& x, double& y); + static void azAltToXY30(AzAlt aa, double& x, double& y); + static AzAlt xy85ToAzAlt(double x, double y); + static AzAlt xy30ToAzAlt(double x, double y); + static double localSiderealTime(QDateTime dateTime, double longitude); static void sunPosition(AzAlt& aa, RADec& rd, double latitude, double longitude, QDateTime dt); diff --git a/swagger/sdrangel/api/swagger/include/GS232Controller.yaml b/swagger/sdrangel/api/swagger/include/GS232Controller.yaml index f3a201aa7..b555a959e 100644 --- a/swagger/sdrangel/api/swagger/include/GS232Controller.yaml +++ b/swagger/sdrangel/api/swagger/include/GS232Controller.yaml @@ -50,7 +50,13 @@ GS232ControllerSettings: type: number format: float protocol: - description: (0 GS-232, 1 SPID rot2prog) + description: (0 GS-232, 1 SPID rot2prog, 2 rotcltd, 3 DFM) + type: integer + precision: + description: Precision of azimuth and elevation values + type: integer + coordinates: + description: (0 Az/El, 1 X/Y 85, 2 X/Y 30) type: integer title: type: string diff --git a/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.cpp index b6f4c3056..954e40380 100644 --- a/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.cpp @@ -60,6 +60,10 @@ SWGGS232ControllerSettings::SWGGS232ControllerSettings() { m_tolerance_isSet = false; protocol = 0; m_protocol_isSet = false; + precision = 0; + m_precision_isSet = false; + coordinates = 0; + m_coordinates_isSet = false; title = nullptr; m_title_isSet = false; rgb_color = 0; @@ -116,6 +120,10 @@ SWGGS232ControllerSettings::init() { m_tolerance_isSet = false; protocol = 0; m_protocol_isSet = false; + precision = 0; + m_precision_isSet = false; + coordinates = 0; + m_coordinates_isSet = false; title = new QString(""); m_title_isSet = false; rgb_color = 0; @@ -158,6 +166,8 @@ SWGGS232ControllerSettings::cleanup() { + + if(title != nullptr) { delete title; } @@ -217,6 +227,10 @@ SWGGS232ControllerSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&protocol, pJson["protocol"], "qint32", ""); + ::SWGSDRangel::setValue(&precision, pJson["precision"], "qint32", ""); + + ::SWGSDRangel::setValue(&coordinates, pJson["coordinates"], "qint32", ""); + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); @@ -297,6 +311,12 @@ SWGGS232ControllerSettings::asJsonObject() { if(m_protocol_isSet){ obj->insert("protocol", QJsonValue(protocol)); } + if(m_precision_isSet){ + obj->insert("precision", QJsonValue(precision)); + } + if(m_coordinates_isSet){ + obj->insert("coordinates", QJsonValue(coordinates)); + } if(title != nullptr && *title != QString("")){ toJsonValue(QString("title"), title, obj, QString("QString")); } @@ -485,6 +505,26 @@ SWGGS232ControllerSettings::setProtocol(qint32 protocol) { this->m_protocol_isSet = true; } +qint32 +SWGGS232ControllerSettings::getPrecision() { + return precision; +} +void +SWGGS232ControllerSettings::setPrecision(qint32 precision) { + this->precision = precision; + this->m_precision_isSet = true; +} + +qint32 +SWGGS232ControllerSettings::getCoordinates() { + return coordinates; +} +void +SWGGS232ControllerSettings::setCoordinates(qint32 coordinates) { + this->coordinates = coordinates; + this->m_coordinates_isSet = true; +} + QString* SWGGS232ControllerSettings::getTitle() { return title; @@ -618,6 +658,12 @@ SWGGS232ControllerSettings::isSet(){ if(m_protocol_isSet){ isObjectUpdated = true; break; } + if(m_precision_isSet){ + isObjectUpdated = true; break; + } + if(m_coordinates_isSet){ + isObjectUpdated = true; break; + } if(title && *title != QString("")){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.h b/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.h index 4f12f326e..eff95dede 100644 --- a/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.h @@ -91,6 +91,12 @@ public: qint32 getProtocol(); void setProtocol(qint32 protocol); + qint32 getPrecision(); + void setPrecision(qint32 precision); + + qint32 getCoordinates(); + void setCoordinates(qint32 coordinates); + QString* getTitle(); void setTitle(QString* title); @@ -167,6 +173,12 @@ private: qint32 protocol; bool m_protocol_isSet; + qint32 precision; + bool m_precision_isSet; + + qint32 coordinates; + bool m_coordinates_isSet; + QString* title; bool m_title_isSet;