third_party.pigweed.src/pw_transfer/context.cc
Alexei Frolov ff057e8ff9 pw_transfer: Start C++ client
This starts an implementation of a C++ transfer client suitable for
device to device transfers. Both read and write transfer support is
added. The code is incomplete and untested; pw_rpc raw clients are
required before this can be functional.

Change-Id: I17154c50986f7de8027fbc4e0143e86e3c64dd64
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/61792
Commit-Queue: Alexei Frolov <frolv@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
2021-09-28 00:16:04 +00:00

73 lines
2.7 KiB
C++

// Copyright 2021 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_transfer/internal/context.h"
#include "pw_assert/check.h"
#include "pw_status/try.h"
#include "pw_varint/varint.h"
namespace pw::transfer::internal {
size_t MaxWriteChunkSize(const Context& transfer,
size_t max_chunk_size_bytes,
uint32_t channel_id) {
// Start with the user-provided maximum chunk size, which should be the usable
// payload length on the RPC ingress path after any transport overhead.
ssize_t max_size = max_chunk_size_bytes;
// Subtract the RPC overhead (pw_rpc/internal/packet.proto).
//
// type: 1 byte key, 1 byte value (CLIENT_STREAM)
// channel_id: 1 byte key, varint value (calculate from stream)
// service_id: 1 byte key, 4 byte value
// method_id: 1 byte key, 4 byte value
// payload: 1 byte key, varint length (remaining space)
// status: 0 bytes (not set in stream packets)
//
// TOTAL: 14 bytes + encoded channel_id size + encoded payload length
//
max_size -= 14;
max_size -= varint::EncodedSize(channel_id);
max_size -= varint::EncodedSize(max_size);
// Subtract the transfer service overhead for a client write chunk
// (pw_transfer/transfer.proto).
//
// transfer_id: 1 byte key, varint value (calculate)
// offset: 1 byte key, varint value (calculate)
// data: 1 byte key, varint length (remaining space)
//
// TOTAL: 3 + encoded transfer_id + encoded offset + encoded data length
//
size_t max_offset_in_window = transfer.offset() + transfer.pending_bytes();
max_size -= 3;
max_size -= varint::EncodedSize(transfer.transfer_id());
max_size -= varint::EncodedSize(max_offset_in_window);
max_size -= varint::EncodedSize(max_size);
// A resulting value of zero (or less) renders write transfers unusable, as
// there is no space to send any payload. This should be considered a
// programmer error in the transfer service setup.
PW_CHECK_INT_GT(
max_size,
0,
"Transfer service maximum chunk size is too small to fit a payload. "
"Increase max_chunk_size_bytes to support write transfers.");
return max_size;
}
} // namespace pw::transfer::internal