blob: a48b7552473ee0bcaede2f05782cf87587fbe92f [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 "i2cutil2.h"
#include <span>
namespace {
zx_status_t execute_paginated(fidl::ClientEnd<fuchsia_hardware_i2c::Device>& client,
cpp20::span<i2cutil::TransactionData> transactions) {
if (transactions.size() > i2cutil::kMaxTransactionCount) {
return ZX_ERR_OUT_OF_RANGE;
}
fidl::Arena arena;
auto i2c_transactions =
fidl::VectorView<fuchsia_hardware_i2c::wire::Transaction>(arena, transactions.size());
for (size_t i = 0; i < transactions.size(); i++) {
switch (transactions[i].type) {
case i2cutil::TransactionType::Read: {
i2c_transactions[i] =
fuchsia_hardware_i2c::wire::Transaction::Builder(arena)
.data_transfer(fuchsia_hardware_i2c::wire::DataTransfer::WithReadSize(
static_cast<uint32_t>(transactions[i].count)))
.Build();
break;
}
case i2cutil::TransactionType::Write: {
auto write_data = fidl::VectorView<uint8_t>::FromExternal(transactions[i].bytes);
i2c_transactions[i] =
fuchsia_hardware_i2c::wire::Transaction::Builder(arena)
.data_transfer(
fuchsia_hardware_i2c::wire::DataTransfer::WithWriteData(arena, write_data))
.Build();
break;
}
}
}
// Execute the list of transactions.
const fidl::WireResult result = fidl::WireCall(client)->Transfer(i2c_transactions);
if (!result.ok()) {
fprintf(stderr, "i2cutil: error executing transaction: %s\n", result.status_string());
return result.status();
}
const fit::result response = result.value();
if (response.is_error()) {
fprintf(stderr, "i2cutil: error executing transaction: %d\n", response.error_value());
return response.error_value();
}
// Fill in any reads that were requested in the transaction list.
size_t read_txn_num = 0;
for (size_t i = 0; i < transactions.size(); i++) {
if (transactions[i].type == i2cutil::TransactionType::Read) {
std::copy(response->read_data[read_txn_num].begin(), response->read_data[read_txn_num].end(),
std::back_inserter(transactions[i].bytes));
if (transactions[i].bytes.size() != transactions[i].count) {
fprintf(stderr, "warning: requested %lu bytes, got %lu\n", transactions[i].count,
transactions[i].bytes.size());
}
read_txn_num++;
}
}
return ZX_OK;
}
} // namespace
namespace i2cutil {
zx_status_t execute(fidl::ClientEnd<fuchsia_hardware_i2c::Device> client,
std::vector<i2cutil::TransactionData>& transactions) {
for (size_t i = 0; i < transactions.size(); i += kMaxTransactionCount) {
const size_t start = i;
const size_t count = std::min(kMaxTransactionCount, transactions.size() - i);
zx_status_t result = execute_paginated(client, {transactions.data() + start, count});
if (result != ZX_OK) {
return result;
}
}
return ZX_OK;
}
} // namespace i2cutil