Skip to content

Commit c5ee7c2

Browse files
committed
MSFS 2024 SU4 Release
1 parent 2219300 commit c5ee7c2

File tree

373 files changed

+29806
-5257
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

373 files changed

+29806
-5257
lines changed

src/garminsdk/autopilot/FmaData.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { APAltitudeModes } from '@microsoft/msfs-sdk';
2+
13
/**
24
* Data describing autopilot status used by Garmin FMAs.
35
*/
@@ -26,9 +28,30 @@ export type FmaData = {
2628
/** The armed lateral mode. */
2729
lateralArmed: number;
2830

29-
/** Whether the lateral mode is in a failed state. */
31+
/**
32+
* Whether the lateral mode is in a failed state.
33+
* @deprecated Please use `lateralReversionFromMode` instead to access lateral mode reversion state.
34+
*/
3035
lateralModeFailed: boolean;
3136

37+
/**
38+
* The lateral mode that was reverted to activate the current lateral mode, or `null` if the current active lateral
39+
* mode was not activated due to a mode reversion.
40+
*/
41+
lateralReversionFromMode: number | null;
42+
43+
/**
44+
* The vertical mode that was reverted to activate the current vertical mode, or `null` if the current active
45+
* vertical mode was not activated due to a mode reversion.
46+
*/
47+
verticalReversionFromMode: number | null;
48+
49+
/**
50+
* The altitude capture mode that was reverted to activate the current vertical mode, or `null` if the current active
51+
* vertical mode was not activated due to a mode reversion.
52+
*/
53+
verticalAltitudeReversionFromMode: APAltitudeModes | null;
54+
3255
/** The state of VNAV to be displayed on the FMA. */
3356
vnavState: FmaVNavState;
3457
}

