summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format15
-rw-r--r--CMakeLists.txt3
-rw-r--r--imagealgos.cpp22
-rw-r--r--main.cpp1069
-rw-r--r--printerclient.cpp18
5 files changed, 767 insertions, 360 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..56838cf
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,15 @@
+AccessModifierOffset: -4
+AlignAfterOpenBracket: BlockIndent
+AllowAllArgumentsOnNextLine: false
+AllowAllParametersOfDeclarationOnNextLine: false
+BasedOnStyle: Microsoft
+BinPackParameters: false
+BinPackArguments: false
+BreakConstructorInitializers: BeforeComma
+ColumnLimit: 80
+InsertNewlineAtEOF: true
+IndentWidth: 4
+SpacesBeforeTrailingComments: 2
+UseTab: Never
+LineEnding: LF
+PointerAlignment: Left
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e07bf77..a00e7f3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -58,7 +58,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 Quick HttpServer SerialPort)
+find_package(Qt6 6.4 REQUIRED COMPONENTS Gui Quick HttpServer SerialPort)
find_package(TBB REQUIRED)
@@ -91,6 +91,7 @@ target_link_libraries(app${PROJECT_NAME}
PRIVATE
"${LIBCAMERA_LIBRARIES}"
PkgConfig::Pistache
+ Qt6::Gui
Qt6::HttpServer
Qt6::SerialPort
wiringPi
diff --git a/imagealgos.cpp b/imagealgos.cpp
index b4fba4b..267e4ae 100644
--- a/imagealgos.cpp
+++ b/imagealgos.cpp
@@ -303,7 +303,7 @@ Pixels& Pixels::operator/=(const float divider)
QList<QLineF> pixelsToLines(const Pixels &rawProfile)
{
const auto& pixels = rawProfile.pixels;
- QList<QPointF> points { pixels.size() };
+ QList<QPointF> points(pixels.size());
for (int i = 0; i < pixels.size(); ++i)
{
@@ -320,7 +320,7 @@ QList<QLineF> pointsToLines(const QList<QPointF> &points)
constexpr double maxDistanceFromLine { 3 };
constexpr double minLineLength { 10 };
- QList<int> lineAnchors { 0, points.size() - 1 };
+ QList<int> lineAnchors{0, int(points.count() - 1)};
auto vecLength = [](const QPointF& vector) {
return std::hypot(vector.x(), vector.y());
@@ -364,7 +364,7 @@ QList<QLineF> pointsToLines(const QList<QPointF> &points)
// distance
// qDebug() << "dist" << fabs(x*y2 - y*x2) / norm << point << line;
- return fabs(x*y2 - y*x2) / norm;
+ return fabs(x * y2 - y * x2) / norm;
};
// for (const auto& p : points)
@@ -386,13 +386,21 @@ QList<QLineF> pointsToLines(const QList<QPointF> &points)
const QLineF line { points.at(leftPointIdx), points.at(rightPointIdx) };
+ // std::cout << "max between " << leftPointIdx + 1 << " and "
+ // << rightPointIdx - 1 << std::endl;
+
const auto farthest = std::max_element(
// std::execution::par_unseq,
points.cbegin() + leftPointIdx + 1,
points.cbegin() + rightPointIdx - 1,
[line, distanceToLine](const QPointF& a, const QPointF& b) {
return distanceToLine(a, line) < distanceToLine(b, line);
- });
+ }
+ );
+
+ // std::cout << "done max" << std::endl;
+ // auto tmp = *farthest;
+ // std::cout << "done farthest" << std::endl;
// qDebug() << "farthest point" << distanceToLine(*farthest, line);
// qDebug() << "farthest dist" << distanceToLine(*farthest, line);
@@ -400,7 +408,13 @@ QList<QLineF> pointsToLines(const QList<QPointF> &points)
if (distanceToLine(*farthest, line) > maxDistanceFromLine)
{
+ // std::cout << "try insert at " << i + 1 << ". lineAnchors.size is
+ // "
+ // << lineAnchors.size()
+ // << ". inserting this: " << farthest - points.cbegin()
+ // << std::endl;
lineAnchors.insert(i + 1, farthest - points.cbegin());
+ // std::cout << "done insert" << std::endl;
--i;
// qDebug() << "I'm here" << i;
continue;
diff --git a/main.cpp b/main.cpp
index c1b3fe2..4666179 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,48 +1,49 @@
#include <chrono>
#include <errno.h>
+#include <fstream>
#include <iostream>
#include <iterator>
-#include <fstream>
#include <string.h>
-#include <thread>
#include <sys/mman.h>
+#include <thread>
#include "LibCamera.h"
-#include "printerclient.h"
-#include "httpservice.h"
+#include "fuck_intel.h"
#include "genetic_algos.h"
+#include "httpservice.h"
+#include "imagealgos.h"
#include "pigpio.h"
+#include "printerclient.h"
#include "rotaryencoder.h"
-#include "imagealgos.h"
-#include "fuck_intel.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QHttpServer>
+#include <QImage>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QSerialPort>
#include <QTextStream>
-#include <QtConcurrent/QtConcurrentRun>
#include <QTimer>
+#include <QtConcurrent/QtConcurrentRun>
-#define try_apply_config() \
-if(!applyConfig(config)) \
- { \
- camera->release(); \
- cm->stop(); \
- \
- return EXIT_FAILURE;\
+#define try_apply_config() \
+ if (!applyConfig(config)) \
+ { \
+ camera->release(); \
+ cm->stop(); \
+ \
+ return EXIT_FAILURE; \
}
-
const QString exposureTimeKey = "exposureTime";
const QString laserLevelKey = "laserLevel";
-enum ScanningModeFlags : uint8_t {
+enum ScanningModeFlags : uint8_t
+{
None = 0,
Calibration
};
@@ -50,57 +51,83 @@ enum ScanningModeFlags : uint8_t {
// ScanningModeFlags operator|(ScanningModeFlags lhs, ScanningModeFlags rhs)
// {
// using T = std::underlying_type<ScanningModeFlags>::type;
-// return static_cast<ScanningModeFlags>(static_cast<T>(lhs) | static_cast<T>(rhs));
+// return static_cast<ScanningModeFlags>(static_cast<T>(lhs) |
+// static_cast<T>(rhs));
// }
-ScanningModeFlags scanningModeFlags { ScanningModeFlags::None };
+ScanningModeFlags scanningModeFlags{ScanningModeFlags::None};
QElapsedTimer calibrationTimer;
extern volatile int32_t positionSteps;
-struct requested_params_t {
- int32_t exposureTime = { 1000 };
- int32_t laserLevel = { 3000 };
- uint32_t stepsPerMm { 200 };
+struct requested_params_t
+{
+ int32_t exposureTime = {1000};
+ int32_t laserLevel = {3000};
+ uint32_t stepsPerMm{200};
} requested_params;
-namespace {
+namespace
+{
Image img;
Pixels pixels;
std::vector<Pixels> calibrationPixels;
QMutex calibrationPixelsMutex;
-}
+} // namespace
-const QString dumpsRoot { QStringLiteral("/home/user/dumps") };
+const QString dumpsRoot{QStringLiteral("/home/user/dumps")};
using namespace std::chrono_literals;
static std::shared_ptr<libcamera::Camera> camera;
std::unique_ptr<libcamera::CameraConfiguration> config;
-static std::map<int, std::pair<void *, unsigned int>> mappedBuffers_;
+static std::map<int, std::pair<void*, unsigned int>> mappedBuffers_;
std::vector<std::unique_ptr<libcamera::Request>> requests;
libcamera::ControlList lastControls;
static QList<Pixels> openDump(const QString& dumpPath = "");
static std::optional<Pixels> openRawProfile(const QString& filePath);
-constexpr float hardcodedZRangeMm { 175.f };
-constexpr size_t calibrationTableHeight { 0x4000 }; // 16384
+constexpr float hardcodedZRangeMm{175.f};
+constexpr size_t calibrationTableHeight{0x4000}; // 16384
// img_width * calibrationTableHeight
using CalibrationColumn = std::array<float, calibrationTableHeight>;
using CalibrationTable = std::array<CalibrationColumn, img_width>;
constexpr auto calibrationColumnHeight = std::tuple_size<CalibrationColumn>();
// CalibrationTable* calibrationTable { new CalibrationTable {{ 0 }} };
-static bool applyConfig(const std::unique_ptr<libcamera::CameraConfiguration> & config);
-static void onRequestCompleted(libcamera::Request *completed_request);
+namespace
+{
+QSharedPointer<CalibrationTable> calibrationTableZ;
+QSharedPointer<CalibrationTable> calibrationTableX;
+constexpr uint16_t discretesInRage{16384};
+} // namespace
+
+static bool applyConfig(
+ const std::unique_ptr<libcamera::CameraConfiguration>& config
+);
+static void onRequestCompleted(libcamera::Request* completed_request);
static void printControls();
static void dumpCalibrationPixels();
static QList<Pixels> filter(const QList<Pixels>& rawProfiles);
-static QSharedPointer<CalibrationTable> calibrate(const QList<Pixels>& rawProfiles);
+static QSharedPointer<CalibrationTable> calibrateX(
+ const QList<Pixels>& rawProfiles
+);
+static QSharedPointer<CalibrationTable> calibrateZ(
+ const QList<Pixels>& rawProfiles
+);
+
+static QImage calibrationTableToImage(
+ const QSharedPointer<CalibrationTable>& calibrationTable
+);
+
+static void interpolate(QSharedPointer<CalibrationTable>& table);
+static void interpolate(CalibrationColumn& column);
auto printPixels = [](const auto& pixels) {
- for (size_t i = (img_width - 10) / 2; i < img_width - ((img_width - 10) / 2); ++i)
+ for (size_t i = (img_width - 10) / 2;
+ i < img_width - ((img_width - 10) / 2);
+ ++i)
{
std::cout << pixels[i] << " ";
}
@@ -109,70 +136,100 @@ auto printPixels = [](const auto& pixels) {
bool initLaser();
-class A
+int main(int argc, char* argv[])
{
-public:
- A(const int var) : m_var{ var } { std::cout << m_var << std::endl; }
-
-private:
- int m_var { 0 };
-};
-
-class B : public A
-{
-public:
- B(const int var) : A{var} {}
-};
-
-int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
- // if (!initLaser())
- // {
- // return EXIT_FAILURE;
- // }
+ if (!initLaser())
+ {
+ return EXIT_FAILURE;
+ }
- if (false)
+ PrinterClient printerClient;
+
+ if (true)
{
// auto rawProfiles = openDump("/home/user/dumps/2024.11.24_19.17.32");
// auto rawProfiles = openDump("/home/user/dumps/2024.11.26_21.53.55");
- auto rawProfiles = openDump("/home/user/dumps/2024.11.26_21.53.55_small");
- qDebug() << "raw profiles count is" << rawProfiles.size();
- // qDebug() << "height" << calibrationColumnHeight;
+ // auto rawProfiles =
+ // openDump("/home/user/dumps/2024.11.26_21.53.55_small");
+
+ {
+ auto rawProfiles = openDump("/home/user/dumps/2024.12.07_14.09.33");
+ // auto rawProfiles = openDump("/home/user/dumps/z");
+ qDebug() << "raw z-profiles count is" << rawProfiles.size();
+ // qDebug() << "height" << calibrationColumnHeight;
+
+ auto filteredRawProfiles = filter(std::move(rawProfiles));
+ qDebug() << "filtered z-profiles count is"
+ << filteredRawProfiles.count();
+
+ ::calibrationTableZ = calibrateZ(std::move(filteredRawProfiles));
+
+ bool ok = calibrationTableToImage(::calibrationTableZ)
+ .save("/home/user/dumps/z/imageZ.png");
- auto filteredRawProfiles = filter(rawProfiles);
- qDebug() << "filtered profiles count is" << filteredRawProfiles.count();
+ if (!ok)
+ {
+ qDebug() << "cannot save imageZ.png";
+ exit(EXIT_FAILURE);
+ }
+
+ interpolate(::calibrationTableZ);
+
+ calibrationTableToImage(::calibrationTableZ)
+ .save("/home/user/dumps/z/imageZ_interpolated.png");
+ }
+
+ {
+ auto rawProfiles = openDump("/home/user/dumps/2024.12.07_14.51.07");
+ qDebug() << "raw x-profiles count is" << rawProfiles.size();
+ // qDebug() << "height" << calibrationColumnHeight;
- auto calibrationTable = calibrate(filteredRawProfiles);
- // auto calibrationTable = calibrate(rawProfiles);
- // CalibrationTable* aaa { new CalibrationTable {{ 0 }} };
- // (*aaa)[1][0] = 123;
- // CalibrationTable bbb {{ 0 }};
- // bbb[1][0] = 123;
+ auto filteredRawProfiles = filter(std::move(rawProfiles));
+ qDebug() << "filtered x-profiles count is"
+ << filteredRawProfiles.count();
- // float* values = new float[calibrationColumnHeight];
+ ::calibrationTableX = calibrateX(std::move(filteredRawProfiles));
+
+ bool ok = calibrationTableToImage(::calibrationTableX)
+ .save("/home/user/dumps/z/imageX.png");
+
+ if (!ok)
+ {
+ qDebug() << "cannot save imageX.png";
+ exit(EXIT_FAILURE);
+ }
+
+ interpolate(::calibrationTableX);
+
+ calibrationTableToImage(::calibrationTableX)
+ .save("/home/user/dumps/z/imageX_interpolated.png");
+ }
}
+ // exit(EXIT_SUCCESS);
+
QElapsedTimer t;
t.start();
qDebug() << "msecs before encoder:" << t.elapsed();
RotaryEncoder encoder;
- PrinterClient printerClient;
qDebug() << "msecs before camera:" << t.elapsed();
// FIXME: don't use one var for everything
int ret;
- std::unique_ptr<libcamera::CameraManager> cm = std::make_unique<libcamera::CameraManager>();
+ std::unique_ptr<libcamera::CameraManager> cm =
+ std::make_unique<libcamera::CameraManager>();
cm->start();
const auto cameras = cm->cameras();
- openDump();
+ // openDump();
if (cameras.empty())
- {
+ {
std::cout << "No cameras were identified on the system." << std::endl;
cm->stop();
@@ -200,8 +257,10 @@ int main(int argc, char *argv[]) {
}
// FIXME: nullptr
- // std::unique_ptr<CameraConfiguration> config = camera->generateConfiguration( { StreamRole::Viewfinder } );
- /*std::unique_ptr<CameraConfiguration> */config = camera->generateConfiguration( { libcamera::StreamRole::Raw } );
+ // std::unique_ptr<CameraConfiguration> config =
+ // camera->generateConfiguration( { StreamRole::Viewfinder } );
+ /*std::unique_ptr<CameraConfiguration> */ config =
+ camera->generateConfiguration({libcamera::StreamRole::Raw});
if (config->empty())
{
@@ -224,12 +283,15 @@ int main(int argc, char *argv[]) {
// }
// FIXME: nullptr
- libcamera::StreamConfiguration &streamConfig = config->at(0);
- std::cout << "Default viewfinder configuration is: " << streamConfig.toString() << std::endl;
- std::cout << "Pixel format is: " << streamConfig.pixelFormat.toString() << std::endl;
+ libcamera::StreamConfiguration& streamConfig = config->at(0);
+ std::cout << "Default viewfinder configuration is: "
+ << streamConfig.toString() << std::endl;
+ std::cout << "Pixel format is: " << streamConfig.pixelFormat.toString()
+ << std::endl;
std::cout << "Buffer count is: " << streamConfig.bufferCount << std::endl;
// FIXME: empty variant
- std::cout << "Color space is: " << streamConfig.colorSpace.value().toString() << std::endl;
+ std::cout << "Color space is: "
+ << streamConfig.colorSpace.value().toString() << std::endl;
std::cout << "Orientation is: " << config->orientation << std::endl;
// formats::R8,
// formats::R10,
@@ -263,7 +325,8 @@ int main(int argc, char *argv[]) {
// doit(Rotate270Mirror);
// doit(Rotate90);
- std::cout << "new config " << streamConfig.toString() << std::endl;
+ std::cout
+ << "new config " << streamConfig.toString() << std::endl;
// FIXME: may crassh even on success (e.g. by setting pixelFormat to "8")
if (camera->configure(config.get()) != EXIT_SUCCESS)
@@ -292,13 +355,15 @@ int main(int argc, char *argv[]) {
}
size_t allocated = size_t(ret);
- std::cout << "Allocated " << allocated << " buffers for stream" << std::endl;
+ std::cout << "Allocated " << allocated << " buffers for stream"
+ << std::endl;
- const std::vector<std::unique_ptr<libcamera::FrameBuffer>> &buffers = allocator->buffers(stream);
+ const std::vector<std::unique_ptr<libcamera::FrameBuffer>>& buffers =
+ allocator->buffers(stream);
// for (size_t i = 0; i < buffers.size(); ++i)
static int expOffset = 0;
- for (const auto & buffer : buffers)
+ for (const auto& buffer : buffers)
{
std::unique_ptr<libcamera::Request> request = camera->createRequest();
@@ -318,10 +383,16 @@ int main(int argc, char *argv[]) {
return ret;
}
- for (const auto & plane : buffer->planes())
+ for (const auto& plane : buffer->planes())
{
- void *memory = mmap(NULL, plane.length, PROT_READ, MAP_SHARED,
- plane.fd.get(), 0);
+ void* memory = mmap(
+ NULL,
+ plane.length,
+ PROT_READ,
+ MAP_SHARED,
+ plane.fd.get(),
+ 0
+ );
mappedBuffers_[plane.fd.get()] =
std::make_pair(memory, plane.length);
}
@@ -330,20 +401,24 @@ int main(int argc, char *argv[]) {
std::int64_t lowerUS = 1 * 1000 * 1000 / desiredFPS;
std::int64_t higherUS = lowerUS;
- std::int64_t value_pair[2] = { higherUS / 2, higherUS };
+ std::int64_t value_pair[2] = {higherUS / 2, higherUS};
request->controls().set(libcamera::controls::AnalogueGain, 1.0);
request->controls().set(libcamera::controls::ExposureTime, 100);
request->controls().set(
libcamera::controls::FrameDurationLimits,
- libcamera::Span<const std::int64_t, 2>(value_pair));
+ libcamera::Span<const std::int64_t, 2>(value_pair)
+ );
requests.push_back(std::move(request));
}
camera->requestCompleted.connect(onRequestCompleted);
- std::unique_ptr<libcamera::ControlList> camcontrols { new libcamera::ControlList() };
- // camcontrols->set(controls::FrameDurationLimits, libcamera::Span<const std::int64_t, 2>({8702, 10718903}));
+ std::unique_ptr<libcamera::ControlList> camcontrols{
+ new libcamera::ControlList()
+ };
+ // camcontrols->set(controls::FrameDurationLimits, libcamera::Span<const
+ // std::int64_t, 2>({8702, 10718903}));
// camcontrols->set(controls::ExposureTime, 100);
// camcontrols->set(controls::AnalogueGain, 0.1);
@@ -357,7 +432,7 @@ int main(int argc, char *argv[]) {
// camera->start();
- for (auto & request : requests)
+ for (auto& request : requests)
{
camera->queueRequest(request.get());
}
@@ -388,15 +463,16 @@ int main(int argc, char *argv[]) {
QJsonArray pixels;
- for (size_t i = 0; i < img_width; ++i) {
+ for (size_t i = 0; i < img_width; ++i)
+ {
// pixels << img_height - img.pixels[i];
pixels << ::pixels.pixels[i];
}
QJsonObject json;
json["pixels"] = pixels;
- json["encoderPosition"] = qint64 { encoder.position() };
- json["measurementCounter"] = qint64 { img.counters.measurementCounter };
+ json["encoderPosition"] = qint64{encoder.position()};
+ json["measurementCounter"] = qint64{img.counters.measurementCounter};
json["timestampUs"] = qint64(img.counters.timestampUs);
const auto lines = pixelsToLines(::pixels);
@@ -407,9 +483,9 @@ int main(int argc, char *argv[]) {
for (const auto& l : lines)
{
- jsonLines << QJsonArray {
- QJsonArray { l.p1().x(), l.p1().y() },
- QJsonArray { l.p2().x(), l.p2().y() }
+ jsonLines << QJsonArray{
+ QJsonArray{l.p1().x(), l.p1().y()},
+ QJsonArray{l.p2().x(), l.p2().y()}
};
}
@@ -418,155 +494,178 @@ int main(int argc, char *argv[]) {
return QHttpServerResponse(QJsonDocument(json).toJson());
});
+ qHttpServer.route(
+ "/v1/commands/resetEncoder",
+ [&](const QHttpServerRequest& request) -> QHttpServerResponse {
+ if (request.method() != QHttpServerRequest::Method::Post)
+ {
+ return QHttpServerResponse::StatusCode::NotFound;
+ }
- qHttpServer.route("/v1/commands/resetEncoder", [&](const QHttpServerRequest &request) -> QHttpServerResponse {
- if (request.method() != QHttpServerRequest::Method::Post) {
- return QHttpServerResponse::StatusCode::NotFound;
- }
-
- qDebug() << "reset encoder";
-
- positionSteps = 0;
+ qDebug() << "reset encoder";
- return QHttpServerResponse::StatusCode::Ok;
- });
+ positionSteps = 0;
- qHttpServer.route("/v1/commands/startCalibration", [&](const QHttpServerRequest &request) -> QHttpServerResponse {
- if (request.method() != QHttpServerRequest::Method::Post) {
- return QHttpServerResponse::StatusCode::NotFound;
+ return QHttpServerResponse::StatusCode::Ok;
}
+ );
- qDebug() << "start calibration";
+ qHttpServer.route(
+ "/v1/commands/startCalibration",
+ [&](const QHttpServerRequest& request) -> QHttpServerResponse {
+ if (request.method() != QHttpServerRequest::Method::Post)
+ {
+ return QHttpServerResponse::StatusCode::NotFound;
+ }
- // TODO: use flags
- scanningModeFlags = ScanningModeFlags::Calibration;
- calibrationTimer.start();
+ qDebug() << "start calibration";
- return QHttpServerResponse::StatusCode::Ok;
- });
+ // TODO: use flags
+ scanningModeFlags = ScanningModeFlags::Calibration;
+ calibrationTimer.start();
- qHttpServer.route("/v1/commands/gCode", [&](const QHttpServerRequest &request) -> QHttpServerResponse {
- if (request.method() != QHttpServerRequest::Method::Post) {
- return QHttpServerResponse::StatusCode::NotFound;
+ return QHttpServerResponse::StatusCode::Ok;
}
+ );
- const auto command = request.body();
+ qHttpServer.route(
+ "/v1/commands/gCode",
+ [&](const QHttpServerRequest& request) -> QHttpServerResponse {
+ if (request.method() != QHttpServerRequest::Method::Post)
+ {
+ return QHttpServerResponse::StatusCode::NotFound;
+ }
- qDebug() << "send gCode:" << command;
+ const auto command = request.body();
- printerClient.sendCommand(command);
+ qDebug() << "send gCode:" << command;
- return QHttpServerResponse::StatusCode::Ok;
- });
+ printerClient.sendCommand(command);
- qHttpServer.route("/v1/commands/startCalibration", [&](const QHttpServerRequest &request) -> QHttpServerResponse {
- if (request.method() != QHttpServerRequest::Method::Post) {
- return QHttpServerResponse::StatusCode::NotFound;
+ return QHttpServerResponse::StatusCode::Ok;
}
+ );
- const auto command = request.body();
+ qHttpServer.route(
+ "/v1/commands/startCalibration",
+ [&](const QHttpServerRequest& request) -> QHttpServerResponse {
+ if (request.method() != QHttpServerRequest::Method::Post)
+ {
+ return QHttpServerResponse::StatusCode::NotFound;
+ }
- qDebug() << "send gCode:" << command;
+ const auto command = request.body();
- printerClient.sendCommand(command);
+ qDebug() << "send gCode:" << command;
- return QHttpServerResponse::StatusCode::Ok;
- });
+ printerClient.sendCommand(command);
- qHttpServer.route("/v1/sensor/params", [&](const QHttpServerRequest &request) -> QHttpServerResponse {
+ return QHttpServerResponse::StatusCode::Ok;
+ }
+ );
- switch (request.method()) {
- case QHttpServerRequest::Method::Get:
- {
- std::lock_guard<std::mutex> lg(pgm_image_mtx);
- QJsonObject json;
+ qHttpServer.route(
+ "/v1/sensor/params",
+ [&](const QHttpServerRequest& request) -> QHttpServerResponse {
+ switch (request.method())
+ {
+ case QHttpServerRequest::Method::Get: {
+ std::lock_guard<std::mutex> lg(pgm_image_mtx);
+ QJsonObject json;
- const libcamera::ControlIdMap & ctrlIdMap = camera->controls().idmap();
+ const libcamera::ControlIdMap& ctrlIdMap =
+ camera->controls().idmap();
- qDebug() << "readParams:" << lastControls.size();
- qDebug() << request.method();
+ qDebug() << "readParams:" << lastControls.size();
+ qDebug() << request.method();
- for (const auto & [id, value]: lastControls)
- {
- const libcamera::ControlId * controlId = ctrlIdMap.at(id);
- auto name = QString::fromStdString(controlId->name());
- const auto valueStr = QString::fromStdString(value.toString());
- qDebug() << "\t param:"
- << controlId->id()
- << name
- << valueStr
- ;
+ for (const auto& [id, value] : lastControls)
+ {
+ const libcamera::ControlId* controlId = ctrlIdMap.at(id);
+ auto name = QString::fromStdString(controlId->name());
+ const auto valueStr =
+ QString::fromStdString(value.toString());
+ qDebug()
+ << "\t param:" << controlId->id() << name << valueStr;
- name[0] = name[0].toLower();
- json[name] = valueStr;
- }
+ name[0] = name[0].toLower();
+ json[name] = valueStr;
+ }
- json[laserLevelKey] = requested_params.laserLevel;
+ json[laserLevelKey] = requested_params.laserLevel;
- qDebug() << "response body:" << json;
+ qDebug() << "response body:" << json;
- // QHttpServerResponse
- return QHttpServerResponse(QJsonDocument(json).toJson());
- }
+ // QHttpServerResponse
+ return QHttpServerResponse(QJsonDocument(json).toJson());
+ }
- case QHttpServerRequest::Method::Post:
- {
- qDebug() << "request body:" << request.body();
+ case QHttpServerRequest::Method::Post: {
+ qDebug() << "request body:" << request.body();
- auto json = QJsonDocument::fromJson(request.body()).object();
+ auto json = QJsonDocument::fromJson(request.body()).object();
+
+ if (json.contains(exposureTimeKey))
+ {
+ const int32_t value{json[exposureTimeKey].toInt()};
- if (json.contains(exposureTimeKey)) {
- const int32_t value { json[exposureTimeKey].toInt() };
+ if (value == 0)
+ {
+ return QHttpServerResponse::StatusCode::NotFound;
+ }
- if (value == 0) {
- return QHttpServerResponse::StatusCode::NotFound;
+ qDebug() << "set new exposure time:" << value;
+ requested_params.exposureTime = value;
}
- qDebug() << "set new exposure time:" << value;
- requested_params.exposureTime = value;
- }
+ if (json.contains(laserLevelKey))
+ {
+ const int32_t value{json[laserLevelKey].toInt()};
- if (json.contains(laserLevelKey)) {
- const int32_t value { json[laserLevelKey].toInt() };
+ if (value == 0)
+ {
+ return QHttpServerResponse::StatusCode::NotFound;
+ }
- if (value == 0) {
- return QHttpServerResponse::StatusCode::NotFound;
- }
+ qDebug() << "set new laserLevel:" << value;
+ requested_params.laserLevel = value;
- qDebug() << "set new laserLevel:" << value;
- requested_params.laserLevel = value;
+ const QString laserLevelFile{
+ "/sys/class/pwm/pwmchip2/pwm1/duty_cycle"
+ };
+ QFile f{laserLevelFile};
- const QString laserLevelFile { "/sys/class/pwm/pwmchip2/pwm1/duty_cycle"};
- QFile f { laserLevelFile };
+ if (!f.open(QFile::ReadWrite))
+ {
+ qDebug() << "cannot open laser level file:"
+ << f.errorString();
+ qDebug() << "file path is" << f.fileName();
+ return QHttpServerResponse::StatusCode::
+ InternalServerError;
+ }
- if (!f.open(QFile::ReadWrite)) {
- qDebug() << "cannot open laser level file:" << f.errorString();
- qDebug() << "file path is" << f.fileName();
- return QHttpServerResponse::StatusCode::InternalServerError;
- }
+ QTextStream s{&f};
- QTextStream s { &f };
+ s << value;
- s << value;
+ s >> requested_params.laserLevel;
- s >> requested_params.laserLevel;
+ qDebug() << "done with laser level";
+ }
- qDebug() << "done with laser level";
+ return QHttpServerResponse(request.body());
+ }
+ default: {
+ return QHttpServerResponse(QByteArray("unsupported http method")
+ );
+ }
}
-
- return QHttpServerResponse(request.body());
- }
- default:
- {
- return QHttpServerResponse(QByteArray("unsupported http method"));
- }
}
- });
+ );
qDebug() << "listen: " << qHttpServer.listen(QHostAddress::Any, 8081);
- QFuture<void> future = QtConcurrent::run([](){
-
+ QFuture<void> future = QtConcurrent::run([]() {
Port port(8080);
Address addr(Ipv4::any(), port);
@@ -591,7 +690,7 @@ int main(int argc, char *argv[]) {
future.cancel();
future.waitForFinished();
- for (auto & [fd, mem] : mappedBuffers_)
+ for (auto& [fd, mem] : mappedBuffers_)
{
munmap(mem.first, mem.second);
}
@@ -632,7 +731,8 @@ int main(int argc, char *argv[]) {
// // ControlList controls_;
// int64_t frame_time = 1000000 / 10;
// // Set frame rate
- // // controls_.set( controls::FrameDurationLimits, libcamera::Span<const int64_t, 2>(
+ // // controls_.set( controls::FrameDurationLimits, libcamera::Span<const
+ // int64_t, 2>(
// // { frame_time, frame_time } ));
// // Adjust the brightness of the output images, in the range -1.0 to 1.0
// // controls_.set(controls::Brightness, 0.5);
@@ -666,7 +766,6 @@ int main(int argc, char *argv[]) {
// // cam.set(controls);
// // }
-
// frame_count++;
// if ((time(0) - start_time) >= 1){
// printf("fps: %d\n", frame_count);
@@ -688,17 +787,18 @@ int main(int argc, char *argv[]) {
* Signals operate in the libcamera CameraManager thread context, so it is
* important not to block the thread for a long time, as this blocks internal
* processing of the camera pipelines, and can affect realtime performance.
-*/
-void onRequestCompleted(libcamera::Request *completed_request)
+ */
+void onRequestCompleted(libcamera::Request* completed_request)
{
using namespace libcamera;
- static std::chrono::steady_clock::time_point fpsTimstamp = std::chrono::steady_clock::now();
+ static std::chrono::steady_clock::time_point fpsTimstamp =
+ std::chrono::steady_clock::now();
QElapsedTimer t;
t.start();
- static uint32_t performanceCounter { 0 };
- static uint32_t elapsedSum { 0 };
+ static uint32_t performanceCounter{0};
+ static uint32_t elapsedSum{0};
bool verbose = false;
@@ -709,19 +809,20 @@ void onRequestCompleted(libcamera::Request *completed_request)
return;
}
- const std::map<const Stream *, FrameBuffer *> &buffers = completed_request->buffers();
+ const std::map<const Stream*, FrameBuffer*>& buffers =
+ completed_request->buffers();
// std::cout << "request completed, buffers count is " << buffers.size();
// // TODO: rewrite this shit
for (auto [stream, buffer] : buffers)
{
- const auto & streamConfig = stream->configuration();
- const auto & imageSize = streamConfig.size;
- const auto & pixelFormat = streamConfig.pixelFormat;
- const auto & stride = streamConfig.stride;
+ const auto& streamConfig = stream->configuration();
+ const auto& imageSize = streamConfig.size;
+ const auto& pixelFormat = streamConfig.pixelFormat;
+ const auto& stride = streamConfig.stride;
- const FrameMetadata &metadata = buffer->metadata();
+ const FrameMetadata& metadata = buffer->metadata();
// if (verbose)
// {
@@ -732,12 +833,12 @@ void onRequestCompleted(libcamera::Request *completed_request)
for (size_t i = 0; i < buffer->planes().size(); ++i)
{
- const FrameBuffer::Plane & plane = buffer->planes()[i];
- const FrameMetadata::Plane & metaplane = buffer->metadata().planes()[i];
+ const FrameBuffer::Plane& plane = buffer->planes()[i];
+ const FrameMetadata::Plane& metaplane =
+ buffer->metadata().planes()[i];
size_t size = std::min(metaplane.bytesused, plane.length);
- void * data = mappedBuffers_[plane.fd.get()].first;
-
+ void* data = mappedBuffers_[plane.fd.get()].first;
// FIXME: remove hardcode
img.width = imageSize.width;
@@ -749,7 +850,8 @@ void onRequestCompleted(libcamera::Request *completed_request)
img.pixelFormat = pixelFormat;
img.counters.measurementCounter = metadata.sequence;
img.counters.timestampUs = metadata.timestamp / 1000;
- img.counters.encoderPosition = RotaryEncoder::instance()->position();
+ img.counters.encoderPosition =
+ RotaryEncoder::instance()->position();
// qDebug() << "pos:" << img.counters.encoderPosition;
// uint16_t unpacked[img.width * img.height] = { 0 };
@@ -762,14 +864,18 @@ void onRequestCompleted(libcamera::Request *completed_request)
// qDebug() << "calibration mode" << scanningModeFlags;
- if (scanningModeFlags == ScanningModeFlags::Calibration) {
- const int32_t maxEncoderPosition = int32_t(hardcodedZRangeMm) * requested_params.stepsPerMm;
+ if (scanningModeFlags == ScanningModeFlags::Calibration)
+ {
+ const int32_t maxEncoderPosition =
+ int32_t(hardcodedZRangeMm) * requested_params.stepsPerMm;
// qDebug() << "calibration max range" << maxEncoderPosition;
- // qDebug() << "calibration encoder pos" << pixels.counters.encoderPosition;
+ // qDebug() << "calibration encoder pos" <<
+ // pixels.counters.encoderPosition;
if (pixels.counters.encoderPosition >= 0 &&
pixels.counters.encoderPosition <= maxEncoderPosition)
{
- qDebug() << "calibration save at pos:" << pixels.counters.encoderPosition;
+ qDebug() << "calibration save at pos:"
+ << pixels.counters.encoderPosition;
QMutexLocker l(&calibrationPixelsMutex);
::calibrationPixels.push_back(std::move(pixels));
}
@@ -791,7 +897,8 @@ void onRequestCompleted(libcamera::Request *completed_request)
}
else
{
- // qDebug() << "calibration skip at pos:" << pixels.counters.encoderPosition;
+ // qDebug() << "calibration skip at pos:" <<
+ // pixels.counters.encoderPosition;
}
}
@@ -799,15 +906,15 @@ void onRequestCompleted(libcamera::Request *completed_request)
}
}
- const libcamera::ControlList &metadata = completed_request->metadata();
- const ControlInfoMap & control_map = camera->controls();
+ const libcamera::ControlList& metadata = completed_request->metadata();
+ const ControlInfoMap& control_map = camera->controls();
// const ControlIdMap & ctrlIdMap = control_map.idmap();
auto frameDurationCtrl = control_map.find(&controls::FrameDurationLimits);
// auto expTimeCtrl = control_map.find(&controls::ExposureTime);
- double fps = frameDurationCtrl == control_map.end() ?
- std::numeric_limits<double>::quiet_NaN() :
- (1e6 / frameDurationCtrl->second.min().get<int64_t>());
+ double fps = frameDurationCtrl == control_map.end()
+ ? std::numeric_limits<double>::quiet_NaN()
+ : (1e6 / frameDurationCtrl->second.min().get<int64_t>());
auto exp = metadata.get(controls::ExposureTime);
auto ag = metadata.get(controls::AnalogueGain);
@@ -817,26 +924,27 @@ void onRequestCompleted(libcamera::Request *completed_request)
if (verbose)
{
- std::cout << "fps: " << fps
- << " exp: " << *exp
- << " ag: " << *ag
+ std::cout << "fps: " << fps << " exp: " << *exp << " ag: "
+ << *ag
// << " br: " << *br
- << " ae: " << *ae
- << " aa: " << *completed_request->controls()
- .get(libcamera::controls::ExposureTime)
+ << " ae: " << *ae << " aa: "
+ << *completed_request->controls().get(
+ libcamera::controls::ExposureTime
+ )
<< std::endl;
}
completed_request->reuse(Request::ReuseBuffers);
completed_request->controls().set(libcamera::controls::AeEnable, false);
- completed_request->controls().set(libcamera::controls::draft
- ::NoiseReductionMode,
- libcamera::controls::draft
- ::NoiseReductionModeEnum
- ::NoiseReductionModeHighQuality);
- completed_request->controls().set(libcamera::controls::ExposureTime,
- requested_params.exposureTime);
-
+ completed_request->controls().set(
+ libcamera::controls::draft ::NoiseReductionMode,
+ libcamera::controls::draft ::NoiseReductionModeEnum ::
+ NoiseReductionModeHighQuality
+ );
+ completed_request->controls().set(
+ libcamera::controls::ExposureTime,
+ requested_params.exposureTime
+ );
camera->queueRequest(completed_request);
@@ -844,20 +952,23 @@ void onRequestCompleted(libcamera::Request *completed_request)
elapsedSum += t.elapsed();
// if (performanceCounter == 20)
- std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+ std::chrono::steady_clock::time_point now =
+ std::chrono::steady_clock::now();
if ((now - fpsTimstamp) > 1000ms)
{
- auto msPerFrame { float(elapsedSum / performanceCounter) };
+ auto msPerFrame{float(elapsedSum / performanceCounter)};
- double configFps = frameDurationCtrl == control_map.end() ?
- std::numeric_limits<double>::quiet_NaN() :
- (1e6 / frameDurationCtrl->second.min().get<int64_t>());
+ double configFps =
+ frameDurationCtrl == control_map.end()
+ ? std::numeric_limits<double>::quiet_NaN()
+ : (1e6 / frameDurationCtrl->second.min().get<int64_t>());
- auto fps { 1000.f / msPerFrame };
+ auto fps{1000.f / msPerFrame};
qDebug() << "fps ideal/real is" << configFps << "/" << fps
- << "; ms per frame is" << msPerFrame << "counted fps" << performanceCounter;
+ << "; ms per frame is" << msPerFrame << "counted fps"
+ << performanceCounter;
elapsedSum = 0;
performanceCounter = 0;
@@ -865,29 +976,29 @@ void onRequestCompleted(libcamera::Request *completed_request)
}
// qDebug() << "-------------------------------------------";
-
}
-static bool applyConfig(const std::unique_ptr<libcamera::CameraConfiguration> & config)
+static bool applyConfig(
+ const std::unique_ptr<libcamera::CameraConfiguration>& config
+)
{
using namespace libcamera;
auto status = config->validate();
// WARNING: unsafe
- libcamera::StreamConfiguration &streamConfig = config->at(0);
+ libcamera::StreamConfiguration& streamConfig = config->at(0);
- switch (status) {
+ switch (status)
+ {
case CameraConfiguration::Status::Valid:
std::cout << "config is valid" << std::endl;
break;
case CameraConfiguration::Status::Adjusted:
- std::cout << "\tpixelFormat: "
- << streamConfig.pixelFormat.toString() << std::endl;
- std::cout << "\tbufferCount: "
- << streamConfig.bufferCount << std::endl;
- std::cout << "\torientation: "
- << config->orientation << std::endl;
+ std::cout << "\tpixelFormat: " << streamConfig.pixelFormat.toString()
+ << std::endl;
+ std::cout << "\tbufferCount: " << streamConfig.bufferCount << std::endl;
+ std::cout << "\torientation: " << config->orientation << std::endl;
break;
case CameraConfiguration::Status::Invalid:
std::cout << "config is invalid, quit." << std::endl;
@@ -901,18 +1012,19 @@ static bool applyConfig(const std::unique_ptr<libcamera::CameraConfiguration> &
static void printControls()
{
using namespace libcamera;
- const libcamera::ControlInfoMap & control_map = camera->controls();
+ const libcamera::ControlInfoMap& control_map = camera->controls();
// for (const auto & [id, info]: control_map)
- for (const std::pair<const ControlId *, ControlInfo> & pair : control_map)
+ for (const std::pair<const ControlId*, ControlInfo>& pair : control_map)
{
- const ControlId * const & id = pair.first;
- const ControlInfo & info = pair.second;
+ const ControlId* const& id = pair.first;
+ const ControlInfo& info = pair.second;
- std::cout << "\tc " << id->name()
- << " (" << id->id()
+ std::cout << "\tc " << id->name() << " (" << id->id()
<< "): " << info.toString()
- << (info.def().isNone() ? "" : " (dflt:" + info.def().toString() + ")");
+ << (info.def().isNone()
+ ? ""
+ : " (dflt:" + info.def().toString() + ")");
if (!info.values().size())
{
@@ -922,7 +1034,7 @@ static void printControls()
std::cout << " - [";
- for (const auto & v : info.values())
+ for (const auto& v : info.values())
{
std::cout << " " << v.toString();
}
@@ -940,26 +1052,27 @@ static void dumpCalibrationPixels()
std::swap(rawProfiles, ::calibrationPixels);
}
- const QString dumpSubdir {
+ const QString dumpSubdir{
QDateTime::currentDateTime().toString("yyyy.MM.dd_hh.mm.ss")
};
- const QDir dumpPath { dumpsRoot + "/" + dumpSubdir };
+ const QDir dumpPath{dumpsRoot + "/" + dumpSubdir};
if (!dumpPath.mkdir(dumpPath.path()))
{
- qWarning() << "cannot create dump dir: " << dumpPath.path();
+ qWarning() << "cannot create dir: " << dumpPath.path();
return;
}
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);
+ const auto filename =
+ QLatin1String("raw_profile_meas_%1_enc_%2")
+ .arg(QString::number(rawProfile.counters.measurementCounter))
+ .arg(rawProfile.counters.encoderPosition);
const auto filepath = dumpPath.path() + "/" + filename;
- QFile f { filepath };
+ QFile f{filepath};
if (!f.open(QFile::WriteOnly))
{
@@ -969,11 +1082,12 @@ static void dumpCalibrationPixels()
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;
@@ -1002,16 +1116,16 @@ static void dumpCalibrationPixels()
qDebug() << "dump finished";
}
-static QList<Pixels> openDump(const QString &dumpPath)
+static QList<Pixels> openDump(const QString& dumpPath)
{
- QString dirToRead { dumpPath };
+ QString dirToRead{dumpPath};
qDebug() << "trying to open dump path:" << dirToRead;
if (dirToRead.isEmpty())
{
qDebug() << "dumpPath not specified. looking into" << dumpsRoot;
- QDir dumpsRootDir { dumpsRoot };
+ QDir dumpsRootDir{dumpsRoot};
const auto filter = QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable;
// there is no battery in my rpi5 for now
@@ -1029,12 +1143,12 @@ static QList<Pixels> openDump(const QString &dumpPath)
dirToRead = dumpsRoot + "/" + entries.last();
}
- QDir dumpDir { dirToRead };
+ QDir dumpDir{dirToRead};
const auto filter = QDir::Files;
const auto sort = QDir::Name;
- const auto filenames = dumpDir.entryList(filter, sort);
+ auto filenames = dumpDir.entryList(filter, sort);
if (filenames.isEmpty())
{
@@ -1042,36 +1156,47 @@ static QList<Pixels> openDump(const QString &dumpPath)
return {};
}
- QList<std::optional<Pixels>> resultOptionals { filenames.size() };
+ qDebug() << "create results array" << filenames.size();
+ auto resultOptionals =
+ QScopedPointer(new QList<std::optional<Pixels>>(filenames.size()));
QElapsedTimer t;
t.start();
+ qDebug() << "open real files";
std::transform(
- std::execution::par,
- filenames.begin(), filenames.end(),
- resultOptionals.begin(),
+ std::execution::par_unseq,
+ filenames.begin(),
+ filenames.end(),
+ resultOptionals->begin(),
[dirToRead](const auto& filename) {
- std::cout << '.';
+ // std::cout << '.';
return openRawProfile(dirToRead + "/" + filename);
- });
+ }
+ );
- std::cout << std::endl;
+ filenames.clear();
+ filenames.squeeze();
+
+ qDebug() << Q_FUNC_INFO << "open raw profiles: elapsed (ms)" << t.elapsed();
+ // std::cout << std::endl;
std::remove_if(
std::execution::par,
- resultOptionals.begin(),
- resultOptionals.end(),
- [](auto& a) { return !a.has_value(); });
+ resultOptionals->begin(),
+ resultOptionals->end(),
+ [](auto& a) { return !a.has_value(); }
+ );
- QList<Pixels> result { resultOptionals.size() };
+ QList<Pixels> result(resultOptionals->size());
std::transform(
std::execution::par,
- std::make_move_iterator(resultOptionals.begin()),
- std::make_move_iterator(resultOptionals.end()),
+ std::make_move_iterator(resultOptionals->begin()),
+ std::make_move_iterator(resultOptionals->end()),
result.begin(),
- [](auto& p) { return p.value(); });
+ [](auto& p) { return p.value(); }
+ );
qDebug() << Q_FUNC_INFO << "elapsed (ms)" << t.elapsed();
@@ -1080,7 +1205,7 @@ static QList<Pixels> openDump(const QString &dumpPath)
static std::optional<Pixels> openRawProfile(const QString& filePath)
{
- QFile f { filePath };
+ QFile f{filePath};
if (!f.open(QFile::ReadOnly))
{
@@ -1096,15 +1221,26 @@ static std::optional<Pixels> openRawProfile(const QString& filePath)
Pixels result;
result.counters.timestampUs = jsonCounters["timestampUs"].toInteger();
- result.counters.measurementCounter = jsonCounters["measurementCounter"].toInteger();
- result.counters.encoderPosition = jsonCounters["encoderPosition"].toInteger();
+ result.counters.measurementCounter =
+ jsonCounters["measurementCounter"].toInteger();
+ result.counters.encoderPosition =
+ jsonCounters["encoderPosition"].toInteger();
const auto jsonPixels = json["pixels"].toArray();
+ // TODO: check json pixels count
+ std::transform(
+ // std::execution::par_unseq,
+ jsonPixels.constBegin(),
+ jsonPixels.constEnd(),
+ result.pixels.begin(),
+ [](const auto& jsonPixel) { return jsonPixel.toDouble(); }
+ );
- for (size_t i = 0; i < jsonPixels.count() && i < result.pixels.size(); ++i)
- {
- result.pixels[i] = jsonPixels[i].toDouble();
- }
+ // for (size_t i = 0; i < jsonPixels.count() && i < result.pixels.size();
+ // ++i)
+ // {
+ // result.pixels[i] = jsonPixels[i].toDouble();
+ // }
return result;
}
@@ -1117,36 +1253,38 @@ static QList<Pixels> filter(const QList<Pixels>& rawProfiles)
// for (size_t i = 0; i < 10; ++i)
// {
- // std::cout << "pos - " << rawProfiles.at(i).counters.encoderPosition << std::endl;
+ // std::cout << "pos - " << rawProfiles.at(i).counters.encoderPosition
+ // << std::endl;
// }
// ++it;
while (it != rawProfiles.constEnd())
{
Pixels sum = *it;
- std::cout << "current pos is " << sum.counters.encoderPosition << std::endl;
+ // std::cout << "current pos is " << sum.counters.encoderPosition
+ // << std::endl;
- printPixels(sum.pixels);
+ // printPixels(sum.pixels);
- size_t count { 1 };
+ size_t count{1};
++it;
- std::cout << "here\n";
- while (it != rawProfiles.constEnd() && it->counters.encoderPosition == sum.counters.encoderPosition)
+ // std::cout << "here\n";
+ while (it != rawProfiles.constEnd() &&
+ it->counters.encoderPosition == sum.counters.encoderPosition)
{
- std::cout << "here2\n";
- std::cout << "\tadd to pos " << it->counters.encoderPosition << std::endl;
+ // std::cout << "here2\n";
+ // std::cout << "\tadd to pos " << it->counters.encoderPosition
+ // << std::endl;
sum += *it;
- std::cout << "\tadded" << std::endl;
+ // std::cout << "\tadded" << std::endl;
++count;
++it;
-
}
-
- std::cout << "here3\n";
+ // std::cout << "here3\n";
sum /= float(count);
- printPixels(sum.pixels);
+ // printPixels(sum.pixels);
result << sum;
@@ -1156,31 +1294,34 @@ static QList<Pixels> filter(const QList<Pixels>& rawProfiles)
return result;
}
-static QSharedPointer<CalibrationTable> calibrate(const QList<Pixels>& rawProfiles)
+static QSharedPointer<CalibrationTable> calibrateZ(
+ const QList<Pixels>& rawProfiles
+)
{
- QSharedPointer<CalibrationTable> result { new CalibrationTable {{ 0 }} };
-
- constexpr uint16_t discretesInRage { 16384 };
+ QSharedPointer<CalibrationTable> result{new CalibrationTable{{0}}};
for (const auto& rawProfile : rawProfiles)
{
- std::cout << "calibration: pos is " << rawProfile.counters.encoderPosition << std::endl;
- const float positionMm {
+ // std::cout << "calibration: pos is "
+ // << rawProfile.counters.encoderPosition << std::endl;
+ const float positionMm{
float(rawProfile.counters.encoderPosition) /
float(requested_params.stepsPerMm)
};
const auto& pixels = rawProfile.pixels;
- printPixels(pixels);
+ // printPixels(pixels);
// static size_t counter { 0 };
// qDebug() << "calibrated" << counter++;
const float pos = rawProfile.counters.encoderPosition;
const float divider = requested_params.stepsPerMm;
- std::cout << pos << " " << divider << " " << pos / divider << std::endl;
- // std::cout << std::setw(5) << rawProfile.counters.encoderPosition
+ // std::cout << pos << " " << divider << " " << pos / divider <<
+ // std::endl; std::cout << std::setw(5) <<
+ // rawProfile.counters.encoderPosition
// << std::setw(5) << requested_params.stepsPerMm
// << std::setw(8) << positionMm
- // << std::setw(8) << float(rawProfile.counters.encoderPosition) /
+ // << std::setw(8) <<
+ // float(rawProfile.counters.encoderPosition) /
// float(requested_params.stepsPerMm)
// << ": ";
@@ -1189,31 +1330,34 @@ static QSharedPointer<CalibrationTable> calibrate(const QList<Pixels>& rawProfil
const auto& pixelValue = pixels.at(columnIdx);
// float[0, img_height] -> uint16_t[0, calibrationColumnHeight]
- const uint16_t discretePixelValue {
+ const uint16_t discretePixelValue{
uint16_t(pixelValue * discretesInRage / img_height)
};
- Q_ASSERT_X(discretePixelValue > 0 && discretePixelValue < calibrationColumnHeight,
- Q_FUNC_INFO,
- ("got ivalid discrete value " +
- QString::number(discretePixelValue) +
- ". pixelValues is " +
- QString::number(pixelValue) +
- ". calc result is " +
- QString::number(pixelValue * discretesInRage / img_height)
- ).toStdString().c_str());
+ Q_ASSERT_X(
+ discretePixelValue > 0 &&
+ discretePixelValue < calibrationColumnHeight,
+ Q_FUNC_INFO,
+ ("got ivalid discrete value " +
+ QString::number(discretePixelValue) + ". pixelValues is " +
+ QString::number(pixelValue) + ". calc result is " +
+ QString::number(pixelValue * discretesInRage / img_height))
+ .toStdString()
+ .c_str()
+ );
// auto& calibrationColumn = result[columnIdx];
auto& calibrationColumn = (*result)[columnIdx];
calibrationColumn[discretePixelValue] = positionMm;
- if (columnIdx >= ((img_width - 10) / 2) && columnIdx < img_width - ((img_width - 10) / 2))
- {
- std::cout << discretePixelValue << ";";
- }
+ // if (columnIdx >= ((img_width - 10) / 2) &&
+ // columnIdx < img_width - ((img_width - 10) / 2))
+ // {
+ // std::cout << discretePixelValue << ";";
+ // }
}
- std::cout << std::endl << std::flush;
+ // std::cout << std::endl << std::flush;
}
return result;
@@ -1221,16 +1365,123 @@ static QSharedPointer<CalibrationTable> calibrate(const QList<Pixels>& rawProfil
// return {};
}
+static QSharedPointer<CalibrationTable> calibrateX(
+ const QList<Pixels>& rawProfiles
+)
+{
+ QSharedPointer<CalibrationTable> result{new CalibrationTable{{0}}};
+
+ for (const auto& rawProfile : rawProfiles)
+ {
+ const auto& pixels = rawProfile.pixels;
+ auto lines = pixelsToLines(rawProfile);
+
+ Q_ASSERT_X(lines.count() > 2, Q_FUNC_INFO, "no lines");
+
+ QList<double> xAnchors(lines.size() + 1);
+
+ std::transform(
+ std::execution::par_unseq,
+ lines.constBegin(),
+ lines.constEnd(),
+ xAnchors.begin(),
+ [](const auto& l) { return l.x1(); }
+ );
+
+ xAnchors.last() = lines.last().x2();
+
+ constexpr double triangleHeightMm{5.};
+ constexpr double triangleBaseMm{8.};
+
+ auto nearestAnchorToX0 = std::min_element(
+ std::execution::par_unseq,
+ xAnchors.constBegin(),
+ xAnchors.constEnd(),
+ [](const auto& a, const auto& b) {
+ return std::abs(a) < std::abs(b);
+ }
+ );
+
+ int nearestAnchorToX0Idx = nearestAnchorToX0 - xAnchors.constBegin();
+
+ QList<double> xAnchorsMm(xAnchors.count());
+
+ for (int i = 0; i < xAnchors.size(); ++i)
+ {
+ xAnchorsMm[i] = (i - nearestAnchorToX0Idx) * triangleBaseMm / 2.;
+ }
+
+ auto xAnchorIt = xAnchors.constBegin() + 1;
+ auto xAnchorMmIt = xAnchorsMm.constBegin() + 1;
+
+ for (size_t columnIdx = 0; columnIdx < pixels.size(); ++columnIdx)
+ {
+ // skip points with to the left from left line and to the right from
+ // right line
+ const auto columnX = int(columnIdx) - int(img_width / 2);
+ if (columnX < xAnchors.first() || columnX > xAnchors.last())
+ {
+ continue;
+ }
+
+ if (columnX > *xAnchorIt)
+ {
+ ++xAnchorIt;
+ ++xAnchorMmIt;
+ }
+ const auto xLeft = *(xAnchorIt - 1);
+ const auto xRight = *(xAnchorIt);
+
+ if (columnX < xLeft || columnX > xRight)
+ {
+ if (rawProfile.counters.encoderPosition >= 0)
+ {
+ qWarning()
+ << "x anchor not found" << xLeft << columnX << xRight;
+ continue;
+ }
+ }
+
+ const auto& pixelValue = pixels.at(columnIdx);
+ const uint16_t discretePixelValue{
+ uint16_t(pixelValue * discretesInRage / img_height)
+ };
+
+ Q_ASSERT_X(
+ discretePixelValue > 0 &&
+ discretePixelValue < calibrationColumnHeight,
+ Q_FUNC_INFO,
+ ("got ivalid discrete value " +
+ QString::number(discretePixelValue) + ". pixelValues is " +
+ QString::number(pixelValue) + ". calc result is " +
+ QString::number(pixelValue * discretesInRage / img_height))
+ .toStdString()
+ .c_str()
+ );
+
+ const auto xLineLen = xRight - xLeft;
+ const auto xLeftMm = *(xAnchorMmIt - 1);
+ const auto xRelative = float(columnX - xLeft) / xLineLen;
+ const auto xMmValue = xLeftMm + xRelative * (triangleBaseMm / 2.);
+
+ auto& calibrationColumn = (*result)[columnIdx];
+ calibrationColumn[discretePixelValue] = xMmValue;
+ }
+ }
+
+ return result;
+}
+
bool initLaser()
{
- const QLatin1String pwmChip { "pwmchip2" };
- const uint16_t pwmChannel { 1 };
- const QLatin1String pwmSystemRoot { "/sys/class/pwm" };
- const QString pwmChipRoot { pwmSystemRoot + "/" + pwmChip };
+ const QLatin1String pwmChip{"pwmchip2"};
+ const uint16_t pwmChannel{1};
+ const QLatin1String pwmSystemRoot{"/sys/class/pwm"};
+ const QString pwmChipRoot{pwmSystemRoot + "/" + pwmChip};
- const QString pwmExportFile { pwmChipRoot + "/export" };
+ const QString pwmExportFile{pwmChipRoot + "/export"};
- QFile f { pwmExportFile };
+ QFile f{pwmExportFile};
if (!f.open(QFile::WriteOnly))
{
@@ -1240,13 +1491,13 @@ bool initLaser()
return false;
}
- QTextStream s { &f };
+ QTextStream s{&f};
s << pwmChannel;
- const QString pwm { QLatin1String("pwm%1").arg(QString::number(pwmChannel)) };
- const QString pwmRoot { pwmChipRoot + "/" + pwm };
+ const QString pwm{QLatin1String("pwm%1").arg(QString::number(pwmChannel))};
+ const QString pwmRoot{pwmChipRoot + "/" + pwm};
- const QString periodFilename { pwmRoot + "/period" };
+ const QString periodFilename{pwmRoot + "/period"};
f.close();
f.setFileName(periodFilename);
@@ -1258,11 +1509,11 @@ bool initLaser()
return false;
}
- const unsigned periodHz { 50'000 };
+ const unsigned periodHz{50'000};
s << periodHz;
- const QString dutyCycleFilename { pwmRoot + "/duty_cycle" };
+ const QString dutyCycleFilename{pwmRoot + "/duty_cycle"};
f.close();
f.setFileName(dutyCycleFilename);
@@ -1274,11 +1525,11 @@ bool initLaser()
return false;
}
- const unsigned dutyCycle { 3'000 };
+ const unsigned dutyCycle{3'000};
s << dutyCycle;
- const QString enableFilename { pwmRoot + "/enable" };
+ const QString enableFilename{pwmRoot + "/enable"};
f.close();
f.setFileName(enableFilename);
@@ -1290,9 +1541,123 @@ bool initLaser()
return false;
}
- const int enable { 1 };
+ const int enable{1};
s << enable;
return true;
}
+
+static QImage calibrationTableToImage(
+ const QSharedPointer<CalibrationTable>& calibrationTable
+)
+{
+ QImage result(
+ QSize(calibrationTable->size(), calibrationTable->at(0).size()),
+ QImage::Format::Format_Indexed8
+ );
+
+ // QImage image(QSize(imageWidth, imageHeight), QImage::Format_Indexed8);
+
+ QColor color(Qt::green);
+ auto r = color.redF();
+ auto g = color.greenF();
+ auto b = color.blueF();
+
+ for (int c = 0; c < 256; c++)
+ {
+ QRgb col = qRgb(int(c * r), int(c * g), int(c * b));
+ result.setColor(c, col);
+ }
+
+ int notNull = 0;
+
+ for (size_t columnIdx = 0; columnIdx < calibrationTable->size();
+ ++columnIdx)
+ {
+ const auto& column = calibrationTable->at(columnIdx);
+
+ for (size_t rowIdx = 0; rowIdx < column.size(); ++rowIdx)
+ {
+ // if (!qFuzzyIsNull(column.at(rowIdx)))
+ // {
+ // qDebug() << "here";
+ // }
+
+ bool hasValue = !qFuzzyIsNull(column.at(rowIdx));
+
+ if (hasValue)
+ {
+ // qDebug() << "x/y" << columnIdx << rowIdx;
+ ++notNull;
+ }
+
+ result.setPixel(columnIdx, rowIdx, hasValue ? 255 : 0);
+ }
+ }
+ qDebug() << "not null count" << notNull;
+
+ return result;
+}
+
+static void interpolate(QSharedPointer<CalibrationTable>& table)
+{
+ std::for_each(
+ std::execution::par,
+ table->begin(),
+ table->end(),
+ [](auto& column) { interpolate(column); }
+ );
+}
+
+static void interpolate(CalibrationColumn& column)
+{
+ auto firstNonZero =
+ std::find_if(column.begin(), column.end(), [](const auto& pixel) {
+ return !qFuzzyIsNull(pixel);
+ });
+
+ if (firstNonZero == column.end())
+ {
+ return;
+ }
+
+ for (auto it = firstNonZero; it != column.cend(); ++it)
+ {
+ auto firstZero =
+ std::find_if(it + 1, column.end(), [](const auto& pixel) {
+ return qFuzzyIsNull(pixel);
+ });
+
+ if (firstZero == column.end())
+ {
+ return;
+ }
+
+ auto nextNonZero =
+ std::find_if(firstZero + 1, column.end(), [](const auto& pixel) {
+ return !qFuzzyIsNull(pixel);
+ });
+
+ if (nextNonZero == column.end())
+ {
+ return;
+ }
+
+ auto prevNonZero = firstZero - 1;
+
+ auto diff = *nextNonZero - *prevNonZero;
+ auto size = nextNonZero - prevNonZero;
+ auto stepDiff = float(diff) / size;
+
+ // qDebug) << *prevNonZero << *nextNonZero << size << stepDiff;
+
+ for (auto zero = firstZero; zero < nextNonZero; ++zero)
+ {
+ *zero = (zero - firstZero + 1) * stepDiff;
+ // qDebug() << "set zero to" << *zero;
+ }
+
+ it = nextNonZero - 1;
+ }
+}
diff --git a/printerclient.cpp b/printerclient.cpp
index c5bf189..a78de50 100644
--- a/printerclient.cpp
+++ b/printerclient.cpp
@@ -5,10 +5,22 @@
#include <QDebug>
#include <QFile>
#include <QSerialPort>
+#include <QSerialPortInfo>
-PrinterClient::PrinterClient(QObject *parent)
- : QObject { parent }
- , m_serialPort { new QSerialPort { "/dev/ttyUSB0", this } }
+QString getFirstTtyUSB()
+{
+ auto ports = QSerialPortInfo::availablePorts();
+
+ std::remove_if(ports.begin(), ports.end(), [](const auto& port) {
+ return !port.portName().contains("ttyUSB");
+ });
+
+ return ports.isEmpty() ? "" : ports.first().portName();
+}
+
+PrinterClient::PrinterClient(QObject* parent)
+ : QObject{parent} // , m_serialPort{new QSerialPort{"/dev/ttyUSB0", this}}
+ , m_serialPort{new QSerialPort{getFirstTtyUSB(), this}}
{
if (!m_serialPort->setBaudRate(QSerialPort::Baud115200)) {
throw std::runtime_error(