mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	GS232 Rotator Controller updates
Add support for hamlib/rotctld protocol. Add support for TCP connections. Name plugin Rotator Controller, rather than GS-232 Rotator Controller, as it now supports 3 different protocols.
This commit is contained in:
		
							parent
							
								
									a41d0319dc
								
							
						
					
					
						commit
						257b265ee8
					
				| @ -127,6 +127,8 @@ void GS232ControllerGUI::onWidgetRolled(QWidget* widget, bool rollDown) | ||||
| { | ||||
|     (void) widget; | ||||
|     (void) rollDown; | ||||
|     m_settings.m_rollupState = saveState(); | ||||
|     applySettings(); | ||||
| } | ||||
| 
 | ||||
| GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) : | ||||
| @ -179,10 +181,14 @@ void GS232ControllerGUI::displaySettings() | ||||
|     ui->azimuth->setValue(m_settings.m_azimuth); | ||||
|     ui->elevation->setValue(m_settings.m_elevation); | ||||
|     ui->protocol->setCurrentIndex((int)m_settings.m_protocol); | ||||
|     ui->connection->setCurrentIndex((int)m_settings.m_connection); | ||||
|     updateDecimals(m_settings.m_protocol); | ||||
|     if (m_settings.m_serialPort.length() > 0) | ||||
|     if (m_settings.m_serialPort.length() > 0) { | ||||
|         ui->serialPort->lineEdit()->setText(m_settings.m_serialPort); | ||||
|     } | ||||
|     ui->baudRate->setCurrentText(QString("%1").arg(m_settings.m_baudRate)); | ||||
|     ui->host->setText(m_settings.m_host); | ||||
|     ui->port->setValue(m_settings.m_port); | ||||
|     ui->track->setChecked(m_settings.m_track); | ||||
|     ui->sources->setCurrentIndex(ui->sources->findText(m_settings.m_source)); | ||||
|     ui->azimuthOffset->setValue(m_settings.m_azimuthOffset); | ||||
| @ -192,9 +198,24 @@ void GS232ControllerGUI::displaySettings() | ||||
|     ui->elevationMin->setValue(m_settings.m_elevationMin); | ||||
|     ui->elevationMax->setValue(m_settings.m_elevationMax); | ||||
|     ui->tolerance->setValue(m_settings.m_tolerance); | ||||
|     restoreState(m_settings.m_rollupState); | ||||
|     updateConnectionWidgets(); | ||||
|     blockApplySettings(false); | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerGUI::updateConnectionWidgets() | ||||
| { | ||||
|     bool serial = m_settings.m_connection == GS232ControllerSettings::SERIAL; | ||||
|     ui->serialPortLabel->setVisible(serial); | ||||
|     ui->serialPort->setVisible(serial); | ||||
|     ui->baudRateLabel->setVisible(serial); | ||||
|     ui->baudRate->setVisible(serial); | ||||
|     ui->hostLabel->setVisible(!serial); | ||||
|     ui->host->setVisible(!serial); | ||||
|     ui->portLabel->setVisible(!serial); | ||||
|     ui->port->setVisible(!serial); | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerGUI::updateSerialPortList() | ||||
| { | ||||
|     ui->serialPort->clear(); | ||||
| @ -315,6 +336,13 @@ void GS232ControllerGUI::on_protocol_currentIndexChanged(int index) | ||||
|     applySettings(); | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerGUI::on_connection_currentIndexChanged(int index) | ||||
| { | ||||
|     m_settings.m_connection = (GS232ControllerSettings::Connection)index; | ||||
|     applySettings(); | ||||
|     updateConnectionWidgets(); | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerGUI::on_serialPort_currentIndexChanged(int index) | ||||
| { | ||||
|     (void) index; | ||||
| @ -329,6 +357,18 @@ void GS232ControllerGUI::on_baudRate_currentIndexChanged(int index) | ||||
|     applySettings(); | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerGUI::on_host_editingFinished() | ||||
| { | ||||
|     m_settings.m_host = ui->host->text(); | ||||
|     applySettings(); | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerGUI::on_port_valueChanged(int value) | ||||
| { | ||||
|     m_settings.m_port = value; | ||||
|     applySettings(); | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerGUI::on_azimuth_valueChanged(double value) | ||||
| { | ||||
|     m_settings.m_azimuth = (float)value; | ||||
| @ -388,7 +428,7 @@ void GS232ControllerGUI::on_tolerance_valueChanged(double value) | ||||
| void GS232ControllerGUI::on_track_stateChanged(int state) | ||||
| { | ||||
|     m_settings.m_track = state == Qt::Checked; | ||||
|     ui->targetsLabel->setEnabled(m_settings.m_track); | ||||
|     ui->targetName->setEnabled(m_settings.m_track); | ||||
|     ui->sources->setEnabled(m_settings.m_track); | ||||
| 
 | ||||
|     if (!m_settings.m_track) { | ||||
| @ -439,7 +479,7 @@ void GS232ControllerGUI::updateStatus() | ||||
|                 break; | ||||
|             case Feature::StError: | ||||
|                 ui->startStop->setStyleSheet("QToolButton { background-color : red; }"); | ||||
|                 QMessageBox::information(this, tr("Message"), m_gs232Controller->getErrorMessage()); | ||||
|                 QMessageBox::critical(this, m_settings.m_title, m_gs232Controller->getErrorMessage()); | ||||
|                 break; | ||||
|             default: | ||||
|                 break; | ||||
|  | ||||
| @ -65,6 +65,7 @@ private: | ||||
|     void blockApplySettings(bool block); | ||||
|     void applySettings(bool force = false); | ||||
|     void displaySettings(); | ||||
|     void updateConnectionWidgets(); | ||||
|     void updateDecimals(GS232ControllerSettings::Protocol protocol); | ||||
|     void updatePipeList(); | ||||
|     void updateSerialPortList(); | ||||
| @ -79,7 +80,10 @@ private slots: | ||||
|     void handleInputMessages(); | ||||
|     void on_startStop_toggled(bool checked); | ||||
|     void on_protocol_currentIndexChanged(int index); | ||||
|     void on_connection_currentIndexChanged(int index); | ||||
|     void on_serialPort_currentIndexChanged(int index); | ||||
|     void on_host_editingFinished(); | ||||
|     void on_port_valueChanged(int value); | ||||
|     void on_baudRate_currentIndexChanged(int index); | ||||
|     void on_track_stateChanged(int state); | ||||
|     void on_azimuth_valueChanged(double value); | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>360</width> | ||||
|     <height>231</height> | ||||
|     <height>281</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="sizePolicy"> | ||||
| @ -37,17 +37,17 @@ | ||||
|   <property name="windowTitle"> | ||||
|    <string>GS-232 Rotator Controller</string> | ||||
|   </property> | ||||
|   <widget class="QWidget" name="settingsContainer" native="true"> | ||||
|   <widget class="QWidget" name="controlsContainer" native="true"> | ||||
|    <property name="geometry"> | ||||
|     <rect> | ||||
|      <x>10</x> | ||||
|      <y>10</y> | ||||
|      <width>341</width> | ||||
|      <height>211</height> | ||||
|      <height>81</height> | ||||
|     </rect> | ||||
|    </property> | ||||
|    <property name="windowTitle"> | ||||
|     <string>Settings</string> | ||||
|     <string>Controls</string> | ||||
|    </property> | ||||
|    <layout class="QVBoxLayout" name="verticalLayout"> | ||||
|     <property name="spacing"> | ||||
| @ -184,34 +184,192 @@ | ||||
|     </item> | ||||
|     <item> | ||||
|      <layout class="QGridLayout" name="gridLayout"> | ||||
|       <item row="2" column="2"> | ||||
|        <widget class="QLabel" name="toleranceLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Tolerance</string> | ||||
|       <item row="0" column="1" colspan="2"> | ||||
|        <widget class="QComboBox" name="sources"> | ||||
|         <property name="minimumSize"> | ||||
|          <size> | ||||
|           <width>150</width> | ||||
|           <height>0</height> | ||||
|          </size> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string>Target to track</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="4" column="0"> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QCheckBox" name="track"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Check to enable automatic tracking of azimuth and elevation from the specified channel</string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>Track</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="3"> | ||||
|        <widget class="QLineEdit" name="targetName"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Name of the target being tracked as indicated by the source channel / feature</string> | ||||
|         </property> | ||||
|         <property name="readOnly"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|    </layout> | ||||
|   </widget> | ||||
|   <widget class="QWidget" name="settingsContainer" native="true"> | ||||
|    <property name="geometry"> | ||||
|     <rect> | ||||
|      <x>10</x> | ||||
|      <y>110</y> | ||||
|      <width>341</width> | ||||
|      <height>161</height> | ||||
|     </rect> | ||||
|    </property> | ||||
|    <property name="windowTitle"> | ||||
|     <string>Settings</string> | ||||
|    </property> | ||||
|    <layout class="QVBoxLayout" name="verticalLayout_2"> | ||||
|     <property name="spacing"> | ||||
|      <number>3</number> | ||||
|     </property> | ||||
|     <property name="leftMargin"> | ||||
|      <number>2</number> | ||||
|     </property> | ||||
|     <property name="topMargin"> | ||||
|      <number>2</number> | ||||
|     </property> | ||||
|     <property name="rightMargin"> | ||||
|      <number>2</number> | ||||
|     </property> | ||||
|     <property name="bottomMargin"> | ||||
|      <number>2</number> | ||||
|     </property> | ||||
|     <item> | ||||
|      <layout class="QGridLayout" name="settingsGridLayout"> | ||||
|       <item row="3" column="0"> | ||||
|        <widget class="QLabel" name="azimuthOffsetLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Azimuth offset</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="4" column="0"> | ||||
|        <widget class="QLabel" name="azimuthMinLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Azimuth min</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="4" column="1"> | ||||
|        <widget class="QSpinBox" name="azimuthOffset"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Specify an offset angel in degrees that will be added to the target azimuth to correct for misalignment</string> | ||||
|         </property> | ||||
|         <property name="minimum"> | ||||
|          <number>-360</number> | ||||
|         </property> | ||||
|        <widget class="QSpinBox" name="azimuthMin"> | ||||
|         <property name="maximum"> | ||||
|          <number>360</number> | ||||
|          <number>450</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QLabel" name="protocolLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Protocol</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="5" column="2"> | ||||
|        <widget class="QLabel" name="elevationMaxLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Elevation max</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="4" column="3"> | ||||
|        <widget class="QSpinBox" name="azimuthMax"> | ||||
|         <property name="maximum"> | ||||
|          <number>450</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="2"> | ||||
|        <widget class="QLabel" name="connectionLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Connection</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="5" column="1"> | ||||
|        <widget class="QSpinBox" name="elevationMin"> | ||||
|         <property name="maximum"> | ||||
|          <number>180</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="2"> | ||||
|        <widget class="QLabel" name="portLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Port</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="6" column="1"> | ||||
|        <widget class="QDoubleSpinBox" name="tolerance"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Tolerance in degrees</string> | ||||
|         </property> | ||||
|         <property name="decimals"> | ||||
|          <number>1</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0"> | ||||
|        <widget class="QLabel" name="serialPortLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Serial Port</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="3"> | ||||
|        <widget class="QComboBox" name="connection"> | ||||
|         <property name="toolTip"> | ||||
|          <string>The type of connection to use to the rotator</string> | ||||
|         </property> | ||||
|         <item> | ||||
|          <property name="text"> | ||||
|           <string>Serial</string> | ||||
|          </property> | ||||
|         </item> | ||||
|         <item> | ||||
|          <property name="text"> | ||||
|           <string>TCP</string> | ||||
|          </property> | ||||
|         </item> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="6" column="0"> | ||||
|        <widget class="QLabel" name="toleranceLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Tolerance</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="3" column="2"> | ||||
|        <widget class="QLabel" name="elevationOffsetLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Elevation offset</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="5" column="0"> | ||||
|        <widget class="QLabel" name="elevationMinLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Elevation min</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="3" column="3"> | ||||
|        <widget class="QSpinBox" name="elevationOffset"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Specify an offset angle in degrees that will be added to the target elevation to correct for misalignment</string> | ||||
| @ -227,7 +385,14 @@ | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="3" column="1"> | ||||
|       <item row="2" column="1"> | ||||
|        <widget class="QLineEdit" name="host"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Host name / IP address of computer running rotctld</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="1"> | ||||
|        <widget class="QComboBox" name="serialPort"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Name of serial port to use to connect to the GS-232 controller</string> | ||||
| @ -237,7 +402,43 @@ | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="3" column="3"> | ||||
|       <item row="0" column="1"> | ||||
|        <widget class="QComboBox" name="protocol"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Command protocol</string> | ||||
|         </property> | ||||
|         <item> | ||||
|          <property name="text"> | ||||
|           <string>GS-232</string> | ||||
|          </property> | ||||
|         </item> | ||||
|         <item> | ||||
|          <property name="text"> | ||||
|           <string>SPID</string> | ||||
|          </property> | ||||
|         </item> | ||||
|         <item> | ||||
|          <property name="text"> | ||||
|           <string>rotctld</string> | ||||
|          </property> | ||||
|         </item> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="0"> | ||||
|        <widget class="QLabel" name="hostLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Host</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="5" column="3"> | ||||
|        <widget class="QSpinBox" name="elevationMax"> | ||||
|         <property name="maximum"> | ||||
|          <number>180</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="3"> | ||||
|        <widget class="QComboBox" name="baudRate"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Serial port baud rate for the GS-232 controller</string> | ||||
| @ -297,161 +498,40 @@ | ||||
|         </item> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="3" column="0"> | ||||
|        <widget class="QLabel" name="serialLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Serial Port</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="4" column="2"> | ||||
|        <widget class="QLabel" name="elevationOffsetLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Elevation offset</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="6" column="2"> | ||||
|        <widget class="QLabel" name="elevationMaxLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Elevation max</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="6" column="1"> | ||||
|        <widget class="QSpinBox" name="elevationMin"> | ||||
|         <property name="maximum"> | ||||
|          <number>180</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="1"> | ||||
|        <widget class="QComboBox" name="protocol"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Command protocol</string> | ||||
|         </property> | ||||
|         <item> | ||||
|          <property name="text"> | ||||
|           <string>GS-232</string> | ||||
|          </property> | ||||
|         </item> | ||||
|         <item> | ||||
|          <property name="text"> | ||||
|           <string>SPID</string> | ||||
|          </property> | ||||
|         </item> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="5" column="0"> | ||||
|        <widget class="QLabel" name="azimuthMinLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Azimuth min</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="5" column="3"> | ||||
|        <widget class="QSpinBox" name="azimuthMax"> | ||||
|         <property name="maximum"> | ||||
|          <number>450</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="0"> | ||||
|        <widget class="QLabel" name="protocolLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Protocol</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="6" column="3"> | ||||
|        <widget class="QSpinBox" name="elevationMax"> | ||||
|         <property name="maximum"> | ||||
|          <number>180</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="6" column="0"> | ||||
|        <widget class="QLabel" name="elevationMinLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Elevation min</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="3" column="2"> | ||||
|        <widget class="QLabel" name="baudRateLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Baud rate</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="5" column="1"> | ||||
|        <widget class="QSpinBox" name="azimuthMin"> | ||||
|         <property name="maximum"> | ||||
|          <number>450</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="5" column="2"> | ||||
|        <widget class="QLabel" name="azimuthMaxLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Azimuth max</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QCheckBox" name="track"> | ||||
|       <item row="3" column="1"> | ||||
|        <widget class="QSpinBox" name="azimuthOffset"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Check to enable automatic tracking of azimuth and elevation from the specified channel</string> | ||||
|          <string>Specify an offset angel in degrees that will be added to the target azimuth to correct for misalignment</string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>Track</string> | ||||
|         <property name="minimum"> | ||||
|          <number>-360</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="2" colspan="2"> | ||||
|        <widget class="QLineEdit" name="targetName"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Name of the target being tracked as indicated by the source channel / feature</string> | ||||
|         </property> | ||||
|         <property name="readOnly"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="1"> | ||||
|        <widget class="QLabel" name="targetNameLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Target</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1"> | ||||
|        <widget class="QLabel" name="targetsLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Source</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="2" colspan="2"> | ||||
|        <widget class="QComboBox" name="sources"> | ||||
|         <property name="minimumSize"> | ||||
|          <size> | ||||
|           <width>150</width> | ||||
|           <height>0</height> | ||||
|          </size> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string>Target to track</string> | ||||
|         <property name="maximum"> | ||||
|          <number>360</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="3"> | ||||
|        <widget class="QDoubleSpinBox" name="tolerance"> | ||||
|        <widget class="QSpinBox" name="port"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Tolerance in degrees</string> | ||||
|          <string>TCP port number rotctld is listening on</string> | ||||
|         </property> | ||||
|         <property name="decimals"> | ||||
|          <number>1</number> | ||||
|         <property name="maximum"> | ||||
|          <number>65535</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="2"> | ||||
|        <widget class="QLabel" name="baudRateLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Baud rate</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
| @ -479,17 +559,6 @@ | ||||
|   <tabstop>elevation</tabstop> | ||||
|   <tabstop>track</tabstop> | ||||
|   <tabstop>sources</tabstop> | ||||
|   <tabstop>targetName</tabstop> | ||||
|   <tabstop>protocol</tabstop> | ||||
|   <tabstop>tolerance</tabstop> | ||||
|   <tabstop>serialPort</tabstop> | ||||
|   <tabstop>baudRate</tabstop> | ||||
|   <tabstop>azimuthOffset</tabstop> | ||||
|   <tabstop>elevationOffset</tabstop> | ||||
|   <tabstop>azimuthMin</tabstop> | ||||
|   <tabstop>azimuthMax</tabstop> | ||||
|   <tabstop>elevationMin</tabstop> | ||||
|   <tabstop>elevationMax</tabstop> | ||||
|  </tabstops> | ||||
|  <resources> | ||||
|   <include location="../../../sdrgui/resources/res.qrc"/> | ||||
|  | ||||
| @ -29,8 +29,8 @@ | ||||
| 
 | ||||
| const PluginDescriptor GS232ControllerPlugin::m_pluginDescriptor = { | ||||
|     GS232Controller::m_featureId, | ||||
|     QStringLiteral("GS-232 Rotator Controller"), | ||||
|     QStringLiteral("6.17.2"), | ||||
|     QStringLiteral("Rotator Controller"), | ||||
|     QStringLiteral("6.17.4"), | ||||
|     QStringLiteral("(c) Jon Beniston, M7RCE"), | ||||
|     QStringLiteral("https://github.com/f4exb/sdrangel"), | ||||
|     true, | ||||
|  | ||||
| @ -50,7 +50,7 @@ void GS232ControllerSettings::resetToDefaults() | ||||
|     m_baudRate = 9600; | ||||
|     m_track = false; | ||||
|     m_source = ""; | ||||
|     m_title = "GS-232 Rotator Controller"; | ||||
|     m_title = "Rotator Controller"; | ||||
|     m_rgbColor = QColor(225, 25, 99).rgb(); | ||||
|     m_useReverseAPI = false; | ||||
|     m_reverseAPIAddress = "127.0.0.1"; | ||||
| @ -63,8 +63,11 @@ void GS232ControllerSettings::resetToDefaults() | ||||
|     m_azimuthMax = 450; | ||||
|     m_elevationMin = 0; | ||||
|     m_elevationMax = 180; | ||||
|     m_tolerance = 0.0f; | ||||
|     m_tolerance = 1.0f; | ||||
|     m_protocol = GS232; | ||||
|     m_connection = SERIAL; | ||||
|     m_host = "127.0.0.1"; | ||||
|     m_port = 4533; | ||||
| } | ||||
| 
 | ||||
| QByteArray GS232ControllerSettings::serialize() const | ||||
| @ -92,6 +95,10 @@ QByteArray GS232ControllerSettings::serialize() const | ||||
|     s.writeS32(20, m_elevationMax); | ||||
|     s.writeFloat(21, m_tolerance); | ||||
|     s.writeS32(22, (int)m_protocol); | ||||
|     s.writeS32(23, (int)m_connection); | ||||
|     s.writeString(24, m_host); | ||||
|     s.writeS32(25, m_port); | ||||
|     s.writeBlob(26, m_rollupState); | ||||
| 
 | ||||
|     return s.final(); | ||||
| } | ||||
| @ -118,7 +125,7 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data) | ||||
|         d.readS32(4, &m_baudRate, 9600); | ||||
|         d.readBool(5, &m_track, false); | ||||
|         d.readString(6, &m_source, ""); | ||||
|         d.readString(8, &m_title, "GS-232 Rotator Controller"); | ||||
|         d.readString(8, &m_title, "Rotator Controller"); | ||||
|         d.readU32(9, &m_rgbColor, QColor(225, 25, 99).rgb()); | ||||
|         d.readBool(10, &m_useReverseAPI, false); | ||||
|         d.readString(11, &m_reverseAPIAddress, "127.0.0.1"); | ||||
| @ -140,8 +147,12 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data) | ||||
|         d.readS32(18, &m_azimuthMax, 450); | ||||
|         d.readS32(19, &m_elevationMin, 0); | ||||
|         d.readS32(20, &m_elevationMax, 180); | ||||
|         d.readFloat(21, &m_tolerance, 0.0f); | ||||
|         d.readFloat(21, &m_tolerance, 1.0f); | ||||
|         d.readS32(22, (int*)&m_protocol, GS232); | ||||
|         d.readS32(23, (int*)&m_connection, SERIAL); | ||||
|         d.readString(24, &m_host, "127.0.0.1"); | ||||
|         d.readS32(25, &m_port, 4533); | ||||
|         d.readBlob(26, &m_rollupState); | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @ -32,6 +32,8 @@ struct GS232ControllerSettings | ||||
|     float m_elevation; | ||||
|     QString m_serialPort; | ||||
|     int m_baudRate; | ||||
|     QString m_host; | ||||
|     int m_port; | ||||
|     bool m_track; | ||||
|     QString m_source;           // Plugin to get az/el from. E.g: "R0:0 ADSBDemod". Use a string, so can be set via WebAPI
 | ||||
|     int m_azimuthOffset; | ||||
| @ -41,7 +43,9 @@ struct GS232ControllerSettings | ||||
|     int m_elevationMin; | ||||
|     int m_elevationMax; | ||||
|     float m_tolerance; | ||||
|     enum Protocol { GS232, SPID } m_protocol; | ||||
|     enum Protocol { GS232, SPID, ROTCTLD } m_protocol; | ||||
|     enum Connection { SERIAL, TCP } m_connection; | ||||
|     QByteArray m_rollupState; | ||||
|     QString m_title; | ||||
|     quint32 m_rgbColor; | ||||
|     bool m_useReverseAPI; | ||||
|  | ||||
| @ -35,11 +35,13 @@ GS232ControllerWorker::GS232ControllerWorker() : | ||||
|     m_msgQueueToFeature(nullptr), | ||||
|     m_running(false), | ||||
|     m_mutex(QMutex::Recursive), | ||||
|     m_device(nullptr), | ||||
|     m_lastAzimuth(-1.0f), | ||||
|     m_lastElevation(-1.0f), | ||||
|     m_spidSetOutstanding(false), | ||||
|     m_spidSetSent(false), | ||||
|     m_spidStatusSent(false) | ||||
|     m_spidStatusSent(false), | ||||
|     m_rotCtlDReadAz(false) | ||||
| { | ||||
|     connect(&m_pollTimer, SIGNAL(timeout()), this, SLOT(update())); | ||||
|     m_pollTimer.start(1000); | ||||
| @ -65,9 +67,12 @@ bool GS232ControllerWorker::startWork() | ||||
| { | ||||
|     QMutexLocker mutexLocker(&m_mutex); | ||||
|     connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); | ||||
|     connect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData); | ||||
|     if (!m_settings.m_serialPort.isEmpty()) { | ||||
|         openSerialPort(m_settings); | ||||
|     connect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readData); | ||||
|     connect(&m_socket, &QTcpSocket::readyRead, this, &GS232ControllerWorker::readData); | ||||
|     if (m_settings.m_connection == GS232ControllerSettings::TCP) { | ||||
|         m_device = openSocket(m_settings); | ||||
|     } else { | ||||
|         m_device = openSerialPort(m_settings); | ||||
|     } | ||||
|     m_running = true; | ||||
|     return m_running; | ||||
| @ -77,10 +82,12 @@ void GS232ControllerWorker::stopWork() | ||||
| { | ||||
|     QMutexLocker mutexLocker(&m_mutex); | ||||
|     // Close serial port as USB/controller activity can create RFI
 | ||||
|     if (m_serialPort.isOpen()) | ||||
|         m_serialPort.close(); | ||||
|     if (m_device && m_device->isOpen()) { | ||||
|         m_device->close(); | ||||
|     } | ||||
|     disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); | ||||
|     disconnect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData); | ||||
|     disconnect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readData); | ||||
|     disconnect(&m_socket, &QTcpSocket::readyRead, this, &GS232ControllerWorker::readData); | ||||
|     m_running = false; | ||||
| } | ||||
| 
 | ||||
| @ -125,17 +132,33 @@ void GS232ControllerWorker::applySettings(const GS232ControllerSettings& setting | ||||
|             << " m_elevationMax: " << settings.m_elevationMax | ||||
|             << " m_tolerance: " << settings.m_tolerance | ||||
|             << " m_protocol: " << settings.m_protocol | ||||
|             << " m_connection: " << settings.m_connection | ||||
|             << " m_serialPort: " << settings.m_serialPort | ||||
|             << " m_baudRate: " << settings.m_baudRate | ||||
|             << " m_host: " << settings.m_host | ||||
|             << " m_port: " << settings.m_port | ||||
|             << " force: " << force; | ||||
| 
 | ||||
|     if ((settings.m_serialPort != m_settings.m_serialPort) || force) | ||||
|     if (settings.m_connection != m_settings.m_connection) | ||||
|     { | ||||
|         openSerialPort(settings); | ||||
|         if (m_device && m_device->isOpen()) { | ||||
|             m_device->close(); | ||||
|         } | ||||
|     } | ||||
|     else if ((settings.m_baudRate != m_settings.m_baudRate) || force) | ||||
| 
 | ||||
|     if (settings.m_connection == GS232ControllerSettings::TCP) | ||||
|     { | ||||
|         m_serialPort.setBaudRate(settings.m_baudRate); | ||||
|         if ((settings.m_host != m_settings.m_host) || (settings.m_port != m_settings.m_port) || force) { | ||||
|             m_device = openSocket(settings); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if ((settings.m_serialPort != m_settings.m_serialPort) || force) { | ||||
|             m_device = openSerialPort(settings); | ||||
|         } else if ((settings.m_baudRate != m_settings.m_baudRate) || force) { | ||||
|             m_serialPort.setBaudRate(settings.m_baudRate); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Apply offset then clamp
 | ||||
| @ -159,22 +182,54 @@ void GS232ControllerWorker::applySettings(const GS232ControllerSettings& setting | ||||
|     m_settings = settings; | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerWorker::openSerialPort(const GS232ControllerSettings& settings) | ||||
| QIODevice *GS232ControllerWorker::openSerialPort(const GS232ControllerSettings& settings) | ||||
| { | ||||
|     qDebug() << "GS232ControllerWorker::openSerialPort: " << settings.m_serialPort; | ||||
|     if (m_serialPort.isOpen()) { | ||||
|         m_serialPort.close(); | ||||
|     } | ||||
|     m_serialPort.setPortName(settings.m_serialPort); | ||||
|     m_serialPort.setBaudRate(settings.m_baudRate); | ||||
|     if (!m_serialPort.open(QIODevice::ReadWrite)) | ||||
|     m_lastAzimuth = -1; | ||||
|     m_lastElevation = -1; | ||||
|     if (!settings.m_serialPort.isEmpty()) | ||||
|     { | ||||
|         qCritical() << "GS232ControllerWorker::openSerialPort: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error(); | ||||
|         if (m_msgQueueToFeature) { | ||||
|         m_serialPort.setPortName(settings.m_serialPort); | ||||
|         m_serialPort.setBaudRate(settings.m_baudRate); | ||||
|         if (!m_serialPort.open(QIODevice::ReadWrite)) | ||||
|         { | ||||
|             qCritical() << "GS232ControllerWorker::openSerialPort: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error(); | ||||
|             m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Failed to open serial port %1: %2").arg(settings.m_serialPort).arg(m_serialPort.error()))); | ||||
|             return nullptr; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return &m_serialPort; | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return nullptr; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| QIODevice *GS232ControllerWorker::openSocket(const GS232ControllerSettings& settings) | ||||
| { | ||||
|     qDebug() << "GS232ControllerWorker::openSocket: " << settings.m_host << settings.m_port; | ||||
|     if (m_socket.isOpen()) { | ||||
|         m_socket.close(); | ||||
|     } | ||||
|     m_lastAzimuth = -1; | ||||
|     m_lastElevation = -1; | ||||
|     m_socket.connectToHost(settings.m_host, settings.m_port); | ||||
|     if (m_socket.waitForConnected(3000)) | ||||
|     { | ||||
|         return &m_socket; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         qCritical() << "GS232ControllerWorker::openSocket: Failed to connect to " << settings.m_host << settings.m_port; | ||||
|         m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Failed to connect to %1:%2").arg(settings.m_host).arg(settings.m_port))); | ||||
|         return nullptr; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerWorker::setAzimuth(float azimuth) | ||||
| @ -200,10 +255,8 @@ void GS232ControllerWorker::setAzimuthElevation(float azimuth, float elevation) | ||||
|         QByteArray data = cmd.toLatin1(); | ||||
|         m_serialPort.write(data); | ||||
|     } | ||||
|     else | ||||
|     else if (m_settings.m_protocol == GS232ControllerSettings::SPID) | ||||
|     { | ||||
|         qDebug() << "GS232ControllerWorker::setAzimuthElevation " << " AZ " << azimuth << " EL " << elevation; | ||||
| 
 | ||||
|         if (!m_spidSetSent && !m_spidStatusSent) | ||||
|         { | ||||
|             QByteArray cmd(13, (char)0); | ||||
| @ -233,21 +286,25 @@ void GS232ControllerWorker::setAzimuthElevation(float azimuth, float elevation) | ||||
|             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_socket.write(data); | ||||
|     } | ||||
|     m_lastAzimuth = azimuth; | ||||
|     m_lastElevation = elevation; | ||||
| } | ||||
| 
 | ||||
| void GS232ControllerWorker::readSerialData() | ||||
| void GS232ControllerWorker::readData() | ||||
| { | ||||
|     char buf[1024]; | ||||
|     qint64 len; | ||||
| 
 | ||||
|     if (m_settings.m_protocol == GS232ControllerSettings::GS232) | ||||
|     { | ||||
|         while (m_serialPort.canReadLine()) | ||||
|         while (m_device->canReadLine()) | ||||
|         { | ||||
|             len = m_serialPort.readLine(buf, sizeof(buf)); | ||||
|             len = m_device->readLine(buf, sizeof(buf)); | ||||
|             if (len != -1) | ||||
|             { | ||||
|                 QString response = QString::fromUtf8(buf, len); | ||||
| @ -258,7 +315,7 @@ void GS232ControllerWorker::readSerialData() | ||||
|                 { | ||||
|                     QString az = match.captured(1); | ||||
|                     QString el = match.captured(2); | ||||
|                     //qDebug() << "GS232ControllerWorker::readSerialData read Az " << az << " El " << el;
 | ||||
|                     //qDebug() << "GS232ControllerWorker::readData read Az " << az << " El " << el;
 | ||||
|                     m_msgQueueToFeature->push(GS232ControllerReport::MsgReportAzAl::create(az.toFloat(), el.toFloat())); | ||||
|                 } | ||||
|                 else if (response == "\r\n") | ||||
| @ -267,27 +324,27 @@ void GS232ControllerWorker::readSerialData() | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     qDebug() << "GS232ControllerWorker::readSerialData - unexpected GS-232 response \"" << response << "\""; | ||||
|                     qWarning() << "GS232ControllerWorker::readData - unexpected GS-232 response \"" << response << "\""; | ||||
|                     m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Unexpected GS-232 response: %1").arg(response))); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     else if (m_settings.m_protocol == GS232ControllerSettings::SPID) | ||||
|     { | ||||
|         while (m_serialPort.bytesAvailable() >= 12) | ||||
|         while (m_device->bytesAvailable() >= 12) | ||||
|         { | ||||
|             len = m_serialPort.read(buf, 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::readSerialData read Az " << az << " El " << el;
 | ||||
|                 //qDebug() << "GS232ControllerWorker::readData read Az " << az << " El " << el;
 | ||||
|                 m_msgQueueToFeature->push(GS232ControllerReport::MsgReportAzAl::create(az, el)); | ||||
|                 if (m_spidStatusSent && m_spidSetSent) { | ||||
|                     qDebug() << "GS232ControllerWorker::readSerialData - m_spidStatusSent and m_spidSetSent set simultaneously"; | ||||
|                     qDebug() << "GS232ControllerWorker::readData - m_spidStatusSent and m_spidSetSent set simultaneously"; | ||||
|                 } | ||||
|                 if (m_spidStatusSent) { | ||||
|                     m_spidStatusSent = false; | ||||
| @ -304,9 +361,78 @@ void GS232ControllerWorker::readSerialData() | ||||
|             else | ||||
|             { | ||||
|                 QByteArray bytes(buf, (int)len); | ||||
|                 qDebug() << "GS232ControllerWorker::readSerialData - unexpected SPID rot2prog response \"" << bytes.toHex() << "\""; | ||||
|                 if (m_msgQueueToFeature) { | ||||
|                     m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Unexpected SPID rot2prog response: %1").arg(bytes.toHex().data()))); | ||||
|                 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))); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @ -315,15 +441,15 @@ void GS232ControllerWorker::readSerialData() | ||||
| 
 | ||||
| void GS232ControllerWorker::update() | ||||
| { | ||||
|     // Request current Az/El from GS-232 controller
 | ||||
|     if (m_serialPort.isOpen()) | ||||
|     // 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_serialPort.write(cmd); | ||||
|             m_device->write(cmd); | ||||
|         } | ||||
|         else | ||||
|         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) | ||||
| @ -336,9 +462,14 @@ void GS232ControllerWorker::update() | ||||
|                 } | ||||
|                 cmd.append((char)0x1f); // Status
 | ||||
|                 cmd.append((char)0x20); // End
 | ||||
|                 m_serialPort.write(cmd); | ||||
|                 m_device->write(cmd); | ||||
|                 m_spidStatusSent = true; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             QByteArray cmd("p\n"); | ||||
|             m_device->write(cmd); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
| #include <QObject> | ||||
| #include <QTimer> | ||||
| #include <QSerialPort> | ||||
| #include <QTcpSocket> | ||||
| 
 | ||||
| #include "util/message.h" | ||||
| #include "util/messagequeue.h" | ||||
| @ -71,7 +72,9 @@ private: | ||||
|     GS232ControllerSettings m_settings; | ||||
|     bool m_running; | ||||
|     QMutex m_mutex; | ||||
|     QIODevice *m_device; | ||||
|     QSerialPort m_serialPort; | ||||
|     QTcpSocket m_socket; | ||||
|     QTimer m_pollTimer; | ||||
| 
 | ||||
|     float m_lastAzimuth; | ||||
| @ -81,15 +84,19 @@ private: | ||||
|     bool m_spidSetSent; | ||||
|     bool m_spidStatusSent; | ||||
| 
 | ||||
|     bool m_rotCtlDReadAz;               //!< rotctrld returns 'p' responses over two lines
 | ||||
|     QString m_rotCtlDAz; | ||||
| 
 | ||||
|     bool handleMessage(const Message& cmd); | ||||
|     void applySettings(const GS232ControllerSettings& settings, bool force = false); | ||||
|     void openSerialPort(const GS232ControllerSettings& settings); | ||||
|     QIODevice *openSerialPort(const GS232ControllerSettings& settings); | ||||
|     QIODevice *openSocket(const GS232ControllerSettings& settings); | ||||
|     void setAzimuth(float azimuth); | ||||
|     void setAzimuthElevation(float azimuth, float elevation); | ||||
| 
 | ||||
| private slots: | ||||
|     void handleInputMessages(); | ||||
|     void readSerialData(); | ||||
|     void readData(); | ||||
|     void update(); | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <h1>GS-232 Rotator Controller Feature Plugin</h1> | ||||
| <h1>Rotator Controller Feature Plugin</h1> | ||||
| 
 | ||||
| <h2>Introduction</h2> | ||||
| 
 | ||||
| The GS-232 Rotator Controller feature plugin allows SDRangel to send commands to GS-232 and SPID rotators. This allows SDRangel to point antennas mounted on a rotator to a specified azimuth and elevation. | ||||
| The Rotator Controller feature plugin allows SDRangel to send commands to GS-232 and SPID rotators as well as hamlib's rotctld, via serial or TCP. This allows SDRangel to point antennas mounted on a rotator to a specified azimuth and elevation. | ||||
| 
 | ||||
| Azimuth and elevation can be set manually by a user in the GUI, via the REST API, or via another plugin, such as the Map Feature, the ADS-B Demodulator, or the Star Tracker. | ||||
| 
 | ||||
| <h2>Interface</h2> | ||||
| 
 | ||||
|  | ||||
|  | ||||
| 
 | ||||
| <h3>1: Start/Stop plugin</h3> | ||||
| 
 | ||||
| @ -42,15 +42,11 @@ For example, the ADS-B plugin will display the flight number of the target aircr | ||||
| 
 | ||||
| <h3>7: Protocol</h3> | ||||
| 
 | ||||
| Selects which serial protocol to use. This can be GS-232 or SPID (rot2prog). | ||||
| Selects which protocol to use. This can be GS-232, SPID (rot2prog) or rotctld. | ||||
| 
 | ||||
| <h3>8: Tolerance</h3> | ||||
| <h3>8: Connection</h3> | ||||
| 
 | ||||
| Specifies a tolerance in degrees, below which, changes in target azimuth or elevation will not be sent to the rotator. | ||||
| This can prevent some rotators that have a limited accuracy from making unbeneficial movements. | ||||
| 
 | ||||
| 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. | ||||
| Selects whether to use a serial connection or TCP. | ||||
| 
 | ||||
| <h3>9: Serial Port</h3> | ||||
| 
 | ||||
| @ -60,25 +56,41 @@ Specifies the serial port (E.g. COM3 on Windows or /dev/ttyS0 on Linux) that wil | ||||
| 
 | ||||
| Specifies the baud rate that will be used to send commands to the rotator. Typically this is 9600 for GS-232. | ||||
| 
 | ||||
| <h3>11: Azimuth Offset</h3> | ||||
| <h3>11: Host</h3> | ||||
| 
 | ||||
| Specifies the hostname / IP address of the computer running rotctld. | ||||
| 
 | ||||
| <h3>12: Port</h3> | ||||
| 
 | ||||
| Specifies the TCP port number rotctld is listening on. | ||||
| 
 | ||||
| <h3>13: Azimuth Offset</h3> | ||||
| 
 | ||||
| The azimuth offset specifies an angle in degrees that is added to the target azimuth before sending to the controller. This allows for a misalignment of the rotator to be corrected. | ||||
| 
 | ||||
| <h3>12: Elevation Offset</h3> | ||||
| <h3>14: Elevation Offset</h3> | ||||
| 
 | ||||
| The elevation offset specifies an angle in degrees that is added to the target elevation before sending to the controller. This allows for a misalignment of the rotator to be corrected. | ||||
| 
 | ||||
| <h3>13 and 14: Azimuth Min and Max</h3> | ||||
| <h3>15 and 16: Azimuth Min and Max</h3> | ||||
| 
 | ||||
| The azimuth min and max values specify the minimum and maximum azimuth values (after offset has been applied), that will be sent to the rotator. | ||||
| These values can be used to prevent the rotator from rotating an antenna in to an obstable. | ||||
| 
 | ||||
| <h3>15 and 16: Elevation Min and Max</h3> | ||||
| <h3>17 and 18: Elevation Min and Max</h3> | ||||
| 
 | ||||
| The elevation min and max values specify the minimum and maximum elevation values (after offset has been applied), that will be sent to the rotator. | ||||
| These values can be used to prevent the rotator from rotating an antenna in to an obstable. | ||||
| If the maximum elevation is set to 0, the controller will only use the M GS-232 command, rather than M and W. | ||||
| 
 | ||||
| <h3>19: Tolerance</h3> | ||||
| 
 | ||||
| Specifies a tolerance in degrees, below which, changes in target azimuth or elevation will not be sent to the rotator. | ||||
| This can prevent some rotators that have a limited accuracy from making unbeneficial movements. | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| <h2>GS-232 Protocol Implementation</h2> | ||||
| 
 | ||||
| The controller uses the Waaa eee command when elevation needs to be set. | ||||
| @ -92,6 +104,10 @@ The 0x1f status command is used to read current azimuth and elevation. | ||||
| A 12 byte response is expected for set and status commands. | ||||
| All frames start with 0x57 and end with 0x20. | ||||
| 
 | ||||
| <h2>rotctld Protocol Implementation</h2> | ||||
| 
 | ||||
| The controller uses the 'P' and 'p' commands to set and get azimuth and elevation. | ||||
| 
 | ||||
| <h2>API</h2> | ||||
| 
 | ||||
| Full details of the API can be found in the Swagger documentation. Here is a quick example of how to set the azimuth and elevation from the command line: | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user