secs4net

repository·base·Indexed 20 days ago

https://github.com/mkjeff/secs4net

.NET implementation of SECS-II, HSMS-SS, and GEM standards for high-performance communication with semiconductor equipment. Features include support for SecsMessage and SecsItem hierarchies, .NET Dependency Injection integration via AddSecs4Net, and memory-efficient handling of large data using IMemoryOwner.

Tokens
2.3K
Snippets
8
Records
8
Agent score
21%

What's inside secs4net

  1. Simulate HSMS-SS/SECS-II devices with Secs4Net

    base

    The SecsDevice sample program allows you to simulate either a device or a host to communicate with other HSMS-SS/SECS-II compliant devices. It serves as a demonstration of how to send and reply to messages using the SECS-II protocol.

    To interact with the demo, you can use SML (SECS Message Language) format to define messages. Ensure you include the closing angle brackets for list items.

    S6F11ReadyToLoad: 'S6F11' W 
        <L [3]
            <U4 [1] 320 >
            <U2 [1] 114 > 
            <L [1]
                <L [2]
                    <U2 [1] 500 >
                    <L [1]
                        <U1 [1] 1 > 
                     >
                 >
             >
         >
    .
  2. Reuse arrays for large item values using IMemoryOwner

    base

    For large unmanaged data, you can create an Item directly from IMemoryOwner<T> or Memory<T>. This is more efficient than allocating new arrays. Note that IMemoryOwner<T>, Item, and SecsMessage all implement IDisposable; you must dispose of them to return the memory to the pool.

    // Using Microsoft.Toolkit.HighPerformance
    var largeArrayOwner = MemoryOwner<int>.Allocate(size: 65535);
    FillLargeArray(largeArrayOwner.Memory);
    
    using var s6f11 = new SecsMessage(6, 11, replyExpected: false)
    {
        Name = "LargeDataEvent",
        SecsItem = L(
            L(
                I2(1121),
                A(""),
                I4(largeArrayOwner)), // Create Item from IMemoryOwner
        );
    }
    
    // When receiving large messages, the decoded items also use MemoryOwner
    using var s6f12 = await secsGem.SendAsync(s6f11);
  3. Configure Secs4Net via .NET Dependency Injection

    base

    Register Secs4Net in your service collection using AddSecs4Net<TLogger>(IConfiguration). The configuration should be provided via an appsettings.json file under a secs4net section. You must implement the ISecsGemLogger interface to handle logging.

    // appsettings.json configuration example:
    // "secs4net": {
    //   "DeviceId": 0,
    //   "IsActive": true,
    //   "IpAddress": "127.0.0.1",
    //   "Port": 5000
    // }
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSecs4Net<DeviceLogger>(Configuration); 
    }
    
    class DeviceLogger : ISecsGemLogger
    {
        // implement ISecsGemLogger methods
    }
  4. Create and send a SecsMessage

    base

    Use the SecsMessage constructor to define the Stream and Function (e.g., 3, 17). You can build the SecsItem hierarchy using helper methods like L (List), U4 (Unsigned 4-byte), A (ASCII string), B (Binary), and Boolean. Use secsGem.SendAsync(message) to send the message and await the secondary response.

    try
    {
        var s3f17 = new SecsMessage(3, 17)
        {
            Name = "CreateProcessJob",
            SecsItem = L(
                U4(0),
                L(
                    L(
                        A("Id"),
                        B(0x0D),
                        L(
                            A("carrier id"),
                            L(U1(1)),
                            L(
                                U1(1),
                                A("recipe"),
                                L()
                            ),
                            Boolean(true),
                            L()
                        )
                    )
                )
            )
        };
    
        // await the secondary message
        var s3f18 = await secsGem.SendAsync(s3f17); 
    }
    catch(SecsException)
    {
        // Handle T3 timeout, SxF0 reply, or S9Fx reply
    }
  5. Create SecsItems using LINQ

    base

    You can use LINQ to transform domain objects into a SecsItem structure. This is particularly useful when mapping complex collections to nested SECS-II lists.

    using static Secs4Net.Item;
    
    var s16f15 = new SecsMessage(16, 15)
    {
        Name = "CreateProcessJob",
        SecsItem = L(
            U4(0),
            L(
                from pj in tx.ProcessJobs 
                select L(
                    A(pj.Id),
                    B(0x0D),
                    L(
                        from carrier in pj.Carriers 
                        select L(
                            A(carrier.Id),
                            L(
                                from slotInfo in carrier.SlotMap 
                                select U1(slotInfo.SlotNo)
                            )
                        ),
                        L(
                            U1(1),
                            A(pj.RecipeId),
                            L()
                        ),
                        Boolean(true),
                        L()
                    )
                )
            )
        )
    };
  6. Handle primary messages with GetPrimaryMessageAsync

    base

    To process incoming primary messages from a device, use GetPrimaryMessageAsync. This returns an enumerable of messages that you can iterate through. Use e.TryReplyAsync(secondaryMsg) to send a response back to the device.

    await foreach (var e in secsGem.GetPrimaryMessageAsync(cancellationToken))
    {
        using var primaryMsg = e.PrimaryMessage;
        // process primaryMsg
    
        using var secondaryMsg = new SecsMessage(...);
        await e.TryReplyAsync(secondaryMsg); 
    }
  7. Access and manipulate SecsItem values

    base

    You can navigate the SecsItem hierarchy using indexers. For unmanaged data, use FirstValue<T>() to retrieve or overwrite values, GetFirstValueOrDefault<T>(fallback) for safe access, and GetMemory<T>() to access the underlying memory. String items can be accessed via GetString().

    // Access list items
    s3f17.SecsItem[1][0][0] == A("Id"); 
    
    // Access unmanaged array items
    byte b2 = s3f17.SecsItem[0].FirstValue<byte>();
    s3f17.SecsItem[0].FirstValue<byte>() = 0; // Overwrite existing memory
    byte b3 = s3f17.SecsItem[0].GetFirstValueOrDefault<byte>(fallbackValue);
    Memory<byte> bytes = s3f17.SecsItem[0].GetMemory<byte>();
    
    // Access string items
    string str = s3f17.SecsItem[1][0][0].GetString();