Skip to main content

Omron FINS

The FINS module targets Omron PLCs over FINS/UDP and FINS/TCP. Zeus handles FINS headers, FINS/TCP node-address handshake, SID matching, end-code exceptions, Memory Area Read/Write/Fill, and Multiple Memory Area Read.

Start with a Virtual PLC

var memory = new FinsSlaveMemory();
memory.DataMemoryWords[100] = 253;
memory.CioWords[10] = 0x0001;

await using var app = ZeusHost.Create(builder =>
{
builder.AddAcquisition(TimeSpan.FromMilliseconds(100));
builder.AddVirtualChannel("fins-link", new FinsSlaveResponder(FinsTransport.Udp, memory));
builder.AddOmronFinsUdp("plc", "fins-link", new FinsOptions
{
SourceNode = 10,
DestinationNode = 1
}, points: map => map
.DmWord("temperature", address: 100, scale: 0.1).Writable("temperature")
.CioBit("running", address: 10, bitOffset: 0).Writable("running"));
});

await app.StartAsync();
var temperature = app.Points.Get<double>("temperature");
await app.Points.WriteAsync("temperature", 18.6);

Run sample: samples/Zeus.Samples.Console.Fins.

Connect to a Real PLC

FINS/UDP commonly uses port 9600:

builder.AddUdpClient("fins-link", options =>
{
options.Host = "192.168.250.1";
options.Port = 9600;
});

builder.AddOmronFinsUdp("plc", "fins-link", new FinsOptions
{
SourceNode = 10,
DestinationNode = 1
});

FINS/TCP also commonly uses 9600. Zeus performs the node-address handshake by default:

builder.AddTcpClient("fins-link", "192.168.250.1", 9600);
builder.AddOmronFinsTcp("plc", "fins-link", new FinsOptions
{
TcpRequestedClientNode = 10
});

If the PLC rejects automatic node allocation, set UseTcpNodeAddressHandshake = false and provide SourceNode / DestinationNode manually.

Read/Write API

var plc = app.Devices.Get<FinsDevice>("plc");

var dm = await plc.ReadDataMemoryWordsAsync(100, 2);
await plc.WriteDataMemoryWordsAsync(110, [10, 20, 30]);

var bits = await plc.ReadCioBitsAsync(10, bitOffset: 0, count: 8);
await plc.WriteCioBitsAsync(10, bitOffset: 0, [true, false, true]);

await plc.FillWordsAsync(FinsMemoryAreaCode.DataMemoryWord, 200, 10, 0x55AA);

Raw FINS commands are also available:

byte[] data = await plc.ExecuteAsync(command: 0x0101, data: requestData);

Memory Areas

AreaWord codeBit codePoint helpers
CIOCioWordCioBit.CioWord(...) / .CioBit(...)
WRWorkWordWorkBit.WorkWord(...) / .WorkBit(...)
HRHoldingWordHoldingBit.HoldingWord(...) / .HoldingBit(...)
ARAuxiliaryWordAuxiliaryBit.AuxiliaryWord(...) / .AuxiliaryBit(...)
DMDataMemoryWordDataMemoryBit.DmWord(...) / .DmBit(...)
TIM/CNTTimerCounterValueTimerCounterFlag.TimerCounterValue(...) / .TimerCounterFlag(...)
EMcurrent / banked EMcurrent / banked EM bit.CurrentEmWord(...), .EmWord(...), etc.

JSON Configuration

{
"channels": [
{ "name": "fins-link", "type": "udp", "host": "192.168.250.1", "port": 9600 }
],
"devices": [
{
"name": "plc",
"channel": "fins-link",
"type": "omron-fins-udp",
"sourceNode": 10,
"destinationNode": 1,
"points": [
{ "name": "temperature", "area": "dm", "address": 100, "dataType": "word", "scale": 0.1, "writable": true },
{ "name": "running", "area": "cio", "address": 10, "bit": 0, "dataType": "bit", "writable": true }
]
}
]
}

Virtual FINS PLC:

{ "name": "fins-link", "type": "virtual", "responder": "fins", "transport": "udp" }

Common Issues

SymptomLikely causeFix
TimeoutUDP/TCP port, node id, or network number is wrongTest with FinsSlaveResponder, then check PLC FINS settings
TCP first request failsNode-address handshake rejectedSet TcpRequestedClientNode or disable handshake and set nodes manually
End code returnedMemory area, address, or count unsupportedInspect the FINS end code and PLC manual
32-bit word order is wrongPLC project uses opposite word orderChange FinsOptions.WordOrder

Next: Points and Acquisition.