[PATCH 2/2] libcamera: Add GyroSensor as a base class

Harvey Yang chenghaoyang at chromium.org
Mon Oct 14 15:18:57 CEST 2024


An android-cros implementation is also added, with defined
SensorHalClient interface connecting to CrOS daemon iioservice.

Signed-off-by: Harvey Yang <chenghaoyang at chromium.org>
Co-developed-by: Han-Lin Chen <hanlinchen at chromium.org>
Signed-off-by: Han-Lin Chen <hanlinchen at chromium.org>
---
 include/libcamera/internal/gyro_sensor.h |  65 ++++++++
 src/libcamera/cros_gyro_sensor.cpp       | 179 +++++++++++++++++++++++
 src/libcamera/gyro_sensor.cpp            |  82 +++++++++++
 src/libcamera/meson.build                |   8 +
 4 files changed, 334 insertions(+)
 create mode 100644 include/libcamera/internal/gyro_sensor.h
 create mode 100644 src/libcamera/cros_gyro_sensor.cpp
 create mode 100644 src/libcamera/gyro_sensor.cpp

diff --git a/include/libcamera/internal/gyro_sensor.h b/include/libcamera/internal/gyro_sensor.h
new file mode 100644
index 000000000..3a2d5ecee
--- /dev/null
+++ b/include/libcamera/internal/gyro_sensor.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Google Inc.
+ *
+ * gyro_sensor.h - A gyroscope sensor
+ */
+
+#pragma once
+
+#include <libcamera/base/class.h>
+
+namespace libcamera {
+
+class GyroSensor final : public libcamera::Extensible
+{
+	LIBCAMERA_DECLARE_PRIVATE()
+
+public:
+	enum class Location {
+		kNone = 0, // The device doesn't have the location attribute.
+		kBase = 1,
+		kLid = 2,
+		kCamera = 3,
+	};
+
+	struct SensorSample {
+		double x_value;
+		double y_value;
+		double z_value;
+		int64_t timestamp;
+	};
+
+	GyroSensor();
+
+	int init(Location location);
+
+	bool startReading(double frequency);
+	void stopReading();
+
+	SensorSample getLatestSample();
+};
+
+#define PUBLIC_GYRO_SENSOR_IMPLEMENTATION                      \
+	GyroSensor::GyroSensor()                               \
+		: Extensible(std::make_unique<Private>())      \
+	{                                                      \
+	}                                                      \
+	int GyroSensor::init(Location location)                \
+	{                                                      \
+		return _d()->init(location);                   \
+	}                                                      \
+	bool GyroSensor::startReading(double frequency)        \
+	{                                                      \
+		return _d()->startReading(frequency);          \
+	}                                                      \
+	void GyroSensor::stopReading()                         \
+	{                                                      \
+		_d()->stopReading();                           \
+	}                                                      \
+	GyroSensor::SensorSample GyroSensor::getLatestSample() \
+	{                                                      \
+		return _d()->getLatestSample();                \
+	}
+
+} /* namespace libcamera */
diff --git a/src/libcamera/cros_gyro_sensor.cpp b/src/libcamera/cros_gyro_sensor.cpp
new file mode 100644
index 000000000..062f0013d
--- /dev/null
+++ b/src/libcamera/cros_gyro_sensor.cpp
@@ -0,0 +1,179 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Google Inc.
+ *
+ * cros_gyro_sensor.cpp - Chromium OS gyroscope sensor using mojo
+ */
+
+#include <libcamera/base/log.h>
+#include <libcamera/base/mutex.h>
+#include <libcamera/base/thread_annotations.h>
+
+#include "libcamera/internal/gyro_sensor.h"
+
+#include <cros-camera/sensor_hal_client.h>
+
+#include "../android/cros_mojo_token.h"
+
+namespace libcamera {
+
+namespace {
+
+std::string convertErrorTypeToString(cros::SamplesObserver::ErrorType error)
+{
+	switch (error) {
+	case cros::SamplesObserver::ErrorType::MOJO_DISCONNECTED:
+		return "MOJO_DISCONNECTED";
+
+	case cros::SamplesObserver::ErrorType::READ_FAILED:
+		return "READ_FAILED";
+
+	case cros::SamplesObserver::ErrorType::INVALID_ARGUMENT:
+		return "INVALID_ARGUMENT";
+
+	case cros::SamplesObserver::ErrorType::DEVICE_REMOVED:
+		return "DEVICE_REMOVED";
+	}
+}
+
+} /* namespace */
+
+LOG_DEFINE_CATEGORY(CrosGyroSensor)
+
+class GyroSensor::Private : public Extensible::Private,
+			    public cros::SamplesObserver
+{
+	LIBCAMERA_DECLARE_PUBLIC(GyroSensor)
+
+public:
+	Private();
+
+	int init(Location location);
+
+	bool startReading(double frequency);
+	void stopReading();
+
+	SensorSample getLatestSample();
+
+	void OnSampleUpdated(cros::SamplesObserver::Sample sample) override;
+	void OnErrorOccurred(cros::SamplesObserver::ErrorType error) override;
+
+private:
+	cros::SensorHalClient *sensorHalClient_;
+	cros::SensorHalClient::Location location_;
+
+	libcamera::Mutex gyroSampleMutex_;
+	SensorSample gyroSample_ LIBCAMERA_TSA_GUARDED_BY(gyroSampleMutex_);
+};
+
+/**
+ * \class libcamera::GyroSensor::Private
+ * \brief CrOS implementation of GyroSensor
+ */
+GyroSensor::Private::Private()
+{
+}
+
+/**
+ * \brief Initialize with \a location inquiried
+ * \param[in] location The gyroscope with \a location needed
+ * \return 0 on success or a negative error code otherwise
+ */
+int GyroSensor::Private::init(Location location)
+{
+	sensorHalClient_ = cros::SensorHalClient::GetInstance(gCrosMojoToken);
+	location_ = static_cast<cros::SensorHalClient::Location>(location);
+	if (sensorHalClient_ &&
+	    sensorHalClient_->HasDevice(
+		    cros::SensorHalClient::DeviceType::kAnglVel, location_)) {
+		return 0;
+	}
+
+	return -ENXIO;
+}
+
+/**
+ * \brief Start reading gyroscope samples with \a frequency
+ * \param[in] frequency The frequency of samples required
+ *
+ * This should be called after init().
+ *
+ * \sa init()
+ *
+ * \return True if succeed
+ */
+bool GyroSensor::Private::startReading(double frequency)
+{
+	return sensorHalClient_->RegisterSamplesObserver(
+		cros::SensorHalClient::DeviceType::kAnglVel,
+		location_, frequency, this);
+}
+
+/**
+ * \brief Stop reading gyroscope samples
+ *
+ * \sa startReading()
+ */
+void GyroSensor::Private::stopReading()
+{
+	sensorHalClient_->UnregisterSamplesObserver(this);
+}
+
+/**
+ * \brief This should be called after startReading()
+ *
+ * \sa startReading()
+ *
+ * \return The latest received sample
+ */
+GyroSensor::SensorSample GyroSensor::Private::getLatestSample()
+{
+	MutexLocker lock(gyroSampleMutex_);
+
+	return gyroSample_;
+}
+
+/**
+ * \brief A sample is updated and pushed to GyroSensor::Private
+ * \param[in] sample The sample being updated
+ */
+void GyroSensor::Private::OnSampleUpdated(cros::SamplesObserver::Sample sample)
+{
+	MutexLocker lock(gyroSampleMutex_);
+
+	gyroSample_.x_value = sample.x_value;
+	gyroSample_.y_value = sample.y_value;
+	gyroSample_.z_value = sample.z_value;
+	gyroSample_.timestamp = sample.timestamp;
+}
+
+/**
+ * \brief An error is occurred and pushed to GyroSensor::Private
+ * \param[in] error The error occurred
+ */
+void GyroSensor::Private::OnErrorOccurred(cros::SamplesObserver::ErrorType error)
+{
+	switch (error) {
+	case cros::SamplesObserver::ErrorType::READ_FAILED:
+		LOG(CrosGyroSensor, Error) << "SensorHalClient error: "
+					   << convertErrorTypeToString(error);
+		break;
+
+	case cros::SamplesObserver::ErrorType::MOJO_DISCONNECTED:
+	case cros::SamplesObserver::ErrorType::INVALID_ARGUMENT:
+	case cros::SamplesObserver::ErrorType::DEVICE_REMOVED:
+		LOG(CrosGyroSensor, Error) << "SensorHalClient error: "
+					   << convertErrorTypeToString(error)
+					   << ", aborting all usages";
+		auto *sensorHalClient =
+			cros::SensorHalClient::GetInstance(gCrosMojoToken);
+		if (sensorHalClient)
+			sensorHalClient->UnregisterSamplesObserver(this);
+
+		break;
+	}
+}
+
+PUBLIC_GYRO_SENSOR_IMPLEMENTATION
+
+} /* namespace libcamera */
diff --git a/src/libcamera/gyro_sensor.cpp b/src/libcamera/gyro_sensor.cpp
new file mode 100644
index 000000000..0ea4f0c71
--- /dev/null
+++ b/src/libcamera/gyro_sensor.cpp
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Google Inc.
+ *
+ * gyro_sensor.cpp - A gyroscope sensor
+ */
+
+/**
+ * \class libcamera::GyroSensor
+ * \brief Gyroscope Sensor
+ *
+ * The GyroSensor class models a gyroscope sensor capable of reporting
+ * gyroscope samples, with x, y, z, and timestamp channels. There might be
+ * multiple gyroscope sensors on a system, while should be distinguishable via
+ * GyroSensor::Location.
+ */
+
+/**
+ * \enum libcamera::GyroSensor::Location
+ * \brief Gyroscope sensor's location type
+ * \var GyroSensor::kNone
+ * \brief No location attribute available
+ * \var GyroSensor::kBase
+ * \brief Gyroscope sensor is on the base
+ * \var GyroSensor::kLid
+ * \brief Gyroscope sensor is on the lid
+ * \var GyroSensor::kCamera
+ * \brief Gyroscope sensor is on the camera
+ */
+
+/**
+ * \struct libcamera::GyroSensor::SensorSample
+ * \brief SensorSample contains all available channels within a sample
+ *
+ * \var SensorSample::x_value
+ * \brief Sensor reading on the x axis
+ *
+ * \var SensorSample::y_value
+ * \brief Sensor reading on the y axis
+ *
+ * \var SensorSample::z_value
+ * \brief Sensor reading on the z axis
+ *
+ * \var SensorSample::timestamp
+ * \brief The timestamp of the sample
+ */
+
+/**
+ * \fn int GyroSensor::init(Location location)
+ * \brief Initialize with \a location inquiried
+ * \param[in] location The gyroscope with \a location needed
+ * \return 0 on success or a negative error code otherwise
+ */
+
+/**
+ * \fn bool GyroSensor::startReading(double frequency)
+ * \brief Start reading gyroscope samples with \a frequency
+ * \param[in] frequency The frequency of samples required
+ *
+ * This should be called after init().
+ *
+ * \sa init()
+ *
+ * \return True if succeed
+ */
+
+/**
+ * \fn void GyroSensor::stopReading()
+ * \brief Stop reading gyroscope samples
+ *
+ * \sa startReading()
+ */
+
+/**
+ * \fn SensorSample GyroSensor::getLatestSample()
+ *
+ * This should be called after startReading()
+ *
+ * \sa startReading()
+ *
+ * \return The latest received sample
+ */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index aa9ab0291..9cd393920 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -60,6 +60,14 @@ includes = [
 
 libcamera_deps = []
 
+if get_option('android').enabled() and get_option('android_platform') == 'cros'
+    libcamera_public_sources += files([
+        'cros_gyro_sensor.cpp',
+        'gyro_sensor.cpp',
+    ])
+    libcamera_deps += [dependency('libcros_camera')]
+endif
+
 libatomic = cc.find_library('atomic', required : false)
 libthreads = dependency('threads')
 
-- 
2.47.0.rc1.288.g06298d1525-goog



More information about the libcamera-devel mailing list