src/garminsdk/autopilot/GarminAPConfig.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,9 +513,8 @@ export class GarminAPConfig implements GarminAPConfigInterface {
513513
* @param apValues The autopilot's state values.
514514
* @returns The autopilot's VNAV path mode director, or `undefined` to omit the director.
515515
*/
516-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
517516
protected createVNavPathDirector(apValues: APValues): PlaneDirector | undefined {
518-
return new APVNavPathDirector(this.bus, { guidance: this.verticalPathGuidance });
517+
return new APVNavPathDirector(apValues, { guidance: this.verticalPathGuidance });
519518
}
520519

521520
/**

src/garminsdk/autopilot/GarminAPUtils.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import {
2+
APAltitudeModes,
23
APBackCourseDirectorActivateNavData, APBackCourseDirectorNavData, APGpsSteerDirectorState,
34
APGSDirectorActivateNavData, APGSDirectorNavData, APLateralModes, APNavDirectorActivateNavData, APNavDirectorNavData,
4-
APValues, APVerticalModes, MathUtils, NavMath, NavSourceType, RadioUtils, SimVarValueType, UnitType
5+
APValues, APVerticalModes, MathUtils, NavMath, NavSourceType, RadioUtils, UnitType
56
} from '@microsoft/msfs-sdk';
67

8+
import { FmaData, FmaVNavState } from './FmaData';
9+
710
/**
811
* A utility class for working with Garmin autopilots.
912
*/
@@ -56,7 +59,7 @@ export class GarminAPUtils {
5659
if (dtk === null) {
5760
return false;
5861
}
59-
const headingDiff = NavMath.diffAngle(SimVar.GetSimVarValue('PLANE HEADING DEGREES MAGNETIC', SimVarValueType.Degree), dtk);
62+
const headingDiff = NavMath.diffAngle(apValues.dataProvider.getItem('heading_magnetic').getValue(), dtk);
6063
const sensitivity = navData.hasLoc ? 1 : .6;
6164
if (Math.abs(navData.deviation * sensitivity) < 1 && Math.abs(headingDiff) < 110) {
6265
return true;
@@ -130,7 +133,7 @@ export class GarminAPUtils {
130133
&& Math.abs(navData.deviation) < 1
131134
) {
132135
const dtk = NavMath.normalizeHeading(navData.locCourse + 180);
133-
const headingDiff = NavMath.diffAngle(SimVar.GetSimVarValue('PLANE HEADING DEGREES MAGNETIC', SimVarValueType.Degree), dtk);
136+
const headingDiff = NavMath.diffAngle(apValues.dataProvider.getItem('heading_magnetic').getValue(), dtk);
134137
if (Math.abs(headingDiff) < 110) {
135138
return true;
136139
}
@@ -357,4 +360,26 @@ export class GarminAPUtils {
357360
// for performance reasons.
358361
return Math.asin(Math.min(Math.sqrt(Math.abs(xtk) / (2 * turnRadius)), 1)) * Avionics.Utils.RAD2DEG;
359362
}
360-
}
363+
364+
/**
365+
* Creates an empty `FmaData` object.
366+
* @returns A new empty `FmaData` object.
367+
*/
368+
public static createEmptyFmaData(): FmaData {
369+
return {
370+
verticalActive: APVerticalModes.NONE,
371+
verticalArmed: APVerticalModes.NONE,
372+
verticalApproachArmed: APVerticalModes.NONE,
373+
verticalAltitudeArmed: APAltitudeModes.NONE,
374+
altitudeCaptureArmed: false,
375+
altitudeCaptureValue: -1,
376+
lateralActive: APLateralModes.NONE,
377+
lateralArmed: APLateralModes.NONE,
378+
lateralModeFailed: false,
379+
lateralReversionFromMode: null,
380+
verticalReversionFromMode: null,
381+
verticalAltitudeReversionFromMode: null,
382+
vnavState: FmaVNavState.OFF
383+
};
384+
}
385+
}

src/garminsdk/autopilot/GarminAutopilot.ts

Lines changed: 115 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import {
2-
AdcEvents, AltitudeSelectEvents, AltitudeSelectManager, AltitudeSelectManagerOptions, APAltitudeModes, APEvents, APLateralModes,
3-
APModePressEvent, APStateManager, APVerticalModes, Autopilot, ConsumerSubject, ConsumerValue, DirectorState,
4-
EventBus, FlightPlanner, MappedSubject, MetricAltitudeSettingsManager, MinimumsMode, NavSourceType, ObjectSubject,
5-
PlaneDirector,
6-
RadioUtils, SetSubject, SimVarValueType, Subject, UnitType, VNavAltCaptureType, VNavState
2+
AdcEvents, AltitudeSelectEvents, AltitudeSelectManager, AltitudeSelectManagerOptions, APAltitudeModes, APEvents,
3+
APLateralModes, APModePressEvent, APStateManager, APVerticalModes, Autopilot, ConsumerSubject, ConsumerValue,
4+
DirectorState, EventBus, FlightPlanner, MappedSubject, MetricAltitudeSettingsManager, MinimumsMode, NavSourceType,
5+
ObjectSubject, PlaneDirector, RadioUtils, SetSubject, SimVarValueType, Subject, UnitType, VNavAltCaptureType,
6+
VNavState
77
} from '@microsoft/msfs-sdk';
88

99
import { MinimumsDataProvider } from '../minimums/MinimumsDataProvider';
1010
import { GarminAPVars } from './data/GarminAPEvents';
1111
import { FmaData, FmaDataEvents, FmaVNavState } from './FmaData';
1212
import { GarminAPConfigInterface } from './GarminAPConfigInterface';
13+
import { GarminAPUtils } from './GarminAPUtils';
1314
import { GarminVNavManager2 } from './vnav/GarminVNavManager2';
1415

1516
/**
@@ -77,18 +78,7 @@ export class GarminAutopilot extends Autopilot<GarminAPConfigInterface> {
7778

7879
protected readonly isAltSelectInitialized = ConsumerValue.create(null, true);
7980

80-
protected readonly fmaData = ObjectSubject.create<FmaData>({
81-
verticalActive: APVerticalModes.NONE,
82-
verticalArmed: APVerticalModes.NONE,
83-
verticalApproachArmed: APVerticalModes.NONE,
84-
verticalAltitudeArmed: APAltitudeModes.NONE,
85-
altitudeCaptureArmed: false,
86-
altitudeCaptureValue: -1,
87-
lateralActive: APLateralModes.NONE,
88-
lateralArmed: APLateralModes.NONE,
89-
lateralModeFailed: false,
90-
vnavState: FmaVNavState.OFF
91-
});
81+
protected readonly fmaData = ObjectSubject.create<FmaData>(GarminAPUtils.createEmptyFmaData());
9282

9383
protected readonly fmaDataPublisher = this.bus.getPublisher<FmaDataEvents>();
9484
protected needPublishFmaData = false;
@@ -103,6 +93,13 @@ export class GarminAutopilot extends Autopilot<GarminAPConfigInterface> {
10393

10494
protected isApproachModeCommandedOn = false;
10595

96+
protected lateralModeReversionFromMode: number | null = null;
97+
protected lateralModeReversionToMode: number | null = null;
98+
99+
protected verticalModeReversionFromMode: number | null = null;
100+
protected verticalModeReversionFromAltitudeMode: APAltitudeModes | null = null;
101+
protected verticalModeReversionToMode: number | null = null;
102+
106103
/**
107104
* Creates a new instance of GarminAutopilot.
108105
* @param bus The event bus.
@@ -287,6 +284,7 @@ export class GarminAutopilot extends Autopilot<GarminAPConfigInterface> {
287284
protected onAfterUpdate(): void {
288285
this.updateApproachModeState();
289286
this.updateNavModeState();
287+
this.updateModeReversionState();
290288
this.updateFma();
291289
}
292290

@@ -339,6 +337,41 @@ export class GarminAutopilot extends Autopilot<GarminAPConfigInterface> {
339337
}
340338
}
341339

340+
/**
341+
* Updates this autopilot's mode reversion state.
342+
*/
343+
protected updateModeReversionState(): void {
344+
if (!this.stateManager.apMasterOn.get() && !this.stateManager.isAnyFlightDirectorOn.get()) {
345+
// If flight director is not on, then reset all mode reversions.
346+
347+
this.lateralModeReversionFromMode = null;
348+
this.lateralModeReversionToMode = null;
349+
this.verticalModeReversionFromMode = null;
350+
this.verticalModeReversionFromAltitudeMode = null;
351+
this.verticalModeReversionToMode = null;
352+
} else {
353+
// If flight director is on, then reset mode reversions if the corresponding active mode is not either NONE
354+
// or the mode to which the original mode reverted.
355+
356+
if (this.lateralModeReversionToMode !== null) {
357+
const lateralActiveMode = this.apValues.lateralActive.get();
358+
if (lateralActiveMode !== this.lateralModeReversionToMode && lateralActiveMode !== APLateralModes.NONE) {
359+
this.lateralModeReversionFromMode = null;
360+
this.lateralModeReversionToMode = null;
361+
}
362+
}
363+
364+
if (this.verticalModeReversionToMode !== null) {
365+
const verticalActiveMode = this.apValues.verticalActive.get();
366+
if (verticalActiveMode !== this.verticalModeReversionToMode && verticalActiveMode !== APVerticalModes.NONE) {
367+
this.verticalModeReversionFromMode = null;
368+
this.verticalModeReversionFromAltitudeMode = null;
369+
this.verticalModeReversionToMode = null;
370+
}
371+
}
372+
}
373+
}
374+
342375
/**
343376
* Publishes data for the FMA.
344377
*/
@@ -364,6 +397,9 @@ export class GarminAutopilot extends Autopilot<GarminAPConfigInterface> {
364397
fmaData.set('lateralActive', this.apValues.lateralActive.get());
365398
fmaData.set('lateralArmed', this.apValues.lateralArmed.get());
366399
fmaData.set('lateralModeFailed', this.lateralModeFailed);
400+
fmaData.set('lateralReversionFromMode', this.lateralModeReversionFromMode);
401+
fmaData.set('verticalReversionFromMode', this.verticalModeReversionFromMode);
402+
fmaData.set('verticalAltitudeReversionFromMode', this.verticalModeReversionFromAltitudeMode);
367403
fmaData.set('vnavState', fmaVNavState);
368404

369405
if (this.needPublishFmaData) {
@@ -596,4 +632,66 @@ export class GarminAutopilot extends Autopilot<GarminAPConfigInterface> {
596632

597633
super.checkModes();
598634
}
635+
636+
/** @inheritDoc */
637+
protected handleLateralActiveModeReversion(mode: number): void {
638+
// For backward compatibility.
639+
if (mode !== APLateralModes.NONE) {
640+
this.lateralModeFailed = true;
641+
}
642+
643+
// Immediately set the active lateral mode to NONE and attempt to activate the NONE director. We do this in order
644+
// to guarantee that the reverted mode is not left as the active lateral mode.
645+
this.apValues.lateralActive.set(APLateralModes.NONE);
646+
this.lateralModes.get(APLateralModes.NONE)?.activate();
647+
648+
// Immediately deactivate the armed lateral mode, if there is one. We do this to guarantee that during a
649+
// reversion, the armed mode ends up as either the default lateral mode (see below) or NONE.
650+
const lateralArmedMode = this.apValues.lateralArmed.get();
651+
if (lateralArmedMode !== APLateralModes.NONE) {
652+
this.lateralModes.get(lateralArmedMode)?.deactivate();
653+
this.apValues.lateralArmed.set(APLateralModes.NONE);
654+
}
655+
656+
// Attempt to arm the default lateral mode. If the default lateral mode is NONE, then we can skip arming because
657+
// we've already activated the NONE director above.
658+
const modeToArm = this.getDefaultLateralMode();
659+
if (modeToArm !== APLateralModes.NONE) {
660+
this.lateralModes.get(modeToArm)?.arm();
661+
}
662+
663+
if (mode !== APLateralModes.NONE) {
664+
this.lateralModeReversionFromMode = mode;
665+
this.lateralModeReversionToMode = modeToArm;
666+
}
667+
}
668+
669+
/** @inheritDoc */
670+
protected handleVerticalActiveModeReversion(mode: number): void {
671+
// Immediately set the active vertical mode to NONE and attempt to activate the NONE director. We do this in
672+
// order to guarantee that the reverted mode is not left as the active vertical mode.
673+
this.apValues.verticalActive.set(APVerticalModes.NONE);
674+
this.verticalModes.get(APVerticalModes.NONE)?.activate();
675+
676+
// Immediately deactivate the armed vertical mode, if there is one. We do this to guarantee that during a
677+
// reversion, the armed mode ends up as either the default vertical mode (see below) or NONE.
678+
const verticalArmedMode = this.apValues.verticalArmed.get();
679+
if (verticalArmedMode !== APLateralModes.NONE) {
680+
this.verticalModes.get(verticalArmedMode)?.deactivate();
681+
this.apValues.verticalArmed.set(APLateralModes.NONE);
682+
}
683+
684+
// Attempt to arm the default vertical mode. If the default vertical mode is NONE, then we can skip arming
685+
// because we've already activated the NONE director above.
686+
const modeToArm = this.getDefaultVerticalMode();
687+
if (modeToArm !== APVerticalModes.NONE) {
688+
this.verticalModes.get(modeToArm)?.arm();
689+
}
690+
691+
if (mode !== APVerticalModes.NONE) {
692+
this.verticalModeReversionFromMode = mode;
693+
this.verticalModeReversionFromAltitudeMode = this.verticalAltitudeArmed;
694+
this.verticalModeReversionToMode = modeToArm;
695+
}
696+
}
599697
}

src/garminsdk/autopilot/vnav/GarminVNavManager2.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ export class GarminVNavManager2 implements VNavManager {
5656
/** @inheritDoc */
5757
public activateMode?: (mode: number) => void;
5858

59+
/** @inheritDoc */
60+
public deactivateMode?: (mode: number) => void;
61+
5962
// eslint-disable-next-line jsdoc/require-returns
6063
/** Whether VNAV is active. */
6164
public get isActive(): boolean {
@@ -217,7 +220,7 @@ export class GarminVNavManager2 implements VNavManager {
217220
}
218221

219222
if (this.apValues.verticalActive.get() === APVerticalModes.PATH) {
220-
this.activateMode && this.activateMode(APVerticalModes.PITCH);
223+
this.deactivateMode && this.deactivateMode(APVerticalModes.PATH);
221224
}
222225
}
223226

@@ -270,4 +273,4 @@ export class GarminVNavManager2 implements VNavManager {
270273
}
271274
}
272275
}
273-
}
276+
}

