Messages get queued

Post questions, comments and feedback to our 3Dconnexion Mac Development Team.

Moderator: Moderators

Post Reply
Martin
Posts: 6
Joined: Tue May 22, 2007 5:36 pm

Messages get queued

Post by Martin » Tue May 22, 2007 5:55 pm

Hi,
I'm trying to add SpaceNavigator support to our 3D Modeler. But I run into a problem. I'm calling the redraw function for the 3D scene directly in the Connexion message handler. That works fine for simple scenes but it doesn't work for complex scenes. It looks like the messages get queued. So all movements get delayed more and more after some time. After removing my had from the space navigator there are still messages sent for some time.

You can easily reproduce that behavior if you modify the "3DxCubeCarbon" example project which comes with the SDK.

Code: Select all

void drawGL (pRecContext pContextInfo, Boolean swap)
{
    // printf("Result of drawGL: Context = %08X = %08X  \n",  pContextInfo, pContextInfo->aglContext ); fflush( stdout );
    
    if ( !pContextInfo || !(pContextInfo->aglContext) )
        return;
    
    // ensure the context is current	
    aglSetCurrentContext( pContextInfo->aglContext );
    
    updateProjection( pContextInfo );
    
    // clear our drawable
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
    // projection matrix already set	
    updateModelView(pContextInfo);
    
    glCallList( pContextInfo->polyList );
    
    if ( swap )
        aglSwapBuffers (pContextInfo->aglContext);
    else
        glFlush();
    
    
    ////////////////////////////////////////////////////
    //add these lines too the 3DxCubeCarbon example code
    ////////////////////////////////////////////////////
    
    int i;
    for(i=0;i<1500000;i++){
       float f=5;
       f=sqrt(f);
       }
    
    ////////////////////////////////////////////////////
    //add these lines too the 3DxCubeCarbon example code
    ////////////////////////////////////////////////////
}

The few added lines should just show what happens if the drawGL function consumes some more CPU time.

Any help would be highly appreciated.


Bye,
Martin

P.S. I use Mac OS X 10.4.9, Driver 1.2, Firmware 3.18

flomotan
Moderator
Moderator
Posts: 287
Joined: Mon Jan 08, 2007 3:37 pm

Post by flomotan » Fri May 25, 2007 2:15 pm

If the display update and the device event handler are running on the same thread, I'd suggest creating a separate thread to listen for device events.

That way, device events don't queue up. Another option is to look at the timestamp for the incoming device event and compare that to the current time. If the device event time is stale (!= to current time), you can choose to ignore the event. The time format is uint64_t as returned by clock_get_uptime.

Having a separate thread to handle device events works very well. You can do something similar to this Carbon code

Code: Select all


//==============================================================================
// Public APIs to be called whenever the app wants to start/stop receiving data
// Mark these function for weak-linking to avoid runtime issues if the 3dconnexion framework
// is not installed
extern OSErr	InstallConnexionHandlers	(ConnexionMessageHandlerProc messageHandler, ConnexionAddedHandlerProc addedHandler, ConnexionRemovedHandlerProc removedHandler) __attribute__((weak_import));


TdxDeviceEvents::TdxDeviceEvents () 
{
	// Check if the driver is installed
	if (InstallConnexionHandlers == NULL)
		return;

	/* must save the main event queue while we're running within the main thread.
	* GetMainEventQueue() is not thread-safe and will cause big problems if 
	* called from the spawned thread
	*/
	m_mainEventQueue = GetMainEventQueue();    

	// Create the listening thread for device events    
	MPCreateTask(&threadProc, 0, 512000, NULL, NULL, NULL, 0, NULL);
}

TdxDeviceEvents::~TdxDeviceEvents ()
{
	// Check if the driver is installed
	if (InstallConnexionHandlers == NULL)
		return;

	if (m_clientID)
		UnregisterConnexionClient(m_clientID);
	CleanupConnexionHandlers();    
}


OSStatus TdxDeviceEvents::threadProc (void* param)
{
	if (InstallConnexionHandlers(messageHandlerProc, 0L, 0L) == noErr)
	{
		m_clientID = RegisterConnexionClient('8BIM', 0,kConnexionClientModeTakeOver, kConnexionMaskAxis); 

		RunCurrentEventLoop(kEventDurationForever);
	}

	return noErr;
}

void TdxDeviceEvents::messageHandlerProc(io_connect_t connection, natural_t messageType, 
										 void *messageArgument)
{
	ConnexionDeviceStatePtr msg;

	msg = (ConnexionDeviceStatePtr)messageArgument;

	switch(messageType)
	{
	case kConnexionMsgDeviceState:
		/* Device state messages are broadcast to all clients.  It is up to
		* the client to figure out if the message is meant for them. This
		* is done by comparing the "client" id sent in the message to our
		* assigned id when the connection to the driver was established.
		*/
		if (msg->client == m_clientID)
		{
			/* report = the kind of device data that's being reported */
			switch (msg->command)
			{
			case kConnexionCmdHandleAxis:
				// handle axes data
				break;

			case kConnexionCmdAppSpecific:
				break;

			case kConnexionCmdHandleButtons:
				break;						
			}
		}
		break;

	default:
		// other messageTypes can happen and should be ignored
		break;
	}
}



