File indexing completed on 2024-04-28 03:43:07
0001 /* 0002 SPDX-FileCopyrightText: 2017 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "buildfilteroffsets.h" 0008 #include <kstars_debug.h> 0009 0010 #include "indi_debug.h" 0011 #include "kstarsdata.h" 0012 #include "kstars.h" 0013 #include "ekos/focus/focus.h" 0014 #include "ekos/manager.h" 0015 #include "Options.h" 0016 #include "auxiliary/kspaths.h" 0017 #include "auxiliary/ksmessagebox.h" 0018 #include "ekos/auxiliary/tabledelegate.h" 0019 0020 #include <QTimer> 0021 #include <QSqlTableModel> 0022 #include <QSqlDatabase> 0023 #include <QSqlRecord> 0024 0025 #include <basedevice.h> 0026 0027 #include <algorithm> 0028 0029 namespace Ekos 0030 { 0031 0032 FilterManager::FilterManager(QWidget *parent) : QDialog(parent) 0033 { 0034 #ifdef Q_OS_OSX 0035 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); 0036 #endif 0037 0038 setupUi(this); 0039 0040 connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); 0041 connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); 0042 0043 connect(buildOffsetsButton, &QPushButton::clicked, this, &FilterManager::buildFilterOffsets); 0044 0045 kcfg_FlatSyncFocus->setChecked(Options::flatSyncFocus()); 0046 connect(kcfg_FlatSyncFocus, &QCheckBox::toggled, this, [this]() 0047 { 0048 Options::setFlatSyncFocus(kcfg_FlatSyncFocus->isChecked()); 0049 }); 0050 0051 createFilterModel(); 0052 0053 // No Edit delegate 0054 noEditDelegate = new NotEditableDelegate(m_FilterView); 0055 m_FilterView->setItemDelegateForColumn(FM_LABEL, noEditDelegate); 0056 0057 // Exposure delegate 0058 exposureDelegate = new DoubleDelegate(m_FilterView, 0.001, 3600, 1); 0059 m_FilterView->setItemDelegateForColumn(FM_EXPOSURE, exposureDelegate); 0060 0061 // Offset delegate 0062 offsetDelegate = new IntegerDelegate(m_FilterView, -10000, 10000, 1); 0063 m_FilterView->setItemDelegateForColumn(FM_OFFSET, offsetDelegate); 0064 0065 // Auto Focus delegate 0066 useAutoFocusDelegate = new ToggleDelegate(m_FilterView); 0067 m_FilterView->setItemDelegateForColumn(FM_AUTO_FOCUS, useAutoFocusDelegate); 0068 0069 // Set Delegates 0070 lockDelegate = new ComboDelegate(m_FilterView); 0071 m_FilterView->setItemDelegateForColumn(FM_LOCK_FILTER, lockDelegate); 0072 lockDelegate->setValues(getLockDelegates()); 0073 0074 // Last AF solution delegate. Set by Autofocus but make editable in case bad data 0075 // corrections need to be made 0076 lastAFSolutionDelegate = new IntegerDelegate(m_FilterView, 0, 1000000, 1); 0077 m_FilterView->setItemDelegateForColumn(FM_LAST_AF_SOLUTION, lastAFSolutionDelegate); 0078 0079 // Last AF solution temperature delegate 0080 lastAFTempDelegate = new DoubleDelegate(m_FilterView, -60.0, 60.0, 1.0); 0081 m_FilterView->setItemDelegateForColumn(FM_LAST_AF_TEMP, lastAFTempDelegate); 0082 0083 // Last AF solution altitude delegate 0084 lastAFAltDelegate = new DoubleDelegate(m_FilterView, 0.0, 90.0, 1.0); 0085 m_FilterView->setItemDelegateForColumn(FM_LAST_AF_ALT, lastAFAltDelegate); 0086 0087 // Ticks / °C delegate 0088 ticksPerTempDelegate = new DoubleDelegate(m_FilterView, -10000.0, 10000.0, 1.0); 0089 m_FilterView->setItemDelegateForColumn(FM_TICKS_PER_TEMP, ticksPerTempDelegate); 0090 0091 // Ticks / °Altitude delegate 0092 ticksPerAltDelegate = new DoubleDelegate(m_FilterView, -10000.0, 10000.0, 1.0); 0093 m_FilterView->setItemDelegateForColumn(FM_TICKS_PER_ALT, ticksPerAltDelegate); 0094 0095 // Wavelength delegate 0096 wavelengthDelegate = new IntegerDelegate(m_FilterView, 200, 1000, 50); 0097 m_FilterView->setItemDelegateForColumn(FM_WAVELENGTH, wavelengthDelegate); 0098 } 0099 0100 void FilterManager::createFilterModel() 0101 { 0102 QSqlDatabase userdb = QSqlDatabase::database(KStarsData::Instance()->userdb()->connectionName()); 0103 0104 m_FilterModel = new QSqlTableModel(this, userdb); 0105 m_FilterView->setModel(m_FilterModel); 0106 m_FilterModel->setTable("filter"); 0107 m_FilterModel->setEditStrategy(QSqlTableModel::OnFieldChange); 0108 0109 m_FilterModel->setHeaderData(FM_LABEL, Qt::Horizontal, i18n("Filter")); 0110 0111 m_FilterModel->setHeaderData(FM_EXPOSURE, Qt::Horizontal, i18n("Filter exposure time during focus"), Qt::ToolTipRole); 0112 m_FilterModel->setHeaderData(FM_EXPOSURE, Qt::Horizontal, i18n("Exposure")); 0113 0114 m_FilterModel->setHeaderData(FM_OFFSET, Qt::Horizontal, i18n("Relative offset in steps"), Qt::ToolTipRole); 0115 m_FilterModel->setHeaderData(FM_OFFSET, Qt::Horizontal, i18n("Offset")); 0116 0117 m_FilterModel->setHeaderData(FM_AUTO_FOCUS, Qt::Horizontal, i18n("Start Auto Focus when filter is activated"), 0118 Qt::ToolTipRole); 0119 m_FilterModel->setHeaderData(FM_AUTO_FOCUS, Qt::Horizontal, i18n("Auto Focus")); 0120 0121 m_FilterModel->setHeaderData(FM_LOCK_FILTER, Qt::Horizontal, i18n("Lock specific filter when running Auto Focus"), 0122 Qt::ToolTipRole); 0123 m_FilterModel->setHeaderData(FM_LOCK_FILTER, Qt::Horizontal, i18n("Lock Filter")); 0124 0125 m_FilterModel->setHeaderData(FM_LAST_AF_SOLUTION, Qt::Horizontal, 0126 i18n("Last AF solution. Updated automatically by the autofocus process."), Qt::ToolTipRole); 0127 m_FilterModel->setHeaderData(FM_LAST_AF_SOLUTION, Qt::Horizontal, i18n("Last AF Solution")); 0128 0129 m_FilterModel->setHeaderData(FM_LAST_AF_TEMP, Qt::Horizontal, 0130 i18n("The temperature of the last AF solution. Updated automatically by the autofocus process."), Qt::ToolTipRole); 0131 m_FilterModel->setHeaderData(FM_LAST_AF_TEMP, Qt::Horizontal, i18n("Last AF Temp (°C)")); 0132 0133 m_FilterModel->setHeaderData(FM_LAST_AF_ALT, Qt::Horizontal, 0134 i18n("The altitude of the last AF solution. Updated automatically by the autofocus process."), Qt::ToolTipRole); 0135 m_FilterModel->setHeaderData(FM_LAST_AF_ALT, Qt::Horizontal, i18n("Last AF Alt (°Alt)")); 0136 0137 m_FilterModel->setHeaderData(FM_TICKS_PER_TEMP, Qt::Horizontal, 0138 i18n("The number of ticks per °C increase in temperature. +ve for outward focuser movement"), Qt::ToolTipRole); 0139 m_FilterModel->setHeaderData(FM_TICKS_PER_TEMP, Qt::Horizontal, i18n("Ticks / °C")); 0140 0141 m_FilterModel->setHeaderData(FM_TICKS_PER_ALT, Qt::Horizontal, 0142 i18n("The number of ticks per degree increase in altitude. +ve for outward focuser movement"), Qt::ToolTipRole); 0143 m_FilterModel->setHeaderData(FM_TICKS_PER_ALT, Qt::Horizontal, i18n("Ticks / °Alt")); 0144 0145 m_FilterModel->setHeaderData(FM_WAVELENGTH, Qt::Horizontal, i18n("Mid-point wavelength of filter in nm"), Qt::ToolTipRole); 0146 m_FilterModel->setHeaderData(FM_WAVELENGTH, Qt::Horizontal, i18n("Wavelength")); 0147 0148 connect(m_FilterModel, &QSqlTableModel::dataChanged, this, &FilterManager::updated); 0149 0150 connect(m_FilterModel, &QSqlTableModel::dataChanged, this, [this](const QModelIndex & topLeft, const QModelIndex &, 0151 const QVector<int> &) 0152 { 0153 reloadFilters(); 0154 if (topLeft.column() == FM_EXPOSURE) 0155 emit exposureChanged(m_FilterModel->data(topLeft).toDouble()); 0156 else if (topLeft.column() == FM_LOCK_FILTER) 0157 { 0158 // Don't allow the lock filter to be set to the current filter - circular dependancy 0159 // Don't allow the lock to be set if this filter is a lock for another filter - nested dependancy 0160 QString lock = m_FilterModel->data(m_FilterModel->index(topLeft.row(), topLeft.column())).toString(); 0161 QString filter = m_FilterModel->data(m_FilterModel->index(topLeft.row(), FM_LABEL)).toString(); 0162 bool alreadyALock = false; 0163 for (int i = 0; i < m_ActiveFilters.count(); i++) 0164 { 0165 if (m_ActiveFilters[i]->lockedFilter() == filter) 0166 { 0167 alreadyALock = true; 0168 break; 0169 } 0170 } 0171 if (alreadyALock || (lock == filter)) 0172 { 0173 m_FilterModel->setData(m_FilterModel->index(topLeft.row(), topLeft.column()), NULL_FILTER); 0174 } 0175 // Update the acceptable values in the lockDelegate 0176 lockDelegate->setValues(getLockDelegates()); 0177 } 0178 else if (topLeft.column() == FM_TICKS_PER_TEMP) 0179 emit ticksPerTempChanged(); 0180 else if (topLeft.column() == FM_TICKS_PER_ALT) 0181 emit ticksPerAltChanged(); 0182 else if (topLeft.column() == FM_WAVELENGTH) 0183 emit wavelengthChanged(); 0184 }); 0185 } 0186 0187 void FilterManager::refreshFilterModel() 0188 { 0189 if (m_FilterWheel == nullptr || m_currentFilterLabels.empty()) 0190 return; 0191 0192 // In case filter model was cleared due to a device disconnect 0193 if (m_FilterModel == nullptr) 0194 createFilterModel(); 0195 0196 QString vendor(m_FilterWheel->getDeviceName()); 0197 m_FilterModel->setFilter(QString("vendor='%1'").arg(vendor)); 0198 m_FilterModel->select(); 0199 0200 m_FilterView->hideColumn(0); 0201 m_FilterView->hideColumn(1); 0202 m_FilterView->hideColumn(2); 0203 m_FilterView->hideColumn(3); 0204 0205 // If we have an existing table but it doesn't match the number of current filters 0206 // then we remove it. 0207 if (m_FilterModel->rowCount() > 0 && m_FilterModel->rowCount() != m_currentFilterLabels.count()) 0208 { 0209 for (int i = 0; i < m_FilterModel->rowCount(); i++) 0210 m_FilterModel->removeRow(i); 0211 0212 m_FilterModel->select(); 0213 } 0214 0215 // If it is first time, let's populate data 0216 if (m_FilterModel->rowCount() == 0) 0217 { 0218 filterProperties *fp = new filterProperties(vendor, "", "", ""); 0219 for (QString &filter : m_currentFilterLabels) 0220 { 0221 fp->color = filter; 0222 KStarsData::Instance()->userdb()->AddFilter(fp); 0223 } 0224 0225 m_FilterModel->select(); 0226 } 0227 // Make sure all the filter colors match DB. If not update model to sync with INDI filter values 0228 else 0229 { 0230 for (int i = 0; i < m_FilterModel->rowCount(); ++i) 0231 { 0232 QModelIndex index = m_FilterModel->index(i, FM_LABEL); 0233 if (m_FilterModel->data(index).toString() != m_currentFilterLabels[i]) 0234 { 0235 m_FilterModel->setData(index, m_currentFilterLabels[i]); 0236 } 0237 } 0238 } 0239 0240 lockDelegate->setValues(getLockDelegates()); 0241 0242 reloadFilters(); 0243 resizeDialog(); 0244 } 0245 0246 void FilterManager::resizeDialog() 0247 { 0248 // Resize the columns to the data and then the dialog to the rows and columns 0249 m_FilterView->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); 0250 int width = m_FilterView->horizontalHeader()->length() + 50; 0251 int height = label->height() + m_FilterView->verticalHeader()->length() + label_2->height() + buttonBox->height() + 100; 0252 this->resize(width, height); 0253 } 0254 // This function processes the list of active filters and returns a list of filters that could be lock filters 0255 // i.e. that don't themselves have locks. 0256 QStringList FilterManager::getLockDelegates() 0257 { 0258 QStringList lockDelegates; 0259 0260 for (int i = 0; i < m_ActiveFilters.count(); i++) 0261 { 0262 if (m_ActiveFilters[i]->lockedFilter() == NULL_FILTER) 0263 lockDelegates.append(m_ActiveFilters[i]->color()); 0264 } 0265 return lockDelegates; 0266 } 0267 0268 void FilterManager::reloadFilters() 0269 { 0270 qDeleteAll(m_ActiveFilters); 0271 currentFilter = nullptr; 0272 targetFilter = nullptr; 0273 m_ActiveFilters.clear(); 0274 operationQueue.clear(); 0275 0276 filterProperties *fp = new filterProperties("", "", "", ""); 0277 0278 for (int i = 0; i < m_FilterModel->rowCount(); ++i) 0279 { 0280 QSqlRecord record = m_FilterModel->record(i); 0281 QString id = record.value("id").toString(); 0282 0283 fp->vendor = record.value("Vendor").toString(); 0284 fp->model = record.value("Model").toString(); 0285 fp->type = record.value("Type").toString(); 0286 fp->color = record.value("Color").toString(); 0287 fp->exposure = record.value("Exposure").toDouble(); 0288 fp->offset = record.value("Offset").toInt(); 0289 fp->lockedFilter = record.value("LockedFilter").toString(); 0290 fp->useAutoFocus = record.value("UseAutoFocus").toInt() == 1; 0291 fp->absFocusPos = record.value("AbsoluteFocusPosition").toInt(); 0292 fp->focusTemperature = record.value("FocusTemperature").toDouble(); 0293 fp->focusAltitude = record.value("FocusAltitude").toDouble(); 0294 fp->focusTicksPerTemp = record.value("FocusTicksPerTemp").toDouble(); 0295 fp->focusTicksPerAlt = record.value("FocusTicksPerAlt").toDouble(); 0296 fp->wavelength = record.value("Wavelength").toInt(); 0297 OAL::Filter *o = new OAL::Filter(id, fp); 0298 m_ActiveFilters.append(o); 0299 } 0300 } 0301 0302 void FilterManager::setFilterWheel(ISD::FilterWheel *filter) 0303 { 0304 // Return if same device and we already initialized the properties. 0305 if (m_FilterWheel == filter && m_FilterNameProperty && m_FilterPositionProperty) 0306 return; 0307 else if (m_FilterWheel) 0308 m_FilterWheel->disconnect(this); 0309 0310 m_FilterWheel = filter; 0311 0312 m_FilterNameProperty = nullptr; 0313 m_FilterPositionProperty = nullptr; 0314 m_FilterConfirmSet = nullptr; 0315 0316 if (!m_FilterWheel) 0317 return; 0318 0319 connect(m_FilterWheel, &ISD::ConcreteDevice::propertyUpdated, this, &FilterManager::updateProperty); 0320 connect(m_FilterWheel, &ISD::ConcreteDevice::Disconnected, this, &FilterManager::processDisconnect); 0321 0322 refreshFilterProperties(); 0323 } 0324 0325 void FilterManager::refreshFilterProperties() 0326 { 0327 if (m_FilterNameProperty && m_FilterPositionProperty) 0328 { 0329 if (m_FilterConfirmSet == nullptr) 0330 m_FilterConfirmSet = m_FilterWheel->getSwitch("CONFIRM_FILTER_SET"); 0331 0332 // All filters are synced up? 0333 if (m_currentFilterLabels.count() == m_FilterNameProperty->ntp) 0334 return; 0335 } 0336 0337 filterNameLabel->setText(m_FilterWheel->getDeviceName()); 0338 0339 m_currentFilterLabels.clear(); 0340 0341 m_FilterNameProperty = m_FilterWheel->getText("FILTER_NAME"); 0342 m_FilterPositionProperty = m_FilterWheel->getNumber("FILTER_SLOT"); 0343 m_FilterConfirmSet = m_FilterWheel->getSwitch("CONFIRM_FILTER_SET"); 0344 0345 refreshFilterLabels(); 0346 refreshFilterPosition(); 0347 0348 if (m_currentFilterPosition >= 1 && m_currentFilterPosition <= m_ActiveFilters.count()) 0349 lastFilterOffset = m_ActiveFilters[m_currentFilterPosition - 1]->offset(); 0350 } 0351 0352 QStringList FilterManager::getFilterLabels(bool forceRefresh) 0353 { 0354 if ((!m_currentFilterLabels.empty() && forceRefresh == false) || !m_FilterNameProperty || !m_FilterPositionProperty) 0355 return m_currentFilterLabels; 0356 0357 QStringList filterList; 0358 0359 for (int i = 0; i < m_FilterPositionProperty->np[0].max; i++) 0360 { 0361 if (m_FilterNameProperty != nullptr && (i < m_FilterNameProperty->ntp)) 0362 filterList.append(m_FilterNameProperty->tp[i].text); 0363 } 0364 0365 return filterList; 0366 } 0367 0368 int FilterManager::getFilterPosition(bool forceRefresh) 0369 { 0370 if (forceRefresh == false || m_FilterPositionProperty == nullptr) 0371 return m_currentFilterPosition; 0372 0373 return static_cast<int>(m_FilterPositionProperty->np[0].value); 0374 } 0375 0376 void FilterManager::refreshFilterLabels() 0377 { 0378 QList filters = getFilterLabels(true); 0379 0380 if (filters != m_currentFilterLabels) 0381 { 0382 m_currentFilterLabels = filters; 0383 refreshFilterModel(); 0384 0385 emit labelsChanged(filters); 0386 0387 // refresh position after filter changes 0388 refreshFilterPosition(); 0389 } 0390 } 0391 0392 void FilterManager::refreshFilterPosition() 0393 { 0394 0395 int pos = getFilterPosition(true); 0396 if (pos != m_currentFilterPosition) 0397 { 0398 m_currentFilterPosition = pos; 0399 emit positionChanged(pos); 0400 } 0401 } 0402 0403 bool FilterManager::setFilterPosition(uint8_t position, FilterPolicy policy) 0404 { 0405 // Position 1 to Max 0406 if (position > m_ActiveFilters.count()) 0407 return false; 0408 0409 m_Policy = policy; 0410 currentFilter = m_ActiveFilters[m_currentFilterPosition - 1]; 0411 targetFilter = m_ActiveFilters[position - 1]; 0412 0413 if (currentFilter == targetFilter) 0414 { 0415 emit ready(); 0416 return true; 0417 } 0418 0419 buildOperationQueue(FILTER_CHANGE); 0420 0421 executeOperationQueue(); 0422 0423 return true; 0424 } 0425 0426 0427 void FilterManager::updateProperty(INDI::Property prop) 0428 { 0429 if (m_FilterWheel == nullptr || m_FilterWheel->getDeviceName() != prop.getDeviceName()) 0430 return; 0431 0432 if (prop.isNameMatch("FILTER_NAME")) 0433 { 0434 auto tvp = prop.getText(); 0435 m_FilterNameProperty = tvp; 0436 0437 refreshFilterLabels(); 0438 } 0439 else if (prop.isNameMatch("FILTER_SLOT")) 0440 { 0441 auto nvp = prop.getNumber(); 0442 if (nvp->s != IPS_OK) 0443 return; 0444 0445 m_FilterPositionProperty = nvp; 0446 refreshFilterPosition(); 0447 0448 if (state == FILTER_CHANGE) 0449 executeOperationQueue(); 0450 // If filter is changed externally, record its current offset as the starting offset. 0451 else if (state == FILTER_IDLE && m_ActiveFilters.count() >= m_currentFilterPosition) 0452 lastFilterOffset = m_ActiveFilters[m_currentFilterPosition - 1]->offset(); 0453 } 0454 } 0455 0456 0457 void FilterManager::processDisconnect() 0458 { 0459 m_currentFilterLabels.clear(); 0460 m_currentFilterPosition = -1; 0461 m_FilterNameProperty = nullptr; 0462 m_FilterPositionProperty = nullptr; 0463 } 0464 0465 void FilterManager::buildOperationQueue(FilterState operation) 0466 { 0467 operationQueue.clear(); 0468 m_useTargetFilter = false; 0469 0470 switch (operation) 0471 { 0472 case FILTER_CHANGE: 0473 { 0474 if ( (m_Policy & CHANGE_POLICY) && targetFilter != currentFilter) 0475 m_useTargetFilter = true; 0476 0477 if (m_useTargetFilter) 0478 { 0479 operationQueue.enqueue(FILTER_CHANGE); 0480 if (m_FocusReady && (m_Policy & OFFSET_POLICY)) 0481 operationQueue.enqueue(FILTER_OFFSET); 0482 else 0483 { 0484 // Keep track of filter and offset either here or after the offset has been processed 0485 lastFilterOffset = targetFilter->offset(); 0486 currentFilter = targetFilter; 0487 } 0488 0489 } 0490 0491 if (m_FocusReady && (m_Policy & AUTOFOCUS_POLICY) && targetFilter->useAutoFocus()) 0492 operationQueue.enqueue(FILTER_AUTOFOCUS); 0493 } 0494 break; 0495 0496 default: 0497 break; 0498 } 0499 } 0500 0501 bool FilterManager::executeOperationQueue() 0502 { 0503 if (operationQueue.isEmpty()) 0504 { 0505 state = FILTER_IDLE; 0506 emit newStatus(state); 0507 emit ready(); 0508 return false; 0509 } 0510 0511 FilterState nextOperation = operationQueue.dequeue(); 0512 0513 bool actionRequired = true; 0514 0515 switch (nextOperation) 0516 { 0517 case FILTER_CHANGE: 0518 { 0519 if (m_ConfirmationPending) 0520 return true; 0521 0522 state = FILTER_CHANGE; 0523 if (m_useTargetFilter) 0524 targetFilterPosition = m_ActiveFilters.indexOf(targetFilter) + 1; 0525 m_FilterWheel->setPosition(targetFilterPosition); 0526 0527 emit newStatus(state); 0528 0529 if (m_FilterConfirmSet) 0530 { 0531 connect(KSMessageBox::Instance(), &KSMessageBox::accepted, this, [this]() 0532 { 0533 KSMessageBox::Instance()->disconnect(this); 0534 m_ConfirmationPending = false; 0535 m_FilterWheel->confirmFilter(); 0536 }); 0537 connect(KSMessageBox::Instance(), &KSMessageBox::rejected, this, [this]() 0538 { 0539 KSMessageBox::Instance()->disconnect(this); 0540 m_ConfirmationPending = false; 0541 }); 0542 0543 m_ConfirmationPending = true; 0544 0545 KSMessageBox::Instance()->questionYesNo(i18n("Set filter to %1. Is filter set?", targetFilter->color()), 0546 i18n("Confirm Filter")); 0547 } 0548 } 0549 break; 0550 0551 case FILTER_OFFSET: 0552 { 0553 state = FILTER_OFFSET; 0554 if (m_useTargetFilter) 0555 { 0556 targetFilterOffset = targetFilter->offset() - lastFilterOffset; 0557 lastFilterOffset = targetFilter->offset(); 0558 currentFilter = targetFilter; 0559 m_useTargetFilter = false; 0560 } 0561 if (targetFilterOffset == 0) 0562 actionRequired = false; 0563 else 0564 { 0565 emit newFocusOffset(targetFilterOffset, false); 0566 emit newStatus(state); 0567 } 0568 } 0569 break; 0570 0571 case FILTER_AUTOFOCUS: 0572 state = FILTER_AUTOFOCUS; 0573 qCDebug(KSTARS) << "FilterManager.cpp is triggering autofocus."; 0574 emit newStatus(state); 0575 emit runAutoFocus(false); 0576 break; 0577 0578 default: 0579 break; 0580 } 0581 0582 // If an additional action is required, return return and continue later 0583 if (actionRequired) 0584 return true; 0585 // Otherwise, continue processing the queue 0586 else 0587 return executeOperationQueue(); 0588 } 0589 0590 bool FilterManager::executeOneOperation(FilterState operation) 0591 { 0592 bool actionRequired = false; 0593 0594 switch (operation) 0595 { 0596 default: 0597 break; 0598 } 0599 0600 return actionRequired; 0601 } 0602 0603 void FilterManager::setFocusOffsetComplete() 0604 { 0605 if (state == FILTER_OFFSET) 0606 executeOperationQueue(); 0607 } 0608 0609 double FilterManager::getFilterExposure(const QString &name) const 0610 { 0611 auto filterDetails = getFilterByName(name); 0612 if (filterDetails) 0613 return filterDetails->exposure(); 0614 0615 // Default value 0616 return 1; 0617 } 0618 0619 bool FilterManager::setFilterExposure(int index, double exposure) 0620 { 0621 if (m_currentFilterLabels.empty()) 0622 return false; 0623 0624 QString color = m_currentFilterLabels[index]; 0625 for (int i = 0; i < m_ActiveFilters.count(); i++) 0626 { 0627 if (color == m_ActiveFilters[i]->color()) 0628 { 0629 m_FilterModel->setData(m_FilterModel->index(i, FM_EXPOSURE), exposure); 0630 m_FilterModel->submitAll(); 0631 refreshFilterModel(); 0632 return true; 0633 } 0634 } 0635 0636 return false; 0637 } 0638 0639 int FilterManager::getFilterOffset(const QString &name) const 0640 { 0641 int offset = INVALID_VALUE; 0642 auto filterDetails = getFilterByName(name); 0643 if (filterDetails) 0644 offset = filterDetails->offset(); 0645 0646 return offset; 0647 } 0648 0649 bool FilterManager::setFilterOffset(QString color, int offset) 0650 { 0651 if (m_currentFilterLabels.empty()) 0652 return false; 0653 0654 for (int i = 0; i < m_ActiveFilters.count(); i++) 0655 { 0656 if (color == m_ActiveFilters[i]->color()) 0657 { 0658 m_FilterModel->setData(m_FilterModel->index(i, FM_OFFSET), offset); 0659 m_FilterModel->submitAll(); 0660 refreshFilterModel(); 0661 return true; 0662 } 0663 } 0664 0665 return false; 0666 } 0667 0668 bool FilterManager::getFilterAbsoluteFocusDetails(const QString &name, int &focusPos, double &focusTemp, 0669 double &focusAlt) const 0670 { 0671 auto filterDetails = getFilterByName(name); 0672 if (filterDetails) 0673 { 0674 focusPos = filterDetails->absoluteFocusPosition(); 0675 focusTemp = filterDetails->focusTemperature(); 0676 focusAlt = filterDetails->focusAltitude(); 0677 return true; 0678 } 0679 0680 return false; 0681 } 0682 0683 bool FilterManager::setFilterAbsoluteFocusDetails(int index, int focusPos, double focusTemp, double focusAlt) 0684 { 0685 if (index < 0 || index >= m_currentFilterLabels.count()) 0686 return false; 0687 0688 QString color = m_currentFilterLabels[index]; 0689 for (int i = 0; i < m_ActiveFilters.count(); i++) 0690 { 0691 if (color == m_ActiveFilters[i]->color()) 0692 { 0693 m_FilterModel->setData(m_FilterModel->index(i, FM_LAST_AF_SOLUTION), focusPos); 0694 m_FilterModel->setData(m_FilterModel->index(i, FM_LAST_AF_TEMP), focusTemp); 0695 m_FilterModel->setData(m_FilterModel->index(i, FM_LAST_AF_ALT), focusAlt); 0696 m_FilterModel->submitAll(); 0697 refreshFilterModel(); 0698 return true; 0699 } 0700 } 0701 0702 return false; 0703 } 0704 0705 QString FilterManager::getFilterLock(const QString &name) const 0706 { 0707 auto filterDetails = getFilterByName(name); 0708 if (filterDetails) 0709 return filterDetails->lockedFilter(); 0710 0711 // Default value 0712 return NULL_FILTER; 0713 } 0714 0715 bool FilterManager::setFilterLock(int index, QString name) 0716 { 0717 if (m_currentFilterLabels.empty()) 0718 return false; 0719 0720 QString color = m_currentFilterLabels[index]; 0721 for (int i = 0; i < m_ActiveFilters.count(); i++) 0722 { 0723 if (color == m_ActiveFilters[i]->color()) 0724 { 0725 m_FilterModel->setData(m_FilterModel->index(i, FM_LOCK_FILTER), name); 0726 m_FilterModel->submitAll(); 0727 refreshFilterModel(); 0728 return true; 0729 } 0730 } 0731 0732 return false; 0733 } 0734 0735 int FilterManager::getFilterWavelength(const QString &name) const 0736 { 0737 auto filterDetails = getFilterByName(name); 0738 if (filterDetails) 0739 return filterDetails->wavelength(); 0740 0741 // Default value 0742 return 500; 0743 } 0744 0745 double FilterManager::getFilterTicksPerTemp(const QString &name) const 0746 { 0747 auto filterDetails = getFilterByName(name); 0748 if (filterDetails) 0749 return filterDetails->focusTicksPerTemp(); 0750 0751 // Something's wrong so return 0 0752 return 0.0; 0753 } 0754 0755 double FilterManager::getFilterTicksPerAlt(const QString &name) const 0756 { 0757 auto filterDetails = getFilterByName(name); 0758 if (filterDetails) 0759 return filterDetails->focusTicksPerAlt(); 0760 0761 // Something's wrong so return 0 0762 return 0.0; 0763 } 0764 0765 OAL::Filter * FilterManager::getFilterByName(const QString &name) const 0766 { 0767 if (m_currentFilterLabels.empty() || 0768 m_currentFilterPosition < 1 || 0769 m_currentFilterPosition > m_currentFilterLabels.count()) 0770 return nullptr; 0771 0772 QString color = name; 0773 if (color.isEmpty()) 0774 color = m_currentFilterLabels[m_currentFilterPosition - 1]; 0775 0776 auto pos = std::find_if(m_ActiveFilters.begin(), m_ActiveFilters.end(), [color](OAL::Filter * oneFilter) 0777 { 0778 return (oneFilter->color() == color); 0779 }); 0780 0781 if (pos != m_ActiveFilters.end()) 0782 return (*pos); 0783 else 0784 return nullptr; 0785 } 0786 0787 void FilterManager::removeDevice(const QSharedPointer<ISD::GenericDevice> &device) 0788 { 0789 if (m_FilterWheel && (m_FilterWheel->getDeviceName() == device->getDeviceName())) 0790 { 0791 m_FilterNameProperty = nullptr; 0792 m_FilterPositionProperty = nullptr; 0793 m_FilterWheel = nullptr; 0794 m_currentFilterLabels.clear(); 0795 m_currentFilterPosition = 0; 0796 qDeleteAll(m_ActiveFilters); 0797 m_ActiveFilters.clear(); 0798 delete(m_FilterModel); 0799 m_FilterModel = nullptr; 0800 } 0801 } 0802 0803 void FilterManager::setFocusStatus(Ekos::FocusState focusState) 0804 { 0805 if (state == FILTER_AUTOFOCUS) 0806 { 0807 switch (focusState) 0808 { 0809 case FOCUS_COMPLETE: 0810 executeOperationQueue(); 0811 break; 0812 0813 case FOCUS_FAILED: 0814 if (++retries == 3) 0815 { 0816 retries = 0; 0817 emit failed(); 0818 return; 0819 } 0820 // Restart again 0821 emit runAutoFocus(false); 0822 break; 0823 0824 default: 0825 break; 0826 0827 } 0828 } 0829 } 0830 0831 bool FilterManager::syncAbsoluteFocusPosition(int index) 0832 { 0833 if (index < 0 || index > m_ActiveFilters.count()) 0834 { 0835 // We've been asked to set the focus position but something's wrong because 0836 // the passed in filter index is bad. Give up and return true - returning false 0837 // just results in an infinite retry loop. 0838 qCWarning(KSTARS_INDI) << __FUNCTION__ << "index" << index << "is out of bounds."; 0839 return true; 0840 } 0841 0842 // By default filter absolute focus offset is zero 0843 // JM 2023.07.03: So if it is zero, we return immediately. 0844 auto absFocusPos = m_ActiveFilters[index]->absoluteFocusPosition(); 0845 0846 if (m_FocusAbsPosition == absFocusPos || absFocusPos <= 0) 0847 { 0848 m_FocusAbsPositionPending = false; 0849 return true; 0850 } 0851 else if (m_FocusAbsPositionPending == false) 0852 { 0853 m_FocusAbsPositionPending = true; 0854 emit newFocusOffset(absFocusPos, true); 0855 } 0856 0857 return false; 0858 } 0859 0860 bool FilterManager::setFilterNames(const QStringList &newLabels) 0861 { 0862 if (m_FilterWheel == nullptr || m_currentFilterLabels.empty()) 0863 return false; 0864 0865 m_FilterWheel->setLabels(newLabels); 0866 return true; 0867 } 0868 0869 QJsonObject FilterManager::toJSON() 0870 { 0871 if (!m_FilterWheel) 0872 return QJsonObject(); 0873 0874 QJsonArray filters; 0875 0876 for (int i = 0; i < m_FilterModel->rowCount(); ++i) 0877 { 0878 QJsonObject oneFilter = 0879 { 0880 {"index", i}, 0881 {"label", m_FilterModel->data(m_FilterModel->index(i, FM_LABEL)).toString()}, 0882 {"exposure", m_FilterModel->data(m_FilterModel->index(i, FM_EXPOSURE)).toDouble()}, 0883 {"offset", m_FilterModel->data(m_FilterModel->index(i, FM_OFFSET)).toInt()}, 0884 {"autofocus", m_FilterModel->data(m_FilterModel->index(i, FM_AUTO_FOCUS)).toBool()}, 0885 {"lock", m_FilterModel->data(m_FilterModel->index(i, FM_LOCK_FILTER)).toString()}, 0886 {"lastafsolution", m_FilterModel->data(m_FilterModel->index(i, FM_LAST_AF_SOLUTION)).toInt()}, 0887 {"lastaftemp", m_FilterModel->data(m_FilterModel->index(i, FM_LAST_AF_TEMP)).toDouble()}, 0888 {"lastafalt", m_FilterModel->data(m_FilterModel->index(i, FM_LAST_AF_ALT)).toDouble()}, 0889 {"tickspertemp", m_FilterModel->data(m_FilterModel->index(i, FM_TICKS_PER_TEMP)).toDouble()}, 0890 {"ticksperalt", m_FilterModel->data(m_FilterModel->index(i, FM_TICKS_PER_ALT)).toDouble()}, 0891 {"wavelength", m_FilterModel->data(m_FilterModel->index(i, FM_WAVELENGTH)).toInt()}, 0892 }; 0893 0894 filters.append(oneFilter); 0895 } 0896 0897 QJsonObject data = 0898 { 0899 {"device", m_FilterWheel->getDeviceName()}, 0900 {"filters", filters} 0901 }; 0902 0903 return data; 0904 0905 } 0906 0907 void FilterManager::setFilterData(const QJsonObject &settings) 0908 { 0909 if (!m_FilterWheel) 0910 return; 0911 0912 if (settings["device"].toString() != m_FilterWheel->getDeviceName()) 0913 return; 0914 0915 QJsonArray filters = settings["filters"].toArray(); 0916 QStringList labels = getFilterLabels(); 0917 0918 for (auto oneFilterRef : filters) 0919 { 0920 QJsonObject oneFilter = oneFilterRef.toObject(); 0921 int row = oneFilter["index"].toInt(); 0922 0923 labels[row] = oneFilter["label"].toString(); 0924 m_FilterModel->setData(m_FilterModel->index(row, FM_LABEL), oneFilter["label"].toString()); 0925 m_FilterModel->setData(m_FilterModel->index(row, FM_EXPOSURE), oneFilter["exposure"].toDouble()); 0926 m_FilterModel->setData(m_FilterModel->index(row, FM_OFFSET), oneFilter["offset"].toInt()); 0927 m_FilterModel->setData(m_FilterModel->index(row, FM_AUTO_FOCUS), oneFilter["autofocus"].toBool()); 0928 m_FilterModel->setData(m_FilterModel->index(row, FM_LOCK_FILTER), oneFilter["lock"].toString()); 0929 m_FilterModel->setData(m_FilterModel->index(row, FM_LAST_AF_SOLUTION), oneFilter["lastafsolution"].toInt()); 0930 m_FilterModel->setData(m_FilterModel->index(row, FM_LAST_AF_TEMP), oneFilter["lastaftemp"].toDouble()); 0931 m_FilterModel->setData(m_FilterModel->index(row, FM_LAST_AF_ALT), oneFilter["lastafalt"].toDouble()); 0932 m_FilterModel->setData(m_FilterModel->index(row, FM_TICKS_PER_TEMP), oneFilter["tickspertemp"].toDouble()); 0933 m_FilterModel->setData(m_FilterModel->index(row, FM_TICKS_PER_ALT), oneFilter["ticksperalt"].toDouble()); 0934 m_FilterModel->setData(m_FilterModel->index(row, FM_WAVELENGTH), oneFilter["wavelength"].toInt()); 0935 } 0936 0937 m_FilterModel->submitAll(); 0938 setFilterNames(labels); 0939 0940 refreshFilterModel(); 0941 } 0942 0943 void FilterManager::buildFilterOffsets() 0944 { 0945 // Launch the Build Filter Offsets utility. The utility uses a sync call to launch the dialog 0946 QSharedPointer<FilterManager> filterManager; 0947 Ekos::Manager::Instance()->getFilterManager(m_FilterWheel->getDeviceName(), filterManager); 0948 BuildFilterOffsets bfo(filterManager); 0949 } 0950 0951 void FilterManager::signalRunAutoFocus(bool buildFilterOffsets) 0952 { 0953 // BuildFilterOffsets signalled runAutoFocus so pass signal to Focus 0954 emit runAutoFocus(buildFilterOffsets); 0955 } 0956 0957 void FilterManager::autoFocusComplete(FocusState completionState, int currentPosition, double currentTemperature, 0958 double currentAlt) 0959 { 0960 // Focus signalled Autofocus completed so pass signal to BuildFilterOffsets 0961 emit autoFocusDone(completionState, currentPosition, currentTemperature, currentAlt); 0962 } 0963 0964 void FilterManager::signalAbortAutoFocus() 0965 { 0966 // BuildFilterOffsets signalled abortAutoFocus so pass signal to Focus 0967 emit abortAutoFocus(); 0968 } 0969 0970 }