Skip to content

Gotchas

Each entry starts with the symptom, then gives the root cause and a complete C# fix. The examples use 192.168.250.100:1025 and a canonical TOYOPUC profile.

P1-D0000 not just D0000

Symptom Root cause Fix
D0000 raises an invalid-address or unknown-device error. Basic area families require a P1-, P2-, or P3- program prefix. Use P1-D0000, P2-D0000, or P3-D0000 for the intended program area.
using System;
using PlcComm.Toyopuc;

var options = new ToyopucConnectionOptions("192.168.250.100")
{
    Port = 1025,
    PlcProfile = "toyopuc:plus:extended",
};

await using var client = await ToyopucDeviceClientFactory.OpenAndConnectAsync(options);
var value = await client.ReadTypedAsync("P1-D0000", "U");
Console.WriteLine($"P1-D0000 = {value}");

.D vs :D

Symptom Root cause Fix
P1-D0100.D reads one bit instead of a 32-bit value. Dot notation means bit-in-word access. .D is hexadecimal bit 13. Use colon notation for typed views, such as P1-D0100:D.
using System;
using PlcComm.Toyopuc;

var options = new ToyopucConnectionOptions("192.168.250.100")
{
    Port = 1025,
    PlcProfile = "toyopuc:plus:extended",
};

await using var client = await ToyopucDeviceClientFactory.OpenAndConnectAsync(options);
var snapshot = await client.ReadNamedAsync(["P1-D0100:D", "P1-D0100.D"]);
Console.WriteLine($"dword={snapshot["P1-D0100:D"]}, bit13={snapshot["P1-D0100.D"]}");

FR values revert after power cycle

Symptom Root cause Fix
An FR value changes during runtime but returns to the old value after a power cycle. FR writes are two-phase. WriteFrAsync(..., commit: false) stages RAM only. Call CommitFrAsync() after staging, or pass commit: true only when flash persistence is intended.
using System;
using PlcComm.Toyopuc;

var options = new ToyopucConnectionOptions("192.168.250.100")
{
    Port = 1025,
    PlcProfile = "toyopuc:pc10g:pc10",
};

await using var client = await ToyopucDeviceClientFactory.OpenAndConnectAsync(options);
await client.ExecuteAsync(inner => inner.WriteFrAsync("FR000000", 0x1234, commit: false));
await client.ExecuteAsync(inner => inner.CommitFrAsync("FR000000", wait: true));
Console.WriteLine("FR write committed");

Non-canonical profile string fails immediately

Symptom Root cause Fix
Opening the connection throws before any PLC request is sent. PlcProfile is required and accepts only exact canonical strings from source. Aliases and blank values are rejected. Copy one exact string from PROFILES.md, such as toyopuc:plus:extended.
using System;
using PlcComm.Toyopuc;

var profile = ToyopucPlcProfiles.NormalizeName("toyopuc:plus:extended");
var options = new ToyopucConnectionOptions("192.168.250.100")
{
    Port = 1025,
    PlcProfile = profile,
};

Console.WriteLine(options.PlcProfile);

Relay hops not probed automatically

Symptom Root cause Fix
Relay reads or writes do not reach the expected PLC. Relay topology is not probed automatically because automatic route guessing can hide configuration mistakes. Set RelayHops explicitly in ToyopucConnectionOptions.
using System;
using PlcComm.Toyopuc;

var options = new ToyopucConnectionOptions("192.168.250.100")
{
    Port = 1025,
    PlcProfile = "toyopuc:nano-10gx:compatible",
    RelayHops = "P1-L2:N4,P1-L2:N6,P1-L2:N2",
};

await using var client = await ToyopucDeviceClientFactory.OpenAndConnectAsync(options);
var value = await client.ReadTypedAsync("P1-D0000", "U");
Console.WriteLine($"Relay P1-D0000 = {value}");

Packed bit notation P1-M0010W

Symptom Root cause Fix
P1-M0010W, P1-M0010H, or P1-M0010L is mistaken for a typed suffix. W, H, and L appended to a bit-area address mean packed word, high byte, or low byte. They are not :D or :F type suffixes. Use packed notation only for bit-area packed views, and use colon notation for typed word values.
using System;
using PlcComm.Toyopuc;

var options = new ToyopucConnectionOptions("192.168.250.100")
{
    Port = 1025,
    PlcProfile = "toyopuc:plus:extended",
};

await using var client = await ToyopucDeviceClientFactory.OpenAndConnectAsync(options);
var packed = await client.ExecuteAsync(inner => inner.ReadAsync("P1-M0010W"));
var dword = await client.ReadTypedAsync("P1-D0100", "D");
Console.WriteLine($"packed={packed}, dword={dword}");

FR write through a generic write path fails

Symptom Root cause Fix
A generic high-level write to FR000000 fails. Generic FR writes are intentionally blocked so persistence is never implicit. Use WriteFrAsync and CommitFrAsync explicitly.
using System;
using PlcComm.Toyopuc;

var options = new ToyopucConnectionOptions("192.168.250.100")
{
    Port = 1025,
    PlcProfile = "toyopuc:pc10g:pc10",
};

await using var client = await ToyopucDeviceClientFactory.OpenAndConnectAsync(options);
await client.ExecuteAsync(inner => inner.WriteFrAsync("FR000000", 0x1234, commit: false));
await client.ExecuteAsync(inner => inner.CommitFrAsync("FR000000", wait: true));
Console.WriteLine("FR helper write completed");

Single-request block reads fail across a boundary

Symptom Root cause Fix
ReadWordsSingleRequestAsync reports an incompatible protocol group. The requested range crosses a boundary that cannot be represented as one compatible protocol request. Use ReadWordsChunkedAsync with an explicit maximum chunk size.
using System;
using PlcComm.Toyopuc;

var options = new ToyopucConnectionOptions("192.168.250.100")
{
    Port = 1025,
    PlcProfile = "toyopuc:plus:extended",
};

await using var client = await ToyopucDeviceClientFactory.OpenAndConnectAsync(options);
var values = await client.ReadWordsChunkedAsync("P1-D0000", 64, maxWordsPerRequest: 16);
Console.WriteLine($"Read {values.Length} words");