My main language is embedded C/C++, but I have a little background in structured text and worked with Codesys a while back in school. I am still figuring out what is possible and best practice in the Codesys environment.
Currently, I am working on a project with a controller PLC that will be controlling a few other devices over CAN bus. I've written the programs to communicate and control the different devices, which I call modules. I call on the modules with my main PLC program (PLC_PRG).
As an example, I added a simplified version of the software structure below.
Now, every device that I'm communicating with has a different cycle time that it wants is communication in. Because of that, I currently have given every module their own task with their own cycle time and priority.
For the PLC_PRG to interact, I use public methods and properties. I really like this functionality and would like to keep using it this way, but I have stumbled on a structural question that made me wonder what would be better practice.
There is a possibility I'll have two or more of one device that all need to be communicated with individually. This would mean that I'd need to be able to run multiple instances of the module.
As far as I can figure out, it is not possible to run multiple instances of a program as tasks. It is also not possible to make a function block a task as it needs to be initiated as an object in a program to be used.
There are different ways in which I could rewrite the modules as function blocks and run them at timed intervals from the main plc_prg. But I don't like the visualisation of that solution and really like the way task management works in Codesys. So what would be the best practice of having multiple instances of function blocks that need to run on a certain cycle time different from the main PLC_PRG?
P.S. While I was writing this, I had a thought that I could split up the module in a function block and an interface program in which I then could create the different instances and could be called as a task. Then PLC_PRG would interact with the interface program. It still feels like a little crude of a solution, though.
A quick example of the idea:

