portdic 1.1.81

dotnet add package portdic --version 1.1.81
                    
NuGet\Install-Package portdic -Version 1.1.81
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="portdic" Version="1.1.81" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="portdic" Version="1.1.81" />
                    
Directory.Packages.props
<PackageReference Include="portdic" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add portdic --version 1.1.81
                    
#r "nuget: portdic, 1.1.81"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package portdic@1.1.81
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=portdic&version=1.1.81
                    
Install as a Cake Addin
#tool nuget:?package=portdic&version=1.1.81
                    
Install as a Cake Tool

PortDic

PortDic is a comprehensive .NET library for industrial automation and communication systems. It provides standardized methods for interacting with industrial automation systems, equipment control, and data acquisition with support for multiple communication protocols.

About

PortDic package provides a complete framework for building industrial automation applications with:

  • Annotation-Based Package System: Declarative programming model using attributes for package registration, API generation, and dependency injection
  • Workflow and Flow Control: Sequential workflow execution with conditional watchers, timeouts, and notifications
  • Protocol Integration: Support for SECS/GEM, MQTT, RTSP, and OPC UA protocols
  • Real-time Data Management: Type-safe data setting and retrieval with event-driven architecture
  • Broadcasting System: Multi-protocol communication management
  • REST API Generation: Automatic endpoint creation from annotations
  • Simple Communication Classes: High-performance asynchronous serial port and TCP communication with automatic reconnection

All features are designed for production use with comprehensive error handling, validation, and thread-safe operations.

Key Features

Annotation System

PortDic uses a comprehensive annotation system for declarative programming:

Category Annotations Purpose
Package Management [Package], [Flow], [Import] Class registration and dependency injection
Workflow Control [Step], [Notify], [WatcherCompare], [WatcherAction], [Timeout] Workflow execution with conditional logic
API Endpoints [API], [Command] REST API generation
Data Handling [Property], [Mapping], [ModelProperty] Data management and transformation
Validation [Valid] Data validation and business rules
Documentation [Comment], [EnumCode] API documentation and enum exposure
Logging [Logger] Dependency injection for logging services

Core Capabilities

  • Real-time Data Exchange: Type-safe data setting and retrieval with automatic type conversion
  • Event-Driven Architecture: Comprehensive event handling for status changes, occurrences, and requests
  • Package Injection: Automatic dependency resolution and inter-package communication
  • Flow Control: Complex workflow management with conditional watchers and timeouts
  • Protocol Support: Industrial communication protocols (SECS/GEM, OPC UA, MQTT, RTSP)
  • Configuration Builder: Fluent interface for protocol configuration
  • Performance Monitoring: Built-in profiling and monitoring capabilities
  • Reference Model: Support for mapping multiple entry keys to reference objects

How to Use

Initialization and Setup

using portdic;

private static IPortDic portdic = Port.GetDictionary("sample");
private static GEM gem = portdic.BroadCast<GEM>();

public FormMain()
{
    InitializeComponent();
    
    // Register packages
    portdic.Add<SampleFlow>("SampleFlow");
    portdic.Add<Bulb>("Bulb1");
    portdic.Add<Bulb>("Bulb5");
    portdic.Add<Heater>("Heater1");
    portdic.Add<Heater>("Heater5");
    portdic.Add<Serial>("COM12");
    
    // Register reference with mapping
    [Import("Heater", "Heater6")]
    public IReference reference;
    
    portdic.Add(ref reference, new ReferenceModel()
    {
        { "Temp1", Room1.RoomTemp1 },
        { "Temp2", Room1.RoomTemp2 },
    });
    
    // Event handlers
    portdic.OnOccurred += Port_OnOccurred;
    portdic.OnStatusChanged += Port_OnStatusChanged;
    portdic.OnRequest += Port_OnRequest;
    
    // GEM event handlers
    gem.OnStatusChanged += Gem_OnStatusChanged;
    gem.OnEvent += Gem_OnEvent;
    gem.OnS2F37_EnableDisableEventReport += Gem_OnS2F37_EnableDisableEventReport;
    gem.OnS10F5_TerminalDisplayMultiBlock += Gem_OnS10F5_TerminalDisplayMultiBlock;
    gem.OnS2F33_DefineReport += Gem_OnS2F33_DefineReport;
    gem.OnS6F11_EventReportSend += Gem_OnS6F11_EventReportSend;
    gem.OnS3F17_CarrierActionRequest += Gem_OnS3F17_CarrierActionRequest;
    gem.OnS7F1_ProcessProgramLoadInquire += Gem_OnS7F1_ProcessProgramLoadInquire;
    
    // Start the Port system
    portdic.Run();
}

