1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-26 17:58:43 -05:00

Add min and max limits for azimuth and elevation in GS-232 controller. Add satellite tracker support

This commit is contained in:
Jon Beniston 2021-02-26 20:27:35 +00:00
parent 5461facb3b
commit cd504da84e
9 changed files with 257 additions and 85 deletions

View File

@ -210,6 +210,12 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, boo
qDebug() << "GS232Controller::applySettings:"
<< " m_azimuth: " << settings.m_azimuth
<< " m_elevation: " << settings.m_elevation
<< " m_azimuthOffset: " << settings.m_azimuthOffset
<< " m_elevationOffset: " << settings.m_elevationOffset
<< " m_azimuthMin: " << settings.m_azimuthMin
<< " m_azimuthMax: " << settings.m_azimuthMax
<< " m_elevationMin: " << settings.m_elevationMin
<< " m_elevationMax: " << settings.m_elevationMax
<< " m_serialPort: " << settings.m_serialPort
<< " m_baudRate: " << settings.m_baudRate
<< " m_track: " << settings.m_track
@ -259,6 +265,15 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, boo
if ((m_settings.m_elevationOffset != settings.m_elevationOffset) || force) {
reverseAPIKeys.append("elevationOffset");
}
if ((m_settings.m_azimuthMin != settings.m_azimuthMin) || force) {
reverseAPIKeys.append("azimuthMin");
}
if ((m_settings.m_azimuthMax != settings.m_azimuthMax) || force) {
reverseAPIKeys.append("azimuthMax");
}
if ((m_settings.m_elevationMin != settings.m_elevationMin) || force) {
reverseAPIKeys.append("elevationMin");
}
if ((m_settings.m_title != settings.m_title) || force) {
reverseAPIKeys.append("title");
}
@ -341,6 +356,10 @@ void GS232Controller::webapiFormatFeatureSettings(
response.getGs232ControllerSettings()->setTrack(settings.m_track);
response.getGs232ControllerSettings()->setAzimuthOffset(settings.m_azimuthOffset);
response.getGs232ControllerSettings()->setElevationOffset(settings.m_elevationOffset);
response.getGs232ControllerSettings()->setAzimuthMin(settings.m_azimuthMin);
response.getGs232ControllerSettings()->setAzimuthMax(settings.m_azimuthMax);
response.getGs232ControllerSettings()->setElevationMin(settings.m_elevationMin);
response.getGs232ControllerSettings()->setElevationMax(settings.m_elevationMax);
if (response.getGs232ControllerSettings()->getTitle()) {
*response.getGs232ControllerSettings()->getTitle() = settings.m_title;
@ -389,6 +408,18 @@ void GS232Controller::webapiUpdateFeatureSettings(
if (featureSettingsKeys.contains("elevationOffset")) {
settings.m_elevationOffset = response.getGs232ControllerSettings()->getElevationOffset();
}
if (featureSettingsKeys.contains("azimuthMin")) {
settings.m_azimuthMin = response.getGs232ControllerSettings()->getAzimuthMin();
}
if (featureSettingsKeys.contains("azimuthMax")) {
settings.m_azimuthMax = response.getGs232ControllerSettings()->getAzimuthMax();
}
if (featureSettingsKeys.contains("elevationMin")) {
settings.m_elevationMin = response.getGs232ControllerSettings()->getElevationMin();
}
if (featureSettingsKeys.contains("elevationMax")) {
settings.m_elevationMax = response.getGs232ControllerSettings()->getElevationMax();
}
if (featureSettingsKeys.contains("title")) {
settings.m_title = *response.getGs232ControllerSettings()->getTitle();
}
@ -441,6 +472,18 @@ void GS232Controller::webapiReverseSendSettings(QList<QString>& featureSettingsK
if (featureSettingsKeys.contains("elevationOffset") || force) {
swgGS232ControllerSettings->setElevationOffset(settings.m_elevationOffset);
}
if (featureSettingsKeys.contains("azimuthMin") || force) {
swgGS232ControllerSettings->setAzimuthMin(settings.m_azimuthMin);
}
if (featureSettingsKeys.contains("azimuthMax") || force) {
swgGS232ControllerSettings->setAzimuthMax(settings.m_azimuthMax);
}
if (featureSettingsKeys.contains("elevationMin") || force) {
swgGS232ControllerSettings->setElevationMin(settings.m_elevationMin);
}
if (featureSettingsKeys.contains("elevationMax") || force) {
swgGS232ControllerSettings->setElevationMax(settings.m_elevationMax);
}
if (featureSettingsKeys.contains("title") || force) {
swgGS232ControllerSettings->setTitle(new QString(settings.m_title));
}

View File

@ -182,6 +182,10 @@ void GS232ControllerGUI::displaySettings()
ui->targets->setCurrentIndex(ui->targets->findText(m_settings.m_target));
ui->azimuthOffset->setValue(m_settings.m_azimuthOffset);
ui->elevationOffset->setValue(m_settings.m_elevationOffset);
ui->azimuthMin->setValue(m_settings.m_azimuthMin);
ui->azimuthMax->setValue(m_settings.m_azimuthMax);
ui->elevationMin->setValue(m_settings.m_elevationMin);
ui->elevationMax->setValue(m_settings.m_elevationMax);
blockApplySettings(false);
}
@ -317,6 +321,30 @@ void GS232ControllerGUI::on_elevationOffset_valueChanged(int value)
applySettings();
}
void GS232ControllerGUI::on_azimuthMin_valueChanged(int value)
{
m_settings.m_azimuthMin = value;
applySettings();
}
void GS232ControllerGUI::on_azimuthMax_valueChanged(int value)
{
m_settings.m_azimuthMax = value;
applySettings();
}
void GS232ControllerGUI::on_elevationMin_valueChanged(int value)
{
m_settings.m_elevationMin = value;
applySettings();
}
void GS232ControllerGUI::on_elevationMax_valueChanged(int value)
{
m_settings.m_elevationMax = value;
applySettings();
}
void GS232ControllerGUI::on_track_stateChanged(int state)
{
m_settings.m_track = state == Qt::Checked;

View File

@ -84,6 +84,10 @@ private slots:
void on_targets_currentTextChanged(const QString& text);
void on_azimuthOffset_valueChanged(int value);
void on_elevationOffset_valueChanged(int value);
void on_azimuthMin_valueChanged(int value);
void on_azimuthMax_valueChanged(int value);
void on_elevationMin_valueChanged(int value);
void on_elevationMax_valueChanged(int value);
void updateStatus();
};

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>175</height>
<width>350</width>
<height>223</height>
</rect>
</property>
<property name="sizePolicy">
@ -42,8 +42,8 @@
<rect>
<x>10</x>
<y>10</y>
<width>301</width>
<height>161</height>
<width>331</width>
<height>191</height>
</rect>
</property>
<property name="windowTitle">
@ -248,45 +248,50 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="serverLayout">
<item>
<widget class="QLabel" name="serialLabel">
<property name="text">
<string>Serial Port</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="serialPort">
<property name="toolTip">
<string>Name of serial port to use to connect to the GS-232 controller</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QLabel" name="baudRateLabel">
<property name="text">
<string>Baud rate</string>
</property>
</widget>
</item>
<item>
<item row="3" column="1">
<widget class="QSpinBox" name="elevationMin">
<property name="maximum">
<number>180</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="elevationMinLabel">
<property name="text">
<string>Elevation min</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="azimuthMinLabel">
<property name="text">
<string>Azimuth min</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="elevationMaxLabel">
<property name="text">
<string>Elevation max</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QSpinBox" name="elevationMax">
<property name="maximum">
<number>180</number>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QComboBox" name="baudRate">
<property name="toolTip">
<string>Serial port baud rate for the GS-232 controller</string>
@ -336,18 +341,52 @@
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<item row="2" column="3">
<widget class="QSpinBox" name="azimuthMax">
<property name="maximum">
<number>450</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="azimuthMin">
<property name="maximum">
<number>450</number>
</property>
</widget>
</item>
<item row="0" 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>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="serialLabel">
<property name="text">
<string>Serial Port</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="azimuthMaxLabel">
<property name="text">
<string>Azimuth max</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="azimuthOffsetLabel">
<property name="text">
<string>Azimuth offset</string>
</property>
</widget>
</item>
<item>
<item row="1" 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>
@ -360,14 +399,14 @@
</property>
</widget>
</item>
<item>
<item row="1" column="2">
<widget class="QLabel" name="elevationOffsetLabel">
<property name="text">
<string>Elevation offset</string>
</property>
</widget>
</item>
<item>
<item row="1" 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>
@ -412,6 +451,10 @@
<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"/>

View File

@ -26,13 +26,15 @@
const QStringList GS232ControllerSettings::m_pipeTypes = {
QStringLiteral("ADSBDemod"),
QStringLiteral("Map"),
QStringLiteral("StarTracker")
QStringLiteral("StarTracker"),
QStringLiteral("SatelliteTracker")
};
const QStringList GS232ControllerSettings::m_pipeURIs = {
QStringLiteral("sdrangel.channel.adsbdemod"),
QStringLiteral("sdrangel.feature.map"),
QStringLiteral("sdrangel.feature.startracker")
QStringLiteral("sdrangel.feature.startracker"),
QStringLiteral("sdrangel.feature.satellitetracker")
};
GS232ControllerSettings::GS232ControllerSettings()
@ -57,6 +59,10 @@ void GS232ControllerSettings::resetToDefaults()
m_reverseAPIFeatureIndex = 0;
m_azimuthOffset = 0;
m_elevationOffset = 0;
m_azimuthMin = 0;
m_azimuthMax = 450;
m_elevationMin = 0;
m_elevationMax = 180;
}
QByteArray GS232ControllerSettings::serialize() const
@ -78,6 +84,10 @@ QByteArray GS232ControllerSettings::serialize() const
s.writeU32(14, m_reverseAPIFeatureIndex);
s.writeS32(15, m_azimuthOffset);
s.writeS32(16, m_elevationOffset);
s.writeS32(17, m_azimuthMin);
s.writeS32(18, m_azimuthMax);
s.writeS32(19, m_elevationMin);
s.writeS32(20, m_elevationMax);
return s.final();
}
@ -122,6 +132,10 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data)
m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
d.readS32(15, &m_azimuthOffset, 0);
d.readS32(16, &m_elevationOffset, 0);
d.readS32(17, &m_azimuthMin, 0);
d.readS32(18, &m_azimuthMax, 450);
d.readS32(19, &m_elevationMin, 0);
d.readS32(20, &m_elevationMax, 180);
return true;
}

