#pragma once // xlidar-driver — LidarManager: the host-facing facade of the SDK. // // The manager scans a plugin directory for driver .so files, registers their // DriverInfo, and creates driver instances by driver_id: // // xlidar::LidarManager manager("/opt/xlidar/plugins"); // manager.load_all_plugins(); // for (const auto& [id, plugin] : manager.available_drivers()) // printf("%s — %s\n", id.c_str(), plugin.info.description.c_str()); // // xlidar::DeviceConfig cfg; // cfg.driver_id = "rplidar_c1_driver"; // cfg.serial_port = "/dev/ttyUSB0"; // auto lidar = manager.create_lidar_device(cfg); // // Plugins stay loaded until the manager is destroyed; the manager must // outlive every device instance it created (instances execute code that // lives inside the plugin .so). #include "lidar_interface.hpp" #include #include #include #include #include namespace xlidar { // One discovered plugin: its registered identity plus where it came from. struct PluginRegistry { DriverInfo info; std::string file_path; // absolute path of the plugin .so }; // Configuration document (config.json): a named list of lidar devices. struct ManagerConfig { std::vector lidars; }; // Returns defaults if the file doesn't exist (without creating it). // Legacy lidarlib entries ({"brand": "OLEI"|"SICK"|"ESPE", ...}) are // migrated on the fly: brand+model resolve to the matching driver_id and the // old angle window keys map to the remap fields. ManagerConfig load_config(const std::string& path); void save_config(const std::string& path, const ManagerConfig& cfg); class LidarManager { public: // plugins_dir: directory holding the driver .so files. Nothing is // touched until load_all_plugins() runs. explicit LidarManager(std::string plugins_dir); ~LidarManager(); LidarManager(const LidarManager&) = delete; LidarManager& operator=(const LidarManager&) = delete; // Scan plugins_dir for *.so, dlopen each, resolve get_driver_info / // create_driver_instance, and register the driver. Files that are not // valid plugins (missing symbols, dlopen failure) are skipped with a // message on stderr. Safe to call again to pick up newly added files // (already-loaded driver_ids are kept, not reloaded). Returns the number // of drivers registered in total. size_t load_all_plugins(); // Registered drivers keyed by driver_id. Stable while the manager lives; // load_all_plugins() may add entries. const std::map& available_drivers() const { return available_; } bool has_driver(const std::string& driver_id) const { return available_.count(driver_id) != 0; } // Create a device instance from the plugin registered for driver_id. // nullptr if driver_id is unknown. The instance is independent and // thread-safe to pump from its own thread; it must be destroyed before // the manager. std::unique_ptr create_lidar_device(const std::string& driver_id, const DeviceConfig& cfg); // Convenience: driver_id taken from cfg.driver_id. std::unique_ptr create_lidar_device(const DeviceConfig& cfg) { return create_lidar_device(cfg.driver_id, cfg); } // Convenience: one instance per entry of a config.json document (see // load_config). Entries whose driver_id is not available are skipped // with a message on stderr. std::vector> create_from_config_file(const std::string& path); const std::string& plugins_dir() const { return plugins_dir_; } private: struct LoadedPlugin { void* handle = nullptr; // dlopen handle xlidar_create_driver_instance_fn create = nullptr; }; std::string plugins_dir_; std::map available_; std::map loaded_; mutable std::mutex mutex_; }; } // namespace xlidar