1 // Copyright 2022 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <array> 17 18 #include "pw_function/function.h" 19 #include "pw_status/status.h" 20 #include "pw_stream/stream.h" 21 #include "pw_transfer/internal/client_context.h" 22 #include "pw_transfer/internal/config.h" 23 #include "pw_transfer/transfer.raw_rpc.pb.h" 24 #include "pw_transfer/transfer_thread.h" 25 26 namespace pw::transfer { 27 28 class Client { 29 public: 30 using CompletionFunc = Function<void(Status)>; 31 32 // Initializes a transfer client on a specified RPC client and channel. 33 // Transfers are processed on a work queue so as not to block any RPC threads. 34 // The work queue does not have to be unique to the transfer client; it can be 35 // shared with other modules (including additional transfer clients). 36 // 37 // As data is processed within the work queue's context, the original RPC 38 // messages received by the transfer service are not available. Therefore, 39 // the transfer client requires an additional buffer where transfer data can 40 // stored during the context switch. 41 // 42 // The size of this buffer is the largest amount of bytes that can be sent 43 // within a single transfer chunk (read or write), excluding any transport 44 // layer overhead. Not all of this size is used to send data -- there is 45 // additional overhead in the pw_rpc and pw_transfer protocols (typically 46 // ~22B/chunk). 47 // 48 // An optional max_bytes_to_receive argument can be provided to set the 49 // default number of data bytes the client will request from the server at a 50 // time. If not provided, this defaults to the size of the data buffer. A 51 // larger value can make transfers more efficient as it minimizes the 52 // back-and-forth between client and server; however, it also increases the 53 // impact of packet loss, potentially requiring larger retransmissions to 54 // recover. 55 Client(rpc::Client& rpc_client, 56 uint32_t channel_id, 57 TransferThread& transfer_thread, 58 size_t max_bytes_to_receive = 0, 59 uint32_t extend_window_divisor = cfg::kDefaultExtendWindowDivisor) client_(rpc_client,channel_id)60 : client_(rpc_client, channel_id), 61 transfer_thread_(transfer_thread), 62 max_parameters_(max_bytes_to_receive > 0 63 ? max_bytes_to_receive 64 : transfer_thread.max_chunk_size(), 65 transfer_thread.max_chunk_size(), 66 extend_window_divisor), 67 has_read_stream_(false), 68 has_write_stream_(false) {} 69 70 // Begins a new read transfer for the given transfer ID. The data read from 71 // the server is written to the provided writer. Returns OK if the transfer is 72 // successfully started. When the transfer finishes (successfully or not), the 73 // completion callback is invoked with the overall status. 74 Status Read( 75 uint32_t transfer_id, 76 stream::Writer& output, 77 CompletionFunc&& on_completion, 78 chrono::SystemClock::duration timeout = cfg::kDefaultChunkTimeout); 79 80 // Begins a new write transfer for the given transfer ID. Data from the 81 // provided reader is sent to the server. When the transfer finishes 82 // (successfully or not), the completion callback is invoked with the overall 83 // status. 84 Status Write( 85 uint32_t transfer_id, 86 stream::Reader& input, 87 CompletionFunc&& on_completion, 88 chrono::SystemClock::duration timeout = cfg::kDefaultChunkTimeout); 89 set_extend_window_divisor(uint32_t extend_window_divisor)90 Status set_extend_window_divisor(uint32_t extend_window_divisor) { 91 if (extend_window_divisor <= 1) { 92 return Status::InvalidArgument(); 93 } 94 95 max_parameters_.set_extend_window_divisor(extend_window_divisor); 96 return OkStatus(); 97 } 98 99 private: 100 using Transfer = pw_rpc::raw::Transfer; 101 102 void OnRpcError(Status status, internal::TransferType type); 103 104 Transfer::Client client_; 105 TransferThread& transfer_thread_; 106 internal::TransferParameters max_parameters_; 107 108 bool has_read_stream_; 109 bool has_write_stream_; 110 }; 111 112 } // namespace pw::transfer 113