PDComm.HsmsEndpoint
Class
A synchronous HSMS (SEMI E37) endpoint that exchanges SECS-II messages over TCP/IP.
public sealed class HsmsEndpoint : IDisposableThe endpoint creates no threads and no callbacks: your code drives it. Call HsmsEndpoint.Start, then repeatedly call HsmsEndpoint.Poll to advance timers and socket I/O and HsmsEndpoint.NextEvent to read state changes, received messages and failures. An active endpoint connects and sends Select.req by itself; a passive endpoint binds its listening socket in HsmsEndpoint.Create. For a ready-made polling loop, use HsmsWorker.
Every method takes an internal lock, so calls from several threads are serialized. HsmsEndpoint.Poll can hold the lock for up to HsmsOptions.ConnectTimeoutMilliseconds during a connection attempt.
The endpoint owns a native handle. For a graceful close, call HsmsEndpoint.Stop, keep polling and reading events until HsmsState.Closed is true, then call HsmsEndpoint.Dispose. Disposing earlier releases the resources without a graceful wire shutdown. Events returned by HsmsEndpoint.NextEvent own their data and stay valid after the endpoint is disposed.
Success of HsmsEndpoint.Request and similar methods only means the message was queued; the outcome arrives later as an event that carries the same HsmsToken.
PdcommRuntime.Initialize(libraryPath);
using var endpoint = HsmsEndpoint.Create("127.0.0.1:5000", options); // options.Mode == HsmsMode.Active
endpoint.Start();
HsmsToken request = default;
while (true)
{
endpoint.Poll();
if (request == default && endpoint.GetState().State == HsmsConnectionState.Selected)
{
request = endpoint.Request(1, 1, true, ReadOnlySpan<byte>.Empty); // S1F1 W
}
using HsmsEvent? next = endpoint.NextEvent();
if (next?.GetInfo() is { Kind: HsmsEventKind.Received, IsReply: true } info && info.Token == request)
{
Console.WriteLine($"S{info.Header!.Value.Stream}F{info.Header.Value.Function}, {info.BodyLength} bytes");
break;
}
}Members
Cancel
Method
Cancels an open transaction of this endpoint.
public bool Cancel(HsmsToken token)A cancelled request completes with a HsmsFailureReason.Cancelled failure event. Cancelling a partially written message may close the connection; bytes already on the wire are not retracted.
Parameters
| Name | Description |
|---|---|
token | The token returned when the transaction started. |
Returns
true if the transaction was open and is now cancelled; otherwise false.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The native call failed.
Create
Method
Creates an HSMS endpoint.
public static HsmsEndpoint Create(string numericAddress, HsmsOptions options)Parameters
| Name | Description |
|---|---|
numericAddress | A numeric IPv4 or IPv6 socket address such as 127.0.0.1:5000 or [::1]:5000; host names are not resolved. An active endpoint connects to it; a passive endpoint listens on it (port 0 selects a free port, see HsmsEndpoint.GetLocalAddress). |
options | The role, session, timers and limits of the endpoint. |
Returns
A new endpoint that the caller owns and must dispose.
Notes
- Throws
ArgumentNullException:numericAddressoroptionsisnull. - Throws
EncoderFallbackException:numericAddresscontains an unpaired surrogate. - Throws
PdcommException: The address is not a numeric socket address or an option is zero or invalid (PdcommStatus.InvalidArgument), the limits are inconsistent (PdcommStatus.LimitExceeded), or a passive endpoint could not bind its socket (PdcommStatus.IoError).
Deselect
Method
Sends Deselect.req to end the selected HSMS session without closing the connection.
public HsmsToken Deselect()Returns
The token of the control transaction; its outcome arrives as an event.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The session is not selected (PdcommStatus.InvalidState), or a Deselect is already pending (PdcommStatus.Backpressure).
Dispose
Method
Releases the native endpoint and closes its sockets.
public void Dispose()Disposal does not perform a graceful HSMS shutdown; call HsmsEndpoint.Stop and drain events first for that. Events already taken from the endpoint stay valid. Calling this method more than once has no effect.
GetLocalAddress
Method
Gets the local socket address, for example the port a passive endpoint actually listens on.
public string GetLocalAddress()Returns
The numeric local socket address, such as 127.0.0.1:50123.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: No socket is open, for example on an active endpoint before it connects (PdcommStatus.IoError).
GetState
Method
Gets the endpoint's connection state.
public HsmsState GetState()Returns
A snapshot of the endpoint state.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The native call failed.
IsPending
Method
Determines whether a transaction of this endpoint is still open.
public bool IsPending(HsmsToken token)Parameters
| Name | Description |
|---|---|
token | The token returned when the transaction started. |
Returns
true if the transaction has not completed yet; otherwise false.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The native call failed.
Linktest
Method
Sends Linktest.req to check that the connection is alive.
public HsmsToken Linktest()Returns
The token of the control transaction; a failure within T6 arrives as a HsmsEventKind.Failed event.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: No connection is open (PdcommStatus.InvalidState), or a Linktest is already pending (PdcommStatus.Backpressure).
NextEvent
Method
Takes the next queued event.
public HsmsEvent? NextEvent()An empty queue does not mean the session is finished; keep polling.
Returns
The next event, which the caller owns and must dispose, or null when no event is queued.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The event could not be allocated (PdcommStatus.AllocationFailed; the event stays queued, so retry), or the endpoint is poisoned.
Poll
Method
Advances timers, connection handling and socket I/O.
public nuint Poll()Can block for up to HsmsOptions.ConnectTimeoutMilliseconds during a connection attempt.
Returns
The number of internal actions performed, at most HsmsOptions.PollBudget. This is not the number of events produced, and zero does not mean the session is finished.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The event queues are full (PdcommStatus.Backpressure; read events withHsmsEndpoint.NextEventfirst), or the endpoint failed.
Reply
Method
Queues the reply to a received primary message.
public void Reply(HsmsEvent primary, byte stream, byte function, bool replyExpected, ReadOnlySpan<byte> body)Parameters
| Name | Description |
|---|---|
primary | The received primary event that expects a reply. |
stream | The reply's stream number, normally the primary's stream. |
function | The reply's function number, normally the primary's function plus one, or 0 to abort. |
replyExpected | Whether to set the W bit on the reply; normally false. |
body | One complete encoded SECS-II item, or an empty span for a header-only reply. |
Notes
- Throws
ArgumentNullException:primaryisnull. - Throws
ObjectDisposedException: The endpoint orprimaryhas been disposed. - Throws
PdcommException:primarybelongs to another endpoint or connection (PdcommStatus.StaleToken), was already answered or is not a primary that expects a reply (PdcommStatus.InvalidArgument), the body exceeds the frame or item limits (PdcommStatus.LimitExceeded), or the reply cannot be queued.
Request
Method
Queues a primary data message.
public HsmsToken Request(byte stream, byte function, bool replyExpected, ReadOnlySpan<byte> body)The body is copied. Success means the message was queued. If replyExpected is true, a HsmsEventKind.Received reply or a HsmsEventKind.Failed event with the returned token completes the transaction; otherwise a HsmsEventKind.W0Written event reports the local write.
Parameters
| Name | Description |
|---|---|
stream | The SECS-II stream number (0 to 127). |
function | The SECS-II function number; primary messages use odd numbers. |
replyExpected | Whether to set the W bit and wait for a reply within T3. |
body | One complete encoded SECS-II item, or an empty span for a header-only message. |
Returns
The token that identifies the transaction in later events.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The session is not selected (PdcommStatus.InvalidState), too many transactions or bytes are queued (PdcommStatus.Backpressure), the body exceeds the frame or item limits (PdcommStatus.LimitExceeded), or the body is not a valid SECS-II item.
Select
Method
Sends Select.req to select the HSMS session.
public HsmsToken Select()An active endpoint selects automatically after connecting; use this method to select again.
Returns
The token of the control transaction; its outcome arrives as an event.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The connection is not in theHsmsConnectionState.NotSelectedstate (PdcommStatus.InvalidState), or a Select is already pending (PdcommStatus.Backpressure).
Start
Method
Starts connecting (active) or listening (passive).
public void Start()Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The endpoint cannot start in its current state.
Stop
Method
Begins a graceful shutdown of the connection.
public void Stop()Keep calling HsmsEndpoint.Poll and HsmsEndpoint.NextEvent until HsmsEndpoint.GetState reports HsmsState.Closed; the shutdown is bounded by HsmsOptions.ShutdownTimeoutMilliseconds.
Notes
- Throws
ObjectDisposedException: The endpoint has been disposed. - Throws
PdcommException: The endpoint cannot stop in its current state.