Join us today!

Notifications
Clear all

[Solved] How to create a generic queue which works for every datatype including structs?

5 Posts
3 Users
4 Likes
613 Views
rruiter
Posts: 63
Topic starter
(@rruiter)
Estimable Member
Joined: 2 years ago

The queue would be a first one in, first one out (FIFO) type, much like this example from InfoSys. But then I want to have a generic implementation. The example from InfoSys works with a fixed STRUCT.

Ideally you would instantiate the struct and pass the size of the queue with it:

VAR
    queue : Queue(n=40)
END_VAR

Then you can add and remove items and get the size of the queue as follows:

VAR
    position1 : Coordinate3D :=  (x:=3, y:=8, z:=-1);
    position2 : Coordinate3D :=  (x:=9, y:=1, z:=0);

    size : UINT;
    currentPosition : Coordinate3D;
END_VAR

queue.Add(position1);
queue.Add(position2);
size := queue.Size(); // 2
currentPosition := queue.Pop(); // (x:=3, y:=8, z:=-1)
size := queue.Size(); // 1

Is this possible in TwinCAT? Making some sort of generic queue for basic types like INT, BOOLs is probably possible using T_Arg/ANY. But how would you do it if you would also include STRUCTs?

Reply
Topic Tags
4 Replies
1 Reply
benhar-dev
(@benhar-dev)
Joined: 2 years ago

Eminent Member
Posts: 17

@rruiter (just remaking a broken post link)

This is possible.  The only thing you can't do is currentPosition := queue.pop() as this would require the method having it's return type known at design time.  Instead you would do queue.pop(currentPosition);

This example can be found here. 
https://github.com/benhar-dev/tc3-push-pop-stack

 

This repo shows how you can push and pop any variable type.  The queue will automatically type check on the way out and will prevent the pop if you try to pop it to the wrong variable type.  

If you are going to be pushing huge numbers of things in to the queue then just keep an eye on your router memory (as that is the pool which __NEW objects are created from) and you may want to increase this if need be. 

I've used this style quite a bit in a few projects.  You can then make small tweaks to the code to make it a key/value pair, a dynamic array, a sorted list.  Ultimately it's an object that holds objects which it looks after.  👍

Reply
TwinControls
Posts: 71
Admin
(@beckhoffsupport)
Member
Joined: 2 years ago

Hi,

I have attached a generic data tracking function block (dictionary) and a program to test it. I have added one integer and one real data type into the list. Inside the Prg_Dictionary program, you need to give a key name to your generic data and use the correct argument conversion function to set your value. (F_INT(), F_REAL(), F_DINT(), F_BOOL() …) 

I have used two data types for test purposes but you can use any data type you would like. 

dataTypes
partTracking

fbPartList contains the key lists and value lists as well as the list size. This is what it looks like after adding an integer and a real value. 

genericData

Hope this helps! It would be great if you can share your thoughts after using it. Maybe you can get it to working with generic structures as well. 

 

Reply
2 Replies
rruiter
(@rruiter)
Joined: 2 years ago

Estimable Member
Posts: 63

@beckhoffsupport Thanks for the reply! I like that your solution makes it easier to see how many items there are in the buffer during debugging. But, I find the solution of @benhar-dev easier to use. With T_Arg you always need the extra function (F_INT, F_REAL, etc.) to get the type information. Also Ben's solution doesn't require a global variable to fix the size of the buffer.

Reply
TwinControls
Admin
(@beckhoffsupport)
Joined: 2 years ago

Member
Posts: 71

@rruiter You are welcome! Yes, @benhar-dev solution's works great and you don't have to define the list size as you said. The one I shared works as a hashmap . It's nice to be able to pop anything by using its 'key name'.

Reply
Share: