Skip to content

Gotchas

LTN/LSTN/LCN/LZ returns wrong values

Item Detail
Symptom Long timer, long counter, or long index values look truncated or shifted.
Root cause LTN, LSTN, LCN, and LZ are 32-bit logical families.
Fix Use :D or :L in named addresses, or pass D or L to ReadTypedAsync.
using System;
using PlcComm.Slmp;

var options = new SlmpConnectionOptions("192.168.250.100", SlmpPlcProfile.IqR)
{
    Port = 1025,
};

await using var client = await SlmpClientFactory.OpenAndConnectAsync(options);
var value = await client.ReadTypedAsync("LTN0", "D");
Console.WriteLine($"LTN0 = {value}");

LCS/LCC reads incorrect

Item Detail
Symptom Long counter state reads do not match the expected contact or coil state.
Root cause LCS and LCC are state bits; they are not 16-bit word current values.
Fix Read them as bit values and let WriteTypedAsync / WriteNamedAsync route writes through random bit write.
using System;
using PlcComm.Slmp;

var options = new SlmpConnectionOptions("192.168.250.100", SlmpPlcProfile.IqR)
{
    Port = 1025,
};

await using var client = await SlmpClientFactory.OpenAndConnectAsync(options);
var state = await client.ReadTypedAsync("LCS0", "BIT");
await client.WriteTypedAsync("LCC0", "BIT", true);
Console.WriteLine($"LCS0 = {state}");

LTS/LTC/LSTS/LSTC write rejected

Item Detail
Symptom Writing a long timer contact or coil through a normal direct bit route is rejected.
Root cause Long timer state writes use SLMP random bit write, not ordinary direct bit write.
Fix Use WriteTypedAsync or WriteNamedAsync so the library selects the correct route.
using System;
using System.Collections.Generic;
using PlcComm.Slmp;

var options = new SlmpConnectionOptions("192.168.250.100", SlmpPlcProfile.IqR)
{
    Port = 1025,
};

await using var client = await SlmpClientFactory.OpenAndConnectAsync(options);
await client.WriteTypedAsync("LTC0", "BIT", true);
var state = await client.ReadTypedAsync("LTC0", "BIT");
Console.WriteLine($"LTC0 = {state}");

G/HG fails

Item Detail
Symptom G or HG fails in the high-level typed or named API.
Root cause Module buffer memory is outside the public high-level device surface.
Fix Use low-level module-buffer APIs on the raw SlmpClient when you need module buffer access.
using System;
using System.Threading.Tasks;
using PlcComm.Slmp;

await using var raw = new SlmpClient("192.168.250.100", SlmpPlcProfile.IqR, port: 1025);
await raw.OpenAsync();

var device = SlmpQualifiedDeviceParser.Parse(@"U3\G100");
var extension = new SlmpExtensionSpec();
ushort[] words = await raw.ReadWordsExtendedAsync(device, points: 4, extension);
Console.WriteLine($"G100 words = {words.Length}");

Mixed write fails

Item Detail
Symptom One mixed write containing word values and bit values fails.
Root cause The PLC rejects SLMP command 0x1406 for a mixed word and bit request.
Fix Send word writes and bit writes as separate calls.
using System;
using PlcComm.Slmp;

var options = new SlmpConnectionOptions("192.168.250.100", SlmpPlcProfile.IqR)
{
    Port = 1025,
};

await using var client = await SlmpClientFactory.OpenAndConnectAsync(options);
await client.WriteNamedAsync(new Dictionary<string, object>
{
    ["D9000"] = (ushort)1234,
});
await client.WriteNamedAsync(new Dictionary<string, object>
{
    ["M9000"] = true,
});
Console.WriteLine("Separated word and bit writes.");

DX/DY fails on iQ-F

Item Detail
Symptom DX or DY is rejected when the selected profile is SlmpPlcProfile.IqF.
Root cause iQ-F profile rules do not support DX and DY.
Fix Use X and Y with the iQ-F profile.
using System;
using PlcComm.Slmp;

var parsed = SlmpAddress.Parse("X20", SlmpPlcProfile.IqF);
Console.WriteLine(SlmpAddress.Format(parsed, SlmpPlcProfile.IqF));

All reads return end code

Item Detail
Symptom The connection opens, but every read returns an SLMP end-code error.
Root cause The selected SlmpPlcProfile does not match the actual PLC hardware.
Fix Choose the profile that matches the PLC; the profile determines frame type and compatibility mode.
using System;
using PlcComm.Slmp;

var options = new SlmpConnectionOptions("192.168.250.100", SlmpPlcProfile.IqR)
{
    Port = 1025,
};

await using var client = await SlmpClientFactory.OpenAndConnectAsync(options);
Console.WriteLine($"{client.FrameType} {client.CompatibilityMode}");

SlmpPlcProfile.Unspecified throws immediately

Item Detail
Symptom Creating connection options or resolving defaults with SlmpPlcProfile.Unspecified fails before any PLC request.
Root cause Unspecified is not a concrete PLC profile and cannot select frame type or compatibility mode.
Fix Use a concrete .NET selector such as SlmpPlcProfile.IqR.
using System;
using PlcComm.Slmp;

try
{
    _ = SlmpPlcProfiles.Resolve(SlmpPlcProfile.Unspecified);
}
catch (ArgumentOutOfRangeException)
{
    var defaults = SlmpPlcProfiles.Resolve(SlmpPlcProfile.IqR);
    Console.WriteLine($"{defaults.FrameType} {defaults.CompatibilityMode}");
}

Concurrent callers crash

Item Detail
Symptom Multiple async callers using one raw SlmpClient cause overlapping requests or inconsistent responses.
Root cause Raw SlmpClient is not thread-safe for concurrent callers.
Fix Use the QueuedSlmpClient returned by SlmpClientFactory.OpenAndConnectAsync.
using System;
using PlcComm.Slmp;

var options = new SlmpConnectionOptions("192.168.250.100", SlmpPlcProfile.IqR)
{
    Port = 1025,
};

await using var client = await SlmpClientFactory.OpenAndConnectAsync(options);
var first = client.ReadTypedAsync("D100", "U");
var second = client.ReadTypedAsync("D101", "U");
var values = await Task.WhenAll(first, second);
Console.WriteLine($"{values[0]}, {values[1]}");

X or Y addresses do not match an iQ-F manual

Item Detail
Symptom X or Y addresses look shifted on iQ-F.
Root cause iQ-F uses octal notation for X and Y; other supported profiles use hexadecimal.
Fix Parse or normalize X and Y with the explicit iQ-F profile.
using System;
using PlcComm.Slmp;

var address = SlmpAddress.Parse("Y217", SlmpPlcProfile.IqF);
Console.WriteLine(SlmpAddress.Format(address, SlmpPlcProfile.IqF));