pnowak
Member
This thread is reaction to another two:
https://support.industry.siemens.com/tf/ww/en/posts/inout-parameter-problem/260345
https://support.industry.siemens.co...en-ob-interrupts-fb/269783?page=0&pageSize=10
I do have MAIN OB1 and fast task OB31. Both write to the same BOOL output %Qx.y. I use some global variable to synchronize both OBs who uses BOOL output. Sometimes OB1, othertimes OB31.
All works perfectly. The magic lies in fact that if one OB doesn't have priority to write to output it simply doesn't write anything = do nothing and the other OBx can write to output.
The situation gets complicated as soon as I need more instances of functionality executed by OB1+OB31. I put functionality into some FB (in OB1 or OB31 or probably both). FB has InOut formal parameter. The real bool output is assigned to formal parameter during FB call. And because elementary InOut parameters is "by value" and not "by ref" (why Siemens, why ???!!!) the magic is broken. InOut is always copied to real parameter at the end of FB call, whether or not the formal parameter was written inside of FB (if not, the last value of InOut is used).
Has anybody hit this problem? What strategy did you use to overcome it ? Any thoughs ?
Some ideas (some from threads mentioned above):
1. If the number of instances is low I can select real output by use of some instance identification (use CASE OF) and write to output inside of FB. "By ref" isn't broken. It works. But this solution is very bad (encapsulation principle broken, every change in output address, number of instances etc deserves rewriting a lot of code; bad readability).
2. Write to 3 state output variable inside FB (TRUE/FALSE/do nothing) and write(false/true) or donothing to real output outside of FB. This deserve some code after FB call.
3. Remember value of real output before FB call. After FB call compare actual and remembered value od real output. If it's unchanged use write output of FB to real output. It seems as simple solution but I think it has two problems: first it doesn't respect what really happen inside FB call (it ignores synchronization between OB1-OB31) and second: if OB31 interrupts OB1 and changes real output value exactly after comparing remembered/actual value and before writing real output this could work wrongly.
4. OB1-FB simply doesn't write to real output but sends write command to OB31 that executes write to real output. I think this is principially the same as solution 2.
5. Declare InOut parameter as UDT (UDT parameters are always "by ref"). Impossible. Can't assign real parameter BOOL (real output) to formal parameter UDT.
Whole problem is caused by Siemens decisison that formal elementary InOut parameters are by value. But elementary InOut by value could be easily reached by combination of one In and one Out. And InOut could be by ref. I understand it's probably caused by history and backward compatibility. But this has easy solution - compiler option.
------------------------------
//EXAMPLE
//OB1 - MAIN - about 10ms
...some code...
FBxx(inoutPar1 := outBool%Qx.y);
//PROBLEM: FB call end always writes some value to outBool%Qx.y even if "do nothing" variant happened inside FB
...some code...
//end of OB1
--------------
//FBxx
IF condition THEN
inoutPar1 := TRUE;
ELSEIF condition2 THEN
inoutPar1 := FALSE;
ELSE
//do nothing
END_IF;
----------------
//OB31 - 1ms
...some code...
IF condition3 THEN
outBool%Qx.y := TRUE;
ELSEIF condition4 THEN
outBool%Qx.y := FALSE;
ELSE
//do nothing
END_IF;
...some code...
//end of OB31
--------------
https://support.industry.siemens.com/tf/ww/en/posts/inout-parameter-problem/260345
https://support.industry.siemens.co...en-ob-interrupts-fb/269783?page=0&pageSize=10
I do have MAIN OB1 and fast task OB31. Both write to the same BOOL output %Qx.y. I use some global variable to synchronize both OBs who uses BOOL output. Sometimes OB1, othertimes OB31.
All works perfectly. The magic lies in fact that if one OB doesn't have priority to write to output it simply doesn't write anything = do nothing and the other OBx can write to output.
The situation gets complicated as soon as I need more instances of functionality executed by OB1+OB31. I put functionality into some FB (in OB1 or OB31 or probably both). FB has InOut formal parameter. The real bool output is assigned to formal parameter during FB call. And because elementary InOut parameters is "by value" and not "by ref" (why Siemens, why ???!!!) the magic is broken. InOut is always copied to real parameter at the end of FB call, whether or not the formal parameter was written inside of FB (if not, the last value of InOut is used).
Has anybody hit this problem? What strategy did you use to overcome it ? Any thoughs ?
Some ideas (some from threads mentioned above):
1. If the number of instances is low I can select real output by use of some instance identification (use CASE OF) and write to output inside of FB. "By ref" isn't broken. It works. But this solution is very bad (encapsulation principle broken, every change in output address, number of instances etc deserves rewriting a lot of code; bad readability).
2. Write to 3 state output variable inside FB (TRUE/FALSE/do nothing) and write(false/true) or donothing to real output outside of FB. This deserve some code after FB call.
3. Remember value of real output before FB call. After FB call compare actual and remembered value od real output. If it's unchanged use write output of FB to real output. It seems as simple solution but I think it has two problems: first it doesn't respect what really happen inside FB call (it ignores synchronization between OB1-OB31) and second: if OB31 interrupts OB1 and changes real output value exactly after comparing remembered/actual value and before writing real output this could work wrongly.
4. OB1-FB simply doesn't write to real output but sends write command to OB31 that executes write to real output. I think this is principially the same as solution 2.
5. Declare InOut parameter as UDT (UDT parameters are always "by ref"). Impossible. Can't assign real parameter BOOL (real output) to formal parameter UDT.
Whole problem is caused by Siemens decisison that formal elementary InOut parameters are by value. But elementary InOut by value could be easily reached by combination of one In and one Out. And InOut could be by ref. I understand it's probably caused by history and backward compatibility. But this has easy solution - compiler option.
------------------------------
//EXAMPLE
//OB1 - MAIN - about 10ms
...some code...
FBxx(inoutPar1 := outBool%Qx.y);
//PROBLEM: FB call end always writes some value to outBool%Qx.y even if "do nothing" variant happened inside FB
...some code...
//end of OB1
--------------
//FBxx
IF condition THEN
inoutPar1 := TRUE;
ELSEIF condition2 THEN
inoutPar1 := FALSE;
ELSE
//do nothing
END_IF;
----------------
//OB31 - 1ms
...some code...
IF condition3 THEN
outBool%Qx.y := TRUE;
ELSEIF condition4 THEN
outBool%Qx.y := FALSE;
ELSE
//do nothing
END_IF;
...some code...
//end of OB31
--------------
Last edited: