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/services/FrameService.lvt

namespace Livt.Net

/**
 * Progress from a serialized receive/handle/transmit poll.
 */
enum FrameServiceProgress
{
	Idle
	Pending
	Completed
	Ignored
	Rejected
	ReceiveFailure
}

/**
 * Common link/service coordinator. Bind TX to the handler's IPacketData response.
 * Owns the lifecycle, borrows fixed RX/handler/TX instances and releases RX after
 * snapshot handling. A prepared response remains stable through backpressure and
 * is released only after terminal TX completion. All participants reset together.
 */
component FrameService<R: IFrameReceiver, H: IResponseService, T: IFrameTransmitter>
{
	// Fixed dependencies and owned transfer coordinator.
	receiver: R
	handler: H
	transfer: ResponseTransfer<T>
	released: bool

	/**
	 * Binds idle participants; the handler must snapshot requests before returning.
	 */
	new(receiver: R, handler: H, transmitter: T)
	{
		this.receiver = receiver
		this.handler = handler
		this.transfer = new ResponseTransfer<T>(transmitter)
	}

	/**
	 * Polls one request/response lifecycle. Completed remains stable until acknowledged.
	 * Rejected/ignored requests release RX and never submit an unprepared response.
	 */
	public fn Poll() FrameServiceProgress
	{
		if (this.transfer.GetState() != ResponseTransferState.Idle) {
			if (this.transfer.Poll() != ResponseTransferState.Completed) {
				return FrameServiceProgress.Pending
			}

			if (!this.released) {
				this.handler.TryReleaseResponse()
				this.released = true
			}

			return FrameServiceProgress.Completed
		}

		var acquired = this.receiver.TryAcquire()

		if (acquired == FrameLinkResult.DeviceFailure) {
			return FrameServiceProgress.ReceiveFailure
		}

		if (acquired != FrameLinkResult.Success) {
			return FrameServiceProgress.Idle
		}

		var result = this.handler.TryHandle()
		this.receiver.TryRelease()

		if (result == ServiceResult.Prepared) {
			this.released = false
			this.transfer.TryBegin()
			return FrameServiceProgress.Pending
		}

		if (result == ServiceResult.Ignored) {
			return FrameServiceProgress.Ignored
		}

		return FrameServiceProgress.Rejected
	}

	/**
	 * Reads completion only after response cleanup has finished.
	 */
	public fn TryGetCompletion(outcome: out FrameTransmitOutcome) FrameLinkResult
	{
		outcome = FrameTransmitOutcome.DeviceFailure

		if (!this.released) {
			return FrameLinkResult.NotReady
		}

		return this.transfer.TryGetCompletion(outcome)
	}

	/**
	 * Allows the next request after the owner has observed the retained result.
	 */
	public fn TryAcknowledgeCompletion() FrameLinkResult
	{
		if (!this.released) {
			return FrameLinkResult.NotReady
		}

		var result = this.transfer.TryAcknowledgeCompletion()

		if (result == FrameLinkResult.Success) {
			this.released = false
		}

		return result
	}

	/**
	 * Requests cancellation without ending source lifetime prematurely.
	 */
	public fn TryCancel() FrameLinkResult
	{
		return this.transfer.TryCancel()
	}
}