| // 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 "da7219.h" |
| |
| #include <fidl/fuchsia.hardware.audio/cpp/wire.h> |
| #include <fidl/fuchsia.hardware.i2c/cpp/wire.h> |
| #include <lib/driver2/service_client.h> |
| |
| namespace { |
| |
| // FIDL server implementation for the `fuchsia.examples.audio/Codec` protocol |
| class Da7219Server : public fidl::WireServer<fuchsia_hardware_audio::Codec> { |
| public: |
| Da7219Server(driver::Logger& logger, std::weak_ptr<I2cChannel> i2c_channel) |
| : logger_(logger), i2c_channel_(i2c_channel) {} |
| |
| // Handle incoming connection requests from FIDL clients |
| static fidl::ServerBindingRef<fuchsia_hardware_audio::Codec> BindDeviceClient( |
| async_dispatcher_t* dispatcher, driver::Logger& logger, std::weak_ptr<I2cChannel> i2c_channel, |
| fidl::ServerEnd<fuchsia_hardware_audio::Codec> request) { |
| // Bind each connection request to a unique FIDL server instance |
| auto server_impl = std::make_unique<Da7219Server>(logger, i2c_channel); |
| return fidl::BindServer(dispatcher, std::move(request), std::move(server_impl), |
| std::mem_fn(&Da7219Server::OnUnbound)); |
| } |
| |
| // This method is called when a server connection is torn down. |
| void OnUnbound(fidl::UnbindInfo info, fidl::ServerEnd<fuchsia_hardware_audio::Codec> server_end) { |
| if (info.is_peer_closed()) { |
| FDF_LOG(DEBUG, "Client disconnected"); |
| } else if (!info.is_user_initiated()) { |
| FDF_LOG(ERROR, "Client connection unbound: %s", info.status_string()); |
| } |
| } |
| |
| // LLCPP implementation for the Codec API. |
| void Reset(ResetCompleter::Sync& completer) override {} |
| void Stop(StopCompleter::Sync& completer) override {} |
| void Start(StartCompleter::Sync& completer) override {} |
| void GetInfo(GetInfoCompleter::Sync& completer) override {} |
| void GetHealthState(GetHealthStateCompleter::Sync& completer) override {} |
| void IsBridgeable(IsBridgeableCompleter::Sync& completer) override {} |
| void SetBridgedMode(SetBridgedModeRequestView request, |
| SetBridgedModeCompleter::Sync& completer) override {} |
| void GetDaiFormats(GetDaiFormatsCompleter::Sync& completer) override {} |
| void SetDaiFormat(SetDaiFormatRequestView request, |
| SetDaiFormatCompleter::Sync& completer) override {} |
| void GetPlugDetectCapabilities(GetPlugDetectCapabilitiesCompleter::Sync& completer) override {} |
| void WatchPlugState(WatchPlugStateCompleter::Sync& completer) override {} |
| void SignalProcessingConnect(SignalProcessingConnectRequestView request, |
| SignalProcessingConnectCompleter::Sync& completer) override {} |
| |
| private: |
| driver::Logger& logger_; |
| std::weak_ptr<I2cChannel> i2c_channel_; |
| }; |
| |
| } // namespace |
| |
| namespace audio { |
| |
| zx::result<> Da7219Driver::Start() { |
| auto channel_result = SetupI2cChannel(); |
| if (channel_result.is_error()) { |
| return channel_result.take_error(); |
| } |
| |
| // Serve the fuchsia.hardware.audio/Codec protocol to clients through the |
| // fuchsia.hardware.audio/CodecService wrapper. |
| driver::ServiceInstanceHandler handler; |
| fuchsia_hardware_audio::CodecService::Handler service(&handler); |
| |
| auto result = |
| service.add_codec([this](fidl::ServerEnd<fuchsia_hardware_audio::Codec> request) -> void { |
| Da7219Server::BindDeviceClient(dispatcher(), logger_, i2c_channel_, std::move(request)); |
| }); |
| ZX_ASSERT(result.is_ok()); |
| |
| result = |
| context().outgoing()->AddService<fuchsia_hardware_audio::CodecService>(std::move(handler)); |
| if (result.is_error()) { |
| FDF_SLOG(ERROR, "Failed to add service", KV("status", result.status_string())); |
| return result.take_error(); |
| } |
| |
| // Test write and read by sending arbitrary values. |
| constexpr uint8_t kTestArbitraryAddress0 = 34; |
| constexpr uint8_t kTestArbitraryDataToWrite0 = 56; |
| constexpr uint8_t kTestArbitraryAddress1 = 78; |
| auto write_status = i2c_channel_->Write(kTestArbitraryAddress0, kTestArbitraryDataToWrite0); |
| if (write_status.is_error()) { |
| FDF_SLOG(ERROR, "Failed to write to I2C", KV("status", write_status.status_string())); |
| return write_status.take_error(); |
| } |
| auto i2c_read = i2c_channel_->Read(kTestArbitraryAddress1); |
| if (i2c_read.is_error()) { |
| FDF_SLOG(ERROR, "Failed to read from I2C", KV("status", i2c_read.status_string())); |
| return i2c_read.take_error(); |
| } |
| FDF_SLOG(INFO, "Read", KV("byte", static_cast<int>(i2c_read.value()))); |
| |
| FDF_SLOG(INFO, "Started"); |
| |
| return zx::ok(); |
| } |
| |
| // Connect to the `fuchsia.hardware.i2c/Device` protocol offered by the parent device node. |
| zx::result<> Da7219Driver::SetupI2cChannel() { |
| auto client_endpoint = |
| driver::Connect<fuchsia_hardware_i2c::Service::Device>(*context().incoming(), "default"); |
| 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(); |
| } |
| |
| } // namespace audio |
| |
| FUCHSIA_DRIVER_RECORD_CPP_V2(driver::Record<audio::Da7219Driver>); |