Skip to content

Commit

Permalink
feat(A380X): Added systems-host and extras-host to A380X (#8418)
Browse files Browse the repository at this point in the history
* Initial add of extras-host to A380X

* Move setting of A32NX_IS_READY to extras-host

* Added systems-host from A32NX to A380X

* Removed commented part in build script
  • Loading branch information
frankkopp authored Jan 19, 2024
1 parent a98ab34 commit d301492
Show file tree
Hide file tree
Showing 22 changed files with 792 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,5 +154,19 @@ htmlgauge00=WasmInstrument/WasmInstrument.html?wasm_module=systems.wasm&wasm_gau
htmlgauge01=WasmInstrument/WasmInstrument.html?wasm_module=fbw.wasm&wasm_gauge=fbw, 0,0,1,1
htmlgauge02=WasmInstrument/WasmInstrument.html?wasm_module=fadec.wasm&wasm_gauge=FadecGauge, 0,0,1,1
htmlgauge03=WasmInstrument/WasmInstrument.html?wasm_module=extra-backend-a380x.wasm&wasm_gauge=Gauge_Extra_Backend,0,0,1,1
# Uncomment when A380 ExtrasHost exists in monorepo
#htmlgauge04=A380X/ExtrasHost/extras-host.html,0,0,1,1

[VCockpit20]
size_mm = 0,0
pixel_size = 0,0
texture = NO_TEXTURE
background_color = 0,0,0

htmlgauge00 = A380X/SystemsHost/systems-host.html,0,0,1,1

[VCockpit21]
size_mm=0,0
pixel_size=0,0
texture=NO_TEXTURE
background_color=0,0,0

htmlgauge04=A380X/ExtrasHost/extras-host.html,0,0,1,1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!-- Copyright (c) 2022 FlyByWire Simulations -->
<!-- SPDX-License-Identifier: GPL-3.0 -->

<script type="text/html" id="A380X_EXTRASHOST"></script>

<script type="text/html" import-script="/JS/dataStorage.js" import-async="false"></script>
<script type="text/html" import-script="/Pages/VCockpit/Instruments/A380X/ExtrasHost/index.js" import-async="false"></script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<script type="text/html" id="A380X_SYSTEMSHOST"></script>

<script type="text/html" import-script="/JS/dataStorage.js" import-async="false"></script>
<script type="text/html" import-script="/Pages/VCockpit/Instruments/A380X/SystemsHost/index.js" import-async="false"></script>
24 changes: 24 additions & 0 deletions fbw-a380x/src/systems/extras-host/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# FBW Extras Host

The ExtrasHost instrument is used to provide non-aircraft and non-wasm related functionality an
environment to run as single instrument without rendering or connection to the MCDU, or the EFB,
where some of these functionalities have been hosted in the past.

The ExtrasHost inherits from the BaseInstruments class that is managed by the simulator.

It uses the msfssdk library for using the EventBus and HEventPublisher and pot. other classes.

## System interfaces

Every module class has to implement the following functions:

- `constructor` to get access to the system-wide EventBus
- `connectedCallback` which is called after the simulator set up everything. These functions will also add the subscribtion to special events.
- `startPublish` which is called as soon as the simulator starts running. It will also start publishing the simulator variables onto the EventBus
- `update` is called in every update call of the simulator, but only after `startPublish` is called

## Examples

See the modules folder for examples on how to implement a module.


13 changes: 13 additions & 0 deletions fbw-a380x/src/systems/extras-host/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) 2021-2023 FlyByWire Simulations
//
// SPDX-License-Identifier: GPL-3.0

'use strict';

const esbuild = require('esbuild');
const path = require('path');
const { createModuleBuild } = require('#build-utils');

const outFile = 'fbw-a380x/out/flybywire-aircraft-a380-842/html_ui/Pages/VCockpit/Instruments/A380X/ExtrasHost/index.js';

esbuild.build(createModuleBuild('fbw-a380x', undefined, path.join(__dirname, './index.ts'), outFile, __dirname));
110 changes: 110 additions & 0 deletions fbw-a380x/src/systems/extras-host/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (c) 2022 FlyByWire Simulations
// SPDX-License-Identifier: GPL-3.0

import { EventBus, HEventPublisher } from '@microsoft/msfs-sdk';
import { NotificationManager } from '@flybywiresim/fbw-sdk';
import { ExtrasSimVarPublisher } from 'extras-host/modules/common/ExtrasSimVarPublisher';
import { PushbuttonCheck } from 'extras-host/modules/pushbutton_check/PushbuttonCheck';
import { KeyInterceptor } from './modules/key_interceptor/KeyInterceptor';
import { VersionCheck } from './modules/version_check/VersionCheck';

