Jump to content
The simFlight Network Forums

FS callbacks


Recommended Posts

Hi,

I have developped a module, for FS 2004, that gets data from FS and controls FS through FSUIPC.

I would like now to synchronize some tasks with FS internal cycles such as frame drawing. I assume that it is possible to ask FS to call callback functions synchronized with its internal cycles... but I don't know how.

- is it actually possible to get callback messages from FS, synchronized with its internal cycles?

- what are the known cycles? Frame drawing? Others?

- how to ask FS to call a callback function?

What I know, up to now:

- how to build the ImportTable, so that FS provides a pointer to a structure that contains a number of pointers to functions my module can call, e.g. for PANELS:

DLLEXPORT struct {

int fnID;

PVOID fnptr;

} ImportTable[] = {

{0x0000000F, NULL}, // 0x0000000F for PANELS

{0x00000000, NULL}

};

What I dont'know:

- to what extent the PANELS functions can be safely/efficiently called by a plain module (as opposed to a gauge).

- whether the PANELS functions do contain functions that can solve my problem, and how to use them.

- whether my problem can be solved by importing (undocumented?) functions with another (undocumented?) fnID (I only know 2 values, 0x0000000F for PANELS, 0x00000013 for GAUGES), and how to use them.

Can someone help me?

Best regards,

Daniel Delande

Link to comment
Share on other sites

- is it actually possible to get callback messages from FS, synchronized with its internal cycles?

I'm not certain about what synchronises with what, but the callbacks are by adding procedures in your code to one or more "chains". There are two FS routines --- Chain and Unchain, both of which used to be in CHAIN.DLL but which are now merged into the base EXE.

