[libcamera-devel,RFC,2/3] libcamera: device_enumerator: Check that expected cameras are available

Message ID 20190930053520.2711-2-paul.elder@ideasonboard.com
State Superseded
Delegated to: Paul Elder
Headers show
Series
  • [libcamera-devel,RFC,1/3] libcamera: pipeline: Add device IDs
Related show

Commit Message

Paul Elder Sept. 30, 2019, 5:35 a.m. UTC
Add a static method to DeviceEnumerator to check if the expected number
of cameras have been enumerated. The expected cameras are the supported
cameras declared by the pipeline handlers that the system has.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
---
 src/libcamera/device_enumerator.cpp       | 69 +++++++++++++++++++++++
 src/libcamera/include/device_enumerator.h |  4 ++
 2 files changed, 73 insertions(+)

Comments

Niklas Söderlund Oct. 3, 2019, 8:05 p.m. UTC | #1
Hi Paul,

Thanks for your work.

On 2019-09-30 01:35:19 -0400, Paul Elder wrote:
> Add a static method to DeviceEnumerator to check if the expected number
> of cameras have been enumerated. The expected cameras are the supported
> cameras declared by the pipeline handlers that the system has.
> 
> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> ---
>  src/libcamera/device_enumerator.cpp       | 69 +++++++++++++++++++++++
>  src/libcamera/include/device_enumerator.h |  4 ++
>  2 files changed, 73 insertions(+)
> 
> diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp
> index 0b596bce..7d28f9b8 100644
> --- a/src/libcamera/device_enumerator.cpp
> +++ b/src/libcamera/device_enumerator.cpp
> @@ -9,10 +9,15 @@
>  #include "device_enumerator_sysfs.h"
>  #include "device_enumerator_udev.h"
>  
> +#include <algorithm>
> +#include <dirent.h>
> +#include <fstream>
>  #include <string.h>
> +#include <sys/types.h>
>  
>  #include "log.h"
>  #include "media_device.h"
> +#include "pipeline_handler.h"
>  #include "utils.h"
>  
>  /**
> @@ -306,4 +311,68 @@ std::shared_ptr<MediaDevice> DeviceEnumerator::search(const DeviceMatch &dm)
>  	return nullptr;
>  }
>  
> +int extractNumberFromFile(std::string &path)
> +{
> +	std::ifstream file;
> +	std::string line;
> +
> +	file.open(path);
> +	if (!file)
> +		return -1;
> +
> +	file >> line;
> +	int i = std::stoi(line, 0, 16);
> +	file.close();
> +
> +	return i;
> +}
> +
> +bool DeviceEnumerator::haveExpectedCameras(CameraManager *cm)
> +{
> +	std::vector<std::reference_wrapper<DeviceID>> &supportedDevices =
> +		PipelineHandlerFactory::getDeviceIDs();
> +	std::vector<DeviceID> availableDevices;
> +	std::vector<DeviceID> intersection;
> +	struct dirent *ent;
> +	DIR *dir;
> +	const char *pciDir = "/sys/bus/pci/devices";
> +
> +	dir = opendir(pciDir);
> +	if (!dir) {
> +		LOG(DeviceEnumerator, Error)
> +			<< "Failed to open sysfs PCI directory";
> +		/* We can't expect any cameras, so we vacuously have them all. */
> +		return true;
> +	}
> +
> +	while ((ent = readdir(dir)) != nullptr) {
> +		std::string path = pciDir + std::string("/") + ent->d_name + "/vendor";
> +		int vendor = extractNumberFromFile(path);
> +		if (vendor < 0)
> +			continue;
> +
> +		path = pciDir + std::string("/") + ent->d_name + "/device";
> +		int device = extractNumberFromFile(path);
> +		if (device < 0)
> +			continue;
> +
> +		availableDevices.push_back(PCIDeviceID(vendor, device));
> +	}
> +
> +	closedir(dir);
> +
> +	std::set_intersection(supportedDevices.begin(), supportedDevices.end(),
> +			      availableDevices.begin(), availableDevices.end(),
> +			      back_inserter(intersection),
> +			      compareDevices<PCIDeviceID>);
> +
> +	if (cm->cameras().size() < intersection.size()) {
> +		LOG(DeviceEnumerator, Warning) << "Not enough cameras!";
> +		return false;
> +	}

To me this seems a bit too strict. Say that I have a Soraka device, run 
a kernel on it without IPU3 support, With this change libcamera would 
not function for a USB camera.

Also comparing against cm->cameras().size() might be skewed if you run 
on a kernel with vivid and/or vimc support built in.

> +
> +	LOG(DeviceEnumerator, Debug) << "All cameras correctly initialized";
> +	return true;
> +}
> +
>  } /* namespace libcamera */
> diff --git a/src/libcamera/include/device_enumerator.h b/src/libcamera/include/device_enumerator.h
> index 770f4277..11c4cdfb 100644
> --- a/src/libcamera/include/device_enumerator.h
> +++ b/src/libcamera/include/device_enumerator.h
> @@ -13,6 +13,8 @@
>  
>  #include <linux/media.h>
>  
> +#include <libcamera/camera_manager.h>
> +
>  namespace libcamera {
>  
>  class MediaDevice;
> @@ -43,6 +45,8 @@ public:
>  
>  	std::shared_ptr<MediaDevice> search(const DeviceMatch &dm);
>  
> +	static bool haveExpectedCameras(CameraManager *cm);
> +
>  protected:
>  	std::shared_ptr<MediaDevice> createDevice(const std::string &deviceNode);
>  	void addDevice(const std::shared_ptr<MediaDevice> &media);
> -- 
> 2.23.0
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

Patch

diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp
index 0b596bce..7d28f9b8 100644
--- a/src/libcamera/device_enumerator.cpp
+++ b/src/libcamera/device_enumerator.cpp
@@ -9,10 +9,15 @@ 
 #include "device_enumerator_sysfs.h"
 #include "device_enumerator_udev.h"
 
+#include <algorithm>
+#include <dirent.h>
+#include <fstream>
 #include <string.h>
+#include <sys/types.h>
 
 #include "log.h"
 #include "media_device.h"
+#include "pipeline_handler.h"
 #include "utils.h"
 
 /**
@@ -306,4 +311,68 @@  std::shared_ptr<MediaDevice> DeviceEnumerator::search(const DeviceMatch &dm)
 	return nullptr;
 }
 
+int extractNumberFromFile(std::string &path)
+{
+	std::ifstream file;
+	std::string line;
+
+	file.open(path);
+	if (!file)
+		return -1;
+
+	file >> line;
+	int i = std::stoi(line, 0, 16);
+	file.close();
+
+	return i;
+}
+
+bool DeviceEnumerator::haveExpectedCameras(CameraManager *cm)
+{
+	std::vector<std::reference_wrapper<DeviceID>> &supportedDevices =
+		PipelineHandlerFactory::getDeviceIDs();
+	std::vector<DeviceID> availableDevices;
+	std::vector<DeviceID> intersection;
+	struct dirent *ent;
+	DIR *dir;
+	const char *pciDir = "/sys/bus/pci/devices";
+
+	dir = opendir(pciDir);
+	if (!dir) {
+		LOG(DeviceEnumerator, Error)
+			<< "Failed to open sysfs PCI directory";
+		/* We can't expect any cameras, so we vacuously have them all. */
+		return true;
+	}
+
+	while ((ent = readdir(dir)) != nullptr) {
+		std::string path = pciDir + std::string("/") + ent->d_name + "/vendor";
+		int vendor = extractNumberFromFile(path);
+		if (vendor < 0)
+			continue;
+
+		path = pciDir + std::string("/") + ent->d_name + "/device";
+		int device = extractNumberFromFile(path);
+		if (device < 0)
+			continue;
+
+		availableDevices.push_back(PCIDeviceID(vendor, device));
+	}
+
+	closedir(dir);
+
+	std::set_intersection(supportedDevices.begin(), supportedDevices.end(),
+			      availableDevices.begin(), availableDevices.end(),
+			      back_inserter(intersection),
+			      compareDevices<PCIDeviceID>);
+
+	if (cm->cameras().size() < intersection.size()) {
+		LOG(DeviceEnumerator, Warning) << "Not enough cameras!";
+		return false;
+	}
+
+	LOG(DeviceEnumerator, Debug) << "All cameras correctly initialized";
+	return true;
+}
+
 } /* namespace libcamera */
diff --git a/src/libcamera/include/device_enumerator.h b/src/libcamera/include/device_enumerator.h
index 770f4277..11c4cdfb 100644
--- a/src/libcamera/include/device_enumerator.h
+++ b/src/libcamera/include/device_enumerator.h
@@ -13,6 +13,8 @@ 
 
 #include <linux/media.h>
 
+#include <libcamera/camera_manager.h>
+
 namespace libcamera {
 
 class MediaDevice;
@@ -43,6 +45,8 @@  public:
 
 	std::shared_ptr<MediaDevice> search(const DeviceMatch &dm);
 
+	static bool haveExpectedCameras(CameraManager *cm);
+
 protected:
 	std::shared_ptr<MediaDevice> createDevice(const std::string &deviceNode);
 	void addDevice(const std::shared_ptr<MediaDevice> &media);