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