メインコンテンツまでスキップ

Entity Objects

Table of Contents


Overview

Entity objects are the primary read/write interface for live equipment state in Port. Each entity class implements IEntity and represents a distinct hardware or logical resource — a load port, a process module, a carrier, a substrate, or a running flow.

Entities are per-location singletons: the first call to Port.GetEntity<T>("LP1") creates the instance; every subsequent call returns the same object. This means you never new an entity yourself — you always retrieve it through the Port API.

Entity ClassSEMI StandardRepresents
LoadModuleEntityE87Load-port transfer and carrier lifecycle state
ProcessModuleEntityE39Process-module execution state and timer
CarrierEntityE87Carrier identity and per-slot occupancy
SubstrateEntityE90Substrate identity, reservation, and route
JobEntityThe currently active job and its route progress
FlowEntityFlow execution state of a named controller
CEIDEntityE30Collection Event ID holder

Retrieving Entities

Use Port.GetEntity<T> to obtain an entity singleton. Pass the location name that matches the [LMC], [PMC], or [TMC] declaration in your Port document.

// Load port entities (location = LMC name)
LoadModuleEntity lp1 = Port.GetEntity<LoadModuleEntity>("LP1");
CarrierEntity carrier = Port.GetEntity<CarrierEntity>("LP1");

// Process module entities (location = PMC name)
ProcessModuleEntity stage1 = Port.GetEntity<ProcessModuleEntity>("Stage1");
SubstrateEntity sub1 = Port.GetEntity<SubstrateEntity>("Stage1");

// Active job singleton (location = Equipment/TM name)
JobEntity job = Port.GetEntity<JobEntity>("TM1");

// Flow state per controller
FlowEntity flow = Port.GetEntity<FlowEntity>("Scheduler");

:::tip Per-location Singleton Calling Port.GetEntity<LoadModuleEntity>("LP1") multiple times always returns the exact same C# object. You can safely cache the reference or call Port.GetEntity on every access — both patterns have the same cost after the first call. :::


Entity Classes

LoadModuleEntity — Load Port (E87)

Holds the five independent SEMI E87 state machines for a single load-port location.

LoadModuleEntity lp1 = Port.GetEntity<LoadModuleEntity>("LP1");

Properties

PropertyTypeDescription
LocationstringLocation name this instance is bound to (e.g. "LP1")
TransferStateLoadPortTransferStateTop-level E87 transfer state
InServiceStateLoadPortInServiceStateE87 in-service sub-state (meaningful only when TransferState is InService)
CarrierStateCarrierStateE87 carrier lifecycle state
CarrierIdStatusCarrierIDStatusE87 carrier ID recognition status
SlotMapStatusSlotMapStatusE87 slot map verification status

State Text Helpers

MethodReturnsDescription
GetStateText()string"OutOfService" or the current in-service sub-state name
GetCarrierStateText()stringHuman-readable name of the current CarrierState

Example

var lp1 = Port.GetEntity<LoadModuleEntity>("LP1");
Console.WriteLine(lp1.GetStateText()); // "ReadyToLoad"
Console.WriteLine(lp1.GetCarrierStateText()); // "NotAccessed"
Console.WriteLine(lp1.TransferState); // LoadPortTransferState.InService

ProcessModuleEntity — Process Module (E39)

Tracks the SEMI E39 process state and recipe-timer data for a single equipment module.

ProcessModuleEntity stage1 = Port.GetEntity<ProcessModuleEntity>("Stage1");

Properties

PropertyTypeDescription
LocationstringLocation name (e.g. "Stage1")
StateModuleProcessStateCurrent SEMI E39 process state
ProcessValuedoubleElapsed process time in seconds (atomic read)
ProcessMaxdoubleTotal recipe step duration in seconds (atomic read)

Methods

MethodReturnsDescription
SetState(ModuleProcessState)ProcessModuleEntityAtomically sets process state and raises Port.ModuleStateChanged
SetState(string)ProcessModuleEntityParses and sets process state by name (case-insensitive)
SetProcessSeconds(double)ProcessModuleEntitySets elapsed process time
SetProcessMax(double)ProcessModuleEntitySets total recipe step duration
SetRecipeName(string)ProcessModuleEntityStores the recipe name for the current step
GetStateText()stringHuman-readable name of State
GetProcessValue()doubleAlias for ProcessValue property
GetProcessMax()doubleAlias for ProcessMax property
GetRecipeName()stringReturns the recipe name set via SetRecipeName

ModuleProcessState Values

StateDescription
InitModule has not started
IdleModule is idle and ready
SetupModule is being prepared
ExecutingModule is processing a substrate
PauseProcessing is paused
CompleteProcessing has completed

Example

