blob: bf6630a5b7a9c8d101ff1b0359f991e0b2968c58 [file] [log] [blame]
// Copyright 2022 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#pragma once
#include "pw_assert/assert.h"
#include "pw_containers/intrusive_list.h"
#include "pw_status/status.h"
#include "pw_stream/stream.h"
#include "pw_transfer/internal/event.h"
namespace pw::transfer {
namespace internal {
// The internal::Handler class is the base class for the transfer handler
// classes. Transfer handlers connect a transfer resource ID to the functions
// that do the actual reads and/or writes.
//
// Handlers use a stream::Reader or stream::Writer to do the reads and writes.
// They also provide optional Prepare and Finalize functions.
class Handler : public IntrusiveList<Handler>::Item {
public:
virtual ~Handler() = default;
constexpr uint32_t id() const { return resource_id_; }
// Called at the beginning of a read transfer. The stream::Reader must be
// ready to read after a successful PrepareRead() call. Returning a non-OK
// status aborts the read.
//
// Status::Unimplemented() indicates that reads are not supported.
virtual Status PrepareRead() = 0;
// FinalizeRead() is called at the end of a read transfer. The status argument
// indicates whether the data transfer was successful or not.
virtual void FinalizeRead(Status) {}
// Called at the beginning of a write transfer. The stream::Writer must be
// ready to read after a successful PrepareRead() call. Returning a non-OK
// status aborts the write.
//
// Status::Unimplemented() indicates that writes are not supported.
virtual Status PrepareWrite() = 0;
// FinalizeWrite() is called at the end of a write transfer. The status
// argument indicates whether the data transfer was successful or not.
//
// Returning an error signals that the transfer failed, even if it had
// succeeded up to this point.
virtual Status FinalizeWrite(Status) { return OkStatus(); }
protected:
constexpr Handler(uint32_t resource_id, stream::Reader* reader)
: resource_id_(resource_id), reader_(reader) {}
constexpr Handler(uint32_t resource_id, stream::Writer* writer)
: resource_id_(resource_id), writer_(writer) {}
void set_reader(stream::Reader& reader) { reader_ = &reader; }
void set_writer(stream::Writer& writer) { writer_ = &writer; }
private:
friend class Context;
// Prepares for either a read or write transfer.
Status Prepare(internal::TransferType type) {
return type == internal::TransferType::kTransmit ? PrepareRead()
: PrepareWrite();
}
// Only valid after a PrepareRead() or PrepareWrite() call that returns OK.
stream::Stream& stream() const {
PW_DASSERT(reader_ != nullptr);
return *reader_;
}
uint32_t resource_id_;
// Use a union to support constexpr construction.
union {
stream::Reader* reader_;
stream::Writer* writer_;
};
};
} // namespace internal
class ReadOnlyHandler : public internal::Handler {
public:
constexpr ReadOnlyHandler(uint32_t resource_id)
: internal::Handler(resource_id, static_cast<stream::Reader*>(nullptr)) {}
constexpr ReadOnlyHandler(uint32_t resource_id, stream::Reader& reader)
: internal::Handler(resource_id, &reader) {}
~ReadOnlyHandler() override = default;
Status PrepareRead() override { return OkStatus(); }
// Writes are not supported.
Status PrepareWrite() final { return Status::PermissionDenied(); }
using internal::Handler::set_reader;
private:
using internal::Handler::set_writer;
};
class WriteOnlyHandler : public internal::Handler {
public:
constexpr WriteOnlyHandler(uint32_t resource_id)
: internal::Handler(resource_id, static_cast<stream::Writer*>(nullptr)) {}
constexpr WriteOnlyHandler(uint32_t resource_id, stream::Writer& writer)
: internal::Handler(resource_id, &writer) {}
~WriteOnlyHandler() override = default;
// Reads are not supported.
Status PrepareRead() final { return Status::PermissionDenied(); }
Status PrepareWrite() override { return OkStatus(); }
using internal::Handler::set_writer;
private:
using internal::Handler::set_reader;
};
class ReadWriteHandler : public internal::Handler {
public:
constexpr ReadWriteHandler(uint32_t resource_id)
: internal::Handler(resource_id, static_cast<stream::Reader*>(nullptr)) {}
constexpr ReadWriteHandler(uint32_t resource_id,
stream::ReaderWriter& reader_writer)
: internal::Handler(resource_id,
&static_cast<stream::Reader&>(reader_writer)) {}
~ReadWriteHandler() override = default;
// Both reads and writes are supported.
Status PrepareRead() override { return OkStatus(); }
Status PrepareWrite() override { return OkStatus(); }
void set_reader_writer(stream::ReaderWriter& reader_writer) {
set_reader(reader_writer);
}
};
} // namespace pw::transfer