File indexing completed on 2024-04-28 15:09:10

0001 /*
0002     SPDX-FileCopyrightText: 2017 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "ui_filtersettings.h"
0010 #include "ekos/ekos.h"
0011 
0012 #include <indi/indifilterwheel.h>
0013 #include <indi/indifocuser.h>
0014 #include <oal/filter.h>
0015 
0016 #include <QQueue>
0017 #include <QPointer>
0018 #include <QStandardItemModel>
0019 
0020 class QSqlTableModel;
0021 class ComboDelegate;
0022 class NotEditableDelegate;
0023 class NotEditableDelegate2dp;
0024 class DoubleDelegate;
0025 class IntegerDelegate;
0026 class ToggleDelegate;
0027 
0028 namespace Ekos
0029 {
0030 
0031 class FilterManager : public QDialog, public Ui::FilterSettings
0032 {
0033         Q_OBJECT
0034 
0035         // BuildFilterOffsets is a friend class so it can access methods in FilterManager
0036         friend class BuildFilterOffsets;
0037 
0038     public:
0039 
0040         typedef enum
0041         {
0042             CHANGE_POLICY    = 1 << 0,
0043             OFFSET_POLICY    = 1 << 1,
0044             AUTOFOCUS_POLICY = 1 << 2,
0045             ALL_POLICIES     = CHANGE_POLICY | OFFSET_POLICY | AUTOFOCUS_POLICY,
0046             NO_AUTOFOCUS_POLICY = CHANGE_POLICY | OFFSET_POLICY
0047         } FilterPolicy;
0048 
0049         enum
0050         {
0051             FM_LABEL = 4,
0052             FM_EXPOSURE,
0053             FM_OFFSET,
0054             FM_AUTO_FOCUS,
0055             FM_LOCK_FILTER,
0056             FM_LAST_AF_SOLUTION,
0057             FM_LAST_AF_TEMP,
0058             FM_LAST_AF_ALT,
0059             FM_TICKS_PER_TEMP,
0060             FM_TICKS_PER_ALT,
0061             FM_WAVELENGTH
0062         };
0063 
0064         FilterManager(QWidget *parent = nullptr);
0065 
0066         QJsonObject toJSON();
0067         void setFilterData(const QJsonObject &settings);
0068 
0069         void createFilterModel();
0070         void refreshFilterModel();
0071 
0072         QStringList getFilterLabels(bool forceRefresh = false);
0073         int getFilterPosition(bool forceRefresh = false);
0074         /**
0075          * @brief refreshFilterLabels Update the filter labels from the device and signal changes.
0076          */
0077         void refreshFilterLabels();
0078         /**
0079          * @brief refreshFilterPos Update the filter wheel position and signal changes.
0080          */
0081         void refreshFilterPosition();
0082 
0083         // The target position and offset
0084         int getTargetFilterPosition()
0085         {
0086             return targetFilterPosition;
0087         }
0088         int getTargetFilterOffset()
0089         {
0090             return targetFilterOffset;
0091         }
0092 
0093         /**
0094          * @brief setFilterAbsoluteFocusDetails set params from successful autofocus run
0095          * @param index filter index
0096          * @param focusPos the position of the focus solution
0097          * @param focusTemp the temperature at the time of the focus run
0098          * @param focusAlt the altitude at the time of the focus run
0099          * @return whether function worked or not
0100          */
0101         bool setFilterAbsoluteFocusDetails(int index, int focusPos, double focusTemp, double focusAlt);
0102 
0103         /**
0104          * @brief getFilterAbsoluteFocusDetails get params from the last successful autofocus run
0105          * @param name filter name
0106          * @param focusPos the position of the focus solution
0107          * @param focusTemp the temperature at the time of the focus run
0108          * @param focusAlt the altitude at the time of the focus run
0109          * @return whether function worked or not
0110          */
0111         bool getFilterAbsoluteFocusDetails(const QString &name, int &focusPos, double &focusTemp, double &focusAlt) const;
0112 
0113         // Set absolute focus position, if supported, to the current filter absolute focus position.
0114         bool syncAbsoluteFocusPosition(int index);
0115 
0116         /**
0117          * @brief getFilterExposure Get optimal exposure time for the specified filter
0118          * @param name filter to obtain exposure time for
0119          * @return exposure time in seconds.
0120          */
0121         double getFilterExposure(const QString &name = QString()) const;
0122         bool setFilterExposure(int index, double exposure);
0123 
0124         /**
0125          * @brief getFilterOffset returns the offset for the specified filter
0126          * @param name of the filter
0127          * @return filter offset (INVALID_VALUE in the case of a problem)
0128          */
0129         int getFilterOffset(const QString &name) const;
0130 
0131         /**
0132          * @brief setFilterOffset set the offset for the specified filter
0133          * @param color of the filter
0134          * @param the new filter offset
0135          * @return whether or not the operation was successful
0136          */
0137         bool setFilterOffset(QString color, int offset);
0138 
0139         /**
0140          * @brief getFilterWavelength Get mid-point wavelength for the specified filter
0141          * @param name filter to obtain exposure time for
0142          * @return wavelength in nm.
0143          */
0144         int getFilterWavelength(const QString &name = QString()) const;
0145 
0146         /**
0147          * @brief getFilterTicksPerTemp gets the ticks per degree C
0148          * @param name filter to obtain exposure time for
0149          * @return ticks / degree C
0150          */
0151         double getFilterTicksPerTemp(const QString &name = QString()) const;
0152 
0153         /**
0154          * @brief getFilterTicksPerAlt gets the ticks per degree of altitude
0155          * @param name filter to obtain exposure time for
0156          * @return ticks / degree Alt
0157          */
0158         double getFilterTicksPerAlt(const QString &name = QString()) const;
0159 
0160         /**
0161          * @brief getFilterLock Return filter that should be used when running autofocus for the supplied filter
0162          * For example, "Red" filter can be locked to use "Lum" when doing autofocus. "Green" filter can be locked to "--"
0163          * which means that no filter change is necessary.
0164          * @param name filter which we need to query its locked filter.
0165          * @return locked filter. "--" indicates no locked filter and whatever current filter should be used.
0166          *
0167          */
0168         QString getFilterLock(const QString &name) const;
0169         bool setFilterLock(int index, QString name);
0170 
0171         /**
0172          * @brief setCurrentFilterWheel Set the FilterManager active filter wheel.
0173          * @param filter pointer to filter wheel device
0174          */
0175         void setFilterWheel(ISD::FilterWheel *filter);
0176         ISD::FilterWheel *filterWheel() const
0177         {
0178             return m_FilterWheel;
0179         }
0180 
0181         /**
0182          * @brief setFocusReady Set whether a focuser device is active and in use.
0183          * @param enabled true if focus is ready, false otherwise.
0184          */
0185         void setFocusReady(bool enabled)
0186         {
0187             m_FocusReady = enabled;
0188         }
0189 
0190 
0191         /**
0192          * @brief applyFilterFocusPolicies Check if we need to apply any filter policies for focus operations.
0193          */
0194         void applyFilterFocusPolicies();
0195 
0196         /**
0197          * @brief buildFilterOffsets Launch the Build Filter Offsets utility
0198          * @param FM pointer to the FilterManager
0199          */
0200         void buildFilterOffsets();
0201 
0202     public slots:
0203         // Position. if applyPolicy is true then all filter offsets and autofocus & lock policies are applied.
0204         bool setFilterPosition(uint8_t position, Ekos::FilterManager::FilterPolicy policy = ALL_POLICIES);
0205         // Change filter names
0206         bool setFilterNames(const QStringList &newLabels);
0207         // Offset Request completed
0208         void setFocusOffsetComplete();
0209         // Remove Device
0210         void removeDevice(const QSharedPointer<ISD::GenericDevice> &device);
0211         // Refresh Filters after model update
0212         void reloadFilters();
0213         // Resize the dialog to the contents
0214         void resizeDialog();
0215         // Focus Status
0216         void setFocusStatus(Ekos::FocusState focusState);
0217         // Set absolute focus position
0218         void setFocusAbsolutePosition(int value)
0219         {
0220             m_FocusAbsPosition = value;
0221         }
0222         // Inti filter property after connection
0223         void refreshFilterProperties();
0224         // Signal from BuildFilterOffsets to run Autofocus. Pass onto Focus
0225         void signalRunAutoFocus(bool buildFilterOffsets);
0226         // Signal from BuildFilterOffsets to abort AF run. Pass onto Focus
0227         void signalAbortAutoFocus();
0228         // Signal from Focus that Autofocus has completed - used by BuildFilterOffsets utility
0229         void autoFocusComplete(FocusState completionState, int currentPosition, double currentTemperature, double currentAlt);
0230 
0231     signals:
0232         // Emitted only when there is a change in the filter slot number
0233         void positionChanged(int);
0234         // Emitted when filter change operation completed successfully including any focus offsets or auto-focus operation
0235         void labelsChanged(QStringList);
0236         // Emitted when filter exposure duration changes
0237         void exposureChanged(double);
0238         // Emitted when filter change completed including all required actions
0239         void ready();
0240         // Emitted when operation fails
0241         void failed();
0242         // Status signal
0243         void newStatus(Ekos::FilterState state);
0244         // Run AutoFocus
0245         void runAutoFocus(bool buildOffsets);
0246         // Abort AutoFocus
0247         void abortAutoFocus();
0248         // New Focus offset requested
0249         void newFocusOffset(int value, bool useAbsoluteOffset);
0250         // database was updated
0251         void updated();
0252         // Filter ticks per degree of temperature changed
0253         void ticksPerTempChanged();
0254         // Filter ticks per degree of altitude changed
0255         void ticksPerAltChanged();
0256         // Filter wavelength changed
0257         void wavelengthChanged();
0258         // Pass on Autofocus completed signal to Build Filter Offsets
0259         void autoFocusDone(FocusState completionState, int currentPosition, double currentTemperature, double currentAlt);
0260 
0261     private slots:
0262         void updateProperty(INDI::Property prop);
0263         void processDisconnect();
0264 
0265     private:
0266 
0267         // Filter Wheel Devices
0268         ISD::FilterWheel *m_FilterWheel = { nullptr };
0269 
0270         // Position and Labels
0271         QStringList m_currentFilterLabels;
0272         int m_currentFilterPosition = { -1 };
0273         double m_currentFilterExposure = { -1 };
0274 
0275         // Filter Structure
0276         QList<OAL::Filter *> m_ActiveFilters;
0277         OAL::Filter *targetFilter = { nullptr };
0278         OAL::Filter *currentFilter = { nullptr };
0279         bool m_useTargetFilter = { false };
0280 
0281         // Autofocus retries
0282         uint8_t retries = { 0 };
0283 
0284         int16_t lastFilterOffset { 0 };
0285 
0286         // Table model
0287         QSqlTableModel *m_FilterModel = { nullptr };
0288 
0289         // INDI Properties of current active filter
0290         ITextVectorProperty *m_FilterNameProperty { nullptr };
0291         INumberVectorProperty *m_FilterPositionProperty { nullptr };
0292         ISwitchVectorProperty *m_FilterConfirmSet { nullptr };
0293 
0294         // Accessor function to return filter pointer for the passed in name.
0295         // nullptr is returned if there isn't a match
0296         OAL::Filter * getFilterByName(const QString &name) const;
0297 
0298         // Operation stack
0299         void buildOperationQueue(FilterState operation);
0300         bool executeOperationQueue();
0301         bool executeOneOperation(FilterState operation);
0302 
0303         // Update model
0304         void syncDBToINDI();
0305 
0306         // Get the list of possible lock filters to set in the combo box.
0307         // The list excludes filters already setup with a lock to prevent nested dependencies
0308         QStringList getLockDelegates();
0309 
0310         // Operation Queue
0311         QQueue<FilterState> operationQueue;
0312 
0313         FilterState state = { FILTER_IDLE };
0314 
0315         int targetFilterPosition { -1 };
0316         int targetFilterOffset { - 1 };
0317 
0318 
0319         bool m_FocusReady { false };
0320         bool m_FocusAbsPositionPending { false};
0321         int m_FocusAbsPosition { -1 };
0322 
0323         // Delegates
0324         QPointer<ComboDelegate> lockDelegate;
0325         QPointer<NotEditableDelegate> noEditDelegate;
0326         QPointer<DoubleDelegate> exposureDelegate;
0327         QPointer<IntegerDelegate> offsetDelegate;
0328         QPointer<ToggleDelegate> useAutoFocusDelegate;
0329         QPointer<IntegerDelegate> lastAFSolutionDelegate;
0330         QPointer<DoubleDelegate> lastAFTempDelegate;
0331         QPointer<DoubleDelegate> lastAFAltDelegate;
0332         QPointer<DoubleDelegate> ticksPerTempDelegate;
0333         QPointer<DoubleDelegate> ticksPerAltDelegate;
0334         QPointer<IntegerDelegate> wavelengthDelegate;
0335 
0336         // Policies
0337         FilterPolicy m_Policy = { ALL_POLICIES };
0338 
0339         bool m_ConfirmationPending { false };
0340 };
0341 
0342 }