[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kstars/filtermanager] kstars: Filter Manager ready for test. It controls all aspects of filter chan
From: Jasem Mutlaq <null () kde ! org>
Date: 2017-09-30 19:55:52
Message-ID: E1dyNrc-0002Vj-Vv () code ! kde ! org
[Download RAW message or body]
Git commit 0125213e0465b1c0aa8b8ee7b46795e143c5d6ca by Jasem Mutlaq.
Committed on 30/09/2017 at 19:55.
Pushed by mutlaqja into branch 'filtermanager'.
Filter Manager ready for test. It controls all aspects of filter changes including \
offset management, locked filter, and autofocus
M +1 -0 kstars/CMakeLists.txt
M +506 -63 kstars/ekos/auxiliary/filtermanager.cpp
M +124 -30 kstars/ekos/auxiliary/filtermanager.h
M +25 -9 kstars/ekos/auxiliary/filtersettings.ui
M +27 -36 kstars/ekos/ekosmanager.cpp
M +1 -1 kstars/ekos/ekosmanager.h
https://commits.kde.org/kstars/0125213e0465b1c0aa8b8ee7b46795e143c5d6ca
diff --git a/kstars/CMakeLists.txt b/kstars/CMakeLists.txt
index 1314bde77..81daab106 100644
--- a/kstars/CMakeLists.txt
+++ b/kstars/CMakeLists.txt
@@ -183,6 +183,7 @@ if (INDI_FOUND)
ekos/auxiliary/dustcap.cpp
ekos/auxiliary/darklibrary.cpp
ekos/auxiliary/filtermanager.cpp
+ ekos/auxiliary/filterdelegate.cpp
# Capture
ekos/capture/capture.cpp
diff --git a/kstars/ekos/auxiliary/filtermanager.cpp \
b/kstars/ekos/auxiliary/filtermanager.cpp index 39a408c61..5946252ff 100644
--- a/kstars/ekos/auxiliary/filtermanager.cpp
+++ b/kstars/ekos/auxiliary/filtermanager.cpp
@@ -11,111 +11,192 @@
#include <QSqlTableModel>
#include <QSqlDatabase>
+#include <QSqlRecord>
+#include <algorithm>
#include <basedevice.h>
#include "kstarsdata.h"
#include "kstars.h"
#include "auxiliary/kspaths.h"
+#include "ekos/auxiliary/filterdelegate.h"
#include "indi_debug.h"
#include "Options.h"
+namespace Ekos
+{
+
FilterManager::FilterManager() : QDialog(KStars::Instance())
{
setupUi(this);
- refreshFilterData();
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(close()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
}
-void FilterManager::refreshFilterData()
+
+void FilterManager::refreshFilterModel()
{
if (m_currentFilterDevice == nullptr)
return;
+ QString vendor(m_currentFilterDevice->getDeviceName());
+
delete (filterModel);
+
filterModel = new QSqlTableModel(this, \
KStarsData::Instance()->userdb()->GetDatabase()); filterModel->setTable("filter");
+ filterModel->setFilter(QString("vendor='%1'").arg(vendor));
filterModel->select();
+ filterModel->setEditStrategy(QSqlTableModel::OnFieldChange);
+
+ // If it is first time, let's populate data
+ if (filterModel->rowCount() == 0)
+ {
+ for (QString filter : m_currentFilterLabels)
+ KStarsData::Instance()->userdb()->AddFilter(vendor, "", "", filter, 0, \
1.0, false, "--"); +
+ // Seems ->select() is not enough, have to create a new model.
+ delete (filterModel);
+ filterModel = new QSqlTableModel(this, \
KStarsData::Instance()->userdb()->GetDatabase()); + \
filterModel->setTable("filter"); + \
filterModel->setFilter(QString("vendor='%1'").arg(m_currentFilterDevice->getDeviceName()));
+ filterModel->select();
+ filterModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
+ }
+ // Make sure all the filter colors match DB. If not update model to sync with \
INDI filter values + else
+ {
+ for (int i = 0; i < filterModel->rowCount(); ++i)
+ {
+ QModelIndex index = filterModel->index(i, 4);
+ if (filterModel->data(index).toString() != m_currentFilterLabels[i])
+ {
+ filterModel->setData(index, m_currentFilterLabels[i]);
+ }
+ }
+ }
+
+ filterModel->setHeaderData(4, Qt::Horizontal, i18n("Filter"));
+
+ filterModel->setHeaderData(5, Qt::Horizontal, i18n("Filter exposure time during \
focus"), Qt::ToolTipRole); + filterModel->setHeaderData(5, Qt::Horizontal, \
i18n("Exposure")); +
+ filterModel->setHeaderData(6, Qt::Horizontal, i18n("Relative offset in steps"), \
Qt::ToolTipRole); + filterModel->setHeaderData(6, Qt::Horizontal, i18n("Offset"));
+
+ filterModel->setHeaderData(7, Qt::Horizontal, i18n("Start AutoFocus when filter \
is activated"), Qt::ToolTipRole); + filterModel->setHeaderData(7, Qt::Horizontal, \
i18n("AutoFocus")); +
+ filterModel->setHeaderData(8, Qt::Horizontal, i18n("Lock specific filter when \
running AutoFocus"), Qt::ToolTipRole); + filterModel->setHeaderData(8, \
Qt::Horizontal, i18n("Lock Filter"));
filterView->setModel(filterModel);
+ filterView->hideColumn(0);
+ filterView->hideColumn(1);
+ filterView->hideColumn(2);
+ filterView->hideColumn(3);
- // Get all OAL equipment filter list
- KStarsData::Instance()->userdb()->GetAllFilters(m_FilterList);
- m_ActiveFilters.clear();
+ // No Edit delegate
+ noEditDelegate = new NotEditableDelegate(filterView);
+ filterView->setItemDelegateForColumn(4, noEditDelegate);
+
+ // Exposure delegate
+ exposureDelegate = new ExposureDelegate(filterView);
+ filterView->setItemDelegateForColumn(5, exposureDelegate);
+
+ // Offset delegate
+ offsetDelegate = new OffsetDelegate(filterView);
+ filterView->setItemDelegateForColumn(6, offsetDelegate);
- // Get all filters for the current filter device
- QString currentFilterDevice = QString(m_currentFilterDevice->getDeviceName());
+ // Auto Focus delegate
+ useAutoFocusDelegate = new UseAutoFocusDelegate(filterView);
+ filterView->setItemDelegateForColumn(7, useAutoFocusDelegate);
- for (OAL::Filter *oneFilter : m_FilterList)
+ // Set Delegates
+ lockDelegate = new LockDelegate(m_currentFilterLabels, filterView);
+ filterView->setItemDelegateForColumn(8, lockDelegate);
+
+ reloadFilters();
+
+ connect(filterModel, &QSqlTableModel::dataChanged, [this](const QModelIndex \
&topLeft, const QModelIndex &, const QVector<int> &) {
- if (oneFilter->vendor() == currentFilterDevice)
- m_ActiveFilters.append(oneFilter);
- }
+ reloadFilters();
+ if (topLeft.column() == 5)
+ emit exposureChanged(filterModel->data(topLeft).toDouble());
+ });
}
-void FilterManager::addFilter(ISD::GDInterface *filter)
+void FilterManager::reloadFilters()
{
- m_filterDevices.append(filter);
- m_currentFilterDevice = filter;
+ qDeleteAll(m_ActiveFilters);
+ currentFilter = nullptr;
+ targetFilter = nullptr;
+ lockedFilter = nullptr;
+ m_ActiveFilters.clear();
+ operationQueue.clear();
+
+ for (int i = 0; i < filterModel->rowCount(); ++i)
+ {
+ QSqlRecord record = filterModel->record(i);
+ QString id = record.value("id").toString();
+ QString vendor = record.value("Vendor").toString();
+ QString model = record.value("Model").toString();
+ QString type = record.value("Type").toString();
+ QString color = record.value("Color").toString();
+ double exposure = record.value("Exposure").toDouble();
+ int offset = record.value("Offset").toInt();
+ QString lockedFilter = record.value("LockedFilter").toString();
+ bool useAutoFocus = record.value("UseAutoFocus").toInt() == 1;
+ OAL::Filter *o = new OAL::Filter(id, model, vendor, type, color, \
exposure, offset, useAutoFocus, lockedFilter); + m_ActiveFilters.append(o);
+ }
}
void FilterManager::setCurrentFilter(ISD::GDInterface *filter)
{
- m_currentFilterDevice = filter;
- m_currentFilterList.clear();
+ if (m_currentFilterDevice == filter)
+ return;
+ else
+ m_currentFilterDevice->disconnect(this);
+
+ filterNameLabel->setText(filter->getDeviceName());
- m_currentFilterList = getFilterLabelsForDevice(filter);
- m_currentFilterPosition = getFilterPositionForDevice(filter);
+ m_currentFilterDevice = filter;
+ m_currentFilterLabels.clear();
- m_currentFilterName = filter->getBaseDevice()->getText("FILTER_NAME");
- m_currentFilterSlot = filter->getBaseDevice()->getNumber("FILTER_SLOT");
+ m_FilterNameProperty = filter->getBaseDevice()->getText("FILTER_NAME");
+ m_FilterPositionProperty = filter->getBaseDevice()->getNumber("FILTER_SLOT");
- for (ISD::GDInterface *oneFilter : m_FilterList)
- oneFilter->disconnect(this);
+ m_currentFilterPosition = getFilterPosition(true);
+ m_currentFilterLabels = getFilterLabels(true);
connect(filter, SIGNAL(textUpdated(ITextVectorProperty*)), this, \
SLOT(processText(ITextVectorProperty*)));
connect(filter, SIGNAL(numberUpdated(INumberVectorProperty*)), this, \
SLOT(processNumber(INumberVectorProperty*)));
-}
+ connect(filter, SIGNAL(switchUpdated(ISwitchVectorProperty*)), this, \
SLOT(processSwitch(ISwitchVectorProperty*)));
-void FilterManager::addFocuser(ISD::GDInterface *focuser)
-{
- m_focuserDevices.append(dynamic_cast<ISD::Focuser*>(focuser));
- m_currentFocuserDevice = dynamic_cast<ISD::Focuser*>(focuser);
-}
+ refreshFilterModel();
-void FilterManager::setCurrentFocuser(ISD::GDInterface *focuser)
-{
- m_currentFocuserDevice = dynamic_cast<ISD::Focuser*>(focuser);
+ lastFilterOffset = m_ActiveFilters[m_currentFilterPosition-1]->offset();
}
-QStringList FilterManager::getFilterLabels(ISD::GDInterface *filter)
+QStringList FilterManager::getFilterLabels(bool forceRefresh)
{
- if (filter == nullptr)
- return m_currentFilterList;
-
- return getFilterLabelsForDevice(filter);
-}
-
-QStringList FilterManager::getFilterLabelsForDevice(ISD::GDInterface *filter)
-{
- if (filter == m_currentFilterDevice && m_currentFilterList.isEmpty() == false)
- return m_currentFilterList;
-
- ITextVectorProperty *name = filter->getBaseDevice()->getText("FILTER_NAME");
- INumberVectorProperty *slot = filter->getBaseDevice()->getNumber("FILTER_SLOT");
+ if (forceRefresh == false)
+ return m_currentFilterLabels;
QStringList filterList;
QStringList filterAlias = Options::filterAlias();
- for (int i = 0; i < slot->np[0].max; i++)
+ for (int i = 0; i < m_FilterPositionProperty->np[0].max; i++)
{
QString item;
- if (name != nullptr && (i < name->ntp))
- item = name->tp[i].text;
+ if (m_FilterNameProperty != nullptr && (i < m_FilterNameProperty->ntp))
+ item = m_FilterNameProperty->tp[i].text;
else if (i < filterAlias.count() && filterAlias[i].isEmpty() == false)
item = filterAlias.at(i);
else
@@ -127,33 +208,395 @@ QStringList \
FilterManager::getFilterLabelsForDevice(ISD::GDInterface *filter) return filterList;
}
-int FilterManager::getFilterPosition(ISD::GDInterface *filter)
+int FilterManager::getFilterPosition(bool forceRefresh)
{
- if (filter == nullptr)
+ if (forceRefresh == false)
return m_currentFilterPosition;
- return getFilterPositionForDevice(filter);
+ return static_cast<int>(m_FilterPositionProperty->np[0].value);
}
-int FilterManager::getFilterPositionForDevice(ISD::GDInterface *filter)
+bool FilterManager::setFilterPosition(uint8_t position, FilterPolicy policy)
{
- if (filter == m_currentFilterDevice)
- return static_cast<int>(m_currentFilterSlot->np[0].value);
+ // Position 1 to Max
+ if (position > m_ActiveFilters.count())
+ return false;
- INumberVectorProperty *slot = filter->getBaseDevice()->getNumber("FILTER_SLOT");
- if (slot == nullptr)
+ m_Policy = policy;
+ currentFilter= m_ActiveFilters[m_currentFilterPosition - 1];
+ targetFilter = m_ActiveFilters[position-1];
+
+ if (currentFilter == targetFilter)
{
- qCWarning(KSTARS_INDI) << "Unable to find FILTER_SLOT in" << \
filter->getBaseDevice();
- return -1;
+ emit ready();
+ return true;
}
- return static_cast<int>(slot->np[0].value);
+ lockedFilter = nullptr;
+ if (targetFilter->useAutoFocus() && targetFilter->lockedFilter() != "--")
+ {
+ QString color = targetFilter->lockedFilter();
+ // Search for locked filter by filter color name
+ auto pos = std::find_if(m_ActiveFilters.begin(), m_ActiveFilters.end(), \
[color](OAL::Filter *oneFilter) + {
+ return (oneFilter->color() == color);
+ });
+ if (pos != m_ActiveFilters.end())
+ lockedFilter = *pos;
+ }
+
+ buildOperationQueue(FILTER_CHANGE);
+
+ executeOperationQueue();
+
+ return true;
}
-bool FilterManager::setFilterPosition(uint8_t position, ISD::GDInterface *filter)
+void FilterManager::processNumber(INumberVectorProperty *nvp)
{
- if (filter == nullptr)
- return m_currentFilterDevice->runCommand(INDI_SET_FILTER, &position);
+ if (nvp->s != IPS_OK || strcmp(nvp->name, "FILTER_SLOT") || \
m_currentFilterDevice == nullptr || strcmp(nvp->device, \
m_currentFilterDevice->getDeviceName())) + return;
+
+ m_FilterPositionProperty = nvp;
+
+ if (m_currentFilterPosition != \
static_cast<int>(m_FilterPositionProperty->np[0].value)) + {
+ m_currentFilterPosition = \
static_cast<int>(m_FilterPositionProperty->np[0].value); + emit \
positionChanged(m_currentFilterPosition); + }
+
+ if (state == FILTER_CHANGE)
+ executeOperationQueue();
+ // If filter is changed externally, record its current offset as the starting \
offset. + else if (state == FILTER_IDLE)
+ lastFilterOffset = m_ActiveFilters[m_currentFilterPosition-1]->offset();
+
+ // Check if we have to apply Focus Offset
+ // Focus offsets are always applied first
+
+
- return filter->runCommand(INDI_SET_FILTER, &position);
+ // Check if we have to start Auto Focus
+ // If new filter position changed, and new filter policy is to perform \
auto-focus then autofocus is initiated. +
+ // Capture Module
+ // 3x L ---> 3x HA ---> 3x L
+ // Capture calls setFilterPosition("L").
+ // 0. Change filter to desired filter "L"
+ // 1. Is there any offset from last offset that needs to be applied?
+ // 1.1 Yes --> Apply focus offset and wait until position is changed:
+ // 1.1.1 Position complete, now check for useAutoFocus policy (#2).
+ // 1.1.2 Position failed, retry?
+ // 1.2 No --> Go to #2
+ // 2. Is there autofocus policy for current filter?
+ // 2.1. Yes --> Check filter lock policy
+ // 2.1.1 If filter lock is another filter --> Change filter
+ // 2.1.2 If filter lock is same filter --> proceed to 2.3
+ // 2.2 No --> Process to 2.3
+ // 2.3 filter lock policy filter is applied, start autofocus.
+ // 2.4 Autofocus complete. Check filter lock policy
+ // 2.4.1 If filter lock policy was applied --> revert filter
+ // 2.4.1.1 If filter offset policy is applicable --> Apply offset
+ // 2.4.1.2 If no filter offset policy is applicable --> Go to 2.5
+ // 2.4.2 No filter lock policy, go to 2.5
+ // 2.5 All complete, emit ready()
+
+ // Example. Current filter L. setFilterPosition("HA"). AutoFocus = YES. HA lock \
policy: L, HA offset policy: +100 with respect to L + // Operation Stack. \
offsetDiff = 100 + // If AutoFocus && current filter = lock policy filter
+ // AUTO_FOCUS (on L)
+ // CHANGE_FILTER (to HA)
+ // APPLY_OFFSET: +100
+
+ // Example. Current filter L. setFilterPosition("HA"). AutoFocus = No. HA lock \
policy: L, HA offset policy: +100 with respect to L + // Operation Stack. \
offsetDiff = 100 + // CHANGE_FILTER (to HA)
+ // APPLY_OFFSET: +100
+
+
+
+
+ // Example. Current filter R. setFilterPosition("B"). AutoFocus = YES. B lock \
policy: "--", B offset policy: +70 with respect to L + // R offset = -50 with \
respect to L + // FILTER_CHANGE (to B)
+ // FILTER_OFFSET (+120)
+ // AUTO_FOCUS
+
+ // Example. Current filter R. setFilterPosition("HA"). AutoFocus = YES. HA lock \
policy: L, HA offset policy: +100 with respect to L + // R offset = -50 with \
respect to L + // Operation Stack. offsetDiff = +150
+ // CHANGE_FILTER (to L)
+ // APPLY_OFFSET: +50 (L - R)
+ // AUTO_FOCUS
+ // CHANGE_FILTER (HA)
+ // APPLY_OFFSET: +100
+
+
+
+ // Example. Current filter R. setFilterPosition("HA"). AutoFocus = No. HA lock \
policy: L, HA offset policy: +100 with respect to L + // R offset = -50 with \
respect to L + // Operation Stack. offsetDiff = +150
+ // CHANGE_FILTER (to HA)
+ // APPLY_OFFSET: +150 (HA - R)
+
+
+
+ // Example. Current filter L. setFilterPosition("R"). AutoFocus = Yes. R lock \
policy: R, R offset policy: -50 with respect to L + // Operation Stack. offsetDiff \
= -50 + // CHANGE_FILTER (to R)
+ // APPLY_OFFSET: -50 (R - L)
+ // AUTO_FOCUS
+
+
+}
+
+void FilterManager::processText(ITextVectorProperty *tvp)
+{
+ if (strcmp(tvp->name, "FILTER_NAME") || m_currentFilterDevice == nullptr || \
strcmp(tvp->device, m_currentFilterDevice->getDeviceName()) ) + \
return; +
+ m_FilterNameProperty = tvp;
+
+ QStringList newFilterLabels = getFilterLabels(true);
+
+ if (newFilterLabels != m_currentFilterLabels)
+ {
+ m_currentFilterLabels = newFilterLabels;
+
+ refreshFilterModel();
+
+ emit labelsChanged(newFilterLabels);
+ }
+}
+
+void FilterManager::processSwitch(ISwitchVectorProperty *svp)
+{
+ if (m_currentFilterDevice == nullptr || strcmp(svp->device, \
m_currentFilterDevice->getDeviceName())) + return;
+
+}
+
+void FilterManager::buildOperationQueue(FilterState operation)
+{
+ operationQueue.clear();
+ m_useLockedFilter = false;
+ m_useTargetFilter = false;
+
+ switch (operation)
+ {
+ case FILTER_CHANGE:
+
+ if ( (m_Policy & LOCK_POLICY) && lockedFilter != nullptr && lockedFilter != \
currentFilter) + m_useLockedFilter = true;
+ if ( (m_Policy & CHANGE_POLICY) && ((m_Policy & ~LOCK_POLICY) || \
lockedFilter == nullptr) && targetFilter != currentFilter) + \
m_useTargetFilter = true; +
+ if (m_useLockedFilter || m_useTargetFilter)
+ {
+ operationQueue.enqueue(FILTER_CHANGE);
+ if (m_Policy & OFFSET_POLICY)
+ operationQueue.enqueue(FILTER_OFFSET);
+ }
+
+ if ( (m_Policy & AUTOFOCUS_POLICY) && targetFilter->useAutoFocus())
+ {
+ operationQueue.enqueue(FILTER_AUTOFOCUS);
+
+ if (lockedFilter != nullptr && lockedFilter != targetFilter)
+ {
+ m_useTargetFilter = true;
+ if (m_Policy & (CHANGE_POLICY|LOCK_POLICY))
+ operationQueue.enqueue(FILTER_CHANGE);
+ if (m_Policy & OFFSET_POLICY)
+ operationQueue.enqueue(FILTER_OFFSET);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool FilterManager::executeOperationQueue()
+{
+ if (operationQueue.isEmpty())
+ {
+ state = FILTER_IDLE;
+ emit newStatus(state);
+ emit ready();
+ return false;
+ }
+
+ FilterState nextOperation = operationQueue.dequeue();
+
+ bool actionRequired = true;
+
+ switch (nextOperation)
+ {
+ case FILTER_CHANGE:
+ {
+ state = FILTER_CHANGE;
+ if (m_useLockedFilter)
+ targetFilterPosition = m_ActiveFilters.indexOf(lockedFilter) + 1;
+ else if (m_useTargetFilter)
+ targetFilterPosition = m_ActiveFilters.indexOf(targetFilter) + 1;
+ m_currentFilterDevice->runCommand(INDI_SET_FILTER, &targetFilterPosition);
+ emit newStatus(state);
+ }
+ break;
+
+ case FILTER_OFFSET:
+ {
+ state = FILTER_OFFSET;
+ if (m_useLockedFilter)
+ {
+ targetFilterOffset = lockedFilter->offset() - lastFilterOffset;
+ lastFilterOffset = lockedFilter->offset();
+ currentFilter = lockedFilter;
+ m_useLockedFilter = false;
+ }
+ else if (m_useTargetFilter)
+ {
+ targetFilterOffset = targetFilter->offset() - lastFilterOffset;
+ lastFilterOffset = targetFilter->offset();
+ currentFilter = targetFilter;
+ m_useTargetFilter = false;
+ }
+ if (targetFilterOffset == 0)
+ actionRequired = false;
+ else
+ {
+ emit newFocusOffset(targetFilterOffset);
+ emit newStatus(state);
+ }
+ }
+ break;
+
+ case FILTER_AUTOFOCUS:
+ state = FILTER_AUTOFOCUS;
+ emit newStatus(state);
+ emit checkFocus(0.01);
+ break;
+
+ default:
+ break;
+ }
+
+ // If an additional action is required, return return and continue later
+ if (actionRequired)
+ return true;
+ // Othereise, continue processing the queue
+ else
+ return executeOperationQueue();
+}
+
+bool FilterManager::executeOneOperation(FilterState operation)
+{
+ bool actionRequired = false;
+
+ switch (operation)
+ {
+ default:
+ break;
+ }
+
+ return actionRequired;
+}
+
+void FilterManager::setFocusOffsetComplete()
+{
+ if (state == FILTER_OFFSET)
+ executeOperationQueue();
+}
+
+double FilterManager::getFilterExposure(const QString &name) const
+{
+ QString color = name;
+ if (color.isEmpty())
+ color = m_currentFilterLabels[m_currentFilterPosition-1];
+ // Search for locked filter by filter color name
+ auto pos = std::find_if(m_ActiveFilters.begin(), m_ActiveFilters.end(), \
[color](OAL::Filter *oneFilter) + {return (oneFilter->color() == color);});
+
+ if (pos != m_ActiveFilters.end())
+ return (*pos)->exposure();
+
+ // Default value
+ return 1;
+}
+
+bool FilterManager::setFilterExposure(double exposure)
+{
+ QString color = m_currentFilterLabels[m_currentFilterPosition-1];
+ for (int i=0; i < m_ActiveFilters.count(); i++)
+ {
+ if (color == m_ActiveFilters[i]->color())
+ {
+ filterModel->setData(filterModel->index(i, 5), exposure);
+ filterModel->submitAll();
+ refreshFilterModel();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QString FilterManager::getFilterLock(const QString &name) const
+{
+ // Search for locked filter by filter color name
+ auto pos = std::find_if(m_ActiveFilters.begin(), m_ActiveFilters.end(), \
[name](OAL::Filter *oneFilter) + {return (oneFilter->color() == name);});
+
+ if (pos != m_ActiveFilters.end())
+ return (*pos)->lockedFilter();
+
+ // Default value
+ return "--";
+}
+
+void FilterManager::removeDevice(ISD::GDInterface *device)
+{
+ if (device == m_currentFilterDevice)
+ {
+ m_FilterNameProperty = nullptr;
+ m_FilterPositionProperty = nullptr;
+ m_currentFilterDevice = nullptr;
+ m_currentFilterLabels.clear();
+ m_currentFilterPosition = 0;
+ qDeleteAll(m_ActiveFilters);
+ m_ActiveFilters.clear();
+ delete(filterModel);
+ filterModel = nullptr;
+ }
+}
+
+void FilterManager::setFocusStatus(Ekos::FocusState focusState)
+{
+ if (state == FILTER_AUTOFOCUS)
+ {
+ switch (focusState)
+ {
+ case FOCUS_COMPLETE:
+ executeOperationQueue();
+ break;
+
+ case FOCUS_FAILED:
+ if (++retries == 3)
+ {
+ retries = 0;
+ emit failed();
+ return;
+ }
+ // Restart again
+ emit checkFocus(0.01);
+ break;
+
+ default:
+ break;
+
+ }
+ }
+}
}
diff --git a/kstars/ekos/auxiliary/filtermanager.h \
b/kstars/ekos/auxiliary/filtermanager.h index 9928e2850..6c5dd3ed2 100644
--- a/kstars/ekos/auxiliary/filtermanager.h
+++ b/kstars/ekos/auxiliary/filtermanager.h
@@ -10,69 +10,135 @@
#pragma once
#include <QDialog>
+#include <QSqlDatabase>
+#include <QQueue>
+#include <QPointer>
+
#include <indi/indistd.h>
#include <indi/indifocuser.h>
#include <oal/filter.h>
-#include <QSqlDatabase>
+
+#include "ekos/ekos.h"
#include "ui_filtersettings.h"
class QSqlTableModel;
+class LockDelegate;
+class NotEditableDelegate;
+class ExposureDelegate;
+class OffsetDelegate;
+class UseAutoFocusDelegate;
+
+namespace Ekos
+{
class FilterManager : public QDialog, public Ui::FilterSettings
{
+ Q_OBJECT
public:
+
+ typedef enum
+ {
+ CHANGE_POLICY = 1 << 0,
+ LOCK_POLICY = 1 << 1,
+ OFFSET_POLICY = 1 << 2,
+ AUTOFOCUS_POLICY = 1 << 3,
+ ALL_POLICIES = CHANGE_POLICY | OFFSET_POLICY | LOCK_POLICY | \
AUTOFOCUS_POLICY + } FilterPolicy;
+
FilterManager();
- void refreshFilterData();
- QStringList getFilterLabels(ISD::GDInterface *filter=nullptr);
+ void refreshFilterModel();
+
+ QStringList getFilterLabels(bool forceRefresh=false);
+
+ int getFilterPosition(bool forceRefresh=false);
+
+ // The target position and offset
+ int getTargetFilterPosition() { return targetFilterPosition; }
+ int getTargetFilterOffset() { return targetFilterOffset; }
+
+ /**
+ * @brief getFilterExposure Get optimal exposure time for the specified filter
+ * @param name filter to obtain exposure time for
+ * @return exposure time in seconds.
+ */
+ double getFilterExposure(const QString &name = QString()) const;
+ bool setFilterExposure(double exposure);
- bool setFilterPosition(uint8_t position, ISD::GDInterface *filter=nullptr);
- int getFilterPosition(ISD::GDInterface *filter=nullptr);
+ /**
+ * @brief getFilterLock Return filter that should be used when running autofocus \
for the supplied filter + * For example, "Red" filter can be locked to use "Lum" \
when doing autofocus. "Green" filter can be locked to "--" + * which means that \
no filter change is necessary. + * @param name filter which we need to query its \
locked filter. + * @return locked filter. "--" indicates no locked filter and \
whatever current filter should be used. + *
+ */
+ QString getFilterLock(const QString &name) const;
- void addFilter(ISD::GDInterface *filter);
- void setCurrentFilter(ISD::GDInterface *filter);
+ void setCurrentFilter(ISD::GDInterface *filter);
- void addFocuser(ISD::GDInterface *focuser);
- void setCurrentFocuser(ISD::GDInterface *focuser);
+
+ /**
+ * @brief applyFilterFocusPolicies Check if we need to apply any filter policies \
for focus operations. + */
+ void applyFilterFocusPolicies();
public slots:
- void updateFilterNames();
- void updateFilterPosition();
+ // Position. if applyPolicy is true then all filter offsets and autofocus & lock \
policies are applied. + bool setFilterPosition(uint8_t position, FilterPolicy \
policy = ALL_POLICIES); + // Offset
+ void setFocusOffsetComplete();
+ // Remove Device
+ void removeDevice(ISD::GDInterface *device);
+ // Refresh Filters after model update
+ void reloadFilters();
+ // Focus Status
+ void setFocusStatus(Ekos::FocusState focusState);
signals:
// Emitted only when there is a change in the filter slot number
- void currentFilterPositionChanged(int);
+ void positionChanged(int);
// Emitted when filter change operation completed successfully including any \
focus offsets or auto-focus operation
- void currentFilterPositionCompleted(int);
- // Emitted when filter labels are updated for the current filter
- void currentFilterLabelsChanged(QStringList);
-
-private slots:
- // Apply changes to database
- void apply();
+ void labelsChanged(QStringList);
+ // Emitted when filter exposure duration changes
+ void exposureChanged(double);
+ // Emitted when filter change completed including all required actions
+ void ready();
+ // Emitted when operation fails
+ void failed();
+ // Status signal
+ void newStatus(FilterState state);
+ // Check Focus
+ void checkFocus(double);
+ // New Focus offset requested
+ void newFocusOffset(int16_t);
+
+private slots:
void processText(ITextVectorProperty *tvp);
void processNumber(INumberVectorProperty *nvp);
void processSwitch(ISwitchVectorProperty *svp);
private:
- QStringList getFilterLabelsForDevice(ISD::GDInterface *filter);
- int getFilterPositionForDevice(ISD::GDInterface *filter);
-
// Filter Wheel Devices
- QList<ISD::GDInterface*> m_filterDevices;
ISD::GDInterface *m_currentFilterDevice = { nullptr };
- QStringList m_currentFilterList;
+
+ // Position and Labels
+ QStringList m_currentFilterLabels;
int m_currentFilterPosition = { -1 };
+ double m_currentFilterExposure = { -1 };
// Filter Structure
QList<OAL::Filter *> m_ActiveFilters;
- QList<OAL::Filter *> m_FilterList;
+ OAL::Filter *targetFilter = { nullptr };
+ OAL::Filter *currentFilter = { nullptr };
+ OAL::Filter *lockedFilter = { nullptr };
+ bool m_useLockedFilter = { false };
+ bool m_useTargetFilter = { false };
- // Focusers
- QList<ISD::Focuser *> m_focuserDevices;
- ISD::Focuser *m_currentFocuserDevice = { nullptr };
+ // Autofocus retries
+ uint8_t retries = { 0 };
int16_t lastFilterOffset { 0 };
@@ -80,6 +146,34 @@ private:
QSqlTableModel *filterModel = { nullptr };
// INDI Properties of current active filter
- ITextVectorProperty *m_currentFilterName { nullptr };
- INumberVectorProperty *m_currentFilterSlot { nullptr };
+ ITextVectorProperty *m_FilterNameProperty { nullptr };
+ INumberVectorProperty *m_FilterPositionProperty { nullptr };
+
+ // Operation stack
+ void buildOperationQueue(FilterState operation);
+ bool executeOperationQueue();
+ bool executeOneOperation(FilterState operation);
+
+ // Update model
+ void syncDBToINDI();
+
+ // Operation Queue
+ QQueue<FilterState> operationQueue;
+
+ FilterState state = { FILTER_IDLE };
+
+ int targetFilterPosition = { -1 };
+ int targetFilterOffset = { - 1 };
+
+ // Delegates
+ QPointer<LockDelegate> lockDelegate;
+ QPointer<NotEditableDelegate> noEditDelegate;
+ QPointer<ExposureDelegate> exposureDelegate;
+ QPointer<OffsetDelegate> offsetDelegate;
+ QPointer<UseAutoFocusDelegate> useAutoFocusDelegate;
+
+ // Policies
+ FilterPolicy m_Policy = { ALL_POLICIES };
};
+
+}
diff --git a/kstars/ekos/auxiliary/filtersettings.ui \
b/kstars/ekos/auxiliary/filtersettings.ui index 61f60b3ce..e4df7085f 100644
--- a/kstars/ekos/auxiliary/filtersettings.ui
+++ b/kstars/ekos/auxiliary/filtersettings.ui
@@ -19,17 +19,17 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
- <string>FW:</string>
+ <string>Filter Wheel</string>
</property>
</widget>
</item>
<item>
- <widget class="QComboBox" name="FWCombo">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <widget class="QLabel" name="filterNameLabel">
+ <property name="styleSheet">
+ <string notr="true">font-weight:bold;</string>
+ </property>
+ <property name="text">
+ <string/>
</property>
</widget>
</item>
@@ -49,7 +49,23 @@
</layout>
</item>
<item>
- <widget class="QTableView" name="filterView"/>
+ <widget class="QTableView" name="filterView">
+ <property name="sizeAdjustPolicy">
+ <enum>QAbstractScrollArea::AdjustToContents</enum>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderStretchLastSection">
+ <bool>false</bool>
+ </attribute>
+ </widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
@@ -97,7 +113,7 @@
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
- <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel</set>
+ <set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
diff --git a/kstars/ekos/ekosmanager.cpp b/kstars/ekos/ekosmanager.cpp
index 2d3ec32dc..c017f7049 100644
--- a/kstars/ekos/ekosmanager.cpp
+++ b/kstars/ekos/ekosmanager.cpp
@@ -106,10 +106,7 @@ EkosManager::EkosManager(QWidget *parent) : QDialog(parent)
connect(clearB, SIGNAL(clicked()), this, SLOT(clearLog()));
// Summary
- // previewPixmap = new QPixmap(QPixmap(":/images/noimage.png"));
-
- // Filter Manager
- filterManager.reset(new FilterManager());
+ // previewPixmap = new QPixmap(QPixmap(":/images/noimage.png"));
// Profiles
connect(addProfileB, SIGNAL(clicked()), this, SLOT(addProfile()));
@@ -312,6 +309,9 @@ void EkosManager::reset()
{
qCDebug(KSTARS_EKOS) << "Resetting Ekos Manager...";
+ // Filter Manager
+ filterManager.reset(new Ekos::FilterManager());
+
nDevices = 0;
useGuideHead = false;
@@ -1137,8 +1137,6 @@ void EkosManager::setFilter(ISD::GDInterface *filterDevice)
alignProcess->addFilter(filterDevice);
- filterManager->addFilter(filterDevice);
-
if (Options::defaultAlignFW().isEmpty() == false)
alignProcess->setFilter(Options::defaultAlignFW(), -1);
}
@@ -1151,9 +1149,7 @@ void EkosManager::setFocuser(ISD::GDInterface *focuserDevice)
initFocus();
- focusProcess->addFocuser(focuserDevice);
-
- filterManager->addFocuser(focuserDevice);
+ focusProcess->addFocuser(focuserDevice);
appendLogText(i18n("%1 focuser is online.", focuserDevice->getDeviceName()));
}
@@ -1236,6 +1232,7 @@ void EkosManager::removeDevice(ISD::GDInterface *devInterface)
break;
}
+
appendLogText(i18n("%1 is offline.", devInterface->getDeviceName()));
// #1 Remove from Generic Devices
@@ -1269,7 +1266,7 @@ void EkosManager::processNewText(ITextVectorProperty *tvp)
{
if (!strcmp(tvp->name, "FILTER_NAME"))
{
- filterManager->updateFilterNames();
+ //filterManager->updateFilterNames();
/*if (captureProcess.get() != nullptr)
captureProcess->checkFilter();
@@ -1322,10 +1319,10 @@ void EkosManager::processNewNumber(INumberVectorProperty \
*nvp) return;
}
+ /*
if (!strcmp(nvp->name, "FILTER_SLOT"))
- {
- filterManager->updateFilterNames();
- /*if (captureProcess.get() != nullptr)
+ {
+ if (captureProcess.get() != nullptr)
captureProcess->checkFilter();
if (focusProcess.get() != nullptr)
@@ -1333,8 +1330,9 @@ void EkosManager::processNewNumber(INumberVectorProperty *nvp)
if (alignProcess.get() != nullptr)
alignProcess->checkFilter();
- */
+
}
+ */
}
void EkosManager::processNewProperty(INDI::Property *prop)
@@ -1436,10 +1434,10 @@ void EkosManager::processNewProperty(INDI::Property *prop)
return;
}
+ /*
if (!strcmp(prop->getName(), "FILTER_NAME"))
- {
- filterManager->updateFilterNames();
- /*if (captureProcess.get() != nullptr)
+ {
+ if (captureProcess.get() != nullptr)
captureProcess->checkFilter();
if (focusProcess.get() != nullptr)
@@ -1447,10 +1445,11 @@ void EkosManager::processNewProperty(INDI::Property *prop)
if (alignProcess.get() != nullptr)
alignProcess->checkFilter();
- */
+
return;
}
+ */
if (!strcmp(prop->getName(), "ASTROMETRY_SOLVER"))
{
@@ -1663,12 +1662,6 @@ void EkosManager::initCapture()
SLOT(setFocusStatus(Ekos::FocusState)), Qt::UniqueConnection);
connect(focusProcess.get(), &Ekos::Focus::newHFR, captureProcess.get(), \
&Ekos::Capture::setHFR, Qt::UniqueConnection);
- // Adjust focus position
- connect(captureProcess.get(), SIGNAL(newFocusOffset(int16_t)), \
focusProcess.get(), SLOT(adjustRelativeFocus(int16_t)),
- Qt::UniqueConnection);
- connect(focusProcess.get(), SIGNAL(focusPositionAdjusted()), \
captureProcess.get(), SLOT(preparePreCaptureActions()),
- Qt::UniqueConnection);
-
// Meridian Flip
connect(captureProcess.get(), SIGNAL(meridianFlipStarted()), \
focusProcess.get(), SLOT(resetFrame()), Qt::UniqueConnection); }
@@ -1735,6 +1728,8 @@ void EkosManager::initAlign()
toolsWidget->setTabIcon(index, icon);
}
+ alignProcess->setFilterManager(filterManager);
+
if (captureProcess.get() != nullptr)
{
// Align Status
@@ -1752,9 +1747,6 @@ void EkosManager::initAlign()
if (focusProcess.get() != nullptr)
{
- // Filter lock
- //connect(focusProcess.get(), \
SIGNAL(filterLockUpdated(ISD::GDInterface*,int)), alignProcess.get(),
- //SLOT(setLockedFilter(ISD::GDInterface*,int)), \
Qt::UniqueConnection);
connect(focusProcess.get(), SIGNAL(newStatus(Ekos::FocusState)), \
alignProcess.get(), SLOT(setFocusStatus(Ekos::FocusState)), Qt::UniqueConnection);
}
@@ -1788,6 +1780,14 @@ void EkosManager::initFocus()
connect(focusProcess.get(), SIGNAL(newProfilePixmap(QPixmap&)), this, \
SLOT(updateFocusProfilePixmap(QPixmap&)));
connect(focusProcess.get(), SIGNAL(newHFR(double)), this, \
SLOT(updateCurrentHFR(double)));
+ focusProcess->setFilterManager(filterManager);
+ connect(filterManager.data(), SIGNAL(checkFocus(double)), focusProcess.get(), \
SLOT(checkFocus(double)), Qt::UniqueConnection); + connect(focusProcess.get(), \
SIGNAL(newStatus(Ekos::FocusState)), filterManager.data(), \
SLOT(setFocusStatus(Ekos::FocusState)), Qt::UniqueConnection); + \
connect(filterManager.data(), SIGNAL(newFocusOffset(int16_t)), focusProcess.get(), \
SLOT(adjustRelativeFocus(int16_t)), + Qt::UniqueConnection);
+ connect(focusProcess.get(), SIGNAL(focusPositionAdjusted()), \
filterManager.data(), SLOT(setFocusOffsetComplete()), + \
Qt::UniqueConnection); +
if (Options::ekosLeftIcons())
{
QTransform trans;
@@ -1815,12 +1815,6 @@ void EkosManager::initFocus()
SLOT(setFocusStatus(Ekos::FocusState)), Qt::UniqueConnection);
connect(focusProcess.get(), &Ekos::Focus::newHFR, captureProcess.get(), \
&Ekos::Capture::setHFR, Qt::UniqueConnection);
- // Adjust focus position
- connect(captureProcess.get(), SIGNAL(newFocusOffset(int16_t)), \
focusProcess.get(), SLOT(adjustRelativeFocus(int16_t)),
- Qt::UniqueConnection);
- connect(focusProcess.get(), SIGNAL(focusPositionAdjusted()), \
captureProcess.get(), SLOT(preparePreCaptureActions()),
- Qt::UniqueConnection);
-
// Meridian Flip
connect(captureProcess.get(), SIGNAL(meridianFlipStarted()), \
focusProcess.get(), SLOT(resetFrame()), Qt::UniqueConnection); }
@@ -1834,9 +1828,6 @@ void EkosManager::initFocus()
if (alignProcess.get() != nullptr)
{
- // Filter lock
- //connect(focusProcess.get(), \
SIGNAL(filterLockUpdated(ISD::GDInterface*,int)), alignProcess.get(),
- //SLOT(setLockedFilter(ISD::GDInterface*,int)), \
Qt::UniqueConnection);
connect(focusProcess.get(), SIGNAL(newStatus(Ekos::FocusState)), \
alignProcess.get(), SLOT(setFocusStatus(Ekos::FocusState)), Qt::UniqueConnection);
}
diff --git a/kstars/ekos/ekosmanager.h b/kstars/ekos/ekosmanager.h
index 74433c207..214987f69 100644
--- a/kstars/ekos/ekosmanager.h
+++ b/kstars/ekos/ekosmanager.h
@@ -287,7 +287,7 @@ class EkosManager : public QDialog, public Ui::EkosManager
QList<std::shared_ptr<ProfileInfo>> profiles;
// Filter Manager
- QSharedPointer<FilterManager> filterManager;
+ QSharedPointer<Ekos::FilterManager> filterManager;
// Mount Summary
QProgressIndicator *mountPI { nullptr };
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic