| // 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>); |