/**
* This is the main class for the extras-host instrument.
*
* It provides an environment for non-aircraft non-wasm systems/modules to run in.
*
* Usage:
* - Add new modules as private readonly members of this class.
* - Add the modules to the constructor.
* - Add the modules to the connectedCallback() method.
* - Add the modules to the Update() method.
*
* Each module must implement the following methods:
* - `constructor` to get access to the system-wide EventBus
* - `connectedCallback` which is called after the simulator set up everything. These functions will also add the subscribtion to special events.
* - `startPublish` which is called as soon as the simulator starts running. It will also start publishing the simulator variables onto the EventBus
* - `update` is called in every update call of the simulator, but only after `startPublish` is called
*/
class ExtrasHost extends BaseInstrument {
private readonly bus: EventBus;

private readonly notificationManager: NotificationManager;

private readonly hEventPublisher: HEventPublisher;

private readonly simVarPublisher: ExtrasSimVarPublisher;

private readonly pushbuttonCheck: PushbuttonCheck;

private readonly versionCheck: VersionCheck;

private readonly keyInterceptor: KeyInterceptor;

/**
* "mainmenu" = 0
* "loading" = 1
* "briefing" = 2
* "ingame" = 3
*/
private gameState = 0;

constructor() {
super();

this.bus = new EventBus();
this.hEventPublisher = new HEventPublisher(this.bus);
this.simVarPublisher = new ExtrasSimVarPublisher(this.bus);

this.notificationManager = new NotificationManager();

this.pushbuttonCheck = new PushbuttonCheck(this.bus, this.notificationManager);
this.versionCheck = new VersionCheck(this.bus);
this.keyInterceptor = new KeyInterceptor(this.bus, this.notificationManager);

console.log('A380X_EXTRASHOST: Created');
}

get templateID(): string {
return 'A380X_EXTRASHOST';
}

public getDeltaTime() {
return this.deltaTime;
}

public onInteractionEvent(args: string[]): void {
this.hEventPublisher.dispatchHEvent(args[0]);
}

public connectedCallback(): void {
super.connectedCallback();

this.pushbuttonCheck.connectedCallback();
}

public Update(): void {
super.Update();

if (this.gameState !== GameState.ingame) {
const gs = this.getGameState();
if (gs === GameState.ingame) {
// Start the modules
this.hEventPublisher.startPublish();
this.versionCheck.startPublish();
this.keyInterceptor.startPublish();
this.simVarPublisher.startPublish();

// Signal that the aircraft is ready via L:A32NX_IS_READY
SimVar.SetSimVarValue('L:A32NX_IS_READY', 'number', 1);
console.log('A380X_EXTRASHOST: Aircraft is ready');
}
this.gameState = gs;
} else {
this.simVarPublisher.onUpdate();
}

// Call module update() methods here if they have one
}
}

registerInstrument('extras-host', ExtrasHost);
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) 2023-2024 FlyByWire Simulations
// SPDX-License-Identifier: GPL-3.0