Event Handling

Status Change Events
private void Port_OnStatusChanged(object sender, PortStatusArgs e)
{
    switch (e.Status)
    {
        case PortStauts.Idle:
            break;
        case PortStauts.Executed:
            break;
        case PortStauts.Stopped:
            break;
        case PortStauts.Shutdown:
            break;
        case PortStauts.Failed:
            break;
        case PortStauts.Synchronized:
            OnReady = true;
            break;
    }
}
Occurrence Events
private void Port_OnOccurred(object sender, PortEventArgs e)
{
    switch (e.EventType)
    {
        case EventType.Reject:
            Console.WriteLine(e.Message);
            break;
        // Other event types: Info, Warning, Error
    }
}
Request Events
private void Port_OnRequest(object sender, PortRequestArgs e)
{
    Console.WriteLine(string.Join(" ", e.Flags));
}

Package Development with Annotations

Basic Package Example
using portdatatype;
using portdic;

[Package]
public class Bulb
{
    [Logger]
    public ILogger Logger { get; set; }

    [Property]
    public IProperty Property { get; set; }

    [API]
    public string Comport
    {
        set
        {
            // Handle comport setting logic
            Logger.Write($"Comport set to: {value}");
        }
        get
        {
            return comport;
        }
    }

    [API(EntryDataType.Enum)]
    public string OffOn
    {
        set
        {
            // Handle on/off state
        }
        get
        {
            return offon;
        }
    }

    [Valid("Invalid bulb state")]
    public bool Valid()
    {
        return true;
    }
}
Package with Property Format
[Package]
public class Heater
{
    [Logger]
    public ILogger Logger { get; set; }
    
    [Property]
    public IProperty Property { get; set; }

    [API(EntryDataType.Char)]
    public string Power
    {
        set
        {
            Trace.WriteLine($"Power {value}");
        }
        get
        {
            return "12345678910";
        }
    }

    [API(EntryDataType.Num, PropertyFormat.Json, "Unit")]
    public double Temp
    {
        get
        {
            if (this.Property != null)
            {
                if (this.Property.TryToGetValue("Unit", out string unit))
                {
                    if (unit == "F")
                    {
                        return (r.NextDouble() * 9 / 5) + 32;
                    }
                    else if (unit == "C")
                    {
                        return r.NextDouble();
                    }
                }
            }
            return double.NaN;
        }
    }

    [Valid("Invalid for connection")]
    public bool Valid()
    {
        return true;
    }
}
Workflow with Flow Control and Watchers
[Flow]
public class SampleFlow
{
    [Notify]
    public INotify Notify { get; set; }

    [Step]
    [WatcherCompare(Room1.Heater5Temp1, ">=", 50)]
    [WatcherCompare(Room1.Heater5Temp2, ">=", 50)]
    [WatcherAction(Room1.Bulb1OnOff5, "Off")]
    [Timeout(0, 0)]
    public void Step1()
    {
        Notify.Alert("hello ~~~~");
        Task.Delay(1000).Wait();
        Notify.Next();
    }

    [Step(nameof(Step1))]
    [WatcherCompare(Room1.Heater5Temp1, "<", 50)]
    [WatcherCompare(Room1.Heater5Temp2, "<", 50)]
    [WatcherAction(Room1.Bulb1OnOff5, "On")]
    [Timeout(0, 0)]
    public void Step2()
    {
        Task.Delay(1000).Wait();
        Notify.Next();
    }