src/garminsdk/autopilot/vnav/GarminVNavUtils.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
BitFlags, FlightPlan, FlightPlanSegment, FlightPlanUtils, LegDefinition, LegDefinitionFlags, LegType, MathUtils,
3-
TocBocDetails, UnitType, VerticalFlightPlan, VNavConstraint, VNavLeg, VNavUtils
3+
TocBocDetails, UncomputedVNavConstraint, UnitType, VerticalFlightPlan, VNavConstraint, VNavLeg, VNavUtils
44
} from '@microsoft/msfs-sdk';
55

66
import { FmsUtils } from '../../flightplan/FmsUtils';
@@ -97,9 +97,9 @@ export class GarminVNavUtils {
9797
* @returns Whether the specified climb constraint should be invalidated.
9898
*/
9999
public static invalidateClimbConstraint(
100-
constraint: VNavConstraint,
100+
constraint: UncomputedVNavConstraint,
101101
index: number,
102-
constraints: readonly VNavConstraint[],
102+
constraints: readonly UncomputedVNavConstraint[],
103103
firstDescentConstraintIndex: number,
104104
priorMinAltitude: number,
105105
priorMaxAltitude: number
@@ -146,9 +146,9 @@ export class GarminVNavUtils {
146146
* @returns Whether the specified descent constraint should be invalidated.
147147
*/
148148
public static invalidateDescentConstraint(
149-
constraint: VNavConstraint,
149+
constraint: UncomputedVNavConstraint,
150150
index: number,
151-
constraints: readonly VNavConstraint[],
151+
constraints: readonly UncomputedVNavConstraint[],
152152
priorMinAltitude: number,
153153
priorMaxAltitude: number,
154154
requiredFpa: number,

0 commit comments

Comments
 (0)