본문으로 건너뛰기

Attribute

Port uses C# attributes to declaratively define package registration, API generation, dependency injection, and workflow control. This page is a categorized reference for all Port attributes.


Quick Reference

Summary table of all Port attributes.

CategoryAttributeTargetDescription
Package[Package]classRegister Port-managed package
[Handler]propertyInject IPackageHandler (log + property)
[Preset]methodInitialization after injection
[API]property, fieldGenerate REST API endpoint
[Valid]methodValidation gate
[Comment]propertyAPI documentation
[Command]methodCommand endpoint
Flow[Flow]classWorkflow definition
[Controller]classFlow controller
[FlowStep]methodWorkflow step
[Model]propertyInject IFlowModel
[FlowNotify]propertyInject IFlowNotify
[FlowWatcherCompare]methodStep condition watcher
[FlowWatcherAction]methodStep completion action
[FlowControl]propertyInject IFlowControl
[StepTimer]propertyInject IStepTimer
[Step]methodPackage-level step
[Import]field, propertyCross-package dependency
[Timeout]methodStep timeout
GEM/SECS[GEM]classGEM handler
[GemHandler]propertyInject IGemHandler
[Preset]methodInitialization config
[SECS]propertySECS field mapping
Controller[AppController]classApplication controller
[TransferController]classTransfer controller
[TransferHandler]propertyInject ITransferHandler
[Location]methodDefine transfer location
Document[Document]classSource document path
[Save]methodOutput file paths
[ColumnHeader]propertyColumn header mapping
[EntryKey]propertyKey column
[EntryProperty]propertyProperty column
[EntryDataType]propertyData type

Package Attributes

Attributes used for defining package classes and generating APIs.

AttributeTargetInjected TypeArgumentsDescription
[Package]classRegisters class as a Port-managed package
[Handler]propertyIPackageHandlerInjects handler — unified access to logging and entry property
[Preset]methodCalled once after injection; use for initialization and event wiring
[API]property, fieldEntryDataType, PropertyFormat, keysGenerates REST API endpoint

Package

Registers a class as a managed package in the Port Dictionary system.

[Package]
public class Bulb
{
[Handler]
public IPackageHandler Handler { get; set; }

[API(EntryDataType.Enum)]
public string OffOn { get; set; } = "Off";
}

Handler

Injects IPackageHandler, which provides unified access to logging and entry property values. Use SetLogger in [Preset] to enable file logging, then call Write anywhere inside the package.

[Package]
public class Heater
{
[Handler]
public IPackageHandler Handler { get; set; }

[Preset]
public void Preset()
{
// Enable file logging — writes to C:\Logs\Heater\
Handler.SetLogger(@"C:\Logs");
}

[API]
public double Temp
{
get
{
// Read entry property (set in .page via property:{...})
if (Handler.EntryProperty.TryToGetValue("Unit", out string unit))
{
Handler.Write($"[INFO] Unit={unit}");
return unit == "F" ? 212.0 : 100.0;
}
return double.NaN;
}
}
}

IPackageHandler members:

MemberDescription
SetLogger(rootPath)Enable file logging; creates rootPath/packageName/ sub-directory
SetLogger(rootPath, conf)Same with rotation and retention options via PortLogConfiguration
Write(message)Write a plain text log entry
Write(code, header, dict)Write a structured log entry with LogTypeCode, header, and key-value data
EntryPropertyCurrent IProperty for the active Get/Set request; use TryToGetValue to read values

IProperty.TryToGetValue usage:

// .page entry definition
// RoomTemp f8 property:{"Unit":"C","Max":"300"}

// Inside a package API property getter:
if (Handler.EntryProperty.TryToGetValue("Unit", out string unit))
{
// unit == "C"
}
if (Handler.EntryProperty.TryToGetValue("Max", out string max))
{
double limit = double.Parse(max); // limit == 300.0
}

API

Automatically registers a property as a REST API endpoint. Specify the data type with EntryDataType.

// Basic usage
[API]
public string Status { get; set; }

// Enum type
[API(EntryDataType.Enum)]
public string OffOn { get; set; }

// Numeric with JSON property keys
[API(EntryDataType.Num, PropertyFormat.Json, "Unit")]
public double Temp1 { get; set; }

// String type
[API(EntryDataType.Char)]
public string Power { get; set; }

