blob: a1fdf1528dfafa37ad0b91ead76bb86ba9ccb504 [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"
namespace {
// FIDL server implementation for the `fuchsia.examples.audio/Device` protocol
class Da7219Server : public fidl::WireServer<fuchsia_hardware_audio::Codec> {
public:
explicit Da7219Server(driver::Namespace& ns, async_dispatcher_t* dispatcher,
std::weak_ptr<I2cChannel> i2c_channel)
: i2c_channel_(i2c_channel) {
auto logger_result = driver::Logger::Create(ns, dispatcher, "da7219-server");
ZX_ASSERT(logger_result.is_ok());
logger_ = std::move(*logger_result);
}
// Handle incoming connection requests from FIDL clients
static fidl::ServerBindingRef<fuchsia_hardware_audio::Codec> BindDeviceClient(
driver::Namespace& ns, async_dispatcher_t* dispatcher, 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>(ns, dispatcher, 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 {
// static
zx::status<std::unique_ptr<Da7219Driver>> Da7219Driver::Start(
fuchsia_driver_framework::wire::DriverStartArgs& start_args, fdf::UnownedDispatcher dispatcher,
fidl::WireSharedClient<fuchsia_driver_framework::Node> node, driver::Namespace ns,
driver::Logger logger) {
auto driver = std::make_unique<Da7219Driver>(dispatcher->async_dispatcher(), std::move(node),
std::move(ns), std::move(logger));
auto result = driver->Run(std::move(start_args.outgoing_dir()));
if (result.is_error()) {
return result.take_error();
}
return zx::ok(std::move(driver));
}
zx::status<> Da7219Driver::Run(fidl::ServerEnd<fuchsia_io::Directory> outgoing_dir) {
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.
component::ServiceHandler handler;
fuchsia_hardware_audio::CodecService::Handler service(&handler);
auto result =
service.add_codec([this](fidl::ServerEnd<fuchsia_hardware_audio::Codec> request) -> void {
Da7219Server::BindDeviceClient(ns_, dispatcher_, i2c_channel_, std::move(request));
});
ZX_ASSERT(result.is_ok());
result = 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();
}
auto status = outgoing_.Serve(std::move(outgoing_dir));
if (status.is_error()) {
FDF_SLOG(ERROR, "Failed to serve outgoing directory", KV("status", status.status_string()));
return status.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::status<> Da7219Driver::SetupI2cChannel() {
auto client_endpoint = ns_.Connect<fuchsia_hardware_i2c::Device>();
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_V1(audio::Da7219Driver);