Martin
Posts: 6
Joined: Tue May 22, 2007 5:36 pm

Post by Martin » Mon May 28, 2007 5:00 am

Hi,
thanks for your tips I highly appreciate that. But I'm still fighting with that problem. First of all my app is a Cocoa app so I'm not sure if I could really use that Carbon code. Using threads sounds like a solid solution but how do I handle it with pthreads or NSThreads for example where I don't have a Carbon event loop.

The "clock_get_uptime" solution sounded easy,although a little bit less solid, but the clock_get_uptime() function seams to be a kernel function which causes a crash when used in a normal user app.

One last question. Why are the messages queued in the driver. Is there a practical need for that behavior? For example Cocoa also doesn't queue mouse or keyboard events. Wouldn't it be easier for the users if the Connexion SDK won't queue messages. So they wouldn't have to deal with the work around via threads. A extra function to turn ON/OFF queuing in the Connexion SDK would be a perfect solution.


Bye,
Martin

flomotan
Moderator
Moderator
Posts: 287
Joined: Mon Jan 08, 2007 3:37 pm

Post by flomotan » Wed May 30, 2007 11:54 am

Hi Martin,

The sample code can be adopted for use in Cocoa. As you mentioned, you can use NSThreads and couple that with NSRunLoop.

With regards to queuing up events, the driver does not technically queue up the events. It uses IOKit and it in turn sends the events to each client. If a client is unable to process the event, it sits in a queue. This is the normal behavior that Apple promotes.

Applications usually try to process most, if not all, device events. For motion events, you can accumulate the event values over a certain time span and average them out to understand how much motion the user was actually trying to do. Then, button events of course are normally not thrown away.

ettore
Moderator
Moderator
Posts: 127
Joined: Wed Mar 14, 2007 5:55 pm
Location: SF Bay Area, CA
Contact:

Post by ettore » Sat Jun 02, 2007 1:24 pm

Martin wrote:First of all my app is a Cocoa app so I'm not sure if I could really use that Carbon code.
Cocoa and Carbon can coexist very nicely. As a rule of thumb, if there are no mixed UI elements there are no big problems. More info about integrating Cocoa and Carbon here:

http://developer.apple.com/documentatio ... index.html
ettore pasquini
software engineer
3Dconnexion, inc.

Martin
Posts: 6
Joined: Tue May 22, 2007 5:36 pm

Post by Martin » Sun Jun 03, 2007 11:05 am

Hi,
thanks for your help. I finally got it working smoothly. But it turned out to be much more complicated then the SDK samples code and manual implied.

Calling the redraw function within the Connexion Message simply doesn't work for complex scenes.
Using threads helped. But calling the redraw function from a second thread was a source for crashes since my scene graph and tools were not thread save.
The solution was a second thread for the Connexion messages and some inter thread communication from the second thread to the main thread of my app for redrawing.

So even although it is working now I still hope that the SDK will handle that "queuing problem" in the future. Then there won't be need for mutil-threading anymore to use the Connexion SDK.

Bye,
Martin

flomotan
Moderator
Moderator
Posts: 287
Joined: Mon Jan 08, 2007 3:37 pm

Post by flomotan » Mon Jun 04, 2007 10:46 am

Thanks Martin for the update. I created enhancement request 4503 to track this. We'll try to get this into a release soon.

Martin
Posts: 6
Joined: Tue May 22, 2007 5:36 pm

Post by Martin » Mon Jun 04, 2007 4:34 pm

Hi,
I'm happy to hear that. I'm sure many developers will appreciate that enhancement. :D

And many thanks again for the excellent support.

Bye,
Martin

Richard Wright
Posts: 3
Joined: Thu Apr 03, 2008 8:41 am
Location: Lake Mary, FL

Queued Messages

Post by Richard Wright » Thu Apr 03, 2008 8:56 am

I'm having the same issue. Any chance we'll see this added to the driver "soon".

Richard

davecotter
Posts: 20
Joined: Tue Mar 11, 2008 10:36 pm

Post by davecotter » Fri Apr 13, 2012 12:53 pm

+1 for this request

davecotter
Posts: 20
Joined: Tue Mar 11, 2008 10:36 pm

Post by davecotter » Fri Apr 13, 2012 1:07 pm

meanwhile, see this thread to learn how to discard the unwanted events

viewtopic.php?t=4973

Post Reply