The best way to find out what these procedures are and how to use them is to do what I did -- disassemble one of the shorter modules. You must already know that, like Gauges, each module has an INIT and a DEINIT call from FS, listed in its linkage. (If you don't know this much, best first to write some gauges and see how they operate, examine the code.) Most all modules register one or more procedures in specific Chains in their "Init" routine, and Unchain them in their "Deinit" routine. You will be able to spot those quite easily after finding the Initi and Deinit routines via the Linkage export.

- to what extent the PANELS functions can be safely/efficiently called by a plain module (as opposed to a gauge).

Those calls work fine IF there's a panel loaded, but are likely to crash FS if used before FS is "ready to fly" (fully loaded a panel), or is in the process of reloading one as part of loading an aircraft. You might find the FSUIPC offset 3364 and 3365 flags useful here, but it is difficult to make things truly crash-proof if you make gauge calls from a DLL.

- whether my problem can be solved by importing (undocumented?) functions with another (undocumented?) fnID (I only know 2 values, 0x0000000F for PANELS, 0x00000013 for GAUGES), and how to use them.

The 0x13 value for gauges isn't used in the ImportTable -- obviously, not all gauges can fit in one import entry in any case. Worse, I think some add-in DLLs used the same ID, presumably because they used the Panels SDK as a starting point.

You can determine the correct IDs for each official FS DLL by looking at the declaration of their ID in their Linkage. Only "Linkage" and "ImportTable" are exported in any case by DLs and Gauges, so you should have no trouble sussing out the structures -- but get the official panels SDK for it to be revealed fairly clearly in any case.

Bear in mind that once you set off down this path you will have a program which, like FSUIPC and my other modules, will need checking and updating, perhaps extensively, for each new version of FS.

Regards,

Pete

Link to comment
Share on other sites

Thanks for answering,

I anticipate hours of time in reverse engineering! For instance, as Chain and Unchain are apparently not exported symbols, I understand I have to step through the Init procedure of a simple module, and find a call to a FS function with an argument that is the address of a module's function (which is in turn called by FS from time to time). Anyway, it is a matter of time.

Since you have already been through this process, and as you say, the portability to new versions of FS is an important issue, are you considering adding a synchronization service, or something similar, to FSUIPC, some day?

Best regards,

Daniel Delande

Link to comment
Share on other sites

I understand I have to step through the Init procedure of a simple module, and find a call to a FS function with an argument that is the address of a module's function (which is in turn called by FS from time to time).

It's a little easier than that, as there will be another, for the same module function, to an adjacent address in FS's EXE Linkage table, in the DLL's "De-init" too. Choose a DLL with small Initi and Deinit routines and it can be pretty quick.

are you considering adding a synchronization service, or something similar, to FSUIPC, some day?

Well, no, because I prefer to encourage the use of external EXE programs. One of the best applications for FS is, for me, completely ruined by being an FS DLL rather than an external program which I can run on a WideFS client PC -- this is FSNavigator. Shame.

Regards,

Pete

Link to comment
Share on other sites

It's a little easier than that, as there will be another, for the same module function, to an adjacent address in FS's EXE Linkage table, in the DLL's "De-init" too.

I'm uncertain about what you mean. I guess the pointers to Chain and Unchain are adjacent in the structure imported by a module and filled by FS (by similarity with Init and Deinit addresses that are adjacent in the exported structure of a module). Also, if the Chain function is called in the Init procedure of a module, the Unchain function should be called in the Deinit procedure.

rather than an external program which I can run on a WideFS client PC

For sure, if one has 2 PCs available for FS, running extra tasks outside the main PC is preferable. However, this works if one has 2 PCs, and if WideFS+FSUIPC support all the interfaces needed by the extra tasks. As an example, I need to get data from the joysticks (I know that FSUIPC can do that to a certain extent) and to write things to the parallel and serial ports. Also, adding tasks in the PC that runs FS certainly impacts the performance of FS, but in my opinion, it is a matter of taste of the user to accept the cost of lower FS performances, and have the benefit of extra functions (in my case: animate a small home-made pedestal). Note that this is a simple remark, I totally accept that you have full authority on what FSUIPC should do and should not do.

Link to comment
Share on other sites

I'm uncertain about what you mean. I guess the pointers to Chain and Unchain are adjacent in the structure imported by a module and filled by FS (by similarity with Init and Deinit addresses that are adjacent in the exported structure of a module).

What is "filled in by FS" is the pointer in your ImportTable to each imported Module's "Linkage" structure. And, yes, the poniters are exactly similar to the Init/Deinit pair in all of the Linkage structures -- but it isn't those which are filled in by FS.

Also, if the Chain function is called in the Init procedure of a module, the Unchain function should be called in the Deinit procedure.

It is almost universally, though of course it doesn't have to be programmed that way. Any, I've just looked them up and the calls for Chain and Unchain are at offsets off the base EXE's Linkage of 0x438 and 0x43C respectively. This is in FS2004 only. That should make it easy for you to spot them.

I am pretty sure the closest you'll get to a frame rate call is chain 0x13, though in FS2004 that seems to go twice as fast when the flight mode display is showing (Shift+Z). Very odd. I had to take special steps to deal with that.

As an example, I need to get data from the joysticks (I know that FSUIPC can do that to a certain extent) and to write things to the parallel and serial ports.

All of which are, if anything, easier to do without impacting FS performance from an external program, whether on the same PC as FS or on a separate PC interfacing through WideFS.

Also, adding tasks in the PC that runs FS certainly impacts the performance of FS

Running inside FS means taking a great deal more care about how you organise the program and perform the tasks you are doing. Instead of having Windows timeslice for you, you are now responsible. It is MUCH more difficult not to impact FS performance from a DLL or Gauge than from an external program, where Windows is helping considerably. Much of the 5+ near full-time years put into FSUIPC and WideServer has been spent on making sure they have minimal impact.

If you run FS on an Intel P4 with "hyperthreading", FS only appears to run in one of the two virtual processors. You can add a few ancillary programs running in the other without any noticeable impact.

Of course, it is still best to offload all your joystick, serial and parallel processing activity to another PC if possible.

Regards,

Pete

Link to comment
Share on other sites

Bingo!

As you said, I could easily spot the offsets 0x438/0x43C in various module Init/DeInit's. I found that 2 arguments are passed to FS: the address of the callback function (of course) and a 4-byte datum that has small values (0x10 is frequent); this must be the chain ID. I tried 0x10 first, then 0x13, as you said. I also found that the callback function has one 4-byte argument and returns nothing.

The tests with 0x13 made my short callback function called at high frequencies (e.g. 280 Hz, for a shown 70 Hz frame rate). I observed as you said that the frequency is lower when the frame rate does not show. I also observed that the argument passed to the callback function takes cyclically a small number of different values (typically 3 to 6).

I now have first to go through some more testing, and finally to modify my application. I think I'll simply check the current time at each call and decide whether the callback function has simply to return or to do something. I'll also cut the 'something's into slices as thin as possible so as to get a frame rate as constant as possible.

Thank you Pete, your help made me save a considerable amount of time!

When I am finished with modifications, I let you know how synchronizing my app with FS impacts the overall performance.

Thanks, thanks again.

Daniel Delande

Link to comment
Share on other sites

I also found that the callback function has one 4-byte argument and returns nothing.

Yes, it is a void function (returns nothing), but I think it has two 32-bit parameters passed to it, the uses of which vary according to the chain number.

When I am finished with modifications, I let you know how synchronizing my app with FS impacts the overall performance.

Okay, I'll be interested. As I said, a lot of the work is designing for minimal impact.

Regards,

Pete

Link to comment
Share on other sites

  • 2 weeks later...

I had no problem to move the code of my app from the thread where it was to the callback function, but this did not change anything, i.e. the frame rate was still far from constant, even when I made "thin slices". So I re-enabled some debugging code so as to get timing data and I found that the duration of a slice was generally ranging from 9 to 17 microseconds (that are peanuts compared to, say, the 33 milliseconds of a 30 Hz frame), but in a particular case went up to 21 milliseconds (this occurs when the slice intends to poll a disconnected analogue joystick)! Of course, such a figure affects significantly the frame rate, and synchronizing the polling with FS cannot help.

When the disconnected analogue joystick problem is removed, there is no visible difference between the 2 strategies, i.e. synchronizing with FS or running in a separate thread.

So, finally, as you said, the separate thread is actually the best solution, since it does not interfere too much with FS internals, and it does not raise questions about the next versions of FS.

However, I do not regret having investigated FS callbacks, because I learnt about FS internals, and it makes me appreciate the work you have to provide to build FSUIPC.

Thanks again,

Daniel Delande

Link to comment
Share on other sites

... I found that the duration of a slice was generally ranging from 9 to 17 microseconds (that are peanuts compared to, say, the 33 milliseconds of a 30 Hz frame), but in a particular case went up to 21 milliseconds (this occurs when the slice intends to poll a disconnected analogue joystick)!

Is this on WinXP ? It may explain why some folks (not all) get odd problems with FSUIPC versions 3.20-3.30 with my button PollInterval changed to a default 25 mSecs. However, these were only with Win2K and Win98/Me, never WinXP.

In the imminent version 3.40 of FSUIPC I am defaulting the PollInterval to 50 on Win2K and Win98/Me, leaving it at 25 on WinXP.

However, I do not regret having investigated FS callbacks, because I learnt about FS internals, and it makes me appreciate the work you have to provide to build FSUIPC.

Okay, glad you benefitted.

Best regards,

Pete

Link to comment
Share on other sites

Is this on WinXP ?

Yes.

I made some tests with different combinations of FS, Windows and DirectX:

- FS2004+XP+DX9

- FS2002+XP+DX9

- FS2002+XP+DX8

- FS2002+98+DX8

- FS98+98+DX8

- FS98+98+DX6

The last case is the only one that has a short polling duration (about 40 microseconds) when the analogue joystick is disconnected. The other cases vary from 5 to 21 milliseconds.

When the joystick is connected, the pollling duration is about 1 millisecond in all cases.

I don't know whether this may help, it does not look consistent with the odd problems you stated.

Best regards,

Daniel Delande

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use. Guidelines Privacy Policy We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.