82 lines
3.5 KiB
C++
82 lines
3.5 KiB
C++
#pragma once
|
|
|
|
#include "fgc/Config.h"
|
|
#include "fgc/ICameraSource.h"
|
|
#include "fgc/IrbgrabApi.h"
|
|
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
namespace fgc {
|
|
|
|
// The thermal camera: an InfraTec TarisIR mini through the IRBGRAB SDK
|
|
// (IrbgrabApi.h), one camera per source.
|
|
//
|
|
// The camera is kept grabbing from open() to close(), whatever the scan does:
|
|
// a microbolometer that is stopped and restarted starts with zero frames and a
|
|
// fresh NUC. A worker thread owns every SDK call - connecting, polling the
|
|
// newest frame of counts, switching the calibration profile, reconnecting
|
|
// when the camera goes quiet - so nothing here ever blocks the control loop.
|
|
// trigger() hands over the newest frame if it is fresh enough, and otherwise
|
|
// says no at once: the thermal picture of a waypoint is best effort, the
|
|
// colour camera's is not.
|
|
//
|
|
// A camera that is missing, unlicensed or unreachable is not a startup error.
|
|
// The source reports why in offline(), keeps retrying, and the scan goes on
|
|
// without it.
|
|
class TarisCameraSource : public ICameraSource {
|
|
public:
|
|
struct Options {
|
|
std::string serial; // the camera's serial number
|
|
int calib_profile = 0;
|
|
double frame_rate_hz = 5.0;
|
|
int max_frame_age_ms = 400;
|
|
std::string library = "libirbgrab_x86_64-linux.so";
|
|
std::string interface; // for diagnostics only; may be empty
|
|
int stall_ms = 5000; // connected but no frame this long: reconnect
|
|
int retry_min_ms = 2000; // between connection attempts, doubling...
|
|
int retry_max_ms = 30000;// ...up to this
|
|
int calib_timeout_ms = 15000;// a profile switch takes about 3 s
|
|
};
|
|
static Options fromSpec(const CameraSpec& spec);
|
|
|
|
// api: the SDK, or null to load opts.library when the worker starts.
|
|
// has_net_raw: may this process open a raw socket (the SDK needs one)?
|
|
// Null: read the effective capabilities from /proc/self/status.
|
|
explicit TarisCameraSource(Options opts, std::shared_ptr<const irbgrab::Api> api = nullptr,
|
|
std::function<bool()> has_net_raw = nullptr);
|
|
~TarisCameraSource() override;
|
|
|
|
void open() override;
|
|
void close() override;
|
|
// Only open and close delivery; the camera keeps grabbing either way.
|
|
void start() override;
|
|
void stop() override;
|
|
bool trigger() override;
|
|
void setFrameCallback(FrameCallback cb) override;
|
|
int cameraCount() const override { return 1; }
|
|
std::vector<CameraDeviceInfo> deviceInfo() override;
|
|
std::string offline(int camera_index) override;
|
|
bool grabFrame(int camera_index, Frame& out, int timeout_ms) override;
|
|
// "CalibProfile" (index), "KelvinPerCount", "HousingTemperature" (degC).
|
|
bool readFeature(int camera_index, const std::string& name, double& value) override;
|
|
// "CalibProfile": switch, and wait until the camera has (seconds).
|
|
bool setFeature(int camera_index, const std::string& name, const std::string& value) override;
|
|
// Disconnect and connect again; waits until it is back or gives up.
|
|
bool resetCamera(int camera_index) override;
|
|
|
|
// The counts' scale the profiles are documented to have (TarisIR mini):
|
|
// 0.01 K for profile 0, 0.02 K for profile 1; 0 for any other.
|
|
static double expectedKelvinPerCount(int calib_profile);
|
|
|
|
// Does /proc/self/status grant CAP_NET_RAW?
|
|
static bool processHasNetRaw();
|
|
|
|
private:
|
|
struct Impl;
|
|
std::unique_ptr<Impl> impl_;
|
|
};
|
|
|
|
} // namespace fgc
|