summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Kostovsky <nikita@kostovsky.me>2026-02-26 16:33:12 +0100
committerNikita Kostovsky <nikita@kostovsky.me>2026-02-26 16:33:12 +0100
commita688e436f03309d5813b68a375f694412018ca0b (patch)
tree8a5cdbb170fbb8417de42a09832d2eaf527ff61e
parent1664027209ea3b8eb327b7755e4111577e66a2ee (diff)
add sync moveSteps
-rw-r--r--CMakeLists.txt3
-rw-r--r--src/camera/icamera.h4
-rw-r--r--src/camera/veyeimx287m.cpp19
-rw-r--r--src/camera/veyeimx287m.h25
-rw-r--r--src/image.cpp4
-rw-r--r--src/main.cpp10
-rw-r--r--src/printerclient.cpp55
-rw-r--r--src/printerclient.h33
-rw-r--r--src/protocols/httpserver.cpp27
9 files changed, 173 insertions, 7 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 46ed7d5..4ce5645 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -136,7 +136,7 @@ set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std:c++latest")
set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std:c++latest")
-find_package(Qt6 6.4 REQUIRED COMPONENTS Gui Quick HttpServer SerialPort)
+find_package(Qt6 6.4 REQUIRED COMPONENTS Gui Quick HttpServer Network SerialPort)
find_package(TBB REQUIRED)
@@ -158,6 +158,7 @@ target_link_libraries(app${PROJECT_NAME}
Qt6::Gui
Qt6::HttpServer
Qt6::SerialPort
+ Qt6::Network
wiringPi
TBB::tbb
)
diff --git a/src/camera/icamera.h b/src/camera/icamera.h
index 545daf9..1fa0d18 100644
--- a/src/camera/icamera.h
+++ b/src/camera/icamera.h
@@ -49,6 +49,10 @@ public:
[[nodiscard]] virtual bool set_gain(const float value) = 0;
[[nodiscard]] virtual std::optional<float> get_gain() = 0;
+ [[nodiscard]] virtual bool set_triggerExposureDelay(const std::chrono::microseconds us) = 0;
+ [[nodiscard]] virtual std::optional<const std::chrono::microseconds> get_triggerExposureDelay()
+ = 0;
+
[[nodiscard]] virtual bool getImage(Image *image) = 0;
[[nodiscard]] virtual std::shared_ptr<Image> getImage() = 0;
diff --git a/src/camera/veyeimx287m.cpp b/src/camera/veyeimx287m.cpp
index 1301c66..2a06a72 100644
--- a/src/camera/veyeimx287m.cpp
+++ b/src/camera/veyeimx287m.cpp
@@ -397,6 +397,25 @@ std::optional<float> VeyeIMX287m::get_gain()
return *value * 10;
}
+bool VeyeIMX287m::set_triggerExposureDelay(const std::chrono::microseconds us)
+{
+ using namespace veye::imx287m;
+ return m_i2c->write(static_cast<uint16_t>(Register::Trigger_Exp_Delay), us.count());
+}
+
+std::optional<const std::chrono::microseconds> VeyeIMX287m::get_triggerExposureDelay()
+{
+ using namespace veye::imx287m;
+
+ const auto value = m_i2c->read(static_cast<uint32_t>(Register::Trigger_Exp_Delay));
+
+ if (!value) {
+ return {};
+ }
+
+ return std::chrono::microseconds{*value};
+}
+
bool VeyeIMX287m::openCam()
{
m_cam_fd = open(videoDevice, O_RDWR);
diff --git a/src/camera/veyeimx287m.h b/src/camera/veyeimx287m.h
index b875bb7..3a73cd2 100644
--- a/src/camera/veyeimx287m.h
+++ b/src/camera/veyeimx287m.h
@@ -25,6 +25,28 @@ class i2c;
class HttpServer;
+/*
+ * start calibration
+ * - send move zRange/16384 mm
+ * - wait StepDelay, ignore all pixels
+ * - collect 10 (64?) profiles
+ * - dump profiles
+ */
+
+/*!
+ * \brief The VeyeIMX287m class - control and receive data from VEYE IMX287
+ * camera
+ * \todo
+ * - implement `trgnum` - The number of image frames output by one trigger signal
+ * in trigger mode. Might be helpful in calibration mode
+ * - implement `trgfilter_enable` - for rising/falling edge support
+ * - implement `trgexp_delay` - Exposure delay, i.e. the time to turn on the
+ * Strobe signal in advance. The difference between trgexp_delay and trgdelay,
+ * see manual for details. (which manual?)
+ * - implement UDP streams, http is a bit slow even over 1GbE
+ * - implement roi
+ * - blcmode/blacklevel? (does it work in this camera?)
+ */
class VeyeIMX287m : public ICamera
{
constexpr static char videoDevice[] = "/dev/video0";
@@ -63,6 +85,9 @@ public:
bool set_gain(const float value) override;
std::optional<float> get_gain() override;
+ bool set_triggerExposureDelay(const std::chrono::microseconds us) override;
+ std::optional<const std::chrono::microseconds> get_triggerExposureDelay() override;
+
public:
/*!
* \brief processedCounter - count of images processed in current second.
diff --git a/src/image.cpp b/src/image.cpp
index b2cd535..0d9b92d 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -249,6 +249,8 @@ void Image::copyFromData(const void *src, size_t size)
void Image::copy(data_t &dst, const radxa_data_t &src)
{
for (size_t i = 0; i < img_height; ++i) {
- memcpy(dst[i].data(), src[i].data(), img_width);
+ const auto dst_data = static_cast<void *>(dst[i].data());
+ const auto src_data = static_cast<const void *>(src[i].data());
+ memcpy(dst_data, src_data, img_width);
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 01e4eac..208004f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -30,6 +30,7 @@
#include "camera/veyeimx287m.h"
#include "dumps.h"
#include "imagealgos.h"
+#include "printerclient.h"
#include "profile.h"
#include "protocols/httpserver.h"
#include "scanner.h"
@@ -88,6 +89,8 @@ int main(int argc, char *argv[])
std::signal(s, SIG_DFL);
};
+ qDebug() << "sizeof(Pixels):" << sizeof(Pixels);
+
std::signal(SIGINT, sigHandler);
std::signal(SIGTERM, sigHandler);
@@ -211,6 +214,8 @@ int main(int argc, char *argv[])
scanner->startAllProtocols();
+ Esp32Stand stand{QHostAddress{"192.168.18.248"}, 80, 1600};
+
QHttpServer qHttpServer;
qHttpServer.route("/v1/profile", [&]() -> QHttpServerResponse {
@@ -274,7 +279,12 @@ int main(int argc, char *argv[])
qDebug() << "send gCode:" << command;
+ // WARNING: tmp logic
+ auto distanceMm = command.split(' ').at(1);
+ distanceMm.remove(0, 1);
+
// printerClient.sendCommand(command);
+ stand.moveMm(distanceMm.toInt());
return QHttpServerResponse::StatusCode::Ok;
});
diff --git a/src/printerclient.cpp b/src/printerclient.cpp
index 4fed38f..3a548e9 100644
--- a/src/printerclient.cpp
+++ b/src/printerclient.cpp
@@ -1,11 +1,15 @@
#include "printerclient.h"
-#include <exception>
-
+#include <QCoreApplication>
#include <QDebug>
#include <QFile>
+#include <QNetworkReply>
#include <QSerialPort>
#include <QSerialPortInfo>
+#include <QThread>
+#include <QUrlQuery>
+
+#include "macro.h"
QString getFirstTtyUSB()
{
@@ -84,3 +88,50 @@ void PrinterClient::onErrorOccured(QSerialPort::SerialPortError error)
qWarning() << "serial port error:" << m_serialPort->errorString()
<< "-" << error;
}
+
+Esp32Stand::Esp32Stand(const QHostAddress &address, const uint32_t port, const uint32_t stepsPerMm)
+ : m_apiRoot{QStringLiteral("http://") + address.toString() + ':' + QString::number(port)}
+ , INIT_FIELD(stepsPerMm)
+ , m_manager{new QNetworkAccessManager{this}}
+{}
+
+bool Esp32Stand::moveMm(const double mm)
+{
+ return moveSteps(mm * m_stepsPerMm);
+}
+
+bool Esp32Stand::moveSteps(const int steps)
+{
+ qDebug() << __func__ << "move" << steps << "steps";
+ QElapsedTimer t;
+ t.start();
+ QUrlQuery query;
+ query.addQueryItem(QStringLiteral("steps"), QString::number(steps));
+
+ QUrl url{m_apiRoot + QStringLiteral("/move")};
+ url.setQuery(query);
+
+ std::mutex mtx;
+
+ const auto reply = m_manager->get(QNetworkRequest{url});
+ mtx.lock();
+
+ connect(reply, &QNetworkReply::finished, this, [reply, &mtx]() {
+ qDebug() << reply->readAll();
+ mtx.unlock();
+ });
+
+ while (!reply->isFinished()) {
+ reply->waitForReadyRead(100);
+ qApp->processEvents();
+ }
+
+ // TODO: fix this shit, EPS should reply when finished
+ // QThread::msleep(500);
+
+ std::lock_guard g{mtx};
+
+ qDebug() << __func__ << "moved" << steps << "steps" << t.elapsed();
+
+ return true;
+}
diff --git a/src/printerclient.h b/src/printerclient.h
index d1266dd..189bfb5 100644
--- a/src/printerclient.h
+++ b/src/printerclient.h
@@ -1,11 +1,42 @@
#pragma once
+#include <QHostAddress>
+#include <QNetworkAccessManager>
#include <QObject>
-
#include <QSerialPort>
class QSerialPort;
+class IStand
+{
+public:
+ virtual ~IStand() = default;
+
+public:
+ /*!
+ * \warning be careful when rounding mm to steps
+ */
+ virtual bool moveMm(const double mm) = 0;
+ virtual bool moveSteps(const int steps) = 0;
+};
+
+// TODO: think if QObject is needed
+class Esp32Stand : public QObject, public IStand
+{
+public:
+ explicit Esp32Stand(const QHostAddress &address, const uint32_t port, const uint32_t stepsPerMm);
+ ~Esp32Stand() override = default;
+
+public:
+ bool moveMm(const double mm) override;
+ bool moveSteps(const int steps) override;
+
+private:
+ QString m_apiRoot;
+ uint32_t m_stepsPerMm{0};
+ QNetworkAccessManager *m_manager{nullptr};
+};
+
class PrinterClient : public QObject
{
// Q_OBJECT
diff --git a/src/protocols/httpserver.cpp b/src/protocols/httpserver.cpp
index 3d5a0d5..dc3b59a 100644
--- a/src/protocols/httpserver.cpp
+++ b/src/protocols/httpserver.cpp
@@ -185,15 +185,21 @@ QHttpServerResponse HttpServer::POST_params(const QHttpServerRequest &request)
return QJsonDocument{QJsonObject{{QStringLiteral("error"), message}}}
.toJson();
};
- const auto invalidValue =
- [jsonError](const auto fieldName) -> const QString {
+ const auto invalidValue = [jsonError](const auto fieldName) -> const QString {
+ qDebug() << "invalid value:" << fieldName;
return jsonError(fieldName + QStringLiteral(" has invalid value"));
};
+ const auto failedToSet = [jsonError](const auto fieldName) -> const QString {
+ qDebug() << "failed to set" << fieldName;
+ return jsonError(QStringLiteral("failed to set") + fieldName);
+ };
+
const auto autoExposure = json["autoExposure"];
const auto exposureTime = json["exposureTime"];
const auto autoGain = json["autoGain"];
const auto gain = json["gain"];
+ const auto triggerExposureDelayUs = json["triggerExposureDelayUs"];
if (!autoExposure.isNull()) {
if (autoExposure.isBool()) {
@@ -232,6 +238,23 @@ QHttpServerResponse HttpServer::POST_params(const QHttpServerRequest &request)
}
}
+ if (!triggerExposureDelayUs.isNull()) {
+ if (triggerExposureDelayUs.isDouble()) {
+ const auto ok = m_camera->set_triggerExposureDelay(
+ std::chrono::microseconds{triggerExposureDelayUs.toInt()});
+
+ if (!ok) {
+ {
+ invalidValue("triggerExposureDelayUs"),
+ QHttpServerResponse::StatusCode::BadRequest;
+ }
+ }
+ } else {
+ return {invalidValue("triggerExposureDelayUs"),
+ QHttpServerResponse::StatusCode::BadRequest};
+ }
+ }
+
return QHttpServerResponse::StatusCode::Ok;
}