Inter-module Communications and Callbacks

jarmonik

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 28, 2008
Messages
2,666
Reaction score
795
Points
128
Here are some questions about orbiter development issues.

1)
Who to reset a log file created by an addon ? Of course, an obvious place to reset an existing log is when the orbiter application is started. But the problem is that the orbiter application is automatically respawn when the user will exit the simulation session into a launch pad. An other possibility is to reset the log when the simulation window is opened but that would reset any information printed after loading a module.

There is probably a workaround for this problem by checking the time when the log was last modified and reset the log only if more than just a few seconds has elapsed since the log was previously used.



2)
What about inter-module communications and callbacks ? It appears that there are more and more issues those requires more extensive information change between a modules like a vessel and MFD. For an example a vessel developper may need to assign a callback function that would be called by a specific MFD or an other module. I was thinking something like this...

HMODULE hModule = oapiGetModuleHandle(char *module_name, int n);

"n" is required because there may exist more than one module with the same name. LoadModule() is not a good option because it doesn't check that the module is activated from launchpad and it might spawn a new instance of the module that would be useless.

hModule could be used by GetProcAddress
GetMFDVersion = GetProcAddress(hModule, "GetVersion");
AssignMFDCallback = GetProcAddress(hModule, "AssignCallback");

if (GetMFDVersion()>1.2) {
AssignMFDCallback(MyCallbackFnc);
}

//
// Called by MFD
//
MyCallbackFnc(double mjd)
{
}



But... Since a MFD is object-oriented "a class" would it be enough just to get a pointer into the class ?

if (MFD->GetVersion()>1.2) {
MFD->AssignCallback("MyCallbackFnc");
}

But that would definately require having a header file of the class.
 
Last edited:

computerex

Addon Developer
Addon Developer
Joined
Oct 16, 2007
Messages
1,282
Reaction score
17
Points
0
Location
Florida
Don't forget, you can also use clbkConsumeBufferedKey to pass messages.
 

jarmonik

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 28, 2008
Messages
2,666
Reaction score
795
Points
128
Don't forget, you can also use clbkConsumeBufferedKey to pass messages.

Yeah, probably. But I don't think it will work if you wish to hook a solar sails in an integrator of multibody predictor. Or if the thrust or ISP varies with the fuel quantity.
 

jarmonik

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 28, 2008
Messages
2,666
Reaction score
795
Points
128
Does anyone know how the code/memory protection is working. Can I use a class pointer that is transfered from one module into an other or does it cause CTD.
 

mjessick

Donator
Donator
Joined
Apr 26, 2008
Messages
174
Reaction score
0
Points
0
Location
Houston
IIRC, DLL's exist in the memory space of the calling process.
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
1)
Who to reset a log file created by an addon ? Of course, an obvious place to reset an existing log is when the orbiter application is started. But the problem is that the orbiter application is automatically respawn when the user will exit the simulation session into a launch pad. An other possibility is to reset the log when the simulation window is opened but that would reset any information printed after loading a module.

There is probably a workaround for this problem by checking the time when the log was last modified and reset the log only if more than just a few seconds has elapsed since the log was previously used.

I had this problem, too. Without changing code, all I can come up is the advice to disable dbeachy's (now core-integrated) fast shutdown-method for debugging sessions to get a proper log file.
Alternatively you can copy the log-file to a "persistent" file with each user-invoked shutdown. This way, shutdowns won't cause the "real" log-file to be deleted after re-spawn.
Of course, creating a kind of ring-buffer for logging-events is possible, too. I'm currently playing with the log4net-platform and the appenders, which allows such logging-tricks. This is managed, though, and I don't know if it is available for unmanaged, too.

2)
What about inter-module communications and callbacks ? It appears that there are more and more issues those requires more extensive information change between a modules like a vessel and MFD. For an example a vessel developper may need to assign a callback function that would be called by a specific MFD or an other module.

I also thought about this. Your intuitive solution would be my prefered one, too: something like DanSteph's OS3-SDK with late-binding in a statically-linked lib and a handle-based (maybe using the OBJHANDLE directly) communication for passing data back and forth. While the lib (i.e. the interface) can be used by developers, the actual communicator-dll is a well-versioned centralized module, much like Dan's OrbiterSound is.

Don't forget, you can also use clbkConsumeBufferedKey to pass messages.

Hielor's KeyComm and similar systems work fine, but this is only the infrastructure for the data exchange. The real issue is the content of the data exchange. Pointers will always cause troubles, if there is only the slightest difference in meaning on either side of the communication.

Does anyone know how the code/memory protection is working. Can I use a class pointer that is transfered from one module into an other or does it cause CTD.

Yes. You can, as long as the class memory layout of your class-user is the same as the class-producer. And this is the problem... you'll quickly tap into version-problems and DLL-hell with such a solution. Serialization is the safest here, IMHO.

There is also the singleton design pattern: http://en.wikipedia.org/wiki/Singleton_pattern

This will require a kind of strong-naming in native code to rule out DLL-hell. If you have a closed system (e.g. only you are using the system and there is no SDK or the like), this can work, of course.

BTW: jarmonik, thank you very much for IMFD!

regards,
Face
 

reverend

Addon Developer
Addon Developer
Beta Tester
Joined
Apr 14, 2008
Messages
221
Reaction score
2
Points
18
I have tested OUIPC (Orbiter Universal Interprocess Communications) For this purpose, with success. Only drawback to this is OUIPC being TCP based. Addons can communicate with eachother through the localhost TCP loopback.

The limitation here is also content. Any information passed must be converted or serialized into an ASCII string.

OUIPC has a registry function whereby a connect client can register (or save) arbitrary data, and another client can find this data as long as it knows the name of the registry key the first client registered the information in.

This doesn't sound ideal for your request, and there's no support currently for callbacks. This would not work if you needed 'real-time' functions performed: ie, sending function calls on a per-tick basis would severely slow the system down. I have been thinking about implementing a 'local channel' for doing this. This would provide the same functionality, but the communications would be performed in a local memory pipe instead of through the TCP Loopback.

I'm currently re-writing OUIPC.NET for VC++ 2008 / .NET 3.5. I'm not sure how much is going to change until I've finished the coding.

And one last note, is that I'm re-working OUIPC to include the ability to stream binary data using RTP (Real-Time Protocol), the protocol dominately used for voice and video over IP. This will allow for the transmission of 'datagram' type binary packets for carrying information back and forth.
 

Imagineer

New member
Joined
Feb 11, 2008
Messages
47
Reaction score
0
Points
0
Location
N42 2.9 W 91 35.4
Methods like clbkConsumeBufferedKey and OUIPC create what amounts to the Data Link Layer of the OSI networking model. If anything like an Application Layer is going to work then the content of the Presentation Layer needs to be defined.

Or put another way, if communication among MFD's and Vessels are going to be any more than a one-off solution, a standard set of messages are going to have to be defined.

The ARINC 429 Standard is an example of standardizing the content and format of data transmitted by Air Data Computers, Inertial Reference Systems, etc.

Examples of MFD to Vessel communication would be a target attitude, a target Delta-V, or a target AOA.

Examples of ship to MFD communication would be a table representing ISP as a function of thrust, or how long it will take to achieve a target attitude.

Similar examples can be found in other topics like cargo, fuel and power transfer.

If such standards can be agreed upon, then there is a potential for a far richer communication among the parts of a simulation leading to more realistic behavior.
 

computerex

Addon Developer
Addon Developer
Joined
Oct 16, 2007
Messages
1,282
Reaction score
17
Points
0
Location
Florida
This will require a kind of strong-naming in native code to rule out DLL-hell. If you have a closed system (e.g. only you are using the system and there is no SDK or the like), this can work, of course.

regards,
Face

I have used it before to create a keyboard interface for modules, because as of right now, you only have keyboard access if you are making an MFD, or a vessel, otherwise you have to resort to using the win32 API. It was more for organization, and to prevent other modules from overwriting each other's registered keys. It restricted the keyboard input to one module at a time. You would register a callback with the system, and the user could switch between each registered modules with TAB + LEFT or TAB + RIGHT. It would show you the registered name of the module on top in red for 3 seconds.
 
Top