LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Custom Event Queue - converting cluster references to objects

Solved!
Go to solution

I would like to use a queue to manage multiple tasks that must be executed at periodic intervals.  The number of events and the time between them will not be defined until runtime.  These are not "front panel" events or "user events" but background execution events like "read temperature" or "measure voltage"  The most fundamental implementation might use a cluster with a long integer to store the execution time and a string to indicate the name of the event to be raised at that time.  References to each event could be added to the queue in any number and in any order.  Instead of handling the queue in the standard FIFO order, the queue will be sorted by execution time.  The bottom loop with monitor the queue and raise the events as the test runs.  The loop previews the front-most element in the queue until the current time is equal to or greater than the execution time of the event.  Then the cluster would be dequeue and raise the event before being discarded.

 

I'm confident I can assemble and sort the queue but I'm having trouble with the handling loop below.  I can't seem to convert the cluster references back to cluster objects in order to access the numeric and string contents.  I tried using the functions below but with no success. 

 

Also, I'm unclear exactly how each event gets raised or triggerd when its execution time has arrived.  I realize the code I've attached is not functional but I wanted to keep it simple and I'm only asking questions about the bottom loop. 

 

The queue I'm describing should be distinct from the internal event queue LabVIEW uses to respond to Front Panel input and updating indicators.   I've also added an image of my block diagram and the vi file.   I'd appreciate ideas and suggestions to move this forward.  Thanks.

 

Ref to Obj.png

 

Here is my block diagram

custom event queue.png

0 Kudos
Message 1 of 11
(1,204 Views)

You should generate the User Event at the time of Current time exceeding the Cluster time (i.e. inside the bottom case diagram), and instead of putting the Event Refnum into the queue, just put the cluster itself. I think then you will find it much more straightforward.

0 Kudos
Message 2 of 11
(1,183 Views)

You've created a queue of user event references.

 

You want a queue of data. Or a user event.

 

If you want a queue of data why is the user event there at all?

 

Choose between a user event or a queue.

 

Don't put a user event reference in the queue! You're enqueueing the same reference. The user event that you generate is never read anywhere. You need an event structure to register for that event, and only the event in the top loop does that.

 

wiebeCARYA_0-1649147245164.png

 

 

 

You still have other problems...

 

A Preview Queue Element will only preview the first element. What if the 2nd element needs to be executed earlier? Then again, what if the 1st element is executed and a 2nd comes in with an earlier time?

 

You should probably flush the queue, and collect all elements and tread them as a collection.

Message 3 of 11
(1,167 Views)

Thanks for your reply.  I can see that I should have enqueued the cluster itself, not the reference.  In terms of your other comment, perhaps you missed that I am planning to sort the queue by time stamp rather than using it as a standard FIFO.  That way I can be confident that the first item in the queue is the next to be executed.  Maybe a sorted collection as you suggested would work better.  I'll look into that.

0 Kudos
Message 4 of 11
(1,136 Views)

Thanks for your reply.  Yeah, initially I tried using a queue of clusters but I believe the "Generate User Event" function returns a reference to a cluster which a queue of type "cluster" will not accept (see the image below).   After a fresh look at it this morning, it seems like the "Generate User Event" function is intended for capturing "user events" as the name implies.  But I'm trying to work with custom events (background data collection tasks) so I think it's the wrong function for me.  I guess I'm unclear on how to create and raise a custom (non-user) event.  Can an event be raised somehow using the name (text or string) of the event?

 

using a queue of type "cluster"using a queue of type "cluster"

0 Kudos
Message 5 of 11
(1,130 Views)

@skinnedknuckles wrote:

Thanks for your reply.  Yeah, initially I tried using a queue of clusters but I believe the "Generate User Event" function returns a reference to a cluster which a queue of type "cluster" will not accept (see the image below).  


