How to make inputs of a function block method optional? - twincat

When calling a method of a function block, is it possible to make certain input variables optional? If I call fbA.methA() without assignments for all input variables, TwinCAT throws an error: "Function methA requires exactly 'x' inputs." There are times when some inputs are unnecessary or irrelevant, but so far I've had to assign dummy values to those inputs to get the code to compile.

I don't think that that is possible. You could make extra methods which all call a base method.
For example:
FUNCTION_BLOCK Multiplier
METHOD Multiply : REAL
VAR_INPUT
number1 : REAL;
number2 : REAL;
END_VAR
METHOD MultiplyByTwo : REAL
VAR_INPUT
number : REAL;
END_VAR
MultiplyByTwo := Multiply(2, number);
That way you also reduce the number of inputs of your method, thereby making it easier to test and use.

You also could screen the parameters as they are passed in (still requires parameters but they have no meaning aka always pass "0").
FUNCTION_BLOCK CAT
METHOD DECIBELS: REAL
VAR_INPUT
MEOW, PURR: BOOL;
END_VAR
// body
DECIBELS := 0.0;
IF MEOW <> 0
DECIBELS := DECIBELS + 10.0;
END_IF;
IF PURR <> 0
DECIBELS := DECIBELS + 5.0;
END_IF;
END_METHOD
END_FUNCTION_BLOCK
you can invoke this like:
PROGRAM MAIN
VAR
C: CAT;
RESULT: ARRAY [1..4] OF REAL;
END_VAR
// body
RESULT[1] := C.DECIBELS(TRUE, TRUE); // will return 15.0
RESULT[2] := C.DECIBELS(TRUE, 0); // will return 10.0
RESULT[3] := C.DECIBELS(0, TRUE); // will return 5.0
RESULT[4] := C.DECIBELS(0, 0); // will return 0.0
END_PROGRAM
Hope this helps

Related

How to throw an exception in TwinCAT

When using object-oriented programming aspects with Beckhoff TwinCAT 3 I recently tried to implement some Assert-like function which should throw an exception in case a guard clause evaluates to false.
Something like this:
FUNCTION GuardI
VAR_INPUT
Condition : BOOL;
Format : T_MaxString;
Value : INT;
END_VAR
IF (NOT Condition) THEN
ADSLOGDINT(
msgCtrlMask := ADSLOG_MSGTYPE_ERROR OR ADSLOG_MSGTYPE_LOG,
msgFmtStr := Format,
dintArg := Value);
// throw exception here
END_IF
So - how would I have it throw an exception?
I don't think it is possible to throw an exception from a quick look at the documentation. Note that exception handling (__TRY, __CATCH) only works for TwinCAT >= 4024.0 and for 32-bit systems.
You can do this like:
Create a Function called ASSERT
FUNCTION ASSERT
VAR_INPUT
E: BOOL;
END_VAR
VAR
EXCEPTION_THROWN, PURR: INT;
END_VAR
// body
IF NOT E THEN
EXCEPTION_THROWN := 0 / PURR;
END_IF
END_FUNCTION
Once you do this it will throw an exception guaranteed by Beckhoff because of the division by zero you would invoke this function like this (be sure that your are within the scope of that function via namespace or library reference):
PROGRAM MAIN
VAR
MEOW: INT; // zero by default
CONDITION: BOOL; // false by default
END_VAR
// body
IF MEOW = 1 THEN
ASSERT(FALSE);
END_IF
// ...
ASSERT(CONDITION); // key off your condition true or false
END_PROGRAM
Once you set "MEOW" to "1" or your condition evaluates to "FALSE" This will produce a Core Dump and you can load this core dump and review the call stack.
Hope this helps.

How can i declare or set an auto value changeable boolean variable in twincat 3