/**
* The AircraftPresetsList class is used to get the name of a preset from the preset ID.
* These need to align with the IDs in the Presets C++ WASM and the AircraftPresets.tsx in the EFB.
* WASM: src/presets/src/Aircraft/AircraftProcedures.h
*/
export class AircraftPresetsList {
private static list: { index: number, name: string }[] = [
{ index: 1, name: 'Cold & Dark' },
{ index: 2, name: 'Powered' },
{ index: 3, name: 'Ready for Pushback' },
{ index: 4, name: 'Ready for Taxi' },
{ index: 5, name: 'Ready for Takeoff' },
];

public static getPresetName(presetID: number): string {
const index = presetID - 1;
if (index < 0 || index > AircraftPresetsList.list.length) {
return '';
}
return AircraftPresetsList.list[index].name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2023 FlyByWire Simulations
// SPDX-License-Identifier: GPL-3.0

import { EventBus, PublishPacer, SimVarDefinition, SimVarPublisher, SimVarValueType } from '@microsoft/msfs-sdk';

/* eslint-disable camelcase */

export interface ExtrasSimVarEvents {
/** ECP TO CONF pushbutton state */
ecp_to_config_pushbutton: boolean,
/** FWC flight phase from 1 - 10 */
fwc_flight_phase: number,
}

export class ExtrasSimVarPublisher extends SimVarPublisher<ExtrasSimVarEvents> {
private static readonly simVars = new Map<keyof ExtrasSimVarEvents, SimVarDefinition>([
['ecp_to_config_pushbutton', { name: 'L:A32NX_BTN_TOCONFIG', type: SimVarValueType.Bool }],
['fwc_flight_phase', { name: 'L:A32NX_FWC_FLIGHT_PHASE', type: SimVarValueType.Number }],
]);

constructor(bus: EventBus, pacer?: PublishPacer<ExtrasSimVarEvents>) {
super(ExtrasSimVarPublisher.simVars, bus, pacer);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright (c) 2022 FlyByWire Simulations
// SPDX-License-Identifier: GPL-3.0

import { EventBus, KeyEvents, KeyEventManager } from '@microsoft/msfs-sdk';
import { NotificationManager, NotificationType, PopUpDialog } from '@flybywiresim/fbw-sdk';
import { AircraftPresetsList } from '../common/AircraftPresetsList';

/**
* This class is used to intercept the key events for the engine auto start and engine auto shutdown.
*
* Additional key events can be added in the registerIntercepts() method.
*/
export class KeyInterceptor {
private eventBus: EventBus;

private keyInterceptManager: KeyEventManager;

private dialogVisible = false;

constructor(private readonly bus: EventBus, private readonly notification: NotificationManager) {
this.eventBus = bus;
KeyEventManager.getManager(this.eventBus).then((manager) => {
this.keyInterceptManager = manager;
this.registerIntercepts();
});
console.log('KeyInterceptor: Created');
}

public startPublish(): void {
console.log('KeyInterceptor: startPublish()');
}

private registerIntercepts() {
this.keyInterceptManager.interceptKey('ENGINE_AUTO_START', false);
this.keyInterceptManager.interceptKey('ENGINE_AUTO_SHUTDOWN', false);

const subscriber = this.eventBus.getSubscriber<KeyEvents>();
subscriber.on('key_intercept').handle((keyData) => {
switch (keyData.key) {
case 'ENGINE_AUTO_START':
console.log('KeyInterceptor: ENGINE_AUTO_START');
this.engineAutoStartAction();
break;
case 'ENGINE_AUTO_SHUTDOWN':
console.log('KeyInterceptor: ENGINE_AUTO_SHUTDOWN');
this.engineAutoStopAction();
break;
default:
break;
}
});
}

private engineAutoStartAction() {
if (!this.dialogVisible) {
// If loading already in progress show a notification and return
if (this.isAlreadyLoading()) return;
// Show a dialog to ask user to load a preset or cancel
this.dialogVisible = true;
const dialog = new PopUpDialog();
const presetID = 4; // "Ready for Taxi"
dialog.showPopUp(
'Ctrl+E Not supported',
`<div style="font-size: 120%; text-align: left;">
Engine Auto Start is not supported by the A380X.<br/>
<br/>
Do you want to you use the flyPad's Aircraft Presets to set the aircraft to
<strong>"${AircraftPresetsList.getPresetName(presetID)}"</strong>?
</div>`,
'small',
() => this.loadPreset(presetID),
() => this.dialogVisible = false,
);
}
}

private engineAutoStopAction() {
if (this.isAlreadyLoading()) return;
// If engines are running show a dialog to ask user to load a preset or cancel
if (!this.dialogVisible && this.isOneEngineRunning()) {
this.dialogVisible = true;
const dialog = new PopUpDialog();
const presetID = 2;
dialog.showPopUp(
'Shift+Ctrl+E Not supported',
`<div style="font-size: 120%; text-align: left;">
Engine Auto Shutdown is not supported by the A380X.<br/>
<br/>
Do you want to you use the flyPad's Aircraft Presets to set the aircraft to
<strong>"${AircraftPresetsList.getPresetName(presetID)}"</strong>?
</div>`,
'small',
() => this.loadPreset(presetID),
() => this.dialogVisible = false,
);
}
}

private isAlreadyLoading() {
const loadingInProgress = SimVar.GetSimVarValue('L:A32NX_AIRCRAFT_PRESET_LOAD', 'Number');
if (loadingInProgress > 0) {
this.notification.showNotification({
title: 'Aircraft Presets',
message: `Loading Preset is already in progress "${(AircraftPresetsList.getPresetName(loadingInProgress))}"`,
type: NotificationType.Message,
timeout: 1500,
});
return true;
}
return false;
}

private isOneEngineRunning() {
const engine1N1 = SimVar.GetSimVarValue('L:A32NX_ENGINE_N1:1', 'Number');
const engine2N1 = SimVar.GetSimVarValue('L:A32NX_ENGINE_N1:2', 'Number');
return engine1N1 > 0.1 || engine2N1 > 0.1;
}

private loadPreset(presetID: number) {
console.log(`Setting aircraft preset to ${AircraftPresetsList.getPresetName(presetID)}`);
SimVar.SetSimVarValue('L:A32NX_AIRCRAFT_PRESET_LOAD', 'Number', presetID);
this.dialogVisible = false;
}
}
Loading

0 comments on commit d301492

Please sign in to comment.