View File

@ -36,6 +36,10 @@ struct GS232ControllerSettings
QString m_target; // Plugin to get az/el from. E.g: "R0:0 ADSBDemod". Use a string, so can be set via WebAPI
int m_azimuthOffset;
int m_elevationOffset;
int m_azimuthMin;
int m_azimuthMax;
int m_elevationMin;
int m_elevationMax;
QString m_title;
quint32 m_rgbColor;
bool m_useReverseAPI;

View File

@ -16,6 +16,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include <QDebug>
#include <QTcpServer>
#include <QTcpSocket>
@ -35,7 +37,9 @@ GS232ControllerWorker::GS232ControllerWorker() :
m_msgQueueToFeature(nullptr),
m_msgQueueToGUI(nullptr),
m_running(false),
m_mutex(QMutex::Recursive)
m_mutex(QMutex::Recursive),
m_lastAzimuth(-1),
m_lastElevation(-1)
{
connect(&m_pollTimer, SIGNAL(timeout()), this, SLOT(update()));
m_pollTimer.start(1000);
@ -57,6 +61,7 @@ bool GS232ControllerWorker::startWork()
QMutexLocker mutexLocker(&m_mutex);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData);
openSerialPort(m_settings);
m_running = true;
return m_running;
}
@ -64,6 +69,9 @@ bool GS232ControllerWorker::startWork()
void GS232ControllerWorker::stopWork()
{
QMutexLocker mutexLocker(&m_mutex);
// Close serial port as USB/controller activity can create RFI
if (m_serialPort.isOpen())
m_serialPort.close();
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
disconnect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData);
m_running = false;
@ -104,71 +112,78 @@ void GS232ControllerWorker::applySettings(const GS232ControllerSettings& setting
<< " m_elevation: " << settings.m_elevation
<< " m_azimuthOffset: " << settings.m_azimuthOffset
<< " m_elevationOffset: " << settings.m_elevationOffset
<< " m_azimuthMin: " << settings.m_azimuthMin
<< " m_azimuthMax: " << settings.m_azimuthMax
<< " m_elevationMin: " << settings.m_elevationMin
<< " m_elevationMax: " << settings.m_elevationMax
<< " m_serialPort: " << settings.m_serialPort
<< " m_baudRate: " << settings.m_baudRate
<< " force: " << force;
if ((settings.m_serialPort != m_settings.m_serialPort) || force)
{
if (m_serialPort.isOpen())
m_serialPort.close();
m_serialPort.setPortName(settings.m_serialPort);
m_serialPort.setBaudRate(settings.m_baudRate);
if (!m_serialPort.open(QIODevice::ReadWrite))
{
qCritical() << "GS232ControllerWorker::applySettings: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error();
if (m_msgQueueToFeature)
m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Failed to open serial port %1: %2").arg(settings.m_serialPort).arg(m_serialPort.error())));
}
openSerialPort(settings);
}
else if ((settings.m_baudRate != m_settings.m_baudRate) || force)
{
m_serialPort.setBaudRate(settings.m_baudRate);
}
if ((settings.m_elevation != m_settings.m_elevation)
|| (settings.m_elevationOffset != m_settings.m_elevationOffset)
|| force)
// Apply offset then clamp
int azimuth = settings.m_azimuth;
azimuth += settings.m_azimuthOffset;
azimuth = std::max(azimuth, settings.m_azimuthMin);
azimuth = std::min(azimuth, settings.m_azimuthMax);
int elevation = settings.m_elevation;
elevation += settings.m_elevationOffset;
elevation = std::max(elevation, settings.m_elevationMin);
elevation = std::min(elevation, settings.m_elevationMax);
if (((elevation != m_lastElevation) || force) && (settings.m_elevationMax != 0))
{
setAzimuthElevation(settings.m_azimuth, settings.m_elevation, settings.m_azimuthOffset, settings.m_elevationOffset);
setAzimuthElevation(azimuth, elevation);
}
else if ((settings.m_azimuth != m_settings.m_azimuth)
|| (settings.m_azimuthOffset != m_settings.m_azimuthOffset)
|| force)
else if ((azimuth != m_lastAzimuth) || force)
{
setAzimuth(settings.m_azimuth, settings.m_azimuthOffset);
setAzimuth(azimuth);
}
m_settings = settings;
}
void GS232ControllerWorker::setAzimuth(int azimuth, int azimuthOffset)
void GS232ControllerWorker::openSerialPort(const GS232ControllerSettings& settings)
{
if (m_serialPort.isOpen())
m_serialPort.close();
m_serialPort.setPortName(settings.m_serialPort);
m_serialPort.setBaudRate(settings.m_baudRate);
if (!m_serialPort.open(QIODevice::ReadWrite))
{
qCritical() << "GS232ControllerWorker::openSerialPort: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error();
if (m_msgQueueToFeature)
m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Failed to open serial port %1: %2").arg(settings.m_serialPort).arg(m_serialPort.error())));
}
m_lastAzimuth = -1;
m_lastElevation = -1;
}
void GS232ControllerWorker::setAzimuth(int azimuth)
{
azimuth += azimuthOffset;
if (azimuth < 0)
azimuth = 0;
else if (azimuth > 450)
azimuth = 450;
QString cmd = QString("M%1\r\n").arg(azimuth, 3, 10, QLatin1Char('0'));
QByteArray data = cmd.toLatin1();
m_serialPort.write(data);
m_lastAzimuth = azimuth;
}
void GS232ControllerWorker::setAzimuthElevation(int azimuth, int elevation, int azimuthOffset, int elevationOffset)
void GS232ControllerWorker::setAzimuthElevation(int azimuth, int elevation)
{
azimuth += azimuthOffset;
if (azimuth < 0)
azimuth = 0;
else if (azimuth > 450)
azimuth = 450;
elevation += elevationOffset;
if (elevation < 0)
elevation = 0;
else if (elevation > 180)
elevation = 180;
QString cmd = QString("W%1 %2\r\n").arg(azimuth, 3, 10, QLatin1Char('0')).arg(elevation, 3, 10, QLatin1Char('0'));
QByteArray data = cmd.toLatin1();
m_serialPort.write(data);
m_lastAzimuth = azimuth;
m_lastElevation = elevation;
}
void GS232ControllerWorker::readSerialData()

