Livt packages
Livt.Net
Version 1.4.1
Ethernet, IPv4, TCP, UDP, ARP, TFTP, and Telnet networking components for Livt hardware.
Published files (163)
src/drivers/ethernet/EthernetFrameTransmitter.lvt
namespace Livt.Net.Drivers.Ethernet
using Livt.Net
using Livt.IO
enum EthernetFrameTransmitState
{
Idle;
Copying;
Terminal
}
/**
* Copies a statically bound prepared source into the IO MAC's exclusive TX slot.
* The borrow covers copying and wire completion. One serialized application owner;
* this adapter is the only owner of the underlying IO transmitter capability.
*/
component EthernetFrameTransmitter<S: IPacketData> : IFrameTransmitter
{
source: S
device: IEthernetTransmitter
phase: EthernetFrameTransmitState
length: int
outcome: FrameTransmitOutcome
deviceCompletion: bool
new(device: IEthernetTransmitter, source: S)
{
this.device = device;
this.source = source
}
override fn GetMinimumFrameLength() int
{
return 60
}
override fn GetMaximumFrameLength() int
{
return device.GetTransmitCapacity()
}
override fn SupportsCancellation() bool
{
return false
}
override fn IsSourceBorrowed() bool
{
return phase == EthernetFrameTransmitState.Copying
}
override fn TryCancel() FrameLinkResult
{
if (phase != EthernetFrameTransmitState.Copying) { return FrameLinkResult.Invalid }
return FrameLinkResult.Unsupported
}
override fn TrySubmit() FrameLinkResult
{
if (phase != EthernetFrameTransmitState.Idle) { return FrameLinkResult.Busy }
if (!source.IsReady()) { return FrameLinkResult.Invalid }
var size = source.GetAvailableLength()
if (size <= 0) { return FrameLinkResult.Invalid }
if (size < 60 || size > device.GetTransmitCapacity()) { return FrameLinkResult.Unsupported }
var result = device.TryBegin(size)
if (result != EthernetResult.Success) { return EthernetLinkResults.Map(result) }
length = size
deviceCompletion = false
phase = EthernetFrameTransmitState.Copying
return FrameLinkResult.Accepted
}
override fn TryGetCompletion(result: out FrameTransmitOutcome) FrameLinkResult
{
result = FrameTransmitOutcome.DeviceFailure
if (phase != EthernetFrameTransmitState.Terminal) { return FrameLinkResult.NotReady }
result = outcome
return FrameLinkResult.Success
}
override fn TryAcknowledgeCompletion() FrameLinkResult
{
if (phase != EthernetFrameTransmitState.Terminal) { return FrameLinkResult.NotReady }
if (deviceCompletion) {
var result = device.TryAcknowledgeCompletion()
if (result != EthernetResult.Success) { return EthernetLinkResults.Map(result) }
}
deviceCompletion = false
phase = EthernetFrameTransmitState.Idle
return FrameLinkResult.Success
}
process Transfer()
{
while (true) {
while (phase != EthernetFrameTransmitState.Copying) {}
var failed = false
for (var index = 0; index < length; index++) {
var value: byte = 0
if (source.TryRead(index, value) != PacketDataResult.Success) {
failed = true;
break
}
if (device.TryAppend(value) != EthernetResult.Success) {
failed = true;
break
}
}
if (!failed) {
if (device.TryCommit() != EthernetResult.Accepted) { failed = true }
}
outcome = FrameTransmitOutcome.DeviceFailure
if (failed) {
// No commit was accepted: discard fill before ending the source borrow.
device.TryDiscard()
} else {
var terminal: EthernetTransmitOutcome = EthernetTransmitOutcome.None
var result = device.TryGetCompletion(terminal)
while (result == EthernetResult.NotReady) {
result = device.TryGetCompletion(terminal)
}
if (result == EthernetResult.Success) {
deviceCompletion = true
if (terminal == EthernetTransmitOutcome.Sent) { outcome = FrameTransmitOutcome.Delivered }
}
}
phase = EthernetFrameTransmitState.Terminal
// Do not revisit a completed transfer while the application acknowledges it.
while (phase == EthernetFrameTransmitState.Terminal) {}
}
}
}