    [Step(nameof(Step2))]
    [WatcherCompare(Room1.Heater5Temp1, ">", 30)]
    [WatcherCompare(Room1.Heater5Temp2, ">", 30)]
    [WatcherAction(Room1.Bulb1OnOff5, "Off")]
    [Timeout(0, 0)]
    public void Step3()
    {
        Task.Delay(1000).Wait();
        Notify.Next();
    }
}

SET/GET Operations

// Setting values using entry key string
if (portdic.Set(selectKey.Text, setValue.Text))
{
    MessageBox.Show($"Success: {selectKey.Text} = {setValue.Text}");
}
else
{
    MessageBox.Show($"Failed: {selectKey.Text} = {setValue.Text}");
}

// Setting values using entry constants
portdic.Set(Room1.BulbOnOff, "On");
portdic.Set(Com12.Split, "0x0A");
portdic.Set(Com12.Message, "Hello");

// Getting values - returns string representation
string value = portdic.Get(entryKey)?.String();
string temp1 = portdic.Get(Room1.RoomTemp1)?.String();

// Setting flow actions
Port.GetDictionary("Sample").Set("SampleFlow", FlowAction.Executing);
Port.GetDictionary("Sample").Set("SampleFlow", FlowAction.Initialization);

// Alternative syntax
portdic["room1"].Set("BulbOnOff", "Off");

Entry Key Constants

Entry keys can be defined as constants for type-safe access:

public static class Room1
{
    public const string BulbOnOff = "room1.BulbOnOff";
    public const string RoomTemp1 = "room1.RoomTemp1";
    public const string RoomTemp2 = "room1.RoomTemp2";
    public const string Heater5Temp1 = "room1.Heater5Temp1";
    // ... more entries
}

// Usage
portdic.Set(Room1.BulbOnOff, "On");
string temp = portdic.Get(Room1.RoomTemp1)?.String();

Protocol Integration

GEM (SECS/GEM) Integration
// Get GEM broadcast instance
private static GEM gem = portdic.BroadCast<GEM>();

// Or create with builder
var gem = portdic.BroadCast<GEM>(Port.CreateBuilder(BroadcastType.GEM)
    .Mode(Mode.Active)
    .Listen("127.0.0.1:5000")
    .DeviceID("EQ001")
    .T1(10).T2(5).T3(10)
    .Build());

// Handle GEM events
gem.OnStatusChanged += (time, statustext) => 
{
    Console.WriteLine(statustext);
};

gem.OnEvent += (time, eventtext) => 
{
    Console.WriteLine(eventtext);
};

gem.OnS2F37_EnableDisableEventReport += (replier, message) => 
{
    replier.Reply(message.SystemBytes, new ERACK(EventReportAcknowledge.Accepted));
};

gem.OnS2F33_DefineReport += (replier, message) => 
{
    replier.Reply(message.SystemBytes, new ACKC(ACKC.Code.ACCEPTED));
};

gem.OnS10F5_TerminalDisplayMultiBlock += (replier, message) => 
{
    replier.Reply(message.SystemBytes, new ACKC(ACKC.Code.ACCEPTED));
};

gem.OnS3F17_CarrierActionRequest += (replier, message) => 
{
    var v = message.Deserialize<S3F17Message>();
    // Process carrier action request
};

gem.OnS7F1_ProcessProgramLoadInquire += (replier, message) => 
{
    var v = message.Deserialize<S7F11Message>();
    // Process program load inquire
};
GEM Message Deserialization
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 S3F17MessageItem ITEMS { set; get; } = new S3F17MessageItem();
}

public class S3F17MessageItem
{
    [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(3, MappingRule.ByKey)]
    public List<U1> SlotMap { set; get; }

