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 in= cluding 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/auxiliar= y/filtermanager.cpp index 39a408c61..5946252ff 100644 --- a/kstars/ekos/auxiliary/filtermanager.cpp +++ b/kstars/ekos/auxiliary/filtermanager.cpp @@ -11,111 +11,192 @@ = #include #include +#include +#include = #include = #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 =3D=3D nullptr) return; = + QString vendor(m_currentFilterDevice->getDeviceName()); + delete (filterModel); + filterModel =3D new QSqlTableModel(this, KStarsData::Instance()->userd= b()->GetDatabase()); filterModel->setTable("filter"); + filterModel->setFilter(QString("vendor=3D'%1'").arg(vendor)); filterModel->select(); + filterModel->setEditStrategy(QSqlTableModel::OnFieldChange); + + // If it is first time, let's populate data + if (filterModel->rowCount() =3D=3D 0) + { + for (QString filter : m_currentFilterLabels) + KStarsData::Instance()->userdb()->AddFilter(vendor, "", "", fi= lter, 0, 1.0, false, "--"); + + // Seems ->select() is not enough, have to create a new model. + delete (filterModel); + filterModel =3D new QSqlTableModel(this, KStarsData::Instance()->u= serdb()->GetDatabase()); + filterModel->setTable("filter"); + filterModel->setFilter(QString("vendor=3D'%1'").arg(m_currentFilte= rDevice->getDeviceName())); + filterModel->select(); + filterModel->setEditStrategy(QSqlTableModel::OnManualSubmit); + } + // Make sure all the filter colors match DB. If not update model to sy= nc with INDI filter values + else + { + for (int i =3D 0; i < filterModel->rowCount(); ++i) + { + QModelIndex index =3D filterModel->index(i, 4); + if (filterModel->data(index).toString() !=3D m_currentFilterLa= bels[i]) + { + filterModel->setData(index, m_currentFilterLabels[i]); + } + } + } + + filterModel->setHeaderData(4, Qt::Horizontal, i18n("Filter")); + + filterModel->setHeaderData(5, Qt::Horizontal, i18n("Filter exposure ti= me 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 wh= en filter is activated"), Qt::ToolTipRole); + filterModel->setHeaderData(7, Qt::Horizontal, i18n("AutoFocus")); + + filterModel->setHeaderData(8, Qt::Horizontal, i18n("Lock specific filt= er 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 =3D new NotEditableDelegate(filterView); + filterView->setItemDelegateForColumn(4, noEditDelegate); + + // Exposure delegate + exposureDelegate =3D new ExposureDelegate(filterView); + filterView->setItemDelegateForColumn(5, exposureDelegate); + + // Offset delegate + offsetDelegate =3D new OffsetDelegate(filterView); + filterView->setItemDelegateForColumn(6, offsetDelegate); = - // Get all filters for the current filter device - QString currentFilterDevice =3D QString(m_currentFilterDevice->getDevi= ceName()); + // Auto Focus delegate + useAutoFocusDelegate =3D new UseAutoFocusDelegate(filterView); + filterView->setItemDelegateForColumn(7, useAutoFocusDelegate); = - for (OAL::Filter *oneFilter : m_FilterList) + // Set Delegates + lockDelegate =3D new LockDelegate(m_currentFilterLabels, filterView); + filterView->setItemDelegateForColumn(8, lockDelegate); + + reloadFilters(); + + connect(filterModel, &QSqlTableModel::dataChanged, [this](const QModel= Index &topLeft, const QModelIndex &, const QVector &) { - if (oneFilter->vendor() =3D=3D currentFilterDevice) - m_ActiveFilters.append(oneFilter); - } + reloadFilters(); + if (topLeft.column() =3D=3D 5) + emit exposureChanged(filterModel->data(topLeft).toDouble()); + }); } = -void FilterManager::addFilter(ISD::GDInterface *filter) +void FilterManager::reloadFilters() { - m_filterDevices.append(filter); - m_currentFilterDevice =3D filter; + qDeleteAll(m_ActiveFilters); + currentFilter =3D nullptr; + targetFilter =3D nullptr; + lockedFilter =3D nullptr; + m_ActiveFilters.clear(); + operationQueue.clear(); + + for (int i =3D 0; i < filterModel->rowCount(); ++i) + { + QSqlRecord record =3D filterModel->record(i); + QString id =3D record.value("id").toString(); + QString vendor =3D record.value("Vendor").toString(); + QString model =3D record.value("Model").toString(); + QString type =3D record.value("Type").toString(); + QString color =3D record.value("Color").toString(); + double exposure =3D record.value("Exposure").toDouble(); + int offset =3D record.value("Offset").toInt(); + QString lockedFilter =3D record.value("LockedFilter").toString(); + bool useAutoFocus =3D record.value("UseAutoFocus").toInt() =3D=3D = 1; + OAL::Filter *o =3D new OAL::Filter(id, model, vendor, type, col= or, exposure, offset, useAutoFocus, lockedFilter); + m_ActiveFilters.append(o); + } } = void FilterManager::setCurrentFilter(ISD::GDInterface *filter) { - m_currentFilterDevice =3D filter; - m_currentFilterList.clear(); + if (m_currentFilterDevice =3D=3D filter) + return; + else + m_currentFilterDevice->disconnect(this); + + filterNameLabel->setText(filter->getDeviceName()); = - m_currentFilterList =3D getFilterLabelsForDevice(filter); - m_currentFilterPosition =3D getFilterPositionForDevice(filter); + m_currentFilterDevice =3D filter; + m_currentFilterLabels.clear(); = - m_currentFilterName =3D filter->getBaseDevice()->getText("FILTER_NAME"= ); - m_currentFilterSlot =3D filter->getBaseDevice()->getNumber("FILTER_SLO= T"); + m_FilterNameProperty =3D filter->getBaseDevice()->getText("FILTER_NAME= "); + m_FilterPositionProperty =3D filter->getBaseDevice()->getNumber("FILTE= R_SLOT"); = - for (ISD::GDInterface *oneFilter : m_FilterList) - oneFilter->disconnect(this); + m_currentFilterPosition =3D getFilterPosition(true); + m_currentFilterLabels =3D getFilterLabels(true); = connect(filter, SIGNAL(textUpdated(ITextVectorProperty*)), this, SLOT(= processText(ITextVectorProperty*))); connect(filter, SIGNAL(numberUpdated(INumberVectorProperty*)), this, S= LOT(processNumber(INumberVectorProperty*))); -} + connect(filter, SIGNAL(switchUpdated(ISwitchVectorProperty*)), this, S= LOT(processSwitch(ISwitchVectorProperty*))); = -void FilterManager::addFocuser(ISD::GDInterface *focuser) -{ - m_focuserDevices.append(dynamic_cast(focuser)); - m_currentFocuserDevice =3D dynamic_cast(focuser); -} + refreshFilterModel(); = -void FilterManager::setCurrentFocuser(ISD::GDInterface *focuser) -{ - m_currentFocuserDevice =3D dynamic_cast(focuser); + lastFilterOffset =3D m_ActiveFilters[m_currentFilterPosition-1]->offse= t(); } = -QStringList FilterManager::getFilterLabels(ISD::GDInterface *filter) +QStringList FilterManager::getFilterLabels(bool forceRefresh) { - if (filter =3D=3D nullptr) - return m_currentFilterList; - - return getFilterLabelsForDevice(filter); -} - -QStringList FilterManager::getFilterLabelsForDevice(ISD::GDInterface *filt= er) -{ - if (filter =3D=3D m_currentFilterDevice && m_currentFilterList.isEmpty= () =3D=3D false) - return m_currentFilterList; - - ITextVectorProperty *name =3D filter->getBaseDevice()->getText("FILTER= _NAME"); - INumberVectorProperty *slot =3D filter->getBaseDevice()->getNumber("FI= LTER_SLOT"); + if (forceRefresh =3D=3D false) + return m_currentFilterLabels; = QStringList filterList; = QStringList filterAlias =3D Options::filterAlias(); = - for (int i =3D 0; i < slot->np[0].max; i++) + for (int i =3D 0; i < m_FilterPositionProperty->np[0].max; i++) { QString item; = - if (name !=3D nullptr && (i < name->ntp)) - item =3D name->tp[i].text; + if (m_FilterNameProperty !=3D nullptr && (i < m_FilterNameProperty= ->ntp)) + item =3D m_FilterNameProperty->tp[i].text; else if (i < filterAlias.count() && filterAlias[i].isEmpty() =3D= =3D false) item =3D 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 =3D=3D nullptr) + if (forceRefresh =3D=3D false) return m_currentFilterPosition; = - return getFilterPositionForDevice(filter); + return static_cast(m_FilterPositionProperty->np[0].value); } = -int FilterManager::getFilterPositionForDevice(ISD::GDInterface *filter) +bool FilterManager::setFilterPosition(uint8_t position, FilterPolicy polic= y) { - if (filter =3D=3D m_currentFilterDevice) - return static_cast(m_currentFilterSlot->np[0].value); + // Position 1 to Max + if (position > m_ActiveFilters.count()) + return false; = - INumberVectorProperty *slot =3D filter->getBaseDevice()->getNumber("FI= LTER_SLOT"); - if (slot =3D=3D nullptr) + m_Policy =3D policy; + currentFilter=3D m_ActiveFilters[m_currentFilterPosition - 1]; + targetFilter =3D m_ActiveFilters[position-1]; + + if (currentFilter =3D=3D targetFilter) { - qCWarning(KSTARS_INDI) << "Unable to find FILTER_SLOT in" << filte= r->getBaseDevice(); - return -1; + emit ready(); + return true; } = - return static_cast(slot->np[0].value); + lockedFilter =3D nullptr; + if (targetFilter->useAutoFocus() && targetFilter->lockedFilter() !=3D = "--") + { + QString color =3D targetFilter->lockedFilter(); + // Search for locked filter by filter color name + auto pos =3D std::find_if(m_ActiveFilters.begin(), m_ActiveFilters= .end(), [color](OAL::Filter *oneFilter) + { + return (oneFilter->color() =3D=3D color); + }); + if (pos !=3D m_ActiveFilters.end()) + lockedFilter =3D *pos; + } + + buildOperationQueue(FILTER_CHANGE); + + executeOperationQueue(); + + return true; } = -bool FilterManager::setFilterPosition(uint8_t position, ISD::GDInterface *= filter) +void FilterManager::processNumber(INumberVectorProperty *nvp) { - if (filter =3D=3D nullptr) - return m_currentFilterDevice->runCommand(INDI_SET_FILTER, &positio= n); + if (nvp->s !=3D IPS_OK || strcmp(nvp->name, "FILTER_SLOT") || m_curren= tFilterDevice =3D=3D nullptr || strcmp(nvp->device, m_currentFilterDevice->= getDeviceName())) + return; + + m_FilterPositionProperty =3D nvp; + + if (m_currentFilterPosition !=3D static_cast(m_FilterPositionProp= erty->np[0].value)) + { + m_currentFilterPosition =3D static_cast(m_FilterPositionPrope= rty->np[0].value); + emit positionChanged(m_currentFilterPosition); + } + + if (state =3D=3D FILTER_CHANGE) + executeOperationQueue(); + // If filter is changed externally, record its current offset as the s= tarting offset. + else if (state =3D=3D FILTER_IDLE) + lastFilterOffset =3D m_ActiveFilters[m_currentFilterPosition-1]->o= ffset(); + + // 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 =3D Y= ES. HA lock policy: L, HA offset policy: +100 with respect to L + // Operation Stack. offsetDiff =3D 100 + // If AutoFocus && current filter =3D lock policy filter + // AUTO_FOCUS (on L) + // CHANGE_FILTER (to HA) + // APPLY_OFFSET: +100 + + // Example. Current filter L. setFilterPosition("HA"). AutoFocus =3D N= o. HA lock policy: L, HA offset policy: +100 with respect to L + // Operation Stack. offsetDiff =3D 100 + // CHANGE_FILTER (to HA) + // APPLY_OFFSET: +100 + + + + + // Example. Current filter R. setFilterPosition("B"). AutoFocus =3D YE= S. B lock policy: "--", B offset policy: +70 with respect to L + // R offset =3D -50 with respect to L + // FILTER_CHANGE (to B) + // FILTER_OFFSET (+120) + // AUTO_FOCUS + + // Example. Current filter R. setFilterPosition("HA"). AutoFocus =3D Y= ES. HA lock policy: L, HA offset policy: +100 with respect to L + // R offset =3D -50 with respect to L + // Operation Stack. offsetDiff =3D +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 =3D N= o. HA lock policy: L, HA offset policy: +100 with respect to L + // R offset =3D -50 with respect to L + // Operation Stack. offsetDiff =3D +150 + // CHANGE_FILTER (to HA) + // APPLY_OFFSET: +150 (HA - R) + + + + // Example. Current filter L. setFilterPosition("R"). AutoFocus =3D Ye= s. R lock policy: R, R offset policy: -50 with respect to L + // Operation Stack. offsetDiff =3D -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 =3D=3D n= ullptr || strcmp(tvp->device, m_currentFilterDevice->getDeviceName()) = ) + return; = + + m_FilterNameProperty =3D tvp; + + QStringList newFilterLabels =3D getFilterLabels(true); + + if (newFilterLabels !=3D m_currentFilterLabels) + { + m_currentFilterLabels =3D newFilterLabels; + + refreshFilterModel(); + + emit labelsChanged(newFilterLabels); + } +} + +void FilterManager::processSwitch(ISwitchVectorProperty *svp) +{ + if (m_currentFilterDevice =3D=3D nullptr || strcmp(svp->device, m_curr= entFilterDevice->getDeviceName())) + return; + +} + +void FilterManager::buildOperationQueue(FilterState operation) +{ + operationQueue.clear(); + m_useLockedFilter =3D false; + m_useTargetFilter =3D false; + + switch (operation) + { + case FILTER_CHANGE: + + if ( (m_Policy & LOCK_POLICY) && lockedFilter !=3D nullptr && lock= edFilter !=3D currentFilter) + m_useLockedFilter =3D true; + if ( (m_Policy & CHANGE_POLICY) && ((m_Policy & ~LOCK_POLICY) || l= ockedFilter =3D=3D nullptr) && targetFilter !=3D currentFilter) + m_useTargetFilter =3D 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 !=3D nullptr && lockedFilter !=3D targetFilte= r) + { + m_useTargetFilter =3D 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 =3D FILTER_IDLE; + emit newStatus(state); + emit ready(); + return false; + } + + FilterState nextOperation =3D operationQueue.dequeue(); + + bool actionRequired =3D true; + + switch (nextOperation) + { + case FILTER_CHANGE: + { + state =3D FILTER_CHANGE; + if (m_useLockedFilter) + targetFilterPosition =3D m_ActiveFilters.indexOf(lockedFilter)= + 1; + else if (m_useTargetFilter) + targetFilterPosition =3D m_ActiveFilters.indexOf(targetFilter)= + 1; + m_currentFilterDevice->runCommand(INDI_SET_FILTER, &targetFilterPo= sition); + emit newStatus(state); + } + break; + + case FILTER_OFFSET: + { + state =3D FILTER_OFFSET; + if (m_useLockedFilter) + { + targetFilterOffset =3D lockedFilter->offset() - lastFilterOffs= et; + lastFilterOffset =3D lockedFilter->offset(); + currentFilter =3D lockedFilter; + m_useLockedFilter =3D false; + } + else if (m_useTargetFilter) + { + targetFilterOffset =3D targetFilter->offset() - lastFilterOffs= et; + lastFilterOffset =3D targetFilter->offset(); + currentFilter =3D targetFilter; + m_useTargetFilter =3D false; + } + if (targetFilterOffset =3D=3D 0) + actionRequired =3D false; + else + { + emit newFocusOffset(targetFilterOffset); + emit newStatus(state); + } + } + break; + + case FILTER_AUTOFOCUS: + state =3D FILTER_AUTOFOCUS; + emit newStatus(state); + emit checkFocus(0.01); + break; + + default: + break; + } + + // If an additional action is required, return return and continue lat= er + if (actionRequired) + return true; + // Othereise, continue processing the queue + else + return executeOperationQueue(); +} + +bool FilterManager::executeOneOperation(FilterState operation) +{ + bool actionRequired =3D false; + + switch (operation) + { + default: + break; + } + + return actionRequired; +} + +void FilterManager::setFocusOffsetComplete() +{ + if (state =3D=3D FILTER_OFFSET) + executeOperationQueue(); +} + +double FilterManager::getFilterExposure(const QString &name) const +{ + QString color =3D name; + if (color.isEmpty()) + color =3D m_currentFilterLabels[m_currentFilterPosition-1]; + // Search for locked filter by filter color name + auto pos =3D std::find_if(m_ActiveFilters.begin(), m_ActiveFilters.end= (), [color](OAL::Filter *oneFilter) + {return (oneFilter->color() =3D=3D color);}); + + if (pos !=3D m_ActiveFilters.end()) + return (*pos)->exposure(); + + // Default value + return 1; +} + +bool FilterManager::setFilterExposure(double exposure) +{ + QString color =3D m_currentFilterLabels[m_currentFilterPosition-1]; + for (int i=3D0; i < m_ActiveFilters.count(); i++) + { + if (color =3D=3D 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 =3D std::find_if(m_ActiveFilters.begin(), m_ActiveFilters.end= (), [name](OAL::Filter *oneFilter) + {return (oneFilter->color() =3D=3D name);}); + + if (pos !=3D m_ActiveFilters.end()) + return (*pos)->lockedFilter(); + + // Default value + return "--"; +} + +void FilterManager::removeDevice(ISD::GDInterface *device) +{ = + if (device =3D=3D m_currentFilterDevice) + { + m_FilterNameProperty =3D nullptr; + m_FilterPositionProperty =3D nullptr; + m_currentFilterDevice =3D nullptr; + m_currentFilterLabels.clear(); + m_currentFilterPosition =3D 0; + qDeleteAll(m_ActiveFilters); + m_ActiveFilters.clear(); + delete(filterModel); + filterModel =3D nullptr; + } +} + +void FilterManager::setFocusStatus(Ekos::FocusState focusState) +{ + if (state =3D=3D FILTER_AUTOFOCUS) + { + switch (focusState) + { + case FOCUS_COMPLETE: + executeOperationQueue(); + break; + + case FOCUS_FAILED: + if (++retries =3D=3D 3) + { + retries =3D 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 +#include +#include +#include + #include #include #include -#include + +#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 =3D 1 << 0, + LOCK_POLICY =3D 1 << 1, + OFFSET_POLICY =3D 1 << 2, + AUTOFOCUS_POLICY =3D 1 << 3, + ALL_POLICIES =3D CHANGE_POLICY | OFFSET_POLICY | LOCK_POLICY |= AUTOFOCUS_POLICY + } FilterPolicy; + FilterManager(); - void refreshFilterData(); = - QStringList getFilterLabels(ISD::GDInterface *filter=3Dnullptr); + void refreshFilterModel(); + + QStringList getFilterLabels(bool forceRefresh=3Dfalse); + + int getFilterPosition(bool forceRefresh=3Dfalse); + + // The target position and offset + int getTargetFilterPosition() { return targetFilterPosition; } + int getTargetFilterOffset() { return targetFilterOffset; } + + /** + * @brief getFilterExposure Get optimal exposure time for the specifie= d filter + * @param name filter to obtain exposure time for + * @return exposure time in seconds. + */ + double getFilterExposure(const QString &name =3D QString()) const; + bool setFilterExposure(double exposure); = - bool setFilterPosition(uint8_t position, ISD::GDInterface *filter=3Dnu= llptr); - int getFilterPosition(ISD::GDInterface *filter=3Dnullptr); + /** + * @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 aut= ofocus. "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 filte= r policies for focus operations. + */ + void applyFilterFocusPolicies(); = public slots: - void updateFilterNames(); - void updateFilterPosition(); + // Position. if applyPolicy is true then all filter offsets and autofo= cus & lock policies are applied. + bool setFilterPosition(uint8_t position, FilterPolicy policy =3D ALL_P= OLICIES); + // 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 includi= ng 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 m_filterDevices; ISD::GDInterface *m_currentFilterDevice =3D { nullptr }; - QStringList m_currentFilterList; + + // Position and Labels + QStringList m_currentFilterLabels; int m_currentFilterPosition =3D { -1 }; + double m_currentFilterExposure =3D { -1 }; = // Filter Structure QList m_ActiveFilters; - QList m_FilterList; + OAL::Filter *targetFilter =3D { nullptr }; + OAL::Filter *currentFilter =3D { nullptr }; + OAL::Filter *lockedFilter =3D { nullptr }; + bool m_useLockedFilter =3D { false }; + bool m_useTargetFilter =3D { false }; = - // Focusers - QList m_focuserDevices; - ISD::Focuser *m_currentFocuserDevice =3D { nullptr }; + // Autofocus retries + uint8_t retries =3D { 0 }; = int16_t lastFilterOffset { 0 }; = @@ -80,6 +146,34 @@ private: QSqlTableModel *filterModel =3D { 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 operationQueue; + + FilterState state =3D { FILTER_IDLE }; + + int targetFilterPosition =3D { -1 }; + int targetFilterOffset =3D { - 1 }; + + // Delegates + QPointer lockDelegate; + QPointer noEditDelegate; + QPointer exposureDelegate; + QPointer offsetDelegate; + QPointer useAutoFocusDelegate; + + // Policies + FilterPolicy m_Policy =3D { ALL_POLICIES }; }; + +} diff --git a/kstars/ekos/auxiliary/filtersettings.ui b/kstars/ekos/auxiliar= y/filtersettings.ui index 61f60b3ce..e4df7085f 100644 --- a/kstars/ekos/auxiliary/filtersettings.ui +++ b/kstars/ekos/auxiliary/filtersettings.ui @@ -19,17 +19,17 @@ - FW: + Filter Wheel - - - - 0 - 0 - + + + font-weight:bold; + + + @@ -49,7 +49,23 @@ - + + + QAbstractScrollArea::AdjustToContents + + + QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPres= sed|QAbstractItemView::SelectedClicked + + + QAbstractItemView::SingleSelection + + + true + + + false + + @@ -97,7 +113,7 @@ Qt::Horizontal - QDialogButtonBox::Apply|QDialogButtonBox::Cancel + QDialogButtonBox::Close 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(pa= rent) connect(clearB, SIGNAL(clicked()), this, SLOT(clearLog())); = // Summary - // previewPixmap =3D new QPixmap(QPixmap(":/images/noimage.png")); - - // Filter Manager - filterManager.reset(new FilterManager()); + // previewPixmap =3D 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 =3D 0; = useGuideHead =3D false; @@ -1137,8 +1137,6 @@ void EkosManager::setFilter(ISD::GDInterface *filterD= evice) = alignProcess->addFilter(filterDevice); = - filterManager->addFilter(filterDevice); - if (Options::defaultAlignFW().isEmpty() =3D=3D false) alignProcess->setFilter(Options::defaultAlignFW(), -1); } @@ -1151,9 +1149,7 @@ void EkosManager::setFocuser(ISD::GDInterface *focuse= rDevice) = initFocus(); = - focusProcess->addFocuser(focuserDevice); - - filterManager->addFocuser(focuserDevice); + focusProcess->addFocuser(focuserDevice); = = appendLogText(i18n("%1 focuser is online.", focuserDevice->getDeviceNa= me())); } @@ -1236,6 +1232,7 @@ void EkosManager::removeDevice(ISD::GDInterface *devI= nterface) 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() !=3D nullptr) captureProcess->checkFilter(); @@ -1322,10 +1319,10 @@ void EkosManager::processNewNumber(INumberVectorPro= perty *nvp) return; } = + /* if (!strcmp(nvp->name, "FILTER_SLOT")) - { - filterManager->updateFilterNames(); - /*if (captureProcess.get() !=3D nullptr) + { = + if (captureProcess.get() !=3D nullptr) captureProcess->checkFilter(); = if (focusProcess.get() !=3D nullptr) @@ -1333,8 +1330,9 @@ void EkosManager::processNewNumber(INumberVectorPrope= rty *nvp) = if (alignProcess.get() !=3D 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() !=3D nullptr) + { = + if (captureProcess.get() !=3D nullptr) captureProcess->checkFilter(); = if (focusProcess.get() !=3D nullptr) @@ -1447,10 +1445,11 @@ void EkosManager::processNewProperty(INDI::Property= *prop) = if (alignProcess.get() !=3D nullptr) alignProcess->checkFilter(); - */ + = return; } + */ = if (!strcmp(prop->getName(), "ASTROMETRY_SOLVER")) { @@ -1663,12 +1662,6 @@ void EkosManager::initCapture() SLOT(setFocusStatus(Ekos::FocusState)), Qt::UniqueConnecti= on); connect(focusProcess.get(), &Ekos::Focus::newHFR, captureProcess.g= et(), &Ekos::Capture::setHFR, Qt::UniqueConnection); = - // Adjust focus position - connect(captureProcess.get(), SIGNAL(newFocusOffset(int16_t)), foc= usProcess.get(), SLOT(adjustRelativeFocus(int16_t)), - Qt::UniqueConnection); - connect(focusProcess.get(), SIGNAL(focusPositionAdjusted()), captu= reProcess.get(), SLOT(preparePreCaptureActions()), - Qt::UniqueConnection); - // Meridian Flip connect(captureProcess.get(), SIGNAL(meridianFlipStarted()), focus= Process.get(), SLOT(resetFrame()), Qt::UniqueConnection); } @@ -1735,6 +1728,8 @@ void EkosManager::initAlign() toolsWidget->setTabIcon(index, icon); } = + alignProcess->setFilterManager(filterManager); + if (captureProcess.get() !=3D nullptr) { // Align Status @@ -1752,9 +1747,6 @@ void EkosManager::initAlign() = if (focusProcess.get() !=3D nullptr) { - // Filter lock - //connect(focusProcess.get(), SIGNAL(filterLockUpdated(ISD::GDInte= rface*,int)), alignProcess.get(), - //SLOT(setLockedFilter(ISD::GDInterface*,int)), Qt::Unique= Connection); connect(focusProcess.get(), SIGNAL(newStatus(Ekos::FocusState)), a= lignProcess.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(updateC= urrentHFR(double))); = + focusProcess->setFilterManager(filterManager); + connect(filterManager.data(), SIGNAL(checkFocus(double)), focusProcess= .get(), SLOT(checkFocus(double)), Qt::UniqueConnection); + connect(focusProcess.get(), SIGNAL(newStatus(Ekos::FocusState)), filte= rManager.data(), SLOT(setFocusStatus(Ekos::FocusState)), Qt::UniqueConnecti= on); + connect(filterManager.data(), SIGNAL(newFocusOffset(int16_t)), focusPr= ocess.get(), SLOT(adjustRelativeFocus(int16_t)), + Qt::UniqueConnection); + connect(focusProcess.get(), SIGNAL(focusPositionAdjusted()), filterMan= ager.data(), SLOT(setFocusOffsetComplete()), + Qt::UniqueConnection); + if (Options::ekosLeftIcons()) { QTransform trans; @@ -1815,12 +1815,6 @@ void EkosManager::initFocus() SLOT(setFocusStatus(Ekos::FocusState)), Qt::UniqueConnecti= on); connect(focusProcess.get(), &Ekos::Focus::newHFR, captureProcess.g= et(), &Ekos::Capture::setHFR, Qt::UniqueConnection); = - // Adjust focus position - connect(captureProcess.get(), SIGNAL(newFocusOffset(int16_t)), foc= usProcess.get(), SLOT(adjustRelativeFocus(int16_t)), - Qt::UniqueConnection); - connect(focusProcess.get(), SIGNAL(focusPositionAdjusted()), captu= reProcess.get(), SLOT(preparePreCaptureActions()), - Qt::UniqueConnection); - // Meridian Flip connect(captureProcess.get(), SIGNAL(meridianFlipStarted()), focus= Process.get(), SLOT(resetFrame()), Qt::UniqueConnection); } @@ -1834,9 +1828,6 @@ void EkosManager::initFocus() = if (alignProcess.get() !=3D nullptr) { - // Filter lock - //connect(focusProcess.get(), SIGNAL(filterLockUpdated(ISD::GDInte= rface*,int)), alignProcess.get(), - //SLOT(setLockedFilter(ISD::GDInterface*,int)), Qt::Unique= Connection); connect(focusProcess.get(), SIGNAL(newStatus(Ekos::FocusState)), a= lignProcess.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::EkosMana= ger QList> profiles; = // Filter Manager - QSharedPointer filterManager; + QSharedPointer filterManager; = // Mount Summary QProgressIndicator *mountPI { nullptr };