summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNikita Kostovsky <nikita@kostovsky.me>2025-11-13 12:12:07 +0100
committerNikita Kostovsky <nikita@kostovsky.me>2025-11-13 12:12:07 +0100
commit3396ea3e7cf5a0def0ea720bcb863b374fd1cd0e (patch)
tree55082bf91ff2dabd2957f0cf11150a7d39ababc3 /src
parentc33006b2a8468f48cfbace39fe7c534f910fce0d (diff)
implement GET_pixels in http server
Diffstat (limited to 'src')
-rw-r--r--src/camera/veyeimx287m.cpp12
-rw-r--r--src/camera/veyeimx287m.h5
-rw-r--r--src/httpservice.cpp110
-rw-r--r--src/httpservice.h27
4 files changed, 148 insertions, 6 deletions
diff --git a/src/camera/veyeimx287m.cpp b/src/camera/veyeimx287m.cpp
index 5b745aa..16ab344 100644
--- a/src/camera/veyeimx287m.cpp
+++ b/src/camera/veyeimx287m.cpp
@@ -16,7 +16,9 @@
#include <QElapsedTimer>
+// orpheus
#include "constants.h"
+#include "httpservice.h"
#include "imagealgos.h"
#include "mem_utils.h"
#include "pixels.h"
@@ -308,6 +310,9 @@ bool VeyeIMX287m::init()
if (!initCam())
return false;
+ if (!initHttpServer())
+ return false;
+
return true;
}
@@ -620,6 +625,13 @@ bool VeyeIMX287m::initCam()
return true;
}
+bool VeyeIMX287m::initHttpServer()
+{
+ m_httpServer = std::make_shared<HttpServer>(this);
+
+ return m_httpServer != nullptr;
+}
+
void VeyeIMX287m::dequeueFrameLoop(std::stop_token stopToken)
{
// std::cout << "VeyeIMX287m: start stream" << std::endl;
diff --git a/src/camera/veyeimx287m.h b/src/camera/veyeimx287m.h
index b28ce96..5afc84b 100644
--- a/src/camera/veyeimx287m.h
+++ b/src/camera/veyeimx287m.h
@@ -10,6 +10,8 @@
#include "icamera.h"
+class HttpServer;
+
class VeyeIMX287m : public ICamera
{
constexpr static char videoDevice[] = "/dev/video0";
@@ -51,6 +53,7 @@ private:
bool openCam();
bool selectCam(int camIdx = 0);
bool initCam();
+ bool initHttpServer();
void dequeueFrameLoop(std::stop_token stopToken);
void calcFrameLoop(std::stop_token stopToken);
@@ -82,4 +85,6 @@ private:
std::jthread m_streamThread;
// std::jthread m_calcThreads[1];
std::jthread m_calcThreads[4];
+
+ std::shared_ptr<HttpServer> m_httpServer;
};
diff --git a/src/httpservice.cpp b/src/httpservice.cpp
index 7b89e23..14cf60d 100644
--- a/src/httpservice.cpp
+++ b/src/httpservice.cpp
@@ -1,16 +1,122 @@
#include "httpservice.h"
+// qt
+#include <QHttpServer>
+
+// orpheus
+#include "camera/veyeimx287m.h"
#include "constants.h"
+#include "image.h"
+#include "imagealgos.h"
#include "macro.h"
+// rapidjson
+#include "rapidjson/document.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/writer.h"
+
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(const std::shared_ptr<ICamera> &camera,
+HttpServer::HttpServer(ICamera *camera,
+ // QObject *parent,
const QHostAddress &address,
const uint16_t port)
+ // : QObject{parent}
: INIT_FIELD(camera)
, INIT_FIELD(address)
, INIT_FIELD(port)
-{}
+ , m_server{std::make_shared<QHttpServer>()}
+{
+ const auto apiPrefix = QStringLiteral("/v1");
+ const auto pixelsPath = apiPrefix + "/pixels";
+ qDebug().noquote() << Q_FUNC_INFO << ": pixelsPath: " << pixelsPath;
+ m_server->route(pixelsPath, [this]() { return GET_pixels(); });
+
+ qDebug().noquote() << Q_FUNC_INFO << ": listen: " << m_server->listen(m_address, m_port);
+}
+
+QHttpServerResponse HttpServer::GET_pixels()
+{
+ QElapsedTimer t;
+ t.start();
+ // std::shared_ptr<std::nullptr_t> logTime = std::make_shared<std::nullptr_t>(nullptr, [t]() {
+ // qDebug() << "HttpServer::GET_pixels: elapsed" << t.nsecsElapsed() / 1000 << "(us)";
+ // });
+ const std::shared_ptr<std::nullptr_t> logTime{nullptr, [t](auto unused_ptr) {
+ qDebug() << "HttpServer::GET_pixels: elapsed"
+ << t.nsecsElapsed() / 1000 << "(us)";
+ }};
+
+ Image img;
+ {
+ // const auto sharedCam = m_camera.lock();
+ // FIME: don't cast anything, use interface
+ // auto cam = dynamic_cast<VeyeIMX287m *>(sharedCam.get());
+ auto cam = dynamic_cast<VeyeIMX287m *>(m_camera);
+
+ if (!cam) {
+ qWarning() << "NO CAM";
+ return QHttpServerResponse::StatusCode::ServiceUnavailable;
+ }
+
+ // yeaah
+ // ::img = &img;
+ if (!cam->getImage(img)) {
+ qWarning() << "cannot get image";
+ return QHttpServerResponse::StatusCode::ServiceUnavailable;
+ }
+
+ // ::pixels = std::move(img.pixels());
+ ++cam->processedCounter;
+ }
+
+ // FIXME: not thread-safe, don't use this static shared_ptr at all
+ const auto pixels = img.sharedPixels();
+ // const auto lines = pixelsToLines(::pixels);
+ const auto lines = pixelsToLines(*pixels);
+
+ // qt json does not allow to limit double precision, so using rapidjson
+ rapidjson::Document jd;
+ jd.SetObject();
+ auto &al = jd.GetAllocator();
+
+ const auto nan2zero = [](const auto &value) { return qIsNaN(value) ? 0 : value; };
+
+ rapidjson::Value rjPixels{rapidjson::kArrayType};
+
+ for (size_t i = 0; i < img_width; ++i) {
+ rjPixels.PushBack(nan2zero(pixels->pixels[i]), al);
+ }
+
+ rapidjson::Value rjLines{rapidjson::kArrayType};
+
+ for (const auto &l : lines) {
+ rapidjson::Value rjLineP1{rapidjson::kArrayType};
+ rjLineP1.PushBack(nan2zero(l.p1().x()), al).PushBack(nan2zero(l.p1().y()), al);
+ rapidjson::Value rjLineP2{rapidjson::kArrayType};
+ rjLineP2.PushBack(nan2zero(l.p2().x()), al).PushBack(nan2zero(l.p2().y()), al);
+ rapidjson::Value rjLinePoints{rapidjson::kArrayType};
+ rjLinePoints.PushBack(rjLineP1, al).PushBack(rjLineP2, al);
+
+ rjLines.PushBack(rjLinePoints, al);
+ }
+
+ // jd.AddMember("encoderPosition", qint64{encoder.position()});
+ // FIXME: get prom pixels struct
+ jd.AddMember("measurementCounter", img.counters.measurementCounter, al);
+ jd.AddMember("timestampUs", img.counters.timestampUs, al);
+ jd.AddMember("pixels", rjPixels.Move(), al);
+ jd.AddMember("lines", rjLines.Move(), al);
+
+ rapidjson::StringBuffer buffer;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+ writer.SetMaxDecimalPlaces(2);
+ jd.Accept(writer);
+ const QString res{(const char *) buffer.GetString()};
+ // qDebug() << "size:" << res.size();
+ // qDebug().noquote() << "ret pix";
+
+ return QHttpServerResponse{res};
+}
diff --git a/src/httpservice.h b/src/httpservice.h
index 2b0e7f5..0fbd54d 100644
--- a/src/httpservice.h
+++ b/src/httpservice.h
@@ -2,22 +2,41 @@
// qt
#include <QHostAddress>
+#include <QHttpServerResponse>
+// #include <QObject>
class ICamera;
+class QHttpServer;
-class HttpServer
+class HttpServer // : public QObject
{
+ // Q_OBJECT
+
+private:
+ struct Stats
+ {
+ uint64_t GET_pixels_us{0};
+ } m_stats{0};
+
public:
static constexpr auto DefaultAddress = QHostAddress::Any;
- static constexpr uint16_t DefaultPort{8081};
+ static constexpr uint16_t DefaultPort{8080};
public:
- explicit HttpServer(const std::shared_ptr<ICamera> &camera,
+ explicit HttpServer(ICamera *camera,
+ // QObject *parent = nullptr,
const QHostAddress &address = DefaultAddress,
const uint16_t port = DefaultPort);
+ // TODO: methods starting with GET_/POST_ will be routed automatically
+public:
+ QHttpServerResponse GET_pixels();
+
private:
- std::shared_ptr<ICamera> m_camera{nullptr};
+ // std::weak_ptr<ICamera> m_camera;
+ ICamera *m_camera{nullptr};
QHostAddress m_address{DefaultAddress};
uint16_t m_port{DefaultPort};
+
+ std::shared_ptr<QHttpServer> m_server;
};