Jump to content
The simFlight Network Forums

PMDG NGX SDK


Recommended Posts

For a device that needs to poll the different items status, it would be necessary to store the data in Lua (ipc.set) and then implement the loop that polls the data.

It just seemed like an easier solution to me to simply propagate the SDK behaviour to Lua, and then store the data there or just process it as it comes.

You're probably right though. I'll think about your suggestions. Keep in mind that I'm 100% new to C++, so I may very well making some stupid decisions without even knowing

Anyway, the CTD is fixed and I'm going to give it a rest for now, go have dinner with mom and dad and forget about it for a couple of hours.

Pete, thank you very much for your help, seriously

Link to comment
Share on other sites

  • Replies 157
  • Created
  • Last Reply

Top Posters In This Topic

For a device that needs to poll the different items status, it would be necessary to store the data in Lua (ipc.set) and then implement the loop that polls the data.

I was thinking more of local storage in your DLL. The NGX data is a fixed structure with a fixed size. Just store it in defined static memory in the DLL, and feed it on request. OR use an event system.

The "get/set" global variable system is only needed for passing data from one Lua plug-in to another, as they run in different threads and each have their own stacks (which is their 'memory' -- DLLs and EXE's are different, they can own memory and keep stuff in it.

Anyway, the CTD is fixed and I'm going to give it a rest for now, go have dinner with mom and dad and forget about it for a couple of hours.

Pete, thank you very much for your help, seriously

Okay. I might write to PMDG in any case, for clarification. If I'm allowed to provide the NGX data via FSUIPC offsets, as I do for native FSX data, then I'll do so and let you know.

Have a great weekend (or what's left of it!).

Pete

Link to comment
Share on other sites

Of course if you can provide native support in FSUIPC that would be golden.

If you have any problems with the EULA eventually and want me to do something different that you may find more useful you can count on me for that.

Have a great weekend (or what's left of it!).

Same Pete

Later

Link to comment
Share on other sites

Looks great, but that's just for SIOC - opencockpits devices, isn't it?

My idea was to integrate the SDK in Lua, to access all the VRInsight, GoFlight, Linda... facilities. Actually it should work for those opencockpits devices too, for all I know they use FSUIPC.

At this point I'm going to finish it no matter what, just for fun. I want to try that HWND_MESSAGE thingy, and if I can implement events in the DLL that trigger Lua scripts (is that what you meant?) then that would be nice too

I have the APU EGT showing in the VRInsight display and that's sort of cool, hehe

Link to comment
Share on other sites

I'm starting to realise what you meant Pete. For some stupid reason I thought I was getting events from NGX items like "FUEL PUMP: ON" when actually every time there's an event related to the NGX the entire data strct gets updated & stored.

I changed the code to use a struct to store the PMDG_NGX_Data struct state instead of individual bool, char, std... and of course since I'm storing the entire struct there's no reason not to implement functions to retrieve that data on demand.

I can do that with registered Lua functions, or I could store the struct in FSUIPC offsets instead of a local PMDG_NGX_Data struct.

I have also googled the HWND_MESSAGE and most results are responses from you to other noobs in this environment like me in several forums haha. I think I get the idea, it's to only get calls to the dispatcher when a message aimed to the invisible window I need to create arrives, instead of any message and then filtering by the NGX data

Link to comment
Share on other sites

I have also googled the HWND_MESSAGE and most results are responses from you to other noobs in this environment like me in several forums haha. I think I get the idea, it's to only get calls to the dispatcher when a message aimed to the invisible window I need to create arrives, instead of any message and then filtering by the NGX data

If you have MS visual Studio installed you should be getting definitive information from MSDN (Microsoft Developer Network), which access is normally installed with MS Visual Studio. Here's what that gets me:

To create a Message Only Window specify HWND_MESSAGE(-3) for the cp.Parent member.

Message-Only Windows

A message-only window enables you to send and receive messages. It is not visible, has no z-order, cannot be enumerated, and does not receive broadcast messages. The window simply dispatches messages.

To create a message-only window, specify the HWND_MESSAGE constant or a handle to an existing message-only window in the hWndParent parameter of the CreateWindowEx function. You can also change an existing window to a message-only window by specifying HWND_MESSAGE in the hWndNewParent parameter of the SetParent function.

To find message-only windows, specify HWND_MESSAGE in the hwndParent parameter of the FindWindowEx function. In addition, FindWindowEx searches message-only windows as well as top-level windows if both the hwndParent and hwndChildAfter parameters are NULL.

Regards

Pete

Link to comment
Share on other sites

Ok, I'll try that.

That and the SimConnect help for SimConnect_Open should be enough to get it working.

On a side note, I've done several "optimizations" or more precisely, corrected some retarded aspects of my implementation, like opening the Lua file everytime the dispatcher gets called.

Also I'm checking if there's a "callback" (I know the name is not very well suited, it should be "event-triggered" or smth like that) Lua function implemented for each item in the NGX to be executed when something in the struct changes.

Using a try - catch I omit the call to the Lua function if it's not implemented. More efficient and allows the developer to implement only a subset of the functions

I'm still a bit worried about what will happen when I have 400+ items implemented. With 4 of them it works fine right now, but if it takes 500ms or more to update the entire struct, I'm not sure how fluid it's going to be once it's done, or even if it might crash or something. I'll do a test with a long loop.

Link to comment
Share on other sites

I'm still a bit worried about what will happen when I have 400+ items implemented. With 4 of them it works fine right now, but if it takes 500ms or more to update the entire struct

Surely you just copy the data in one call to the Runtime C lib function memcpy() or to the Windows function CopyMemory(). What's taking 500 mSecs?

Pete

Link to comment
Share on other sites

Well, right now I'm checking every single member of the struct for modifications. If something is modified and there's a Lua function implemented, I call the Lua function.

I can always use an initialization param to set the plugin to "read-only" so it doesn't call anything and just stores the struct like you said, and then use registered C++ functions to retrieve the data from Lua on-demand.

I know you suggested packing all the modifications and sending them in a single call to Lua, or using a C++ event (not sure how to do this, will need to investigate)

Link to comment
Share on other sites

Well, right now I'm checking every single member of the struct for modifications. If something is modified and there's a Lua function implemented, I call the Lua function.

Surely the other way round, only checking those which are requested to see if they've changed?

Regards

Pete

Link to comment
Share on other sites

Surely the other way round, only checking those which are requested to see if they've changed?

Regards

Pete

That's what I'm doing now.

if an exception is risen upon the call to the Lua function (not implemented, so not requested), that item is not checked for modifications anymore.

The new status is still stored in case it needs to be retrieved from Lua by calling to the corresponding registered C++ function.


if (bLuaEventCallbacks) {
if (bIRS_DisplaySelector && pS->IRS_DisplaySelector != pDBAK->IRS_DisplaySelector)
{
try {
LuaCall<NullT, unsigned char>(LuaGlobal, "IRS_DisplaySelector").call(pDBAK->IRS_DisplaySelector);
} catch (...) {
bIRS_DisplaySelector = false;
}
}
}

memcpy (pDBAK, pS, sizeof(pS));
[/CODE]

I will give the option to ignore the first part altogether (passing the bLuaEventCallbacks param to false) and just store the data, with no Lua "callbacks", and just get the data on demand from a set of registered C++ functions (very much like the original idea)

Link to comment
Share on other sites

By the way, there seems to be a problem with memcpy. The members are not cloned, so the arrays in the struct are not copied (at least that's what seems to me)

A memcpy with the size set to the size of the struct copies the whole struct. I've no idea what you mean by "the arrays in the struct are not cloned". Do you mean the arrays are represented by pointers to somewhere else in memory? If so, whose memory? Bear in mind this SimConnect client data feature can be used by a separate EXE or even from a separate PC, so all the data must be in that one block which is passed via a Pipe or TCP protocol.

Regards

Pete

Link to comment
Share on other sites

No, no. It's not taking more than a couple ms right now, but I only got like 15 items implemented of a total of maybe 450 - 500.

I was worried that once it's finished, sending 500 calls to Lua may last too long, but I don't think that many items will change in the same pass. Did a test with 100 calls and only took 70ms.

Obviously if someone wants to constantly poll the data, it's on them to program that efficiently, having maybe 3 or 4 threads each taking care of 100 -150 items

I just tried calling one of the functions 500 times, simulating a poll pass and the calls from Lua to the registered C functions took 0 (zero) miliseconds.

It's only when I print something with ipc.log or store the data with ipc.set that it takes about 500ms.

Interestingly enough it takes exactly 500ms, 1ms for each ipc call. If I add a second ipc call, then it's 1s.

But the time it takes to execute the static functions calls is negligible

Link to comment
Share on other sites

Hi Dario,

I know nothing of lua (not using it), but let me tell you (just for information) how my lekseecon (a C++ program) reads data from the NGX SDK via SimConnect.

The simconnect interface is abstracted by a SimConnectClient object.That object takes care of opening and closing the connection to FSX, initialisation, and mapping the needed client events to simobjects (however, that part is out of scope her, I only detail reading now).

Five times per second an object abstracting the SDK, calls a read on the SimconnectClient object. That object calls the simconnect callback procedure and it checks whether the NGX datastructure has changed. If so, it copies the whole structure to the same strucure into my lekseecon C++ program.

Also 5 times per second a check operation on objects representing annunciators, values (like heading, altitude, course) in the end-user application is called. Every object has a 'const reference' (set at compile time) to that part in the NGX datastructure, within lekseecon, to which it needs to be checked. If there is a change in value it will send the new value to the end users application via an object abstracting the SIOC interface or an object abstracting the FSUIPC interface.

In my lekseecon program for the Level-D 767 I do exactly the same (with the Level-D SDK). I have about 400 objects that poll the datastructure (within lekseecon!) 5 times per sond, but with the powerful cpu's we have these days that is no problem at all. Lekseecon is always below 0,00 % in the Task Manager.

Link to comment
Share on other sites

Interestingly enough it takes exactly 500ms, 1ms for each ipc call.

Some ipc calls in Lua threads are explicitly subjected, in FSUIPC, to a "sleep" of 0 or 1 millisecond. This is in order to make sure other threads, and FS's own main thread, gets enough time. In fact the vast majority of the time needs to be spent in the FS executing threads.

I'm not sure why you are using ipc.set, which stores values in another (permanent) Lua threads's stack so that they can be retrieved by other threads using ipc.get, but obviously there's a process switch involved each time you do that.

Alternatively I would assume that if you are updating FSUIPC offsets from your DLL you'd be doing that directly via the FSUIPC DLL module interface, not via Lua programmed code.

There is really no need for FSUIPC to provide Lua plug-ins with ultra-fast execution speeds. The application here is merely the updating of displays or whatever with read-ots from the NGX. FSUIPC + Lua can easily meet the needs of displays at any rate needed smooth to the eye. The prime aim of FSUIPC in these matters is the provision of useful plug-in facilities which don't detract from or impinge upon the performance of FS in any noticeable, or even, hopefully, measurable way.

Regards

Pete

Link to comment
Share on other sites

Hi Dario,

I know nothing of lua (not using it), but let me tell you (just for information) how my lekseecon (a C++ program) reads data from the NGX SDK via SimConnect.

The simconnect interface is abstracted by a SimConnectClient object.That object takes care of opening and closing the connection to FSX, initialisation, and mapping the needed client events to simobjects (however, that part is out of scope her, I only detail reading now).

Five times per second an object abstracting the SDK, calls a read on the SimconnectClient object. That object calls the simconnect callback procedure and it checks whether the NGX datastructure has changed. If so, it copies the whole structure to the same strucure into my lekseecon C++ program.

Also 5 times per second a check operation on objects representing annunciators, values (like heading, altitude, course) in the end-user application is called. Every object has a 'const reference' (set at compile time) to that part in the NGX datastructure, within lekseecon, to which it needs to be checked. If there is a change in value it will send the new value to the end users application via an object abstracting the SIOC interface or an object abstracting the FSUIPC interface.

In my lekseecon program for the Level-D 767 I do exactly the same (with the Level-D SDK). I have about 400 objects that poll the datastructure (within lekseecon!) 5 times per sond, but with the powerful cpu's we have these days that is no problem at all. Lekseecon is always below 0,00 % in the Task Manager.

Thanks for the explanation Nico. Obviously the modular design in your original Lekseecon for the LDS767 has paid off in the end.

Wish I had the knowledge to use classes/objects in C++ but I don't.

I don't own the LDS767 but will be very interested in trying your Lekseecon for the NGX if you release it someday. I asked PMDG about the EULA but haven't received an answer yet

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.