blob: 9320d26bcdde96f13f7c6aa3244a4c0110a06ac0 [file] [log] [blame]
// Copyright 2022 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 "i2c_temperature.h"
#include <lib/driver/component/cpp/service_client.h>
#include "constants.h"
#include "temperature_server.h"
namespace i2c_temperature {
zx::result<> I2cTemperatureDriver::Start() {
// Connect to the I2C bus controller.
auto channel_result = SetupI2cChannel();
if (channel_result.is_error()) {
return channel_result.take_error();
}
// Serve the examples.i2c.temperature/Device protocol to clients through the
// examples.i2c.temperature/Service wrapper.
examples_i2c_temperature::Service::InstanceHandler handler({
.device = fit::bind_member<&I2cTemperatureDriver::Serve>(this),
});
auto result =
context().outgoing()->AddService<examples_i2c_temperature::Service>(std::move(handler));
if (result.is_error()) {
FDF_SLOG(ERROR, "Failed to add service", KV("status", result.status_string()));
return result.take_error();
}
// Reset the sensor.
auto write_result = i2c_channel_->Write16(kSoftResetCommand);
if (write_result.is_error()) {
FDF_SLOG(ERROR, "Failed to send reset command: ", KV("status", write_result.status_string()));
return write_result.take_error();
}
// Initialize the driver compat service context.
compat::Context::ConnectAndCreate(
&context(), dispatcher(),
fit::bind_member<&I2cTemperatureDriver::InitializeCompatService>(this));
return zx::ok();
}
// Connect to the `fuchsia.hardware.i2c/Device` protocol offered by the parent device node.
zx::result<> I2cTemperatureDriver::SetupI2cChannel() {
auto client_endpoint = fdf::Connect<fuchsia_hardware_i2c::Service::Device>(*context().incoming());
if (client_endpoint.status_value() != ZX_OK) {
FDF_SLOG(ERROR, "Failed to setup I2cChannel", KV("status", client_endpoint.status_string()));
return client_endpoint.take_error();
}
auto i2c_client = fidl::WireClient(std::move(*client_endpoint), dispatcher());
i2c_channel_ = std::make_shared<I2cChannel>(std::move(i2c_client));
return zx::ok();
}
// Initialize the driver compat context and export `examples.i2.temperature/Service` to
// devfs.
void I2cTemperatureDriver::InitializeCompatService(
zx::result<std::shared_ptr<compat::Context>> compat_result) {
if (!compat_result.is_ok()) {
FDF_SLOG(ERROR, "Failed to create compat context.",
KV("status", compat_result.status_string()));
node().reset();
return;
}
compat_context_ = std::move(*compat_result);
zx::result connection = this->context().incoming()->Connect<fuchsia_device_fs::Exporter>();
if (connection.is_error()) {
FDF_SLOG(ERROR, "Failed to connect to fuchsia_device_fs::Exporter",
KV("status", connection.status_string()));
node().reset();
return;
}
fidl::WireSyncClient devfs_exporter{std::move(connection.value())};
zx::result connector = devfs_connector_.Bind(dispatcher());
if (connector.is_error()) {
FDF_SLOG(ERROR, "Failed to bind devfs_connector: %s", KV("status", connector.status_string()));
node().reset();
return;
}
fidl::WireResult export_result = devfs_exporter->ExportV2(
std::move(connector.value()),
fidl::StringView::FromExternal(compat_context_->TopologicalPath(name())),
fidl::StringView(), fuchsia_device_fs::ExportOptions());
if (!export_result.ok()) {
FDF_SLOG(ERROR, "Failed to export to devfs: %s", KV("status", export_result.status_string()));
node().reset();
return;
}
if (export_result.value().is_error()) {
FDF_SLOG(ERROR, "Failed to export to devfs: %s",
KV("status", zx_status_get_string(export_result.value().error_value())));
node().reset();
return;
}
}
void I2cTemperatureDriver::Serve(fidl::ServerEnd<examples_i2c_temperature::Device> request) {
I2cTemperatureServer::BindDeviceClient(dispatcher(), &logger(), i2c_channel_, std::move(request));
}
} // namespace i2c_temperature
FUCHSIA_DRIVER_RECORD_CPP_V2(fdf::Record<i2c_temperature::I2cTemperatureDriver>);