View File

@ -76,11 +76,15 @@ private:
QSerialPort m_serialPort;
QTimer m_pollTimer;
int m_lastAzimuth;
int m_lastElevation;
bool handleMessage(const Message& cmd);
void applySettings(const GS232ControllerSettings& settings, bool force = false);
MessageQueue *getMessageQueueToGUI() { return m_msgQueueToGUI; }
void setAzimuth(int azimuth, int azimuthOffset);
void setAzimuthElevation(int azimuth, int elevation, int azimuthOffset, int elevationOffset);
void openSerialPort(const GS232ControllerSettings& settings);
void setAzimuth(int azimuth);
void setAzimuthElevation(int azimuth, int elevation);
private slots:
void handleInputMessages();

View File

@ -54,6 +54,23 @@ The azimuth offset specifies an angle in degrees that is added to the target azi
The elevation offset specifies an angle in degrees that is added to the target elevation before sending to the controller. This allows for a misalignment of the rotator to be corrected.
<h3>11 and 12: 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>13 and 14: 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.
<h2>GS-232 Protocol Implementation</h2>
The controller uses the Waaa eee command when elevation needs to be set.
When only azimuth needs to be set, the Maaa command is used.
The C2 command is used to read current azimuth and elevation. A response of AZ=aaaEL=eee is expected.
<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: