GS-232 Controller updates.

Update GS-232 controller to use message pipes for the target.
Add field displaying the name of the target.
Add azimuth and elevation offsets.
Report worker thread errors to the GUI.
This commit is contained in:
Jon Beniston 2021-01-13 19:44:53 +00:00
parent f2ebd72004
commit 931a63dc8b
13 changed files with 417 additions and 403 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

View File

@ -20,33 +20,42 @@
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QBuffer>
#include <QRegExp>
#include "SWGFeatureSettings.h"
#include "SWGFeatureReport.h"
#include "SWGFeatureActions.h"
#include "SWGSimplePTTReport.h"
#include "SWGDeviceState.h"
#include "SWGTargetAzimuthElevation.h"
#include "dsp/dspengine.h"
#include "device/deviceset.h"
#include "channel/channelapi.h"
#include "feature/featureset.h"
#include "maincore.h"
#include "gs232controllerworker.h"
#include "gs232controller.h"
#include "gs232controllerworker.h"
#include "gs232controllerreport.h"
MESSAGE_CLASS_DEFINITION(GS232Controller::MsgConfigureGS232Controller, Message)
MESSAGE_CLASS_DEFINITION(GS232Controller::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(GS232Controller::MsgReportWorker, Message)
const char* const GS232Controller::m_featureIdURI = "sdrangel.feature.gs232controller";
const char* const GS232Controller::m_featureId = "GS232Controller";
GS232Controller::GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface) :
Feature(m_featureIdURI, webAPIAdapterInterface),
m_ptt(false)
Feature(m_featureIdURI, webAPIAdapterInterface)
{
qDebug("GS232Controller::GS232Controller: webAPIAdapterInterface: %p", webAPIAdapterInterface);
setObjectName(m_featureId);
m_worker = new GS232ControllerWorker(webAPIAdapterInterface);
m_worker = new GS232ControllerWorker();
m_state = StIdle;
m_errorMessage = "GS232Controller error";
m_selectedPipe = nullptr;
connect(&m_updatePipesTimer, SIGNAL(timeout()), this, SLOT(updatePipes()));
m_updatePipesTimer.start(1000);
}
GS232Controller::~GS232Controller()
@ -105,21 +114,46 @@ bool GS232Controller::handleMessage(const Message& cmd)
return true;
}
else if (GS232ControllerSettings::MsgChannelIndexChange::match(cmd))
else if (MsgReportWorker::match(cmd))
{
GS232ControllerSettings::MsgChannelIndexChange& cfg = (GS232ControllerSettings::MsgChannelIndexChange&) cmd;
int newChannelIndex = cfg.getIndex();
qDebug() << "GS232Controller::handleMessage: MsgChannelIndexChange: " << newChannelIndex;
GS232ControllerSettings settings = m_settings;
settings.m_channelIndex = newChannelIndex;
applySettings(settings, false);
if (getMessageQueueToGUI())
MsgReportWorker& report = (MsgReportWorker&) cmd;
if (report.getMessage() == "Connected")
m_state = StRunning;
else if (report.getMessage() == "Disconnected")
m_state = StIdle;
else
{
GS232ControllerSettings::MsgChannelIndexChange *msg = new GS232ControllerSettings::MsgChannelIndexChange(cfg);
getMessageQueueToGUI()->push(msg);
m_state = StError;
m_errorMessage = report.getMessage();
}
return true;
}
else if (MainCore::MsgTargetAzimuthElevation::match(cmd))
{
// New target from another plugin
if ((m_state == StRunning) && m_settings.m_track)
{
MainCore::MsgTargetAzimuthElevation& msg = (MainCore::MsgTargetAzimuthElevation&) cmd;
// Is it from the selected pipe?
if (msg.getPipeSource() == m_selectedPipe)
{
if (getMessageQueueToGUI())
{
// Forward to GUI - which will then send us updated settings
getMessageQueueToGUI()->push(new MainCore::MsgTargetAzimuthElevation(msg));
}
else
{
// No GUI, so save target - applySettings will propagate to worker
SWGSDRangel::SWGTargetAzimuthElevation *swgTarget = msg.getSWGTargetAzimuthElevation();
m_settings.m_azimuth = swgTarget->getAzimuth();
m_settings.m_elevation = swgTarget->getElevation();
applySettings(m_settings);
}
}
else
qDebug() << "GS232Controller::handleMessage: No match " << msg.getPipeSource() << " " << m_selectedPipe;
}
return true;
}
else
@ -128,6 +162,23 @@ bool GS232Controller::handleMessage(const Message& cmd)
}
}
void GS232Controller::updatePipes()
{
QList<AvailablePipeSource> availablePipes = updateAvailablePipeSources("target", GS232ControllerSettings::m_pipeTypes, GS232ControllerSettings::m_pipeURIs, this);
if (availablePipes != m_availablePipes)
{
m_availablePipes = availablePipes;
if (getMessageQueueToGUI())
{
MsgReportPipes *msgToGUI = MsgReportPipes::create();
QList<AvailablePipeSource>& msgAvailablePipes = msgToGUI->getAvailablePipes();
msgAvailablePipes.append(availablePipes);
getMessageQueueToGUI()->push(msgToGUI);
}
}
}
QByteArray GS232Controller::serialize() const
{
return m_settings.serialize();
@ -158,8 +209,7 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, boo
<< " m_serialPort: " << settings.m_serialPort
<< " m_baudRate: " << settings.m_baudRate
<< " m_track: " << settings.m_track
<< " m_deviceIndex: " << settings.m_deviceIndex
<< " m_channelIndex: " << settings.m_channelIndex
<< " m_target: " << settings.m_target
<< " m_title: " << settings.m_title
<< " m_rgbColor: " << settings.m_rgbColor
<< " m_useReverseAPI: " << settings.m_useReverseAPI
@ -186,11 +236,24 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, boo
if ((m_settings.m_track != settings.m_track) || force) {
reverseAPIKeys.append("track");
}
if ((m_settings.m_deviceIndex != settings.m_deviceIndex) || force) {
reverseAPIKeys.append("deviceIndex");
if ((m_settings.m_target != settings.m_target)
|| (!settings.m_target.isEmpty() && (m_selectedPipe == nullptr)) // Change in available pipes
|| force)
{
if (!settings.m_target.isEmpty())
{
m_selectedPipe = getPipeEndPoint(settings.m_target, m_availablePipes);
if (m_selectedPipe == nullptr)
qDebug() << "GS232Controller::applySettings: No plugin corresponding to target " << settings.m_target;
}
reverseAPIKeys.append("target");
}
if ((m_settings.m_channelIndex != settings.m_channelIndex) || force) {
reverseAPIKeys.append("channelIndex");
if ((m_settings.m_azimuthOffset != settings.m_azimuthOffset) || force) {
reverseAPIKeys.append("azimuthOffset");
}
if ((m_settings.m_elevationOffset != settings.m_elevationOffset) || force) {
reverseAPIKeys.append("elevationOffset");
}
if ((m_settings.m_title != settings.m_title) || force) {
reverseAPIKeys.append("title");
@ -252,7 +315,6 @@ int GS232Controller::webapiSettingsPutPatch(
MsgConfigureGS232Controller *msg = MsgConfigureGS232Controller::create(settings, force);
m_inputMessageQueue.push(msg);
qDebug("GS232Controller::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureGS232Controller *msgToGUI = MsgConfigureGS232Controller::create(settings, force);
@ -273,8 +335,8 @@ void GS232Controller::webapiFormatFeatureSettings(
response.getGs232ControllerSettings()->setSerialPort(new QString(settings.m_serialPort));
response.getGs232ControllerSettings()->setBaudRate(settings.m_baudRate);
response.getGs232ControllerSettings()->setTrack(settings.m_track);
response.getGs232ControllerSettings()->setDeviceIndex(settings.m_deviceIndex);
response.getGs232ControllerSettings()->setChannelIndex(settings.m_channelIndex);
response.getGs232ControllerSettings()->setAzimuthOffset(settings.m_azimuthOffset);
response.getGs232ControllerSettings()->setElevationOffset(settings.m_elevationOffset);
if (response.getGs232ControllerSettings()->getTitle()) {
*response.getGs232ControllerSettings()->getTitle() = settings.m_title;
@ -292,8 +354,6 @@ void GS232Controller::webapiFormatFeatureSettings(
}
response.getGs232ControllerSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getGs232ControllerSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIFeatureSetIndex);
response.getGs232ControllerSettings()->setReverseApiChannelIndex(settings.m_reverseAPIFeatureIndex);
}
void GS232Controller::webapiUpdateFeatureSettings(
@ -316,11 +376,14 @@ void GS232Controller::webapiUpdateFeatureSettings(
if (featureSettingsKeys.contains("track")) {
settings.m_track = response.getGs232ControllerSettings()->getTrack() != 0;
}
if (featureSettingsKeys.contains("deviceIndex")) {
settings.m_deviceIndex = response.getGs232ControllerSettings()->getDeviceIndex();
if (featureSettingsKeys.contains("target")) {
settings.m_target = *response.getGs232ControllerSettings()->getTarget();
}
if (featureSettingsKeys.contains("channelIndex")) {
settings.m_channelIndex = response.getGs232ControllerSettings()->getChannelIndex();
if (featureSettingsKeys.contains("azimuthOffset")) {
settings.m_azimuthOffset = response.getGs232ControllerSettings()->getAzimuthOffset();
}
if (featureSettingsKeys.contains("elevationOffset")) {
settings.m_elevationOffset = response.getGs232ControllerSettings()->getElevationOffset();
}
if (featureSettingsKeys.contains("title")) {
settings.m_title = *response.getGs232ControllerSettings()->getTitle();
@ -337,12 +400,6 @@ void GS232Controller::webapiUpdateFeatureSettings(
if (featureSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getGs232ControllerSettings()->getReverseApiPort();
}
if (featureSettingsKeys.contains("reverseAPIDeviceIndex")) {
settings.m_reverseAPIFeatureSetIndex = response.getGs232ControllerSettings()->getReverseApiDeviceIndex();
}
if (featureSettingsKeys.contains("reverseAPIChannelIndex")) {
settings.m_reverseAPIFeatureIndex = response.getGs232ControllerSettings()->getReverseApiChannelIndex();
}
}
void GS232Controller::webapiReverseSendSettings(QList<QString>& featureSettingsKeys, const GS232ControllerSettings& settings, bool force)
@ -371,11 +428,14 @@ void GS232Controller::webapiReverseSendSettings(QList<QString>& featureSettingsK
if (featureSettingsKeys.contains("track") || force) {
swgGS232ControllerSettings->setTrack(settings.m_track);
}
if (featureSettingsKeys.contains("deviceIndex") || force) {
swgGS232ControllerSettings->setDeviceIndex(settings.m_deviceIndex);
if (featureSettingsKeys.contains("target") || force) {
swgGS232ControllerSettings->setTarget(new QString(settings.m_target));
}
if (featureSettingsKeys.contains("channelIndex") || force) {
swgGS232ControllerSettings->setChannelIndex(settings.m_channelIndex);
if (featureSettingsKeys.contains("azimuthOffset") || force) {
swgGS232ControllerSettings->setAzimuthOffset(settings.m_azimuthOffset);
}
if (featureSettingsKeys.contains("elevationOffset") || force) {
swgGS232ControllerSettings->setElevationOffset(settings.m_elevationOffset);
}
if (featureSettingsKeys.contains("title") || force) {
swgGS232ControllerSettings->setTitle(new QString(settings.m_title));

View File

@ -21,6 +21,7 @@
#include <QThread>
#include <QNetworkRequest>
#include <QTimer>
#include "feature/feature.h"
#include "util/message.h"
@ -81,6 +82,25 @@ public:
{ }
};
class MsgReportWorker : public Message {
MESSAGE_CLASS_DECLARATION
public:
QString getMessage() { return m_message; }
static MsgReportWorker* create(QString message) {
return new MsgReportWorker(message);
}
private:
QString m_message;
MsgReportWorker(QString message) :
Message(),
m_message(message)
{}
};
GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface);
virtual ~GS232Controller();
virtual void destroy() { delete this; }
@ -122,7 +142,10 @@ private:
QThread m_thread;
GS232ControllerWorker *m_worker;
GS232ControllerSettings m_settings;
bool m_ptt;
//QHash<PipeEndPoint*, AvailablePipeSource> m_availablePipes;
QList<AvailablePipeSource> m_availablePipes;
PipeEndPoint *m_selectedPipe;
QTimer m_updatePipesTimer;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
@ -133,7 +156,9 @@ private:
void webapiReverseSendSettings(QList<QString>& featureSettingsKeys, const GS232ControllerSettings& settings, bool force);
private slots:
void updatePipes();
void networkManagerFinished(QNetworkReply *reply);
//void handlePipeMessageQueue(MessageQueue* messageQueue);
};
#endif // INCLUDE_FEATURE_GS232CONTROLLER_H_

View File

@ -21,6 +21,8 @@
#include <QLineEdit>
#include <QSerialPortInfo>
#include "SWGTargetAzimuthElevation.h"
#include "feature/featureuiset.h"
#include "gui/basicfeaturesettingsdialog.h"
#include "mainwindow.h"
@ -51,7 +53,6 @@ void GS232ControllerGUI::resetToDefaults()
QByteArray GS232ControllerGUI::serialize() const
{
qDebug("GS232ControllerGUI::serialize: %d", m_settings.m_channelIndex);
return m_settings.serialize();
}
@ -59,8 +60,6 @@ bool GS232ControllerGUI::deserialize(const QByteArray& data)
{
if (m_settings.deserialize(data))
{
qDebug("GS232ControllerGUI::deserialize: %d", m_settings.m_channelIndex);
updateDeviceSetList();
displaySettings();
applySettings(true);
return true;
@ -85,30 +84,28 @@ bool GS232ControllerGUI::handleMessage(const Message& message)
return true;
}
else if (GS232ControllerSettings::MsgChannelIndexChange::match(message))
else if (PipeEndPoint::MsgReportPipes::match(message))
{
const GS232ControllerSettings::MsgChannelIndexChange& cfg = (GS232ControllerSettings::MsgChannelIndexChange&) message;
int newChannelIndex = cfg.getIndex();
qDebug("GS232ControllerGUI::handleMessage: GS232ControllerSettings::MsgChannelIndexChange: %d", newChannelIndex);
ui->channel->blockSignals(true);
ui->channel->setCurrentIndex(newChannelIndex);
m_settings.m_channelIndex = newChannelIndex;
ui->channel->blockSignals(false);
PipeEndPoint::MsgReportPipes& report = (PipeEndPoint::MsgReportPipes&) message;
m_availablePipes = report.getAvailablePipes();
updatePipeList();
return true;
} else if (GS232ControllerReport::MsgReportAzAl::match(message))
}
else if (GS232ControllerReport::MsgReportAzAl::match(message))
{
GS232ControllerReport::MsgReportAzAl& azAl = (GS232ControllerReport::MsgReportAzAl&) message;
if (azAl.getType() == GS232ControllerReport::AzAlType::TARGET)
{
ui->azimuth->setValue(round(azAl.getAzimuth()));
ui->elevation->setValue(round(azAl.getElevation()));
}
else
{
ui->azimuthCurrentText->setText(QString("%1").arg(round(azAl.getAzimuth())));
ui->elevationCurrentText->setText(QString("%1").arg(round(azAl.getElevation())));
}
ui->azimuthCurrentText->setText(QString("%1").arg(round(azAl.getAzimuth())));
ui->elevationCurrentText->setText(QString("%1").arg(round(azAl.getElevation())));
return true;
}
else if (MainCore::MsgTargetAzimuthElevation::match(message))
{
MainCore::MsgTargetAzimuthElevation& msg = (MainCore::MsgTargetAzimuthElevation&) message;
SWGSDRangel::SWGTargetAzimuthElevation *swgTarget = msg.getSWGTargetAzimuthElevation();
ui->azimuth->setValue(round(swgTarget->getAzimuth()));
ui->elevation->setValue(round(swgTarget->getElevation()));
ui->targetName->setText(*swgTarget->getName());
return true;
}
@ -157,7 +154,6 @@ GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featu
m_statusTimer.start(1000);
updateSerialPortList();
updateDeviceSetList();
displaySettings();
applySettings(true);
}
@ -183,6 +179,9 @@ void GS232ControllerGUI::displaySettings()
ui->serialPort->lineEdit()->setText(m_settings.m_serialPort);
ui->baudRate->setCurrentText(QString("%1").arg(m_settings.m_baudRate));
ui->track->setChecked(m_settings.m_track);
ui->targets->setCurrentIndex(ui->targets->findText(m_settings.m_target));
ui->azimuthOffset->setValue(m_settings.m_azimuthOffset);
ui->elevationOffset->setValue(m_settings.m_elevationOffset);
blockApplySettings(false);
}
@ -198,102 +197,34 @@ void GS232ControllerGUI::updateSerialPortList()
}
}
void GS232ControllerGUI::updateDeviceSetList()
void GS232ControllerGUI::updatePipeList()
{
MainWindow *mainWindow = MainWindow::getInstance();
std::vector<DeviceUISet*>& deviceUISets = mainWindow->getDeviceUISets();
std::vector<DeviceUISet*>::const_iterator it = deviceUISets.begin();
QString currentText = ui->targets->currentText();
ui->targets->blockSignals(true);
ui->targets->clear();
QList<PipeEndPoint::AvailablePipeSource>::const_iterator it = m_availablePipes.begin();
ui->device->blockSignals(true);
ui->device->clear();
unsigned int deviceIndex = 0;
for (; it != deviceUISets.end(); ++it, deviceIndex++)
for (int i = 0; it != m_availablePipes.end(); ++it, i++)
{
DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine;
if (deviceSourceEngine) {
ui->device->addItem(QString("R%1").arg(deviceIndex), deviceIndex);
}
ui->targets->addItem(it->getName());
}
int newDeviceIndex;
if (it != deviceUISets.begin())
if (currentText.isEmpty())
{
if (m_settings.m_deviceIndex < 0) {
ui->device->setCurrentIndex(0);
} else {
ui->device->setCurrentIndex(m_settings.m_deviceIndex);
}
newDeviceIndex = ui->device->currentData().toInt();
if (m_availablePipes.size() > 0)
ui->targets->setCurrentIndex(0);
}
else
ui->targets->setCurrentIndex(ui->targets->findText(currentText));
ui->targets->blockSignals(false);
QString newText = ui->targets->currentText();
if (currentText != newText)
{
newDeviceIndex = -1;
m_settings.m_target = newText;
ui->targetName->setText("");
applySettings();
}
if (newDeviceIndex != m_settings.m_deviceIndex)
{
qDebug("GS232ControllerGUI::updateDeviceSetLists: device index changed: %d", newDeviceIndex);
m_settings.m_deviceIndex = newDeviceIndex;
}
updateChannelList();
ui->device->blockSignals(false);
}
bool GS232ControllerGUI::updateChannelList()
{
int newChannelIndex;
ui->channel->blockSignals(true);
ui->channel->clear();
if (m_settings.m_deviceIndex < 0)
{
newChannelIndex = -1;
}
else
{
MainWindow *mainWindow = MainWindow::getInstance();
std::vector<DeviceUISet*>& deviceUISets = mainWindow->getDeviceUISets();
DeviceUISet *deviceUISet = deviceUISets[m_settings.m_deviceIndex];
int nbChannels = deviceUISet->getNumberOfChannels();
for (int ch = 0; ch < nbChannels; ch++) {
ui->channel->addItem(QString("%1").arg(ch), ch);
}
if (nbChannels > 0)
{
if (m_settings.m_channelIndex < 0) {
ui->channel->setCurrentIndex(0);
} else {
ui->channel->setCurrentIndex(m_settings.m_channelIndex);
}
newChannelIndex = ui->channel->currentIndex();
}
else
{
newChannelIndex = -1;
}
}
ui->channel->blockSignals(false);
if (newChannelIndex != m_settings.m_channelIndex)
{
qDebug("GS232ControllerGUI::updateChannelList: channel index changed: %d", newChannelIndex);
m_settings.m_channelIndex = newChannelIndex;
return true;
}
return false;
}
void GS232ControllerGUI::leaveEvent(QEvent*)
@ -346,32 +277,6 @@ void GS232ControllerGUI::on_startStop_toggled(bool checked)
}
}
void GS232ControllerGUI::on_devicesRefresh_clicked()
{
updateDeviceSetList();
displaySettings();
applySettings();
}
void GS232ControllerGUI::on_device_currentIndexChanged(int index)
{
if (index >= 0)
{
m_settings.m_deviceIndex = ui->device->currentData().toInt();
updateChannelList();
applySettings();
}
}
void GS232ControllerGUI::on_channel_currentIndexChanged(int index)
{
if (index >= 0)
{
m_settings.m_channelIndex = index;
applySettings();
}
}
void GS232ControllerGUI::on_serialPort_currentIndexChanged(int index)
{
(void) index;
@ -389,23 +294,43 @@ void GS232ControllerGUI::on_baudRate_currentIndexChanged(int index)
void GS232ControllerGUI::on_azimuth_valueChanged(int value)
{
m_settings.m_azimuth = value;
ui->targetName->setText("");
applySettings();
}
void GS232ControllerGUI::on_elevation_valueChanged(int value)
{
m_settings.m_elevation = value;
ui->targetName->setText("");
applySettings();
}
void GS232ControllerGUI::on_azimuthOffset_valueChanged(int value)
{
m_settings.m_azimuthOffset = value;
applySettings();
}
void GS232ControllerGUI::on_elevationOffset_valueChanged(int value)
{
m_settings.m_elevationOffset = value;
applySettings();
}
void GS232ControllerGUI::on_track_stateChanged(int state)
{
m_settings.m_track = state == Qt::Checked;
ui->devicesRefresh->setEnabled(m_settings.m_track);
ui->deviceLabel->setEnabled(m_settings.m_track);
ui->device->setEnabled(m_settings.m_track);
ui->channelLabel->setEnabled(m_settings.m_track);
ui->channel->setEnabled(m_settings.m_track);
ui->targetsLabel->setEnabled(m_settings.m_track);
ui->targets->setEnabled(m_settings.m_track);
if (!m_settings.m_track)
ui->targetName->setText("");
applySettings();
}
void GS232ControllerGUI::on_targets_currentTextChanged(const QString& text)
{
m_settings.m_target = text;
ui->targetName->setText("");
applySettings();
}
@ -415,15 +340,23 @@ void GS232ControllerGUI::updateStatus()
if (m_lastFeatureState != state)
{
// We set checked state of start/stop button, in case it was changed via API
bool oldState;
switch (state)
{
case Feature::StNotStarted:
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
break;
case Feature::StIdle:
oldState = ui->startStop->blockSignals(true);
ui->startStop->setChecked(false);
ui->startStop->blockSignals(oldState);
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
break;
case Feature::StRunning:
oldState = ui->startStop->blockSignals(true);
ui->startStop->setChecked(true);
ui->startStop->blockSignals(oldState);
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
break;
case Feature::StError:

View File

@ -23,6 +23,7 @@
#include "feature/featuregui.h"
#include "util/messagequeue.h"
#include "pipes/pipeendpoint.h"
#include "gs232controllersettings.h"
class PluginAPI;
@ -50,6 +51,7 @@ private:
FeatureUISet* m_featureUISet;
GS232ControllerSettings m_settings;
bool m_doApplySettings;
QList<PipeEndPoint::AvailablePipeSource> m_availablePipes;
GS232Controller* m_gs232Controller;
MessageQueue m_inputMessageQueue;
@ -62,9 +64,8 @@ private:
void blockApplySettings(bool block);
void applySettings(bool force = false);
void displaySettings();
void updatePipeList();
void updateSerialPortList();
void updateDeviceSetList();
bool updateChannelList(); //!< true if channel index has changed
bool handleMessage(const Message& message);
void leaveEvent(QEvent*);
@ -75,14 +76,14 @@ private slots:
void onWidgetRolled(QWidget* widget, bool rollDown);
void handleInputMessages();
void on_startStop_toggled(bool checked);
void on_devicesRefresh_clicked();
void on_device_currentIndexChanged(int index);
void on_channel_currentIndexChanged(int index);
void on_serialPort_currentIndexChanged(int index);
void on_baudRate_currentIndexChanged(int index);
void on_track_stateChanged(int state);
void on_azimuth_valueChanged(int value);
void on_elevation_valueChanged(int value);
void on_targets_currentTextChanged(const QString& text);
void on_azimuthOffset_valueChanged(int value);
void on_elevationOffset_valueChanged(int value);
void updateStatus();
};

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>320</width>
<height>187</height>
<height>175</height>
</rect>
</property>
<property name="sizePolicy">
@ -24,7 +24,7 @@
</property>
<property name="maximumSize">
<size>
<width>320</width>
<width>350</width>
<height>16777215</height>
</size>
</property>
@ -43,7 +43,7 @@
<x>10</x>
<y>10</y>
<width>301</width>
<height>171</height>
<height>161</height>
</rect>
</property>
<property name="windowTitle">
@ -179,6 +179,74 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="localDeviceLayout">
<item>
<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>
<widget class="QLabel" name="targetsLabel">
<property name="text">
<string>Source</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="targets">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Target to track</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="channelLayout">
<item>
<widget class="QLabel" name="targetNameLabel">
<property name="text">
<string>Target</string>
</property>
</widget>
</item>
<item>
<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>
<item>
<layout class="QHBoxLayout" name="serverLayout">
<item>
@ -271,107 +339,50 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="localDeviceLayout">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="track">
<property name="toolTip">
<string>Check to enable automatic tracking of azimuth and elevation from the specified channel</string>
</property>
<widget class="QLabel" name="azimuthOffsetLabel">
<property name="text">
<string>Track</string>
<string>Azimuth offset</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="devicesRefresh">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<widget class="QSpinBox" name="azimuthOffset">
<property name="toolTip">
<string>Refresh indexes of available device sets</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/>
<property name="minimum">
<number>-360</number>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
<property name="maximum">
<number>360</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="deviceLabel">
<widget class="QLabel" name="elevationOffsetLabel">
<property name="text">
<string>Device</string>
<string>Elevation offset</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="device">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<widget class="QSpinBox" name="elevationOffset">
<property name="toolTip">
<string>Receiver deviceset index</string>
<string>Specify an offset angle in degrees that will be added to the target elevation to correct for misalignment</string>
</property>
<property name="minimum">
<number>-180</number>
</property>
<property name="maximum">
<number>180</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelLabel">
<property name="text">
<string>Channel</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="channel">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel index</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="channelLayout">
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
@ -390,6 +401,18 @@
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>startStop</tabstop>
<tabstop>azimuth</tabstop>
<tabstop>elevation</tabstop>
<tabstop>track</tabstop>
<tabstop>targets</tabstop>
<tabstop>targetName</tabstop>
<tabstop>serialPort</tabstop>
<tabstop>baudRate</tabstop>
<tabstop>azimuthOffset</tabstop>
<tabstop>elevationOffset</tabstop>
</tabstops>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>

View File

@ -27,7 +27,6 @@ class GS232ControllerReport : public QObject
{
Q_OBJECT
public:
enum AzAlType {TARGET, ACTUAL};
class MsgReportAzAl : public Message {
MESSAGE_CLASS_DECLARATION
@ -35,23 +34,20 @@ public:
public:
float getAzimuth() const { return m_azimuth; }
float getElevation() const { return m_elevation; }
AzAlType getType() const { return m_type; }
static MsgReportAzAl* create(float azimuth, float elevation, AzAlType type)
static MsgReportAzAl* create(float azimuth, float elevation)
{
return new MsgReportAzAl(azimuth, elevation, type);
return new MsgReportAzAl(azimuth, elevation);
}
private:
float m_azimuth;
float m_elevation;
AzAlType m_type;
MsgReportAzAl(float azimuth, float elevation, AzAlType type) :
MsgReportAzAl(float azimuth, float elevation) :
Message(),
m_azimuth(azimuth),
m_elevation(elevation),
m_type(type)
m_elevation(elevation)
{
}
};

View File

@ -23,7 +23,15 @@
#include "gs232controllersettings.h"
MESSAGE_CLASS_DEFINITION(GS232ControllerSettings::MsgChannelIndexChange, Message)
const QStringList GS232ControllerSettings::m_pipeTypes = {
QStringLiteral("ADSBDemod"),
QStringLiteral("StarTracker")
};
const QStringList GS232ControllerSettings::m_pipeURIs = {
QStringLiteral("sdrangel.channel.adsbdemod"),
QStringLiteral("sdrangel.feature.startracker")
};
GS232ControllerSettings::GS232ControllerSettings()
{
@ -37,8 +45,7 @@ void GS232ControllerSettings::resetToDefaults()
m_serialPort = "";
m_baudRate = 9600;
m_track = false;
m_deviceIndex = -1;
m_channelIndex = -1;
m_target = "";
m_title = "GS-232 Rotator Controller";
m_rgbColor = QColor(225, 25, 99).rgb();
m_useReverseAPI = false;
@ -46,6 +53,8 @@ void GS232ControllerSettings::resetToDefaults()
m_reverseAPIPort = 8888;
m_reverseAPIFeatureSetIndex = 0;
m_reverseAPIFeatureIndex = 0;
m_azimuthOffset = 0;
m_elevationOffset = 0;
}
QByteArray GS232ControllerSettings::serialize() const
@ -57,8 +66,7 @@ QByteArray GS232ControllerSettings::serialize() const
s.writeString(3, m_serialPort);
s.writeS32(4, m_baudRate);
s.writeBool(5, m_track);
s.writeS32(6, m_deviceIndex);
s.writeS32(7, m_channelIndex);
s.writeString(6, m_target);
s.writeString(8, m_title);
s.writeU32(9, m_rgbColor);
s.writeBool(10, m_useReverseAPI);
@ -66,6 +74,8 @@ QByteArray GS232ControllerSettings::serialize() const
s.writeU32(12, m_reverseAPIPort);
s.writeU32(13, m_reverseAPIFeatureSetIndex);
s.writeU32(14, m_reverseAPIFeatureIndex);
s.writeS32(15, m_azimuthOffset);
s.writeS32(16, m_elevationOffset);
return s.final();
}
@ -91,8 +101,7 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data)
d.readString(3, &m_serialPort, "");
d.readS32(4, &m_baudRate, 9600);
d.readBool(5, &m_track, false);
d.readS32(6, &m_deviceIndex, -1);
d.readS32(7, &m_channelIndex, -1);
d.readString(6, &m_target, "");
d.readString(8, &m_title, "GS-232 Rotator Controller");
d.readU32(9, &m_rgbColor, QColor(225, 25, 99).rgb());
d.readBool(10, &m_useReverseAPI, false);
@ -109,6 +118,8 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data)
m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp;
d.readU32(14, &utmp, 0);
m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
d.readS32(15, &m_azimuthOffset, 0);
d.readS32(16, &m_elevationOffset, 0);
return true;
}

View File

@ -25,35 +25,18 @@
#include "util/message.h"
class Serializable;
class PipeEndPoint;
struct GS232ControllerSettings
{
class MsgChannelIndexChange : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getIndex() const { return m_index; }
static MsgChannelIndexChange* create(int index) {
return new MsgChannelIndexChange(index);
}
protected:
int m_index;
MsgChannelIndexChange(int index) :
Message(),
m_index(index)
{ }
};
int m_azimuth;
int m_elevation;
QString m_serialPort;
int m_baudRate;
int m_deviceIndex;
bool m_track;
int m_channelIndex;
QString m_target; // Plugin to get az/el from. E.g: "R0:0 ADSBDemod". Use a string, so can be set via WebAPI
int m_azimuthOffset;
int m_elevationOffset;
QString m_title;
quint32 m_rgbColor;
bool m_useReverseAPI;
@ -66,6 +49,9 @@ struct GS232ControllerSettings
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
static const QStringList m_pipeTypes;
static const QStringList m_pipeURIs;
};
#endif // INCLUDE_FEATURE_GS232CONTROLLERSETTINGS_H_

View File

@ -24,25 +24,14 @@
#include <QSerialPort>
#include <QRegularExpression>
#include "SWGDeviceState.h"
#include "SWGSuccessResponse.h"
#include "SWGErrorResponse.h"
#include "SWGDeviceSettings.h"
#include "SWGChannelSettings.h"
#include "SWGDeviceSet.h"
#include "SWGChannelReport.h"
#include "webapi/webapiadapterinterface.h"
#include "webapi/webapiutils.h"
#include "gs232controller.h"
#include "gs232controllerworker.h"
#include "gs232controllerreport.h"
MESSAGE_CLASS_DEFINITION(GS232ControllerWorker::MsgConfigureGS232ControllerWorker, Message)
MESSAGE_CLASS_DEFINITION(GS232ControllerReport::MsgReportAzAl, Message)
GS232ControllerWorker::GS232ControllerWorker(WebAPIAdapterInterface *webAPIAdapterInterface) :
m_webAPIAdapterInterface(webAPIAdapterInterface),
GS232ControllerWorker::GS232ControllerWorker() :
m_msgQueueToFeature(nullptr),
m_msgQueueToGUI(nullptr),
m_running(false),
@ -113,10 +102,10 @@ void GS232ControllerWorker::applySettings(const GS232ControllerSettings& setting
qDebug() << "GS232ControllerWorker::applySettings:"
<< " m_azimuth: " << settings.m_azimuth
<< " m_elevation: " << settings.m_elevation
<< " m_azimuthOffset: " << settings.m_azimuthOffset
<< " m_elevationOffset: " << settings.m_elevationOffset
<< " m_serialPort: " << settings.m_serialPort
<< " m_baudRate: " << settings.m_baudRate
<< " m_deviceIndex: " << settings.m_deviceIndex
<< " m_channelIndex: " << settings.m_channelIndex
<< " force: " << force;
if ((settings.m_serialPort != m_settings.m_serialPort) || force)
@ -126,34 +115,57 @@ void GS232ControllerWorker::applySettings(const GS232ControllerSettings& setting
m_serialPort.setPortName(settings.m_serialPort);
m_serialPort.setBaudRate(settings.m_baudRate);
if (!m_serialPort.open(QIODevice::ReadWrite))
{
qCritical() << "GS232ControllerWorker::applySettings: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error();
if (m_msgQueueToFeature)
m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Failed to open serial port %1: %2").arg(settings.m_serialPort).arg(m_serialPort.error())));
}
}
else if ((settings.m_baudRate != m_settings.m_baudRate) || force)
{
m_serialPort.setBaudRate(settings.m_baudRate);
}
if ((settings.m_elevation != m_settings.m_elevation) || force)
if ((settings.m_elevation != m_settings.m_elevation)
|| (settings.m_elevationOffset != m_settings.m_elevationOffset)
|| force)
{
setAzimuthElevation(settings.m_azimuth, settings.m_elevation);
setAzimuthElevation(settings.m_azimuth, settings.m_elevation, settings.m_azimuthOffset, settings.m_elevationOffset);
}
else if ((settings.m_azimuth != m_settings.m_azimuth) || force)
else if ((settings.m_azimuth != m_settings.m_azimuth)
|| (settings.m_azimuthOffset != m_settings.m_azimuthOffset)
|| force)
{
setAzimuth(settings.m_azimuth);
setAzimuth(settings.m_azimuth, settings.m_azimuthOffset);
}
m_settings = settings;
}
void GS232ControllerWorker::setAzimuth(int azimuth)
void GS232ControllerWorker::setAzimuth(int azimuth, int azimuthOffset)
{
azimuth += azimuthOffset;
if (azimuth < 0)
azimuth = 0;
else if (azimuth > 450)
azimuth = 450;
QString cmd = QString("M%1\r\n").arg(azimuth, 3, 10, QLatin1Char('0'));
QByteArray data = cmd.toLatin1();
m_serialPort.write(data);
}
void GS232ControllerWorker::setAzimuthElevation(int azimuth, int elevation)
void GS232ControllerWorker::setAzimuthElevation(int azimuth, int elevation, int azimuthOffset, int elevationOffset)
{
azimuth += azimuthOffset;
if (azimuth < 0)
azimuth = 0;
else if (azimuth > 450)
azimuth = 450;
elevation += elevationOffset;
if (elevation < 0)
elevation = 0;
else if (elevation > 180)
elevation = 180;
QString cmd = QString("W%1 %2\r\n").arg(azimuth, 3, 10, QLatin1Char('0')).arg(elevation, 3, 10, QLatin1Char('0'));
QByteArray data = cmd.toLatin1();
m_serialPort.write(data);
@ -170,7 +182,6 @@ void GS232ControllerWorker::readSerialData()
if (len != -1)
{
QString response = QString::fromUtf8(buf, len);
QRegularExpression re("AZ=(\\d\\d\\d)EL=(\\d\\d\\d)");
QRegularExpressionMatch match = re.match(response);
if (match.hasMatch())
@ -179,15 +190,17 @@ void GS232ControllerWorker::readSerialData()
QString el = match.captured(2);
//qDebug() << "GS232ControllerWorker::readSerialData read az " << az << " el " << el;
if (getMessageQueueToGUI())
{
GS232ControllerReport::MsgReportAzAl *msg = GS232ControllerReport::MsgReportAzAl::create(
az.toFloat(), el.toFloat(), GS232ControllerReport::ACTUAL);
getMessageQueueToGUI()->push(msg);
}
getMessageQueueToGUI()->push( GS232ControllerReport::MsgReportAzAl::create(az.toFloat(), el.toFloat()));
}
else if (response == "\r\n")
{
// Ignore
}
else
{
qDebug() << "GS232ControllerWorker::readSerialData unknown response " << response;
qDebug() << "GS232ControllerWorker::readSerialData - unexpected response " << response;
if (m_msgQueueToFeature)
m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Unexpected GS-232 serial reponse: %1").arg(response)));
}
}
}
@ -201,48 +214,4 @@ void GS232ControllerWorker::update()
QByteArray cmd("C2\r\n");
m_serialPort.write(cmd);
}
// Request target Az/EL from channel
if (m_settings.m_track)
{
SWGSDRangel::SWGChannelReport response;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC = m_webAPIAdapterInterface->devicesetChannelReportGet(
m_settings.m_deviceIndex,
m_settings.m_channelIndex,
response,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("GS232ControllerWorker::update: get channel report error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
}
else
{
QJsonObject *jsonObj = response.asJsonObject();
double targetAzimuth;
double targetElevation;
bool gotElevation = false;
bool gotAzimuth = false;
if (WebAPIUtils::getSubObjectDouble(*jsonObj, "targetAzimuth", targetAzimuth))
gotAzimuth = true;
if (WebAPIUtils::getSubObjectDouble(*jsonObj, "targetElevation", targetElevation))
gotElevation = true;
if (gotAzimuth && gotElevation)
{
if (getMessageQueueToGUI())
{
GS232ControllerReport::MsgReportAzAl *msg = GS232ControllerReport::MsgReportAzAl::create(
targetAzimuth, targetElevation, GS232ControllerReport::TARGET);
getMessageQueueToGUI()->push(msg);
}
}
}
}
}

View File

@ -28,8 +28,6 @@
#include "gs232controllersettings.h"
class WebAPIAdapterInterface;
class GS232ControllerWorker : public QObject
{
Q_OBJECT
@ -57,7 +55,7 @@ public:
{ }
};
GS232ControllerWorker(WebAPIAdapterInterface *webAPIAdapterInterface);
GS232ControllerWorker();
~GS232ControllerWorker();
void reset();
bool startWork();
@ -69,7 +67,6 @@ public:
private:
WebAPIAdapterInterface *m_webAPIAdapterInterface;
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object
MessageQueue *m_msgQueueToGUI;
@ -82,8 +79,8 @@ private:
bool handleMessage(const Message& cmd);
void applySettings(const GS232ControllerSettings& settings, bool force = false);
MessageQueue *getMessageQueueToGUI() { return m_msgQueueToGUI; }
void setAzimuth(int azimuth);
void setAzimuthElevation(int azimuth, int elevation);
void setAzimuth(int azimuth, int azimuthOffset);
void setAzimuthElevation(int azimuth, int elevation, int azimuthOffset, int elevationOffset);
private slots:
void handleInputMessages();

View File

@ -4,11 +4,11 @@
The GS-232 Rotator Controller feature plugin allows SDRangel to send commands to GS-232 rotators. 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 ADS-B Demodulator, which can track a selected aircraft.
Azimuth and elevation can be set manually by a user in the GUI, via the REST API, or via another plugin, such as the ADS-B Demodulator, which can track a selected aircraft, or the Star Tracker, for radio astronomy or EME communication.
<h2>Interface</h2>
![File source channel plugin GUI](../../../doc/img/GS232Controller_plugin.png)
![GS232 Rotator Controller feature plugin GUI](../../../doc/img/GS232Controller_plugin.png)
<h3>1: Start/Stop plugin</h3>
@ -16,37 +16,50 @@ This button starts or stops the plugin. When the plugin is stopped, azimuth and
<h3>2: Azimuth</h3>
Specifies the target azimuth (angle in degrees, clockwise from North) to point the antenna towards. Valid values range from 0 to 450 degrees. The value to the right of the target azimuth, is the current azimuth read from the GS-232 rotator.
Specifies the target azimuth (angle in degrees, clockwise from North) to point the antenna towards. Valid values range from 0 to 450 degrees.
The value to the right of the target azimuth, is the current azimuth read from the GS-232 rotator.
<h3>3: Elevation</h3>
Specifies the target elevation (angle in degrees) to point the antenna towards. Valid values range from 0 to 180 degrees, where 0 and 180 point towards the horizon and 90 degrees to zenith. The value to the right of the target elevation, is the current elevation read from the GS-232 rotator.
Specifies the target elevation (angle in degrees) to point the antenna towards. Valid values range from 0 to 180 degrees, where 0 and 180 point towards the horizon and 90 degrees to zenith.
The value to the right of the target elevation, is the current elevation read from the GS-232 rotator.
<h3>4: Serial Port</h3>
<h3>4: Track</h3>
When checked, the target azimuth and elevation will be controlled by the Channel or Feature Source (5).
For example, this allows an aircraft to be tracked, by setting the Source to the ADS-B Demodulator plugin, or the Moon to be tracked by settng Source to the Star Tracker plugin.
<h3>5: Source</h3>
Specify the SDRangel Channel or Feature that that will control the target aziumth and elevation values, when Track (4) is checked.
<h3>6: Target</h3>
When tracking is enabled, this field will display a name for the target being tracked, as indicated by the selected Source plugin (5).
For example, the ADS-B plugin will display the flight number of the target aircraft. The Star Tracker plugin will display Sun, Moon or Star.
<h3>7: Serial Port</h3>
Specifies the serial port (E.g. COM3 on Windows or /dev/ttyS0 on Linux) that will be used to send commands to the GS-232 rotator.
<h3>5: Baud rate</h3>
<h3>8: Baud rate</h3>
Specifies the baud rate that will be used to send commands to the GS-232 rotator. Typically this is 9600.
<h3>6: Track</h3>
<h3>9: Azimuth Offset</h3>
When checked, the GS-232 Rotator Controller plugin will query the channel specified by the Device (8) and Channel (9) combo boxes for the target azimuth and elevation. For example, this allows an aircraft to be tracked, by setting the Device and Channel to correspond to the ADS-B Demodulator plugin.
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>7: Refresh list of devices and channels</h3>
<h3>10: Elevation Offset</h3>
Use this button to refresh the list of devices (8) and channels (9)
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>8: Select device set</h3>
<h2>API</h2>
Specify the SDRangel device set containing the channel plugin that will be asked for aziumth and elevation values. Defaults to R0.
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:
<h3>9: Select channel</h3>
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/settings" -d '{"featureType": "GS232Controller", "GS232ControllerSettings": { "azimuth": 180, "elevation": 45 }}'
The channel index specifies the SDRangel channel that will be asked for azimuth and elevation values. Defaults to 0.
To start sending commands to the rotator:
<h2>Developer Information</h2>
For a channel plugin to be able to set the azimuth and elevation, its channel report should contain targetAzimuth and targetElevation. See the ADS-B plugin as an example.
curl -X POST "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/run"