SLMP .NET User Guide
This guide documents the recommended high-level API surface.
For normal application code, prefer the extension methods on SlmpClient and QueuedSlmpClient.
Recommended Connection Pattern
Create a connected queued client with explicit stable settings:
using PlcComm.Slmp;
var options = new SlmpConnectionOptions("192.168.250.100")
{
Port = 1025,
FrameType = SlmpFrameType.Frame4E,
CompatibilityMode = SlmpCompatibilityMode.Iqr,
};
await using var client = await SlmpClientFactory.OpenAndConnectAsync(options);
Typical pairs:
| PLC family | Frame | Compatibility |
|---|---|---|
| iQ-R / iQ-F | Frame4E |
Iqr |
| Q / L | Frame3E |
Legacy |
Use the queued client as the default application object. It is the safest choice when more than one task may touch the same connection.
Use *SingleRequestAsync when one protocol request is required. Use
*ChunkedAsync only when it is acceptable to split the operation across
multiple requests at word or dword boundaries.
High-Level Helpers
ReadTypedAsync / WriteTypedAsync
Read or write one logical value with conversion.
| dtype | Meaning | Words |
|---|---|---|
U |
unsigned 16-bit | 1 |
S |
signed 16-bit | 1 |
D |
unsigned 32-bit | 2 |
L |
signed 32-bit | 2 |
F |
float32 | 2 |
ushort counter = (ushort)await client.ReadTypedAsync("D100", "U");
float temperature = (float)await client.ReadTypedAsync("D200", "F");
int position = (int)await client.ReadTypedAsync("D300", "L");
await client.WriteTypedAsync("D100", "U", (ushort)42);
await client.WriteTypedAsync("D200", "F", 3.14f);
await client.WriteTypedAsync("D300", "L", -100);
WriteBitInWordAsync
Set or clear one bit inside a word device.
await client.WriteBitInWordAsync("D50", bitIndex: 3, value: true);
await client.WriteBitInWordAsync("D50", bitIndex: 3, value: false);
Use this when a PLC exposes individual flags inside one control word.
ReadNamedAsync
Read a mixed snapshot with one call.
Address notation:
| Form | Meaning |
|---|---|
D100 |
one unsigned 16-bit word |
D200:S |
signed 16-bit |
D300:D |
unsigned 32-bit |
D400:L |
signed 32-bit |
D500:F |
float32 |
D50.3 |
bit 3 inside D50 |
var snapshot = await client.ReadNamedAsync(
[
"D100",
"D200:S",
"D300:D",
"D400:L",
"D500:F",
"D50.3",
]);
Use .bit notation only with word devices such as D50.3.
Address bit devices directly as M1000, M1001, X20, or Y20.
Long-device notes for the high-level helper layer:
- plain
LTN,LSTN, andLCNaddresses default to 32-bit current-value access LTS,LTC,LSTS, andLSTCare resolved through the correspondingReadLongTimerAsync/ReadLongRetentiveTimerAsynchelper-backed 4-word decode instead of direct state reads
This is the recommended helper for dashboards, periodic snapshots, and application logic that needs mixed values.
ReadWordsSingleRequestAsync
Read a contiguous word range.
ushort[] words = await client.ReadWordsSingleRequestAsync("D0", 10);
This helper does not silently split one logical request.
ReadDWordsSingleRequestAsync
Read contiguous 32-bit values.
uint[] dwords = await client.ReadDWordsSingleRequestAsync("D200", 8);
ReadWordsChunkedAsync / ReadDWordsChunkedAsync
Use explicit chunked helpers when the range is too large for one request and splitting is acceptable:
ushort[] largeWords = await client.ReadWordsChunkedAsync("D0", 1000, maxWordsPerRequest: 480);
uint[] largeDwords = await client.ReadDWordsChunkedAsync("D200", 200, maxDwordsPerRequest: 240);
PollAsync
Read the same logical snapshot repeatedly.
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await foreach (var snapshot in client.PollAsync(
["D100", "D200:F", "D50.3"],
TimeSpan.FromSeconds(1),
cts.Token))
{
Console.WriteLine(snapshot["D100"]);
}
Practical Example Sets
Example 1: process values
var snapshot = await client.ReadNamedAsync(
[
"D100:F",
"D102:F",
"D200",
"D50.0",
"D50.1",
]);
Example 2: recipe download
await client.WriteTypedAsync("D100", "U", (ushort)10);
await client.WriteTypedAsync("D101", "U", (ushort)20);
await client.WriteTypedAsync("D102", "U", (ushort)30);
await client.WriteTypedAsync("D200", "F", 12.5f);
await client.WriteTypedAsync("D202", "F", 6.75f);
Example 3: historian-style reads
ushort[] historyWords = await client.ReadWordsChunkedAsync("D1000", 1200, maxWordsPerRequest: 480);
uint[] historyDwords = await client.ReadDWordsChunkedAsync("D2000", 240, maxDwordsPerRequest: 240);
Example 4: one shared connection for many tasks
var first = client.ReadNamedAsync(["D100", "D200:F"]);
var second = client.ReadNamedAsync(["D300", "D50.3"]);
await Task.WhenAll(first, second);
Address Normalization
Use SlmpAddress.Normalize when you need one stable string form:
string canonical = SlmpAddress.Normalize("d100");
Console.WriteLine(canonical); // D100
Sample Projects
The main user-facing sample projects are:
samples/PlcComm.Slmp.HighLevelSamplesamples/PlcComm.Slmp.QueuedSample
Run them from the repository root:
dotnet run --project samples/PlcComm.Slmp.HighLevelSample -- 192.168.250.100 1025 iqr 4e
dotnet run --project samples/PlcComm.Slmp.QueuedSample -- 192.168.250.100 1025 4 10