ProcessModuleEntity stage = Port.GetEntity<ProcessModuleEntity>("Stage1");

// Start processing
stage.SetState(portdic.GEM.E39.ModuleProcessState.Executing)
.SetRecipeName("Oxide_90s")
.SetProcessMax(90.0)
.SetProcessSeconds(0.0);

// Tick the timer each second
stage.SetProcessSeconds(stage.ProcessValue + 1.0);

// Display progress
Console.WriteLine($"Recipe: {stage.GetRecipeName()}");
Console.WriteLine($"Progress: {stage.ProcessValue:F0}/{stage.ProcessMax:F0}s");
Console.WriteLine($"State: {stage.GetStateText()}");

// Complete processing
stage.SetState("Complete");

:::info Event on State Change SetState automatically calls Port.RaiseModuleStateChanged, which fires Port.ModuleStateChanged. Subscribe to this event to get notified whenever any module state changes. :::


CarrierEntity — Carrier & Slot Map

Holds carrier identity, per-slot occupancy state, and lot-selection state for a load-port location.

CarrierEntity carrier = Port.GetEntity<CarrierEntity>("LP1");

Properties

PropertyTypeDescription
SlotCountintTotal number of substrate slots (from [LMC(n)] declaration)

Methods

MethodReturnsDescription
GetCarrierID()stringCarrier ID string for this location
SetSlot(int slot, SlotStates state)voidSets occupancy state of the specified slot (1-based)
GetSlot(int slot)SlotStatesReturns occupancy state; Empty when not set
GetAllSlots()IReadOnlyDictionary<int, SlotStates>Snapshot of all set slot states
SetReturned(int slot, bool returned)voidMarks whether the substrate in this slot has been returned after processing
GetReturned(int slot)boolReturns true when the slot is marked as returned
GetSelected(int slot)boolReturns true when the slot belongs to the currently active lot
GetSlots()IReadOnlyList<SlotEntry>Full 25-element slot view for UI binding

Example

CarrierEntity carrier = Port.GetEntity<CarrierEntity>("LP1");

// Read carrier ID
Console.WriteLine($"Carrier: {carrier.GetCarrierID()}");

// Set slot occupancy after slot mapping
carrier.SetSlot(1, SlotStates.CorrectlyOccupied);
carrier.SetSlot(2, SlotStates.Empty);
carrier.SetSlot(3, SlotStates.DoubleSlotted);

// Check a specific slot
SlotStates s1 = carrier.GetSlot(1); // CorrectlyOccupied

// Mark slot as returned after processing
carrier.SetReturned(1, true);

// Get full slot view for WPF binding
IReadOnlyList<SlotEntry> slots = carrier.GetSlots();
foreach (SlotEntry entry in slots)
{
Console.WriteLine(
$"Slot {entry.SlotNo}: Present={entry.IsPresent}, " +
$"Returned={entry.IsReturned}, Selected={entry.IsSelected}, " +
$"ID={entry.SubstrateId}");
}

SubstrateEntity — Substrate State

Provides substrate identity, reservation state, and route access for a named equipment location.

SubstrateEntity sub = Port.GetEntity<SubstrateEntity>("Stage1");

Methods

MethodReturnsDescription
GetSubstrateID()stringSubstrate ID at this location, or empty string if none
GetExists()booltrue when a substrate is present
GetReserved()booltrue when the location is reserved (substrate placed but not yet complete)
SetReserved(bool)voidSets the reservation flag — true after a Put, false after processing completes
GetState()SubstrateStateCurrent SEMI E90 processing state
SetState(SubstrateState)voidSets the SEMI E90 processing state
GetRoute()SubstrateRouteRoute plan and step progress for the current substrate

Example

SubstrateEntity sub = Port.GetEntity<SubstrateEntity>("Stage1");

// Check whether a substrate is present
if (sub.GetExists())
{
Console.WriteLine($"Substrate: {sub.GetSubstrateID()}");
Console.WriteLine($"Reserved: {sub.GetReserved()}");
Console.WriteLine($"State: {sub.GetState()}");
}

// Reserve the location when a Put command completes
sub.SetReserved(true);
sub.SetState(SubstrateState.Unprocessed);

// After processing finishes
sub.SetState(SubstrateState.Processed);
sub.SetReserved(false);

// Inspect the route for this substrate
SubstrateRoute route = sub.GetRoute();
foreach (RouteInfo info in route.GetAll())
{
Console.WriteLine($"Key: {info.Key}, LastCompleted: {info.LastCompletedStep}");
}

JobEntity — Active Job

Holds the identity and slot assignments of the currently active job, and exposes live route-tracking data. Retrieved per Equipment/TM location — there is one JobEntity singleton per location.

