blob: 3ddd07905c7ef73e5c6efe89b4fce2f230e0b1da [file] [log] [blame]
// Copyright 2024 The Fuchsia 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 "src/sensors/playback/driver_impl.h"
#include <lib/fpromise/bridge.h>
namespace sensors::playback {
namespace {
using fpromise::bridge;
using fpromise::promise;
using fpromise::result;
using fuchsia_hardware_sensors::ActivateSensorError;
using fuchsia_hardware_sensors::ConfigureSensorRateError;
using fuchsia_hardware_sensors::DeactivateSensorError;
using fuchsia_hardware_sensors::Driver;
using fuchsia_sensors_types::SensorEvent;
using fuchsia_sensors_types::SensorInfo;
} // namespace
bool DriverImpl::client_connected_ = false;
DriverImpl::DriverImpl(async_dispatcher_t* dispatcher, PlaybackController& controller)
: ActorBase(dispatcher, scope_), controller_(controller) {}
void DriverImpl::GetSensorsList(GetSensorsListCompleter::Sync& completer) {
ZX_ASSERT(binding_ref_.has_value());
Schedule(controller_.GetSensorsList().and_then(
[completer = completer.ToAsync()](const std::vector<SensorInfo>& sensor_list) mutable {
completer.Reply(sensor_list);
}));
}
void DriverImpl::ActivateSensor(ActivateSensorRequest& request,
ActivateSensorCompleter::Sync& completer) {
ZX_ASSERT(binding_ref_.has_value());
Schedule(controller_.ActivateSensor(request.sensor_id())
.then([completer = completer.ToAsync()](
result<void, ActivateSensorError>& result) mutable -> promise<void> {
if (result.is_ok()) {
completer.Reply(fit::success());
} else {
completer.Reply(fit::error(result.error()));
}
return fpromise::make_ok_promise();
}));
}
void DriverImpl::DeactivateSensor(DeactivateSensorRequest& request,
DeactivateSensorCompleter::Sync& completer) {
ZX_ASSERT(binding_ref_.has_value());
Schedule(controller_.DeactivateSensor(request.sensor_id())
.then([completer = completer.ToAsync()](
result<void, DeactivateSensorError>& result) mutable -> promise<void> {
if (result.is_ok()) {
completer.Reply(fit::success());
} else {
completer.Reply(fit::error(result.error()));
}
return fpromise::make_ok_promise();
}));
}
void DriverImpl::ConfigureSensorRate(ConfigureSensorRateRequest& request,
ConfigureSensorRateCompleter::Sync& completer) {
ZX_ASSERT(binding_ref_.has_value());
Schedule(controller_.ConfigureSensorRate(request.sensor_id(), request.sensor_rate_config())
.then([completer = completer.ToAsync()](
result<void, ConfigureSensorRateError>& result) mutable -> promise<void> {
if (result.is_ok()) {
completer.Reply(fit::success());
} else {
completer.Reply(fit::error(result.error()));
}
return fpromise::make_ok_promise();
}));
}
void DriverImpl::handle_unknown_method(fidl::UnknownMethodMetadata<Driver> metadata,
fidl::UnknownMethodCompleter::Sync& completer) {
ZX_ASSERT(binding_ref_.has_value());
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
void DriverImpl::OnUnbound(fidl::UnbindInfo info, fidl::ServerEnd<Driver> server_end,
fit::callback<void()> unbind_callback) {
// |is_user_initiated| returns true if the server code called |Close| on a
// completer, or |Unbind| / |Close| on the |binding_ref_|, to proactively
// teardown the connection. These cases are usually part of normal server
// shutdown, so logging is unnecessary.
if (info.is_user_initiated()) {
unbind_callback();
return;
}
if (info.is_peer_closed()) {
// If the peer (the client) closed their endpoint, log that as INFO.
FX_LOGS(INFO) << "Client disconnected";
} else {
// Treat other unbind causes as errors.
FX_LOGS(ERROR) << "Server error: " << info;
}
controller_.DriverClientDisconnected(std::move(unbind_callback));
}
promise<void> DriverImpl::DisconnectClient(zx_status_t epitaph) {
bridge<void> bridge;
Schedule([this, epitaph, completer = std::move(bridge.completer)]() mutable {
if (binding_ref_.has_value()) {
FX_LOGS(INFO) << "Disconnecting driver protocol client.";
binding_ref_->Close(epitaph);
binding_ref_ = std::nullopt;
}
completer.complete_ok();
});
return bridge.consumer.promise();
}
void DriverImpl::AttachToController() {
controller_.SetDisconnectDriverClientCallback(
[this](zx_status_t epitaph) { return DisconnectClient(epitaph); });
controller_.SetEventCallback([this](const SensorEvent& event) {
Schedule([this, event]() {
fit::result result = fidl::SendEvent(*binding_ref_)->OnSensorEvent(event);
if (!result.is_ok()) {
FX_LOGS(ERROR) << "Error sending event: " << result.error_value();
}
});
});
}
} // namespace sensors::playback