// List type
[API(EntryDataType.List, PropertyFormat.Array, 0, 1, 2)]
public List<string> Readings { get; set; }

EntryDataType values:

TypeDescription
EntryDataType.TextText
EntryDataType.NumNumeric (double)
EntryDataType.CharASCII string
EntryDataType.EnumEnumeration
EntryDataType.ListList

Valid

Defines a validation method for the package. When it returns false, the error message passed as argument is displayed.

[Valid("Device not connected")]
public bool Valid()
{
return serialPort.IsOpen;
}

Comment

Adds a description to an API property.

[API, Comment("Current temperature (Celsius)")]
public double Temperature { get; set; }

Flow Attributes

Attributes used for defining and controlling workflows (process flows).

AttributeTargetInjected TypeArgumentsDescription
[Flow]classtypeof(T)Defines a workflow class
[Controller]classDefines a controller containing flows
[FlowStep]methodnameof(prevStep)Defines a workflow step
[Model]propertyIFlowModelInjects flow data model
[FlowNotify]propertyIFlowNotifyInjects flow notification/progress control
[FlowWatcherCompare]methodentry, op, valueDefines step execution condition
[FlowWatcherAction]methodentry, valueDefines action on step completion
[FlowControl]propertyIFlowControlInjects flow branching/jump control
[StepTimer]propertyIStepTimerInjects step timer/scheduling
[Step]methodindex, ceid, entryDefines package-level workflow step
[Import]field, propertyIFunction / IReference"packageName", "key"Injects cross-package dependency
[Timeout]methodmin, maxSets step timeout

Controller + Flow

[Controller] defines a controller that contains multiple flows, and [Flow] defines an inner workflow class.

[Controller]
public partial class LoadPortController
{
[Flow]
public class LoadFlow
{
[Model]
public IFlowModel model { get; set; }

[FlowNotify]
public IFlowNotify Notify { get; set; }

[FlowStep]
public void Step1()
{
// First step
Notify.Next(); // Move to next step
}

[FlowStep(nameof(Step1))]
public void Step2()
{
// Runs after Step1
Notify.Next();
}
}
}

FlowStep

Registers a method as a workflow step. Use nameof() to specify the previous step and define execution order.

// First step (no arguments)
[FlowStep]
public void Step1() { Notify.Next(); }

// Runs after Step1
[FlowStep(nameof(Step1))]
public void Step2() { Notify.Next(); }

// Runs after Step2
[FlowStep(nameof(Step2))]
public void Step3() { Notify.Next(); }

FlowWatcherCompare

Defines pre/post conditions for a step. All conditions must be met before proceeding to the next step.

[FlowStep]
[FlowWatcherCompare("@Temp1", ">=", 50)] // Model binding (@)
[FlowWatcherCompare("room2.HeaterTemp4", ">=", 100)] // Direct reference
[FlowWatcherCompare("room2.HeaterTemp5", ">=", Room2.HeaterTemp4)] // Entry-to-entry comparison
public void Step1()
{
Notify.Next();
}

Supported operators: >=, <=, >, <, ==, !=

FlowWatcherAction

Automatically sets a value when a step completes.

[FlowStep]
[FlowWatcherAction("room2.BulbOnOff", "Off")] // Sets BulbOnOff = "Off" on completion
[FlowWatcherAction(Room2.BulbOnOff, "On")] // Using token constants
public void Step1()
{
Notify.Next();
}

Model

Binds and provides Get/Set access to model data within a flow. Use the @ prefix to reference model-bound messages.

[Model]
public IFlowModel model { get; set; }

// Usage
var value = model.Get("@OnOff"); // Read model-bound value
model.Set("@OnOff", "On"); // Write model-bound value
var data = model.Binding("@OnOff"); // Get binding data

FlowNotify

Handles flow progress control and notifications.

[FlowNotify]
public IFlowNotify Notify { get; set; }

// Usage
Notify.Next(); // Move to next step
Notify.Alert("message"); // Raise alert notification
Notify.OccuredAlarm(3000); // Raise alarm (Alarm ID)
Notify.ClearAlarm(3000); // Clear alarm

Step (Package Level)

Defines workflow steps within a [Package] class (instead of a [Flow] class).

[Package(typeof(DataProcessingService))]
public class DataProcessingService
{
[Step(1, "InputData")]
public void ProcessInput()
{
// index 1 — first step
}

[Step(2, 1001, "ProcessData", "QualityCheck")]
public void ProcessData()
{
// index 2, CEID 1001 — second step
}

[Step(10, "FinalizeProcess")]
public void Finalize()
{
// index 10 — final step
}
}

