xref: /aosp_15_r20/external/pigweed/pw_transfer/public/pw_transfer/handler.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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 <limits>
17 
18 #include "pw_assert/assert.h"
19 #include "pw_containers/intrusive_list.h"
20 #include "pw_status/status.h"
21 #include "pw_stream/stream.h"
22 #include "pw_transfer/internal/event.h"
23 
24 namespace pw::transfer {
25 namespace internal {
26 
27 class Context;
28 
29 }  // namespace internal
30 
31 // The Handler class is the base class for the transfer handler classes.
32 // Transfer handlers connect a transfer resource ID to a data stream, wrapped
33 // with initialization and cleanup procedures.
34 //
35 // Handlers use a stream::Reader or stream::Writer to do the reads and writes.
36 // They also provide optional Prepare and Finalize functions.
37 class Handler : public IntrusiveList<Handler>::Item {
38  public:
39   virtual ~Handler() = default;
40 
id()41   constexpr uint32_t id() const { return resource_id_; }
42 
43   // Called at the beginning of a read transfer. The stream::Reader must be
44   // ready to read after a successful PrepareRead() call. Returning a non-OK
45   // status aborts the read.
46   //
47   // Status::Unimplemented() indicates that reads are not supported.
48   virtual Status PrepareRead() = 0;
49 
50   // Called at the beginning of a non-zero read transfer. The stream::Reader
51   // must be ready to read at the given offset after a successful PrepareRead()
52   // call. Returning a non-OK status aborts the read.
53   // The read handler should verify that the offset is a valid read point for
54   // the resource.
55   //
56   // Status::Unimplemented() indicates that non-zero reads are not supported.
PrepareRead(uint32_t offset)57   virtual Status PrepareRead([[maybe_unused]] uint32_t offset) {
58     return Status::Unimplemented();
59   }
60 
61   // FinalizeRead() is called at the end of a read transfer. The status argument
62   // indicates whether the data transfer was successful or not.
FinalizeRead(Status)63   virtual void FinalizeRead(Status) {}
64 
65   // Called at the beginning of a write transfer. The stream::Writer must be
66   // ready to read after a successful PrepareRead() call. Returning a non-OK
67   // status aborts the write.
68   //
69   // Status::Unimplemented() indicates that writes are not supported.
70   virtual Status PrepareWrite() = 0;
71 
72   // Called at the beginning of a non-zero write transfer. The stream::writer
73   // must be ready to write at the given offset after a successful
74   // PrepareWrite() call. Returning a non-OK status aborts the write. The write
75   // handler should verify that the offset is a valid write point for the
76   // resource, and that the resource is prepared to write at that offset.
77   //
78   // Status::Unimplemented() indicates that non-zero writes are not supported.
PrepareWrite(uint32_t offset)79   virtual Status PrepareWrite([[maybe_unused]] uint32_t offset) {
80     return Status::Unimplemented();
81   }
82 
83   // FinalizeWrite() is called at the end of a write transfer. The status
84   // argument indicates whether the data transfer was successful or not.
85   //
86   // Returning an error signals that the transfer failed, even if it had
87   // succeeded up to this point.
FinalizeWrite(Status)88   virtual Status FinalizeWrite(Status) { return OkStatus(); }
89 
90   /// The total size of the transfer resource, if known. If unknown, returns
91   /// `std::numeric_limits<size_t>::max()`.
ResourceSize()92   virtual size_t ResourceSize() const {
93     return std::numeric_limits<size_t>::max();
94   }
95 
96   // GetStatus() is called to Transfer.GetResourceStatus RPC. The application
97   // layer invoking transfers should define the contents of these status
98   // variables for proper interpretation.
99   //
100   // Status::Unimplemented() indicates that the values have not been modifed by
101   // a handler.
GetStatus(uint64_t & readable_offset,uint64_t & writeable_offset,uint64_t & read_checksum,uint64_t & write_checksum)102   virtual Status GetStatus(uint64_t& readable_offset,
103                            uint64_t& writeable_offset,
104                            uint64_t& read_checksum,
105                            uint64_t& write_checksum) {
106     readable_offset = 0;
107     writeable_offset = 0;
108     read_checksum = 0;
109     write_checksum = 0;
110     return Status::Unimplemented();
111   }
112 
113  protected:
Handler(uint32_t resource_id,stream::Reader * reader)114   constexpr Handler(uint32_t resource_id, stream::Reader* reader)
115       : resource_id_(resource_id), reader_(reader) {}
116 
Handler(uint32_t resource_id,stream::Writer * writer)117   constexpr Handler(uint32_t resource_id, stream::Writer* writer)
118       : resource_id_(resource_id), writer_(writer) {}
119 
set_reader(stream::Reader & reader)120   void set_reader(stream::Reader& reader) { reader_ = &reader; }
set_writer(stream::Writer & writer)121   void set_writer(stream::Writer& writer) { writer_ = &writer; }
122 
123  private:
124   friend class internal::Context;
125 
126   // Prepares for either a read or write transfer.
127   Status Prepare(internal::TransferType type, uint32_t offset = 0) {
128     if (offset == 0) {
129       return type == internal::TransferType::kTransmit ? PrepareRead()
130                                                        : PrepareWrite();
131     }
132 
133     return type == internal::TransferType::kTransmit ? PrepareRead(offset)
134                                                      : PrepareWrite(offset);
135   }
136 
137   // Only valid after a PrepareRead() or PrepareWrite() call that returns OK.
stream()138   stream::Stream& stream() const {
139     PW_DASSERT(reader_ != nullptr);
140     return *reader_;
141   }
142 
143   uint32_t resource_id_;
144 
145   // Use a union to support constexpr construction.
146   union {
147     stream::Reader* reader_;
148     stream::Writer* writer_;
149   };
150 };
151 
152 class ReadOnlyHandler : public Handler {
153  public:
ReadOnlyHandler(uint32_t resource_id)154   constexpr ReadOnlyHandler(uint32_t resource_id)
155       : Handler(resource_id, static_cast<stream::Reader*>(nullptr)) {}
156 
ReadOnlyHandler(uint32_t resource_id,stream::Reader & reader)157   constexpr ReadOnlyHandler(uint32_t resource_id, stream::Reader& reader)
158       : Handler(resource_id, &reader) {}
159 
160   ~ReadOnlyHandler() override = default;
161 
PrepareRead()162   Status PrepareRead() override { return OkStatus(); }
163 
164   // Writes are not supported.
PrepareWrite()165   Status PrepareWrite() final { return Status::PermissionDenied(); }
166 
167   using Handler::set_reader;
168 
169  private:
170   using Handler::set_writer;
171 };
172 
173 class WriteOnlyHandler : public Handler {
174  public:
WriteOnlyHandler(uint32_t resource_id)175   constexpr WriteOnlyHandler(uint32_t resource_id)
176       : Handler(resource_id, static_cast<stream::Writer*>(nullptr)) {}
177 
WriteOnlyHandler(uint32_t resource_id,stream::Writer & writer)178   constexpr WriteOnlyHandler(uint32_t resource_id, stream::Writer& writer)
179       : Handler(resource_id, &writer) {}
180 
181   ~WriteOnlyHandler() override = default;
182 
183   // Reads are not supported.
PrepareRead()184   Status PrepareRead() final { return Status::PermissionDenied(); }
185 
PrepareWrite()186   Status PrepareWrite() override { return OkStatus(); }
187 
188   using Handler::set_writer;
189 
190  private:
191   using Handler::set_reader;
192 };
193 
194 class ReadWriteHandler : public Handler {
195  public:
ReadWriteHandler(uint32_t resource_id)196   constexpr ReadWriteHandler(uint32_t resource_id)
197       : Handler(resource_id, static_cast<stream::Reader*>(nullptr)) {}
ReadWriteHandler(uint32_t resource_id,stream::ReaderWriter & reader_writer)198   ReadWriteHandler(uint32_t resource_id, stream::ReaderWriter& reader_writer)
199       : Handler(resource_id, &static_cast<stream::Reader&>(reader_writer)) {}
200 
201   ~ReadWriteHandler() override = default;
202 
203   // Both reads and writes are supported.
PrepareRead()204   Status PrepareRead() override { return OkStatus(); }
PrepareWrite()205   Status PrepareWrite() override { return OkStatus(); }
206 
set_reader_writer(stream::ReaderWriter & reader_writer)207   void set_reader_writer(stream::ReaderWriter& reader_writer) {
208     set_reader(reader_writer);
209   }
210 };
211 
212 }  // namespace pw::transfer
213