We are willing to go for the "OOP" approach with our new PLC implementation. We are struggling a little bit with Codesys and how its supposed to be done in IEC 61131-3. At the moment we are writing down the basic architecture. Both of us have enough expierence with JAVA and C#.
What we want to do is a simple Alarmhandling interface with basic OOP concepts. What's struggling us at the moment is the fact that the FB's seem to get copied when assigned to member variables resp. on method calls.
The alarmhandler would not see this change, because he got a copy. This led us to use ```
REFERENCE TO
in the declaration. But then we face either strange access violations during runtime because we seem to do something wrong or if we use the
REF=
``` assignment, we got strange messages like:
"Can not convert type Motor to type "Pointer To AlarmSourceInterface", even if the Motor does in fact implement the AlarmSourceInterface."
Normally in any other language I would not ask such silly questions, but for "IEC-61131-3" it seems to be near to impossible to find usefull code or samples in the internet. I found some, but only a little, especially to the OOP implementations. And I also didn't find a lot of usefull books written after 1980 .
Do you guys do it the same way with references or is there something we don't get?
Keep in mind that Codesys doesn't support pointer typecast so in your case you expect a reference to the alarmhandlerinterface (the pointer) and you are passing the object itself not it's address.
Also it is possible to do some small things in the VAR declaration area, such as ADR() calling, but not all the code can be placed there (so I don't know if REF= suits there never tried it).
If you want to send a reference of an object you can use several methods:
VAR_IN_OUT
POINTER TO
REFERENCE *
you are not passing the reference in your example (I've used notepad to see your code as in the computer I'm now I don't have any codesys compatible software installed).
Thanks for your post, but I think i dont really understand what you mean.
If have this Motor:
//StartVarDeclarationFUNCTION_BLOCKPUBLICMotorIMPLEMENTSAlarmSourceInterfaceVAR_INPUT
  alarmSource: AlarmSourceInterface;
  alarmHandler: REFERENCETOAlarmHandlerInterface;END_VARVAR_OUTPUTEND_VARVAR
  mAlarmHandler: REFERENCETOAlarmHandlerInterface;  END_VAR//EndVarDeclaration//Codeblockstartthis^.mAlarmHandler :=alarmHandler; //I want to do this in FB_INIT but that will follow later//CodeblockEnd
Now if I want to use the Motor I would do this in my PLC_PRG:
//StartVarDeclarationPROGRAMPLC_PRGVAR
   alarmHandler1: AlarmHandler;
  motor1:  Motor;END_VAR//EndVarDeclaration//Codeblockstartmotor1(alarmHandler :=alarmHandler1);motor1.RaiseAlarm();//CodeblockEnd
When I now go for step by step debugging, here:
motor1(alarmHandler := alarmHandler1); it looses the reference when I later on look on the variable inside the motor:
I cant do this, because its not allowed by syntax:
motor1(alarmHandler REF= alarmHandler1);
So what do I need to do now? If I want to pass alarmHandler1 into the motor? What you think is an elegant way? I ask you this because then I could do this:
mAlarmHandler.registerAlarm(THIS^); --> No errormessage
mAlarmHandler.registerAlarmByReference(THIS^); --> Gives an errormessage as you explained.
And I would not have the problem that I can't compile the code because it sais the errormessage I mentioned before.
@Edit:
PS thanks for the links, I think I already knew them...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Probably the best in your case would be using something like:
FUNCTION_BLOCKPUBLICMotorIMPLEMENTSAlarmSourceInterfaceVAR_INPUT
  alarmSource: AlarmSourceInterface;
  alarmHandler: POINTERTOAlarmHandlerInterface;END_VARVAR_OUTPUTEND_VARVAR
  mAlarmHandler: POINTERTOAlarmHandlerInterface;  END_VAR//EndVarDeclaration//Codeblockstartthis^.mAlarmHandler :=alarmHandler; //I want to do this in FB_INIT but that will follow later//CodeblockEnd
//StartVarDeclarationPROGRAMPLC_PRGVAR
   alarmHandler1: AlarmHandler;
  motor1:  Motor;END_VAR//EndVarDeclaration//Codeblockstartmotor1(alarmHandler :=ADR(alarmHandler1));motor1.RaiseAlarm();//CodeblockEnd
But in your case the most "elegant" way of doing it would be using a property and a reference or a pointer.
If you want to use FB_Init I've used the pointer approach successfully so you should not have any problem doing that.
Keep in mind that when you do an online change pointers can need to be reassigned as the memory addresses can move.
Hope this helps.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Every cycle varinput and output are copied. If you pass an fb, the fb is full copied.
You make two copies. One in varinput assignement and other in private variable.
If you use varinout, only is copied the fb pointer, and you are working with the fb passed.
Fb_init is the constructor, but it not accepts varinout, in that case you have to pass the pointetr and copy it to an internal variable.
Pass in fb_init is faster because it is not necessary to copy the reference every cycle, but when your make the logical code could loose how the connectioms are made
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for your answers, I did what you explained to me (change from "REFERENCE TO" to "POINTER TO"), and the i provide the instance by
motor1(alarmHandler:=ADR(alarmHandler1));
But now it says "Cannot convert type 'Pointer to AlarmHandler' to type 'Pointer to AlarmhandlerInterface'. But AlarmHandler implements AlarmhandlerInterface.
Variable definition from Motor looks like this:
Zitat:
FUNCTION_BLOCK PUBLIC Motor IMPLEMENTS AlarmSourceInterface
VAR_INPUT
alarmSource: AlarmSourceInterface;
alarmHandler: POINTER TO AlarmHandlerInterface;
END_VAR
VAR_OUTPUT
END_VAR
VAR
mAlarmHandler: POINTER TO AlarmHandlerInterface;
END_VAR
AlarmHanlderCode Looks like this:
Zitat:
FUNCTION_BLOCK PUBLIC Motor IMPLEMENTS AlarmSourceInterface
VAR_INPUT
alarmSource: AlarmSourceInterface;
alarmHandler: POINTER TO AlarmHandlerInterface;
END_VAR
VAR_OUTPUT
END_VAR
VAR
mAlarmHandler: POINTER TO AlarmHandlerInterface;
END_VAR
Additionaly since I changed mAlarmHandler to be a Pointer, it sais C0062 "mAlarmHandler" is no structured variable on the following piece of code:
mAlarmHandler.registerAlarm(THIS^);
And if I hover over the mAlarmHandler its sais something like "Program name, function or function block instance expected instead of 'mAlarmHandler.registerAlarm'". Is that the same reason, so I cant do this on a pointer?
By the way:
I want to avoid VAR_IN-OUT in any case if possible because it breaks my interfaces and object resp. FB's encapsulation "by definition". To me they would be like public variables and thats (at least to me) not a solution.
Appreciate your help!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Take a look at the properties to get a more similar way to share variables with the outside world.
Remember that the pointers doesn't allow typecasting here, if you define a pointer to a specific type you can't pass a different pointer there.
The ^ sign means dereference here, so if you are passing this^ you are passing a copy of the complete function block (or the object this points to), but if you are passing this (without the ^) then you are passing the address (the pointer) which is what you want now.
Just please remember to initialize the pointer address to 0 in the declaration and check if the pointer is different than 0 before using it to endure you won't have undesired page faults.
Hope this helps.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I tried it without the ^ but it still gives me the same alarm.
"Remember that the pointers doesn't allow typecasting here, if you define a pointer to a specific type you can't pass a different pointer there."
What would be the solution? Just as an info: My goal is not to use references, or pointers, whatever I just want to pass the same instance of a FB around. If I do it the "classic" way without pointers,refs or anything then the FB's always get copied on asignments. I just want to overcome the copies.
Basically I just want to use it like every other "OOP" language in the field like C#,JAVA,Python,C++ what ever...
I attached my latest project to this post if someone is interested.
Check the last link I pasted in the first message, Stefan shows how to use interfaces correctly to get the most similar to what JAVA, C++, C# gives you.
In any case it is not important what interface you implement, you are passing the function block pointer (in my example pseudo code).
If you want to be able to use a more dynamic approach (given your background and the advantages it offers it is normal you would like to) then look at the Stefan link where good samples are implemented and deeply explained.
Hope this helps.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Joan M hat geschrieben:
Check the last link I pasted in the first message, Stefan shows how to use interfaces correctly to get the most similar to what JAVA, C++, C# gives you.
In any case it is not important what interface you implement, you are passing the function block pointer (in my example pseudo code).
If you want to be able to use a more dynamic approach (given your background and the advantages it offers it is normal you would like to) then look at the Stefan link where good samples are implemented and deeply explained.
Hope this helps.
You refering to this? https://stefanhenneken.wordpress.com/20 ... nterfaces/
I read it completely, even time before but it does not (and in any article) explain the problem of "objects" always beeing copied if you don't use Reference To or similar approaches.
If you don't use REFERENCE TO, POINTER TO or what ever if you just declare FB's as normal. And you pass a FB to another FB, and the "foreign" FB manipuliates the FB you are providing, he will manipulate the copy, not the FB you are providing.
Here is my Pseudocode:
motor1.ManipulateCopyTestString('ManipulationFromOutside');
motor1(alarmHandler := alarmHandler1);
POU1(motorInput := motor1);
//This is the Methodcall from POU1
motorInput.ManipulateCopyTestString('manipulatedinsideforeignfb');
if you now look into "motor1" which was actually manipulated inside POU1, it will still have the string in it 'ManipulationFromOutside' which means POU1 manipulated a copy. And this is my Problem:
Copy's don't make sense at all in an OOP aproach, and if I use pointers or references, I face the problems already describe in this post?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This is a great post on how to create dynamic function blocks using interfaces with proper samples and not only pseudocodes.
Of course I understand you, copies are not what you are after.
In my sample I'm using pointers everywhere to update from outside data that exists on the pointed function block. Unless I've made a mistake (more than possible given I've written the code directly here) it should work properly.
See that article from Stefan which I guess it will give you some extra light on how to do it.
Hope this helps.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for your help, I finally found it yesterday. Interfaces are treated as pointer anyway so the declaration as POINTER TO or REFERENCE TO makes no sense resp. is not useful.
So if you want to use a FB as "fb instance", define in your input/output/method/property "fbinstance : POINTER TO FBType" .
Then you can pass the real pointer from the caller of an FB with ADR(fbinstance).The "opposite direction" would be the ^, so if you need to have the instance, instead of the pointer, often used if you refer to the instance with THIS, you will need the ^ so it doesnt take the pointer, it takes the instance.
To hom it may be interessting:
The goal of our ErrorHanlder code is:
1. Encapsulate functionality to where it belongs to and have a "nice" architecture.
2. Maybe more important, we will have libraries in our company. So if you want to be able to still encapsulate the functionaly of errorhandling inside the error causing element/FB you need kind of an Interface to the element which effectifly handles the error. If your component is in a library, there is no filesystem where you can log to, therre is no HMI you can show your error, resp. you don't know where you will be running.
In our case we startet with a motor. So if the motor runs, and there is something wrong it needs to raise an error and keep the error state. As soon as the error is gone, it can start again. (Could be a circuitbreaker or a VFD in overload, what ever). We in our company normaly want the user to commit an error, so the motor stays in errorstate as long as the user does not commit the error.
For this we have 2 Interfaces:
- The AlarmHandlerInterface (this will be implemented by the FB which is actually resetting the error, making the decision if it has to be logged or viewed on a screen. And it handles user actions to reset the errors.
- The AlarmSourceInterface. This is needed because we want like a callback method to the error causing element so we can reset its errorstate.
INTERFACEAlarmHandlerInterface(*------------------------------------*)METHODRegisterAlarmVAR_INPUTÂ deviceWithAlarm:Â Â AlarmSourceInterface;END_VAR
If the Motor which implements AlarmSourceInterface needs to raise an alarm, it needs to call the RegisterAlarm method from the AlarmHandler which implements the AlarmHandlerInterface (and needs a type of AlarmSourceInterface in this signature). We in our case provided the AlarmHandler to the Motor in the FB_Init method (like a contstructor) so its only called once.
The AlarmHanlder will then put the Motor into an internal list, like this:
METHODRegisterAlarmVAR_INPUT  deviceWithAlarm  :  AlarmSourceInterface;END_VAR(*------------------------------------ *)devicesAlarmList[devicesInList]:=deviceWithAlarm;devicesInList:=devicesInList+1;
In this case its a fixed Array with 100 elements, im sure its possible to improve this to a dynamic approach. Because normally you don't know how many items will be added and need to increase the size of the array / list dynamically.
This code is called when for example the operator on a HMI pressed a button to commit all errors:
METHODPUBLICResetAllAlarms(*------------------------------------*)//ResetsallthealarmsoneachmotorFORcurrentDevice:=0TOdevicesInList-1DO
 devicesAlarmList[currentDevice].resetAlarm();END_FORdevicesInList:=0;
It goes through the array which has only items of type AlarmSourceInterface in it and calls on each of this devices the reset alarm method.
In the future we could also implement warnings and maybe sort of an autocommit depending if you use it.
In our case, the Interfaces and the Motor itself will be in the library. The AlarmHandler is in the project were your work is done.
I will add the project for you so you can have a look into it. I also added pragmas so you see were you have to so something.
Greetings and thanks a lot for your patience. I hope I can put more samples here in the future.
Hello together
We are willing to go for the "OOP" approach with our new PLC implementation. We are struggling a little bit with Codesys and how its supposed to be done in IEC 61131-3. At the moment we are writing down the basic architecture. Both of us have enough expierence with JAVA and C#.
What we want to do is a simple Alarmhandling interface with basic OOP concepts. What's struggling us at the moment is the fact that the FB's seem to get copied when assigned to member variables resp. on method calls.
So from our understanding.
If I do this:
and then do this:
The alarmhandler would not see this change, because he got a copy. This led us to use ```
REFERENCE TO
in the declaration. But then we face either strange access violations during runtime because we seem to do something wrong or if we use the
REF=
``` assignment, we got strange messages like:
"Can not convert type Motor to type "Pointer To AlarmSourceInterface", even if the Motor does in fact implement the AlarmSourceInterface."
Normally in any other language I would not ask such silly questions, but for "IEC-61131-3" it seems to be near to impossible to find usefull code or samples in the internet. I found some, but only a little, especially to the OOP implementations. And I also didn't find a lot of usefull books written after 1980 .
Do you guys do it the same way with references or is there something we don't get?
Really appreciate your Input
BasicOOPAlarmInterface.project [115.63 KiB]
Hi schaepper,
Keep in mind that Codesys doesn't support pointer typecast so in your case you expect a reference to the alarmhandlerinterface (the pointer) and you are passing the object itself not it's address.
Also it is possible to do some small things in the VAR declaration area, such as ADR() calling, but not all the code can be placed there (so I don't know if REF= suits there never tried it).
If you want to send a reference of an object you can use several methods:
REFERENCE *
you are not passing the reference in your example (I've used notepad to see your code as in the computer I'm now I don't have any codesys compatible software installed).
Let's see if those links help you:
Hope this helps.
Thanks for your post, but I think i dont really understand what you mean.
If have this Motor:
Now if I want to use the Motor I would do this in my PLC_PRG:
When I now go for step by step debugging, here:
motor1(alarmHandler := alarmHandler1); it looses the reference when I later on look on the variable inside the motor:
I cant do this, because its not allowed by syntax:
motor1(alarmHandler REF= alarmHandler1);
So what do I need to do now? If I want to pass alarmHandler1 into the motor? What you think is an elegant way? I ask you this because then I could do this:
mAlarmHandler.registerAlarm(THIS^); --> No errormessage
mAlarmHandler.registerAlarmByReference(THIS^); --> Gives an errormessage as you explained.
And I would not have the problem that I can't compile the code because it sais the errormessage I mentioned before.
@Edit:
PS thanks for the links, I think I already knew them...
THIS is a pointer not a reference...
Probably the best in your case would be using something like:
But in your case the most "elegant" way of doing it would be using a property and a reference or a pointer.
If you want to use FB_Init I've used the pointer approach successfully so you should not have any problem doing that.
Keep in mind that when you do an online change pointers can need to be reassigned as the memory addresses can move.
Hope this helps.
Hi.
Var_input variables are public fb_variables.
Var_output are public with readonly access.
Every cycle varinput and output are copied. If you pass an fb, the fb is full copied.
You make two copies. One in varinput assignement and other in private variable.
If you use varinout, only is copied the fb pointer, and you are working with the fb passed.
Fb_init is the constructor, but it not accepts varinout, in that case you have to pass the pointetr and copy it to an internal variable.
Pass in fb_init is faster because it is not necessary to copy the reference every cycle, but when your make the logical code could loose how the connectioms are made
Thanks for your answers, I did what you explained to me (change from "REFERENCE TO" to "POINTER TO"), and the i provide the instance by
But now it says "Cannot convert type 'Pointer to AlarmHandler' to type 'Pointer to AlarmhandlerInterface'. But AlarmHandler implements AlarmhandlerInterface.
Variable definition from Motor looks like this:
AlarmHanlderCode Looks like this:
Additionaly since I changed mAlarmHandler to be a Pointer, it sais C0062 "mAlarmHandler" is no structured variable on the following piece of code:
And if I hover over the mAlarmHandler its sais something like "Program name, function or function block instance expected instead of 'mAlarmHandler.registerAlarm'". Is that the same reason, so I cant do this on a pointer?
By the way:
I want to avoid VAR_IN-OUT in any case if possible because it breaks my interfaces and object resp. FB's encapsulation "by definition". To me they would be like public variables and thats (at least to me) not a solution.
Appreciate your help!
Take a look at the properties to get a more similar way to share variables with the outside world.
Remember that the pointers doesn't allow typecasting here, if you define a pointer to a specific type you can't pass a different pointer there.
The ^ sign means dereference here, so if you are passing this^ you are passing a copy of the complete function block (or the object this points to), but if you are passing this (without the ^) then you are passing the address (the pointer) which is what you want now.
Just please remember to initialize the pointer address to 0 in the declaration and check if the pointer is different than 0 before using it to endure you won't have undesired page faults.
Hope this helps.
I tried it without the ^ but it still gives me the same alarm.
"Remember that the pointers doesn't allow typecasting here, if you define a pointer to a specific type you can't pass a different pointer there."
What would be the solution? Just as an info: My goal is not to use references, or pointers, whatever I just want to pass the same instance of a FB around. If I do it the "classic" way without pointers,refs or anything then the FB's always get copied on asignments. I just want to overcome the copies.
Basically I just want to use it like every other "OOP" language in the field like C#,JAVA,Python,C++ what ever...
I attached my latest project to this post if someone is interested.
BasicOOP.project [114.17 KiB]
pseudocode:
Hope this helps.
motor();
This is exactly the code that will not work because it sais:
Canot convert type "Pointer To AlarmHandler" to type "POINTER to AlarmHandlerInterface"
This where all the post is about...
Yes, the problem is the type.
You can't typecast pointers.
In my code the pointer points to the function block type not to it's interface.
In your code, given the name it looks like it points to the interface the function block implements.
Check the last link I pasted in the first message, Stefan shows how to use interfaces correctly to get the most similar to what JAVA, C++, C# gives you.
In any case it is not important what interface you implement, you are passing the function block pointer (in my example pseudo code).
If you want to be able to use a more dynamic approach (given your background and the advantages it offers it is normal you would like to) then look at the Stefan link where good samples are implemented and deeply explained.
Hope this helps.
You refering to this? https://stefanhenneken.wordpress.com/20 ... nterfaces/
I read it completely, even time before but it does not (and in any article) explain the problem of "objects" always beeing copied if you don't use Reference To or similar approaches.
If you don't use REFERENCE TO, POINTER TO or what ever if you just declare FB's as normal. And you pass a FB to another FB, and the "foreign" FB manipuliates the FB you are providing, he will manipulate the copy, not the FB you are providing.
Here is my Pseudocode:
motor1.ManipulateCopyTestString('ManipulationFromOutside');
motor1(alarmHandler := alarmHandler1);
POU1(motorInput := motor1);
//This is the Methodcall from POU1
motorInput.ManipulateCopyTestString('manipulatedinsideforeignfb');
if you now look into "motor1" which was actually manipulated inside POU1, it will still have the string in it 'ManipulationFromOutside' which means POU1 manipulated a copy. And this is my Problem:
Copy's don't make sense at all in an OOP aproach, and if I use pointers or references, I face the problems already describe in this post?
Check this one: https://stefanhenneken.wordpress.com/2014/11/16/iec-61131-6-abstract-factory-english/
This is a great post on how to create dynamic function blocks using interfaces with proper samples and not only pseudocodes.
Of course I understand you, copies are not what you are after.
In my sample I'm using pointers everywhere to update from outside data that exists on the pointed function block. Unless I've made a mistake (more than possible given I've written the code directly here) it should work properly.
See that article from Stefan which I guess it will give you some extra light on how to do it.
Hope this helps.
Hi.
Convert first your fb to an interface:
A:Interface;
B:fb_ whichimplements interface
B=A
And pass b sa var_input.
Codesys treates as pointers. If you see in debug B you can see the address of A littlel bit offseted.
But if an fb waits for an interface as input, before you have to cast it.
Originally created by: Viacheslav Mezentsev
Example works for me (Codesys 3.5.11.0). Maybe I'm don't understand something?
BasicOOP.project [114.17 KiB]
Hello everybody
Thanks for your help, I finally found it yesterday. Interfaces are treated as pointer anyway so the declaration as POINTER TO or REFERENCE TO makes no sense resp. is not useful.
So if you want to use a FB as "fb instance", define in your input/output/method/property "fbinstance : POINTER TO FBType" .
Then you can pass the real pointer from the caller of an FB with ADR(fbinstance).The "opposite direction" would be the ^, so if you need to have the instance, instead of the pointer, often used if you refer to the instance with THIS, you will need the ^ so it doesnt take the pointer, it takes the instance.
To hom it may be interessting:
The goal of our ErrorHanlder code is:
1. Encapsulate functionality to where it belongs to and have a "nice" architecture.
2. Maybe more important, we will have libraries in our company. So if you want to be able to still encapsulate the functionaly of errorhandling inside the error causing element/FB you need kind of an Interface to the element which effectifly handles the error. If your component is in a library, there is no filesystem where you can log to, therre is no HMI you can show your error, resp. you don't know where you will be running.
In our case we startet with a motor. So if the motor runs, and there is something wrong it needs to raise an error and keep the error state. As soon as the error is gone, it can start again. (Could be a circuitbreaker or a VFD in overload, what ever). We in our company normaly want the user to commit an error, so the motor stays in errorstate as long as the user does not commit the error.
For this we have 2 Interfaces:
- The AlarmHandlerInterface (this will be implemented by the FB which is actually resetting the error, making the decision if it has to be logged or viewed on a screen. And it handles user actions to reset the errors.
- The AlarmSourceInterface. This is needed because we want like a callback method to the error causing element so we can reset its errorstate.
If the Motor which implements AlarmSourceInterface needs to raise an alarm, it needs to call the RegisterAlarm method from the AlarmHandler which implements the AlarmHandlerInterface (and needs a type of AlarmSourceInterface in this signature). We in our case provided the AlarmHandler to the Motor in the FB_Init method (like a contstructor) so its only called once.
The AlarmHanlder will then put the Motor into an internal list, like this:
In this case its a fixed Array with 100 elements, im sure its possible to improve this to a dynamic approach. Because normally you don't know how many items will be added and need to increase the size of the array / list dynamically.
This code is called when for example the operator on a HMI pressed a button to commit all errors:
It goes through the array which has only items of type AlarmSourceInterface in it and calls on each of this devices the reset alarm method.
In the future we could also implement warnings and maybe sort of an autocommit depending if you use it.
In our case, the Interfaces and the Motor itself will be in the library. The AlarmHandler is in the project were your work is done.
I will add the project for you so you can have a look into it. I also added pragmas so you see were you have to so something.
Greetings and thanks a lot for your patience. I hope I can put more samples here in the future.
BasicOOP_AlarmHandling.project [113.41 KiB]