• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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