• 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 <cstddef>
17 #include <cstdint>
18 #include <limits>
19 
20 #include "pw_bytes/span.h"
21 #include "pw_transfer/handler.h"
22 #include "pw_transfer/internal/config.h"
23 #include "pw_transfer/internal/server_context.h"
24 #include "pw_transfer/transfer.raw_rpc.pb.h"
25 #include "pw_transfer/transfer_thread.h"
26 
27 namespace pw::transfer {
28 namespace internal {
29 
30 struct Chunk;
31 
32 }  // namespace internal
33 
34 class TransferService : public pw_rpc::raw::Transfer::Service<TransferService> {
35  public:
36   // Initializes a TransferService that can be registered with an RPC server.
37   //
38   // The transfer service requires a work queue to perform deferred tasks, such
39   // as handling transfer timeouts and retries. This work queue does not need to
40   // be unique to the transfer service; it may be shared with other parts of the
41   // system.
42   //
43   // The provided buffer is used to stage data from transfer chunks before it is
44   // written out to the writer. The size of this buffer is the largest amount of
45   // data that can be sent in a single transfer chunk, excluding any transport
46   // layer overhead.
47   //
48   // max_pending_bytes is the maximum amount of data to ask for at a
49   // time during a write transfer, unless told a more restrictive amount by a
50   // transfer handler. This size can span multiple chunks. A larger value
51   // generally increases the efficiency of write transfers when sent over a
52   // reliable transport. However, if the underlying transport is unreliable,
53   // larger values could slow down a transfer in the event of repeated packet
54   // loss.
55   TransferService(
56       TransferThread& transfer_thread,
57       uint32_t max_pending_bytes,
58       chrono::SystemClock::duration chunk_timeout = cfg::kDefaultChunkTimeout,
59       uint8_t max_retries = cfg::kDefaultMaxRetries,
60       uint32_t extend_window_divisor = cfg::kDefaultExtendWindowDivisor)
61       : max_parameters_(max_pending_bytes,
62                         transfer_thread.max_chunk_size(),
63                         extend_window_divisor),
64         thread_(transfer_thread),
65         chunk_timeout_(chunk_timeout),
66         max_retries_(max_retries) {}
67 
68   TransferService(const TransferService&) = delete;
69   TransferService(TransferService&&) = delete;
70 
71   TransferService& operator=(const TransferService&) = delete;
72   TransferService& operator=(TransferService&&) = delete;
73 
Read(RawServerReaderWriter & reader_writer)74   void Read(RawServerReaderWriter& reader_writer) {
75     reader_writer.set_on_next([this](ConstByteSpan message) {
76       HandleChunk(message, internal::TransferType::kTransmit);
77     });
78     thread_.SetServerReadStream(reader_writer);
79   }
80 
Write(RawServerReaderWriter & reader_writer)81   void Write(RawServerReaderWriter& reader_writer) {
82     reader_writer.set_on_next([this](ConstByteSpan message) {
83       HandleChunk(message, internal::TransferType::kReceive);
84     });
85     thread_.SetServerWriteStream(reader_writer);
86   }
87 
RegisterHandler(internal::Handler & handler)88   void RegisterHandler(internal::Handler& handler) {
89     thread_.AddTransferHandler(handler);
90   }
91 
set_max_pending_bytes(uint32_t max_pending_bytes)92   void set_max_pending_bytes(uint32_t max_pending_bytes) {
93     max_parameters_.set_pending_bytes(max_pending_bytes);
94   }
95 
96   // Sets the maximum size for the data in a pw_transfer chunk. Note that the
97   // max chunk size must always fit within the transfer thread's chunk buffer.
set_max_chunk_size_bytes(uint32_t max_chunk_size_bytes)98   void set_max_chunk_size_bytes(uint32_t max_chunk_size_bytes) {
99     max_parameters_.set_max_chunk_size_bytes(max_chunk_size_bytes);
100   }
101 
UnregisterHandler(internal::Handler & handler)102   void UnregisterHandler(internal::Handler& handler) {
103     thread_.RemoveTransferHandler(handler);
104   }
105 
set_chunk_timeout(chrono::SystemClock::duration chunk_timeout)106   void set_chunk_timeout(chrono::SystemClock::duration chunk_timeout) {
107     chunk_timeout_ = chunk_timeout;
108   }
109 
set_max_retries(uint8_t max_retries)110   void set_max_retries(uint8_t max_retries) { max_retries_ = max_retries; }
111 
set_extend_window_divisor(uint32_t extend_window_divisor)112   Status set_extend_window_divisor(uint32_t extend_window_divisor) {
113     if (extend_window_divisor <= 1) {
114       return Status::InvalidArgument();
115     }
116 
117     max_parameters_.set_extend_window_divisor(extend_window_divisor);
118     return OkStatus();
119   }
120 
121  private:
122   void HandleChunk(ConstByteSpan message, internal::TransferType type);
123 
124   internal::TransferParameters max_parameters_;
125   TransferThread& thread_;
126 
127   chrono::SystemClock::duration chunk_timeout_;
128   uint8_t max_retries_;
129 };
130 
131 }  // namespace pw::transfer
132