    [SECS(4, MappingRule.ByKey)]
    public A Usage { set; get; }
}
MQTT Integration
var mqtt = portdic.BroadCast<MQTT>(Port.CreateBuilder(BroadcastType.MQTT)
    .Listen("127.0.0.1:1883")
    .Users(new User("admin", "admin"))
    .AllowRemotes("127.0.0.1")
    .ClientId("PortClient")
    .QoS(1)
    .Build());
OPC UA Integration
var opcua = portdic.BroadCast<OPCUA>(Port.CreateBuilder(BroadcastType.OPCUA)
    .Listen("opc.tcp://localhost:4840")
    .ApplicationInfo("PortApp", "urn:PortApp", "urn:PortApp")
    .SecurityConfig(SecurityMode.SignAndEncrypt, SecurityPolicy.Basic256Sha256)
    .Credentials("admin", "password")
    .Build());

Performance Monitoring

// Enable profiling
portdic.Profile();

// Performance test example
var t1 = DateTime.Now;
int count = 0;

while (count < 10000)
{
    portdic.Set(Room3.BulbOnOff, "On");
    count++;
}

var t2 = (DateTime.Now - t1).TotalMilliseconds;
Trace.WriteLine($"SPEND TIME: {t2} (ms)");

Simple Communication Classes

Serial Port Communication
using portdic.simple;

public class MySerial : AsyncSerial
{
    public MySerial()
    {
        portName = "COM3";
        baudRate = 9600;
        delimiter = "\n";

        this.DataReceived += (sender, message) => 
        {
            Console.WriteLine($"Received: {message}");
        };
        this.ReconnectSuccess += (sender, e) => 
        {
            Console.WriteLine("Reconnected successfully");
        };
    }

    public override void LogWrite(string log)
    {
        Console.WriteLine(log);
    }
}

// Usage
var serial = new MySerial();
await serial.ConnectAsync();
await serial.SendAsync("Hello World!");
TCP Server
using portdic.simple;

public class MyTCPServer : AsyncTCPServer
{
    public MyTCPServer()
    {
        this.port = "5000";
        this.ClientConnected += (sender, client) => 
        {
            Console.WriteLine($"Client connected: {client.RemoteEndPoint}");
        };
        this.DataReceived += async (sender, data) => 
        {
            Console.WriteLine($"Received from {data.Client.Id}: {data.Message}");
            await this.SendToClientAsync(data.Client, "Echo: " + data.Message);
        };
    }

    public override void LogWrite(string log)
    {
        Console.WriteLine(log);
    }
}

// Usage
var server = new MyTCPServer();
await server.StartAsync();

// Broadcast to all clients
await server.BroadcastAsync("Server message");
TCP Client
using portdic.simple;

public class MyTCPClient : AsyncTCPClient
{
    public MyTCPClient() 
    {
        this.host = "127.0.0.1";
        this.port = "5000";

        this.Connected += (sender, e) => 
        {
            Console.WriteLine("Connected to server");
        };
        this.DataReceived += (sender, message) => 
        {
            Console.WriteLine($"Received: {message}");
        };
        this.ReconnectSuccess += (sender, e) => 
        {
            Console.WriteLine("Reconnected successfully");
        };
    }

    public override void LogWrite(string log)
    {
        Console.WriteLine(log);
    }
}

// Usage
var client = new MyTCPClient();
await client.ConnectAsync();
await client.SendAsync("Hello Server!");
Ring Buffer
using portdic.simple;
using System.Text;

// Create a ring buffer with capacity (must be power of 2)
var buffer = new RingBuffer<byte>(1024);

// Producer: Write data
byte[] data = Encoding.UTF8.GetBytes("Hello");
int written = buffer.Write(data);

// Consumer: Read data
byte[] output = new byte[1024];
int bytesRead = buffer.Read(output);
string message = Encoding.UTF8.GetString(output, 0, bytesRead);

// Single item operations
if (buffer.TryWrite(0x42))
{
    if (buffer.TryRead(out byte value))
    {
        Console.WriteLine($"Read: {value}");
    }
}

