blob: 79e91528d58c3e7fe45528983a9f833303f42b1c [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IIOSERVICE_DAEMON_SAMPLES_HANDLER_H_
#define IIOSERVICE_DAEMON_SAMPLES_HANDLER_H_
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <base/files/file_descriptor_watcher_posix.h>
#include <base/memory/weak_ptr.h>
#include <base/sequenced_task_runner.h>
#include <base/single_thread_task_runner.h>
#include <mojo/public/cpp/bindings/receiver_set.h>
#include <libmems/iio_context.h>
#include <libmems/iio_device.h>
#include "iioservice/daemon/common_types.h"
#include "mojo/sensor.mojom.h"
namespace iioservice {
// A SamplesHandler is a handler of an IioDevice's samples. The user should add,
// remove, and update clients with frequencies and channels, and this handler
// will dispatch samples with clients' desired frequencies and channels when
// samples are received from the kernel.
// The user can provide the same |sample_task_runner| to all SamplesHandler as
// there is no blocking function in SamplesHandler and the thread would not be
// heavily loaded.
class SamplesHandler {
public:
static void SamplesHandlerDeleter(SamplesHandler* handler);
using ScopedSamplesHandler =
std::unique_ptr<SamplesHandler, decltype(&SamplesHandlerDeleter)>;
using OnSampleUpdatedCallback = base::RepeatingCallback<void(
mojo::ReceiverId, libmems::IioDevice::IioSample)>;
using OnErrorOccurredCallback = base::RepeatingCallback<void(
mojo::ReceiverId, cros::mojom::ObserverErrorType)>;
static bool GetDevMinMaxFrequency(libmems::IioDevice* iio_device,
double* min_freq,
double* max_freq);
// use fifo
static ScopedSamplesHandler CreateWithFifo(
scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> sample_task_runner,
libmems::IioDevice* iio_device,
OnSampleUpdatedCallback on_sample_updated_callback,
OnErrorOccurredCallback on_error_occurred_callback);
// no fifo
static ScopedSamplesHandler CreateWithoutFifo(
scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> sample_task_runner,
libmems::IioContext* iio_context,
libmems::IioDevice* iio_device,
OnSampleUpdatedCallback on_sample_updated_callback,
OnErrorOccurredCallback on_error_occurred_callback);
virtual ~SamplesHandler();
// It's the user's responsibility to maintain |client_data| before being
// removed or this class being destructed.
// |client_data.iio_device| should be the same as |iio_device_|.
void AddClient(ClientData* client_data);
void RemoveClient(ClientData* client_data);
void UpdateFrequency(
ClientData* client_data,
double frequency,
cros::mojom::SensorDevice::SetFrequencyCallback callback);
void UpdateChannelsEnabled(
ClientData* client_data,
const std::vector<int32_t>& iio_chn_indices,
bool en,
cros::mojom::SensorDevice::SetChannelsEnabledCallback callback);
void GetChannelsEnabled(
ClientData* client_data,
const std::vector<int32_t>& iio_chn_indices,
cros::mojom::SensorDevice::GetChannelsEnabledCallback callback);
protected:
struct SampleData {
// The starting index of the next sample.
uint64_t sample_index = 0;
// Moving averages of channels except for channels that have no batch mode
std::map<int32_t, int64_t> chns;
};
static const uint32_t kNumReadFailedLogsBeforeGivingUp = 100;
static const uint32_t kNumReadFailedLogsRecovery = 10000;
// use fifo
SamplesHandler(scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> sample_task_runner,
libmems::IioDevice* iio_device,
double min_freq,
double max_freq,
OnSampleUpdatedCallback on_sample_updated_callback,
OnErrorOccurredCallback on_error_occurred_callback);
// no fifo
SamplesHandler(scoped_refptr<base::SequencedTaskRunner> ipc_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> sample_task_runner,
libmems::IioDevice* iio_device,
libmems::IioDevice* trigger_device,
double in_freq,
double ax_freq,
OnSampleUpdatedCallback on_sample_updated_callback,
OnErrorOccurredCallback on_error_occurred_callback);
void SetSampleWatcherOnThread();
void StopSampleWatcherOnThread();
double FixFrequency(double frequency);
void AddActiveClientOnThread(ClientData* client_data);
void AddClientOnThread(ClientData* client_data);
void RemoveActiveClientOnThread(ClientData* client_data, double orig_freq);
void RemoveClientOnThread(ClientData* client_data);
void UpdateFrequencyOnThread(
ClientData* client_data,
double frequency,
cros::mojom::SensorDevice::SetFrequencyCallback callback);
bool AddFrequencyOnThread(double frequency);
bool RemoveFrequencyOnThread(double frequency);
bool UpdateRequestedFrequencyOnThread(double frequency);
void UpdateChannelsEnabledOnThread(
ClientData* client_data,
const std::vector<int32_t>& iio_chn_indices,
bool en,
cros::mojom::SensorDevice::SetChannelsEnabledCallback callback);
void GetChannelsEnabledOnThread(
ClientData* client_data,
const std::vector<int32_t>& iio_chn_indices,
cros::mojom::SensorDevice::GetChannelsEnabledCallback callback);
void SetTimeoutTaskOnThread(ClientData* client_data);
void SampleTimeout(ClientData* client_data, uint64_t sample_index);
void OnSampleAvailableWithoutBlocking();
void AddReadFailedLog();
scoped_refptr<base::SequencedTaskRunner> ipc_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> sample_task_runner_;
bool use_fifo_ = true;
libmems::IioDevice* iio_device_;
libmems::IioDevice* trigger_device_ = nullptr;
// Clients that either have invalid frequency or no enabled channels.
std::set<ClientData*> inactive_clients_;
// First is the active client, second is its data.
std::map<ClientData*, SampleData> clients_map_;
// Requested frequencies from clients.
std::multiset<double> frequencies_;
// Max frequency among |frequencies_|.
double requested_frequency_ = 0.0;
// The real device frequency. Given the kernel is requesting upsampling,
// |dev_frequency_| >= |requested_frequency_|.
double dev_frequency_ = 0.0;
double dev_min_frequency_ = 0.0;
double dev_max_frequency_ = 0.0;
// The next coming sample's id. 0-based.
// Shouldn't overflow as timestamp will overflow first.
uint64_t samples_cnt_ = 0;
uint32_t num_read_failed_logs_ = 0;
uint32_t num_read_failed_logs_recovery_ = 0;
base::RepeatingCallback<void(mojo::ReceiverId, libmems::IioDevice::IioSample)>
on_sample_updated_callback_;
base::RepeatingCallback<void(mojo::ReceiverId,
cros::mojom::ObserverErrorType)>
on_error_occurred_callback_;
std::set<int32_t> no_batch_chn_indices;
std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher_;
private:
base::WeakPtrFactory<SamplesHandler> weak_factory_{this};
};
} // namespace iioservice
#endif // IIOSERVICE_DAEMON_SAMPLES_HANDLER_H_