How to flush events?

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

Moderator: Moderators

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

How to flush events?

Post by davecotter » Thu Apr 05, 2012 4:20 pm

If my operation takes an 8th of a second to complete, then by the end of the first event i've accumulated dozens of events in the que, which now must play out one at a time.

To see this problem, open the 3DxValuesCarbon example, and change this line:

line 149: from this:
----------------
TdxComputeAxes(msg->axis);
----------------

to this:

----------------
#define kMicroSecPerSec 1000000

TdxComputeAxes(msg->axis);
usleep(0.25 * kMicroSecPerSec);
----------------

Now, when you run, twiddle the cap and let go --> it takes forever for the events to catch up to "now"

So what I'd like to do is this:

----------------
#define kMicroSecPerSec 1000000

TdxComputeAxes(msg->axis);
usleep(0.25 * kMicroSecPerSec);
ConnexionControl(kConnexionCtlFlushEvents, 0, &resultI);
----------------

how do i do this??

or: how do i correctly discard all the events except for the one happening RIGHT NOW ?

jwick
Moderator
Moderator
Posts: 2479
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick » Fri Apr 06, 2012 7:22 am

Hi Dave,

It's good to see that you are tackling this. You'll have a lot of happy users.

I'm not familiar with the sample Mac code. I guess I'll have to boot into OS-X and look at it. Are you telling me that our sample code doesn't demonstrate any sort of real-time programming considerations? That might explain a lot... :)

What we usually suggest is to eat all the events from the queue each time you find any events. It is up to you whether you want to A) accumulate, B) accumulate and average, or C) just use the last available event. I tend to favor C since it represents closest to "now" and I really don't care what happened before.

Our sample code should at least mention, if not implement, this.

Jim

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

Post by davecotter » Fri Apr 06, 2012 9:36 am

we suggest is to eat all the events from the queue each time you find any events
Yes, but HOW?

jwick
Moderator
Moderator
Posts: 2479
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick » Fri Apr 06, 2012 10:01 am

By that reaction, I'm assuming there is no way to:

Code: Select all

if (wokenForEventArrival)
{
   while (ConnexionReadEvent(&event) == EVENT_WAS_READ)
   {
      useThisEvent = event;
   }
}

DoViewMath(useThisEvent);
I'll look at the API and discuss with the guy that wrote it, or someone more familiar with it.

AFAIK our SDK is just a thin wrapper over the standard Apple device event system. The data comes through the standard API.
Last edited by jwick on Sat Apr 07, 2012 6:47 am, edited 1 time in total.

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

Post by davecotter » Fri Apr 06, 2012 4:47 pm

There is no "ConnexionReadEvent()" API., and the type of NSEvent is not documented, so i do not see any way to flush them. I need this info to continue, i only have one more working day to show i completed it, else it will be abandoned.

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

Post by davecotter » Mon Apr 09, 2012 10:11 am

i sure hope you can get an answer for me today. as you say, lots of people would be happy to have this built in. but without the ability to say "only give me the most recent event", it's not going to work.

jwick
Moderator
Moderator
Posts: 2479
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick » Mon Apr 09, 2012 12:28 pm

Hi Dave,

We have a couple of suggestions.

1) You can look at the time stamps of the messages as they come in and throw them out if the timestamp is too old. IOW, don't call TdxComputeAxes and all the time consuming operations that entails. You will get a more recent event on the next iteration in your main msg loop.

2) You can put the event gathering into another thread. We ship an example that shows how to do this. That thread would just do the event compression, then signal the main thread that controls the view when the last event is read.

In either case, be careful to not lose the all-zero event that tells you the user has let go of the device. This is often useful information to have to signal a more detailed refresh of the view.

I was also informed that there may be some code around your code base from experiments with this same API from a few years back. That effort was abandoned.

Jim

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

Post by davecotter » Mon Apr 09, 2012 12:36 pm

i was afraid you might say that. bummer.

1) if there is a precise definition of "too old" this might work, but it'd be far too easy to process events you don't need to, or actually miss the last event that you actually want. Due to the realtime nature of whatever calculation we're doing, every event may seem "too old".

