| // 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 |