
Paul Henty
Members-
Posts
1,724 -
Joined
-
Days Won
77
Content Type
Profiles
Forums
Events
Gallery
Downloads
Everything posted by Paul Henty
-
FSUIPCConnect error #12 only with FS2004!
Paul Henty replied to IanAbel's topic in FSUIPC Client DLL for .NET
Just tried here with 2004 - the sim and Visual Studio running 'as admin' - No problems, connected right away. Paul -
FSUIPCConnect error #12 only with FS2004!
Paul Henty replied to IanAbel's topic in FSUIPC Client DLL for .NET
I think on Windows 10 you need to run FS2004 'as administrator' to get it to run. If that's the case then your ACARS program (or Visual Studio if you are developing/debugging) must also run 'as administrator' or they won't be able to communicate. If that's not the problem here, let me know and I'll see if I can find my FS9 discs. Paul -
It depends where you want the message box to appear. If it's in your own application then you just use the normal MessageBox class, or make a form. If you want it to appear inside FlightSim then you need to use the text display facilities provided by FSUIPC. This will just be text display though, there are no buttons and it doesn't look like a messagebox. It either appears as text along the top of the FlightSim window, or if the text is multi-line it appears in a window. This window can be moved by the user or even undocked. I've expanded the example above to display a multiline message in FlightSim when Menu Item 1 is clicked: // Message Writing Offsets: (In their own group and marked as Write-Only) private Offset<string> msgText = new Offset<string>("msg", 0x3380, 128, true); private Offset<string> msgTitle = new Offset<string>("msg", 0x6D60, 32, true); private Offset<short> msgControl = new Offset<short>("msg", 0x32FA, true); private void Form1_Load(object sender, EventArgs e) { try { FSUIPCConnection.Open(); AddMenus(); } catch (FSUIPCException) { // no connection } } private void AddMenus() { UserInputServices ui = FSUIPCConnection.UserInputServices; ui.AddMenuItem("Menu1", "Menu One", false); ui.AddMenuItem("Menu2", "Menu Two", false); ui.MenuSelected += Ui_MenuSelected; this.tmrMenuKeepAlive.Start(); this.tmrCheckForInput.Start(); } private void Ui_MenuSelected(object sender, UserInputMenuEventArgs e) { switch (e.ID) { case "Menu1": // show message in FS msgText.Value = "This is a multiline message.\nThis is line 2\nThis is line 3"; msgTitle.Value = "Example Text Window"; msgControl.Value = 0; FSUIPCConnection.Process("msg"); break; case "Menu2": break; } } private void tmrMenuKeepAlive_Tick(object sender, EventArgs e) { // This timer ticks every 10 seconds FSUIPCConnection.UserInputServices.KeepMenuItemsAlive(); } private void tmrCheckForInput_Tick(object sender, EventArgs e) { // This timer ticks every 250ms FSUIPCConnection.UserInputServices.CheckForInput(); } Please see the examples application - "IS001- Key Presses" under Input Services. Key presses work in a similar way to Menu Items. Paul
-
Hi Achoriham, The following code works fine here on FSX:SE (FSUIPC4): private void Form1_Load(object sender, EventArgs e) { try { FSUIPCConnection.Open(); AddMenus(); } catch (FSUIPCException) { // no connection } } private void AddMenus() { UserInputServices ui = FSUIPCConnection.UserInputServices; ui.AddMenuItem("Menu1", "Menu One", false); ui.AddMenuItem("Menu2", "Menu Two", false); this.tmrMenuKeepAlive.Start(); } private void tmrMenuKeepAlive_Tick(object sender, EventArgs e) { // This timer ticks every 10 seconds. FSUIPCConnection.UserInputServices.KeepMenuItemsAlive(); } Make sure you have the latest updates for FSUIPC and my DLL. If you can't get this working, please post the relevant parts of your code so I can take a look. Paul
-
The control numbers are listed in the PMDG SDK. Look in the following folder under your main FSX install folder: \PMDG\PMDG 737 NGX\SDK e.g. on a typical Steam install it's in: C:\SteamLibrary\steamapps\common\FSX\PMDG\PMDG 737 NGX\SDK The file you need is PMDG_NGX_SDK.h. You can open this with Notepad or any other text editor. This document lists all the controls starting at line 580 (search for "// Control Events") Each event controls a switch. To calculate the control number you add the value of THIRD_PARTY_EVENT_ID_MIN (69632) to the control offset given in the file. for example: EVT_OH_ELEC_BATTERY_SWITCH (THIRD_PARTY_EVENT_ID_MIN + 1) To use the battery switch the CONTROL NUMBER will be 69632 + 1 = 69633 You also need a PARAMETER NUMBER. For PMDG this is usually the mouse button you want to simulate when you press your key. For the left mouse button the parameter will be 536870912 For the right mouse button the parameter will be 2147483648 When you assign your key, you need to select "<Custom Control>" from the dropdown (near the top). Not one of the listed controls. These mostly do not work on PMDG. A popup will appear asking for the control number. Enter the control number you calculated above. Then in the parameter box (below the dropdown), enter one of the mouse button numbers above. Press [confirm] and your key should now work. Paul
-
This is a sub-forum for programmers using FSUIPC with the Microsoft's .NET framework. You'll need to repost your question in Pete's main support forum: https://forum.simflight.com/forum/30-fsuipc-support-pete-dowson-modules/ Paul
-
6520 | 4 | WORD x 2 | MCP_Course[2] From left to right, this means... The data starts at offset 6520 The total length of the data is 4 Bytes. The data is 2 Words (1 Word = 2 bytes = short in c#). The first word (2 bytes) is for one MCP course (probably left), the second word is for the other (probably right). The easiest way to deal with this is to declare 2 ushort offsets for each word. The first one starts at 6520, the second will start 2 bytes later at 6522. e.g. private offset<ushort> MCP_Course_Left = new offset<ushort>("PMDG", 0x6520) private offset<ushort> MCP_Course_Right = new offset<ushort>("PMDG", 0x6522) Paul
-
The static fields in PMDGOffset are not initialised until you either: Create an instance of that class Call a static method/property on that class It looks like you've not used the PMDGOffset class before you've called Update() Here are some possible solutions: 1. Create an instance of the class when your application starts. You don't need to do anything with it if you don't want it: new PMDGOffset(); 2. Add a static method you can call that will force the static fields to be initialised: internal class PMDGOffsets { private static Offset<float> _AIR_SPEED = new Offset<float>("PMDG", 0x6524); internal static void InitOffsets() { // forces static fields to be initialised. } public static float AIR_SPEED { get { return _AIR_SPEED.Value; } set { FSUIPCConnection.SendControlToFS(PMDG_737_NGX_Control.EVT_MCP_IAS_SET, (int)value); } } } Then call PMDGOffsets.InitOffsets() when your program starts. The InitOffsets() method doesn't need to do anything. I recommend that you use offset grouping so that you only process the offsets you need. In the code above, I've changed the airspeed to be in the PMDG group. You would then process just this group in the update class: class PMDG737MCP { public static void Update() { FSUIPCConnection.Process("PMDG"); txt.Text = PMDGOffset.HEADING.ToString(); } } Paul
-
Fractional path of altitude goes negative
Paul Henty replied to Roman Alexeev's topic in FSUIPC Support Pete Dowson Modules
Hi Roman, You can save yourself a lot of trouble by using my .NET DLL for FSUIPC. Here is how you would get the altitude: ' Declare offset at class/form level private Offset<long> altitude = new Offset<long>(0x0570); In your main code... FSUIPCConnection.Process() double altitudeFt = (double)altitude.Value * 3.28084D / (65536D * 65536D); Everything you need to know is on the website: http://fsuipc.paulhenty.com/#home Paul -
No, that's not how the events work. When the event.timer() line is reached the script does not start the timer and wait until it stops. The timer is started and then the script continues to execute. So your current script does this: 1. Creates a function in memory called checkAlive(). 2. Starts a timer that calls that function every 500ms. 3. Creates a function called checkIAS() 4. Reprograms the timer to call checkIAS() every 500ms. 5. Creates a function called checkRALT() 6. Reprograms the timer to call checkRALT() every 500ms Note that all of this happens in a few milliseconds, before the timer has ticked for the first time. Because there is only 1 timer per script. The script does stop at each timer line. It carries on and overwrites the previous timer settings. Yes because the function (e.g. checkAlive()) is called every 500ms and the conditions that play the sound still exist 500ms later. In that case of checkAlive you are looking for IAS >= 25 kts. You play the sound at 25kts, but 500ms later the IAS is still >= 25kts so it plays it again. It will play every 500ms until the IAS comes below 25kts. Stopping the timer was a good way of preventing this when you were only doing one thing with the timer. Now you want to do many things with the timer you can't just stop the timer after the first thing happens. You need to keep track of this yourself. You need to setup some boolean variables (true/false) so that you know what checklist items have been done and which haven't. I show this later... doChecks() was just an example name off the top of my head. The idea is this: 1. Create a single function that you can call with your timer. I came up with the name doChecks(). 2. That function will check every item in your list that hasn't already been done. 3. You could put all the code in the one function but it might get very long. It's better to break them out into a function for each check (as you have now) and have doCheck() call each one in turn. (If it needs calling). 4. You must keep track of what's been done and what hasn't. Here is some code that would be the sort of thing you would do. I don't use LUA so this might not be 100% working, correct LUA, but it shows the basic plan. I've included the three checks you've given but you can hopefully see the logic and how you would expand this basic structure to add other items. local airspeedAliveCalled = false local rotateCalled = false local gearUpCalled = false function checkAlive() ias = ipc.readUD(0X02BC)/128 ipc.lineDisplay("Airspeed="..ias) if ias >= 25 then sound.play("F:\\FSX\\Sound\\wavefiles\\senecaII\\Airspeed alive.wav") ipc.lineDisplay("Airspeed alive") airspeedAliveCalled = true end end function checkIAS() ias = ipc.readUD(0X02BC)/128 ipc.lineDisplay("Airspeed= "..ias) if ias >= 60 then sound.play("F:\\FSX\\Sound\\wavefiles\\senecaII\\70 knots rotate.wav") ipc.lineDisplay("Rotate") rotateCalled = true end end function checkRALT() radio_alt = (3.281/65536)*ipc.readUD (0x31E4) radio_alt = math.floor(radio_alt + 0.5) ipc.lineDisplay("AGL= "..radio_alt) if radio_alt >= 200 then sound.play("F:\\FSX\\Sound\\wavefiles\\senecaII\\Positive climb rate gear up.wav") ipc.lineDisplay("Positive climb rate") gearUpCalled = true end end function doChecks() if not airspeedAliveCalled then checkAlive() elseif not rotateCalled then checkIAS() elseif not gearUpCalled then checkRALT() end end -- Only 1 timer! event.timer(500, "doChecks") Paul
-
From the lua docs on event.timer: So you must either: 1. Break these out into three separate plugins or 2. setup one timer to call a single function e.g. "doChecks()" and either put all the checks in there, or have it call each of your functions in turn. For 2 however, you can't just cancel the event when the action is done. You'll need to setup variables (true/false) to know when each action has completed, has check those each time. Paul
-
Yes there was. One of the internal offsets wasn't getting removed. Thanks for the report. I've just uploaded 3.1.5 to NuGet which should fix this. Paul
-
It's not possible with FSUIPC and so it's not possible with my DLL either. It might be possible using SimConnect but I don't know much about that. It might also depend on the sim you are using. e.g. P3D has many more SimConnect features than FSX. You mentioned VB which is not the best language to use for SimConnect. There are wrappers for .NET but all the documentation is in C# and even that is very poor. If you don't get any other responses here, you could try asking in SimConnect forums or P3D developer forums, or maybe Scenery Developer forums. People there will have more knowledge of what is possible for scenery objects. Paul
-
You're welcome. Looks great!
-
The new version is now live on NuGet. It's 3.1.4-beta so you'll need to make sure you have "Include Prerelease" checked. To access the screen data for a CDU, declare an instance of PMDG_NGX_CDU_Screen: ' Declare a PMDG_NGX_CDU_Screen variable for the CDU ' Pass the base offset address to the contructor Private cdu0 As PMDG_NGX_CDU_Screen = New PMDG_NGX_CDU_Screen(&H5400) This example code shows a number of different ways to access the text and other info: Private Sub CDUExampleCode() ' Call RefreshData to get the latest screen contents ' (Connection must already be open) cdu0.RefreshData() ' Use Powered property to know if CDU is on If (cdu0.Powered) Then ' Use the ToString() method to get a string of the whole screen. ' Use the optional overload to pass a dilimiter for the rows. ' E.g. Here we pass CRLF so we can display the screen in a text box: ' (Use a fixed size font like 'Consolas' or 'Courier New') Me.txtCDU.Text = cdu0.ToString(vbCrLf) Else Me.txtCDU.Text = "No Power" End If ' To get a single row of text use the Rows array: ' e.g. Row 3 (Index 2 - Arrays are 0 based) Dim row3Text As String = cdu0.Rows(2).ToString() ' To get a the data in single cell of the CDU use the Cells array on the row ' e.g. Row 3 (Index 2), First Character (Index 0): Dim R3C1Char As Char = cdu0.Rows(2).Cells(0).Symbol ' Or as a string: Dim R3C1String As String = cdu0.Rows(2).Cells(0).ToString() ' You can also find other data about the cell: Dim R3C1Colour As PMDG_NGX_CDU_COLOR = cdu0.Rows(2).Cells(0).Color Dim R3C1Flags As PMDG_NGX_CDU_FLAG = cdu0.Rows(2).Cells(0).Flags ' To avoid accessing the row everytime, you can hold a reference to the row: Dim row3 As PMDG_NGX_CDU_Row = cdu0.Rows(2) ' The same for cells: Dim R3C1Cell As PMDG_NGX_CDU_Cell = cdu0.Rows(2).Cells(0) ' Example of iterating through all rows: For Each row As PMDG_NGX_CDU_Row In cdu0.Rows Dim rowText As String = row.ToString() ' do more work Next ' Example of iterating through all cells in a row: For Each cell As PMDG_NGX_CDU_Cell In row3.Cells Dim cellChar As Char = cell.Symbol ' do more work Next End Sub Let me know if you need any more help with this, or if there are any problems. Paul
-
Are you using version 3 of the DLL with NuGet? If so, I'm adding support for the PMDG CDUs in the DLL. They are a bit complicated to use because of the way the the data is stored (3 bytes per character). The dll will simplify things and give you a nice .net array for the cells. I'll let you know when it's released (probably late tonight or tomorrow), but you'll need to be getting the dll from NuGet. Paul
-
FSUIPCConnection.Process() Error
Paul Henty replied to geodirk's topic in FSUIPC Client DLL for .NET
Hi Dirk, Thanks for reporting this. It's now fixed. Please use Nuget to update to the latest version of the DLL (3.1.3). Paul -
Hi Padraig, The basic process is that you need to read the pot position (value) and then write to one of the FSUIPC offsets that controls an axis. For example the axis for throttle 1 is offset 0x088C (as described in the FSUIPC documentation). This particular offset expects the values from –4096 (full reverse) to +16384 (full throttle) with 0 being idle. You'll need to translate the values from your pot to cover the range required by FSUIPC. For example assuming there is no reverse and 107 is idle and 198 is full then you'd need: value for fsuipc = (value from pot - 107) / (198-107) * 16384 If you are new to using my DLL in VB.NET there is a beginner's guide video linked on the website (in the help section). This will tell you everything you need to know to get started including where to find the documentation you'll need. Please also look at the Example Code Application as that will show you the basics of how to read and write to FSUIPC offsets. http://fsuipc.paulhenty.com Feel free to post back here if you need any more help with this. Paul
-
FSUIPCConnection.MoveAircraft() Overload Request
Paul Henty replied to geodirk's topic in FSUIPC Client DLL for .NET
You can also set/get the FSUIPCConnection.LocalDateTime property. This is the local time according to the location of the plane in the SIM, not where the user's PC is located. This might be of use to you if you're working with local times. Paul -
FSUIPCConnection.MoveAircraft() Overload Request
Paul Henty replied to geodirk's topic in FSUIPC Client DLL for .NET
Hi Dirk, Are you sure that writing to 0248 changes the season in p3D? It doesn't in FSX and is marked as read-only in the FSUIPC Offsets List. The MoveAircraft() method uses offset 0558, which uses a special feature of SimConnect to move the aircraft. This feature doesn't include the season or date time so there's no way I can include it. I have experimented with this in FSX (I don't have p3d) and found that writing a new datetime and then calling MoveAircraft() only does one scenery refresh. Normally either of these would reload the scenery. But calling them one after the other doesn't do two loads. It seems to abort the first load when starting the second. Here is the code I used: (I used the snapshot overload but it uses the same code. I had to change the season by setting a new date as 0248 is read-only (at least in FSX): FSUIPCConnection.UTCDateTime = dateTimeSave; FSUIPCConnection.MoveAircraft(posSave, false); So I think you can achieve what you want by using this method. Alternatively if you want to use this code (assuming it works in P3D): //set the time/season this.hour.Value = Convert.ToByte(iHour); this.season.Value = 0; sendControl.Value = REFRESH_SCENERY; FSUIPCConnection.Process(); ... you can try not refreshing the scenery here. Just call MoveAircraft() after this and let that reload the scenery. e.g.: //set the time/season this.hour.Value = Convert.ToByte(iHour); this.season.Value = 0; FSUIPCConnection.MoveAircraft(.......); Let me know if these ideas don't work, or don't do what you want, and I'll look into it some more. Paul -
Hi Brad, In C#, the <T> syntax is information for the compiler at compile-time. This means you can't use variables for 'T' because the compiler won't know what the type is. So, the only way to use this syntax is a switch statement with the correct type 'hard-coded': Here's a simple example using a string to hold the type: (Could also be an enum you have created) string variableType = "Int32"; switch (variableType) { case "Int32": int valueInt = myOffset.GetValue<int>(); break; case "Double": double valueDbl = myOffset.GetValue<double>(); break; } Note that the return types are strongly typed. If you need to process these values later, you might consider casting all the values up to 'double's for easier use. (i.e. all the values will be of one type (double)). But this will depend on what your application does with the values. There is another syntax that does take a variable to specify the type: Type variableType = typeof(int); object myValue = myOffset.GetValue(variableType); However, at some point you'll need a switch with this method to generate the real type from the enum or string that you use to hold the offset type. Also note that this method returns an object so you'll also need a switch to cast to the underlying type (unless you're just going to call ToString() on the values). Which method is best comes down to your personal preference and how your application uses the offset values. But I think it's likely that you'll need a switch statement somewhere. It's just down to C# being a type-safe language. Paul
-
Hi George, I don't know of any issues with the LVAR read/write functionality. I've just tried it here with the example app connected to FSX:SE and it works fine. It read the throttle position and I was able to control the range and mode. What version/type of flight sim are you using? When you say it fails to read them, do you mean the values are 0 or is there an error of some kind? Make sure you have the latest FSUIPC installed (see the downloads section on Pete's main forum), and the latest version of my DLL (3.1.1). Paul
-
Is Makerunways modification possible?
Paul Henty replied to roa's topic in FSUIPC Support Pete Dowson Modules
10 seconds is a long time to read that file. If you are using my .NET Client DLL see the latest version (3.1) post in my sub forum. If you use the new AirportsDatabase feature it will save you a lot of coding and loading the database into memory takes about 2 seconds. The database it just a collection in memory, so if you need to get it into a dataset you'll have to transfer the data from the AirportsDatabase with your own code. If you're not using my DLL, here's the testing I did for the different ways of reading the runways.xml File: XMLTextReader: 24490 Airports in 674 ms XDocument: 24490 Airports in 1,254 ms XMLDocument: 24490 Airports in 16,275 ms Manual Read: 24490 Airports in 937 ms If you only need to read the file from top to bottom then XMLTextReader is about twice as fast as XDocument. But even using XDocument only takes just over a second for me. XMLTextReader will require writing a lot more code though. I also added code to create rows in a data table and that didn't add any significant time. XMLTextReader + Create Table Rows: 24490 Airports in 727 ms This test code just finds all the airports from the file, so this is just the time taken to read through the file. There's no other processing. In my DLL I read a lot of the data into an in-memory collection and it takes about 2 seconds with all the string parsing to numbers etc. Paul -
Process() always brings back the current value. If you only want to do something when a value changes then you need to store the old value in a variable. The variable would need to be declared at the form or module level. Then after you Process(), you need to compare the current value with the old to see if it's different. Paul
-
Vb.NET Closest NAVAIDS SQlite
Paul Henty replied to Frédéric-O DUCHEMIN's topic in FSUIPC Client DLL for .NET
These offsets work fine in FSX and FSUIPC4. They always return the next waypoint id and the lon/lat of the next waypoint. The code you posted also works. I used it to follow a flightplan from waypoint to waypoint. It always gave the correct next waypoint and the correct distance and heading. Check your code to make sure you're not constantly reloading the flight plan. If you keep writing to &H130 you'll keep restarting the flightplan from the beginning. Make sure offset &H130 is in it's own group and that it's only processed when you need to load the flight plan. If that's not the problem then it looks like a bug in P3D. Paul