| // 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 <fidl/examples.i2c.temperature/cpp/wire.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. |
| component::ServiceInstanceHandler handler; |
| examples_i2c_temperature::Service::Handler service(&handler); |
| |
| auto result = |
| service.add_device([this](fidl::ServerEnd<examples_i2c_temperature::Device> request) -> void { |
| I2cTemperatureServer::BindDeviceClient(dispatcher(), &logger(), i2c_channel_, |
| std::move(request)); |
| }); |
| ZX_ASSERT(result.is_ok()); |
| |
| 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 = |
| driver::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); |
| |
| auto service_path = std::string(examples_i2c_temperature::Service::Name) + "/" + |
| component::kDefaultInstance + "/" + |
| examples_i2c_temperature::Service::Device::Name; |
| auto status = compat_context_->devfs_exporter().ExportSync( |
| service_path, compat_context_->TopologicalPath(name()), fuchsia_device_fs::ExportOptions()); |
| if (status != ZX_OK) { |
| FDF_SLOG(ERROR, "Failed to export to devfs.", KV("status", zx_status_get_string(status))); |
| node().reset(); |
| return; |
| } |
| } |
| |
| } // namespace i2c_temperature |
| |
| FUCHSIA_DRIVER_RECORD_CPP_V2(driver::Record<i2c_temperature::I2cTemperatureDriver>); |