fwt_software/src/core/CameraMode.cpp

96 lines
3.1 KiB
C++

#include "fgc/CameraMode.h"
#include <algorithm>
#include <filesystem>
#include <stdexcept>
#include <string>
extern "C" {
#include "ini.h"
}
namespace fs = std::filesystem;
namespace fgc {
namespace {
// inih callback. Unlike Config.cpp's handler this APPENDS rather than writing a
// map: mode files depend on file order and on repeated keys (see CameraMode).
int modeHandler(void* user, const char* section, const char* name, const char* value) {
auto* m = static_cast<CameraMode*>(user);
const std::string sec = section ? section : "";
const std::string key = name ? name : "";
const std::string val = value ? value : "";
if (sec == "Camera") {
m->features.emplace_back(key, val);
return 1;
}
if (sec != "Mode") return 0; // unknown section -> parse error
if (key == "description") {
m->description = val;
} else if (key == "settle_wait_ms" || key == "frame_timeout_ms") {
int parsed = 0;
try {
size_t consumed = 0;
parsed = std::stoi(val, &consumed);
if (consumed != val.size() || parsed < 0) return 0;
} catch (const std::exception&) {
return 0;
}
(key == "settle_wait_ms" ? m->settle_wait_ms : m->frame_timeout_ms) = parsed;
} else {
return 0; // unknown [Mode] key -> parse error, not a silent typo
}
return 1;
}
} // namespace
CameraMode loadCameraMode(const std::string& path) {
CameraMode mode;
mode.name = fs::path(path).stem().string();
const int rc = ini_parse(path.c_str(), modeHandler, &mode);
if (rc == -1)
throw std::runtime_error("Cannot open camera mode file: " + path);
if (rc == -2)
throw std::runtime_error("Out of memory reading camera mode file: " + path);
if (rc > 0)
throw std::runtime_error("Camera mode file '" + path + "' line " + std::to_string(rc) +
": unknown section, unknown [Mode] key, or invalid value "
"(expected [Mode] description/settle_wait_ms/frame_timeout_ms, "
"or a [Camera] feature)");
if (mode.features.empty())
throw std::runtime_error("Camera mode file '" + path + "' sets no [Camera] features");
return mode;
}
std::map<std::string, CameraMode> loadCameraModes(const std::string& dir) {
std::error_code ec;
if (!fs::is_directory(dir, ec))
throw std::runtime_error("Camera mode directory not found: " + dir);
// Sorted so startup logs and the UI list modes in a stable order.
std::vector<fs::path> files;
for (const auto& entry : fs::directory_iterator(dir, ec))
if (entry.is_regular_file() && entry.path().extension() == ".ini")
files.push_back(entry.path());
std::sort(files.begin(), files.end());
std::map<std::string, CameraMode> modes;
for (const auto& f : files) {
CameraMode m = loadCameraMode(f.string());
modes.emplace(m.name, std::move(m));
}
if (modes.empty())
throw std::runtime_error("No camera modes (*.ini) in " + dir);
return modes;
}
} // namespace fgc