mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									c50c866732
								
							
						
					
					
						commit
						4ac5e729ff
					
				| @ -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) | ||||
|  | ||||
							
								
								
									
										157
									
								
								plugins/feature/gs232controller/controllerprotocol.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								plugins/feature/gs232controller/controllerprotocol.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -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 <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #include <QRegularExpression> | ||||
| 
 | ||||
| #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<QString>& 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; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										57
									
								
								plugins/feature/gs232controller/controllerprotocol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								plugins/feature/gs232controller/controllerprotocol.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #ifndef INCLUDE_FEATURE_CONTROLLERPROTOCOL_H_ | ||||
| #define INCLUDE_FEATURE_CONTROLLERPROTOCOL_H_ | ||||
| 
 | ||||
| #include <QIODevice> | ||||
| 
 | ||||
| #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<QString>& 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_
 | ||||
| 
 | ||||
							
								
								
									
										239
									
								
								plugins/feature/gs232controller/dfmprotocol.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								plugins/feature/gs232controller/dfmprotocol.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -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 <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #include <QDebug> | ||||
| 
 | ||||
| #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<QString>& 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); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										120
									
								
								plugins/feature/gs232controller/dfmprotocol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								plugins/feature/gs232controller/dfmprotocol.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #ifndef INCLUDE_FEATURE_DFMPROTOCOL_H_ | ||||
| #define INCLUDE_FEATURE_DFMPROTOCOL_H_ | ||||
| 
 | ||||
| #include <QTimer> | ||||
| 
 | ||||
| #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<QString>& 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_
 | ||||
| 
 | ||||
							
								
								
									
										69
									
								
								plugins/feature/gs232controller/dfmstatusdialog.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								plugins/feature/gs232controller/dfmstatusdialog.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -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 <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #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(); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										40
									
								
								plugins/feature/gs232controller/dfmstatusdialog.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								plugins/feature/gs232controller/dfmstatusdialog.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #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
 | ||||
