# secs4net puts SECS-II, HSMS-SS and GEM inside a .NET app

> secs4net is a MIT licensed .NET library for talking to SEMI-compatible equipment over SECS-II, HSMS-SS and GEM, and its value is a message model you can build, inspect and reply to from ordinary C# code.

**mkjeff/secs4net** — SECS-II/HSMS-SS/GEM implementation on .NET

- Repository: https://github.com/mkjeff/secs4net
- Website: https://mkjeff.github.io/secs4net/
- Stars: 672 · Forks: 270
- Language: C#
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/mkjeff-secs4net

## A .NET message model for SECS-II, HSMS-SS and GEM

secs4net is described in one line as a SECS-II, HSMS-SS and GEM implementation on .NET, and the stated purpose is to give an easy way to communicate with SEMI-standard compatible devices. That places it in semiconductor manufacturing, where a host, a controller and a set of tools have to exchange a specific vocabulary of messages, and where the vocabulary itself, the SxFx stream numbers, is a protocol rather than an API.

What the library supplies is a message model. A SecsMessage carries a stream and function pair, a name, and an item tree built with typed helpers such as L, U4, A, B and Boolean. Items are then reachable by index, by LINQ projection, or through typed accessors, and replies are correlated by the library rather than by hand.

For the target audience this is a meaningful shift. Equipment integration in a fab is often built on a vendor SDK, which hides the message layer behind a strongly typed wrapper that only that vendor's tool can use. A general library that speaks the standard lets one codebase talk to several tools, and lets the message contents be asserted in a test.

## The alternative is a vendor SDK or a hand-rolled HSMS-SS socket

The realistic alternatives to secs4net are two, and they fail in opposite directions.

A vendor SDK is the comfortable choice when you only ever integrate one tool. It arrives with matching documentation, a simulator, and a support contact who knows the message set. The cost is that its types are the vendor's, the message layer is often hidden behind method calls, and nothing in it will talk to the next tool on the line. The same equipment bought from a second supplier means a second SDK, a second set of abstractions, and a second integration to maintain.

The other option is to write the HSMS-SS framing yourself over a socket and encode SECS-II items by hand. That gives full control and no dependencies, but it means owning the byte-level header, the length encoding, the reply correlation, the transaction timer behaviour and the item type table. The library takes all of that off your plate, and the release history shows the cost of owning it: v3.0.1 in June 2026 followed v2.4.3 from January 2024, so the two and a half year gap is where the accumulated protocol fixes live.

## Installing Secs4Net and wiring it through dependency injection

The package is distributed on NuGet, and the install step in the project documentation is a single dotnet command:

```bash
    > dotnet add package Secs4Net
```

The library is designed to live inside a host application rather than to be used standalone. The documented setup path is .NET dependency injection, with a configuration section named secs4net read from appsettings.json. That section carries four keys: DeviceId, IsActive, IpAddress and Port, with the sample values showing DeviceId 0, IsActive true, a loopback address and port 5000.

The sample project reference in the documentation is samples/DeviceWorkerService/ServiceProvider.cs, and the repository carries a matching samples directory holding DeviceWorkerService, SecsDevice and WpfVisualizer. The WpfVisualizer sample in particular suggests the intended use is a desktop or service tool that watches the conversation with the device rather than a library embedded in a machine controller.

## Building an S3F17 and reading item values back

Messages are constructed as objects, and the item tree is expressed with typed factory helpers rather than by writing type codes yourself:

```cs
    var s3f17 = new SecsMessage(3, 17)
    {
        Name = "CreateProcessJob",
        SecsItem = L(
            U4(0),
            L(
                L(
                    A("Id"),
                    B(0x0D),
                    L(
                        A("carrier id"),
```

The result is a tree you read back with indexers and typed accessors. The documented accessors cover the common cases, including a string read that resolves to the value Id in the example above:

```cs
    // access string item
    string str = s3f17.SecsItem[1][0][0].GetString(); // str = "Id"
```

There is also a FirstValue<T> accessor, a GetFirstValueOrDefault<T> with a fallback, and a GetMemory<byte> for the unmanaged case, plus a LINQ projection form that turns part of a reply into a sequence of typed records. That combination is what makes the library testable: an assertion can be written against a projected value rather than against a byte array.

One constraint is worth internalising. The count of an item is fixed when the item is created, so values can only be overwritten in existing memory, and a string item cannot be changed because the underlying C# string is immutable.

## Consuming primary messages and replying from a stream

A host application usually waits for the device to speak first, and the library exposes that as an async stream of primary messages:

```cs
await foreach (var e in secsGem.GetPrimaryMessageAsync(cancellationToken))
{     
    using var primaryMsg = e.PrimaryMessage;
    //do something for primary message

    // reply secondary message to device
    using var secondaryMsg = new SecsMessage(...);
    await e.TryReplyAsync(secondaryMsg); 
};
```

Two details in that snippet are easy to miss and costly to get wrong. The primary message is disposed with a using, and so is the reply, because the underlying buffers are pooled. The reply goes through TryReplyAsync on the event rather than through a separate send call, so the library keeps the transaction matching straight and the reply lands against the right primary message.

