blob: 909f593d83ea7f182689cd4f8702b2b2d44005db [file] [log] [blame]
Wyatt Hepler1e636732021-06-14 18:30:13 -07001.. _module-pw_transfer:
2
3===========
4pw_transfer
5===========
6
7.. attention::
8
9 ``pw_transfer`` is under construction and so is its documentation.
10
Alexei Frolov0c94fc22021-07-08 16:05:24 -070011-----
12Usage
13-----
14
Alexei Frolovf93cb262021-07-14 16:05:15 -070015C++
16===
17The transfer service is defined and registered with an RPC server like any other
18RPC service.
19
20To know how to read data from or write data to device, a ``TransferHandler``
21interface is defined (``pw_transfer/public/pw_transfer/handler.h``). Transfer
22handlers wrap a stream reader and/or writer with initialization and completion
23code. Custom transfer handler implementations should derive from
24``ReadOnlyHandler``, ``WriteOnlyHandler``, or ``ReadWriteHandler`` as
25appropriate and override Prepare and Finalize methods if necessary.
26
27A transfer handler should be implemented and instantiated for each unique data
28transfer to or from a device. These handlers are then registered with the
29transfer service using their transfer IDs.
30
31**Example**
32
33.. code-block:: cpp
34
35 #include "pw_transfer/transfer.h"
36
37 namespace {
38
39 // Simple transfer handler which reads data from an in-memory buffer.
40 class SimpleBufferReadHandler : public pw::transfer::ReadOnlyHandler {
41 public:
42 SimpleReadTransfer(uint32_t transfer_id, pw::ConstByteSpan data)
43 : ReadOnlyHandler(transfer_id), reader_(data) {
44 set_reader(reader_);
45 }
46
47 private:
48 pw::stream::MemoryReader reader_;
49 };
50
Alexei Frolov563946f2021-08-05 18:58:48 -070051 // The maximum amount of data that can be sent in a single chunk, excluding
52 // transport layer overhead.
53 constexpr size_t kMaxChunkSizeBytes = 256;
54
55 // In a write transfer, the maximum number of bytes to receive at one time,
56 // (potentially across multiple chunks), unless specified otherwise by the
57 // transfer handler's stream::Writer.
58 constexpr size_t kDefaultMaxBytesToReceive = 1024;
59
Alexei Frolovf93cb262021-07-14 16:05:15 -070060 // Instantiate a static transfer service.
Alexei Frolov563946f2021-08-05 18:58:48 -070061 pw::transfer::TransferService transfer_service(
62 kMaxChunkSizeBytes, kDefaultMaxBytesToReceive);
Alexei Frolovf93cb262021-07-14 16:05:15 -070063
64 // Instantiate a handler for the the data to be transferred.
65 constexpr uint32_t kBufferTransferId = 1;
66 char buffer_to_transfer[256] = { /* ... */ };
67 SimpleBufferReadHandler buffer_handler(kBufferTransferId, buffer_to_transfer);
68
69 } // namespace
70
71 void InitTransfer() {
72 // Register the handler with the transfer service, then the transfer service
73 // with an RPC server.
74 transfer_service.RegisterHandler(buffer_handler);
75 GetSystemRpcServer().RegisterService(transfer_service);
76 }
77
Alexei Frolov0c94fc22021-07-08 16:05:24 -070078Python
79======
80.. automodule:: pw_transfer.transfer
81 :members: Manager, Error
82
83**Example**
84
85.. code-block:: python
86
87 from pw_transfer import transfer
88
89 # Initialize a Pigweed RPC client; see pw_rpc docs for more info.
90 rpc_client = CustomRpcClient()
91 rpcs = rpc_client.channel(1).rpcs
92
93 transfer_service = rpcs.pw.transfer.Transfer
94 transfer_manager = transfer.Manager(transfer_service)
95
96 try:
97 # Read transfer_id 3 from the server.
98 data = transfer_manager.read(3)
99 except transfer.Error as err:
100 print('Failed to read:', err.status)
101
102 try:
103 # Send some data to the server. The transfer manager does not have to be
104 # reinitialized.
105 transfer_manager.write(2, b'hello, world')
106 except transfer.Error as err:
107 print('Failed to write:', err.status)
108
Wyatt Hepler1e636732021-06-14 18:30:13 -0700109--------
110Protocol
111--------
112
113Protocol buffer definition
114==========================
115.. literalinclude:: transfer.proto
116 :language: protobuf
117 :lines: 14-
118
119Server to client transfer (read)
120================================
121.. seqdiag::
122 :scale: 110
123
124 seqdiag {
125 default_note_color = aliceblue;
126
127 client -> server [
128 label = "set transfer parameters",
129 leftnote = "transfer_id\noffset\npending_bytes\nmax_chunk_size\nchunk_delay"
130 ];
131
132 client <-- server [
133 noactivate,
134 label = "requested bytes\n(zero or more chunks)",
Alexei Frolov41cd2502021-07-08 16:03:36 -0700135 rightnote = "transfer_id\noffset\ndata\n(remaining_bytes)"
Wyatt Hepler1e636732021-06-14 18:30:13 -0700136 ];
137
138 client --> server [
139 noactivate,
140 label = "update transfer parameters\n(as needed)",
Alexei Frolov41cd2502021-07-08 16:03:36 -0700141 leftnote = "transfer_id\noffset\npending_bytes\n(max_chunk_size)\n(chunk_delay)"
Wyatt Hepler1e636732021-06-14 18:30:13 -0700142 ];
143
144 client <- server [
145 noactivate,
146 label = "final chunk",
Alexei Frolov41cd2502021-07-08 16:03:36 -0700147 rightnote = "transfer_id\noffset\ndata\nremaining_bytes=0"
Wyatt Hepler1e636732021-06-14 18:30:13 -0700148 ];
149
150 client -> server [
151 noactivate,
Alexei Frolov41cd2502021-07-08 16:03:36 -0700152 label = "acknowledge completion",
153 leftnote = "transfer_id\nstatus=OK"
Wyatt Hepler1e636732021-06-14 18:30:13 -0700154 ];
155 }
156
157Client to server transfer (write)
158=================================
159.. seqdiag::
160 :scale: 110
161
162 seqdiag {
163 default_note_color = aliceblue;
164
165 client -> server [
166 label = "start",
167 leftnote = "transfer_id"
168 ];
169
170 client <- server [
171 noactivate,
172 label = "set transfer parameters",
Alexei Frolov41cd2502021-07-08 16:03:36 -0700173 rightnote = "transfer_id\noffset\npending_bytes\nmax_chunk_size\nchunk_delay"
Wyatt Hepler1e636732021-06-14 18:30:13 -0700174 ];
175
176 client --> server [
177 noactivate,
178 label = "requested bytes\n(zero or more chunks)",
Alexei Frolov41cd2502021-07-08 16:03:36 -0700179 leftnote = "transfer_id\noffset\ndata\n(remaining_bytes)"
Wyatt Hepler1e636732021-06-14 18:30:13 -0700180 ];
181
182 client <-- server [
183 noactivate,
184 label = "update transfer parameters\n(as needed)",
Alexei Frolov41cd2502021-07-08 16:03:36 -0700185 rightnote = "transfer_id\noffset\npending_bytes\n(max_chunk_size)\n(chunk_delay)"
Wyatt Hepler1e636732021-06-14 18:30:13 -0700186 ];
187
188 client -> server [
189 noactivate,
190 label = "final chunk",
Alexei Frolov41cd2502021-07-08 16:03:36 -0700191 leftnote = "transfer_id\noffset\ndata\nremaining_bytes=0"
Wyatt Hepler1e636732021-06-14 18:30:13 -0700192 ];
193
194 client <- server [
Alexei Frolov41cd2502021-07-08 16:03:36 -0700195 noactivate,
196 label = "acknowledge completion",
197 rightnote = "transfer_id\nstatus=OK"
Wyatt Hepler1e636732021-06-14 18:30:13 -0700198 ];
199 }
200
Alexei Frolov41cd2502021-07-08 16:03:36 -0700201Errors
202======
203At any point, either the client or server may terminate the transfer by sending
204an error chunk with the transfer ID and a non-OK status.
205
Wyatt Hepler1e636732021-06-14 18:30:13 -0700206Transmitter flow
207================
208.. mermaid::
209
210 graph TD
211 start([Client initiates<br>transfer]) -->data_request
212 data_request[Receive transfer<br>parameters]-->send_chunk
213
214 send_chunk[Send chunk]-->sent_all
215
216 sent_all{Sent final<br>chunk?} -->|yes|wait
217 sent_all-->|no|sent_requested
218
219 sent_requested{Sent all<br>pending?}-->|yes|data_request
220 sent_requested-->|no|send_chunk
221
222 wait[Wait for receiver]-->is_done
223
224 is_done{Received<br>final chunk?}-->|yes|done
225 is_done-->|no|data_request
226
227 done([Transfer complete])
228
229Receiver flow
230=============
231.. mermaid::
232
233 graph TD
234 start([Client initiates<br>transfer]) -->request_bytes
235 request_bytes[Set transfer<br>parameters]-->wait
236
237 wait[Wait for chunk]-->received_chunk
238
239 received_chunk{Received<br>chunk by<br>deadline?}-->|no|request_bytes
240 received_chunk-->|yes|check_chunk
241
242 check_chunk{Correct<br>offset?} -->|yes|process_chunk
243 check_chunk --> |no|request_bytes
244
245 process_chunk[Process chunk]-->final_chunk
246
247 final_chunk{Final<br>chunk?}-->|yes|signal_completion
248 final_chunk{Final<br>chunk?}-->|no|received_requested
249
250 received_requested{Received all<br>pending?}-->|yes|request_bytes
251 received_requested-->|no|wait
252
253 signal_completion[Signal completion]-->done
254
255 done([Transfer complete])