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