StepTimer

Provides timing control and delayed execution within steps.

[StepTimer]
public IStepTimer Timer { get; set; }

// Usage
Timer.Reserve("timeout", 5000, () => HandleTimeout()); // Execute after 5 seconds
Timer.Once("init", () => Initialize()); // Execute only once
var elapsed = Timer.TotalSeconds; // Elapsed time

FlowControl

Enables dynamic branching and jumping between steps.

[FlowControl]
public IFlowControl FlowControl { get; set; }

// Usage
FlowControl.JumpStep(5); // Jump to step 5
FlowControl.JumpStep(99); // Jump to error handling step

Import

References functionality from other packages via dependency injection.

[Import("Heater", "Heater6")]
public IReference reference;

[Import("MathReferences", "Calculator")]
private IFunction calculator;

// Usage
var result = calculator.Binding("ProcessingData");

Timeout

Sets a timeout for a FlowStep.

[FlowStep]
[Timeout(0, 0)] // min, max (0 = unlimited)
public void Step1()
{
Notify.Next();
}

GEM / SECS Attributes

Attributes used for configuring SECS/GEM semiconductor communication protocol.

AttributeTargetInjected TypeArgumentsDescription
[GEM]classDefines a SECS/GEM handler class
[GemHandler]propertyIGemHandlerInjects GEM handler
[Preset]methodDesignates initialization/configuration method
[SECS]propertyindex, MappingRuleMaps SECS message fields

GEM + GemHandler + Preset

[GEM]
public class GemHelper
{
[GemHandler]
public IGemHandler handler { get; set; } = null!;

[Preset]
private void Preset()
{
handler.SetMode(Mode.Passive); // Passive: Host initiates connection
handler.SetAddress("127.0.0.1:6000"); // HSMS address
handler.SetDevice("0"); // Device ID
handler.SetT3(45); // T3 timeout (seconds)

// Register SECS message handler
handler.OnS10F1_TerminalDisplaySingle += OnTerminalDisplay;
}

private void OnTerminalDisplay(IGemReplier replier, ReceiveSecsMessage message)
{
// Handle terminal message from host
}
}

SECS

Maps SECS message fields to C# properties. Use index for field order and MappingRule for mapping rules.

// S3F17 message structure definition
public class S3F17Message
{
[SECS(0)]
public U2 DATAID { set; get; }

[SECS(1)]
public A CARRIERACTION { set; get; }

[SECS(2)]
public A CARRIERSPEC { set; get; }

[SECS(3)]
public B PORTNUMBER { set; get; }

[SECS(4)]
public S3F17Items ITEMS { set; get; }
}

// Nested items with MappingRule
public class S3F17Items
{
[SECS(0, MappingRule.ByKey)]
public B Capacity { set; get; }

[SECS(1, MappingRule.ByKey)]
public B SubstrateCount { set; get; }

[SECS(2, MappingRule.ByKey)]
public List<ContentMap> ContentMap { set; get; }
}

SECS data types:

TypeDescription
AASCII string
BBinary (1 byte)
U1 / U2 / U4Unsigned integer (1/2/4 bytes)
I1 / I2 / I4Signed integer (1/2/4 bytes)
F4 / F8Float (4/8 bytes)
BOOLBoolean
// Receive and deserialize a message
private void OnS3F17(IGemReplier replier, ReceiveSecsMessage message)
{
var msg = message.Deserialize<S3F17Message>();
// Access msg.DATAID, msg.CARRIERACTION, etc.
}

// Send a reply
private void OnS10F5(IGemReplier replier, ReceiveSecsMessage message)
{
replier.Reply(message.SystemBytes, new ACKC(ACKC.Code.ACCEPTED));
}

Controller Attributes

Attributes used for application controllers and material handling (transfer) control.

AttributeTargetInjected TypeArgumentsDescription
[AppController]classDefines an application-level controller
[TransferController]classDefines a material handling controller
[TransferHandler]propertyITransferHandlerInjects transfer handler
[Location]method"name"Defines a wafer transfer location

AppController

Handles application-level initialization and system logic.

[AppController]
public class EQController
{
[Preset]
public void Preset()
{
// System initialization logic
}
}