// Peek without consuming
if (buffer.TryPeek(out byte peekValue))
{
    Console.WriteLine($"Peeked: {peekValue}");
}

Main Types

The main types provided by this library are:

Core Types

  • IPortDic: Main interface for port dictionary communication, real-time data exchange, and protocol management
  • Port: Factory class for creating port dictionary instances
  • PortDic: Core implementation of the port dictionary system

Annotation Attributes

  • [Package]: Attribute for marking classes as Port-managed packages
  • [Flow]: Attribute for defining workflow classes
  • [API]: Attribute for automatic REST API endpoint generation
  • [Step]: Attribute for marking workflow steps
  • [Import]: Attribute for dependency injection
  • [Property]: Attribute for mapping properties to Entry Properties
  • [Valid]: Attribute for data validation and business rules
  • [Command]: Attribute for marking methods as command endpoints
  • [Logger]: Attribute for dependency injection of logging services
  • [Notify]: Attribute for workflow notification services
  • [WatcherCompare]: Attribute for conditional workflow step execution
  • [WatcherAction]: Attribute for automatic actions on workflow steps
  • [Timeout]: Attribute for workflow step timeout configuration

Interfaces

  • IFlowControl: Interface for workflow control and navigation
  • IStepTimer: Interface for timing and scheduling workflow steps
  • IReference: Interface for function references and collections
  • INotify: Interface for workflow notifications and alerts
  • ILogger: Interface for logging services
  • IProperty: Interface for property access and configuration
  • IGemReplier: Interface for GEM message replies

Enums and Status Types

  • PortStauts: Port status enumeration (Idle, Executed, Stopped, Shutdown, Failed, Synchronized)
  • EventType: Event type enumeration (Info, Warning, Error, Reject)
  • FlowAction: Flow action enumeration (Executing, Initialization, etc.)
  • EntryDataType: Entry data type enumeration (String, Num, Char, Enum, etc.)
  • PropertyFormat: Property format enumeration (Json, etc.)

Simple Communication Classes

  • AsyncSerial: Abstract base class for asynchronous serial port communication with automatic reconnection
  • AsyncTCPServer: Production-ready asynchronous TCP server with client management and 24/7 stability
  • AsyncTCPClient: High-availability asynchronous TCP client with automatic reconnection
  • ClientContext: Represents the context for a connected TCP client, including connection information and message buffering
  • RingBuffer<T>: Lock-free, zero-allocation ring buffer for high-performance scenarios. Thread-safe for single producer and single consumer operations

Protocol Classes

  • GEM: SECS/GEM protocol implementation
  • MQTT: MQTT protocol implementation
  • OPCUA: OPC UA protocol implementation
  • RTSP: RTSP protocol implementation

Additional Documentation

Requirements

  • .NET Standard 2.0 or higher
  • System.IO.Ports package (for serial port functionality)

Feedback & Contributing

PortDic is released as open source. Bug reports and contributions are welcome. Please report issues and submit pull requests through the project repository.

For additional support and examples, refer to the PortDic Documentation.

License

Please refer to the license file included with this package for license information.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on portdic:

Package Downloads
Port.SDK

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.81 0 3/15/2026
1.1.80 41 3/10/2026
1.1.79 74 3/9/2026
1.1.78 84 3/2/2026
1.1.77 466 12/9/2025
1.1.76 457 12/8/2025
1.1.75 305 11/12/2025
1.1.74 308 11/11/2025
1.1.73 228 11/9/2025
1.1.72 201 10/14/2025
1.1.71 210 10/13/2025
1.1.70 148 10/12/2025
1.1.69 200 9/30/2025
1.1.68 176 9/28/2025
1.1.67 207 9/25/2025
1.1.66 211 9/23/2025
1.1.65 228 9/22/2025
1.1.64 242 9/21/2025
1.1.63 262 9/14/2025
1.1.62 208 9/10/2025
Loading failed