2) that's too much work, i have to be done with this.

and yes, the old code is where i started from. i see now that this is the problem they ran into. we have way too many threads now already and have to really justify creating a new one, which can slow down rendering.

i'm amazed that there is no simple, cross platform command for your API that says "flush everything", or a way to say "only hand me the most recent event if there are more than one in the que". this is really a requirement for simple adoption.

jwick
Moderator
Moderator
Posts: 2479
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick » Mon Apr 09, 2012 1:53 pm

davecotter wrote:i was afraid you might say that. bummer.

1) if there is a precise definition of "too old" this might work, but it'd be far too easy to process events you don't need to, or actually miss the last event that you actually want. Due to the realtime nature of whatever calculation we're doing, every event may seem "too old".
The device delivers data at approximately 60Hz. I'd say that anything older than 1/60 of a second ago, that does not have all-zero values, will shortly be followed up by another event. If the values are all-zero, the next event would be the next time the user touches the cap.

davecotter wrote:i'm amazed that there is no simple, cross platform command for your API that says "flush everything", or a way to say "only hand me the most recent event if there are more than one in the que". this is really a requirement for simple adoption.
This isn't our API nor functionality. These are just simple wrappers over the OS-X platform. I do see where this is a place we could try to improve the Apple API, though. I am sure you are correct, that this sort of thing hurts us, preventing others from incorporating support for the products. We did provide a solution for this on Windows. I will look into a better solution for OS-X. The failure of this project should help me to get resources to provide a better solution.

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

Post by davecotter » Mon Apr 09, 2012 2:12 pm

>> simple, cross platform command for your API that says "flush everything"
> This isn't our API nor functionality.

sorry if i wasn't clear. i was asking you to provide such functionality in both SDK's, not that i expected it to exist in the OS.

> We did provide a solution for this on Windows
interestingly i'm not seeing the same performance hit on windows using the messaging API.

do you mean the "SI_AVERAGE_EVENTS" flag? if that does what i think it does, then yes, i'd love to have that on the mac. but i'd be satisfied with just "give me the most recent event, throwing out all previous ones".

as i said in my original post, you could implement this:

> ConnexionControl(kConnexionCtlFlushEvents, 0, &resultI);

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

Post by davecotter » Mon Apr 09, 2012 2:51 pm

apparently, see enhancement request 4503

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

Post by davecotter » Thu Apr 12, 2012 11:17 am

Note that the forums suggest you use "clock_get_uptime" or "mach_absolute_time", but the correct function is "UpTime()".

Code: Select all

#define			kNanoSecondsPerSecond	1000000000
#define			kMilliSecondsPerSecond	1000
#define			kNanoSecondsPerMilli	(kNanoSecondsPerSecond / kMilliSecondsPerSecond)

static bool	IsMostRecentMessage(UInt64& messageT)
{
	UInt64			dur_message_nanoT(UnsignedWideToUInt64(
		AbsoluteDeltaToNanoseconds(UpTime(), UInt64ToUnsignedWide(messageT))));
	UInt64			dur_message_milliT(dur_message_nanoT / kNanoSecondsPerMilli);
	UInt64			dur_tick_milliT(kMilliSecondsPerSecond / 60);
	bool			recentB = dur_message_milliT <= dur_tick_milliT;
	
	return recentB;
}

ngomes
Moderator
Moderator
Posts: 1939
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Post by ngomes » Thu Apr 12, 2012 12:45 pm

davecotter wrote:apparently, see enhancement request 4503
Right. This is indeed the correct issue. Thanks for pointing it out.

I added a reference to this thread in the issue tracker.

Like jwick stated above, the correct way to handle accumulated events is to filter them before calling the application back. The ball's on our side of the court.

ngomes
Moderator
Moderator
Posts: 1939
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Re: How to flush events?

Post by ngomes » Tue May 19, 2015 12:08 pm

3Dconnexion has released a driver update that addresses bug 4503. Version 10.2.2 of 3DxWare 10 was published on May 18, 2015 (yesterday). Your application will need to "weak link" to the driver framework (a "strong" link will lead to problem eventually as it may disconnect the driver from the loaded code in the application).

Post Reply