JobEntity job = Port.GetEntity<JobEntity>("TM1");

Properties

PropertyTypeDescription
IDstringUnique job identifier (empty when no job is active)
NamestringHuman-readable job name
SourceLpstringSource load-port name (e.g. "LP1")
SlotAssignmentsList<SlotAssignment>Per-slot route assignments
CycleCountintNumber of times the job repeats after completion (0 = run once)
CreatedAtDateTimeTimestamp when the job was created
IsActivebooltrue when ID is non-empty
LotCompletedCountintNumber of job cycles completed so far

Methods

MethodReturnsDescription
Queued(JobEntity source)ResultCodeCopies job data from source and marks it as queued — call when a job enters the queue
Processing(JobEntity source)ResultCodeCopies job data from source and marks it as actively processing
Clear()voidResets all fields — marks the job as inactive
GetAllRoute()IEnumerable<RouteInfo>Snapshot of every registered substrate route and step progress

Example

JobEntity job = Port.GetEntity<JobEntity>("TM1");

// Check if a job is active
if (!job.IsActive)
{
Console.WriteLine("No active job.");
return;
}

Console.WriteLine($"Job: {job.Name} (ID: {job.ID})");
Console.WriteLine($"Source: {job.SourceLp}");
Console.WriteLine($"Slots: {job.SlotAssignments.Count}");
Console.WriteLine($"Completed cycles: {job.LotCompletedCount}");

// Print route progress for all substrates
foreach (RouteInfo info in job.GetAllRoute())
{
Console.WriteLine($" [{info.Key}] last step: {info.LastCompletedStep}");
}

// Queue a new job built from persistent storage
var newJob = new JobEntity(
id: "A1B2C3D4",
name: "TestJob",
sourceLp: "LP1",
slotAssignments: assignments,
cycleCount: 0,
createdAt: DateTime.Now);

job.Queued(newJob); // job entered the queue
job.Processing(newJob); // job started executing

// Clear when the job finishes
job.Clear();

FlowEntity — Flow Execution

Provides read-only access to the execution state of a controller's named flows.

FlowEntity flow = Port.GetEntity<FlowEntity>("Scheduler");

Methods

MethodReturnsDescription
GetAction(string flowName = "Queued")FlowActionCurrent FlowAction for the named flow
GetCurrentStep(string flowName = "Queued")stringName of the step currently executing, or null if not started
IsRunning(string flowName = "Queued")booltrue when the flow is actively executing

FlowAction Values

ValueDescription
QueuedFlow is queued and waiting to execute
ExecutingFlow is actively running a step
DoneFlow has finished all steps
PausedFlow execution is paused

Example

FlowEntity flow = Port.GetEntity<FlowEntity>("Scheduler");

// Check default "Queued" flow
Console.WriteLine($"Running: {flow.IsRunning()}");
Console.WriteLine($"Step: {flow.GetCurrentStep()}");
Console.WriteLine($"Action: {flow.GetAction()}");

// Check a specific named flow
Console.WriteLine($"Transfer running: {flow.IsRunning("Transfer")}");
Console.WriteLine($"Transfer step: {flow.GetCurrentStep("Transfer")}");

CEIDEntity

A Collection Event ID entity used to hold SEMI E30 CEID-related data.

CEIDEntity ceid = Port.GetEntity<CEIDEntity>("category");
IImmutableList<int> list = ceid.GetList(); // Returns associated int list

Supporting Types

SlotStates Enum

SEMI E87 slot occupancy state reported by the load-port mapping sensor.

ValueIntegerDescription
Empty0Slot contains no wafer
NotEmpty1Slot contains a wafer but position has not been verified
CorrectlyOccupied2Wafer is correctly seated within slot boundaries
DoubleSlotted3A single wafer spans two adjacent slots
CrossSlotted4A wafer is tilted or misaligned across the slot boundary
var state = carrier.GetSlot(3);
if (state == SlotStates.DoubleSlotted || state == SlotStates.CrossSlotted)
{
Console.WriteLine("Slot 3: mapping error detected");
}

SubstrateState Enum

SEMI E90 substrate processing state.

ValueDescription
UnknownState before slot mapping is performed
AliasedSubstrate ID is duplicated or cannot be uniquely identified
ProcessedSubstrate has already completed processing
UnprocessedSubstrate is waiting and has not yet been processed
SkippedSubstrate has been excluded from the process sequence
sub.SetState(SubstrateState.Unprocessed); // before processing
sub.SetState(SubstrateState.Processed); // after processing
sub.SetState(SubstrateState.Skipped); // excluded slot

SlotAssignment

Associates a load-port slot number with a saved route name.

