[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