lcameraDev: Add session mgr lib for libcamera device binding

This commit is contained in:
2026-06-13 12:02:04 -04:00
parent cc7f4fcd9b
commit 46f767f232
21 changed files with 1363 additions and 64 deletions
@@ -0,0 +1,71 @@
#include <boostAsioLinkageFix.h>
#include <lcameraDev.h>
#include <probeRunner.h>
#include <iostream>
#include <spinscale/co/nonViralTaskNursery.h>
namespace {
sscl::co::NonViralNonPostingInvoker listCamerasCInd(
std::exception_ptr& exceptionStorage,
std::function<void()> callerLambda)
{
(void)exceptionStorage;
(void)callerLambda;
const std::vector<lcamera_dev::LcameraDevCameraInfo> cameras =
co_await lcameraDev_enumerateCamerasCReq();
std::cout << "lcameraDev: found " << cameras.size() << " camera(s)\n";
for (size_t i = 0; i < cameras.size(); ++i)
{
const lcamera_dev::LcameraDevCameraInfo& info = cameras[i];
std::cout << " [" << i << "] id=" << info.id;
if (!info.model.empty()) {
std::cout << " model=" << info.model;
}
if (!info.location.empty()) {
std::cout << " location=" << info.location;
}
std::cout << '\n';
}
co_return;
}
void runListCameras(
const std::shared_ptr<sscl::ComponentThread>& componentThread)
{
lcameraDev_main(componentThread);
sscl::co::NonViralTaskNursery nursery;
nursery.openAdmission();
nursery.launch(
[](sscl::co::NonViralTaskNursery::Slot::Lease& lease)
{
return listCamerasCInd(
lease.getExceptionStorage(),
lease.getCallerLambda());
});
nursery.closeAdmission();
nursery.syncAwaitAllSettlements(componentThread->getIoContext());
lcameraDev_exit();
}
} // namespace
int main()
{
try {
lcamera_dev_probe::runOnComponentThread(runListCameras);
return 0;
}
catch (const std::exception& exc) {
std::cerr << "lcameraDev_list_cameras: " << exc.what() << '\n';
return 1;
}
}
@@ -0,0 +1,78 @@
#include <boostAsioLinkageFix.h>
#include <lcameraDev.h>
#include <probeRunner.h>
#include <iostream>
#include <spinscale/co/nonViralTaskNursery.h>
#include <string>
namespace {
sscl::co::NonViralNonPostingInvoker probeSelectorCInd(
std::exception_ptr& exceptionStorage,
std::function<void()> callerLambda,
const std::string& deviceSelector)
{
(void)exceptionStorage;
(void)callerLambda;
const lcamera_dev::LcameraDevGetOrCreateResult createResult =
co_await lcameraDev_getOrCreateDeviceCReq(deviceSelector);
std::cout << "lcameraDev_probe: opened session for camera id="
<< createResult.resolvedIdentity.id << '\n';
co_await lcameraDev_releaseDeviceCReq(createResult.deviceSession);
std::cout << "lcameraDev_probe: released session\n";
co_return;
}
void runProbe(
const std::shared_ptr<sscl::ComponentThread>& componentThread,
const std::string& deviceSelector)
{
lcameraDev_main(componentThread);
sscl::co::NonViralTaskNursery nursery;
nursery.openAdmission();
nursery.launch(
[deviceSelector](sscl::co::NonViralTaskNursery::Slot::Lease& lease)
{
return probeSelectorCInd(
lease.getExceptionStorage(),
lease.getCallerLambda(),
deviceSelector);
});
nursery.closeAdmission();
nursery.syncAwaitAllSettlements(componentThread->getIoContext());
lcameraDev_exit();
}
} // namespace
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cerr << "Usage: lcameraDev_probe <deviceSelector>\n";
return 1;
}
try {
const std::string deviceSelector = argv[1];
lcamera_dev_probe::runOnComponentThread(
[&](const std::shared_ptr<sscl::ComponentThread>& componentThread)
{
runProbe(componentThread, deviceSelector);
});
return 0;
}
catch (const std::exception& exc) {
std::cerr << "lcameraDev_probe: " << exc.what() << '\n';
return 1;
}
}
@@ -0,0 +1,88 @@
#include <boostAsioLinkageFix.h>
#include <probeRunner.h>
#include <spinscale/component.h>
#include <future>
#include <iostream>
namespace lcamera_dev_probe {
namespace {
constexpr sscl::ThreadId PROBE_PUPPETEER_THREAD_ID = 1;
class DummyPuppeteerComponent
: public sscl::pptr::PuppeteerComponent
{
public:
explicit DummyPuppeteerComponent(
const std::shared_ptr<sscl::PuppeteerThread>& componentThread)
: sscl::pptr::PuppeteerComponent(componentThread)
{}
void handleLoopExceptionHook() override
{
std::cerr << "lcameraDev probe: puppeteer loop exception\n";
}
};
void probePuppeteerMain(
const sscl::PuppeteerThread::EntryFnArguments& args,
const std::function<void(
const std::shared_ptr<sscl::ComponentThread>&)>& work,
std::promise<std::exception_ptr>& donePromise)
{
sscl::PuppeteerThread& thr = args.usableBeforeJolt;
thr.initializeTls();
sscl::ComponentThread::setPuppeteerThreadId(PROBE_PUPPETEER_THREAD_ID);
std::shared_ptr<sscl::PuppeteerThread> thrPtr =
std::static_pointer_cast<sscl::PuppeteerThread>(thr.shared_from_this());
sscl::ComponentThread::setPuppeteerThread(thrPtr);
try {
work(thrPtr);
donePromise.set_value(nullptr);
}
catch (...) {
donePromise.set_value(std::current_exception());
}
thr.getIoContext().stop();
}
} // namespace
void runOnComponentThread(
const std::function<void(
const std::shared_ptr<sscl::ComponentThread>&)>& work)
{
std::promise<std::exception_ptr> donePromise;
std::future<std::exception_ptr> doneFuture = donePromise.get_future();
DummyPuppeteerComponent dummyComponent{
std::shared_ptr<sscl::PuppeteerThread>()};
std::shared_ptr<sscl::PuppeteerThread> probeThread =
std::make_shared<sscl::PuppeteerThread>(
PROBE_PUPPETEER_THREAD_ID,
"lcameraDev-probe",
[&work, &donePromise](
const sscl::PuppeteerThread::EntryFnArguments& args)
{
probePuppeteerMain(args, work, donePromise);
},
dummyComponent,
nullptr);
dummyComponent.thread = probeThread;
probeThread->thread.join();
std::exception_ptr probeException = doneFuture.get();
if (probeException) {
std::rethrow_exception(probeException);
}
}
} // namespace lcamera_dev_probe
+16
View File
@@ -0,0 +1,16 @@
#ifndef LCAMERA_DEV_PROBE_RUNNER_H
#define LCAMERA_DEV_PROBE_RUNNER_H
#include <functional>
#include <memory>
#include <spinscale/componentThread.h>
namespace lcamera_dev_probe {
void runOnComponentThread(
const std::function<void(
const std::shared_ptr<sscl::ComponentThread>&)>& work);
} // namespace lcamera_dev_probe
#endif // LCAMERA_DEV_PROBE_RUNNER_H