Jump to content
The simFlight Network Forums

Can't get aircraft title


Recommended Posts

I have the following class of which other classes inherit from. I am trying to make a title property for the aircraft's name. Unfortunately, title, model, manufacturer, and the others don't work. They keep giving me String.Empty or something similar. On the other hand, the PFD and ComsRadios sections work. Just confused as to why things don't work. I am also having the same problem with the PMDG737 offsets always returning 0. I have a class 'PMDG737' that inherits the following airplane class. Even though the PMDG737 offsets are created after the connection is open, they still report as 0. Only reason I mention it is because the problems are similar. My connection manager is in a different class and works fine. Here is the airplane class.

 

using System.Windows.Threading;
using FSUIPC;

using NHotkey;
using NHotkey.WindowsForms;

using NLog;

using tfm.Airplanes.Shared;
using tfm.Utilities;

namespace tfm.Airplanes
{
    public abstract class Airplane
    {
        // Offsets (kept private unless required to be made public).
        #region

        // Aircraft identifiers.
        #region
        private Offset<string> _ICAOOffset = new Offset<string>(0x0618, 16);
        private Offset<string> _airlineOffset = new Offset<string>(0x062C, 4);
        private Offset<string> _manufacturerOffset = new Offset<string>(0x09D2, 16);
        private Offset<string> _modelOffset = new Offset<string>(0x0B26, 32);
        protected Offset<string> _titleOffset;
        #endregion
        #endregion
        // Fields
        #region
        private readonly Logger logger = LogManager.GetCurrentClassLogger();
        private PFD _pfd = new PFD();
        private FsFuelTanksCollection _fuelTanks;
        private List<FsFuelTank> _activeFuelTanks = new List<FsFuelTank>();
        protected bool _isControlKeysEnabled = false;
        protected bool _isFirstRun = true;
        private CommRadios _comRadios = new CommRadios();
        protected double _lastReportedASLAltitude;
        protected DispatcherTimer _timer;

        private string _title = string.Empty;
        #endregion

        // Event flags.
        #region
        protected bool _aslChangedEventEnabled = false;
        #endregion

        // Properties.
        #region
        // The primary flight display.
        public virtual PFD PFD { get => _pfd; }

        // The coms radio.
        public virtual CommRadios CommRadios { get => _comRadios; }

        // The active fuel tanks on the airplane.
        public virtual List<FsFuelTank> ActiveFuelTanks { get => _activeFuelTanks; }

        // The aircraft's current location.
        public PlayerLocationInfo CurrentLocation { get => FSUIPCConnection.AirportsDatabase.Airports.GetPlayerLocation(AirportComponents.All); }

        // Airline that owns the aircraft.
        public string Airline { get => _airlineOffset.Value; }

        // The aircraft model.
        public string Model { get => _modelOffset.Value; }

        // The manufacturer (could be software developer).
        public string Manufacturer { get => _manufacturerOffset.Value; }

        // Aircraft ICAO code.
        public string ICAO { get => _ICAOOffset.Value; }

        // The aircraft title (all identifiers in a single string).
        public virtual string Title { get => _titleOffset.Value; }
        #endregion

        // Events
        #region
        public EventHandler<ControlKeysRegistrationChangedEventArgs> ControlKeyRegistrationChanged;
        #endregion

        public Airplane()
        {

            _titleOffset = new Offset<string>(0x3d00, 255);

            // Detect fuel tanks.
            DetectFuelTanks();

            // Register features
            RegisterPrimaryControlKeyFeatures();

            this.PFD.AslAltitudeChanged += AnnounceAltitudeChanges;
            this.CommRadios.Com1FrequencyChanged += AnnounceCom1FrequencyChanges;
            this.CommRadios.Com2FrequencyChanged += AnnounceCom2FrequencyChanges;
            this.CommRadios.Com1StandbyFrequencyChanged += AnnounceCom1StandbyFrequencyChanges;
            this.CommRadios.Com2StandbyFrequencyChanged += AnnounceCom2StandbyFrequencyChanges;

            // Enable the aircraft components depending on the first run state.
            this.PFD.Enable();
            this.CommRadios.Enable();

            // Delay setting first run to fals until everything loads.
            Task.Delay(500).ContinueWith(t =>
            {
                _isFirstRun = false;
            });
            _timer = new()
            {
                Interval = TimeSpan.FromMilliseconds(50),
                                };

            _timer.Tick += (s, e) =>
            {
                                try
                {
                    FSUIPCConnection.Process();
                }
                catch(Exception ex)
                {
                    logger.Error(ex.Message);
                }
                                };
                _timer.Start();

                    }

