diff options
| author | Nikita Kostovsky <nikita@kostovsky.me> | 2026-02-26 16:33:12 +0100 |
|---|---|---|
| committer | Nikita Kostovsky <nikita@kostovsky.me> | 2026-02-26 16:33:12 +0100 |
| commit | a688e436f03309d5813b68a375f694412018ca0b (patch) | |
| tree | 8a5cdbb170fbb8417de42a09832d2eaf527ff61e | |
| parent | 1664027209ea3b8eb327b7755e4111577e66a2ee (diff) | |
add sync moveSteps
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/camera/icamera.h | 4 | ||||
| -rw-r--r-- | src/camera/veyeimx287m.cpp | 19 | ||||
| -rw-r--r-- | src/camera/veyeimx287m.h | 25 | ||||
| -rw-r--r-- | src/image.cpp | 4 | ||||
| -rw-r--r-- | src/main.cpp | 10 | ||||
| -rw-r--r-- | src/printerclient.cpp | 55 | ||||
| -rw-r--r-- | src/printerclient.h | 33 | ||||
| -rw-r--r-- | src/protocols/httpserver.cpp | 27 |
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; } |
