blob: 700bb82da4bffb1168fd9d6f622b80714400abbf [file] [log] [blame]
#pragma once
#include <array>
#include <concepts>
#include <cstdint>
/**
* Helper concept for the type returned by `receive_frame`. This must provide a
* buffer and a length. It may also be an RAII type that handles any cleanup
* when it is destroyed.
*
* This is not required to be copyable.
*/
template<typename T>
concept ReceivedEthernetFrame = requires(T frame)
{
{
frame->length
} -> std::convertible_to<uint16_t>;
{
frame->buffer
} -> std::convertible_to<const uint8_t *>;
{
frame->buffer
} -> std::convertible_to<bool>;
};
/**
* Concept for an Ethernet adaptor.
*/
template<typename T>
concept EthernetAdaptor = requires(T adaptor,
const uint8_t *buffer,
uint16_t length,
std::array<uint8_t, 6> macAddress)
{
/**
* The default MAC address for this adaptor. Must return a 6-byte array.
*/
{
T::mac_address_default()
} -> std::same_as<std::array<uint8_t, 6>>;
/**
* Is the default MAC address unique? If the device (e.g. soft MAC)
* doesn't have its own hardware MAC address then callers may prefer to
* generate a locally administered MAC address randomly.
*/
{
T::has_unique_mac_address()
} -> std::convertible_to<bool>;
/**
* Set the MAC address of this adaptor.
*/
{adaptor.mac_address_set(macAddress)};
/**
* Set the MAC address of this adaptor to the default value.
*/
{adaptor.mac_address_set()};
/**
* Check if PHY link is up.
*/
{
adaptor.phy_link_status()
} -> std::convertible_to<bool>;
/**
* Receive a frame. Returns an optional value (convertible to bool) that
* has a length and a buffer. The return value owns the buffer for its
* lifetime.
*/
{
adaptor.receive_frame()
} -> ReceivedEthernetFrame;
/**
* Send a frame identified by a base and length. Returns true if the frame
* was sent successfully, false otherwise.
*
* The third argument is a hook that allows the caller to validate the
* packet after it's been buffered but before it's sent. This avoids
* time-of-check-to-time-of-use issues in egress filtering.
*/
{
adaptor.send_frame(
buffer, length, [](const uint8_t *buffer, uint16_t length) {
return true;
})
} -> std::same_as<bool>;
/**
* Read the current interrupt counter for receive interrupts. If this
* device doesn't support interrupts then this can return some other value.
* This is used only with `receive_interrupt_complete`.
*/
{
adaptor.receive_interrupt_value()
} -> std::same_as<uint32_t>;
/**
* Called after `receive_frame` fails to return new frames to block until a
* new frame is ready to receive.
*
* TODO: This currently blocks on a single value, this may later be
* augmented with an interface that sets up a multiwaiter.
*/
{
adaptor.receive_interrupt_complete(nullptr, 0)
} -> std::same_as<int>;
};