blob: f6ffbfe138031750e706310da2156105994b3afb [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 "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>);