Jump to content
The simFlight Network Forums

Paul Henty

Members
  • Posts

    1,644
  • Joined

  • Days Won

    74

Everything posted by Paul Henty

  1. Hi Axel, It's not possible to target the dll to .NET Standard because it uses some WinForms libraries which are not included in .NET Standard. That's why I have to target net6.0-windows and not plain net6.0. In any case, FSUIPC uses the Win32 API for communication so the dll cannot run on any other platform except windows. I can look at adding net7.0-windows to the target frameworks if that would be of any use? Paul
  2. I don't have any of the PMDG aircraft so I can't answer any specific questions about them. In the SDK I can see controls for the ch selectors, but they don't appear in the readable data structure, so there will be no offset for them. As far as the SDK is concerned these are write-only. I don't know why. Maybe ask in the PMDG support forums. Paul
  3. Hi Andy, The basic FSUIPC weather facilities can tell you the general conditions at either the player location, at lat/lon location, or a weather station (airport). However, it cannot tell you exact positions of clouds etc. You can know the player is in a "broken" cloud layer with rain for example, but you won't know if the player is inside one of the clouds or not. Examples of using the weather facilities are in the Example Application. It's not available in FSUIPC7 however. (Uses offset 0xC000). FSUIPC4, 5 and 6 have a link to a third-party weather application called ActiveSky Next, If you have that, FSUIPC can extract a weather radar bitmap or array to a file on the disk. Potentially your application could use that to work out positions of actual clouds\rain (as displayed by ActiveSky). They don't seem to have a version for MSFS though. See the document called "ASN WX Radar facilities in FSUIPC.pdf" in the FSUIPC documents folder. Paul
  4. New Offsets: public Offset<byte> ELEC_annunBatteryOFF { get; private set; } public Offset<byte> FIRE_annunCargoDEPRESS { get; private set; } public Offset<byte> MCP_panelPowered { get; private set; } public Offset<byte>[] COMM_RadioPanelPowered { get; private set; } public Offset<byte>[] COMM_AudioControlPanelPowered { get; private set; } public Offset<byte> TCAS_ATC_panelPowered { get; private set; } public Offset<byte>[] FIRE_HandleIllumination { get; private set; } public Offset<byte> WheelChocksSet { get; private set; } New Controls: // Window heat & anti-fog power (747-8) EVT_OH_WINDHT_ANTIFOG_PWR_SIDE_L = (THIRD_PARTY_EVENT_ID_MIN + 242), EVT_OH_WINDHT_ANTIFOG_PWR_SIDE_L_GUARD = (THIRD_PARTY_EVENT_ID_MIN + 10242), EVT_OH_WINDHT_ANTIFOG_PWR_FWD_L = (THIRD_PARTY_EVENT_ID_MIN + 243), EVT_OH_WINDHT_ANTIFOG_PWR_FWD_L_GUARD = (THIRD_PARTY_EVENT_ID_MIN + 10243), EVT_OH_WINDHT_ANTIFOG_PWR_SIDE_R = (THIRD_PARTY_EVENT_ID_MIN + 244), EVT_OH_WINDHT_ANTIFOG_PWR_SIDE_R_GUARD = (THIRD_PARTY_EVENT_ID_MIN + 10244), EVT_OH_WINDHT_ANTIFOG_PWR_FWD_R = (THIRD_PARTY_EVENT_ID_MIN + 245), EVT_OH_WINDHT_ANTIFOG_PWR_FWD_R_GUARD = (THIRD_PARTY_EVENT_ID_MIN + 10245), EVT_OH_ELEC_TOWING_PWR = (THIRD_PARTY_EVENT_ID_MIN + 287), // Overhead Maintenance - EMU MAINT (747-8) EVT_OH_EMU_MAINT_PWR_SWITCH = (THIRD_PARTY_EVENT_ID_MIN + 288), EVT_OH_EMU_MAINT_PWR_GUARD = (THIRD_PARTY_EVENT_ID_MIN + 10288), // EFB EVT_EFB_L_START = (THIRD_PARTY_EVENT_ID_MIN + 1700), EVT_EFB_L_MENU = (EVT_EFB_L_START + 0), EVT_EFB_L_BACK = (EVT_EFB_L_START + 1), EVT_EFB_L_PAGE_UP = (EVT_EFB_L_START + 2), EVT_EFB_L_PAGE_DOWN = (EVT_EFB_L_START + 3), EVT_EFB_L_XFR = (EVT_EFB_L_START + 4), EVT_EFB_L_ENTER = (EVT_EFB_L_START + 5), EVT_EFB_L_ZOOM_IN = (EVT_EFB_L_START + 6), EVT_EFB_L_ZOOM_OUT = (EVT_EFB_L_START + 7), EVT_EFB_L_ARROW_UP = (EVT_EFB_L_START + 8), EVT_EFB_L_ARROW_DOWN = (EVT_EFB_L_START + 9), EVT_EFB_L_ARROW_LEFT = (EVT_EFB_L_START + 10), EVT_EFB_L_ARROW_RIGHT = (EVT_EFB_L_START + 11), EVT_EFB_L_LSK_1L = (EVT_EFB_L_START + 12), EVT_EFB_L_LSK_2L = (EVT_EFB_L_START + 13), EVT_EFB_L_LSK_3L = (EVT_EFB_L_START + 14), EVT_EFB_L_LSK_4L = (EVT_EFB_L_START + 15), EVT_EFB_L_LSK_5L = (EVT_EFB_L_START + 16), EVT_EFB_L_LSK_6L = (EVT_EFB_L_START + 17), EVT_EFB_L_LSK_7L = (EVT_EFB_L_START + 18), EVT_EFB_L_LSK_8L = (EVT_EFB_L_START + 19), EVT_EFB_L_LSK_1R = (EVT_EFB_L_START + 20), EVT_EFB_L_LSK_2R = (EVT_EFB_L_START + 21), EVT_EFB_L_LSK_3R = (EVT_EFB_L_START + 22), EVT_EFB_L_LSK_4R = (EVT_EFB_L_START + 23), EVT_EFB_L_LSK_5R = (EVT_EFB_L_START + 24), EVT_EFB_L_LSK_6R = (EVT_EFB_L_START + 25), EVT_EFB_L_LSK_7R = (EVT_EFB_L_START + 26), EVT_EFB_L_LSK_8R = (EVT_EFB_L_START + 27), EVT_EFB_L_BRIGHTNESS = (EVT_EFB_L_START + 28), EVT_EFB_L_POWER = (EVT_EFB_L_START + 29), EVT_EFB_L_KEY_START = (EVT_EFB_L_START + 30), EVT_EFB_L_KEY_A = (EVT_EFB_L_KEY_START + 0), EVT_EFB_L_KEY_B = (EVT_EFB_L_KEY_START + 1), EVT_EFB_L_KEY_C = (EVT_EFB_L_KEY_START + 2), EVT_EFB_L_KEY_D = (EVT_EFB_L_KEY_START + 3), EVT_EFB_L_KEY_E = (EVT_EFB_L_KEY_START + 4), EVT_EFB_L_KEY_F = (EVT_EFB_L_KEY_START + 5), EVT_EFB_L_KEY_G = (EVT_EFB_L_KEY_START + 6), EVT_EFB_L_KEY_H = (EVT_EFB_L_KEY_START + 7), EVT_EFB_L_KEY_I = (EVT_EFB_L_KEY_START + 8), EVT_EFB_L_KEY_J = (EVT_EFB_L_KEY_START + 9), EVT_EFB_L_KEY_K = (EVT_EFB_L_KEY_START + 10), EVT_EFB_L_KEY_L = (EVT_EFB_L_KEY_START + 11), EVT_EFB_L_KEY_M = (EVT_EFB_L_KEY_START + 12), EVT_EFB_L_KEY_N = (EVT_EFB_L_KEY_START + 13), EVT_EFB_L_KEY_O = (EVT_EFB_L_KEY_START + 14), EVT_EFB_L_KEY_P = (EVT_EFB_L_KEY_START + 15), EVT_EFB_L_KEY_Q = (EVT_EFB_L_KEY_START + 16), EVT_EFB_L_KEY_R = (EVT_EFB_L_KEY_START + 17), EVT_EFB_L_KEY_S = (EVT_EFB_L_KEY_START + 18), EVT_EFB_L_KEY_T = (EVT_EFB_L_KEY_START + 19), EVT_EFB_L_KEY_U = (EVT_EFB_L_KEY_START + 20), EVT_EFB_L_KEY_V = (EVT_EFB_L_KEY_START + 21), EVT_EFB_L_KEY_W = (EVT_EFB_L_KEY_START + 22), EVT_EFB_L_KEY_X = (EVT_EFB_L_KEY_START + 23), EVT_EFB_L_KEY_Y = (EVT_EFB_L_KEY_START + 24), EVT_EFB_L_KEY_Z = (EVT_EFB_L_KEY_START + 25), EVT_EFB_L_KEY_0 = (EVT_EFB_L_KEY_START + 26), EVT_EFB_L_KEY_1 = (EVT_EFB_L_KEY_START + 27), EVT_EFB_L_KEY_2 = (EVT_EFB_L_KEY_START + 28), EVT_EFB_L_KEY_3 = (EVT_EFB_L_KEY_START + 29), EVT_EFB_L_KEY_4 = (EVT_EFB_L_KEY_START + 30), EVT_EFB_L_KEY_5 = (EVT_EFB_L_KEY_START + 31), EVT_EFB_L_KEY_6 = (EVT_EFB_L_KEY_START + 32), EVT_EFB_L_KEY_7 = (EVT_EFB_L_KEY_START + 33), EVT_EFB_L_KEY_8 = (EVT_EFB_L_KEY_START + 34), EVT_EFB_L_KEY_9 = (EVT_EFB_L_KEY_START + 35), EVT_EFB_L_KEY_SPACE = (EVT_EFB_L_KEY_START + 36), EVT_EFB_L_KEY_PLUS = (EVT_EFB_L_KEY_START + 37), EVT_EFB_L_KEY_MINUS = (EVT_EFB_L_KEY_START + 38), EVT_EFB_L_KEY_DOT = (EVT_EFB_L_KEY_START + 39), EVT_EFB_L_KEY_SLASH = (EVT_EFB_L_KEY_START + 40), EVT_EFB_L_KEY_BACKSPACE = (EVT_EFB_L_KEY_START + 41), EVT_EFB_L_KEY_DEL = (EVT_EFB_L_KEY_START + 42), EVT_EFB_L_KEY_EQUAL = (EVT_EFB_L_KEY_START + 43), EVT_EFB_L_KEY_MULTIPLY = (EVT_EFB_L_KEY_START + 44), EVT_EFB_L_KEY_LEFT_PAR = (EVT_EFB_L_KEY_START + 45), EVT_EFB_L_KEY_RIGHT_PAR = (EVT_EFB_L_KEY_START + 46), EVT_EFB_L_KEY_QUEST = (EVT_EFB_L_KEY_START + 47), EVT_EFB_L_KEY_QUOTE = (EVT_EFB_L_KEY_START + 48), EVT_EFB_L_KEY_COMMA = (EVT_EFB_L_KEY_START + 49), EVT_EFB_L_KEY_PAGE_UP = (EVT_EFB_L_KEY_START + 50), EVT_EFB_L_KEY_PAGE_DOWN = (EVT_EFB_L_KEY_START + 51), EVT_EFB_L_KEY_ENTER = (EVT_EFB_L_KEY_START + 52), EVT_EFB_L_KEY_ARROW_UP = (EVT_EFB_L_KEY_START + 53), EVT_EFB_L_KEY_ARROW_DOWN = (EVT_EFB_L_KEY_START + 54), EVT_EFB_L_KEY_END = (EVT_EFB_L_KEY_START + 54), EVT_EFB_L_END = (EVT_EFB_L_KEY_START + 54), EVT_EFB_R_START = (EVT_EFB_L_END + 1), EVT_EFB_R_MENU = (EVT_EFB_R_START + 0), EVT_EFB_R_BACK = (EVT_EFB_R_START + 1), EVT_EFB_R_PAGE_UP = (EVT_EFB_R_START + 2), EVT_EFB_R_PAGE_DOWN = (EVT_EFB_R_START + 3), EVT_EFB_R_XFR = (EVT_EFB_R_START + 4), EVT_EFB_R_ENTER = (EVT_EFB_R_START + 5), EVT_EFB_R_ZOOM_IN = (EVT_EFB_R_START + 6), EVT_EFB_R_ZOOM_OUT = (EVT_EFB_R_START + 7), EVT_EFB_R_ARROW_UP = (EVT_EFB_R_START + 8), EVT_EFB_R_ARROW_DOWN = (EVT_EFB_R_START + 9), EVT_EFB_R_ARROW_LEFT = (EVT_EFB_R_START + 10), EVT_EFB_R_ARROW_RIGHT = (EVT_EFB_R_START + 11), EVT_EFB_R_LSK_1L = (EVT_EFB_R_START + 12), EVT_EFB_R_LSK_2L = (EVT_EFB_R_START + 13), EVT_EFB_R_LSK_3L = (EVT_EFB_R_START + 14), EVT_EFB_R_LSK_4L = (EVT_EFB_R_START + 15), EVT_EFB_R_LSK_5L = (EVT_EFB_R_START + 16), EVT_EFB_R_LSK_6L = (EVT_EFB_R_START + 17), EVT_EFB_R_LSK_7L = (EVT_EFB_R_START + 18), EVT_EFB_R_LSK_8L = (EVT_EFB_R_START + 19), EVT_EFB_R_LSK_1R = (EVT_EFB_R_START + 20), EVT_EFB_R_LSK_2R = (EVT_EFB_R_START + 20), EVT_EFB_R_LSK_3R = (EVT_EFB_R_START + 22), EVT_EFB_R_LSK_4R = (EVT_EFB_R_START + 23), EVT_EFB_R_LSK_5R = (EVT_EFB_R_START + 24), EVT_EFB_R_LSK_6R = (EVT_EFB_R_START + 25), EVT_EFB_R_LSK_7R = (EVT_EFB_R_START + 26), EVT_EFB_R_LSK_8R = (EVT_EFB_R_START + 27), EVT_EFB_R_BRIGHTNESS = (EVT_EFB_R_START + 28), EVT_EFB_R_POWER = (EVT_EFB_R_START + 29), EVT_EFB_R_KEY_START = (EVT_EFB_R_START + 30), EVT_EFB_R_KEY_A = (EVT_EFB_R_KEY_START + 0), EVT_EFB_R_KEY_B = (EVT_EFB_R_KEY_START + 1), EVT_EFB_R_KEY_C = (EVT_EFB_R_KEY_START + 2), EVT_EFB_R_KEY_D = (EVT_EFB_R_KEY_START + 3), EVT_EFB_R_KEY_E = (EVT_EFB_R_KEY_START + 4), EVT_EFB_R_KEY_F = (EVT_EFB_R_KEY_START + 5), EVT_EFB_R_KEY_G = (EVT_EFB_R_KEY_START + 6), EVT_EFB_R_KEY_H = (EVT_EFB_R_KEY_START + 7), EVT_EFB_R_KEY_I = (EVT_EFB_R_KEY_START + 8), EVT_EFB_R_KEY_J = (EVT_EFB_R_KEY_START + 9), EVT_EFB_R_KEY_K = (EVT_EFB_R_KEY_START + 10), EVT_EFB_R_KEY_L = (EVT_EFB_R_KEY_START + 11), EVT_EFB_R_KEY_M = (EVT_EFB_R_KEY_START + 12), EVT_EFB_R_KEY_N = (EVT_EFB_R_KEY_START + 13), EVT_EFB_R_KEY_O = (EVT_EFB_R_KEY_START + 14), EVT_EFB_R_KEY_P = (EVT_EFB_R_KEY_START + 15), EVT_EFB_R_KEY_Q = (EVT_EFB_R_KEY_START + 16), EVT_EFB_R_KEY_R = (EVT_EFB_R_KEY_START + 17), EVT_EFB_R_KEY_S = (EVT_EFB_R_KEY_START + 18), EVT_EFB_R_KEY_T = (EVT_EFB_R_KEY_START + 19), EVT_EFB_R_KEY_U = (EVT_EFB_R_KEY_START + 20), EVT_EFB_R_KEY_V = (EVT_EFB_R_KEY_START + 21), EVT_EFB_R_KEY_W = (EVT_EFB_R_KEY_START + 22), EVT_EFB_R_KEY_X = (EVT_EFB_R_KEY_START + 23), EVT_EFB_R_KEY_Y = (EVT_EFB_R_KEY_START + 24), EVT_EFB_R_KEY_Z = (EVT_EFB_R_KEY_START + 25), EVT_EFB_R_KEY_0 = (EVT_EFB_R_KEY_START + 26), EVT_EFB_R_KEY_1 = (EVT_EFB_R_KEY_START + 27), EVT_EFB_R_KEY_2 = (EVT_EFB_R_KEY_START + 28), EVT_EFB_R_KEY_3 = (EVT_EFB_R_KEY_START + 29), EVT_EFB_R_KEY_4 = (EVT_EFB_R_KEY_START + 30), EVT_EFB_R_KEY_5 = (EVT_EFB_R_KEY_START + 31), EVT_EFB_R_KEY_6 = (EVT_EFB_R_KEY_START + 32), EVT_EFB_R_KEY_7 = (EVT_EFB_R_KEY_START + 33), EVT_EFB_R_KEY_8 = (EVT_EFB_R_KEY_START + 34), EVT_EFB_R_KEY_9 = (EVT_EFB_R_KEY_START + 35), EVT_EFB_R_KEY_SPACE = (EVT_EFB_R_KEY_START + 36), EVT_EFB_R_KEY_PLUS = (EVT_EFB_R_KEY_START + 37), EVT_EFB_R_KEY_MINUS = (EVT_EFB_R_KEY_START + 38), EVT_EFB_R_KEY_DOT = (EVT_EFB_R_KEY_START + 39), EVT_EFB_R_KEY_SLASH = (EVT_EFB_R_KEY_START + 40), EVT_EFB_R_KEY_BACKSPACE = (EVT_EFB_R_KEY_START + 41), EVT_EFB_R_KEY_DEL = (EVT_EFB_R_KEY_START + 42), EVT_EFB_R_KEY_EQUAL = (EVT_EFB_R_KEY_START + 43), EVT_EFB_R_KEY_MULTIPLY = (EVT_EFB_R_KEY_START + 44), EVT_EFB_R_KEY_LEFT_PAR = (EVT_EFB_R_KEY_START + 45), EVT_EFB_R_KEY_RIGHT_PAR = (EVT_EFB_R_KEY_START + 46), EVT_EFB_R_KEY_QUEST = (EVT_EFB_R_KEY_START + 47), EVT_EFB_R_KEY_QUOTE = (EVT_EFB_R_KEY_START + 48), EVT_EFB_R_KEY_COMMA = (EVT_EFB_R_KEY_START + 49), EVT_EFB_R_KEY_PAGE_UP = (EVT_EFB_R_KEY_START + 50), EVT_EFB_R_KEY_PAGE_DOWN = (EVT_EFB_R_KEY_START + 51), EVT_EFB_R_KEY_ENTER = (EVT_EFB_R_KEY_START + 52), EVT_EFB_R_KEY_ARROW_UP = (EVT_EFB_R_KEY_START + 53), EVT_EFB_R_KEY_ARROW_DOWN = (EVT_EFB_R_KEY_START + 54), EVT_EFB_R_KEY_END = (EVT_EFB_R_KEY_START + 54), EVT_EFB_R_END = (EVT_EFB_R_KEY_START + 54), // Parameter: 1000000 x (action code) + 1000 x (X Coordinate) + (Y Coordinate) // action codes: 0 = mouse move, 1 = mouse click, 2= mouse release, 3 = mouse wheel up, 4 = mouse wheel down // X / Y Coordinates: 0..1000 of EFB_SCREEN_WIDTH / EFB_SCREEN_HEIGHT (not required for action codes 3 & 4) EVT_EFB_L_SCREEN_ACTION = (THIRD_PARTY_EVENT_ID_MIN + 1900), EVT_EFB_R_SCREEN_ACTION = (THIRD_PARTY_EVENT_ID_MIN + 1901), // Internal use EVT_SC_SENSORS_START = (THIRD_PARTY_EVENT_ID_MIN + 14650), EVT_SC_SENSOR_THROTTLE_1 = (EVT_SC_SENSORS_START + 0), EVT_SC_SENSOR_THROTTLE_2 = (EVT_SC_SENSORS_START + 1), EVT_SC_SENSOR_THROTTLE_3 = (EVT_SC_SENSORS_START + 2), EVT_SC_SENSOR_THROTTLE_4 = (EVT_SC_SENSORS_START + 3), EVT_SC_SENSOR_REVERSER_1 = (EVT_SC_SENSORS_START + 4), EVT_SC_SENSOR_REVERSER_2 = (EVT_SC_SENSORS_START + 5), EVT_SC_SENSOR_REVERSER_3 = (EVT_SC_SENSORS_START + 6), EVT_SC_SENSOR_REVERSER_4 = (EVT_SC_SENSORS_START + 7), EVT_SC_SENSOR_SPEEDBRAKE = (EVT_SC_SENSORS_START + 8), EVT_SC_SENSOR_FLAPS = (EVT_SC_SENSORS_START + 9), EVT_SC_SENSORS_LAST = EVT_SC_SENSOR_FLAPS, EVT_SC_AXIS_START = (THIRD_PARTY_EVENT_ID_MIN + 14680), EVT_SC_AXIS_OUTBD_DISPL_CAPT = (EVT_SC_AXIS_START + 0), EVT_SC_AXIS_INBD_DISPL_CAPT = (EVT_SC_AXIS_START + 1), EVT_SC_AXIS_EICAS_UPR = (EVT_SC_AXIS_START + 2), EVT_SC_AXIS_EICAS_LWR = (EVT_SC_AXIS_START + 3), EVT_SC_AXIS_INBD_DISPL_FO = (EVT_SC_AXIS_START + 4), EVT_SC_AXIS_OUTBD_DISPL_FO = (EVT_SC_AXIS_START + 5), EVT_SC_AXIS_INBD_TERR_CAPT = (EVT_SC_AXIS_START + 6), EVT_SC_AXIS_INBD_TERR_FO = (EVT_SC_AXIS_START + 7), EVT_SC_AXIS_EICAS_LWR_TERR = (EVT_SC_AXIS_START + 8), EVT_SC_AXIS_LAST = EVT_SC_AXIS_EICAS_LWR_TERR, Paul
  5. Hi Andy, Version 3.3.2 is now on NuGet - Includes all the new 747 controls and offsets added. Paul
  6. I can, but it's not in the version of the .h file I have here. I'm using PMDG_747QOTSII_SDK.h from 2017. Could you PM me the file you're working from? That way I can just add all new events in one go. I've also found a newer offset list for the 747 so I'll check those too and add any new offsets. Paul
  7. It takes about 23 seconds on my machine to rebuild the MSFS database (from the files Jason sent). Can you add a progress to see if you get anything back, and also check your "%localappdata%\FSUIPCClientDLL" folder to see if there are any files there. They will be under a folder with a long hex string. Paul
  8. Okay, just tried here in a new 4.8 winforms app and works okay: private async void button1_Click(object sender, EventArgs e) { FSUIPCConnection.Open(); AirportsDatabase db = FSUIPCConnection.AirportsDatabase; await db.RebuildDatabaseAsync(); MessageBox.Show("Done"); } Are you using await? If not, it will just start the rebuild on a background thread and your code will just continue. Paul
  9. Hi Andy, The example code solutions had the nuget paths messed up because I was using them in a larger project. I've sorted them out and re-uploaded them. Please download the latest from the website - 1.4.1. If you can get that to work then we'll look at the problem you're having in your app. A couple of questions What version of .NET is your application targeting? Are you getting any callbacks to the progress class? Paul
  10. Hi Andy, Thanks for the report. I've added the second APUFieldReset offset. Version 3.3.1 is now on NuGet. The events seem to have both switches there already: EVT_OH_ELEC_APU_FIELD1_SWITCH = (THIRD_PARTY_EVENT_ID_MIN + 278), EVT_OH_ELEC_APU_FIELD1_GUARD = (THIRD_PARTY_EVENT_ID_MIN + 10278), EVT_OH_ELEC_APU_FIELD2_SWITCH = (THIRD_PARTY_EVENT_ID_MIN + 279), EVT_OH_ELEC_APU_FIELD2_GUARD = (THIRD_PARTY_EVENT_ID_MIN + 10279), Paul
  11. Jason, Andy. The new version 3.3.0 is now on NuGet with the changes outlined above. You will need to rewrite some of your Airports Database code to use the new methods. The strategy is to limit the data you load into RAM and the number of airports you process when calling SetReferenceLocation(). Details are in this post: More detailed examples are available in the Example Code application. Link in the post above. Sorry you have to change your code, but it just could work the way it was. Let me know if you need any help with it. Paul
  12. Version 3.3.0 is now on NuGet with the change to the TextMenu I mentioned (The menu is now kept when a single line message arrives). Note there are also extensive breaking changes to the Airports Database if you're using that feature. Also if you're using .NET 4 Framework, the DLL no longer supports 4.0 as it's now out of support. It now targets 4.6.2 instead. Paul
  13. Introduction Version 3.3.0 of the FSUIPCClientDLL has significant changes to the Airports Database module. This post explains why this was needed, the main differences and quick exmples of how to use this feature from V3.3.0 onwards. More detailed examples can be found in the Example Code Applications (C# / VB.NET) available on the website: http://fsuipc.paulhenty.com/#downloads Full details of all changes in V3.3.0 can be found here: http://fsuipc.paulhenty.com/#revisionHistory Why change it? The feature was first introduced around the time of FSX and early P3D versions. These products shared the same airports database and was small enough that everything could be comfortably stored in RAM (roughly 300mb). This included all airports, gates, helipads, runways and taxiways. The information was read directly from the MakeRunways text files (.csv/.xml) when the application started and stored in RAM for the lifetime of the application. With modern flight simulators and scenery (especially MSFS) this method of dealing with the Airports Database has become unworkable. The default scenery from a standard install of MSFS takes up over 3GB of RAM. That's a lot for an application to take up, especially one running on the Flight Sim machine. Processing this amount of information makes the application run slowly (e.g. setting the Reference Position on all airports). Also, the time taken to read and parse the MakeRunways text files is now quite slow. It's not good to have to wait for this process to complete every time your application starts. The Airports Database has been partially redesigned and rewritten to work with the large amount of data from the latest Flight Simulators. Instead of holding the data in memory, it is instead held in binary files on the hard disk in a way that it can be accessed very quickly. The importing of the MakeRunways files only needs to be done when they have changed (or if it's the first time you or your users have used your application). After that the data is read from the binary files, so your application's start up can be much faster. There is also more control over what gets loaded into RAM and what data gets processed. Whereas before, all airports, runways, gates etc were loaded into RAM and processed, the new Airports Database lets you control this so you only load and process the data your application needs. For example, if you need to know which taxiway the player is on, you can now do so by only loading taxiways for that airport and only testing that airport. The new ways of using the Airports Database require a little more thought and care than the old way, but the old way is just too inefficient to work on large datasets. Things that haven't changed: The database objects (FsAirport, FsRunway, FsGate etc) have not changed. Your current code that uses these objects will not need to be changed. The differences: Data Stored in Binary Files The data is not read from the MakeRunways output files every time your application starts. The MakeRunways data is parsed and then stored in binary files in a way that the data can be quickly accessed. The data is read from these binary files. The MakeRunways data only needs to be imported (parsed) again if they change. Control of loading of Components (Runways, Gates, Taxiways etc) When you load the database initially, the only data that's loaded is the list of all airports. No component data (Runways, Gates, Taxiways etc) is loaded. If you want that information you can request that it's loaded. This can be done for a single airport or a collection of airports. This keeps the memory footprint down. Collections of Airports When you load the database you get a collection containing all airports. You're free to use that collection if your application requires it (e.g. flight planning). However, if you're application only needs to work with a subset of airports (e.g. airports in a 100nm range of the player, or a specific list of airports used by a Virtual Airline) you can create a new collection of airports that is more relevant to your application. You can do this manually or by filtering the main airports collection. This means you are only processing airports and loading data that is relevant to your application. This improves memory usage and processing times. Managing the Database as your Application Runs Throughout the lifetime of your application, you may use combinations of the above techniques to keep the memory use and processing times to a minimum. Here's an example: You might use the full airports list to get the airports in 60nm of the player. Then you might load runways for those airports to find those with ILS facilities. Then after the user picks an airport you might load Gate information for that single airport so the player can choose a gate. Your application might then keep checking that FsGate object to known when the player has arrived there. Integration with AITrafficServices Integration with AITrafficServices is no longer automatic. If you want the integrated features you need to pass a collection of airports (or a single airport) and the components you wish to process to AITrafficServices.RefreshAITrafficInformation(). Note that this method automatically loads component information on demand as it's required. There's no way for you to know what needs to be loaded in advance. (Re)Building the Database: The database needs to be built before you can use the database and also whenever the MakeRunways output files change. This is typically when the user has updated their scenery. The rebuild method runs in the background so it doesn't block the User Interface. The easiest way to call this method is with the Async-Await pattern. This will wait until the rebuild in complete and then continue executing your code. E.g. C# private async void btnRebuild_Click(object sender, EventArgs e) { AirportsDatabase db = FSUIPCConnection.AirportsDatabase; await db.RebuildDatabaseAsync(); MessageBox.Show("Rebuild Complete"); } VB.NET Private Async Sub btnRebuild_Click(ByVal sender As Object, ByVal e As EventArgs) Dim db = FSUIPCConnection.AirportsDatabase Await db.RebuildDatabaseAsync() MessageBox.Show("Rebuild Complete") End Sub You can also pass a Progress object to RebuildDatabaseAsync to receive progress reports during the rebuild. See the Example Code application for this. Usage: 1. Get a reference to the Airports Database: C# AirportsDatabase db = FSUIPCConnection.AirportsDatabase; VB.NET Dim db = FSUIPCConnection.AirportsDatabase 2. Set the Make Runways Folder (Optional) You can optionally set a path to the MakeRunways output files. If you are using the database with an open FSUIPC Connection this path will be set automatically to the flight simulator main folder. This is where the MakeRunways files are by default. If you're using the database without an FSUIPC Connection, or want to point to a different folder than the default you can set the MakeRunwaysFolder property. C# db.MakeRunwaysFolder = @"C:\Path\To\MakeRunways\Output\Files"; VB.NET db.MakeRunwaysFolder = "C:\Path\To\MakeRunways\Output\Files" 3. Load the Database: Call Load() to load in the main collection of airports. C# if (db.DatabaseFilesExist) { db.Load(); } VB.NET If db.DatabaseFilesExist Then db.Load() End If 4. Get a specific airport using the ICAO indexer: C# FsAirport heathrow = db.Airports["EGLL"]; VB.NET Dim heathrow = db.Airports("EGLL") 5a. Get a cut-down collection of airports by filtering the main collection C# FsAirportCollection localAirports = db.Airports.InRangeOfKilometres(80); FsAirportCollection londonAirports = db.Airports.FindAll(ap => ap.City == "London" && ap.Country == "United Kingdom"); VB.NET Dim localAirports = db.Airports.InRangeOfKilometres(80) Dim londonAirports = db.Airports.FindAll(Function(ap) Equals(ap.City, "London") AndAlso Equals(ap.Country, "United Kingdom")) 5b. Or make your own custom collection of airports: C# string[] virtualAirlineAirportCodes = new string[] { "EGLL", "LFPG", "EDDF", "EIDW", "EGPF", "EGJJ" }; FsAirportCollection virtualAirlineAiports = new FsAirportCollection(); foreach(string icao in virtualAirlineAirportCodes) { virtualAirlineAiports.Add(db.Airports[icao]); } VB.NET Dim virtualAirlineAirportCodes = New String() {"EGLL", "LFPG", "EDDF", "EIDW", "EGPF", "EGJJ"} Dim virtualAirlineAiports As FsAirportCollection = New FsAirportCollection() For Each icao In virtualAirlineAirportCodes virtualAirlineAiports.Add(db.Airports(icao)) Next 7. Load components for an individual airport or a collection C# heathrow.LoadComponents(AirportComponents.Runways | AirportComponents.Gates); virtualAirlineAiports.LoadComponents(AirportComponents.All); VB.NET heathrow.LoadComponents(AirportComponents.Runways Or AirportComponents.Gates) virtualAirlineAiports.LoadComponents(AirportComponents.All) 8. Use the component information after loading: C# foreach(FsRunway rw in heathrow.Runways) { this.cbxRunways.Items.Add(rw.ID + " (" + rw.LengthFeet.ToString("N0") + " ft)"); } VB.NET For Each rw In heathrow.Runways cbxRunways.Items.Add(rw.ID & " (" & rw.LengthFeet.ToString("N0") & " ft)") Next 9. Set the Reference Location for an individual airport or a collection: This will calculate the distance, bearing etc to the airport or each airport in the collection. You can choose which loaded components are processed. Setting reference location for all airports in the collection (No components processed - distance, bearings and boundary checks for airports only). C# localAirports.SetReferenceLocation(AirportComponents.None); VB.NET localAirports.SetReferenceLocation(AirportComponents.None) Setting reference location for one airport. Also calculate distance, bearings, boundary checks for runways and gates: C# heathrow.SetReferenceLocation(AirportComponents.Runways | AirportComponents.Gates); VB.NET heathrow.SetReferenceLocation(AirportComponents.Runways Or AirportComponents.Gates) 10. Fill in the AITraffic Properties by passing a collection to the AITrafficServices. This example will populate the airport, runway and gate information for AITraffic for all virtual airline airports. C# AITrafficServices traffic = FSUIPCConnection.AITrafficServices; traffic.RefreshAITrafficInformation(virtualAirlineAiports, AirportComponents.Runways | AirportComponents.Gates); VB.NET Dim traffic = FSUIPCConnection.AITrafficServices traffic.RefreshAITrafficInformation(virtualAirlineAiports, AirportComponents.Runways Or AirportComponents.Gates) Paul
  14. I've made some changes to the TextMenu helper. The TextMenu class is just a helper for the 0xB000 offset in FSUIPC. I can only supply the information I get from that offset. The way this offset works is that it holds the LAST message that was sent to the screen (regardless of if it was single line or a menu). If a menu appears and then a single line message B000 will only contain the single line message. However, I have changed my DLL so that TextMenu will now keep the last Menu data until a new Menu message arrives. Same with single line messages. Note however that ToString() will still only return the last message, and IsMenu will still only refer to the last message. The menu data will only be cleared when a Menu message arrives with no text. On FSX this happens if the user clears the menu themselves, but not if the menu is closed by the application (eg. GSX). It might be different in P3D. If not, then there's no way you can tell when menus get closed by GSX. This is a limitation of either FSUIPC or SimConnect. Note also that in FSX the single line messages never receive a 'cleared' message. So the last single line message will stay until a new single line message arrives. The changes will be in the next version (3.3.0) which will be available in week or two. I'll let you know when it's out. I can't see that with FSX/FSUIPC4. If it's happening with P3D it might be a problem with FSUIPC6. You can monitor offset 0xB004 (4 byte int) to test this yourself. Single line messages are 0 & 1, Menu = 2. I can only pass on what FSUIPC gives me. Again, not with FSUIPC4. The changed flag is true when the value in offset 0xB000 (4-byte int) changes. This indicates if a new message has arrived. It shouldn't be true all the time. If a menu get's cleared and a clear message is received then Changed should be true the next time you call RefreshData(). After that is should be false (until a new message arrives). You can monitor 0XB000 to see what FSUIPC is sending. Paul
  15. Happy New Year to you too. This current behaviour is by design as it follows FSUIPC behaviour. The same offset is used to read single line messages and multiline menus, so menus get overwritten by messages in FSUIPC. This allow users to read the last message that was sent and also know when messages are removed from the screen. There might be something I can do/suggest, but are two things I'm not clear on... 1. When a menu is on the screen and a new single-line message arrives, does the menu disappear or is it still on the screen and functional? 2. Do you want the menu items available even when the menu has gone from the screen (But a new menu has not arrived)? Paul
  16. I searched for "rudder trim" in the offsets list and found two likely offsets: 0x0C04 which is a 2-byte integer - gives the rudder trim position between –16383 and +16383 0x2EC0 which is a double floating point (8 bytes). Stores the rudder trim defections in Radians. Paul
  17. I've had a look at the Load() and SetReferenceLocation() functions. There is no more optimisation that can be done. The problem is just the amount of data it has to load and work through. The solution to this is to rewrite the airports database to make is possible to only load the airports/data you need or is relevant at the time. This will do two things: 1. Limit the memory taken by your application 2. Make the SetReferenceLocation() much faster because it's not calculating distances to every runway on the planet. This will mean rewriting your code airports database a little, but the current system is not viable. I'm going to use a database to store the airport information on the disk in a way that it can be retrieved very quickly. (Parsing the CSV files is slow so this will only need to be done when the MakeRunways files change). A side benefit of this is that your application won't need to go through the lengthy Load() procedure every time it starts up. This will probably take a few weeks as I also need to update the example code projects. In the mean time you might be able to improve the situation in your application by not loading data you don't need. For example if you don't use the Taxiway information then turn it off with AirportsDatabase.LoadTaxiways = false. Same with any other data you don't use. Paul
  18. So after some investigation, the problem is the mainly the MSFS taxiways. They seem to be made up of many more segments than FSX. When I wrote the airports database in the FSX days it was no problem loading everything into memory. The database with all taxiways only took about 600mb and the SetReferencePosition() only takes around 70ms on my machine. With the MSFS data, the entire in-memory database (with Taxiways) is now 2.6Gb. This is quite a large program to be running on the MSFS computer. The main problem however is that the SetReferencePosition() now takes 350ms. If you're trying to run that every 250ms you can see the problem - it's longer than the timer tick, I assume you're loading the Taxiways because I remember you having a feature to give call outs of which taxiway the pilot was on. Perhaps you can confirm. Loading the entire database into memory is just not feasible now with MSFS. It's not just a question of making optimisations, it really needs a rethink of how the database is handled and when things get loaded. I'll see if I can come up with a plan over the next few days. I'll keep you updated. Paul
  19. Got it, thanks. Looking at the files, the biggest is 500mb (runways.txt) but I don't use that one. Adding up the files that I do use, your MSFS data is 2.5 times larger than my FSX data (191mb vs 75mb). I'll have a look this later today and see if anything can be done. Paul
  20. Hi Andy, So if I understand correctly it's not the actual loading of the database (AirportsDatabase.Load()) that causes the issues, it's repeatedly calling the SetReferenceLocation() with a large airports database. SetReferenceLocation() updates the AirportsDatabase using the current location. It will calculate the distance to the nearby airports, what runway you are on (if you're in the boundary of the airport) etc. If that's what you need every 250ms then there's no other way to do that. If you only need to know the players Lon/Lat you can just use the offsets that provide that information. If you can confirm that SetReferenceLocation() is the problem I will see if I can optimise it. It would be best if I have the large MSFS generated database to work with. If you have an easy way to get it to me (e.g. Google drive/Dropbox link) please send it to me in a private message on here. Otherwise I can maybe fake a larger database with the FSX one. Also, are you using the AI Traffic services as well? Paul
  21. Hi Jason, I can have a look and see if anything can be done. I don't have MSFS however. Would you be able to zip and attach the MakeRunways files make with MSFS so I can test with those? Runways.xml F5.csv R5.csv G5.csv Helipads.csv T5.csv Paul
  22. For regular updates you just need to keep calling the code I've put in btnLoad_Click(). That can all go in your timer tick() function (or a separate method that you call from tick()). All other code is configuration and can just be done once. The time taken to build a new list for the datagrid is negligible (<1 ms). If you keep the list in memory and try to update it with the new information it's going to be far more trouble than it's worth. Paul
  23. Hi Tony, The coms frequencies for airports are available in the FsAirport.COMFrequencies property. This is a collection of FsAirportComFrequency objects which contain the name, type and frequency of all the coms available at the airport. Getting them into the grid is not as simple as the other properties (e.g. ICAO) as the grid doesn't know what to do with collections, so you'll need to use the grid in a more laborious way: The full code is pasted below. It will work on a form with a button and a datagrid. The basic idea is this: (Same numbers are used in code comments) Create a new class that will hold the data displayed in each row of the grid. Setup the columns in the gridview control Set current location and get airports in range Create a new list to store all the new grid items: Create a datagrid item for each airport Go through com frequencies for the airport and add an extra grid row for each public partial class frmAirportsWithComs : Form { // 1. Create a new class that will hold the data displayed in each row of the grid. private class DataGridItem { public string ICAO { get; set; } public string Name { get; set; } public string City { get; set; } public string Distance { get; set; } public string Bearing { get; set; } public string Coms { get; set; } } public frmAirportsWithComs() { InitializeComponent(); FSUIPCConnection.Open(); configureGrid(); FSUIPCConnection.AirportsDatabase.Load(); } // 2. Setup the columns in the gridview control private void configureGrid() { this.dataGridView1.AutoGenerateColumns = false; DataGridViewColumnCollection cols = this.dataGridView1.Columns; cols.Add(createColumn("ICAO", 60, null)); cols.Add(createColumn("Name", 120, null)); cols.Add(createColumn("City", 120, null)); cols.Add(createColumn("Distance", 60, null)); cols.Add(createColumn("Bearing", 60, null)); cols.Add(createColumn("Coms", 120, null)); } private DataGridViewColumn createColumn(string propertyName, int width, string format) { DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn(); col.DataPropertyName = propertyName; col.HeaderText = propertyName; col.Name = propertyName; col.ReadOnly = true; col.Resizable = DataGridViewTriState.True; col.Width = width; if (!string.IsNullOrWhiteSpace(format)) { col.DefaultCellStyle.Format = format; col.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight; } return col; } private void btnLoad_Click(object sender, EventArgs e) { // 3. Set current location and get airports in range FSUIPCConnection.AirportsDatabase.SetReferenceLocation(); FsAirportCollection airports = FSUIPCConnection.AirportsDatabase.Airports; airports = airports.InRangeOfNauticalMiles(40); airports = airports.WithRunway(rw => rw.LengthFeet > 100); // Now we have the airports we need // 4. Create a new list to store all the new grid items: List<DataGridItem> gridItems = new List<DataGridItem>(); // 5. create a datagrid item for each airport foreach (FsAirport ap in airports) { // Create new grid item and add the list DataGridItem item = new DataGridItem(); gridItems.Add(item); // Set the basic properties item.ICAO = ap.ICAO; item.Name = ap.Name; item.City = ap.City; item.Distance = ap.DistanceNauticalMiles.ToString("F2"); item.Bearing = ap.BearingToMagnetic.ToString("000"); // 6. Go through com frequencies for the airport and add an extra grid row for each for (int i = 0; i < ap.COMFrequencies.Count; i++) { // get the next frequency for the airport FsAirportComFrequency freq = ap.COMFrequencies[i]; // if this is not the first com frequency then make a new grid item so it appears on a new row if (i > 0) { item = new DataGridItem(); gridItems.Add(item); } // Add the frequency information item.Coms = freq.ComType.ToString() + ":" + freq.Frequency; } } // Display the grid items this.dataGridView1.DataSource = gridItems; } } Paul
  24. Thanks for the test. That looks to me like a problem on the FSUIPC end. We'll see if John can find anything when he gets back next week, Paul
  25. Hi John, I can't see anything wrong with your code. Have you tried just writing a basic offset - e.g. declare a standard int offset for 7F00 and just write 1 and 0 to it and see if it has any effect? Should activate the first button on stick 64. If you're using FSUIPC7, the offsets list I have says this offset has not been tested/has unknown status. I can't check it here but maybe @John Dowsoncould have a quick look at this offset in FSUIPC7 and confirm if it's working or not. Paul
×
×
  • 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.