blob: ec405a4ed4b2eed963a69b1cdaefb042d6dce0a3 [file] [log] [blame]
// Copyright 2023 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 <optional>
#include "pw_allocator/allocator.h"
#include "pw_bytes/span.h"
#include "pw_function/function.h"
#include "pw_multibuf/multibuf.h"
#include "pw_status/status.h"
#include "pw_status/status_with_size.h"
namespace pw::data_link {
// Generic Data Link interface.
class DataLink {
public:
// Events escalated to upper layers.
enum class Event {
kOpen, // The link is now open.
kClosed, // The link is now closed.
kDataReceived, // Data has been received. Use Read() to fetch it.
kDataRead, // Reading into the provided buffer in Read() is complete.
// The buffer is now free.
// WriteState: kReadPending -> kReadDataReady.
kDataSent, // The data in Write() is in the send process and the buffer
// provided is now free. The link is ready to send more
// data.
};
// Logical states:
// WriteState - { kWriteIdle, kWritePending }
// ReadState - { kReadIdle, kReadPending, kReadDataReady }
// LinkState - { kConnected, kConnectionPending, kDisconnected }
using EventHandlerCallback = pw::Function<void(Event, pw::StatusWithSize)>;
// Closes the underlying links. There will not be any events after this.
virtual ~DataLink() = 0;
// The MTU byte size of the packet which is the payload size plus header(s).
//
// This should only be used to size receive buffers to enable zero copying.
constexpr size_t mtu() { return 0; }
// Initializes the link peripherals if necessary, and the working thread or
// threads depending on the implementation.
// The event handler callback will be called in the working thread.
// Wait for a kConnected event and check its status.
//
// Precondition: link is closed.
virtual void Open(EventHandlerCallback&& event_handler,
allocator::Allocator& write_buffer_allocator) = 0;
// Closes the underlying link, cancelling any pending operations.
//
// Precondition: link is open.
virtual void Close() = 0;
// Gets the location where the outgoing data can be written to if there is no
// ongoing write process. Otherwise, wait for the next kDataSent event.
//
// Precondition:
// Link is open.
virtual std::optional<multibuf::MultiBuf> GetWriteBuffer(size_t size) = 0;
// Writes the entire MultiBuf. The send operation finishes when the kDataSent
// event is emitted. The event has the operation status and how many bytes
// were sent, which must be the size of the provided buffer, since no partial
// writes are supported.
//
// Note: If the caller has a MultiBuf partially filled with data to send, they
// must remove any unused ``MultiBuf::Chunk``s and truncate any partially
// filled ones to avoid writing the empty ``MultiBuf::Chunk``s.
//
// Precondition:
// Link is open.
// No write operation is in progress.
//
// Returns:
// OK: The buffer is successfully in the send process.
// FAILED_PRECONDITION: A write operation is in process. Wait for the next
// kDataSent event.
// INVALID_ARGUMENT: The write buffer is empty.
//
// To send data:
// 1. Get a buffer to write to with GetWriteBuffer().
// 2. Write into buffer.
// 3. Call write with the buffer written to.
// 4. Wait for kDataSent.
// 5. Another buffer can be requested.
virtual Status Write(multibuf::MultiBuf&& buffer) = 0;
// Reads a packet into the provided buffer without blocking. The user cannot
// modify the buffer when Read() is called until the read operation is done
// and the kDataRead event is emitted. The event has the operation status and
// how many bytes were read.
//
// Precondition:
// Link is open.
// No read operation is in progress.
//
// Returns:
// OK: The buffer is successfully in the read process.
// Wait for kDataRead event.
// FAILED_PRECONDITION: A read operation is in progress. Wait for the next
// kDataReceived event.
//
// To read data:
// 1. (Optional) Wait for the kDataReceived event.
// 2. Pass in the input buffer with the amount of bytes to read.
// 3. Wait for the kDataRead event.
// 4. The buffer can be reused now.
virtual Status Read(pw::ByteSpan buffer) = 0;
};
inline DataLink::~DataLink() {}
} // namespace pw::data_link