| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/device/generic_sensor/platform_sensor_fusion.h" |
| |
| #include "base/logging.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "services/device/generic_sensor/platform_sensor_fusion_algorithm.h" |
| #include "services/device/generic_sensor/platform_sensor_provider.h" |
| |
| namespace device { |
| |
| class PlatformSensorFusion::Factory : public base::RefCounted<Factory> { |
| public: |
| static void CreateSensorFusion( |
| mojo::ScopedSharedBufferMapping mapping, |
| std::unique_ptr<PlatformSensorFusionAlgorithm> fusion_algorithm, |
| const PlatformSensorProviderBase::CreateSensorCallback& callback, |
| PlatformSensorProvider* provider) { |
| scoped_refptr<Factory> factory(new Factory(std::move(mapping), |
| std::move(fusion_algorithm), |
| std::move(callback), provider)); |
| factory->FetchSources(); |
| } |
| |
| private: |
| friend class base::RefCounted<Factory>; |
| |
| Factory(mojo::ScopedSharedBufferMapping mapping, |
| std::unique_ptr<PlatformSensorFusionAlgorithm> fusion_algorithm, |
| const PlatformSensorProviderBase::CreateSensorCallback& callback, |
| PlatformSensorProvider* provider) |
| : fusion_algorithm_(std::move(fusion_algorithm)), |
| result_callback_(std::move(callback)), |
| mapping_(std::move(mapping)), |
| provider_(provider) { |
| const auto& types = fusion_algorithm_->source_types(); |
| DCHECK(!types.empty()); |
| // Make sure there are no dups. |
| DCHECK(std::adjacent_find(types.begin(), types.end()) == types.end()); |
| DCHECK(result_callback_); |
| DCHECK(mapping_); |
| DCHECK(provider_); |
| } |
| |
| ~Factory() = default; |
| |
| void FetchSources() { |
| for (mojom::SensorType type : fusion_algorithm_->source_types()) { |
| scoped_refptr<PlatformSensor> sensor = provider_->GetSensor(type); |
| if (sensor) { |
| SensorCreated(std::move(sensor)); |
| } else { |
| provider_->CreateSensor(type, |
| base::Bind(&Factory::SensorCreated, this)); |
| } |
| } |
| } |
| |
| void SensorCreated(scoped_refptr<PlatformSensor> sensor) { |
| if (!result_callback_) { |
| // It is possible, if this callback has been already called |
| // with nullptr (i.e. failed to fetch some of the required |
| // source sensors). See the condition below. |
| return; |
| } |
| |
| if (!sensor) { |
| std::move(result_callback_).Run(nullptr); |
| return; |
| } |
| mojom::SensorType type = sensor->GetType(); |
| sources_map_[type] = std::move(sensor); |
| if (sources_map_.size() == fusion_algorithm_->source_types().size()) { |
| scoped_refptr<PlatformSensor> fusion_sensor(new PlatformSensorFusion( |
| std::move(mapping_), provider_, std::move(fusion_algorithm_), |
| std::move(sources_map_))); |
| std::move(result_callback_).Run(fusion_sensor); |
| } |
| } |
| |
| std::unique_ptr<PlatformSensorFusionAlgorithm> fusion_algorithm_; |
| PlatformSensorProviderBase::CreateSensorCallback result_callback_; |
| mojo::ScopedSharedBufferMapping mapping_; |
| PlatformSensorProvider* provider_; |
| PlatformSensorFusion::SourcesMap sources_map_; |
| }; |
| |
| // static |
| void PlatformSensorFusion::Create( |
| mojo::ScopedSharedBufferMapping mapping, |
| PlatformSensorProvider* provider, |
| std::unique_ptr<PlatformSensorFusionAlgorithm> fusion_algorithm, |
| const PlatformSensorProviderBase::CreateSensorCallback& callback) { |
| Factory::CreateSensorFusion(std::move(mapping), std::move(fusion_algorithm), |
| callback, provider); |
| } |
| |
| PlatformSensorFusion::PlatformSensorFusion( |
| mojo::ScopedSharedBufferMapping mapping, |
| PlatformSensorProvider* provider, |
| std::unique_ptr<PlatformSensorFusionAlgorithm> fusion_algorithm, |
| PlatformSensorFusion::SourcesMap sources) |
| : PlatformSensor(fusion_algorithm->fused_type(), |
| std::move(mapping), |
| provider), |
| fusion_algorithm_(std::move(fusion_algorithm)), |
| source_sensors_(std::move(sources)), |
| reporting_mode_(mojom::ReportingMode::CONTINUOUS) { |
| for (const auto& pair : source_sensors_) |
| pair.second->AddClient(this); |
| |
| fusion_algorithm_->set_fusion_sensor(this); |
| |
| if (std::any_of(source_sensors_.begin(), source_sensors_.end(), |
| [](const SourcesMapEntry& pair) { |
| return pair.second->GetReportingMode() == |
| mojom::ReportingMode::ON_CHANGE; |
| })) { |
| reporting_mode_ = mojom::ReportingMode::ON_CHANGE; |
| } |
| } |
| |
| PlatformSensorFusion::~PlatformSensorFusion() { |
| for (const auto& pair : source_sensors_) |
| pair.second->RemoveClient(this); |
| } |
| |
| mojom::ReportingMode PlatformSensorFusion::GetReportingMode() { |
| return reporting_mode_; |
| } |
| |
| PlatformSensorConfiguration PlatformSensorFusion::GetDefaultConfiguration() { |
| PlatformSensorConfiguration default_configuration; |
| for (const auto& pair : source_sensors_) { |
| double frequency = pair.second->GetDefaultConfiguration().frequency(); |
| if (frequency > default_configuration.frequency()) |
| default_configuration.set_frequency(frequency); |
| } |
| return default_configuration; |
| } |
| |
| bool PlatformSensorFusion::StartSensor( |
| const PlatformSensorConfiguration& configuration) { |
| // Remove all the previously added source configs. |
| StopSensor(); |
| for (const auto& pair : source_sensors_) { |
| if (!pair.second->StartListening(this, configuration)) { |
| StopSensor(); |
| return false; |
| } |
| } |
| |
| fusion_algorithm_->SetFrequency(configuration.frequency()); |
| return true; |
| } |
| |
| void PlatformSensorFusion::StopSensor() { |
| for (const auto& pair : source_sensors_) |
| pair.second->StopListening(this); |
| |
| fusion_algorithm_->Reset(); |
| } |
| |
| bool PlatformSensorFusion::CheckSensorConfiguration( |
| const PlatformSensorConfiguration& configuration) { |
| for (const auto& pair : source_sensors_) { |
| if (!pair.second->CheckSensorConfiguration(configuration)) |
| return false; |
| } |
| return true; |
| } |
| |
| void PlatformSensorFusion::OnSensorReadingChanged(mojom::SensorType type) { |
| SensorReading reading; |
| reading.raw.timestamp = |
| (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(); |
| |
| if (!fusion_algorithm_->GetFusedData(type, &reading)) |
| return; |
| |
| if (GetReportingMode() == mojom::ReportingMode::ON_CHANGE && |
| !fusion_algorithm_->IsReadingSignificantlyDifferent(reading_, reading)) { |
| return; |
| } |
| |
| reading_ = reading; |
| UpdateSharedBufferAndNotifyClients(reading_); |
| } |
| |
| void PlatformSensorFusion::OnSensorError() { |
| NotifySensorError(); |
| } |
| |
| bool PlatformSensorFusion::IsSuspended() { |
| for (auto& client : clients_) { |
| if (!client.IsSuspended()) |
| return false; |
| } |
| return true; |
| } |
| |
| bool PlatformSensorFusion::GetSourceReading(mojom::SensorType type, |
| SensorReading* result) { |
| auto it = source_sensors_.find(type); |
| if (it != source_sensors_.end()) |
| return it->second->GetLatestReading(result); |
| NOTREACHED(); |
| return false; |
| } |
| |
| } // namespace device |