blob: 3c7b64c524c3b8596a86b84a5745262e6300ee54 [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_channel.h"
#include <endian.h>
namespace i2c_temperature {
zx::status<uint16_t> I2cChannel::Read16() {
uint16_t value;
auto status = WriteReadSync(nullptr, 0, reinterpret_cast<uint8_t*>(&value), sizeof(value));
if (status.is_error()) {
return status.take_error();
}
return zx::ok(be16toh(value));
}
zx::result<> I2cChannel::Write16(uint16_t value) {
value = htobe16(value);
return WriteReadSync(reinterpret_cast<uint8_t*>(&value), sizeof(value), nullptr, 0);
}
zx::result<> I2cChannel::WriteReadSync(const uint8_t* tx_buf, size_t tx_len, uint8_t* rx_buf,
size_t rx_len) {
if (tx_len > fuchsia_hardware_i2c::wire::kMaxTransferSize ||
rx_len > fuchsia_hardware_i2c::wire::kMaxTransferSize) {
return zx::error(ZX_ERR_OUT_OF_RANGE);
}
fidl::Arena arena;
fidl::VectorView<uint8_t> write_data(arena, tx_len);
if (tx_len) {
memcpy(write_data.data(), tx_buf, tx_len);
}
auto write_transfer = fuchsia_hardware_i2c::wire::DataTransfer::WithWriteData(arena, write_data);
auto read_transfer =
fuchsia_hardware_i2c::wire::DataTransfer::WithReadSize(static_cast<uint32_t>(rx_len));
fuchsia_hardware_i2c::wire::Transaction transactions[2];
size_t index = 0;
if (tx_len > 0) {
transactions[index++] = fuchsia_hardware_i2c::wire::Transaction::Builder(arena)
.data_transfer(write_transfer)
.Build();
}
if (rx_len > 0) {
transactions[index++] = fuchsia_hardware_i2c::wire::Transaction::Builder(arena)
.data_transfer(read_transfer)
.Build();
}
if (index == 0) {
return zx::error(ZX_ERR_INVALID_ARGS);
}
const auto reply = fidl_client_.sync()->Transfer(
fidl::VectorView<fuchsia_hardware_i2c::wire::Transaction>::FromExternal(transactions, index));
if (!reply.ok()) {
return zx::error(reply.status());
}
if (reply->is_error()) {
return zx::error(reply->error_value());
}
if (rx_len > 0) {
const auto& read_data = reply->value()->read_data;
// Truncate the returned buffer to match the behavior of the Banjo version.
if (read_data.count() != 1) {
return zx::error(ZX_ERR_IO);
}
memcpy(rx_buf, read_data[0].data(), std::min(rx_len, read_data[0].count()));
}
return zx::ok();
}
} // namespace i2c_temperature