I am new to TwinCAT programming. I want to set 4 boolean variables in TwinnCAT 3 and they will change value automatically after 150 milliseconds using structured text. How can I do that?
If you want to change values just for once after execute the timer, basicly you can use like this;
PROGRAM MAIN
VAR
bExecute : BOOL;
bVar1 : BOOL;
bVar2 : BOOL;
bVar3 : BOOL;
bVar4 : BOOL;
Timer1 : TON;
END_VAR
Define variables as above,
write your code as below;
Timer1(IN:= bExecute, PT:=T#150MS);
IF Timer1.Q THEN
bVar1 := NOT bVar1;
bVar2 := NOT bVar2;
bVar3 := NOT bVar3;
bVar4 := NOT bVar4;
bExecute := FALSE; // After executing, if you want to make false the bExecute variable and make Timer.IN false.
END_IF
For more information about Timers please visit here

How to trigger a Function_Block

Hello to all TwinCAT developers,
I am currently developing function blocks with TwinCAT.
I'm trying to find a "standard" way to interact with the outside of the block.
The Beckhoff examples always have a bExec signal to start a state machine on the rising edge.
fbRisingEdge(CLK := bExec);
IF fbRisingEdge.Q THEN
nStep := 1;
END_IF
CASE nStep OF
1:
nStep := nStep + 1;
2:
nStep := nStep + 1;
END_CASE
I find that this principle is heavy to use and requires more code to create the rising edge:
fbFileOpen(sPathName := sPathName, bExecute := FALSE);
fbFileOpen(sPathName := sPathName, bExecute := TRUE);
Would anyone use another alternative to start a state-machine inside a FB?
Thank you, Happy new year!
I use a method defined inside my function block to trigger an action. I Also (sometimes) return a bool from the method which indicates weather the action can be performend or not, depending on the current state.
METHOD M_Open : BOOL
VAR_IN
sPath : STRING;
END_VAR
VAR_OUTPUT
bExecutionAllowed : BOOL;
END_VAR
bExecutionAllowed := _ ; // Calculate depending on the current state
sPathName := sPath;
IF bExecutionAllowed THEN
nStep := 1;
END_IF
Then call the method somewhere once
fbFileHandler.M_Open("Path/To/File");
And the fucntion block cyclically
fbFileHandler();
The function block can than handles multiple different actions which may be triggered each by their own method.

Not overloading operator

Good day, I'm doing some Codeforces exercises in my free time, and I had a problem to test if the user was a boy or a girl, well, my problem isn't that, i have just demonstrated the code.
While compiling my code in my computer ( I'm using version 3.0.4 for i386 ) i get no error, but codeforces gives me this error
program.pas(15,16) Error: Operator is not overloaded: "freq(Char;AnsiString):LongInt;" + "ShortInt"
program.pas(46,4) Fatal: There were 1 errors compiling module, stopping
The error wasn't clear enough to me, as the same script was perfectly compiled with my version.
The platform is using ( version 3.0.2 i386-Win32 ).
program A236;
uses wincrt, sysutils;
var
username : String;
function freq(char: char; username : String): Integer;
var
i: Integer;
begin
freq:= 0;
for i:= 1 to length(username) do
if char = username[i] then
freq:= freq + 1;
//writeln(freq);
end;
function OddUserName(username : String): Boolean;
var
i, counter: Integer;
begin
OddUserName:= false; // even
counter:= 0;
for i:= 1 to length(username) do
if freq(username[i], username) <> 1 then
delete(username, i, 1)
else
counter:= counter + 1;
if counter mod 2 <> 0 then
OddUserName:= true; // odd
//writeln(counter);
//writeln(OddUserName);
end;
begin
readln(username);
if not OddUserName(username) then
writeln('CHAT WITH HER!')
else
writeln('IGNORE HIM!');
//readkey();
end.
The error is supposed to be at this line probably :
function freq(character: char; username : String): Integer;
Thanks for everyone who helps.
Inside of a function, the function's name can be used as a substitute for using an explicit local variable or Result. freq() and OddUserName() are both doing that, but only freq() is using the function name as an operand on the right-hand side of an assignment. freq := freq + 1; should be a legal statement in modern Pascal compilers, see Why i can use function name in pascal as variable name without definition?.
However, it would seem the error message is suggesting that the failing compiler is treating freq in the statement freg + 1 as a function type and not as a local variable. That would explain why it is complaining about not being able to add a ShortInt with a function type.
So, you will have to use an explicit local variable instead, (or the special Result variable, if your compiler provides that), eg:
function freq(charToFind: char; username : String): Integer;
var
i, f: Integer;
begin
f := 0;
for i := 1 to Length(username) do
if charToFind = username[i] then
f := f + 1;
//writeln(f);
freq := f;
end;
function freq(charToFind: char; username : String): Integer;
var
i: Integer;
begin
Result := 0;
for i := 1 to Length(username) do
if charToFind = username[i] then
Result := Result + 1;
//writeln(f);
end;

Passing an array with integer values and char indexes to a function in Pascal

I really would like to see how it's done, the compiler keeps assuming I have integer indexes and returns errors.
How to pass the following array:
countc: Array['a'..'z'] of Integer;
to a function?
In traditional Pascal, before you can pass something like your array to a function, you have to declare a type that your array is an instance of, like this
type
TSimpleArray = Array['A'..'Z', '0'..'9'] of integer;
var
ASimpleArray : TSimpleArray;
In other words, you can't specify the array's bounds in the definition of the function/procedure.
Once you've defined your array type like the above, you can declare a function (or procedure) that has a parameter of the defined type, like this:
function ArrayFunction(SimpleArray : TSimpleArray) : Integer;
var
C1,
C2 : Char;
begin
ArrayFunction := 0;
for C1 := 'A' to 'Z' do
for C2 := '0' to '9' do
ArrayFunction := ArrayFunction + SimpleArray[C1, C2];
end;
which obviously totals the contents of the array.
More modern Pascals like Delphi and FPC's ObjectPascals also support other ways of declaring an array-type parameter, but they have to be zero-based (which precludes the use of char indexes). Delphi and FPC also support the use of `Result' as an alias for the function name, as in
function ArrayFunction(SimpleArray : TSimpleArray) : Integer;
[...]
begin
Result := 0;
which saves time and effort if you rename a function or copy/paste it to define another function.

Resources