// 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 { uint32_t Context::MaxWriteChunkSize(uint32_t max_chunk_size_bytes, uint32_t channel_id) const { // 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); // TODO(frolv): Temporarily add 5 bytes for the new call_id change. The RPC // overhead calculation will be moved into an RPC helper to avoid having // pw_transfer depend on RPC internals. max_size -= 5; // 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 = offset() + pending_bytes(); max_size -= 3; max_size -= varint::EncodedSize(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