#pragma once #include "lidarlib/lidar.hpp" #include #include #include namespace lidarlib { // ─── Settings for one lidar ───────────────────────────────────────────────── // `name` is the unique key used to match entries across saves (rename = old // key removed, new key added) — useful if your GUI reconciles a running set of // lidars against an edited config list. struct LidarConfig { std::string name = "lidar"; std::string ip = "0.0.0.0"; uint16_t port = 2368; std::string model = "AUTO"; // must match an entry in model_names_for_brand(brand) bool inverted = false; // only applies to brand "OLEI" — SickDriver has no equivalent std::string brand = "OLEI"; // must match an entry in brand_names() — "OLEI" or "SICK" friend bool operator==(const LidarConfig& a, const LidarConfig& b) { return a.name == b.name && a.ip == b.ip && a.port == b.port && a.model == b.model && a.inverted == b.inverted && a.brand == b.brand; } friend bool operator!=(const LidarConfig& a, const LidarConfig& b) { return !(a == b); } }; // Any number of lidars — managed as a list so a consuming app/GUI can // add/remove entries freely instead of being locked to a fixed front/rear pair. struct Config { std::vector lidars = { {"front", "0.0.0.0", 2368, "AUTO", false}, {"rear", "0.0.0.0", 2369, "AUTO", true}, }; }; // Known model name -> ModelConfig (matches the constants in lidar.hpp/sick_lidar.hpp). // Returns nullptr if name doesn't match any entry. const ModelConfig* model_by_name(const std::string& name); // Names accepted by model_by_name(), for populating a UI dropdown. const std::vector& model_names(); // Brand names accepted in LidarConfig::brand ("OLEI", "SICK"), for populating // a UI dropdown. const std::vector& brand_names(); // Subset of model_names() valid for a given brand (e.g. "SICK" -> the // MODEL_SICK_* names) — empty if `brand` doesn't match any entry in // brand_names(). Used to filter the model dropdown once a brand is picked, // and to validate that LidarConfig::model actually belongs to its brand. const std::vector& model_names_for_brand(const std::string& brand); // Load config.json at `path`. If the file doesn't exist, returns defaults // (and does NOT create the file — caller decides whether to save it). Config load_config(const std::string& path); // Overwrite `path` with `cfg` serialized as JSON. void save_config(const std::string& path, const Config& cfg); // ─── THE single config function ───────────────────────────────────────────── // Build a ready-to-open lidar from one LidarConfig. This is the one entry point // a GUI/app needs: `brand` selects the transport — exactly "SICK" → TCP, any // other value (incl. "OLEI", empty, or an old config without the field) → OLEI // UDP. `model` is resolved *for that brand*: a name that is unknown OR belongs // to the other brand falls back to the brand's sensible default (MODEL_AUTO for // OLEI, MODEL_SICK_TIM571 for SICK), so a mis-paired brand+model can't silently // configure the wrong driver. `inverted` applies to OLEI only. Returns a unique // handle to the unified Lidar interface — call ->open() then // ->recv_scan(out, timeout_ms) to get ScanResult { LaserScan scan; ExtraInfo // info; }. Never returns nullptr. // // lidarlib::LidarConfig c{"front", "192.168.1.10", 2368, "AUTO", false, "OLEI"}; // auto lidar = lidarlib::make_lidar(c); // lidar->open(); // lidarlib::ScanResult r; // lidar->recv_scan(r, 1000); // r.scan = LaserScan, r.info = ExtraInfo std::unique_ptr make_lidar(const LidarConfig& cfg); } // namespace lidarlib