NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

Synchronous UIMessage Question

I am developing an application using LabWindows/CVI 8.0 and TestStand 3.5. I am using the Batch process model with 8 test sockets. I have a sequence step that is being carried out in the UI due to TestStand's inability to sink ActiveX events. The server/client objects work fine and I get events as expected.

The sequence step simply sends a user defined UIMessage to the UI application which will start the ActiveX operations and wait on completion. I set the synchronous property of the UIMessage to TRUE to block the calling thread until I am done. That works fine. In the UIMessage event handler, I simply wait until the Active X operation is done. My waiting consists of a simple "Do until done" loop that calls Delay(.1) followed by ProcessSystemEvents(). On a single execution, this works fine. When I run more than 1 socket, i.e. multiple executions, it appears to want to run in a batch sequential fashion.

My understanding of the "synchronous" property is that the TestStand thread that sent it will block. My assumption is that each execution runs in its own thread and if a test socket (execution) hits that sequence step, it will block until done. My understanding is that other sockets/executions should be able to execute the same step concurrently with each blocking until the step is done. Is my understanding correct? If so, why don't the other threads post the UIMessage. BTW, I checked via a LabWindows breakpoint and a subsequent UIMessage from another socket does not arrive until the previous socket's message has completely been processed.

John

0 Kudos
Message 1 of 18
(5,371 Views)

Although you have can have any number of independent execution threads, there is only one GUI thread in the application handling UI messages from these threads. It can only handle one message at a time. If takes a long time to handle a synchronous message, it is going to block all other execution threads that are sending synchronous messages (for example, trace messages).

Thus you should immediately acknowledge the message that triggers the lengthy operation and then use some other method to notify the requesting thread when the operation completes.  The methods you can use for this are endless, but they include TestStand globals or synchronization objects and environment specific globals or synchronization objects.

0 Kudos
Message 2 of 18
(5,369 Views)
Thanks James. You have confirmed what I am thinking. If I do a UI Message Acknowledge, the executions take off again. I am currently looking at the TestStand Notification synchronization object. I'm not sure how to do this but I am looking at the GetSyncManager method of the Engine object. Can you shed some light on the right way to to use a Notification created in TestStand but manipulated in LabWindows?

Thanks,
John
0 Kudos
Message 3 of 18
(5,365 Views)

Refer to the SyncManager topic in the API online help (this help topic is in 3.5, I'm not sure about earlier versions).

After you have your sequence create and wait on a notification, I'm guessing you would put something like the following pseudo code in your UI:

ISyncManager mgr = Engine.GetSyncManager("MyNotificationName")

mgr.GetNotification("MyNotificationName").Pulse(dataObject, byRef, applyToAllWaiters)

or

mgr.GetNotification("MyNotificationName").Set(dataObject, byRef, autoClear)

To call into the sync manager from CVI, you'll to use the functions in the <TestStand>\API\CVI\tssync.fp instrument driver. So it would be more like:

TSSyncLib_ISyncManagerGetNotification (syncManagerHandle, NULL, "MyNotificationName", &notification);

etc.

 

 

 

 

 

0 Kudos
Message 4 of 18
(5,361 Views)
James,
I tried what you had suggested but I'm having a problem with it. My LabWindows code is below.  It bombs in the GetNotification call and I get an error dialog indicating "Operation Failed". I traced the code into the GetNotification function and found that at failed where CA_GetInterfaceFromObjHandle is being called. This tells me that there is something wrong with my syncManager handle. Any ideas?
Thanks,
John

LPUNKNOWN tempActiveXRef;
CAObjHandle   syncManager;
CAObjHandle   notification;
VARIANT          tempVairant;

// Get the sync manager
TS_EngineGetSyncManager (gMainWindow.engine, &errorInfo, "fn", &tempActiveXRef);
    
// Convert LPUNKNOWN to VARIANT
tempVariant = CA_VariantIUnknown(tempActiveXRef);

// Convert VARIANT to Object Handle
CA_VariantConvertToType(&tempVariant, CAVT_OBJHANDLE, &syncManager);

// Now that we have the syncManager as a handle, get and set the notification
TSSyncLib_ISyncManagerGetNotification (syncManager, &errorInfo, "fn", &notification);
TSSyncLib_INotificationSet (notification, &errorInfo, (CAObjHandle)NULL, VTRUE, VTRUE);

Message Edited by jlgeek on 06-12-2006 02:04 PM

0 Kudos
Message 5 of 18
(5,351 Views)
Hi John,

One possibility I see is that the Notification "fn" might not exist anymore. The errorInfo struct for the GetNotification call might have more info about the error. Are you calling CreateNotification somewhere before this code is getting called  (either from a notification step or in your cvi code?) and are you keeping the reference to the notification around long enough? You need to make sure that the notification is created first, before any threads try to use it, and that it is being kept around as long as they need it.

Hope this helps,
Doug
0 Kudos
Message 6 of 18
(5,345 Views)
Hi Doug,
Thanks for the input. I am creating the notification in the Setup group for the Main Sequence in TestStand. Just for testing, I am using the name of "fn". The actual application will have a name built with the str() function in TestStand. The lifetime of the notification is set the lifetime of  the execution. In my UI application, I press a start button which starts the execution and runs to completion. UI Messages are used to update the user interface (works fine) and start some processes. The execution in this test case simply sends a UI message to start a process and immediately following, it Waits on the "fn" notification. The UI code tries to set the notification by the code provided in previous replies to this thread. As far as I can tell, the notification still exists when I try to set it. I must admit that I am new to ActiveX programming and the TestStand API. Most of the things I've done seem to work ok but sometimes I wonder whether I am dealing with references correctly all the time.  I try to understand when to destroy handles  and clear variants and when the API handles it for me. It isn't always clear.

Regards,
John

0 Kudos
Message 7 of 18
(5,344 Views)
Are there more details in the error string part of the error info structure?

-Doug
0 Kudos
Message 8 of 18
(5,329 Views)
I think I know what might be the problem. I think you should use CA_CreateObjHandleFromInterface to create the objhandle for the sync manager instead of the variant functions you are using.

Here's an example:

    errChk( CA_CreateObjHandleFromInterface (tmpUnk, &TSSyncLib_IID_ISyncManager, 1,
                                             LOCALE_NEUTRAL, 0, 0, &synchManager));

then call CA_DiscardObjHandle on the handle when you are done with it.


Hope that helps,
-Doug

Message Edited by dug9000 on 06-13-2006 11:34 AM

0 Kudos
Message 9 of 18
(5,329 Views)
Thanks Doug. That was the problem. It now works fine but I'm not sure that I understand the mechanisms. I probably need to better understand the LPUNKNOWN data type and how to manipulate it in various circumstances. I've used the variant technique (obtained from the forums) in changing LPUNKNOWN to object handles in other places successfully. For instance, I use the technique when using the ActiveX adapter to get the context handle from the ActiveX data parameter which is passed as an LPUNKNOWN. I guess that this situation is different. I'm not an ActiveX programmer but I am attempting to learn about LPUNKNOWN, IDispatch, IUnknown, interfaces, etc. etc.

Again, thanks for your input.
John

0 Kudos
Message 10 of 18
(5,319 Views)