The Generate User Event returns it's input... The input is a user event reference. The type of the user event reference is user event reference to a user event that has a cluster as user data. You can certainty enqueue that, but you need a queue with a "user event reference to a user event that has a cluster as user data" as it's queue type. Not sure why do would want that (I can think of a few reasons, but that's not your scenario).

 

Queues and user events can both serve your goal. Pick one. User events or queues. You don't need to mix them.

 

Queues are used many to one. Many writers, one reader. You can dequeue in more then one place, but the other places won't get the elements. Each element is dequeued once.

 

User events are many to many. Many writers, many readers. Each registered event structure gets it's own stack of events, and each generate user event gets added to each registered event structure. (Formally, events get stacked even without an event structure, it's the registration that makes them stack. Don't register and forget to use an event structure).

 

Events.png

 

There's also an example: "User Event Generation.vi"...

 


@skinnedknuckles wrote:

  After a fresh look at it this morning, it seems like the "Generate User Event" function is intended for capturing "user events" as the name implies.  But I'm trying to work with custom events (background data collection tasks) so I think it's the wrong function for me.  


There's no such think as a "custom (non-user) event".

 

There are user events and events. The user events are custom, the non-user events are build in. 

 


@skinnedknuckles wrote:

 I guess I'm unclear on how to create and raise a custom (non-user) event.  Can an event be raised somehow using the name (text or string) of the event?


No, you need the user event's reference to generate a user event. You are already doing that! Passing the user event reference to a queue makes no sense at all. You generate the user event, and event structures registered for it will catch that event.

 

You can't generate user events by a name string, but the data you send can be a string.

 

Also (at the risk of making things more confusing), you could make a map with strings and user events, and get a specific user event by it's name and use it to generate an event.

0 Kudos
Message 6 of 11
(1,113 Views)

Hey Wiebe,

 

Thanks for elaborating.  This is very helpful.  I hear you saying that queues and events are redundant and I should pick one or the other.  Maybe I should back up and ask more fundamental questions. 

 

What if I have 4 different background data collection tasks or actions that I need to execute every 1, 5, 15 and 60 seconds repectively for 4 days.  What data structure would you use to represent these tasks or actions and how would you organize them?  What kind of container would you use to store them that would allow you to sort them and execute each one at it's designated time?  I thought a queue of clusters would serve this purpose and that's why I picked it.  Are there alternative data structures and containers you'd prefer to manage a large collection of tasks or actions?  I could just make some while loops with delay timers in them but I have been assuming there is a more comprehensive way to do this that could handle more complicated scenarios such as non-periodic execution of the tasks or actions.

 

Secondly, I found the description below on Events in LabVIEW on the NI website:

 

LabVIEW generates events from the following sources:

  • User Interface—User interface events include mouse clicks, key presses, and so on.
  • External I/O—External I/O events include hardware timers or triggers that signal when acquisition completes or when an error condition occurs.
 

 

Note  LabVIEW also supports ActiveX and .NET events, which are external I/O events that you can generate programmatically.
  • Block diagram—Block diagram events, or programmatically generated events, include user events, which allow you to generate events with data you define, and other events that occur from the block diagram.

 

I guess when I said "custom (non-user) event" I meant the third source in this list, that is, events generated in the block diagram.  I'll try to find more information on this topic.

 

Thanks again,

 

skinnedknuckles

0 Kudos
Message 7 of 11
(1,101 Views)

I would not have a master tasks queueing events to the lower level tasks. I would have each task control it's own timing. Each would be it's own state machine and at startup you can configure the desired frequency it should collect it's data at. By trying to have a master task handle all of the timing will make things very complicated and a pain to maintain. Treat each data collection task as it's own self contained entity. The master task simply starts the data collection tasks up. Perhaps it can start/stop them during execution or modify the collection frequency but these would be discrete commands given to the task.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
0 Kudos
Message 8 of 11
(1,088 Views)

I think you have a small misunderstanding of how user events work. User events are somewhat poorly named. They sort of imply "events caused by the user", which is incorrect. They are actually "events defined by the programmer".

 

When you generate a user event with Generate User Event, event structures that are registered for that user event fire right away. You do not pre-generate user events like you seem to be trying to do. If you want to use a queue to store the things you need to do, store them as clusters, then generate them when you need to use them, not all ahead of time.

 

Alternatively, unless you need parallel processing you don't really need to use user events at all. Just use your queue, then when you need to process that element just process that element and "do the thing". User events have an internal queue and are handled in the order in which they're generated with no delay between them (assuming your Event Handler loop is in fact in a loop).

 

In your event queue, you register for the event using the Dynamic Event Registration terminals, but you need to add a case to actually do something with that event. Right click on it and select "New Event" then pick your dynamic event to handle it. Again though, you probably don't need user events at all. Just iterate through your queue and, when the timing is correct, dequeue the element and use the EventName on a case structure with the correct subVI(s) inside it.

Message 9 of 11
(1,062 Views)
Solution
Accepted by topic author skinnedknuckles

@skinnedknuckles wrote:

Hey Wiebe,

 

Thanks for elaborating.  This is very helpful.  I hear you saying that queues and events are redundant and I should pick one or the other.  Maybe I should back up and ask more fundamental questions. 

 

What if I have 4 different background data collection tasks or actions that I need to execute every 1, 5, 15 and 60 seconds repectively for 4 days.  What data structure would you use to represent these tasks or actions and how would you organize them?  What kind of container would you use to store them that would allow you to sort them and execute each one at it's designated time?  I thought a queue of clusters would serve this purpose and that's why I picked it.  Are there alternative data structures and containers you'd prefer to manage a large collection of tasks or actions?


A cluster in an array does that.

 

You don't really need a queue at all. If all actions are predefined, you can simply make a VI that returns an array of actions (class or cluster, enum, string, whatever). You can then loop through that array.

 

If you have processes that create the actions "on the fly", then you could indeed use a queue of clusters.

 

Or a user event with the same cluster. That is what the image I send earlier does.

 

In your original post you did create a queue of clusters. That could work. You then tried to add a user event registration to that queue. That didn't work. You need a queue of user event registrations to be able to enqueue a user event registration. You can enqueue a cluster in a queue of clusters.

 

 

0 Kudos
Message 10 of 11
(1,047 Views)