Photo capture and PHD dither support

This commit is contained in:
2019-10-25 14:06:47 +02:00
parent 9c28c841c6
commit 9507d4e0d8
6 changed files with 327 additions and 3 deletions
+6
View File
@@ -12,6 +12,7 @@
#include <QDockWidget>
#include <signal.h>
#include <unistd.h>
#include "photocapture.h"
#ifdef __linux__
#include <sys/ioctl.h>
@@ -35,6 +36,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
setCentralWidget(m_image);
resize(800, 600);
PhotoCapture *photoCapture = new PhotoCapture(this);
QDockWidget *captureDock = new QDockWidget(tr("Photo capture"), this);
captureDock->setWidget(photoCapture);
addDockWidget(Qt::BottomDockWidgetArea, captureDock);
setWindowTitle(tr("Tenmon"));
m_ringList = new ImageRingList(this);
+93
View File
@@ -0,0 +1,93 @@
#include "phd.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
const QHash<PHDState, QString> stateMap = {{Stopped, "Stopped"}, {Selected,"Selected"}, {Calibrating,"Calibrating"}, {Guiding,"Guiding"},
{LostLock,"LostLock"}, {Paused,"Paused"}, {Looping,"Looping"}};
PHD::PHD(QObject *parent) : QObject(parent)
,_messageId(0)
{
_socket = new QTcpSocket(this);
connect(_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
}
void PHD::connectTo(const QHostAddress &address, int port)
{
if(_socket->state() == QTcpSocket::ConnectedState)
{
_socket->disconnect();
_socket->waitForDisconnected();
}
_socket->connectToHost(address, port);
}
QString PHD::stateToString(PHDState state)
{
if(stateMap.contains(state))
return stateMap[state];
else
return QString();
}
PHDState PHD::stringToState(const QString &state)
{
return stateMap.key(state, Unknown);
}
void PHD::dither(float pixels, bool raOnly, int time, int timeout)
{
QVariantList params;
params.append(pixels);
params.append(raOnly);
params.append(QVariantHash({{"pixels",pixels/2.0},{"time",time},{"timeout",timeout}}));
invokeMethod("dither", params);
}
void PHD::parseMessage()
{
QJsonDocument json = QJsonDocument::fromJson(_data);
QJsonObject message = json.object();
//qDebug() << message;
if(message.contains("Event"))
{
QString event = message.value("Event").toString();
if(event=="AppState")
emit stateChanged(stringToState(message.value("State").toString()));
else if(event=="SettleDone")
{
qDebug() << message;
emit settled();
}
}
_data.clear();
}
void PHD::invokeMethod(const QString &method, const QVariantList &params)
{
QJsonDocument json;
QJsonObject message;
message.insert("method", method);
message.insert("id", QString::number(_messageId++));
message.insert("params", QJsonArray::fromVariantList(params));
json.setObject(message);
QByteArray data = json.toJson(QJsonDocument::Compact);
data.append('\n');
_socket->write(data);
}
void PHD::readyRead()
{
QByteArray data = _socket->readAll();
int index;
while((index = data.indexOf('\n')) != -1)
{
_data.append(data.left(index));
data.remove(0, index+1);
parseMessage();
}
if(data.size())
_data.append(data);
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef PHD_H
#define PHD_H
#include <QObject>
#include <QTcpSocket>
typedef enum
{
Stopped,
Selected,
Calibrating,
Guiding,
LostLock,
Paused,
Looping,
Unknown,
}PHDState;
class PHD : public QObject
{
Q_OBJECT
QTcpSocket *_socket;
QByteArray _data;
int _messageId;
public:
explicit PHD(QObject *parent = nullptr);
void connectTo(const QHostAddress &address, int port = 4400);
QString stateToString(PHDState state);
PHDState stringToState(const QString &state);
void dither(float pixels, bool raOnly, int time = 5, int timeout = 30);
private:
void parseMessage();
void invokeMethod(const QString &method, const QVariantList &params);
private slots:
void readyRead();
signals:
void connected();
void settled();
void stateChanged(PHDState state);
};
#endif // PHD_H
+142
View File
@@ -0,0 +1,142 @@
#include "photocapture.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QFileDialog>
#include <QStandardPaths>
#include <QDateTime>
#include <QDebug>
#include <QTimer>
#include <QHostAddress>
PhotoCapture::PhotoCapture(QWidget *parent) : QWidget(parent)
{
QHBoxLayout *layout = new QHBoxLayout(this);
setLayout(layout);
layout->addWidget(new QLabel(tr("Exposure time"), this));
_exposureTime = new QSpinBox(this);
_exposureTime->setValue(60);
_exposureTime->setSingleStep(60);
_exposureTime->setRange(0, 3600);
_exposureTime->setSuffix("s");
layout->addWidget(_exposureTime);
layout->addWidget(new QLabel(tr("Count"), this));
_numberOfExposures = new QSpinBox(this);
_numberOfExposures->setValue(1);
layout->addWidget(_numberOfExposures);
layout->addWidget(new QLabel(tr("Dither frequency"), this));
_ditherFreq = new QSpinBox(this);
_ditherFreq->setValue(1);
_ditherFreq->setRange(0, 10);
layout->addWidget(_ditherFreq);
_startCapture = new QPushButton(tr("Start capture"), this);
connect(_startCapture, SIGNAL(clicked()), this, SLOT(startCaputre()));
layout->addWidget(_startCapture);
QPushButton *selectDirButton = new QPushButton(tr("Select output"), this);
layout->addWidget(selectDirButton);
connect(selectDirButton, SIGNAL(clicked()), this, SLOT(selectDir()));
_process = new QProcess(this);
_process->setProgram("gphoto2");
connect(_process, SIGNAL(finished(int)), this, SLOT(processFinished(int)));
connect(_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdout()));
connect(_process, SIGNAL(readyReadStandardError()), this, SLOT(readStderr()));
QStringList paths = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
if(paths.size())
_outputDir.setPath(paths.first()+"/astro");
_timer = new QTimer(this);
_timer->setInterval(1000);
_timer->setSingleShot(true);
connect(_timer, SIGNAL(timeout()), this, SLOT(startCaputre()));
_phd = new PHD(this);
_phd->connectTo(QHostAddress("127.0.0.1"));
connect(_phd, SIGNAL(settled()), this, SLOT(startCaputre()));
_photoCount = 0;
}
PhotoCapture::~PhotoCapture()
{
if(_process->state()==QProcess::Running)
{
_process->terminate();
_process->waitForFinished(5000);
}
}
void PhotoCapture::startCaputre()
{
if(_process->state()==QProcess::Running)
{
_process->terminate();
_process->waitForFinished(10000);
_startCapture->setText(tr("Start capture"));
_numberOfExposures->setValue(0);
_photoCount = 0;
}
else if(_numberOfExposures->value()>0)
{
_photoCount++;
_startCapture->setText(tr("Stop capture"));
QString file = "capt"+QDateTime::currentDateTime().toString(Qt::ISODate)+".cr2";
QString path = _outputDir.absoluteFilePath(file);
QStringList args = {"--force-overwrite", "--set-config", "eosremoterelease=5",
QString("--wait-event=%1s").arg(_exposureTime->value()),
"--set-config", "eosremoterelease=9",
"--wait-event-and-download=3s",
QString("--filename=%1").arg(path)};
_process->setArguments(args);
_process->start();
}
else
{
_photoCount = 0;
_startCapture->setText(tr("Start capture"));
}
}
void PhotoCapture::processFinished(int exit)
{
if(exit==0)
{
_numberOfExposures->setValue(_numberOfExposures->value()-1);
if(_ditherFreq->value() == _photoCount)
{
_photoCount = 0;
_phd->dither(4, false);
}
else
{
_timer->start();
}
}
else
{
qDebug() << "gphoto failed" << exit;
_startCapture->setText(tr("Start capture"));
}
}
void PhotoCapture::selectDir()
{
QString path = QFileDialog::getExistingDirectory(this, tr("Output directory"), _outputDir.absolutePath());
_outputDir.setPath(path);
}
void PhotoCapture::readStdout()
{
//qDebug() << _process->readAllStandardOutput();
}
void PhotoCapture::readStderr()
{
//qDebug() << _process->readAllStandardError();
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef PHOTOCAPTURE_H
#define PHOTOCAPTURE_H
#include <QWidget>
#include <QSpinBox>
#include <QPushButton>
#include <QProcess>
#include <QDir>
#include "phd.h"
class PhotoCapture : public QWidget
{
Q_OBJECT
QSpinBox *_exposureTime;
QSpinBox *_numberOfExposures;
QSpinBox *_ditherFreq;
QPushButton *_startCapture;
QProcess *_process;
QDir _outputDir;
QTimer *_timer;
PHD *_phd;
int _photoCount;
public:
explicit PhotoCapture(QWidget *parent = nullptr);
~PhotoCapture();
signals:
public slots:
void startCaputre();
private slots:
void processFinished(int exit);
void selectDir();
void readStdout();
void readStderr();
};
#endif // PHOTOCAPTURE_H
+7 -3
View File
@@ -4,7 +4,7 @@
#
#-------------------------------------------------
QT += core gui sql
QT += core gui sql network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
@@ -27,7 +27,9 @@ SOURCES += main.cpp\
database.cpp \
loadrunable.cpp \
imageinfo.cpp \
starfit.cpp
starfit.cpp \
phd.cpp \
photocapture.cpp
HEADERS += mainwindow.h \
imagescrollarea.h \
@@ -36,4 +38,6 @@ HEADERS += mainwindow.h \
loadrunable.h \
imageinfo.h \
rawimage.h \
starfit.h
starfit.h \
phd.h \
photocapture.h