From 1a57bcb8d1a7a49cc8a43596a79d57cd2fbb5dfe Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 4 Jan 2019 21:19:38 +0200 Subject: libcamera: Add event notification infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add three new classes, EventDispatcher, EventNotifier and Timer, that define APIs for file descriptor event notification and timers. The implementation of the EventDispatcher is meant to be provided to libcamera by the application. The event dispatcher is integrated twith the camera manager to implement automatic registration of timers and events. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- include/libcamera/camera_manager.h | 7 ++ include/libcamera/event_dispatcher.h | 33 ++++++++++ include/libcamera/event_notifier.h | 42 ++++++++++++ include/libcamera/libcamera.h | 1 + include/libcamera/meson.build | 3 + include/libcamera/timer.h | 37 +++++++++++ src/libcamera/camera_manager.cpp | 41 +++++++++++- src/libcamera/event_dispatcher.cpp | 103 +++++++++++++++++++++++++++++ src/libcamera/event_notifier.cpp | 121 +++++++++++++++++++++++++++++++++++ src/libcamera/meson.build | 3 + src/libcamera/timer.cpp | 105 ++++++++++++++++++++++++++++++ 11 files changed, 495 insertions(+), 1 deletion(-) create mode 100644 include/libcamera/event_dispatcher.h create mode 100644 include/libcamera/event_notifier.h create mode 100644 include/libcamera/timer.h create mode 100644 src/libcamera/event_dispatcher.cpp create mode 100644 src/libcamera/event_notifier.cpp create mode 100644 src/libcamera/timer.cpp diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h index e14da0f8..15e7c162 100644 --- a/include/libcamera/camera_manager.h +++ b/include/libcamera/camera_manager.h @@ -14,6 +14,7 @@ namespace libcamera { class Camera; class DeviceEnumerator; +class EventDispatcher; class PipelineHandler; class CameraManager @@ -27,13 +28,19 @@ public: static CameraManager *instance(); + void setEventDispatcher(EventDispatcher *dispatcher); + EventDispatcher *eventDispatcher(); + private: CameraManager(); CameraManager(const CameraManager &) = delete; void operator=(const CameraManager &) = delete; + ~CameraManager(); DeviceEnumerator *enumerator_; std::vector pipes_; + + EventDispatcher *dispatcher_; }; } /* namespace libcamera */ diff --git a/include/libcamera/event_dispatcher.h b/include/libcamera/event_dispatcher.h new file mode 100644 index 00000000..c20518c6 --- /dev/null +++ b/include/libcamera/event_dispatcher.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * event_dispatcher.h - Event dispatcher + */ +#ifndef __LIBCAMERA_EVENT_DISPATCHER_H__ +#define __LIBCAMERA_EVENT_DISPATCHER_H__ + +#include + +namespace libcamera { + +class EventNotifier; +class Timer; + +class EventDispatcher +{ +public: + virtual ~EventDispatcher(); + + virtual void registerEventNotifier(EventNotifier *notifier) = 0; + virtual void unregisterEventNotifier(EventNotifier *notifier) = 0; + + virtual void registerTimer(Timer *timer) = 0; + virtual void unregisterTimer(Timer *timer) = 0; + + virtual void processEvents() = 0; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_EVENT_DISPATCHER_H__ */ diff --git a/include/libcamera/event_notifier.h b/include/libcamera/event_notifier.h new file mode 100644 index 00000000..1e9b6da1 --- /dev/null +++ b/include/libcamera/event_notifier.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * event_notifier.h - File descriptor event notifier + */ +#ifndef __LIBCAMERA_EVENT_NOTIFIER_H__ +#define __LIBCAMERA_EVENT_NOTIFIER_H__ + +#include + +namespace libcamera { + +class EventNotifier +{ +public: + enum Type { + Read, + Write, + Exception, + }; + + EventNotifier(int fd, Type type); + virtual ~EventNotifier(); + + Type type() const { return type_; } + int fd() const { return fd_; } + + bool enabled() const { return enabled_; } + void setEnabled(bool enable); + + Signal activated; + +private: + int fd_; + Type type_; + bool enabled_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_EVENT_NOTIFIER_H__ */ diff --git a/include/libcamera/libcamera.h b/include/libcamera/libcamera.h index f9556a8b..785babef 100644 --- a/include/libcamera/libcamera.h +++ b/include/libcamera/libcamera.h @@ -9,5 +9,6 @@ #include #include +#include #endif /* __LIBCAMERA_LIBCAMERA_H__ */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 6f87689e..d7cb55ba 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -1,8 +1,11 @@ libcamera_api = files([ 'camera.h', 'camera_manager.h', + 'event_dispatcher.h', + 'event_notifier.h', 'libcamera.h', 'signal.h', + 'timer.h', ]) install_headers(libcamera_api, diff --git a/include/libcamera/timer.h b/include/libcamera/timer.h new file mode 100644 index 00000000..97dcc01f --- /dev/null +++ b/include/libcamera/timer.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * timer.h - Generic timer + */ +#ifndef __LIBCAMERA_TIMER_H__ +#define __LIBCAMERA_TIMER_H__ + +#include + +#include + +namespace libcamera { + +class Timer +{ +public: + Timer(); + + void start(unsigned int msec); + void stop(); + bool isRunning() const; + + unsigned int interval() const { return interval_; } + uint64_t deadline() const { return deadline_; } + + Signal timeout; + +private: + unsigned int interval_; + uint64_t deadline_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_TIMER_H__ */ diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 1a9d2f38..6e1d5db1 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -6,8 +6,10 @@ */ #include +#include #include "device_enumerator.h" +#include "log.h" #include "pipeline_handler.h" /** @@ -37,10 +39,15 @@ namespace libcamera { CameraManager::CameraManager() - : enumerator_(nullptr) + : enumerator_(nullptr), dispatcher_(nullptr) { } +CameraManager::~CameraManager() +{ + delete dispatcher_; +} + /** * \brief Start the camera manager * @@ -176,4 +183,36 @@ CameraManager *CameraManager::instance() return &manager; } +/** + * \brief Set the event dispatcher + * \param dispatcher Pointer to the event dispatcher + * + * libcamera requires an event dispatcher to integrate event notification and + * timers with the application event loop. Applications shall call this function + * once and only once before the camera manager is started with start() to set + * the event dispatcher. + * + * The CameraManager takes ownership of the event dispatcher and will delete it + * when the application terminates. + */ +void CameraManager::setEventDispatcher(EventDispatcher *dispatcher) +{ + if (dispatcher_) { + LOG(Warning) << "Event dispatcher is already set"; + return; + } + + dispatcher_ = dispatcher; +} + +/** + * \brief Retrieve the event dispatcher + * \return Pointer to the event dispatcher, or nullptr if no event dispatcher + * has been set + */ +EventDispatcher *CameraManager::eventDispatcher() +{ + return dispatcher_; +} + } /* namespace libcamera */ diff --git a/src/libcamera/event_dispatcher.cpp b/src/libcamera/event_dispatcher.cpp new file mode 100644 index 00000000..54627302 --- /dev/null +++ b/src/libcamera/event_dispatcher.cpp @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * event_dispatcher.cpp - Event dispatcher + */ + +#include + +/** + * \file event_dispatcher.h + */ + +namespace libcamera { + +/** + * \class EventDispatcher + * \brief Interface to manage the libcamera events and timers + * + * The EventDispatcher class allows the integration of the application event + * loop with libcamera by abstracting how events and timers are managed and + * processed. + * + * To listen to events, libcamera creates EventNotifier instances and registers + * them with the dispatcher with registerEventNotifier(). The event notifier + * \ref EventNotifier::activated signal is then emitted by the dispatcher + * whenever the event is detected. + * + * To set timers, libcamera creates Timer instances and registers them with the + * dispatcher with registerTimer(). The timer \ref Timer::timeout signal is then + * emitted by the dispatcher when the timer times out. + */ + +EventDispatcher::~EventDispatcher() +{ +} + +/** + * \fn EventDispatcher::registerEventNotifier() + * \brief Register an event notifier + * \param notifier The event notifier to register + * + * Once the \a notifier is registered with the dispatcher, the dispatcher will + * emit the notifier \ref EventNotifier::activated signal whenever a + * corresponding event is detected on the notifier's file descriptor. The event + * is monitored until the notifier is unregistered with + * unregisterEventNotifier(). + * + * Registering multiple notifiers for the same file descriptor and event type is + * not allowed and results in undefined behaviour. + */ + +/** + * \fn EventDispatcher::unregisterEventNotifier() + * \brief Unregister an event notifier + * \param notifier The event notifier to unregister + * + * After this function returns the \a notifier is guaranteed not to emit the + * \ref EventNotifier::activated signal. + * + * If the notifier isn't registered, this function performs no operation. + */ + +/** + * \fn EventDispatcher::registerTimer() + * \brief Register a timer + * \param timer The timer to register + * + * Once the \a timer is registered with the dispatcher, the dispatcher will emit + * the timer \ref Timer::timeout signal when the timer times out. The timer can + * be unregistered with unregisterTimer() before it times out, in which case the + * signal will not be emitted. + * + * When the \a timer times out, it is automatically unregistered by the + * dispatcher and can be registered back as early as from the \ref Timer::timeout + * signal handlers. + * + * Registering the same timer multiple times is not allowed and results in + * undefined behaviour. + */ + +/** + * \fn EventDispatcher::unregisterTimer() + * \brief Unregister a timer + * \param timer The timer to unregister + * + * After this function returns the \a timer is guaranteed not to emit the + * \ref Timer::timeout signal. + * + * If the timer isn't registered, this function performs no operation. + */ + +/** + * \fn EventDispatcher::processEvents() + * \brief Wait for and process pending events + * + * This function processes all pending events associated with registered event + * notifiers and timers and signals the corresponding EventNotifier and Timer + * objects. If no events are pending, it waits for the first event and processes + * it before returning. + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/event_notifier.cpp b/src/libcamera/event_notifier.cpp new file mode 100644 index 00000000..71775a9c --- /dev/null +++ b/src/libcamera/event_notifier.cpp @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * event_notifier.cpp - File descriptor event notifier + */ + +#include +#include +#include + +/** + * \file event_notifier.h + * \brief File descriptor event notifier + */ + +namespace libcamera { + +/** + * \class EventNotifier + * \brief Notify of activity on a file descriptor + * + * The EventNotifier models a file descriptor event source that can be + * monitored. It is created with the file descriptor to be monitored and the + * type of event, and is enabled by default. It will emit the \ref activated + * signal whenever an event of the monitored type occurs on the file descriptor. + * + * Supported type of events are EventNotifier::Read, EventNotifier::Write and + * EventNotifier::Exception. The type is specified when constructing the + * notifier, and can be retrieved using the type() function. To listen to + * multiple event types on the same file descriptor multiple notifiers must be + * created. + * + * The notifier can be disabled with the setEnable() function. When the notifier + * is disabled it ignores events and does not emit the \ref activated signal. + * The notifier can then be re-enabled with the setEnable() function. + * + * Creating multiple notifiers of the same type for the same file descriptor is + * not allowed and results in undefined behaviour. + * + * Notifier events are detected and dispatched from the + * EventDispatcher::processEvents() function. + */ + +/** + * \enum EventNotifier::Type + * Type of file descriptor event to listen for. + * \var EventNotifier::Read + * Data is available to be read from the file descriptor + * \var EventNotifier::Write + * Data can be written to the file descriptor + * \var EventNotifier::Exception + * An exception has occurred on the file descriptor + */ + +/** + * \brief Construct an event notifier with a file descriptor and event type + * \param fd The file descriptor to monitor + * \param type The event type to monitor + */ +EventNotifier::EventNotifier(int fd, Type type) + : fd_(fd), type_(type), enabled_(false) +{ + setEnabled(true); +} + +EventNotifier::~EventNotifier() +{ + setEnabled(false); +} + +/** + * \fn EventNotifier::type() + * \brief Retrieve the type of the event being monitored + * \return The type of the event + */ + +/** + * \fn EventNotifier::fd() + * \brief Retrieve the file descriptor being monitored + * \return The file descriptor + */ + +/** + * \fn EventNotifier::enabled() + * \brief Retrieve the notifier state + * \return True if the notifier is enabled, or false otherwise + * \sa setEnable() + */ + +/** + * \brief Enable or disable the notifier + * \param enable True to enable the notifier, false to disable it + * + * This function enables or disables the notifier. A disabled notifier ignores + * events and does not emit the \ref activated signal. + */ +void EventNotifier::setEnabled(bool enable) +{ + if (enabled_ == enable) + return; + + enabled_ = enable; + + EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher(); + if (enable) + dispatcher->registerEventNotifier(this); + else + dispatcher->unregisterEventNotifier(this); +} + +/** + * \var EventNotifier::activated + * \brief Signal emitted when the event occurs + * + * This signal is emitted when the event \ref type() occurs on the file + * descriptor monitored by the notifier. The notifier pointer is passed as a + * parameter. + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 3ec86e75..61fb9320 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -2,11 +2,14 @@ libcamera_sources = files([ 'camera.cpp', 'camera_manager.cpp', 'device_enumerator.cpp', + 'event_dispatcher.cpp', + 'event_notifier.cpp', 'log.cpp', 'media_device.cpp', 'media_object.cpp', 'pipeline_handler.cpp', 'signal.cpp', + 'timer.cpp', ]) libcamera_headers = files([ diff --git a/src/libcamera/timer.cpp b/src/libcamera/timer.cpp new file mode 100644 index 00000000..b5212ba2 --- /dev/null +++ b/src/libcamera/timer.cpp @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * timer.cpp - Generic timer + */ + +#include + +#include +#include +#include + +#include "log.h" + +/** + * \file timer.h + * \brief Generic timer + */ + +namespace libcamera { + +/** + * \class Timer + * \brief Single-shot timer interface + * + * The Timer class models a single-shot timer that is started with start() and + * emits the \ref timeout signal when it times out. + * + * Once started the timer will run until it times out. It can be stopped with + * stop(), and once it times out or is stopped, can be started again with + * start(). + */ + +/** + * \brief Construct a timer + */ +Timer::Timer() +{ +} + +/** + * \brief Start or restart the timer with a timeout of \a msec + * \param msec The timer duration in milliseconds + * + * If the timer is already running it will be stopped and restarted. + */ +void Timer::start(unsigned int msec) +{ + struct timespec tp; + clock_gettime(CLOCK_MONOTONIC, &tp); + + interval_ = msec; + deadline_ = tp.tv_sec * 1000000000ULL + tp.tv_nsec + msec * 1000000; + + LOG(Debug) << "Starting timer " << this << " with interval " << msec + << ": deadline " << deadline_; + + CameraManager::instance()->eventDispatcher()->registerTimer(this); +} + +/** + * \brief Stop the timer + * + * After this function returns the timer is guaranteed not to emit the + * \ref timeout signal. + * + * If the timer is not running this function performs no operation. + */ +void Timer::stop() +{ + CameraManager::instance()->eventDispatcher()->unregisterTimer(this); + + deadline_ = 0; +} + +/** + * \brief Check if the timer is running + * \return True if the timer is running, false otherwise + */ +bool Timer::isRunning() const +{ + return deadline_ != 0; +} + +/** + * \fn Timer::interval() + * \brief Retrieve the timer interval + * \return The timer interval in milliseconds + */ + +/** + * \fn Timer::deadline() + * \brief Retrieve the timer deadline + * \return The timer deadline in nanoseconds + */ + +/** + * \var Timer::timeout + * \brief Signal emitted when the timer times out + * + * The timer pointer is passed as a parameter. + */ + +} /* namespace libcamera */ -- cgit v1.2.1