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/link/TestFrameTransmitter.lvt
namespace Livt.Net
enum TestTransmitState
{
Idle
Borrowed
Terminal
Resetting
}
/**
* Deterministic transmitter for contract tests. Advance reads at most one source
* byte. A later Advance publishes delivery, allowing tests to hold completion.
* Test controls/capture access are outside the public transmitter capability.
*/
component TestFrameTransmitter<P: IPacketData, MAX_LENGTH: int = 1514, CANCELLABLE: bool = true> : IFrameTransmitter
{
static assert MAX_LENGTH >= 60, "Frame limit must accommodate minimum Ethernet frame"
// Borrowed fixed source; retained from acceptance until terminal quiescence.
source: P
// Owned capture snapshot and submitted length.
captured: byte[MAX_LENGTH]
const LENGTH_BITS: int = Bits.RequiredFor(MAX_LENGTH)
capturedLength: logic[LENGTH_BITS]
length: logic[LENGTH_BITS]
// Transfer lifecycle, harness controls and retained terminal result.
phase: TestTransmitState
ready: bool
borrowed: bool
cancelRequested: bool
failureRequested: bool
outcome: FrameTransmitOutcome
/**
* Borrows a fixed source, owns capture storage and starts idle and ready.
* Construction does not read or acquire the source.
*/
new(source: P)
{
this.source = source
capturedLength = 0
length = 0
phase = TestTransmitState.Idle
ready = true
borrowed = false
cancelRequested = false
failureRequested = false
outcome = FrameTransmitOutcome.DeviceFailure
}
/**
* Returns the minimum supported submission length in bytes, including padding and excluding FCS.
*/
override fn GetMinimumFrameLength() int
{
return 60
}
/**
* Returns the maximum supported submission length in bytes, excluding FCS.
*/
override fn GetMaximumFrameLength() int
{
return MAX_LENGTH
}
/**
* Reports whether cancellation can be requested; it does not guarantee immediate quiescence.
*/
override fn SupportsCancellation() bool
{
return CANCELLABLE
}
/**
* Reports whether the source and its dependencies must remain published and unchanged.
*/
override fn IsSourceBorrowed() bool
{
return borrowed
}
/**
* Requests transmission of the fixed, prepared source. Accepted starts the borrow,
* not delivery. Rejection leaves the source unborrowed and preserves old results.
* Busy means an active transfer or unacknowledged completion; NotReady means
* admission is paused. Invalid means unprepared/empty data; Unsupported means
* length outside the advertised bounds; DeviceFailure means admission failed.
*/
override fn TrySubmit() FrameLinkResult
{
if (phase == TestTransmitState.Resetting) {
return FrameLinkResult.NotReady
}
if (phase != TestTransmitState.Idle) {
return FrameLinkResult.Busy
}
if (!ready) {
return FrameLinkResult.NotReady
}
if (failureRequested) {
return FrameLinkResult.DeviceFailure
}
if (!source.IsReady()) {
return FrameLinkResult.Invalid
}
var size = source.GetAvailableLength()
if (size <= 0) {
return FrameLinkResult.Invalid
}
if (size < 60 || size > MAX_LENGTH) {
return FrameLinkResult.Unsupported
}
length = size as logic[LENGTH_BITS]
capturedLength = 0
cancelRequested = false
borrowed = true
phase = TestTransmitState.Borrowed
return FrameLinkResult.Accepted
}
/**
* Requests cancellation of an active borrow. Accepted is not terminal completion;
* keep the source unchanged until completion or coordinated reset finishes.
* Unsupported preserves ownership; Busy means already requested, Invalid means
* no pending transfer, and NotReady means reset prevents cancellation.
*/
override fn TryCancel() FrameLinkResult
{
if (phase == TestTransmitState.Resetting) {
return FrameLinkResult.NotReady
}
if (phase != TestTransmitState.Borrowed) {
return FrameLinkResult.Invalid
}
if (!CANCELLABLE) {
return FrameLinkResult.Unsupported
}
if (cancelRequested) {
return FrameLinkResult.Busy
}
cancelRequested = true
return FrameLinkResult.Accepted
}
/**
* Returns Success and a retained terminal outcome when available, otherwise
* NotReady. The output is meaningful only on Success. This does not acknowledge it.
*/
override fn TryGetCompletion(outcome: out FrameTransmitOutcome) FrameLinkResult
{
outcome = FrameTransmitOutcome.DeviceFailure
if (phase != TestTransmitState.Terminal) {
return FrameLinkResult.NotReady
}
outcome = this.outcome
return FrameLinkResult.Success
}
/**
* Acknowledges a retained terminal result, allowing another submission.
* Returns NotReady when no terminal result is available.
*/
override fn TryAcknowledgeCompletion() FrameLinkResult
{
if (phase != TestTransmitState.Terminal) {
return FrameLinkResult.NotReady
}
phase = TestTransmitState.Idle
return FrameLinkResult.Success
}
/**
* Controls submission readiness and pauses byte transfer; terminal handling still advances.
*/
public fn SetReady(ready: bool)
{
this.ready = ready
}
/**
* Inject/clear device failure. During a borrow it is observed on Advance.
*/
public fn SetFailure(failed: bool)
{
failureRequested = failed
}
/**
* Advances an active transfer by at most one scheduled source read. Cancellation
* and errors take priority over paused transfer. A later call publishes delivery
* after the last byte; terminal completion releases the source borrow.
*/
public fn Advance()
{
if (phase != TestTransmitState.Borrowed) {
return
}
// Quiescence/error handling continues even when data transfer is paused.
if (failureRequested) {
outcome = FrameTransmitOutcome.DeviceFailure;
borrowed = false;
phase = TestTransmitState.Terminal;
return
}
if (cancelRequested) {
outcome = FrameTransmitOutcome.Cancelled;
borrowed = false;
phase = TestTransmitState.Terminal;
return
}
if (!ready) {
return
}
if (capturedLength == length) {
outcome = FrameTransmitOutcome.Delivered;
borrowed = false;
phase = TestTransmitState.Terminal;
return
}
var value: byte = 0x00
var result = source.TryRead((capturedLength as uint) as int, value)
if (result != PacketDataResult.Success) {
outcome = FrameTransmitOutcome.DeviceFailure;
borrowed = false;
phase = TestTransmitState.Terminal;
return
}
captured[(capturedLength as uint) as int] = value
capturedLength++
}
/**
* Returns the number of captured bytes, including a partial transfer snapshot.
*/
public fn GetCapturedLength() int
{
return (capturedLength as uint) as int
}
/**
* Reads index in 0..capturedLength-1; Invalid leaves output zero.
* Capture inspection does not acquire the source or acknowledge completion.
*/
public fn TryReadCaptured(index: int, value: out byte) PacketDataResult
{
value = 0x00
if (index < 0 || index >= ((capturedLength as uint) as int)) {
return PacketDataResult.Invalid
}
value = captured[index]
return PacketDataResult.Success
}
/**
* Enters the reset barrier and disables readiness without releasing the source.
* Only CompleteReset after reader quiescence ends the borrow.
*/
public fn BeginReset()
{
phase = TestTransmitState.Resetting;
ready = false
}
/**
* Ends the borrow only when the harness declares all readers quiescent.
*/
public fn CompleteReset()
{
if (phase != TestTransmitState.Resetting) {
return
}
borrowed = false
capturedLength = 0
length = 0
cancelRequested = false
failureRequested = false
outcome = FrameTransmitOutcome.DeviceFailure
phase = TestTransmitState.Idle
ready = false
}
}