blob: ca3c0a34784ae4a8151be1d7b63ba834a4cc1b1a [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 "i2c_server.h"
#include <lib/driver2/structured_logger.h>
namespace test_i2c_controller {
// Static
// Handle incoming connection requests from FIDL clients
fidl::ServerBindingRef<fuchsia_hardware_i2c::Device> I2cDeviceServer::BindDeviceClient(
std::shared_ptr<I2cDeviceServer> server_impl, async_dispatcher_t* dispatcher,
fidl::ServerEnd<fuchsia_hardware_i2c::Device> request) {
// Bind each connection request to the shared instance.
return fidl::BindServer(dispatcher, std::move(request), server_impl,
std::mem_fn(&I2cDeviceServer::OnUnbound));
}
// This method is called when a server connection is torn down.
void I2cDeviceServer::OnUnbound(fidl::UnbindInfo info,
fidl::ServerEnd<fuchsia_hardware_i2c::Device> 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());
}
}
// Protocol method of `fuchsia.hardware.i2c.Device` to handle data transfer requests.
void I2cDeviceServer::Transfer(TransferRequestView request, TransferCompleter::Sync& completer) {
FDF_SLOG(DEBUG, "Received transfer request");
// Must be either a write transfer (2 bytes write) or
// a read transfer (1 byte write and 1 byte read).
if (request->transactions.count() == 1) { // Write transfer.
ZX_ASSERT(request->transactions[0].has_data_transfer());
const auto& transfer = request->transactions[0].data_transfer();
ZX_ASSERT(transfer.is_write_data() && !transfer.is_read_size());
ZX_ASSERT(transfer.write_data().count() == 2);
FDF_SLOG(INFO, "Received write", KV("address", static_cast<int>(transfer.write_data()[0])));
FDF_SLOG(INFO, "Received write", KV("data", static_cast<int>(transfer.write_data()[1])));
completer.ReplySuccess({});
} else if (request->transactions.count() == 2) { // Read transfer.
ZX_ASSERT(request->transactions[0].has_data_transfer());
const auto& transfer0 = request->transactions[0].data_transfer();
ZX_ASSERT(transfer0.is_write_data() && !transfer0.is_read_size());
ZX_ASSERT(transfer0.write_data().count() == 1);
FDF_SLOG(INFO, "Received write", KV("address", static_cast<int>(transfer0.write_data()[0])));
const auto& transfer1 = request->transactions[1].data_transfer();
ZX_ASSERT(!transfer1.is_write_data() && transfer1.is_read_size());
ZX_ASSERT(transfer1.read_size() == 1);
fidl::Arena allocator;
auto read_bytes = fidl::VectorView<uint8_t>(allocator, 1);
// Test read by sending arbitrary values.
constexpr uint8_t kTestArbitraryDataToRead = 12;
read_bytes[0] = kTestArbitraryDataToRead;
FDF_SLOG(INFO, "Read data to send", KV("data", static_cast<int>(read_bytes[0])));
auto read_results = fidl::VectorView<fidl::VectorView<uint8_t>>(allocator, 1);
read_results[0] = read_bytes;
completer.ReplySuccess(read_results);
} else {
completer.ReplyError(ZX_ERR_INVALID_ARGS);
}
}
} // namespace test_i2c_controller