        // Register/unregister hotkeys.
        #region
        protected virtual void RegisterPrimaryControlKeyFeatures()
        {

            HotkeyManager.Current.AddOrReplace("Primary control key", Keys.Oem6, (s, e) =>
{
    /*
     * Register the hotkeys for the primary control key. Each one passes through two layers of control.
     * (1) The OnPrimaryControlKeyPressed event where a secondary method is called. This first control layer allows the hotkey to call
     * the features code, and also allowing the trapping code to release the key to Windows.
     * (2) The features code, usually represented as a method in the form of On{featurename}KeyPressed where the feature's code lives.
     * 
     * Most of the features following the above format are speech requests with the primary and secondary control keys. Anything else is usually represented in the UI.
     */

    // Play the PFD sound whenever the key is pressed.
    AudioManager.Mixer.AddMixerInput(AudioManager.PFDSound);

    // Register the keys in the primary control section.
    HotkeyManager.Current.AddOrReplace("ASL altitude", Keys.A, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("Current location", Keys.C, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("Com radios", Keys.C | Keys.Shift, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("Heading", Keys.H, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("AGL altitude", Keys.G, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("Indicated airspeed", Keys.S, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("Mach speed", Keys.M, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("Ground speed", Keys.U, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("Vertical speed", Keys.V, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("Remaining fuel", Keys.F, PrimaryControlKeyPressed);
    HotkeyManager.Current.AddOrReplace("Altimeter", Keys.B, PrimaryControlKeyPressed);
});
            _isControlKeysEnabled = true;
            ControlKeyRegistrationChanged?.Invoke(this, new ControlKeysRegistrationChangedEventArgs(_isControlKeysEnabled));
        }

        protected virtual void UnregisterPrimaryControlKeyFeatures()
        {
            HotkeyManager.Current.Remove("ASL altitude");
            HotkeyManager.Current.Remove("Current location");
            HotkeyManager.Current.Remove("Com radios");
            HotkeyManager.Current.Remove("Heading");
            HotkeyManager.Current.Remove("AGL altitude");
            HotkeyManager.Current.Remove("Indicated airspeed");
            HotkeyManager.Current.Remove("Mach speed");
            HotkeyManager.Current.Remove("Ground speed");
            HotkeyManager.Current.Remove("Vertical speed");
            HotkeyManager.Current.Remove("Remaining fuel");
            HotkeyManager.Current.Remove("Altimeter");
        }

        public virtual void ToggleControlKeys()
        {

            _isControlKeysEnabled = !_isControlKeysEnabled;

            if (_isControlKeysEnabled)
            {
                RegisterPrimaryControlKeyFeatures();
            }
            else
            {
                UnregisterPrimaryControlKeyFeatures();
                HotkeyManager.Current.Remove("Primary control key");

                ControlKeyRegistrationChanged?.Invoke(this, new ControlKeysRegistrationChangedEventArgs(_isControlKeysEnabled));
            }

        }
        #endregion

        // Hotkey event handlers.
        #region
        protected virtual async void PrimaryControlKeyPressed(object sender, HotkeyEventArgs e)
        {
            switch (e.Name)
            {
                case "ASL altitude":
                    OnASLAltitudeKeyPress();
                    break;
                case "AGL altitude":
                    OnAGLAltitudeKeyPress();
                    break;
                case "Current location":
                   OnCurrentLocationKeyPressed();

                                        break;
                case "Com radios":
                    OnComRadioKeyPress();
                    break;
                case "Heading":
                    OnHeadingKeyPress();
                    break;
                case "Altimeter":
                    OnAltimeterKeyPress();
                    break;
                case "Ground speed":
                    OnGroundSpeedKeyPress();
                    break;
                case "Indicated airspeed":
                    OnIndicatedAirspeedKeyPress();
                    break;
                case "Mach speed":
                    OnMachSpeedKeyPress();
                    break;
                case "Remaining fuel":
                    OnRemainingFuelKeyPress();
                    break;
                case "Vertical speed":
                    OnVerticalSpeedKeyPress();
                    break;
            }

            // Unregister primary control features so they don't interfere with normal Windows operation.
            UnregisterPrimaryControlKeyFeatures();
        }

        protected virtual void OnASLAltitudeKeyPress()
        {
            string units = tfm.Properties.Settings.Default.DisplayAltitudesInMeters ? "meters" : "feet";
            AudioManager.Output(
                tfm.Properties.Settings.Default.DisplayAltitudesInMeters ?
                $"{Math.Truncate(PFD.AslAltitude)} {units}" :
                $"{Math.Truncate(MathServices.MetersToFeet(PFD.AslAltitude))} {units}"
                );

            // Remove the hotkey so it doesn't interfere with typing.
            HotkeyManager.Current.Remove("ASL altitude");
        }
        protected virtual void OnAGLAltitudeKeyPress()
        {

            string units = tfm.Properties.Settings.Default.DisplayAltitudesInMeters ? "meters" : "feet";
            AudioManager.Output(
                tfm.Properties.Settings.Default.DisplayAltitudesInMeters ?
                $"{PFD.AglAltitude} {units}" :
$"{Math.Truncate(MathServices.MetersToFeet(PFD.AglAltitude))} {units}"
);

            HotkeyManager.Current.Remove("AGL altitude");
        }
        protected virtual void OnHeadingKeyPress()
        {
            AudioManager.Output(PFD.TrueHeading.ToString());

            HotkeyManager.Current.Remove("Heading");
        }
        protected virtual void OnIndicatedAirspeedKeyPress()
        {
            AudioManager.Output($"{PFD.IndicatedAirSpeed} knots");

            HotkeyManager.Current.Remove("Indicated airspeed");
        }
        protected virtual void OnMachSpeedKeyPress()
        {
            AudioManager.Output($"Mach {PFD.MachSpeed}");

            HotkeyManager.Current.Remove("Mach speed");
        }
        protected virtual void OnGroundSpeedKeyPress()
        {
            AudioManager.Output($"{PFD.GroundSpeed} knots");

            HotkeyManager.Current.Remove("Ground speed");
        }
        protected virtual void OnVerticalSpeedKeyPress()
        {

            string units = tfm.Properties.Settings.Default.DisplayAltitudesInMeters ? "MPS" : "FPM";

            AudioManager.Output(
                tfm.Properties.Settings.Default.DisplayAltitudesInMeters ?
                $"{PFD.VerticalSpeed} {units}" :
                $"{Math.Truncate(MathServices.MetersPerSecondToFeetPerMinute(PFD.VerticalSpeed))} {units}"
                );

            HotkeyManager.Current.Remove("Vertical speed");
        }
        protected virtual void OnRemainingFuelKeyPress()
        {
            FSUIPCConnection.PayloadServices.RefreshData();
            double lbs = Math.Truncate(FSUIPCConnection.PayloadServices.FuelWeightLbs);
            double gal = Math.Truncate(FSUIPCConnection.PayloadServices.FuelLevelUSGallons);
            AudioManager.Output($"{lbs} pounds ({gal} Gallons");

            HotkeyManager.Current.Remove("Remaining fuel");
        }
        protected virtual void OnAltimeterKeyPress()
        {

            string units = tfm.Properties.Settings.Default.DisplayAltimeterInches ? "inches" : "millibars";

            AudioManager.Output(
                tfm.Properties.Settings.Default.DisplayAltimeterInches ?
                $"{MathServices.MillibarsToInches(PFD.Altimeter)} {units}" :
                $"{PFD.Altimeter} {units}"
                );

            HotkeyManager.Current.Remove("Altimeter");
        }
        protected virtual void OnComRadioKeyPress()
        {
            AudioManager.Output($"Com1: {this.CommRadios.Comm1Frequency}");
            AudioManager.Output($"Com2: {this.CommRadios.Com2Frequency}");
            AudioManager.Output($"Com 1 standby: {this.CommRadios.Com1StandbyFrequency}");
            AudioManager.Output($"Com 2 standby: {this.CommRadios.Com2StandbyFrequency}");
        }
        protected virtual async Task OnCurrentLocationKeyPressed()
        {

            try
            {
                var location = await LocationService.GetLocationInfoAsync();
                AudioManager.Output(location);
            }
            catch(Exception ex)
            {
                logger.Error("Error in getting current location.");
            }
                    }
        #endregion
        // Event handlers for aircraft changes.
        #region

        protected virtual void AnnounceAltitudeChanges(object sender, AltitudeChangedEventArgs e)
        {
            if (_isFirstRun) return;
            double currentAltitude = tfm.Properties.Settings.Default.DisplayAltitudesInMeters ? e.Meters : e.Feet;
            string units = tfm.Properties.Settings.Default.DisplayAltitudesInMeters ? "meters" : "feet";
            bool announceAltitudes = tfm.Properties.Settings.Default.AltitudeAnnouncements;
            double altitudeInterval = double.Parse(tfm.Properties.Settings.Default.AnnounceAltitudeInterval);

            if (announceAltitudes)
            {
                double startingAltitude = Math.Ceiling(currentAltitude / altitudeInterval) * altitudeInterval;
                for (double i = startingAltitude; i < 65000; i += altitudeInterval)
                {
                    if (currentAltitude >= i - 10 && currentAltitude <= i + 10)
                    {
                        if (_lastReportedASLAltitude != i)
                        {
                            AudioManager.Output($"{i} {units}");
                            _lastReportedASLAltitude = i;
                        }
                        break;
                    }
                }
            }
        }

        protected virtual void AnnounceCom1FrequencyChanges(object sender, ComFrequencyChangedEventArgs e)
        {
                        if (!_isFirstRun)
            {
                AudioManager.Output($"Com1: {e.Frequency}");
            }
        }
        
        protected virtual void AnnounceCom2FrequencyChanges(object sender, ComFrequencyChangedEventArgs e)
        {
            if (!_isFirstRun)
            {
                AudioManager.Output($"Com2: {this.CommRadios.Com2Frequency}");
            }
        }
        
        protected virtual void AnnounceCom1StandbyFrequencyChanges(object sender, ComFrequencyChangedEventArgs e)
        {
            if (!_isFirstRun)
            {
                AudioManager.Output($"Com1 standby: {this.CommRadios.Com1StandbyFrequency}");
            }

        }

        protected virtual void AnnounceCom2StandbyFrequencyChanges(object sender, ComFrequencyChangedEventArgs e)
        {
            if (!_isFirstRun)
            {
                AudioManager.Output($"Com2 standby: {this.CommRadios.Com2StandbyFrequency}");
            }

        }
        #endregion
        // Detect the active fuel tanks on the airplane and get their values.
        protected virtual void DetectFuelTanks()
        {
                        if (FSUIPCConnection.IsOpen)
            {

                FSUIPCConnection.PayloadServices.RefreshData();
                _activeFuelTanks.Clear();

                // Assign the fuel tanks to our class level variable for easier access
                _fuelTanks = FSUIPCConnection.PayloadServices.FuelTanks;
                foreach (FsFuelTank tank in _fuelTanks)
                {
                    if (tank.IsPresent)
                    {
                        _activeFuelTanks.Add(tank);
                        logger.Info("found " + tank.Tank.ToString());
                    }
                }
            }
        }                           

    }
}
 

Link to comment
Share on other sites

I suggest you make a very plain, simple application so you can test out offsets that don't appear to work. Just a form that opens a connection, processes the offsets and writes them to the form.

If they don't work in your simple project then you need to ask John Dowson in the main MSFS (FSUIPC7) support forum. Maybe some of the offsets don't work in FSUIPC7. 

If they do work in your simple project then it's something to do with the logic in your application. You'll need to use the tools available to find out what the problem is (break points, logging etc.).

Paul

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.