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