TransferController + Location

Controller for wafer transfer robot control. Use [Location] to define transfer locations.

[TransferController]
public class TransferController
{
[TransferHandler]
public ITransferHandler handler { get; set; } = null!;

[Location("LP1")]
public int LP1() => -1; // -1: location not ready

[Location("LP2")]
public int LP2() => -1;

[Location("Upper")]
public int Upper() => -1;

[Location("Lower")]
public int Lower() => -1;

[Preset]
public void Preset()
{
handler.OnFlowFinished += OnFlowFinished;
}

private void OnFlowFinished(ITransferReplier replier, TransferFlowArgs e)
{
if (e.Key == "LP1Get")
{
// e.Current — current location
// e.Next — next location
// replier.RequestMove(e.Current, e.Next)
}
}
}

Document Attributes

Attributes used for extracting data from Excel/Word documents and generating .page files and C# constant classes.

AttributeTargetInjected TypeArgumentsDescription
[Document]class"filePath"Specifies source Excel/Word document path
[Save]method"pagePath", "csPath"Specifies output file paths (.page, .cs)
[ColumnHeader]propertyMaps to Excel column header
[EntryKey]propertyDesignates primary key column
[EntryProperty]propertyDesignates additional property column
[EntryDataType]propertySpecifies SECS data type

Document + Save

Converts an Excel/Word document into a .page file and a C# constants class. This is the approach used in the equipment project to generate device/io.page from IO_Map Ver2.2.docx.

Step 1: Define a model class that maps Excel columns to .page entry fields.

public class IOModel
{
[ColumnHeader, EntryProperty]
public string Pin_No { set; get; } = string.Empty;

[ColumnHeader, EntryProperty]
public string Port_NO { set; get; } = string.Empty;

[ColumnHeader, EntryKey] // This column becomes the entry Name
public string Description { set; get; } = string.Empty;

[ColumnHeader, EntryProperty]
public string Model { set; get; } = string.Empty;

[ColumnHeader, EntryProperty]
public string Bit_On { set; get; } = string.Empty;

[EntryDataType] // Default data type for all entries
public string DataType { set; get; } = "enum.OffOn";
}
AttributeRole
[ColumnHeader]Maps property to an Excel column by name
[EntryKey]Designates this column as the entry name (first field in .page)
[EntryProperty]Includes this column in the property:{...} JSON
[EntryDataType]Sets the data type field (second field in .page)

Step 2: Define the document converter with [Document] and [Save].

[Document(@"D:\PORT\SampleArduinoLib\equipment\port\IO_Map Ver2.2.docx")]
public class IODocument
{
[Save(@"D:\PORT\SampleArduinoLib\equipment\port\device\io.page",
@"D:\PORT\SampleArduinoLib\equipment\port\io1.cs")]
public Document<IOModel> Convert(Document<IOModel> doc)
{
doc.ForEach(v => v.DataType = "enum.OffOn"); // Set all entries to enum type
doc.ForEach(v => v.Package = "DigitalIO.DI"); // Link all to DigitalIO.DI package
return doc;
}
}

Step 3: Register in your MainWindow to trigger conversion.

Port.Add<IODocument>(@"D:\PORT\SampleArduinoLib\equipment\port\IO_Map Ver2.2.docx");

Generated io.page:

Main_CDA_Pressure_Switch_Check enum.OffOn pkg:DigitalIO.DI property:{"Pin_No":"1","Port_NO":"X01.00","Model":"ISE40A-C6-R-F","Bit_On":"Sensing"}
Door_Lock_On_Check enum.OffOn pkg:DigitalIO.DI property:{"Pin_No":"6","Port_NO":"X01.05","Model":"G7SA-2A2B","Bit_On":"Lock"}
FFU1_Normal_Status enum.OffOn pkg:DigitalIO.DI property:{"Pin_No":"15","Port_NO":"X01.14","Model":"MS-FC300","Bit_On":"Normal"}

Generated io1.cs:

// Auto-generated by Port. Do not edit manually.
namespace equipment
{
public static class Io1
{
public const string Main_CDA_Pressure_Switch_Check = "Main_CDA_Pressure_Switch_Check";
public const string Door_Lock_On_Check = "Door_Lock_On_Check";
public const string FFU1_Normal_Status = "FFU1_Normal_Status";
// ...
}
}

For more detailed usage, see the .NET Integration Guide.