PropertyTypeDescription
SlotIndexint1-based slot index within the load-port carrier
RouteNamestringName of the route assigned to this slot
var assignments = new List<SlotAssignment>
{
new SlotAssignment { SlotIndex = 1, RouteName = "RouteA" },
new SlotAssignment { SlotIndex = 2, RouteName = "RouteB" },
new SlotAssignment { SlotIndex = 3, RouteName = "RouteA" },
};

SlotEntry Struct

An immutable view of a single slot's state within a CarrierEntity. Property names match the WPF SlotCellTemplate data-trigger bindings.

PropertyTypeDescription
IsPresentbooltrue when the slot has a substrate in the carrier map
IsReturnedbooltrue when the substrate has been returned after processing
IsSelectedbooltrue when this slot is part of the currently active lot
SlotNoint1-based slot number (1–25 for a standard FOUP)
SubstrateIdstringSubstrate identity key (e.g. "LP1#3"); empty when IsPresent is false
// Typically obtained from CarrierEntity.GetSlots()
IReadOnlyList<SlotEntry> slots = carrier.GetSlots();

// Bind to WPF ItemsControl — each SlotEntry exposes the correct property names
slotListView.ItemsSource = slots;

// Or iterate manually
foreach (SlotEntry slot in slots)
{
if (slot.IsPresent && !slot.IsReturned)
Console.WriteLine($"Slot {slot.SlotNo}: {slot.SubstrateId} — in progress");
}

SubstrateRoute

Provides read-only access to the route plan and step-completion progress for a single substrate. Obtained from SubstrateEntity.GetRoute().

MethodReturnsDescription
GetAll()IEnumerable<RouteInfo>Route entry for this substrate, or an empty sequence if no route is registered
SubstrateRoute route = Port.GetEntity<SubstrateEntity>("Stage1").GetRoute();

foreach (RouteInfo info in route.GetAll())
{
Console.WriteLine($"Route key: {info.Key}");
Console.WriteLine($"Last completed step: {info.LastCompletedStep}");
foreach (var step in info.Steps)
Console.WriteLine($" Step: {step.Name}");
}

Thread Safety

All entity property setters are thread-safe:

MechanismUsed For
System.Threading.Interlocked.ExchangeAll int-backed state fields (TransferState, InServiceState, etc.)
Interlocked.Exchange on long bit patternsdouble fields (ProcessValue, ProcessMax) — safe on 32-bit runtimes
volatile on reference typesstring fields (e.g. _recipeName) — guarantees cross-thread visibility

You can safely read and write entity properties from multiple threads simultaneously without additional locking.

// Safe to call from background threads, timer callbacks, or async handlers
Task.Run(() =>
{
Port.GetEntity<ProcessModuleEntity>("Stage1")
.SetProcessSeconds(elapsed)
.SetState(ModuleProcessState.Executing);
});

:::warning Dictionary reads are not locked GetAllSlots() and GetSlots() read from internal Dictionary<int, SlotStates> fields. If you write to a CarrierEntity from one thread while iterating GetAllSlots() on another, add your own synchronization around the iteration. :::


Common Patterns

Conditional State Update

var lp = Port.GetEntity<LoadModuleEntity>("LP1");

if (lp.TransferState == LoadPortTransferState.InService
&& lp.InServiceState == LoadPortInServiceState.ReadyToLoad)
{
// Issue transfer command
}

Monitoring Job Progress

JobEntity job = Port.GetEntity<JobEntity>("TM1");

if (job.IsActive)
{
int total = job.SlotAssignments.Count;
int completed = 0;

foreach (RouteInfo info in job.GetAllRoute())
{
if (info.LastCompletedStep >= info.Steps.Length - 1)
completed++;
}

Console.WriteLine($"Job {job.Name}: {completed}/{total} substrates complete");
Console.WriteLine($"Completed cycles: {job.LotCompletedCount}");
}

Carrier Slot Map Update

// Typically called from the slot-map-received event handler
CarrierEntity carrier = Port.GetEntity<CarrierEntity>("LP1");

for (int slot = 1; slot <= carrier.SlotCount; slot++)
{
SlotStates state = ReadSensorState(slot); // your hardware read
carrier.SetSlot(slot, state);
}

Checking Flow Before Transfer

FlowEntity scheduler = Port.GetEntity<FlowEntity>("Scheduler");

if (!scheduler.IsRunning("Transfer"))
{
Console.WriteLine("Scheduler is idle — safe to start new transfer");
}
else
{
Console.WriteLine($"Transfer running at step: {scheduler.GetCurrentStep("Transfer")}");
}

See also: Scheduler for substrate transfer configuration, Flow for flow step authoring, Attribute Reference for [LMC], [PMC], and [TMC] declarations.