#pragma once // c/cpp #include #include #include #include // qt #include #include #include // orpheus #include "constants.h" #include "icamera.h" #include "image.h" // TODO: remove this include #include "printerclient.h" #include "utils/sem_queue.h" namespace veye { namespace imx287m { class i2c; } // namespace imx287m } // namespace veye class HttpServer; class IStand; /* * 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"; public: using buffer_t = std::array; public: VeyeIMX287m(); ~VeyeIMX287m() override; public slots: void onMoveFinished() override; public: static std::vector> search(); public: bool startStream() override; void startCalibration(std::shared_ptr stand, double zRangeMm) override; bool dequeueImageBuffer(size_t &image); std::shared_ptr getImage() override; bool init(); // parameters public: [[nodiscard]] bool set_autoExposure(const bool enable) override; [[nodiscard]] std::optional get_autoExposure() override; [[nodiscard]] bool set_autoGain(const bool enable) override; [[nodiscard]] std::optional get_autoGain() override; [[nodiscard]] bool set_exposureTime(const std::chrono::microseconds us) override; [[nodiscard]] std::optional get_exposureTime() override; [[nodiscard]] bool set_gain(const float value) override; [[nodiscard]] std::optional get_gain() override; [[nodiscard]] bool set_triggerExposureDelay(const std::chrono::microseconds us) override; [[nodiscard]] std::optional get_triggerExposureDelay() override; public: /*! * \brief processedCounter - count of images processed in current second. * Used for performance measurement and bottlenecks analysing */ uint32_t processedCounter{0}; private: bool openCam(); bool initCam(); bool initI2C(); // bool initHttpServer(); void getFrameLoop(std::stop_token stopToken); void rotateFrameLoop(std::stop_token stopToken); void calcPixelsLoop(std::stop_token stopToken); private: /*! * \brief m_cam_fd - camera file descriptor */ int m_cam_fd{-1}; /*! * \brief m_previousFrameCounter - used to detect dropped frames */ std::optional m_previousFrameCounter{}; static constexpr uint8_t BUFFER_COUNT{4}; // std::array m_images; /*! * \brief m_imageMutexes - lock while processing image from m_images */ std::array m_imageMutexes; // TODO: split this // there should be no chance of changing image by ioctl during futher processing struct buffer { void *mem{nullptr}; using sequence_t = decltype(v4l2_buffer::sequence); // TODO: think about optional/expected sequence_t sequence{std::numeric_limits::max()}; // std::shared_ptr image{std::make_shared()}; }; std::vector m_rawBuffers; struct Semaphore { sem_queue, BUFFER_COUNT> rawSemQueue; // sem_queue rawSemQueue; sem_queue, BUFFER_COUNT> rotSemQueue; // sem_queue rotSemQueue; } m_sync; std::mutex m_camMtx; /*! * \brief m_buffersQueue - queue of buffers which require extracting pixels */ std::queue> m_buffersQueue; std::jthread m_streamThread; std::jthread m_getThreads[1]; // std::jthread m_getThreads[4]; // TODO: sync all loops somehow to guarantee frames order std::jthread m_rotateThreads[2]; std::jthread m_calcPixelsThreads[1]; std::mutex m_lastImageMtx; std::shared_ptr m_lastProcessedImage{}; std::shared_ptr m_i2c; std::shared_ptr m_httpServer; // calibration // TODO: re-organize this logic bool m_isCalibrating{false}; bool m_ignoreFrames{false}; // std::vector> m_calibrationPixels; std::unordered_map>> m_calibrationPixels; std::shared_ptr m_stand; double m_zRangeMm{std::numeric_limits::quiet_NaN()}; bool m_isMoving{false}; };