lcameraDev: Add session mgr lib for libcamera device binding
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
#include <selectorResolve.h>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace lcamera_dev {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string toLowerAscii(const std::string& text)
|
||||
{
|
||||
std::string lowered = text;
|
||||
for (char& ch : lowered) {
|
||||
ch = static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
|
||||
}
|
||||
return lowered;
|
||||
}
|
||||
|
||||
bool recordMatchesCriterion(
|
||||
const CameraIdentityRecord& record, const SelectorCriterion& criterion)
|
||||
{
|
||||
switch (criterion.kind)
|
||||
{
|
||||
case SelectorCriterionKind::LibcameraId:
|
||||
return record.id == criterion.value;
|
||||
|
||||
case SelectorCriterionKind::Index:
|
||||
return false;
|
||||
|
||||
case SelectorCriterionKind::Model:
|
||||
return record.model == criterion.value;
|
||||
|
||||
case SelectorCriterionKind::ModelSubstr:
|
||||
return record.model.find(criterion.value) != std::string::npos;
|
||||
|
||||
case SelectorCriterionKind::Location:
|
||||
return toLowerAscii(record.locationLabel)
|
||||
== toLowerAscii(criterion.value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int parseIndexCriterion(const SelectorCriterion& criterion)
|
||||
{
|
||||
try {
|
||||
return std::stoi(criterion.value);
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
throw std::runtime_error("Invalid index: value in deviceSelector");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string formatCameraListForDiagnostics(
|
||||
const std::vector<CameraIdentityRecord>& records)
|
||||
{
|
||||
std::ostringstream result;
|
||||
result << "Known cameras:\n";
|
||||
|
||||
for (size_t i = 0; i < records.size(); ++i)
|
||||
{
|
||||
const CameraIdentityRecord& record = records[i];
|
||||
result << " [" << i << "] id=" << record.id;
|
||||
if (!record.model.empty()) {
|
||||
result << " model=" << record.model;
|
||||
}
|
||||
if (!record.locationLabel.empty()) {
|
||||
result << " location=" << record.locationLabel;
|
||||
}
|
||||
result << '\n';
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
CameraIdentityRecord resolveSelectorAgainstRecords(
|
||||
const std::vector<SelectorCriterion>& criteria,
|
||||
const std::vector<CameraIdentityRecord>& records)
|
||||
{
|
||||
std::optional<int> indexCriterion;
|
||||
for (const SelectorCriterion& criterion : criteria)
|
||||
{
|
||||
if (criterion.kind != SelectorCriterionKind::Index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int index = parseIndexCriterion(criterion);
|
||||
if (index < 0
|
||||
|| static_cast<size_t>(index) >= records.size())
|
||||
{
|
||||
throw std::runtime_error("index: selector out of range");
|
||||
}
|
||||
|
||||
indexCriterion = index;
|
||||
}
|
||||
|
||||
std::vector<const CameraIdentityRecord*> matches;
|
||||
matches.reserve(records.size());
|
||||
|
||||
for (const CameraIdentityRecord& record : records)
|
||||
{
|
||||
bool matchesAll = true;
|
||||
for (const SelectorCriterion& criterion : criteria)
|
||||
{
|
||||
if (criterion.kind == SelectorCriterionKind::Index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!recordMatchesCriterion(record, criterion))
|
||||
{
|
||||
matchesAll = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matchesAll) {
|
||||
continue;
|
||||
}
|
||||
|
||||
matches.push_back(&record);
|
||||
}
|
||||
|
||||
if (indexCriterion.has_value())
|
||||
{
|
||||
const CameraIdentityRecord& indexedRecord =
|
||||
records.at(static_cast<size_t>(*indexCriterion));
|
||||
|
||||
auto it = std::find_if(
|
||||
matches.begin(), matches.end(),
|
||||
[&indexedRecord](const CameraIdentityRecord* candidate) {
|
||||
return candidate->id == indexedRecord.id;
|
||||
});
|
||||
|
||||
if (it == matches.end())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"index: criterion conflicts with other selector clauses");
|
||||
}
|
||||
|
||||
if (matches.size() > 1)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Ambiguous deviceSelector: multiple cameras match\n"
|
||||
+ formatCameraListForDiagnostics(records));
|
||||
}
|
||||
|
||||
return indexedRecord;
|
||||
}
|
||||
|
||||
if (matches.empty())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"No camera matches deviceSelector\n"
|
||||
+ formatCameraListForDiagnostics(records));
|
||||
}
|
||||
|
||||
if (matches.size() > 1)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Ambiguous deviceSelector: multiple cameras match\n"
|
||||
+ formatCameraListForDiagnostics(records));
|
||||
}
|
||||
|
||||
return *matches.front();
|
||||
}
|
||||
|
||||
} // namespace lcamera_dev
|
||||
Reference in New Issue
Block a user