diff options
| author | Nikita Kostovsky <nikita@kostovsky.me> | 2026-03-06 20:40:29 +0100 |
|---|---|---|
| committer | Nikita Kostovsky <nikita@kostovsky.me> | 2026-03-06 20:40:29 +0100 |
| commit | 05f0938a65c4f8c330791097680e1e094260bb60 (patch) | |
| tree | d11e48c96eed6de03c51b793081310d96dee8618 | |
| parent | 051cb23a807a6914e2cda7e3b08d69ed29f347dd (diff) | |
refactoring
| -rw-r--r-- | src/calibration.cpp | 73 | ||||
| -rw-r--r-- | src/calibration.h | 13 | ||||
| -rw-r--r-- | src/camera/icamera.h | 46 | ||||
| -rw-r--r-- | src/camera/veyeimx287m.cpp | 76 | ||||
| -rw-r--r-- | src/camera/veyeimx287m.h | 17 | ||||
| -rw-r--r-- | src/constants.h | 7 | ||||
| -rw-r--r-- | src/image.cpp | 3 | ||||
| -rw-r--r-- | src/iscanner.cpp | 5 | ||||
| -rw-r--r-- | src/iscanner.h | 11 | ||||
| -rw-r--r-- | src/main.cpp | 95 | ||||
| -rw-r--r-- | src/pixels.cpp | 2 | ||||
| -rw-r--r-- | src/printerclient.cpp | 38 | ||||
| -rw-r--r-- | src/printerclient.h | 16 | ||||
| -rw-r--r-- | src/profile.cpp | 39 | ||||
| -rw-r--r-- | src/protocols/httpserver.cpp | 47 | ||||
| -rw-r--r-- | src/protocols/httpserver.h | 5 | ||||
| -rw-r--r-- | src/protocols/iprotocol.cpp | 4 | ||||
| -rw-r--r-- | src/protocols/iprotocol.h | 7 | ||||
| -rw-r--r-- | src/protocols/pixelsudpstreamer.cpp | 4 | ||||
| -rw-r--r-- | src/protocols/pixelsudpstreamer.h | 2 | ||||
| -rw-r--r-- | src/scanner.cpp | 15 | ||||
| -rw-r--r-- | src/scanner.h | 9 |
22 files changed, 389 insertions, 145 deletions
diff --git a/src/calibration.cpp b/src/calibration.cpp index 6cc85a1..05aed58 100644 --- a/src/calibration.cpp +++ b/src/calibration.cpp @@ -207,6 +207,7 @@ QList<Pixels> filter( Pixels sum = *it; size_t count{1}; + qDebug() << "\t" << __func__ << "enc pos:" << it->counters.encoderPosition; ++it; while (it != rawProfiles.constEnd() @@ -214,6 +215,7 @@ QList<Pixels> filter( sum += *it; ++count; ++it; + qDebug() << "\t\t" << __func__ << "enc pos:" << it->counters.encoderPosition; } sum /= float(count); @@ -356,12 +358,13 @@ CalibrationTablePtr calibrateX( return result; } -void dumpCalibrationPixels( - std::vector<Pixels>&& calibrationPixels) +void dumpCalibrationPixels(const std::vector<std::shared_ptr<Pixels> > &calibrationPixels, + const DumpFormat format) { - std::vector<Pixels> rawProfiles; + const auto &rawProfiles = calibrationPixels; + // std::vector<Pixels> rawProfiles; - std::swap(rawProfiles, calibrationPixels); + // std::swap(rawProfiles, calibrationPixels); const QString dumpSubdir{ QDateTime::currentDateTime().toString("yyyy.MM.dd_hh.mm.ss")}; @@ -375,47 +378,53 @@ void dumpCalibrationPixels( for (const auto& rawProfile : rawProfiles) { const auto filename = QLatin1String("raw_profile_meas_%1_enc_%2") - .arg(QString::number( - rawProfile.counters.measurementCounter)) - .arg(rawProfile.counters.encoderPosition); + .arg(QString::number(rawProfile->counters.measurementCounter)) + .arg(rawProfile->counters.encoderPosition); const auto filepath = dumpPath.path() + "/" + filename; - QFile f{filepath}; + // TODO: move out of `for` loop + // TODO: use switch, or remove enum and create a separate function + if (format == DumpFormat::Json) { + QFile f{filepath}; - if (!f.open(QFile::WriteOnly)) { - qWarning() << "cannot open dump dump file" << f.fileName(); - qWarning() << "error is:" << f.errorString(); + if (!f.open(QFile::WriteOnly)) { + qWarning() << "cannot open dump dump file" << f.fileName(); + qWarning() << "error is:" << f.errorString(); - return; - } + return; + } - QJsonObject jsonCounters{ - {"timestampUs", qint64(rawProfile.counters.timestampUs)}, - {"measurementCounter", - qint64(rawProfile.counters.measurementCounter)}, - {"encoderPosition", qint64(rawProfile.counters.encoderPosition)}, - }; + QJsonObject jsonCounters{ + {"timestampUs", qint64(rawProfile->counters.timestampUs)}, + {"measurementCounter", qint64(rawProfile->counters.measurementCounter)}, + {"encoderPosition", qint64(rawProfile->counters.encoderPosition)}, + }; - QJsonObject json; + QJsonObject json; - json["counters"] = jsonCounters; + json["counters"] = jsonCounters; - QJsonArray jsonPixels; + QJsonArray jsonPixels; - for (const auto& pixel : rawProfile.pixels) { - jsonPixels << pixel; - } + for (const auto &pixel : rawProfile->pixels) { + jsonPixels << pixel; + } - json["pixels"] = jsonPixels; + json["pixels"] = jsonPixels; - if (!f.write(QJsonDocument(json).toJson())) { - qWarning() << "cannot write file" << f.fileName(); - qWarning() << "error is" << f.errorString(); + if (!f.write(QJsonDocument(json).toJson())) { + qWarning() << "cannot write file" << f.fileName(); + qWarning() << "error is" << f.errorString(); - return; - } + return; + } - qDebug() << "file written: " << f.fileName(); + qDebug() << "file written: " << f.fileName(); + } else if (format == DumpFormat::Binary) { + if (!rawProfile->save(filepath)) { + return; + } + } } qDebug() << "dump finished"; diff --git a/src/calibration.h b/src/calibration.h index c2e5d73..4eee441 100644 --- a/src/calibration.h +++ b/src/calibration.h @@ -2,8 +2,6 @@ #include <array> -#include "fuck_intel.h" - #include <QSharedPointer> #include "constants.h" @@ -18,7 +16,10 @@ constexpr auto calibrationColumnHeight = std::tuple_size<CalibrationColumn>(); bool openCalibrationTable(const QString &filename, CalibrationTablePtr &table); -void dumpCalibrationPixels(std::vector<Pixels> &&calibrationPixels); +// void dumpCalibrationPixels(std::vector<Pixels> &&calibrationPixels); +enum class DumpFormat { Json, Binary }; +void dumpCalibrationPixels(const std::vector<std::shared_ptr<Pixels> > &calibrationPixels, + const DumpFormat format = DumpFormat::Json); bool dump(const CalibrationTablePtr &table, const QString &filename); QList<Pixels> filter(const QList<Pixels> &rawProfiles); @@ -31,3 +32,9 @@ QImage calibrationTableToImage(const CalibrationTablePtr &calibrationTable); void interpolate(CalibrationTablePtr &table); void interpolate(CalibrationColumn &column); + +// TODO: remove from this file +namespace { +static CalibrationTablePtr calibrationTableZ; +static CalibrationTablePtr calibrationTableX; +} // namespace diff --git a/src/camera/icamera.h b/src/camera/icamera.h index d6a2e9a..94408b6 100644 --- a/src/camera/icamera.h +++ b/src/camera/icamera.h @@ -1,24 +1,26 @@ #pragma once -#ifdef emit -#define emit_backup emit -#undef emit -#endif +#include <QObject> -#ifdef slots -#define slots_backup slots -#undef slots -#endif +// #ifdef emit +// #define emit_backup emit +// #undef emit +// #endif -#include <libcamera/base/signal.h> +// #ifdef slots +// #define slots_backup slots +// #undef slots +// #endif -#ifdef emit_backup -#define emit emit_backup -#endif +// // #include <libcamera/base/signal.h> -#ifdef slots_backup -#define slots slots_backup -#endif +// #ifdef emit_backup +// #define emit emit_backup +// #endif + +// #ifdef slots_backup +// #define slots slots_backup +// #endif // cpp #include <chrono> @@ -26,12 +28,24 @@ // orpheus #include "image.h" -class ICamera +class IStand; + +class ICamera : public QObject { + Q_OBJECT + public: virtual ~ICamera() = default; +signals: + void moveMm(double Mm); + +public slots: + virtual void onMoveFinished() = 0; + public: + virtual void startCalibration(std::shared_ptr<IStand> stand, double zRangeMm) = 0; + [[nodiscard]] virtual bool set_autoExposure(const bool enable) = 0; /*! diff --git a/src/camera/veyeimx287m.cpp b/src/camera/veyeimx287m.cpp index 1fd57f6..1d64395 100644 --- a/src/camera/veyeimx287m.cpp +++ b/src/camera/veyeimx287m.cpp @@ -14,8 +14,10 @@ #include <QElapsedTimer> // orpheus +#include "calibration.h" #include "camera/veye_i2c.h" #include "constants.h" +#include "pixels.h" #include "protocols/httpserver.h" #include "veyeimx287m_types.h" @@ -238,6 +240,12 @@ VeyeIMX287m::~VeyeIMX287m() std::cout << "camera closed" << std::endl; } +void VeyeIMX287m::onMoveFinished() +{ + qDebug() << __func__; + m_isMoving = false; +} + std::vector<std::shared_ptr<ICamera> > VeyeIMX287m::search() { // FIXME: use saved params, get rid of hardcode @@ -248,11 +256,11 @@ std::vector<std::shared_ptr<ICamera> > VeyeIMX287m::search() if (!cam->init()) return {}; - // if (!cam->set_autoExposure(false)) - if (!cam->set_autoExposure(true)) + if (!cam->set_autoExposure(false)) + // if (!cam->set_autoExposure(true)) return {}; - if (!cam->set_exposureTime(std::chrono::microseconds(30))) + if (!cam->set_exposureTime(std::chrono::microseconds(18))) return {}; if (!cam->set_autoGain(false)) @@ -292,6 +300,22 @@ bool VeyeIMX287m::startStream() return true; } +void VeyeIMX287m::startCalibration(std::shared_ptr<IStand> stand, double zRangeMm) +{ + m_calibrationPixels.clear(); + m_zRangeMm = zRangeMm; + m_stand = stand; + + // auto standObj = dynamic_cast<Esp32Stand *>(stand.get()); + + // if (standObj) { + // standObj->moveToThread(QThread::currentThread()); + // } + + m_stand->resetPosSteps(); + m_isCalibrating = true; +} + bool VeyeIMX287m::init() { if (!openCam()) @@ -361,6 +385,7 @@ std::optional<bool> VeyeIMX287m::get_autoGain() bool VeyeIMX287m::set_exposureTime(const std::chrono::microseconds us) { using namespace veye::imx287m; + std::cout << __func__ << ": " << us << std::endl; return m_i2c->write(static_cast<uint16_t>(Register::ME_Time), us.count()); } @@ -652,6 +677,8 @@ void VeyeIMX287m::rotateFrameLoop(std::stop_token stopToken) void VeyeIMX287m::calcPixelsLoop(std::stop_token stopToken) { + uint8_t collectedInPos{0}; + while (!stopToken.stop_requested()) { // const auto idx = m_sync.rotSemQueue.dequeue(); const auto image = m_sync.rotSemQueue.dequeue(); @@ -661,6 +688,49 @@ void VeyeIMX287m::calcPixelsLoop(std::stop_token stopToken) std::lock_guard l{m_lastImageMtx}; m_lastProcessedImage = image; } + + if (m_isCalibrating) { + // if (m_ignoreFrames) { + if (m_isMoving) { + continue; + } else { + pixels->counters.encoderPosition = m_stand->posSteps(); + constexpr uint8_t neededCount{8}; + + if (collectedInPos < neededCount) { + m_calibrationPixels.push_back(pixels); + ++collectedInPos; + } else { + // if (m_stand->posMm() < m_zRangeMm) { + if (m_stand->posMm() < debugZRange) { + // TODO: dump pixels + // dumpCalibrationPixels(m_calibrationPixels); + qDebug() << "moveMm:" << m_zRangeMm << ::discretesInRage + << "currPos:" << m_stand->posMm() << "zRange:" << m_zRangeMm + << m_zRangeMm / ::discretesInRage + << "pos steps:" << pixels->counters.encoderPosition; + m_isMoving = true; + + collectedInPos = 0; + emit moveMm(m_zRangeMm / ::discretesInRage); + // m_stand->moveMm(m_zRangeMm / ::discretesInRage); + } else { + qDebug() << "move to home:" << -m_zRangeMm; + qDebug() << "================================"; + m_isMoving = true; + // emit moveMm(-m_zRangeMm); + // emit moveMm(debugZRange); + // m_stand->moveMm(-m_zRangeMm); + m_isCalibrating = false; + // m_stand.reset(); + const auto tmp = m_calibrationPixels; + // dumpCalibrationPixels(m_calibrationPixels); + dumpCalibrationPixels(tmp, DumpFormat::Binary); + m_calibrationPixels.clear(); + } + } + } + } } } diff --git a/src/camera/veyeimx287m.h b/src/camera/veyeimx287m.h index b624fd2..bdc57d9 100644 --- a/src/camera/veyeimx287m.h +++ b/src/camera/veyeimx287m.h @@ -15,6 +15,8 @@ #include "constants.h" #include "icamera.h" #include "image.h" +// TODO: remove this include +#include "printerclient.h" #include "utils/sem_queue.h" namespace veye { @@ -24,6 +26,7 @@ class i2c; } // namespace veye class HttpServer; +class IStand; /* * start calibration @@ -58,12 +61,17 @@ public: VeyeIMX287m(); ~VeyeIMX287m() override; +public slots: + void onMoveFinished() override; + public: static std::vector<std::shared_ptr<ICamera>> search(); public: bool startStream() override; + void startCalibration(std::shared_ptr<IStand> stand, double zRangeMm) override; + bool dequeueImageBuffer(size_t &image); std::shared_ptr<Image> getImage() override; @@ -157,4 +165,13 @@ private: std::shared_ptr<veye::imx287m::i2c> m_i2c; std::shared_ptr<HttpServer> m_httpServer; + + // calibration + // TODO: re-organize this logic + bool m_isCalibrating{false}; + bool m_ignoreFrames{false}; + std::vector<std::shared_ptr<Pixels>> m_calibrationPixels; + std::shared_ptr<IStand> m_stand; + double m_zRangeMm{std::numeric_limits<double>::quiet_NaN()}; + bool m_isMoving{false}; }; diff --git a/src/constants.h b/src/constants.h index 83c81c8..6770f5f 100644 --- a/src/constants.h +++ b/src/constants.h @@ -34,4 +34,9 @@ const QString exposureTimeKey = "exposureTime"; const QString laserLevelKey = "laserLevel"; const QString gainKey = "gain"; -const QString dumpsRoot{QStringLiteral("/home/user/dumps")}; +// TODO: remove hardcode +const QString user{"radxa"}; + +const QString dumpsRoot{QStringLiteral("/home/%1/dumps").arg(user)}; + +constexpr double debugZRange{5.0}; diff --git a/src/image.cpp b/src/image.cpp index 0d9b92d..b840b3d 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -201,7 +201,8 @@ std::shared_ptr<Pixels> Image::sharedPixels() { t.start(); - static auto result = std::make_shared<Pixels>(); + // TODO: get rid of this alloc + auto result = std::make_shared<Pixels>(); result->counters = counters; std::transform(rotated_cw.cbegin(), rotated_cw.cend(), result->pixels.begin(), process_column); diff --git a/src/iscanner.cpp b/src/iscanner.cpp index c52bb9d..5229b4e 100644 --- a/src/iscanner.cpp +++ b/src/iscanner.cpp @@ -5,3 +5,8 @@ IScanner::IScanner(std::shared_ptr<ICamera> camera, : m_camera{camera} , m_protocols{protocols} {} + +std::shared_ptr<ICamera> IScanner::camera() const +{ + return m_camera; +} diff --git a/src/iscanner.h b/src/iscanner.h index 75300e1..e09197e 100644 --- a/src/iscanner.h +++ b/src/iscanner.h @@ -4,12 +4,16 @@ #include <memory> #include <vector> +// TODO: remove this include +#include "calibration.h" + class IProtocol; class ICamera; class IScanner { public: + // TODO: get rid of constructor or rename class explicit IScanner(std::shared_ptr<ICamera> camera, std::vector<std::shared_ptr<IProtocol>> protocols); virtual ~IScanner() = default; @@ -18,6 +22,13 @@ public: virtual bool startAllProtocols() = 0; virtual void stopAllProtocols() = 0; + // TODO: think about more flexible calibration interface + virtual CalibrationTablePtr calibrationTableX() const = 0; + virtual CalibrationTablePtr calibrationTableZ() const = 0; + + // TODO: add nullptr check everywhere where this function is used + std::shared_ptr<ICamera> camera() const; + protected: std::shared_ptr<ICamera> m_camera; std::vector<std::shared_ptr<IProtocol>> m_protocols; diff --git a/src/main.cpp b/src/main.cpp index 208004f..2d86dac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,11 +68,6 @@ QMutex calibrationPixelsMutex; using namespace std::chrono_literals; -namespace { -CalibrationTablePtr calibrationTableZ; -CalibrationTablePtr calibrationTableX; -} // namespace - auto printPixels = [](const auto &pixels) { for (size_t i = (img_width - 10) / 2; i < img_width - ((img_width - 10) / 2); @@ -99,30 +94,44 @@ int main(int argc, char *argv[]) QList<QFuture<void>> initializers; qDebug() << "size of raw profile" << sizeof(Pixels); - if (false) { + + // Pixels p; + // p.counters.encoderPosition = 123; + // if (!p.save("/tmp/tmp.pixels")) { + // return EXIT_FAILURE; + // } + + // Pixels p1; + // if (!p1.load("/tmp/tmp.pixels")) { + // return EXIT_FAILURE; + // } + // qDebug() << p.counters.encoderPosition << p.counters.encoderPosition; + // return EXIT_SUCCESS; + + if (true) { // open binary calibration table - if (true) { + if (false) { initializers << QtConcurrent::run([&]() { - if (!openCalibrationTable( - "/home/user/dumps/binz.calibration_table", - // "/tmp/binz.calibration_table", - ::calibrationTableZ)) { + if (!openCalibrationTable(QStringLiteral("/home/%1/dumps/binz.calibration_table") + .arg(user), + // "/tmp/binz.calibration_table", + ::calibrationTableZ)) { exit(EXIT_FAILURE); } }); initializers << QtConcurrent::run([&]() { - if (!openCalibrationTable( - "/home/user/dumps/binx.calibration_table", - // "/tmp/binx.calibration_table", - ::calibrationTableX)) { + if (!openCalibrationTable(QStringLiteral("/home/%1/dumps/binx.calibration_table") + .arg(user), + // "/tmp/binx.calibration_table", + ::calibrationTableX)) { exit(EXIT_FAILURE); } }); } if (false) { - auto rawProfiles = openDump("/home/user/dumps/binx"); + auto rawProfiles = openDump(QStringLiteral("/home/%1/dumps/binx").arg(user)); qDebug() << "raw x-profiles count is" << rawProfiles.size(); // qDebug() << "height" << calibrationColumnHeight; @@ -136,22 +145,29 @@ int main(int argc, char *argv[]) } // load binary calibration dumps and calibrate - if (false) { + if (true) { if (true) { - auto rawProfiles = openDump("/home/user/dumps/binz"); + auto rawProfiles = openDump(QStringLiteral("/home/%1/dumps/binz").arg(user)); qDebug() << "raw z-profiles count is" << rawProfiles.size(); + if (rawProfiles.empty()) { + return EXIT_FAILURE; + } + auto filteredRawProfiles = filter(std::move(rawProfiles)); qDebug() << "filtered z-profiles count is" << filteredRawProfiles.count(); ::calibrationTableZ = calibrateZ(std::move(filteredRawProfiles), requested_params.stepsPerMm); + // DEBUG + ::calibrationTableX = CalibrationTablePtr{new CalibrationTable{{0}}}; + memset(::calibrationTableX.get(), 0, sizeof(CalibrationTable)); interpolate(::calibrationTableZ); if (!dump(::calibrationTableZ, - "/home/user/dumps/binz.calibration_table")) { + QStringLiteral("/home/%1/dumps/binz.calibration_table").arg(user))) { qApp->exit(EXIT_FAILURE); } } @@ -159,8 +175,8 @@ int main(int argc, char *argv[]) qDebug() << "--------------------------------------------------------"; - if (true) { - auto rawProfiles = openDump("/home/user/dumps/binx"); + if (false) { + auto rawProfiles = openDump(QStringLiteral("/home/%1/dumps/binx").arg(user)); qDebug() << "raw x-profiles count is" << rawProfiles.size(); auto filteredRawProfiles = filter(std::move(rawProfiles)); @@ -172,13 +188,15 @@ int main(int argc, char *argv[]) interpolate(::calibrationTableX); if (!dump(::calibrationTableX, - "/home/user/dumps/binx.calibration_table")) { + QStringLiteral("/home/%1/dumps/binx.calibration_table").arg(user))) { qApp->exit(EXIT_FAILURE); } } } } + // exit(EXIT_SUCCESS); + QElapsedTimer t; t.start(); @@ -205,32 +223,29 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - auto httpServer = std::make_shared<HttpServer>(camera); - - const auto scanner - = std::make_shared<Scanner>(camera, - std::vector<std::shared_ptr<IProtocol>>{ - httpServer}); + // TODO: refactor: scanner and http server depend on each other + const auto scanner = std::make_shared<Scanner>(camera); + auto httpServer = std::make_shared<HttpServer>(scanner); scanner->startAllProtocols(); + httpServer->start(); - Esp32Stand stand{QHostAddress{"192.168.18.248"}, 80, 1600}; + auto stand = std::make_shared<Esp32Stand>(QHostAddress{"192.168.18.248"}, 80, 1600); QHttpServer qHttpServer; qHttpServer.route("/v1/profile", [&]() -> QHttpServerResponse { // std::cout << "http: profile" << std::endl; - return QHttpServerResponse::StatusCode::ServiceUnavailable; + // return QHttpServerResponse::StatusCode::ServiceUnavailable; std::lock_guard<std::mutex> lg(pgm_image_mtx); - if (!::calibrationTableZ || !::calibrationTableX) - return QHttpServerResponse::StatusCode::ServiceUnavailable; + // if (!::calibrationTableZ || !::calibrationTableX) + // return QHttpServerResponse::StatusCode::ServiceUnavailable; - const Profile profile(::pixels, - ::calibrationTableZ, - ::calibrationTableX); + const Profile profile{::pixels, ::calibrationTableZ, ::calibrationTableX}; const QJsonObject json{{"profile", QJsonObject(profile)}}; + // qDebug() << "profile:" << QJsonDocument(json).toJson(); return QHttpServerResponse(QJsonDocument(json).toJson()); }); @@ -263,6 +278,14 @@ int main(int argc, char *argv[]) // TODO: use flags scanningModeFlags = ScanningModeFlags::Calibration; calibrationTimer.start(); + QObject::connect(camera.get(), &ICamera::moveMm, stand.get(), &IStand::moveMm); + QObject::connect(stand.get(), + &IStand::moveFinished, + camera.get(), + &ICamera::onMoveFinished); + + //camera->startCalibration(stand, 200); + camera->startCalibration(stand, 200); return QHttpServerResponse::StatusCode::Ok; }); @@ -284,7 +307,7 @@ int main(int argc, char *argv[]) distanceMm.remove(0, 1); // printerClient.sendCommand(command); - stand.moveMm(distanceMm.toInt()); + stand->moveMm(distanceMm.toInt()); return QHttpServerResponse::StatusCode::Ok; }); diff --git a/src/pixels.cpp b/src/pixels.cpp index 3b69c99..e6d359c 100644 --- a/src/pixels.cpp +++ b/src/pixels.cpp @@ -87,6 +87,8 @@ bool Pixels::save( return false; } + std::cout << "saved pixels at enc pos " << counters.encoderPosition << std::endl; + return true; } diff --git a/src/printerclient.cpp b/src/printerclient.cpp index 3a548e9..c19e2a8 100644 --- a/src/printerclient.cpp +++ b/src/printerclient.cpp @@ -92,9 +92,28 @@ void PrinterClient::onErrorOccured(QSerialPort::SerialPortError 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}} + // , m_manager{new QNetworkAccessManager{this}} + // WARNING: memleak + , m_manager{new QNetworkAccessManager{}} {} +bool Esp32Stand::resetPosSteps() +{ + m_posSteps = 0; + + return true; +} + +int Esp32Stand::posSteps() +{ + return m_posSteps; +} + +double Esp32Stand::posMm() +{ + return m_posSteps / double(m_stepsPerMm); +} + bool Esp32Stand::moveMm(const double mm) { return moveSteps(mm * m_stepsPerMm); @@ -103,23 +122,30 @@ bool Esp32Stand::moveMm(const double mm) bool Esp32Stand::moveSteps(const int steps) { qDebug() << __func__ << "move" << steps << "steps"; - QElapsedTimer t; - t.start(); + // QElapsedTimer t; + // t.start(); + QUrlQuery query; query.addQueryItem(QStringLiteral("steps"), QString::number(steps)); + // qDebug() << "here-2"; QUrl url{m_apiRoot + QStringLiteral("/move")}; url.setQuery(query); std::mutex mtx; + // qDebug() << "here-1"; + const auto reply = m_manager->get(QNetworkRequest{url}); + // qDebug() << "here-123"; mtx.lock(); + // qDebug() << "here"; connect(reply, &QNetworkReply::finished, this, [reply, &mtx]() { qDebug() << reply->readAll(); mtx.unlock(); }); + // qDebug() << "here2"; while (!reply->isFinished()) { reply->waitForReadyRead(100); @@ -131,7 +157,11 @@ bool Esp32Stand::moveSteps(const int steps) std::lock_guard g{mtx}; - qDebug() << __func__ << "moved" << steps << "steps" << t.elapsed(); + // qDebug() << __func__ << "moved" << steps << "steps" << t.elapsed(); + + m_posSteps += steps; + + emit moveFinished(); return true; } diff --git a/src/printerclient.h b/src/printerclient.h index 189bfb5..232dad8 100644 --- a/src/printerclient.h +++ b/src/printerclient.h @@ -7,12 +7,20 @@ class QSerialPort; -class IStand +class IStand : public QObject { + Q_OBJECT + public: virtual ~IStand() = default; +signals: + void moveFinished(); + public: + virtual bool resetPosSteps() = 0; + virtual int posSteps() = 0; + virtual double posMm() = 0; /*! * \warning be careful when rounding mm to steps */ @@ -21,13 +29,16 @@ public: }; // TODO: think if QObject is needed -class Esp32Stand : public QObject, public IStand +class Esp32Stand : public IStand { public: explicit Esp32Stand(const QHostAddress &address, const uint32_t port, const uint32_t stepsPerMm); ~Esp32Stand() override = default; public: + bool resetPosSteps() override; + int posSteps() override; + double posMm() override; bool moveMm(const double mm) override; bool moveSteps(const int steps) override; @@ -35,6 +46,7 @@ private: QString m_apiRoot; uint32_t m_stepsPerMm{0}; QNetworkAccessManager *m_manager{nullptr}; + int m_posSteps{0}; }; class PrinterClient : public QObject diff --git a/src/profile.cpp b/src/profile.cpp index 64ba091..3ed11ba 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -11,33 +11,35 @@ Profile::Profile( const CalibrationTablePtr calibrationTableX) : m_counters(pixels.counters) { - if (!calibrationTableZ || !calibrationTableX) - { - std::cerr << __func__ << ": got invalid calibration tables" - << std::endl; + // if (!calibrationTableZ || !calibrationTableX) { + // std::cerr << __func__ << ": got invalid calibration tables" << std::endl; - return; - } + // return; + // } static bool done{false}; - if (!done) { - for (size_t i = 9471; i < 9472; i++) { - std::cout << __func__ << ": row #" << i << ": "; + // if (!done) { + // // for (size_t i = 9471; i < 9472; i++) { + // for (size_t i = 0; i < calibrationTableHeight; i++) { + // std::cout << __func__ << ": row #" << i << ": "; - for (size_t j = 0; j < img_width; ++j) { - const auto& x = calibrationTableX->at(j).at(i); - const auto& z = calibrationTableZ->at(j).at(i); - std::cout << "Profile: table: " << x << ' ' << z << std::endl; - } + // for (size_t j = 0; j < img_width; ++j) { + // const auto &x = calibrationTableX ? calibrationTableX->at(j).at(i) : j; + // const auto &z = calibrationTableZ->at(j).at(i); + // std::cout << "Profile: table: " << x << ' ' << z << std::endl; + // } - std::cout << std::endl; - } - } + // std::cout << std::endl; + // } + // } for (size_t i = 0; i < img_width; ++i) { try { const auto& pixel = pixels.pixels[i]; + if (!qFuzzyIsNull(pixel)) { + qt_noop(); + } const auto pixelDiscrete = pixel * discretesInRage / img_height; if (Q_UNLIKELY(pixel >= sizeof(CalibrationColumn) / sizeof(float))) { qWarning() << "got invalid calibration pixel at" << i << ":" @@ -79,8 +81,7 @@ Profile::Profile( // TODO: use only NaN (or zero?) everywhere // NOTE: QJsonValue converts NaN to zero if (qFuzzyIsNull(z) || std::isnan(z)) { - // qDebug() << "got nan z for discrete" << pixelDiscrete << leftMmZ - // << rightMmZ; + // qDebug() << "got nan z for discrete" << pixelDiscrete << leftMmZ << rightMmZ; m_pointsMm.at(i) = {std::nan(""), std::nan("")}; continue; } diff --git a/src/protocols/httpserver.cpp b/src/protocols/httpserver.cpp index dc3b59a..3ca1f5c 100644 --- a/src/protocols/httpserver.cpp +++ b/src/protocols/httpserver.cpp @@ -12,7 +12,9 @@ #include "constants.h" #include "image.h" #include "imagealgos.h" +#include "iscanner.h" #include "macro.h" +#include "profile.h" #include "utils/elapsed_logger.h" // rapidjson @@ -24,10 +26,10 @@ extern uint8_t pgm_image[64 + img_width * img_height * sizeof(uint8_t)]; extern size_t pgm_image_size; extern std::mutex pgm_image_mtx; -HttpServer::HttpServer(std::shared_ptr<ICamera> camera, +HttpServer::HttpServer(std::shared_ptr<IScanner> scanner, const QHostAddress &address, const uint16_t port) - : IProtocol{camera} + : IProtocol{scanner} , INIT_FIELD(address) , INIT_FIELD(port) // , m_server{std::make_shared<QHttpServer>()} @@ -40,11 +42,14 @@ bool HttpServer::start() // TODO: move these vars outside const auto apiPrefix = QStringLiteral("/v1"); + // TODO: route automatically const auto pixelsPath = apiPrefix + "/pixels"; + const auto profilesPath = apiPrefix + "/profile"; qDebug().noquote() << Q_FUNC_INFO << ": pixelsPath: " << pixelsPath; // TODO: get rid of lamdas, there should be a better way m_server->route(pixelsPath, [this]() { return GET_pixels(); }); + m_server->route(profilesPath, [this]() { return GET_profile(); }); m_server->route(apiPrefix + QStringLiteral("/sensor/params"), QHttpServerRequest::Method::Get, [this]() { return GET_params(); }); @@ -86,7 +91,7 @@ QHttpServerResponse HttpServer::GET_image() { // Image img; - const auto image = m_camera->getImage(); + const auto image = m_scanner->camera()->getImage(); // if (!m_camera->getImage(&img)) { if (!image) { @@ -110,7 +115,7 @@ QFuture<QHttpServerResponse> HttpServer::GET_image_async() QHttpServerResponse HttpServer::GET_pixels() { - if (!m_camera) { + if (!m_scanner) { qWarning() << "NO CAM"; return QHttpServerResponse::StatusCode::ServiceUnavailable; } @@ -118,7 +123,7 @@ QHttpServerResponse HttpServer::GET_pixels() std::shared_ptr<Image> image; { // const elapsed_logger logger{__func__}; - /*const auto */ image = m_camera->getImage(); + /*const auto */ image = m_scanner->camera()->getImage(); } if (!image) { @@ -176,6 +181,17 @@ QHttpServerResponse HttpServer::GET_pixels() return QHttpServerResponse{res}; } +QHttpServerResponse HttpServer::GET_profile() +{ + const auto image = m_scanner->camera()->getImage(); + const auto pixels = image->sharedPixels(); + const auto profile = Profile{*pixels, ::calibrationTableZ, ::calibrationTableX}; + + const QJsonObject json{profile}; + + return QHttpServerResponse{QJsonDocument{json}.toJson()}; +} + QHttpServerResponse HttpServer::POST_params(const QHttpServerRequest &request) { const auto json = QJsonDocument::fromJson(request.body()).object(); @@ -201,9 +217,11 @@ QHttpServerResponse HttpServer::POST_params(const QHttpServerRequest &request) const auto gain = json["gain"]; const auto triggerExposureDelayUs = json["triggerExposureDelayUs"]; + // TODO: unify args processing to avoid code duplicates if (!autoExposure.isNull()) { if (autoExposure.isBool()) { - m_camera->set_autoExposure(autoExposure.toBool()); + // TODO: enable -Werror and some pedantic checks + m_scanner->camera()->set_autoExposure(autoExposure.toBool()); } else { return {invalidValue("autoExposure"), QHttpServerResponse::StatusCode::BadRequest}; @@ -212,8 +230,7 @@ QHttpServerResponse HttpServer::POST_params(const QHttpServerRequest &request) if (!exposureTime.isNull()) { if (exposureTime.isDouble()) { - m_camera->set_exposureTime( - std::chrono::microseconds{exposureTime.toInt()}); + m_scanner->camera()->set_exposureTime(std::chrono::microseconds{exposureTime.toInt()}); } else { return {invalidValue("exposureTime"), QHttpServerResponse::StatusCode::BadRequest}; @@ -222,7 +239,7 @@ QHttpServerResponse HttpServer::POST_params(const QHttpServerRequest &request) if (!autoGain.isNull()) { if (autoGain.isBool()) { - m_camera->set_autoGain(autoGain.toBool()); + m_scanner->camera()->set_autoGain(autoGain.toBool()); } else { return {invalidValue("autoGain"), QHttpServerResponse::StatusCode::BadRequest}; @@ -231,7 +248,7 @@ QHttpServerResponse HttpServer::POST_params(const QHttpServerRequest &request) if (!gain.isNull()) { if (gain.isDouble()) { - m_camera->set_gain(gain.toDouble()); + m_scanner->camera()->set_gain(gain.toDouble()); } else { return {invalidValue("gain"), QHttpServerResponse::StatusCode::BadRequest}; @@ -240,7 +257,7 @@ QHttpServerResponse HttpServer::POST_params(const QHttpServerRequest &request) if (!triggerExposureDelayUs.isNull()) { if (triggerExposureDelayUs.isDouble()) { - const auto ok = m_camera->set_triggerExposureDelay( + const auto ok = m_scanner->camera()->set_triggerExposureDelay( std::chrono::microseconds{triggerExposureDelayUs.toInt()}); if (!ok) { @@ -270,10 +287,10 @@ QHttpServerResponse HttpServer::GET_params() }; const auto json = QJsonObject{ - {"autoExposure", val_or_null(m_camera->get_autoExposure())}, - {"exposureTime", chrono_val_or_null(m_camera->get_exposureTime())}, - {"autoGain", val_or_null(m_camera->get_autoGain())}, - {"gain", val_or_null(m_camera->get_gain())}, + {"autoExposure", val_or_null(m_scanner->camera()->get_autoExposure())}, + {"exposureTime", chrono_val_or_null(m_scanner->camera()->get_exposureTime())}, + {"autoGain", val_or_null(m_scanner->camera()->get_autoGain())}, + {"gain", val_or_null(m_scanner->camera()->get_gain())}, }; qDebug().noquote() << __func__ << ": " << json; diff --git a/src/protocols/httpserver.h b/src/protocols/httpserver.h index e3ca66f..320ce00 100644 --- a/src/protocols/httpserver.h +++ b/src/protocols/httpserver.h @@ -9,7 +9,7 @@ // orpheus #include "iprotocol.h" -class ICamera; +class IScanner; class QHttpServer; class HttpServer : public IProtocol @@ -25,7 +25,7 @@ public: static constexpr uint16_t DefaultPort{8080}; public: - explicit HttpServer(std::shared_ptr<ICamera> camera, + explicit HttpServer(std::shared_ptr<IScanner> scanner, const QHostAddress &address = DefaultAddress, const uint16_t port = DefaultPort); ~HttpServer() override = default; @@ -45,6 +45,7 @@ public: */ QFuture<QHttpServerResponse> GET_image_async(); QHttpServerResponse GET_pixels(); + QHttpServerResponse GET_profile(); QHttpServerResponse POST_params(const QHttpServerRequest &request); QHttpServerResponse GET_params(); diff --git a/src/protocols/iprotocol.cpp b/src/protocols/iprotocol.cpp index 5422a9d..02270b4 100644 --- a/src/protocols/iprotocol.cpp +++ b/src/protocols/iprotocol.cpp @@ -1,5 +1,5 @@ #include "iprotocol.h" -IProtocol::IProtocol(std::shared_ptr<ICamera> camera) - : m_camera{camera} +IProtocol::IProtocol(std::shared_ptr<IScanner> camera) + : m_scanner{camera} {} diff --git a/src/protocols/iprotocol.h b/src/protocols/iprotocol.h index 75259bc..3f49eb6 100644 --- a/src/protocols/iprotocol.h +++ b/src/protocols/iprotocol.h @@ -2,12 +2,13 @@ #include <memory> -class ICamera; +class IScanner; class IProtocol { public: - explicit IProtocol(std::shared_ptr<ICamera> camera); + // TODO: get rid of constructor or rename class + explicit IProtocol(std::shared_ptr<IScanner> camera); virtual ~IProtocol() = default; public: @@ -15,5 +16,5 @@ public: virtual void stop() = 0; protected: - std::shared_ptr<ICamera> m_camera; + std::shared_ptr<IScanner> m_scanner; }; diff --git a/src/protocols/pixelsudpstreamer.cpp b/src/protocols/pixelsudpstreamer.cpp index e7498d7..2855a35 100644 --- a/src/protocols/pixelsudpstreamer.cpp +++ b/src/protocols/pixelsudpstreamer.cpp @@ -2,9 +2,9 @@ #include <QUdpSocket> -PixelsUdpStreamer::PixelsUdpStreamer(std::shared_ptr<ICamera> camera, QObject *parent) +PixelsUdpStreamer::PixelsUdpStreamer(std::shared_ptr<IScanner> scanner, QObject *parent) : QObject{parent} - , IProtocol{camera} + , IProtocol{scanner} {} bool PixelsUdpStreamer::start() diff --git a/src/protocols/pixelsudpstreamer.h b/src/protocols/pixelsudpstreamer.h index a7f69b7..dacc9cb 100644 --- a/src/protocols/pixelsudpstreamer.h +++ b/src/protocols/pixelsudpstreamer.h @@ -15,7 +15,7 @@ class PixelsUdpStreamer : public QObject, public IProtocol Q_OBJECT public: - explicit PixelsUdpStreamer(std::shared_ptr<ICamera> camera, QObject *parent = nullptr); + explicit PixelsUdpStreamer(std::shared_ptr<IScanner> scanner, QObject *parent = nullptr); ~PixelsUdpStreamer() override = default; public slots: diff --git a/src/scanner.cpp b/src/scanner.cpp index 07d3c0f..9012769 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -2,9 +2,10 @@ #include "protocols/iprotocol.h" -Scanner::Scanner(std::shared_ptr<ICamera> camera, - std::vector<std::shared_ptr<IProtocol>> protocols) +Scanner::Scanner(std::shared_ptr<ICamera> camera, std::vector<std::shared_ptr<IProtocol>> protocols) : IScanner{camera, protocols} + , m_calibrationTableX{new CalibrationTable{}} + , m_calibrationTableZ{new CalibrationTable{}} { // m_protocols.push_back() } @@ -28,3 +29,13 @@ void Scanner::stopAllProtocols() protocol->stop(); } } + +CalibrationTablePtr Scanner::calibrationTableX() const +{ + return m_calibrationTableX; +} + +CalibrationTablePtr Scanner::calibrationTableZ() const +{ + return m_calibrationTableZ; +} diff --git a/src/scanner.h b/src/scanner.h index 8031dda..4d81d1a 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -6,10 +6,17 @@ class Scanner : public IScanner { public: explicit Scanner(std::shared_ptr<ICamera> camera, - std::vector<std::shared_ptr<IProtocol>> protocols); + std::vector<std::shared_ptr<IProtocol>> protocols = {}); ~Scanner() override = default; public: bool startAllProtocols() override; void stopAllProtocols() override; + + CalibrationTablePtr calibrationTableX() const override; + CalibrationTablePtr calibrationTableZ() const override; + +private: + CalibrationTablePtr m_calibrationTableX; + CalibrationTablePtr m_calibrationTableZ; }; |