| 
 | ||||
							
								
								
									
										413
									
								
								plugins/feature/gs232controller/dfmstatusdialog.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										413
									
								
								plugins/feature/gs232controller/dfmstatusdialog.ui
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,413 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <ui version="4.0"> | ||||
|  <class>DFMStatusDialog</class> | ||||
|  <widget class="QDialog" name="DFMStatusDialog"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>474</width> | ||||
|     <height>488</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="font"> | ||||
|    <font> | ||||
|     <family>Liberation Sans</family> | ||||
|     <pointsize>9</pointsize> | ||||
|    </font> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>DFM Status</string> | ||||
|   </property> | ||||
|   <layout class="QVBoxLayout" name="verticalLayout"> | ||||
|    <item> | ||||
|     <widget class="QGroupBox" name="groupBox"> | ||||
|      <layout class="QGridLayout" name="gridLayout"> | ||||
|       <item row="6" column="0" colspan="3"> | ||||
|        <widget class="QGroupBox" name="statusGroup"> | ||||
|         <property name="title"> | ||||
|          <string>Status</string> | ||||
|         </property> | ||||
|         <layout class="QFormLayout" name="formLayout"> | ||||
|          <item row="0" column="0"> | ||||
|           <widget class="QLabel" name="trackOnLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Track</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="0" column="1"> | ||||
|           <widget class="QCheckBox" name="trackOn"> | ||||
|            <property name="focusPolicy"> | ||||
|             <enum>Qt::NoFocus</enum> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string/> | ||||
|            </property> | ||||
|            <property name="checkable"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="0"> | ||||
|           <widget class="QLabel" name="driverOnLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Drives</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="1"> | ||||
|           <widget class="QCheckBox" name="driveOn"> | ||||
|            <property name="focusPolicy"> | ||||
|             <enum>Qt::NoFocus</enum> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string/> | ||||
|            </property> | ||||
|            <property name="checkable"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="0"> | ||||
|           <widget class="QLabel" name="brakesOnLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Brakes</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="1"> | ||||
|           <widget class="QCheckBox" name="brakesOn"> | ||||
|            <property name="focusPolicy"> | ||||
|             <enum>Qt::NoFocus</enum> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string/> | ||||
|            </property> | ||||
|            <property name="checkable"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="0"> | ||||
|           <widget class="QLabel" name="pumpsOnLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Pumps</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="1"> | ||||
|           <widget class="QCheckBox" name="pumpsOn"> | ||||
|            <property name="mouseTracking"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|            <property name="focusPolicy"> | ||||
|             <enum>Qt::NoFocus</enum> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string/> | ||||
|            </property> | ||||
|            <property name="checkable"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="4" column="1"> | ||||
|           <widget class="QComboBox" name="controller"> | ||||
|            <item> | ||||
|             <property name="text"> | ||||
|              <string>None</string> | ||||
|             </property> | ||||
|            </item> | ||||
|            <item> | ||||
|             <property name="text"> | ||||
|              <string>OCU</string> | ||||
|             </property> | ||||
|            </item> | ||||
|            <item> | ||||
|             <property name="text"> | ||||
|              <string>LCU</string> | ||||
|             </property> | ||||
|            </item> | ||||
|            <item> | ||||
|             <property name="text"> | ||||
|              <string>MCU</string> | ||||
|             </property> | ||||
|            </item> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="4" column="0"> | ||||
|           <widget class="QLabel" name="controllerLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Controller</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|         </layout> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="8" column="2"> | ||||
|        <spacer name="verticalSpacer"> | ||||
|         <property name="orientation"> | ||||
|          <enum>Qt::Vertical</enum> | ||||
|         </property> | ||||
|         <property name="sizeHint" stdset="0"> | ||||
|          <size> | ||||
|           <width>20</width> | ||||
|           <height>40</height> | ||||
|          </size> | ||||
|         </property> | ||||
|        </spacer> | ||||
|       </item> | ||||
|       <item row="2" column="0" colspan="2"> | ||||
|        <widget class="QGroupBox" name="antennaPositionGroup"> | ||||
|         <property name="title"> | ||||
|          <string>Antenna Position</string> | ||||
|         </property> | ||||
|         <layout class="QFormLayout" name="formLayout_2"> | ||||
|          <item row="2" column="1"> | ||||
|           <widget class="QLineEdit" name="currentRA"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="0"> | ||||
|           <widget class="QLabel" name="currentRALabel"> | ||||
|            <property name="text"> | ||||
|             <string>RA</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="0"> | ||||
|           <widget class="QLabel" name="currentDecLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Dec</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="1"> | ||||
|           <widget class="QLineEdit" name="currentDec"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="0"> | ||||
|           <widget class="QLabel" name="currentHALabel"> | ||||
|            <property name="text"> | ||||
|             <string>HA</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="1"> | ||||
|           <widget class="QLineEdit" name="currentHA"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|         </layout> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="2"> | ||||
|        <widget class="QGroupBox" name="dateTimeGroup"> | ||||
|         <property name="title"> | ||||
|          <string>Date/Time</string> | ||||
|         </property> | ||||
|         <layout class="QFormLayout" name="formLayout_3"> | ||||
|          <item row="0" column="0"> | ||||
|           <widget class="QLabel" name="stLabel"> | ||||
|            <property name="text"> | ||||
|             <string>ST</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="0"> | ||||
|           <widget class="QLabel" name="utLabel"> | ||||
|            <property name="text"> | ||||
|             <string>UT</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="0" column="1"> | ||||
|           <widget class="QLineEdit" name="st"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="1"> | ||||
|           <widget class="QLineEdit" name="ut"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|         </layout> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="3" column="0" colspan="3"> | ||||
|        <widget class="QGroupBox" name="xyStatus"> | ||||
|         <property name="title"> | ||||
|          <string>X/Y Status</string> | ||||
|         </property> | ||||
|         <layout class="QGridLayout" name="gridLayout_2"> | ||||
|          <item row="4" column="1"> | ||||
|           <widget class="QLineEdit" name="torqueX"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="1"> | ||||
|           <widget class="QLineEdit" name="currentX"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="4" column="0"> | ||||
|           <widget class="QLabel" name="torqueXYLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Torque</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="1"> | ||||
|           <widget class="QLineEdit" name="rateX"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="4" column="2"> | ||||
|           <widget class="QLineEdit" name="torqueY"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="2"> | ||||
|           <widget class="QLineEdit" name="currentY"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="0"> | ||||
|           <widget class="QLabel" name="rateXYLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Rate</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="0" column="1"> | ||||
|           <widget class="QLabel" name="xColumnLabel"> | ||||
|            <property name="text"> | ||||
|             <string>X</string> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="0"> | ||||
|           <widget class="QLabel" name="currentXYLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Antenna</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="0" column="2"> | ||||
|           <widget class="QLabel" name="yColumnLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Y</string> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="2"> | ||||
|           <widget class="QLineEdit" name="rateY"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="0"> | ||||
|           <widget class="QLabel" name="siderealRateXYLabel"> | ||||
|            <property name="text"> | ||||
|             <string>Sidereal Rate</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="1"> | ||||
|           <widget class="QLineEdit" name="siderealRateX"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="2"> | ||||
|           <widget class="QLineEdit" name="siderealRateY"> | ||||
|            <property name="readOnly"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|         </layout> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QDialogButtonBox" name="buttonBox"> | ||||
|      <property name="orientation"> | ||||
|       <enum>Qt::Horizontal</enum> | ||||
|      </property> | ||||
|      <property name="standardButtons"> | ||||
|       <set>QDialogButtonBox::Close</set> | ||||
|      </property> | ||||
|     </widget> | ||||
|    </item> | ||||
|   </layout> | ||||
|  </widget> | ||||
|  <resources/> | ||||
|  <connections> | ||||
|   <connection> | ||||
|    <sender>buttonBox</sender> | ||||
|    <signal>accepted()</signal> | ||||
|    <receiver>DFMStatusDialog</receiver> | ||||
|    <slot>accept()</slot> | ||||
|    <hints> | ||||
|     <hint type="sourcelabel"> | ||||
|      <x>248</x> | ||||
|      <y>254</y> | ||||
|     </hint> | ||||
|     <hint type="destinationlabel"> | ||||
|      <x>157</x> | ||||
|      <y>274</y> | ||||
|     </hint> | ||||
|    </hints> | ||||
|   </connection> | ||||
|   <connection> | ||||
|    <sender>buttonBox</sender> | ||||
|    <signal>rejected()</signal> | ||||
|    <receiver>DFMStatusDialog</receiver> | ||||
|    <slot>reject()</slot> | ||||
|    <hints> | ||||
|     <hint type="sourcelabel"> | ||||
|      <x>316</x> | ||||
|      <y>260</y> | ||||
|     </hint> | ||||
|     <hint type="destinationlabel"> | ||||
|      <x>286</x> | ||||
|      <y>274</y> | ||||
|     </hint> | ||||
|    </hints> | ||||
|   </connection> | ||||
|  </connections> | ||||
| </ui> | ||||
| @ -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<QString>& 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<QSerialPortInfo> serialPorts = QSerialPortInfo::availablePorts(); | ||||
|     QListIterator<QSerialPortInfo> i(serialPorts); | ||||
|     response.getGs232ControllerReport()->setSerialPorts(new QList<QString*>()); | ||||
| 
 | ||||
|     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<QSerialPortInfo> serialPortInfos = QSerialPortInfo::availablePorts(); | ||||
|     QListIterator<QSerialPortInfo> 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; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
| #include <QThread> | ||||
| #include <QNetworkRequest> | ||||
| #include <QHash> | ||||
| #include <QTimer> | ||||
| 
 | ||||
| #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<QObject*, GS232ControllerSettings::AvailableChannelOrFeature> 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_
 | ||||
|  | ||||
| @ -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<GS232ControllerSettings::AvailableChannelOrFeature>& 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) | ||||
| ˙ | ||||