I cant get FB_MBReadinputs to work in Twincat, when Factory IO is sending/receiving Input and Holding registers.
First off here's my currently working snip of handling Modbus from Factory IO:
VAR
GAB_FactoryIO_Inputs AT %I* : ARRAY [0..15] OF BYTE;
...
END_VAR
LFB_MBReadInputs(
sIPAddr := '192.168.0.109',
nTCPPort := 505,
nUnitID := 255,
nQuantity := 64,
nMBAddr := 0,
cbLength := SIZEOF(IO.GAB_FactoryIO_Inputs),
pDestAddr := ADR(IO.GAB_FactoryIO_Inputs),
bExecute := TRUE,
tTimeout := T#1S,
bBusy => ,
bError => ,
nErrId => ,
cbRead => ,
);
LFB_MBReadInputs(bExecute := FALSE);
It runs in state machine and churns out bytes happily, to be again written by MBWriteCoils.
But what I cant get to working is FB_MBReadRegs. Beckhoff examples look almost identical between MBReadInputs and MBReadRegs, I first got ADS error 1794 and changed VAR to DINT, and WORD, but now nothing happens instead of error. I'm expecting X, Y and Z coordinates to any bytes, bits or ints on registers, but absolutely nothing happens.
I've tried simplifying and figuring out where's the problem and here's whats going on currently:
VAR
GAB_FactoryIO_RegsIN AT %I* : ARRAY [0..5] OF DINT;
LFB_MBReadRegs(
sIPAddr := '192.168.0.109',
nTCPPort := 505,
nUnitID := 255,
nQuantity := 16,
nMBAddr := 0,
cbLength := 100,
pDestAddr := ADR(IO.GAB_FactoryIO_RegsIN),
bExecute := TRUE,
tTimeout := T#1S,
bBusy => ,
bError => ,
nErrId => ,
cbRead => ,
);
LFB_MBReadRegs(bExecute := FALSE);
Adding suggestions by @kolyur as far as I understand how it should go as part of state machine.
Apparently now that I had a new try at it, IF FB_MBReadRegs=bBusy THEN... doesnt work. "Error Functionblock 'FB_MBReadRegs' must be instantiated to be accessed". So thats a project for tomorrow to figure out.
After playing around for a while, I still dont fully grasp using or not using %I*, but %M* (or %MB0 and %MB64) did do the trick. Found part of the solution in https://forge.codesys.com/forge/talk/CODESYS-V2/thread/cc22cd1dc1/ Anyway, I misunderstood what MBReadRegs does, because MBReadInputRegs is where its at when receiving position info/whatever from Factorio.
Below apparently working code snip:
VAR_GLOBAL
GAB_FactoryIO_Inputs AT %I* : ARRAY [0..15] OF BYTE; //I/O between Factory IO and TC
GAB_FactoryIO_Outputs AT %Q* : ARRAY [0..15] OF BYTE;
GAB_FactoryIO_RegsIN AT %MB0 : ARRAY [0..5] OF WORD; // %M* on both didnt work, coordinates spiraled to thousands
GAB_FactoryIO_RegsOUT AT %MB32 : ARRAY [0..5] OF WORD;
END_VAR
VAR;
LFB_MBReadInputRegs : FB_MBReadInputRegs ;
END_VAR
CASE iState OF
//...other states in between
10: //next is in its own file
LFB_MBReadInputRegs(
sIPAddr := '192.168.0.109',
nTCPPort := 505,
nUnitID := 255,
nQuantity := 12,
nMBAddr := 0,
cbLength := 100,
pDestAddr := ADR(IO.GAB_FactoryIO_RegsIN),
bExecute := TRUE,
tTimeout := T#1S,
bBusy => ,
bError => ,
nErrId => ,
cbRead => ,
);
LFB_MBReadInputRegs(bExecute := FALSE);
//5ms wait routine and jump to next iState
Another edit a bit later:
New situation where bErr 1794 just wouldnt go away.
- For some reason cbLength didnt like 100 anymore, but had to have its size read
- Also reboot. Useless amounts of struggling with troubleshooting would have been spared if I just cut the power from PLC power switch. Even though logically thinking software reboot is just as good, but memory problems got better with hard reset anyway.
IF NOT bModbusBusy4 THEN
bModbusBusy4 := TRUE;
fbMBReadInputRegs (
sIPAddr := ipAddr,
nTCPPort := 506,
nUnitID := 255,
nQuantity := 32,
nMBAddr := 0,
cbLength := SIZEOF(TIO.GAB_FactoryIO_RegsIN),
pDestAddr := ADR(TIO.GAB_FactoryIO_RegsIN),
bExecute := TRUE,
tTimeout := T#1S,
bBusy => ,
bError => ,
nErrId => ,
cbRead => ,
);
ELSE
IF NOT fbMBReadInputRegs.bBusy THEN
bModbusBusy4 := FALSE;
END_IF
fbMBReadInputRegs(bExecute := FALSE);
END_IF