The same pairing applies when sending: an await on SendAsync returns the secondary message that the device sent back. So the round trip is a request, a reply, and a primary stream, and a host that handles all three is the normal case rather than an extension of the library.

## The 16,777,215 byte ceiling and pooled buffers for large items

SECS-II encodes item lengths in a limited number of bytes, and that limit shows up as a hard boundary in the library. The documentation states that the maximum encoded bytes in a single non-List item is 16,777,215, and that raw data above that is split into separate items.

For large payloads the library can build items from a Memory<T> or from an IMemoryOwner<T>, which lets a caller allocate a buffer once, fill it, and hand it over without an intermediate copy:

```cs
var largeArrayOwner = MemoryOwner<int>.Allocate(size: 65535);

// feed the value into largeArrayOwner.Memory or largeArrayOwner.Span
FillLargeArray(largeArrayOwner.Memory);
```

The sample uses the IMemoryOwner<T> implementation from Microsoft.Toolkit.HighPerformance, and the library references it internally. The same mechanism applies on the receive side, because the item decoded by PipeDecoder also uses a MemoryOwner<T> when the data array is large.

The cost of that design is that IMemoryOwner<T>, Item and SecsMessage all implement IDisposable, and a forgotten Dispose keeps the array out of the pool until the garbage collector runs. In a service that handles thousands of messages a second, disposing is not optional bookkeeping.

## Timeouts, error replies and what the documentation leaves open

Failures in this protocol arrive in two forms, and the library groups them under one exception type. The documented catch block covers a T3 timeout, a device reply of SxF0, and a device reply of S9Fx:

```cs
catch(SecsException)
{
    // exception  when
    // T3 timeout
    // device reply SxF0
    // device reply S9Fx
}
```

That grouping is convenient and also coarse. A timeout, a fatal system error and an abort reply are different operational events, and a host that wants to retry the first while alarming on the third has to inspect the exception rather than the catch clause alone. The documentation does not describe how to configure the T3 timer value, nor does it document a retry policy, so those behaviours have to be confirmed against the source before a production host relies on them.

The documentation also says little about what happens to a partially delivered message or about reconnection after a socket drop, and there is no note about rolling back a transaction that timed out after the device had already acted. Those are questions for the maintainer, not gaps you can fill by reading the samples.

## MIT licence, v3.0.1, and the gap since v2.4.3

The package is released under the MIT Licence, and the project documentation hosts the published pages at mkjeff.github.io/secs4net, with the source and its CI badges in the same repository. The repository layout shows a conventional .NET solution, with secs4net.slnx at the root, src and test directories, a Directory.Build.props, a global.json, a common directory and a common.json and common.sml file, plus a LINQPad.md file that suggests the library is meant to be poked at interactively.

The release history needs attention. v3.0.1 was published on 2026-06-07, v2.4.3 on 2024-01-20 and v2.4.2 on 2024-01-04. The repository is not archived and the last push was on 2026-08-12, so work continues after the current tag, and the gap between the 2.x and 3.x lines is a major version jump that deserves a diff before any production upgrade.

MIT terms mean you can use the library inside a proprietary host tool without licensing exposure beyond attribution, which is one of the practical reasons this approach is chosen over a vendor SDK. That is a licensing observation, not advice on how to structure your own product.

## Conclusion

secs4net fits .NET teams integrating a tool with a fab host or equipment simulator, and it fits people who want to see and assert on the actual SxFx message rather than a vendor specific wrapper API. It does not fit a C# shop that has no contact with SEMI standards, since there is nothing in the package to learn without that context. Before adopting it, confirm your equipment speaks the HSMS-SS framing you need, check the v3.0.1 package against the 2.4.3 line you may already have in production, and read one message from your own tool with GetPrimaryMessageAsync before designing around the reply shape.

## FAQ

### How do I install secs4net in a .NET project?

The documented install step is a single dotnet command that adds the NuGet package: dotnet add package Secs4Net. The package is published on NuGet as Secs4Net.

### How is the device connection configured in secs4net?

Through dependency injection and a secs4net section in appsettings.json, registered with services.AddSecs4Net<DeviceLogger>(Configuration). The documented configuration keys are DeviceId, IsActive, IpAddress and Port.

### How does secs4net report a device timeout or an error reply?

It throws a SecsException. The documented cases are a T3 timeout, a device reply of SxF0 and a device reply of S9Fx, all caught with a single SecsException catch clause.

### How large can a single secs4net item be?

The maximum encoded bytes in a single non-List item is 16,777,215, which is three bytes of length. Larger raw data has to be split into separate items, and creating them from sliced Memory<T> is more efficient.

### What is the licence of secs4net and when was it last released?

It is released under the MIT Licence. The most recent release is v3.0.1, published on 2026-06-07, and the last push to the repository was on 2026-08-12.

## Sources

- [License: MIT](https://github.com/mkjeff/secs4net/blob/base/LICENSE)
- [mkjeff/secs4net on GitHub](https://github.com/mkjeff/secs4net)
- [Project website](https://mkjeff.github.io/secs4net/)
- [README](https://github.com/mkjeff/secs4net/blob/base/README.md)
- [Releases](https://github.com/mkjeff/secs4net/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mkjeff-secs4net
