ZFW Target Set
This commit is contained in:
parent
9224300c85
commit
ee46d0bff1
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "tfdidesign-md11-load-manager",
|
"name": "tfdidesign-md11-load-manager",
|
||||||
"version": "0.1.15",
|
"version": "0.1.17",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@ -1,104 +1,40 @@
|
|||||||
import { FC, StrictMode, useCallback, useEffect, useRef, useState } from 'react';
|
import { FC, StrictMode, useCallback, useEffect, useState } from 'react';
|
||||||
import Freight from './components/freight/Freight';
|
|
||||||
import Pax from './components/pax/Pax';
|
import Pax from './components/pax/Pax';
|
||||||
import { PayloadFreight, calculateCGsFreight, getWeightsFreight } from './configs/freighter';
|
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_LIVE_DATA_EVENT, TFDI_SIMBRIEF_USERNAME_EVENT } from './constants';
|
||||||
import { PaxConfig, PayloadPax } from './configs/pax';
|
import { WASMDataPax } from './types/WASMData';
|
||||||
import { Fuel, getFuel, initialFuel, initialPayload } from './configs/shared';
|
|
||||||
|
|
||||||
interface IAppProps {
|
interface IAppProps {
|
||||||
commBus: ViewListener.ViewListener;
|
commBus: ViewListener.ViewListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
const App: FC<IAppProps> = ({ commBus }) => {
|
const App: FC<IAppProps> = ({ commBus }) => {
|
||||||
// Inferred
|
|
||||||
const [unit, setUnit] = useState<'lbs' | 'kg'>('lbs');
|
|
||||||
const [isCargo, setIsCargo] = useState(false);
|
|
||||||
const [isER, setIsER] = useState(false);
|
|
||||||
const [SBUsername, setSBUsername] = useState<string>();
|
const [SBUsername, setSBUsername] = useState<string>();
|
||||||
|
//FIXME: TS Type
|
||||||
// From sim
|
const [WASMData, setWASMData] = useState<WASMDataPax>();
|
||||||
const [payloadLive, setPayloadLive] = useState<PayloadPax | PayloadFreight>(initialPayload);
|
|
||||||
const [fuel, setFuel] = useState<Fuel>(initialFuel);
|
|
||||||
const [GSXPaxNum, setGSXPaxNum] = useState(0);
|
|
||||||
const [GSXCargoPercent, setGSXCargoPercent] = useState(0);
|
|
||||||
const [GSXState, setGSXState] = useState<'boarding' | 'deboarding' | 'idle'>('idle');
|
|
||||||
|
|
||||||
// Calculated
|
|
||||||
const [CGs, setCGs] = useState<[number, number]>([0, 0]);
|
|
||||||
|
|
||||||
const [isReady, setIsReady] = useState(false);
|
const [isReady, setIsReady] = useState(false);
|
||||||
|
|
||||||
const requestRef = useRef<number | undefined>(undefined);
|
|
||||||
|
|
||||||
// Main Loop for Live Payload
|
// Main Loop for Live Payload
|
||||||
const mainLoop = () => {
|
|
||||||
try {
|
|
||||||
if (SimVar.IsReady()) {
|
|
||||||
setIsER(SimVar.GetSimVarValue('L:MD11_OPT_ER', 'bool'));
|
|
||||||
setIsCargo(SimVar.GetSimVarValue('L:MD11_EFB_IS_CARGO', 'bool'));
|
|
||||||
setUnit((SimVar.GetSimVarValue('L:MD11_EFB_OPTIONS_GENERAL', 'number') & 1) << 0 ? 'lbs' : 'kg');
|
|
||||||
|
|
||||||
// GSX
|
|
||||||
const boardingState = SimVar.GetSimVarValue('L:FSDT_GSX_BOARDING_STATE', 'number');
|
|
||||||
const deboardingState = SimVar.GetSimVarValue('L:FSDT_GSX_DEBOARDING_STATE', 'number');
|
|
||||||
setGSXState(boardingState === 5 ? 'boarding' : deboardingState === 5 ? 'deboarding' : 'idle');
|
|
||||||
setGSXPaxNum(
|
|
||||||
boardingState === 5
|
|
||||||
? SimVar.GetSimVarValue('L:FSDT_GSX_NUMPASSENGERS_BOARDING_TOTAL', 'number')
|
|
||||||
: deboardingState === 5
|
|
||||||
? SimVar.GetSimVarValue('L:FSDT_GSX_NUMPASSENGERS_DEBOARDING_TOTAL', 'number')
|
|
||||||
: 0
|
|
||||||
);
|
|
||||||
setGSXCargoPercent(
|
|
||||||
boardingState === 5
|
|
||||||
? SimVar.GetSimVarValue('L:FSDT_GSX_BOARDING_CARGO_PERCENT', 'number')
|
|
||||||
: deboardingState === 5
|
|
||||||
? 100 - SimVar.GetSimVarValue('L:FSDT_GSX_DEBOARDING_CARGO_PERCENT', 'number')
|
|
||||||
: 0
|
|
||||||
);
|
|
||||||
|
|
||||||
const payload = isCargo ? getWeightsFreight(unit) : PaxConfig.getWeights(unit);
|
|
||||||
const _fuel = getFuel(unit);
|
|
||||||
|
|
||||||
setCGs(
|
|
||||||
isCargo
|
|
||||||
? calculateCGsFreight(payload as PayloadFreight, _fuel)
|
|
||||||
: PaxConfig.calculateCGs(payload as PayloadPax, _fuel)
|
|
||||||
);
|
|
||||||
setPayloadLive(payload);
|
|
||||||
setFuel(_fuel);
|
|
||||||
}
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
requestRef.current = requestAnimationFrame(mainLoop);
|
|
||||||
};
|
|
||||||
useEffect(() => {
|
|
||||||
requestRef.current = requestAnimationFrame(mainLoop);
|
|
||||||
|
|
||||||
if (requestRef.current !== undefined) return () => cancelAnimationFrame(requestRef.current as number);
|
|
||||||
}, [unit, isCargo]);
|
|
||||||
|
|
||||||
// CommBus
|
// CommBus
|
||||||
const usernameCallback = useCallback((username: string) => {
|
const usernameCallback = useCallback((username: string) => {
|
||||||
setSBUsername(username);
|
setSBUsername(username);
|
||||||
setIsReady(true);
|
setIsReady(true);
|
||||||
}, []);
|
}, []);
|
||||||
const wasmCallback = useCallback((data: any) => {
|
const wasmCallback = useCallback((data: string) => {
|
||||||
console.log('WASM DATA', JSON.parse(data));
|
setWASMData(JSON.parse(data));
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('Initializing CommBus');
|
console.log('Initializing CommBus');
|
||||||
|
|
||||||
commBus.on('receiveSimBriefUsername', usernameCallback);
|
commBus.on(COMM_BUS_LIVE_DATA_EVENT, usernameCallback);
|
||||||
commBus.on('khofmann_tfdi_md-11_load_manager_live_data', wasmCallback);
|
commBus.on(COMM_BUS_LIVE_DATA_EVENT, wasmCallback);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Coherent.call('COMM_BUS_WASM_CALLBACK', 'requestSimBriefUsername', 'null');
|
Coherent.call(COHERENT_COMBUS_WASM_CALL, TFDI_SIMBRIEF_USERNAME_EVENT, 'null');
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
commBus.off('receiveSimBriefUsername', usernameCallback);
|
commBus.off('receiveSimBriefUsername', usernameCallback);
|
||||||
commBus.off('khofmann_tfdi_md-11_load_manager_live_data', wasmCallback);
|
commBus.off(COMM_BUS_LIVE_DATA_EVENT, wasmCallback);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -106,21 +42,11 @@ const App: FC<IAppProps> = ({ commBus }) => {
|
|||||||
<StrictMode>
|
<StrictMode>
|
||||||
<div className="flex w-full justify-center pt-2 bg-zinc-900">
|
<div className="flex w-full justify-center pt-2 bg-zinc-900">
|
||||||
<div className="flex w-3/4 flex-col items-center">
|
<div className="flex w-3/4 flex-col items-center">
|
||||||
{isReady ? (
|
{isReady && WASMData ? (
|
||||||
isCargo ? (
|
WASMData.userData.isCargo ? (
|
||||||
<Freight isER={isER} unit={unit} OEW={payloadLive.empty} CGs={CGs} />
|
<>Not yet Implemented</>
|
||||||
) : (
|
) : (
|
||||||
<Pax
|
<Pax WASMData={WASMData} username={SBUsername} />
|
||||||
isER={isER}
|
|
||||||
unit={unit}
|
|
||||||
CGs={CGs}
|
|
||||||
fuelLive={fuel}
|
|
||||||
payloadLive={payloadLive as PayloadPax}
|
|
||||||
username={SBUsername}
|
|
||||||
GSXPaxNum={GSXPaxNum}
|
|
||||||
GSXCargoPercent={GSXCargoPercent}
|
|
||||||
GSXState={GSXState}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<h1 className="text-sm font-medium">LOADING</h1>
|
<h1 className="text-sm font-medium">LOADING</h1>
|
||||||
|
|||||||
@ -1,92 +0,0 @@
|
|||||||
import { FC, useState } from 'react';
|
|
||||||
import { PayloadFreight } from '../../configs/freighter';
|
|
||||||
import { initialPayload, SharedConfig } from '../../configs/shared';
|
|
||||||
import Profile from '../profile/Profile';
|
|
||||||
import Tabbar from '../tabbar/Tabbar';
|
|
||||||
|
|
||||||
interface FreightProps {
|
|
||||||
isER: boolean;
|
|
||||||
unit: 'kg' | 'lbs';
|
|
||||||
OEW: number;
|
|
||||||
CGs: [number, number];
|
|
||||||
}
|
|
||||||
|
|
||||||
const Freight: FC<FreightProps> = ({ isER, unit, OEW, CGs }) => {
|
|
||||||
const [selectedTab, setSelectedTab] = useState(0);
|
|
||||||
const [payload, setPayload] = useState<PayloadFreight>(initialPayload);
|
|
||||||
const [inPreview, setInPreview] = useState(true);
|
|
||||||
|
|
||||||
const upper1 = () => {
|
|
||||||
return Math.round(payload.upper1Left + payload.upper1Right);
|
|
||||||
};
|
|
||||||
const upper2 = () => {
|
|
||||||
return Math.round(payload.upper2Left + payload.upper2Right);
|
|
||||||
};
|
|
||||||
const upper3 = () => {
|
|
||||||
return Math.round(payload.upper3Left + payload.upper3Right);
|
|
||||||
};
|
|
||||||
const upper4 = () => {
|
|
||||||
return Math.round(payload.upper4Left + payload.upper4Right);
|
|
||||||
};
|
|
||||||
const lower1 = () => {
|
|
||||||
return Math.round(payload.lowerForward);
|
|
||||||
};
|
|
||||||
const lower2 = () => {
|
|
||||||
return Math.round(payload.lowerRear);
|
|
||||||
};
|
|
||||||
const _OEW = () => {
|
|
||||||
return Math.round(OEW + (isER ? SharedConfig.erExtraWeight[unit] * 2 : 1));
|
|
||||||
};
|
|
||||||
const crew = () => {
|
|
||||||
return Math.round(payload.pilot + payload.firstOfficer + payload.engineer);
|
|
||||||
};
|
|
||||||
const cgs = (): [string, string] => {
|
|
||||||
return [CGs[0].toFixed(1), CGs[1].toFixed(1)];
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Profile
|
|
||||||
type="F"
|
|
||||||
isER={isER}
|
|
||||||
upper1={`${upper1()}`}
|
|
||||||
upper2={`${upper2()}`}
|
|
||||||
upper3={`${upper3()}`}
|
|
||||||
upper4={`${upper4()}`}
|
|
||||||
lower1={`${lower1()}`}
|
|
||||||
lower2={`${lower2()}`}
|
|
||||||
OEW={`${_OEW()}`}
|
|
||||||
crew={`${crew()}`}
|
|
||||||
unit={unit.toUpperCase()}
|
|
||||||
inPreview={inPreview}
|
|
||||||
CGs={cgs()}
|
|
||||||
/>
|
|
||||||
<Tabbar tabs={['Simbrief', 'ZFW', 'Cargo']} selectedTab={selectedTab} setSelectedTab={setSelectedTab} />
|
|
||||||
|
|
||||||
<div className="relative flex w-full items-center justify-start gap-x-6">
|
|
||||||
<button
|
|
||||||
className="middle none center rounded-lg bg-green-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-green-500/20 transition-all hover:shadow-lg hover:shadow-green-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
|
|
||||||
data-ripple-light="true"
|
|
||||||
onClick={() => {
|
|
||||||
console.log('TODO: SET PAYLOAD IN SIM');
|
|
||||||
setInPreview(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Load
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="middle none center rounded-lg bg-red-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-red-500/20 transition-all hover:shadow-lg hover:shadow-red-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
|
|
||||||
data-ripple-light="true"
|
|
||||||
onClick={() => {
|
|
||||||
console.log('TODO: CLEAR PAYLOAD IN SIM');
|
|
||||||
setInPreview(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Unload
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Freight;
|
|
||||||
@ -1,167 +1,97 @@
|
|||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useState } from 'react';
|
||||||
import { PaxConfig, PayloadPax } from '../../configs/pax';
|
import { WASMDataPax } from '../../types/WASMData';
|
||||||
import { Fuel, initialPayload, SharedConfig } from '../../configs/shared';
|
|
||||||
import Profile from '../profile/Profile';
|
import Profile from '../profile/Profile';
|
||||||
import SBEntryPax from '../SBEntry/SBEntryPax';
|
|
||||||
import StationEntryPax from '../stationEntry/StationEntryPax';
|
|
||||||
import Tabbar from '../tabbar/Tabbar';
|
import Tabbar from '../tabbar/Tabbar';
|
||||||
import ZFWEntryPax from '../zfwEntry/ZFWEntryPax';
|
import ZFWEntryPax from '../zfwEntry/ZFWEntryPax';
|
||||||
|
|
||||||
interface PaxProps {
|
interface PaxProps {
|
||||||
isER: boolean;
|
WASMData: WASMDataPax;
|
||||||
unit: 'kg' | 'lbs';
|
|
||||||
CGs: [number, number];
|
|
||||||
payloadLive: PayloadPax;
|
|
||||||
fuelLive: Fuel;
|
|
||||||
username?: string;
|
username?: string;
|
||||||
GSXPaxNum: number;
|
|
||||||
GSXCargoPercent: number;
|
|
||||||
GSXState: 'boarding' | 'deboarding' | 'idle';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Pax: FC<PaxProps> = ({
|
const Pax: FC<PaxProps> = ({ WASMData, username }) => {
|
||||||
isER,
|
|
||||||
unit,
|
|
||||||
CGs,
|
|
||||||
fuelLive,
|
|
||||||
payloadLive,
|
|
||||||
username,
|
|
||||||
GSXPaxNum,
|
|
||||||
GSXCargoPercent,
|
|
||||||
GSXState,
|
|
||||||
}) => {
|
|
||||||
const [selectedTab, setSelectedTab] = useState(0);
|
const [selectedTab, setSelectedTab] = useState(0);
|
||||||
const [payload, setPayload] = useState<PayloadPax>(initialPayload);
|
|
||||||
const [loadingState, setLoadingState] = useState<'preview' | 'accepted' | 'loaded'>('preview');
|
const [loadingState, setLoadingState] = useState<'preview' | 'accepted' | 'loaded'>('preview');
|
||||||
|
|
||||||
const upper1 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
const upper1 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
||||||
if (overrideState !== 'loaded')
|
if (overrideState !== 'loaded') return WASMData.targetPayload.business1;
|
||||||
return PaxConfig.weightToPax(payload.business1Left + payload.business1Center + payload.business1Right, unit);
|
|
||||||
|
|
||||||
return PaxConfig.weightToPax(
|
return WASMData.livePayload.business1;
|
||||||
payloadLive.business1Left + payloadLive.business1Center + payloadLive.business1Right,
|
|
||||||
unit
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
const upper2 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
const upper2 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
||||||
if (overrideState !== 'loaded')
|
if (overrideState !== 'loaded') return WASMData.targetPayload.business2;
|
||||||
return PaxConfig.weightToPax(payload.business2Left + payload.business2Center + payload.business2Right, unit);
|
|
||||||
|
|
||||||
return PaxConfig.weightToPax(
|
return WASMData.livePayload.business2;
|
||||||
payloadLive.business2Left + payloadLive.business2Center + payloadLive.business2Right,
|
|
||||||
unit
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
const upper3 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
const upper3 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
||||||
if (overrideState !== 'loaded')
|
if (overrideState !== 'loaded') return WASMData.targetPayload.economy1;
|
||||||
return PaxConfig.weightToPax(payload.economy1Left + payload.economy1Center + payload.economy1Right, unit);
|
|
||||||
|
|
||||||
return PaxConfig.weightToPax(
|
return WASMData.livePayload.economy1;
|
||||||
payloadLive.economy1Left + payloadLive.economy1Center + payloadLive.economy1Right,
|
|
||||||
unit
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
const upper4 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
const upper4 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
|
||||||
if (overrideState !== 'loaded')
|
if (overrideState !== 'loaded') return WASMData.targetPayload.economy2;
|
||||||
return PaxConfig.weightToPax(payload.economy2Left + payload.economy2Center + payload.economy2Right, unit);
|
|
||||||
|
|
||||||
return PaxConfig.weightToPax(
|
return WASMData.livePayload.economy2;
|
||||||
payloadLive.economy2Left + payloadLive.economy2Center + payloadLive.economy2Right,
|
|
||||||
unit
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
const lower1 = () => {
|
const lower1 = () => {
|
||||||
if (loadingState !== 'loaded') return Math.round(payload.forwardCargo);
|
if (loadingState !== 'loaded') return Math.round(WASMData.targetPayload.forwardCargo);
|
||||||
|
|
||||||
return Math.round(payloadLive.forwardCargo);
|
return Math.round(WASMData.livePayload.forwardCargo);
|
||||||
};
|
};
|
||||||
const lower2 = () => {
|
const lower2 = () => {
|
||||||
if (loadingState !== 'loaded') return Math.round(payload.rearCargo);
|
if (loadingState !== 'loaded') return Math.round(WASMData.targetPayload.rearCargo);
|
||||||
|
|
||||||
return Math.round(payloadLive.rearCargo);
|
return Math.round(WASMData.livePayload.rearCargo);
|
||||||
};
|
};
|
||||||
const _OEW = () => {
|
const OEW = () => {
|
||||||
if (loadingState !== 'loaded')
|
if (loadingState !== 'loaded') return Math.round(WASMData.targetPayload.empty);
|
||||||
return Math.round(payloadLive.empty + (isER ? SharedConfig.erExtraWeight[unit] * 2 : 1));
|
|
||||||
|
|
||||||
return Math.round(payloadLive.empty + payloadLive.leftAuxPax + payloadLive.rightAuxPax);
|
return Math.round(WASMData.livePayload.empty);
|
||||||
};
|
};
|
||||||
const crew = () => {
|
const crew = () => {
|
||||||
if (loadingState !== 'loaded') return PaxConfig.weights.base[unit].total;
|
if (loadingState !== 'loaded') return Math.round(WASMData.targetPayload.crew);
|
||||||
|
|
||||||
return Math.round(
|
return Math.round(WASMData.livePayload.crew);
|
||||||
payloadLive.cabinCrewFront +
|
|
||||||
payloadLive.cabinCrewRear +
|
|
||||||
payloadLive.pilot +
|
|
||||||
payloadLive.firstOfficer +
|
|
||||||
payloadLive.engineer
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const _CGs = (): [string, boolean, string, boolean] => {
|
const CGs = (): [string, boolean, string, boolean] => {
|
||||||
if (loadingState !== 'loaded') {
|
if (loadingState !== 'loaded') {
|
||||||
const __CGs = PaxConfig.calculateCGs(
|
|
||||||
{
|
|
||||||
...payload,
|
|
||||||
empty: payloadLive.empty,
|
|
||||||
cabinCrewFront: PaxConfig.weights.base[unit].cabinCrewFront,
|
|
||||||
cabinCrewRear: PaxConfig.weights.base[unit].cabinCrewRear,
|
|
||||||
pilot: PaxConfig.weights.base[unit].pilot,
|
|
||||||
firstOfficer: PaxConfig.weights.base[unit].firstOfficer,
|
|
||||||
engineer: PaxConfig.weights.base[unit].engineer,
|
|
||||||
leftAuxPax: isER ? SharedConfig.erExtraWeight[unit] : 0,
|
|
||||||
rightAuxPax: isER ? SharedConfig.erExtraWeight[unit] : 0,
|
|
||||||
},
|
|
||||||
fuelLive
|
|
||||||
);
|
|
||||||
return [
|
return [
|
||||||
__CGs[0].toFixed(1),
|
WASMData.targetPayload.ZFWCG.toFixed(1),
|
||||||
__CGs[0] < SharedConfig.CGLimits.min || __CGs[0] > SharedConfig.CGLimits.max,
|
WASMData.targetPayload.ZFWCG < WASMData.limits.minCG || WASMData.targetPayload.ZFWCG > WASMData.limits.maxCG,
|
||||||
__CGs[1].toFixed(1),
|
WASMData.targetPayload.TOCG.toFixed(1),
|
||||||
__CGs[1] < SharedConfig.CGLimits.min || __CGs[1] > SharedConfig.CGLimits.max,
|
WASMData.targetPayload.TOCG < WASMData.limits.minCG || WASMData.targetPayload.TOCG > WASMData.limits.maxCG,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CGs[0].toFixed(1),
|
WASMData.livePayload.ZFWCG.toFixed(1),
|
||||||
CGs[0] < SharedConfig.CGLimits.min || CGs[0] > SharedConfig.CGLimits.max,
|
WASMData.livePayload.ZFWCG < WASMData.limits.minCG || WASMData.livePayload.ZFWCG > WASMData.limits.maxCG,
|
||||||
CGs[1].toFixed(1),
|
WASMData.livePayload.TOCG.toFixed(1),
|
||||||
CGs[1] < SharedConfig.CGLimits.min || CGs[1] > SharedConfig.CGLimits.max,
|
WASMData.livePayload.TOCG < WASMData.limits.minCG || WASMData.livePayload.TOCG > WASMData.limits.maxCG,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO: Make GSX optional
|
|
||||||
useEffect(() => {
|
|
||||||
if (GSXState === 'idle') return;
|
|
||||||
|
|
||||||
PaxConfig.setWeightsProgressive(
|
|
||||||
payload,
|
|
||||||
GSXState === 'boarding' ? GSXPaxNum : payload.paxCount.total - GSXPaxNum,
|
|
||||||
GSXCargoPercent,
|
|
||||||
unit
|
|
||||||
);
|
|
||||||
}, [GSXPaxNum, GSXCargoPercent, GSXState]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Profile
|
<Profile
|
||||||
type="PAX"
|
type="PAX"
|
||||||
isER={isER}
|
isER={WASMData.userData.isER}
|
||||||
upper1={`${upper1()}`}
|
upper1={`${upper1()}`}
|
||||||
upper1max={loadingState === 'loaded' ? `${upper1('preview')}` : `${PaxConfig.stationMax.business1}`}
|
upper1max={loadingState === 'loaded' ? `${upper1('preview')}` : `${WASMData.limits.business1}`}
|
||||||
upper2={`${upper2()}`}
|
upper2={`${upper2()}`}
|
||||||
upper2max={loadingState === 'loaded' ? `${upper2('preview')}` : `${PaxConfig.stationMax.business2}`}
|
upper2max={loadingState === 'loaded' ? `${upper2('preview')}` : `${WASMData.limits.business2}`}
|
||||||
upper3={`${upper3()}`}
|
upper3={`${upper3()}`}
|
||||||
upper3max={loadingState === 'loaded' ? `${upper3('preview')}` : `${PaxConfig.stationMax.economy1}`}
|
upper3max={loadingState === 'loaded' ? `${upper3('preview')}` : `${WASMData.limits.economy1}`}
|
||||||
upper4={`${upper4()}`}
|
upper4={`${upper4()}`}
|
||||||
upper4max={loadingState === 'loaded' ? `${upper4('preview')}` : `${PaxConfig.stationMax.economy2}`}
|
upper4max={loadingState === 'loaded' ? `${upper4('preview')}` : `${WASMData.limits.economy2}`}
|
||||||
lower1={`${lower1()}`}
|
lower1={`${lower1()}`}
|
||||||
lower2={`${lower2()}`}
|
lower2={`${lower2()}`}
|
||||||
OEW={`${_OEW()}`}
|
OEW={`${OEW()}`}
|
||||||
crew={`${crew()}`}
|
crew={`${crew()}`}
|
||||||
unit={unit.toUpperCase()}
|
unit={WASMData.userData.isImperial ? 'LBS' : 'KG'}
|
||||||
inPreview={loadingState !== 'loaded'}
|
inPreview={loadingState !== 'loaded'}
|
||||||
CGs={_CGs()}
|
CGs={CGs()}
|
||||||
/>
|
/>
|
||||||
<Tabbar
|
<Tabbar
|
||||||
tabs={
|
tabs={
|
||||||
@ -171,6 +101,7 @@ const Pax: FC<PaxProps> = ({
|
|||||||
setSelectedTab={setSelectedTab}
|
setSelectedTab={setSelectedTab}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/*
|
||||||
{username && selectedTab === 0 && (
|
{username && selectedTab === 0 && (
|
||||||
<SBEntryPax
|
<SBEntryPax
|
||||||
unit={unit}
|
unit={unit}
|
||||||
@ -190,26 +121,18 @@ const Pax: FC<PaxProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
*/}
|
||||||
{((username && selectedTab === 1) || (!username && selectedTab === 0)) && (
|
{((username && selectedTab === 1) || (!username && selectedTab === 0)) && (
|
||||||
<ZFWEntryPax
|
<ZFWEntryPax
|
||||||
unit={unit}
|
WASMData={WASMData}
|
||||||
isER={isER}
|
|
||||||
initialPayload={payload}
|
|
||||||
fuelLive={fuelLive}
|
|
||||||
payloadLive={payloadLive}
|
|
||||||
loadingState={loadingState}
|
loadingState={loadingState}
|
||||||
setLoadingState={setLoadingState}
|
setLoadingState={setLoadingState}
|
||||||
updateView={(_payload) => {
|
|
||||||
setPayload(_payload);
|
|
||||||
}}
|
|
||||||
loadAircraft={() => {
|
loadAircraft={() => {
|
||||||
PaxConfig.setBaseWeight(unit, isER);
|
console.log('SET WEIGHT');
|
||||||
PaxConfig.setWeights(payload, unit);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{/*
|
||||||
{((username && selectedTab === 2) || (!username && selectedTab === 1)) && (
|
{((username && selectedTab === 2) || (!username && selectedTab === 1)) && (
|
||||||
<StationEntryPax
|
<StationEntryPax
|
||||||
unit={unit}
|
unit={unit}
|
||||||
@ -228,6 +151,7 @@ const Pax: FC<PaxProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
*/}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,106 +1,36 @@
|
|||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { PaxConfig, PayloadPax } from '../../configs/pax';
|
import { emptyAircraft, SharedConfig } from '../../configs/shared';
|
||||||
import { Fuel, SharedConfig } from '../../configs/shared';
|
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants';
|
||||||
|
import { WASMDataPax } from '../../types/WASMData';
|
||||||
import CGSelect from '../CGSelect/CGSelect';
|
import CGSelect from '../CGSelect/CGSelect';
|
||||||
import ActionBar from '../actionbar/ActionBar';
|
import ActionBar from '../actionbar/ActionBar';
|
||||||
|
|
||||||
interface StationEntryProps {
|
interface StationEntryProps {
|
||||||
unit: 'kg' | 'lbs';
|
WASMData: WASMDataPax;
|
||||||
isER: boolean;
|
|
||||||
initialPayload: PayloadPax;
|
|
||||||
fuelLive: Fuel;
|
|
||||||
payloadLive: PayloadPax;
|
|
||||||
loadingState: 'preview' | 'accepted' | 'loaded';
|
loadingState: 'preview' | 'accepted' | 'loaded';
|
||||||
setLoadingState: (newState: StationEntryProps['loadingState']) => void;
|
setLoadingState: (newState: StationEntryProps['loadingState']) => void;
|
||||||
updateView: (payload: PayloadPax) => void;
|
|
||||||
loadAircraft: () => void;
|
loadAircraft: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ZFWEntryPax: FC<StationEntryProps> = ({
|
const ZFWEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoadingState, loadAircraft }) => {
|
||||||
unit,
|
const [targetZFWCG, setTargetZFWCG] = useState(WASMData.targetPayload.ZFWCG);
|
||||||
isER,
|
const [fuel, setFuel] = useState(Math.round(WASMData.livePayload.fuel));
|
||||||
initialPayload,
|
const [ZFW, setZFW] = useState(Math.round(Math.max(WASMData.limits.minZFW, WASMData.targetPayload.total)));
|
||||||
fuelLive,
|
|
||||||
payloadLive,
|
|
||||||
loadingState,
|
|
||||||
setLoadingState,
|
|
||||||
updateView,
|
|
||||||
loadAircraft,
|
|
||||||
}) => {
|
|
||||||
const [targetZFWCG, setTargetZFWCG] = useState(SharedConfig.CGLimits.default);
|
|
||||||
const [fuel, setFuel] = useState(
|
|
||||||
Math.round(
|
|
||||||
fuelLive.main1 +
|
|
||||||
fuelLive.main1Tip +
|
|
||||||
fuelLive.main2 +
|
|
||||||
fuelLive.main3 +
|
|
||||||
fuelLive.main3Tip +
|
|
||||||
fuelLive.upperAux +
|
|
||||||
fuelLive.lowerAux +
|
|
||||||
fuelLive.tail +
|
|
||||||
fuelLive.forwardAux1 +
|
|
||||||
fuelLive.forwardAux2
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const [ZFW, setZFW] = useState(
|
|
||||||
Math.round(
|
|
||||||
PaxConfig.weights.base[unit].total +
|
|
||||||
(isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) +
|
|
||||||
payloadLive.empty +
|
|
||||||
initialPayload.business1Left +
|
|
||||||
initialPayload.business1Center +
|
|
||||||
initialPayload.business1Right +
|
|
||||||
initialPayload.business2Left +
|
|
||||||
initialPayload.business2Center +
|
|
||||||
initialPayload.business2Right +
|
|
||||||
initialPayload.economy1Left +
|
|
||||||
initialPayload.economy1Center +
|
|
||||||
initialPayload.economy1Right +
|
|
||||||
initialPayload.economy2Left +
|
|
||||||
initialPayload.economy2Center +
|
|
||||||
initialPayload.economy2Right +
|
|
||||||
initialPayload.forwardCargo +
|
|
||||||
initialPayload.rearCargo
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const _ZFW = () => {
|
const _ZFW = () => {
|
||||||
if (loadingState !== 'loaded') return ZFW;
|
if (loadingState !== 'loaded') return ZFW;
|
||||||
|
|
||||||
return Math.round(
|
return Math.round(WASMData.livePayload.total);
|
||||||
payloadLive.empty +
|
|
||||||
payloadLive.pilot +
|
|
||||||
payloadLive.firstOfficer +
|
|
||||||
payloadLive.engineer +
|
|
||||||
payloadLive.cabinCrewFront +
|
|
||||||
payloadLive.business1Left +
|
|
||||||
payloadLive.business1Center +
|
|
||||||
payloadLive.business1Right +
|
|
||||||
payloadLive.business2Left +
|
|
||||||
payloadLive.business2Center +
|
|
||||||
payloadLive.business2Right +
|
|
||||||
payloadLive.economy1Left +
|
|
||||||
payloadLive.economy1Center +
|
|
||||||
payloadLive.economy1Right +
|
|
||||||
payloadLive.economy2Left +
|
|
||||||
payloadLive.economy2Center +
|
|
||||||
payloadLive.economy2Right +
|
|
||||||
payloadLive.cabinCrewRear +
|
|
||||||
payloadLive.forwardCargo +
|
|
||||||
payloadLive.rearCargo +
|
|
||||||
payloadLive.leftAuxPax +
|
|
||||||
payloadLive.rightAuxPax
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
const ZFWValid = () => {
|
const ZFWValid = () => {
|
||||||
return _ZFW() <= PaxConfig.maxZWF[unit];
|
return _ZFW() <= WASMData.limits.maxZFW;
|
||||||
};
|
};
|
||||||
|
|
||||||
const GW = () => {
|
const GW = () => {
|
||||||
return fuel + _ZFW();
|
return fuel + _ZFW();
|
||||||
};
|
};
|
||||||
const GWValid = () => {
|
const GWValid = () => {
|
||||||
return GW() <= (isER ? SharedConfig.maxTOW.er[unit] : SharedConfig.maxTOW.norm[unit]);
|
return GW() <= WASMData.limits.maxTOW;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleInput = (input: string, maxValue: number, setter: (value: number) => void) => {
|
const handleInput = (input: string, maxValue: number, setter: (value: number) => void) => {
|
||||||
@ -121,20 +51,13 @@ const ZFWEntryPax: FC<StationEntryProps> = ({
|
|||||||
|
|
||||||
const converted = parseInt(input);
|
const converted = parseInt(input);
|
||||||
if (converted) {
|
if (converted) {
|
||||||
if (converted < 0)
|
if (converted < 0) setZFW(Math.round(WASMData.targetPayload.empty + WASMData.targetPayload.crew));
|
||||||
setZFW(
|
else if (converted > WASMData.limits.maxZFW) setZFW(WASMData.limits.maxZFW);
|
||||||
Math.round(
|
|
||||||
PaxConfig.weights.base[unit].total + (isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) + payloadLive.empty
|
|
||||||
)
|
|
||||||
);
|
|
||||||
else if (converted > PaxConfig.maxZWF[unit]) setZFW(PaxConfig.maxZWF[unit]);
|
|
||||||
else setZFW(converted);
|
else setZFW(converted);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleBlur = (input: string) => {
|
const handleBlur = (input: string) => {
|
||||||
const minZFW = Math.round(
|
const minZFW = Math.round(WASMData.targetPayload.empty + WASMData.targetPayload.crew);
|
||||||
PaxConfig.weights.base[unit].total + (isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) + payloadLive.empty
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!input) {
|
if (!input) {
|
||||||
setZFW(minZFW);
|
setZFW(minZFW);
|
||||||
@ -144,30 +67,39 @@ const ZFWEntryPax: FC<StationEntryProps> = ({
|
|||||||
const converted = parseInt(input);
|
const converted = parseInt(input);
|
||||||
if (converted) {
|
if (converted) {
|
||||||
if (converted < minZFW) setZFW(minZFW);
|
if (converted < minZFW) setZFW(minZFW);
|
||||||
else if (converted > PaxConfig.maxZWF[unit]) setZFW(PaxConfig.maxZWF[unit]);
|
else if (converted > WASMData.limits.maxZFW) setZFW(WASMData.limits.maxZFW);
|
||||||
else setZFW(converted);
|
else setZFW(converted);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateView(PaxConfig.distribute(converted, targetZFWCG, payloadLive.empty, fuelLive, unit, isER));
|
updateData(converted);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() =>
|
() =>
|
||||||
setFuel((prev) =>
|
setFuel((prev) => {
|
||||||
prev > (isER ? SharedConfig.maxFuel.er[unit] : SharedConfig.maxFuel.norm[unit])
|
if (prev > WASMData.limits.maxFuel) return WASMData.limits.maxFuel;
|
||||||
? isER
|
return prev;
|
||||||
? SharedConfig.maxFuel.er[unit]
|
}),
|
||||||
: SharedConfig.maxFuel.norm[unit]
|
[WASMData.userData.isER]
|
||||||
: prev
|
|
||||||
),
|
|
||||||
[isER]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updateData = (ZFWTarget?: number, CGTarget?: number) => {
|
||||||
|
Coherent.call(
|
||||||
|
COHERENT_COMBUS_WASM_CALL,
|
||||||
|
COMM_BUS_UPDATE_TARGET_EVENT,
|
||||||
|
JSON.stringify({
|
||||||
|
mode: 1,
|
||||||
|
ZFWTarget: ZFWTarget ?? ZFW,
|
||||||
|
CGTarget: CGTarget ?? targetZFWCG,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
|
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
|
||||||
<div className="relative flex w-full items-center justify-between rounded-t-md bg-zinc-600 p-2 px-4">
|
<div className="relative flex w-full items-center justify-between rounded-t-md bg-zinc-600 p-2 px-4">
|
||||||
<label>Target ZFW ({unit})</label>
|
<label>Target ZFW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
@ -188,14 +120,14 @@ const ZFWEntryPax: FC<StationEntryProps> = ({
|
|||||||
increase={() =>
|
increase={() =>
|
||||||
setTargetZFWCG((prev) => {
|
setTargetZFWCG((prev) => {
|
||||||
const _new = prev + 0.1;
|
const _new = prev + 0.1;
|
||||||
updateView(PaxConfig.distribute(ZFW, _new, payloadLive.empty, fuelLive, unit, isER));
|
updateData(undefined, _new);
|
||||||
return _new;
|
return _new;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
decrease={() =>
|
decrease={() =>
|
||||||
setTargetZFWCG((prev) => {
|
setTargetZFWCG((prev) => {
|
||||||
const _new = prev - 0.1;
|
const _new = prev - 0.1;
|
||||||
updateView(PaxConfig.distribute(ZFW, _new, payloadLive.empty, fuelLive, unit, isER));
|
updateData(undefined, _new);
|
||||||
return _new;
|
return _new;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -205,29 +137,27 @@ const ZFWEntryPax: FC<StationEntryProps> = ({
|
|||||||
|
|
||||||
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
|
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
|
||||||
<div className="relative flex w-full items-center justify-between rounded-md bg-zinc-600 p-2 px-4">
|
<div className="relative flex w-full items-center justify-between rounded-md bg-zinc-600 p-2 px-4">
|
||||||
<label>Fuel ({unit})</label>
|
<label>Fuel ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
className={`w-1/2 rounded-lg border border-white bg-zinc-700 px-3 py-2 text-right`}
|
className={`w-1/2 rounded-lg border border-white bg-zinc-700 px-3 py-2 text-right`}
|
||||||
value={fuel}
|
value={fuel}
|
||||||
onChange={(e) =>
|
onChange={(e) => handleInput(e.target.value, WASMData.limits.maxFuel, setFuel)}
|
||||||
handleInput(
|
|
||||||
e.target.value,
|
|
||||||
isER ? SharedConfig.maxFuel.er[unit] : SharedConfig.maxFuel.norm[unit],
|
|
||||||
setFuel
|
|
||||||
)
|
|
||||||
}
|
|
||||||
disabled={loadingState !== 'preview'}
|
disabled={loadingState !== 'preview'}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
className="middle none center rounded-lg bg-green-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-green-500/20 transition-all hover:shadow-lg hover:shadow-green-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
|
className="middle none center rounded-lg bg-green-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-green-500/20 transition-all hover:shadow-lg hover:shadow-green-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
|
||||||
data-ripple-light="true"
|
data-ripple-light="true"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
SimVar.SetSimVarValue('L:MD11_EFB_PAYLOAD_FUEL', 'lbs', unit === 'kg' ? fuel * 2.20462262185 : fuel);
|
SimVar.SetSimVarValue(
|
||||||
|
'L:MD11_EFB_PAYLOAD_FUEL',
|
||||||
|
'lbs',
|
||||||
|
WASMData.userData.isImperial ? fuel : fuel * 2.20462262185
|
||||||
|
);
|
||||||
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
|
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
|
||||||
}}
|
}}
|
||||||
disabled={loadingState !== 'preview'}
|
disabled={loadingState !== 'preview' || fuel === Math.round(WASMData.livePayload.fuel)}
|
||||||
>
|
>
|
||||||
Load Fuel
|
Load Fuel
|
||||||
</button>
|
</button>
|
||||||
@ -237,7 +167,7 @@ const ZFWEntryPax: FC<StationEntryProps> = ({
|
|||||||
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
|
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
|
||||||
<div className="relative flex w-full items-center justify-between rounded-t-md bg-zinc-600 p-2 px-4">
|
<div className="relative flex w-full items-center justify-between rounded-t-md bg-zinc-600 p-2 px-4">
|
||||||
<label>
|
<label>
|
||||||
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} ZFW ({unit})
|
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} ZFW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@ -249,7 +179,7 @@ const ZFWEntryPax: FC<StationEntryProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 p-2 px-4">
|
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 p-2 px-4">
|
||||||
<label>
|
<label>
|
||||||
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} GW ({unit})
|
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} GW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@ -274,7 +204,7 @@ const ZFWEntryPax: FC<StationEntryProps> = ({
|
|||||||
unload={() => {
|
unload={() => {
|
||||||
setLoadingState('preview');
|
setLoadingState('preview');
|
||||||
|
|
||||||
PaxConfig.unload(unit, isER);
|
emptyAircraft();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_LIVE_DATA_EVENT } from '../constants';
|
||||||
|
|
||||||
export interface Fuel {
|
export interface Fuel {
|
||||||
main1: number;
|
main1: number;
|
||||||
main3: number;
|
main3: number;
|
||||||
@ -164,3 +166,13 @@ export const getFuel = (unit: 'kg' | 'lbs') => {
|
|||||||
|
|
||||||
return fuel;
|
return fuel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const emptyAircraft = () => {
|
||||||
|
Coherent.call(
|
||||||
|
COHERENT_COMBUS_WASM_CALL,
|
||||||
|
COMM_BUS_LIVE_DATA_EVENT,
|
||||||
|
JSON.stringify({
|
||||||
|
mode: 3,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
export const COMMANDS = 'KHOFMANN_PDF_READER_COMMANDS';
|
export const COHERENT_COMBUS_WASM_CALL = 'COMM_BUS_WASM_CALLBACK';
|
||||||
export const DATA = 'KHOFMANN_PDF_READER_DATA';
|
export const TFDI_SIMBRIEF_USERNAME_EVENT = 'requestSimBriefUsername';
|
||||||
export const LIST = 'LIST';
|
export const COMM_BUS_LIVE_DATA_EVENT = 'khofmann_tfdi_md-11_load_manager_live_data';
|
||||||
export const LOAD = 'LOAD';
|
export const COMM_BUS_UPDATE_TARGET_EVENT = 'khofmann_tfdi_md-11_load_manager_update_target';
|
||||||
export const SAVE = 'SAVE';
|
|
||||||
export const MAX_LIST = 10;
|
|
||||||
|
|||||||
85
PackageSources/js-bundle/src/types/WASMData.d.ts
vendored
Normal file
85
PackageSources/js-bundle/src/types/WASMData.d.ts
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
export interface WASMDataPax {
|
||||||
|
livePayload: LivePayloadPax;
|
||||||
|
targetPayload: TargetPayloadPax;
|
||||||
|
GSX: GSX;
|
||||||
|
userData: UserData;
|
||||||
|
limits: LimitsPax;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TargetPayloadPax {
|
||||||
|
empty: number;
|
||||||
|
crew: number;
|
||||||
|
business1: number;
|
||||||
|
business2: number;
|
||||||
|
economy1: number;
|
||||||
|
economy2: number;
|
||||||
|
forwardCargo: number;
|
||||||
|
rearCargo: number;
|
||||||
|
ZFWCG: number;
|
||||||
|
TOCG: number;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LivePayloadPax extends TargetPayloadPax {
|
||||||
|
fuel: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TargetPayloadF {
|
||||||
|
empty: number;
|
||||||
|
crew: number;
|
||||||
|
upper1: number;
|
||||||
|
upper2: number;
|
||||||
|
upper3: number;
|
||||||
|
upper4: number;
|
||||||
|
lowerForward: number;
|
||||||
|
lowerRear: number;
|
||||||
|
ZFWCG: number;
|
||||||
|
TOCG: number;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LivePayloadF extends TargetPayloadF {
|
||||||
|
fuel: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GSX {
|
||||||
|
boardingState: number;
|
||||||
|
deboardingState: number;
|
||||||
|
passengersBoarded: number;
|
||||||
|
passengersDeboarded: number;
|
||||||
|
cargoBoarded: number;
|
||||||
|
cargoDeboarded: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Limits {
|
||||||
|
minCG: number;
|
||||||
|
maxCG: number;
|
||||||
|
maxFuel: number;
|
||||||
|
maxTOW: number;
|
||||||
|
maxZFW: number;
|
||||||
|
minZFW: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LimitsPax extends Limits {
|
||||||
|
business1: number;
|
||||||
|
business2: number;
|
||||||
|
economy1: number;
|
||||||
|
economy2: number;
|
||||||
|
forwardCargo: number;
|
||||||
|
rearCargo: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LimitsF extends Limits {
|
||||||
|
upper1: number;
|
||||||
|
upper2: number;
|
||||||
|
upper3: number;
|
||||||
|
upper4: number;
|
||||||
|
lowerForward: number;
|
||||||
|
lowerRear: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserData {
|
||||||
|
isCargo: boolean;
|
||||||
|
isER: boolean;
|
||||||
|
isImperial: boolean;
|
||||||
|
}
|
||||||
@ -15,7 +15,7 @@ FuelData_t* liveFuelData;
|
|||||||
bool commBusCallbackRegistered;
|
bool commBusCallbackRegistered;
|
||||||
HANDLE simConnect;
|
HANDLE simConnect;
|
||||||
FILE* logFile;
|
FILE* logFile;
|
||||||
char sendTimer = 0;
|
MODULE_VAR tick18 = { TICK18 };
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
extern "C" MSFS_CALLBACK void module_init(void) {
|
extern "C" MSFS_CALLBACK void module_init(void) {
|
||||||
@ -35,6 +35,8 @@ extern "C" MSFS_CALLBACK void module_init(void) {
|
|||||||
targetFPayloadData = new fPayloadData_t();
|
targetFPayloadData = new fPayloadData_t();
|
||||||
liveFuelData = new FuelData_t();
|
liveFuelData = new FuelData_t();
|
||||||
|
|
||||||
|
targetFPayloadData->ZFWCG = targetPaxPayloadData->ZFWCG = 21;
|
||||||
|
|
||||||
#pragma region SimConnect
|
#pragma region SimConnect
|
||||||
|
|
||||||
// SimConnect open
|
// SimConnect open
|
||||||
@ -414,15 +416,15 @@ extern "C" MSFS_CALLBACK void module_deinit(void) {
|
|||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
extern "C" MSFS_CALLBACK bool Load_Manager_gauge_callback(FsContext ctx, int service_id, void* pData) {
|
extern "C" MSFS_CALLBACK bool Load_Manager_gauge_callback(FsContext ctx, int service_id, void* pData) {
|
||||||
/*
|
|
||||||
switch (service_id) {
|
switch (service_id) {
|
||||||
case PANEL_SERVICE_PRE_UPDATE: {
|
case PANEL_SERVICE_PRE_UPDATE: {
|
||||||
|
lookup_var(&tick18);
|
||||||
|
if (fmod(tick18.var_value.n, 3) == 0) sendData();
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,6 +433,8 @@ void commBusUpdateTargetCallback(const char* args, unsigned int size, void* ctx)
|
|||||||
printf("Target payload update request: %d", receiveData(args));
|
printf("Target payload update request: %d", receiveData(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma region JSON data handling
|
||||||
|
|
||||||
// JSON receive
|
// JSON receive
|
||||||
int receiveData(const char* buf) {
|
int receiveData(const char* buf) {
|
||||||
if (liveFPayloadData == nullptr || livePaxPayloadData == nullptr || targetFPayloadData == nullptr || targetPaxPayloadData == nullptr ||
|
if (liveFPayloadData == nullptr || livePaxPayloadData == nullptr || targetFPayloadData == nullptr || targetPaxPayloadData == nullptr ||
|
||||||
@ -440,20 +444,6 @@ int receiveData(const char* buf) {
|
|||||||
document.Parse(buf);
|
document.Parse(buf);
|
||||||
if (document.HasParseError()) return document.GetParseError();
|
if (document.HasParseError()) return document.GetParseError();
|
||||||
|
|
||||||
// Shared part 1
|
|
||||||
targetFPayloadData->empty = targetPaxPayloadData->empty = FROM_POUNDS(UserData->isImperial, liveFPayloadData->empty);
|
|
||||||
targetFPayloadData->pilot = targetPaxPayloadData->pilot = PILOT_WEIGHT(UserData->isImperial);
|
|
||||||
targetFPayloadData->firstOfficer = targetPaxPayloadData->firstOfficer = PILOT_WEIGHT(UserData->isImperial);
|
|
||||||
targetFPayloadData->engineer = targetPaxPayloadData->engineer = PILOT_WEIGHT(UserData->isImperial);
|
|
||||||
// Shared part 2
|
|
||||||
targetFPayloadData->leftAux = targetPaxPayloadData->leftAux = UserData->isER ? AUX_WEIGHT(UserData->isImperial) : 0;
|
|
||||||
targetFPayloadData->rightAux = targetPaxPayloadData->rightAux = UserData->isER ? AUX_WEIGHT(UserData->isImperial) : 0;
|
|
||||||
// Pax only fixed weights
|
|
||||||
if (!UserData->isCargo) {
|
|
||||||
targetPaxPayloadData->cabinCrewFront = FRONT_CREW_WEIGHT(UserData->isImperial);
|
|
||||||
targetPaxPayloadData->cabinCrewRear = REAR_CREW_WEIGHT(UserData->isImperial);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.HasMember("mode")) {
|
if (document.HasMember("mode")) {
|
||||||
int mode = document["mode"].GetUint();
|
int mode = document["mode"].GetUint();
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
@ -512,6 +502,7 @@ int receiveData(const char* buf) {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
sendData();
|
||||||
}
|
}
|
||||||
else return -1;
|
else return -1;
|
||||||
|
|
||||||
@ -533,6 +524,10 @@ void sendData () {
|
|||||||
targetPayload.SetObject();
|
targetPayload.SetObject();
|
||||||
rapidjson::Value GSX;
|
rapidjson::Value GSX;
|
||||||
GSX.SetObject();
|
GSX.SetObject();
|
||||||
|
rapidjson::Value userData;
|
||||||
|
userData.SetObject();
|
||||||
|
rapidjson::Value limits;
|
||||||
|
limits.SetObject();
|
||||||
|
|
||||||
rapidjson::StringBuffer strbuf;
|
rapidjson::StringBuffer strbuf;
|
||||||
rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
|
rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
|
||||||
@ -558,6 +553,12 @@ void sendData () {
|
|||||||
livePayload.AddMember("upper4", FROM_POUNDS(UserData->isImperial, liveFPayloadData->upper4Left + liveFPayloadData->upper4Right), allocator);
|
livePayload.AddMember("upper4", FROM_POUNDS(UserData->isImperial, liveFPayloadData->upper4Left + liveFPayloadData->upper4Right), allocator);
|
||||||
livePayload.AddMember("lowerForward", FROM_POUNDS(UserData->isImperial, liveFPayloadData->lowerForward), allocator);
|
livePayload.AddMember("lowerForward", FROM_POUNDS(UserData->isImperial, liveFPayloadData->lowerForward), allocator);
|
||||||
livePayload.AddMember("lowerRear", FROM_POUNDS(UserData->isImperial, liveFPayloadData->lowerRear), allocator);
|
livePayload.AddMember("lowerRear", FROM_POUNDS(UserData->isImperial, liveFPayloadData->lowerRear), allocator);
|
||||||
|
livePayload.AddMember("total", FROM_POUNDS(UserData->isImperial, liveFPayloadData->total), allocator);
|
||||||
|
// CGs
|
||||||
|
//TODO: Enable for F
|
||||||
|
//calculateCGs(liveFPayloadData, liveFuelData, &liveFPayloadData->ZFWCG, &liveFPayloadData->TOCG, true);
|
||||||
|
targetPayload.AddMember("ZFWCG", liveFPayloadData->ZFWCG, allocator);
|
||||||
|
targetPayload.AddMember("TOCG", liveFPayloadData->TOCG, allocator);
|
||||||
}
|
}
|
||||||
// Pax only (converted to passengers)
|
// Pax only (converted to passengers)
|
||||||
else {
|
else {
|
||||||
@ -566,7 +567,7 @@ void sendData () {
|
|||||||
FROM_POUNDS(UserData->isImperial, livePaxPayloadData->engineer) + FROM_POUNDS(UserData->isImperial, livePaxPayloadData->cabinCrewFront) +
|
FROM_POUNDS(UserData->isImperial, livePaxPayloadData->engineer) + FROM_POUNDS(UserData->isImperial, livePaxPayloadData->cabinCrewFront) +
|
||||||
FROM_POUNDS(UserData->isImperial, livePaxPayloadData->cabinCrewRear),
|
FROM_POUNDS(UserData->isImperial, livePaxPayloadData->cabinCrewRear),
|
||||||
allocator);
|
allocator);
|
||||||
livePayload.AddMember("businnes1",
|
livePayload.AddMember("business1",
|
||||||
(short)(FROM_POUNDS(UserData->isImperial, livePaxPayloadData->business1Left + livePaxPayloadData->business1Center +
|
(short)(FROM_POUNDS(UserData->isImperial, livePaxPayloadData->business1Left + livePaxPayloadData->business1Center +
|
||||||
livePaxPayloadData->business1Right) / PAX_WEIGHT(UserData->isImperial)),
|
livePaxPayloadData->business1Right) / PAX_WEIGHT(UserData->isImperial)),
|
||||||
allocator);
|
allocator);
|
||||||
@ -584,11 +585,12 @@ void sendData () {
|
|||||||
allocator);
|
allocator);
|
||||||
livePayload.AddMember("forwardCargo", FROM_POUNDS(UserData->isImperial, livePaxPayloadData->forwardCargo), allocator);
|
livePayload.AddMember("forwardCargo", FROM_POUNDS(UserData->isImperial, livePaxPayloadData->forwardCargo), allocator);
|
||||||
livePayload.AddMember("rearCargo", FROM_POUNDS(UserData->isImperial, livePaxPayloadData->rearCargo), allocator);
|
livePayload.AddMember("rearCargo", FROM_POUNDS(UserData->isImperial, livePaxPayloadData->rearCargo), allocator);
|
||||||
|
livePayload.AddMember("total", FROM_POUNDS(UserData->isImperial, livePaxPayloadData->total), allocator);
|
||||||
|
// CGs
|
||||||
|
calculateCGs(livePaxPayloadData, liveFuelData, &livePaxPayloadData->ZFWCG, &livePaxPayloadData->TOCG, true);
|
||||||
|
livePayload.AddMember("ZFWCG",livePaxPayloadData->ZFWCG, allocator);
|
||||||
|
livePayload.AddMember("TOCG", livePaxPayloadData->TOCG, allocator);
|
||||||
}
|
}
|
||||||
// CGs
|
|
||||||
calculateCGs(livePaxPayloadData, liveFuelData, &livePaxPayloadData->ZFWCG, &livePaxPayloadData->TOCG, true);
|
|
||||||
livePayload.AddMember("ZFWCG", UserData->isCargo ? liveFPayloadData->ZFWCG : livePaxPayloadData->ZFWCG, allocator);
|
|
||||||
livePayload.AddMember("TOCG", UserData->isCargo ? liveFPayloadData->ZFWCG : livePaxPayloadData->TOCG, allocator);
|
|
||||||
// Fuel
|
// Fuel
|
||||||
livePayload.AddMember("fuel", FROM_POUNDS(UserData->isImperial, liveFuelData->total), allocator);
|
livePayload.AddMember("fuel", FROM_POUNDS(UserData->isImperial, liveFuelData->total), allocator);
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
@ -610,6 +612,12 @@ void sendData () {
|
|||||||
targetPayload.AddMember("upper4", targetFPayloadData->upper4Left + targetFPayloadData->upper4Right, allocator);
|
targetPayload.AddMember("upper4", targetFPayloadData->upper4Left + targetFPayloadData->upper4Right, allocator);
|
||||||
targetPayload.AddMember("lowerForward", targetFPayloadData->lowerForward, allocator);
|
targetPayload.AddMember("lowerForward", targetFPayloadData->lowerForward, allocator);
|
||||||
targetPayload.AddMember("lowerRear", targetFPayloadData->lowerRear, allocator);
|
targetPayload.AddMember("lowerRear", targetFPayloadData->lowerRear, allocator);
|
||||||
|
targetPayload.AddMember("total", targetFPayloadData->total, allocator);
|
||||||
|
// CGs
|
||||||
|
//TODO: Enable for F
|
||||||
|
//calculateCGs(targetFPayloadData, liveFuelData, &targetFPayloadData->ZFWCG, &targetFPayloadData->TOCG, UserData->isImperial);
|
||||||
|
targetPayload.AddMember("ZFWCG", targetFPayloadData->ZFWCG, allocator);
|
||||||
|
targetPayload.AddMember("TOCG", targetFPayloadData->TOCG, allocator);
|
||||||
}
|
}
|
||||||
// Pax only (converted to passengers)
|
// Pax only (converted to passengers)
|
||||||
else {
|
else {
|
||||||
@ -617,16 +625,18 @@ void sendData () {
|
|||||||
targetPaxPayloadData->pilot + targetPaxPayloadData->firstOfficer + targetPaxPayloadData->engineer +
|
targetPaxPayloadData->pilot + targetPaxPayloadData->firstOfficer + targetPaxPayloadData->engineer +
|
||||||
targetPaxPayloadData->cabinCrewFront + targetPaxPayloadData->cabinCrewRear,
|
targetPaxPayloadData->cabinCrewFront + targetPaxPayloadData->cabinCrewRear,
|
||||||
allocator);
|
allocator);
|
||||||
targetPayload.AddMember("businnes1", targetPaxPayloadData->paxCount.business1, allocator);
|
targetPayload.AddMember("business1", targetPaxPayloadData->paxCount.business1, allocator);
|
||||||
targetPayload.AddMember("business2", targetPaxPayloadData->paxCount.business2, allocator);
|
targetPayload.AddMember("business2", targetPaxPayloadData->paxCount.business2, allocator);
|
||||||
targetPayload.AddMember("economy1", targetPaxPayloadData->paxCount.economy1, allocator);
|
targetPayload.AddMember("economy1", targetPaxPayloadData->paxCount.economy1, allocator);
|
||||||
targetPayload.AddMember("economy2", targetPaxPayloadData->paxCount.economy2, allocator);
|
targetPayload.AddMember("economy2", targetPaxPayloadData->paxCount.economy2, allocator);
|
||||||
targetPayload.AddMember("forwardCargo", targetPaxPayloadData->forwardCargo, allocator);
|
targetPayload.AddMember("forwardCargo", targetPaxPayloadData->forwardCargo, allocator);
|
||||||
targetPayload.AddMember("rearCargo", targetPaxPayloadData->rearCargo, allocator);
|
targetPayload.AddMember("rearCargo", targetPaxPayloadData->rearCargo, allocator);
|
||||||
|
targetPayload.AddMember("total", targetPaxPayloadData->total, allocator);
|
||||||
|
// CGs
|
||||||
|
calculateCGs(targetPaxPayloadData, liveFuelData, &targetPaxPayloadData->ZFWCG, &targetPaxPayloadData->TOCG, UserData->isImperial);
|
||||||
|
targetPayload.AddMember("ZFWCG", targetPaxPayloadData->ZFWCG, allocator);
|
||||||
|
targetPayload.AddMember("TOCG", targetPaxPayloadData->TOCG, allocator);
|
||||||
}
|
}
|
||||||
// CGs
|
|
||||||
targetPayload.AddMember("ZFWCG", UserData->isCargo ? targetFPayloadData->ZFWCG : targetPaxPayloadData->ZFWCG, allocator);
|
|
||||||
targetPayload.AddMember("TOCG", UserData->isCargo ? targetFPayloadData->TOCG : targetPaxPayloadData->TOCG, allocator);
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
@ -639,10 +649,47 @@ void sendData () {
|
|||||||
GSX.AddMember("cargoBoarded", GSXData->cargoBoarded, allocator);
|
GSX.AddMember("cargoBoarded", GSXData->cargoBoarded, allocator);
|
||||||
GSX.AddMember("cargoDeboarded", GSXData->cargoDeboarded, allocator);
|
GSX.AddMember("cargoDeboarded", GSXData->cargoDeboarded, allocator);
|
||||||
|
|
||||||
|
// User Data
|
||||||
|
userData.AddMember<bool>("isCargo", UserData->isCargo, allocator);
|
||||||
|
userData.AddMember<bool>("isER", UserData->isER, allocator);
|
||||||
|
userData.AddMember<bool>("isImperial", UserData->isImperial, allocator);
|
||||||
|
|
||||||
|
// Limits
|
||||||
|
limits.AddMember("minCG", MIN_CG, allocator);
|
||||||
|
limits.AddMember("maxCG", MAX_CG, allocator);
|
||||||
|
limits.AddMember("maxFuel", UserData->isER ? MAX_FUEL_ER(UserData->isImperial) : MAX_FUEL(UserData->isImperial), allocator);
|
||||||
|
limits.AddMember("maxTOW", UserData->isER ? MAX_TOW_ER(UserData->isImperial) : MAX_TOW(UserData->isImperial), allocator);
|
||||||
|
// Cargo Only
|
||||||
|
// TODO: Actual F limits
|
||||||
|
if (UserData->isCargo) {
|
||||||
|
limits.AddMember("upper1", -1, allocator);
|
||||||
|
limits.AddMember("upper2", -1, allocator);
|
||||||
|
limits.AddMember("upper3", -1, allocator);
|
||||||
|
limits.AddMember("upper4", -1, allocator);
|
||||||
|
limits.AddMember("lowerForward", MAX_FRONT_CARGO(UserData->isImperial), allocator);
|
||||||
|
limits.AddMember("lowerRear", MAX_REAR_CARGO(UserData->isImperial), allocator);
|
||||||
|
// TODO: Actual F limit
|
||||||
|
//limits.AddMember("MaxZFW", MAX_F_ZFW, allocator);
|
||||||
|
limits.AddMember("minZFW", targetFPayloadData->empty + targetFPayloadData->leftAux + targetFPayloadData->rightAux, allocator);
|
||||||
|
}
|
||||||
|
// Pax only
|
||||||
|
else {
|
||||||
|
limits.AddMember("business1", MAX_BUSINESS_1, allocator);
|
||||||
|
limits.AddMember("business2", MAX_BUSINESS_2, allocator);
|
||||||
|
limits.AddMember("economy1", MAX_ECONOMY_1, allocator);
|
||||||
|
limits.AddMember("economy2", MAX_ECONOMY_2, allocator);
|
||||||
|
limits.AddMember("forwardCargo", MAX_FRONT_CARGO(UserData->isImperial), allocator);
|
||||||
|
limits.AddMember("rearCargo", MAX_REAR_CARGO(UserData->isImperial), allocator);
|
||||||
|
limits.AddMember("maxZFW", MAX_PAX_ZFW(UserData->isImperial), allocator);
|
||||||
|
limits.AddMember("minZFW", targetPaxPayloadData->empty + targetPaxPayloadData->leftAux + targetPaxPayloadData->rightAux, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
// Construct document
|
// Construct document
|
||||||
document.AddMember("livePayload", livePayload.Move(), allocator);
|
document.AddMember("livePayload", livePayload.Move(), allocator);
|
||||||
document.AddMember("targetPayload", targetPayload.Move(), allocator);
|
document.AddMember("targetPayload", targetPayload.Move(), allocator);
|
||||||
document.AddMember("GSX", GSX.Move(), allocator);
|
document.AddMember("GSX", GSX.Move(), allocator);
|
||||||
|
document.AddMember("userData", userData.Move(), allocator);
|
||||||
|
document.AddMember("limits", limits.Move(), allocator);
|
||||||
|
|
||||||
// Write to CommBus
|
// Write to CommBus
|
||||||
document.Accept(writer);
|
document.Accept(writer);
|
||||||
@ -650,6 +697,8 @@ void sendData () {
|
|||||||
fsCommBusCall(COMM_BUS_LIVE_DATA_EVENT, strbuf.GetString(), strbuf.GetSize(), FsCommBusBroadcast_JS);
|
fsCommBusCall(COMM_BUS_LIVE_DATA_EVENT, strbuf.GetString(), strbuf.GetSize(), FsCommBusBroadcast_JS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
// Logfile
|
// Logfile
|
||||||
void log(FILE* file, const char* format, void* optionalElement)
|
void log(FILE* file, const char* format, void* optionalElement)
|
||||||
{
|
{
|
||||||
@ -670,16 +719,18 @@ void CALLBACK MyDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void* pContex
|
|||||||
case DATA_REQUEST_EMPTY_WEIGHT: {
|
case DATA_REQUEST_EMPTY_WEIGHT: {
|
||||||
liveFPayloadData->empty = livePaxPayloadData->empty = *((double*)&pObjData->dwData);
|
liveFPayloadData->empty = livePaxPayloadData->empty = *((double*)&pObjData->dwData);
|
||||||
|
|
||||||
sendTimer++;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DATA_REQUEST_PAYLOAD_F: {
|
case DATA_REQUEST_PAYLOAD_F: {
|
||||||
fPayloadData_t* data = (fPayloadData_t*)&pObjData->dwData;
|
fPayloadData_t* data = (fPayloadData_t*)&pObjData->dwData;
|
||||||
data->empty = liveFPayloadData->empty;
|
data->empty = liveFPayloadData->empty;
|
||||||
memcpy(liveFPayloadData, data, sizeof(fPayloadData_t));
|
memcpy(liveFPayloadData, data, sizeof(fPayloadData_t));
|
||||||
|
liveFPayloadData->total = liveFPayloadData->empty + liveFPayloadData->pilot + liveFPayloadData->firstOfficer +
|
||||||
sendTimer++;
|
liveFPayloadData->engineer + liveFPayloadData->upper1Left + liveFPayloadData->upper1Right +
|
||||||
|
liveFPayloadData->upper2Left + liveFPayloadData->upper2Right + liveFPayloadData->upper3Left +
|
||||||
|
liveFPayloadData->upper3Right + liveFPayloadData->upper4Left + liveFPayloadData->upper4Right +
|
||||||
|
liveFPayloadData->lowerForward + liveFPayloadData->lowerRear + liveFPayloadData->leftAux +
|
||||||
|
liveFPayloadData->rightAux;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -687,8 +738,14 @@ void CALLBACK MyDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void* pContex
|
|||||||
paxPayloadData_t* data = (paxPayloadData_t*)&pObjData->dwData;
|
paxPayloadData_t* data = (paxPayloadData_t*)&pObjData->dwData;
|
||||||
data->empty = livePaxPayloadData->empty;
|
data->empty = livePaxPayloadData->empty;
|
||||||
memcpy(livePaxPayloadData, data, sizeof(paxPayloadData_t));
|
memcpy(livePaxPayloadData, data, sizeof(paxPayloadData_t));
|
||||||
|
livePaxPayloadData->total = livePaxPayloadData->empty + livePaxPayloadData->pilot + livePaxPayloadData->firstOfficer +
|
||||||
sendTimer++;
|
livePaxPayloadData->engineer + livePaxPayloadData->cabinCrewFront + livePaxPayloadData->business1Left +
|
||||||
|
livePaxPayloadData->business1Center + livePaxPayloadData->business1Right + livePaxPayloadData->business2Left +
|
||||||
|
livePaxPayloadData->business2Center + livePaxPayloadData->business2Right + livePaxPayloadData->economy1Left +
|
||||||
|
livePaxPayloadData->economy1Center + livePaxPayloadData->economy1Right + livePaxPayloadData->economy2Left +
|
||||||
|
livePaxPayloadData->economy2Center + livePaxPayloadData->economy2Right + livePaxPayloadData->cabinCrewRear +
|
||||||
|
livePaxPayloadData->forwardCargo + livePaxPayloadData->rearCargo + livePaxPayloadData->leftAux +
|
||||||
|
livePaxPayloadData->rightAux;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -708,16 +765,12 @@ void CALLBACK MyDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void* pContex
|
|||||||
liveFuelData->lowerAux + liveFuelData->main1Tip + liveFuelData->main3Tip + liveFuelData->tail +
|
liveFuelData->lowerAux + liveFuelData->main1Tip + liveFuelData->main3Tip + liveFuelData->tail +
|
||||||
liveFuelData->forwardAux1 + liveFuelData->forwardAux2;
|
liveFuelData->forwardAux1 + liveFuelData->forwardAux2;
|
||||||
|
|
||||||
sendTimer++;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DATA_REQUEST_GSX: {
|
case DATA_REQUEST_GSX: {
|
||||||
GSXData_t* data = (GSXData_t*)&pObjData->dwData;
|
GSXData_t* data = (GSXData_t*)&pObjData->dwData;
|
||||||
memcpy(GSXData, data, sizeof(GSXData_t));
|
memcpy(GSXData, data, sizeof(GSXData_t));
|
||||||
|
|
||||||
sendTimer++;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DATA_REQUEST_USER_DATA: {
|
case DATA_REQUEST_USER_DATA: {
|
||||||
@ -725,7 +778,19 @@ void CALLBACK MyDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void* pContex
|
|||||||
data->isImperial = ((long)data->isImperial) & 1;
|
data->isImperial = ((long)data->isImperial) & 1;
|
||||||
memcpy(UserData, data, sizeof(UserData_t));
|
memcpy(UserData, data, sizeof(UserData_t));
|
||||||
|
|
||||||
sendTimer++;
|
// Update static weights
|
||||||
|
// Shared part 1
|
||||||
|
targetFPayloadData->empty = targetPaxPayloadData->empty = FROM_POUNDS(UserData->isImperial, liveFPayloadData->empty);
|
||||||
|
targetFPayloadData->pilot = targetPaxPayloadData->pilot = targetFPayloadData->firstOfficer = targetPaxPayloadData->firstOfficer =
|
||||||
|
targetFPayloadData->engineer = targetPaxPayloadData->engineer = PILOT_WEIGHT(UserData->isImperial);
|
||||||
|
// Shared part 2
|
||||||
|
targetFPayloadData->leftAux = targetPaxPayloadData->leftAux = targetFPayloadData->rightAux = targetPaxPayloadData->rightAux =
|
||||||
|
UserData->isER ? AUX_WEIGHT(UserData->isImperial) : 0;
|
||||||
|
// Pax only fixed weights
|
||||||
|
if (!UserData->isCargo) {
|
||||||
|
targetPaxPayloadData->cabinCrewFront = FRONT_CREW_WEIGHT(UserData->isImperial);
|
||||||
|
targetPaxPayloadData->cabinCrewRear = REAR_CREW_WEIGHT(UserData->isImperial);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -734,12 +799,6 @@ void CALLBACK MyDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void* pContex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send once every request "frame"
|
|
||||||
if (sendTimer == 6) {
|
|
||||||
sendData();
|
|
||||||
sendTimer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SIMCONNECT_RECV_ID_EXCEPTION:
|
case SIMCONNECT_RECV_ID_EXCEPTION:
|
||||||
|
|||||||
@ -13,6 +13,11 @@ void distribute(paxPayloadData_t* const targetPayload, const FuelData_t* const f
|
|||||||
|
|
||||||
//SimBrief Entry, SB pax count and total cargo
|
//SimBrief Entry, SB pax count and total cargo
|
||||||
void distribute(paxPayloadData_t* const targetPayload, const FuelData_t* const fuel, unsigned short numPax, unsigned int cargo, const double CGTarget, const bool isImperial) {
|
void distribute(paxPayloadData_t* const targetPayload, const FuelData_t* const fuel, unsigned short numPax, unsigned int cargo, const double CGTarget, const bool isImperial) {
|
||||||
|
// Clear
|
||||||
|
targetPayload->paxCount.business1 = targetPayload->paxCount.business2 = targetPayload->paxCount.economy1 = targetPayload->paxCount.economy2 =
|
||||||
|
targetPayload->paxCount.total = 0;
|
||||||
|
targetPayload->forwardCargo = targetPayload->rearCargo = 0;
|
||||||
|
|
||||||
unsigned short _numPax = 0;
|
unsigned short _numPax = 0;
|
||||||
unsigned int count = MAX_PAX;
|
unsigned int count = MAX_PAX;
|
||||||
// Initial distribution pax + bags
|
// Initial distribution pax + bags
|
||||||
@ -219,12 +224,22 @@ void generatePayload(paxPayloadData_t* const targetPayload, const bool isImperia
|
|||||||
targetPayload->business2Left = targetPayload->business2Center = targetPayload->business2Right = (targetPayload->paxCount.business2 / 3.0) * PAX_WEIGHT(isImperial);
|
targetPayload->business2Left = targetPayload->business2Center = targetPayload->business2Right = (targetPayload->paxCount.business2 / 3.0) * PAX_WEIGHT(isImperial);
|
||||||
targetPayload->economy1Left = targetPayload->economy1Center = targetPayload->economy1Right = (targetPayload->paxCount.economy1 / 3.0) * PAX_WEIGHT(isImperial);
|
targetPayload->economy1Left = targetPayload->economy1Center = targetPayload->economy1Right = (targetPayload->paxCount.economy1 / 3.0) * PAX_WEIGHT(isImperial);
|
||||||
targetPayload->economy2Left = targetPayload->economy2Center = targetPayload->economy2Right = (targetPayload->paxCount.economy2 / 3.0) * PAX_WEIGHT(isImperial);
|
targetPayload->economy2Left = targetPayload->economy2Center = targetPayload->economy2Right = (targetPayload->paxCount.economy2 / 3.0) * PAX_WEIGHT(isImperial);
|
||||||
|
targetPayload->total = targetPayload->empty + targetPayload->pilot + targetPayload->firstOfficer + targetPayload->engineer + targetPayload->cabinCrewFront +
|
||||||
|
targetPayload->business1Left + targetPayload->business1Center + targetPayload->business1Right + targetPayload->business2Left +
|
||||||
|
targetPayload->business2Center + targetPayload->business2Right + targetPayload->economy1Left + targetPayload->economy1Center +
|
||||||
|
targetPayload->economy1Right + targetPayload->economy2Left + targetPayload->economy2Center + targetPayload->economy2Right +
|
||||||
|
targetPayload->cabinCrewRear + targetPayload->forwardCargo + targetPayload->rearCargo + targetPayload->leftAux + targetPayload->rightAux;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalise to Pounds
|
// Normalise to Pounds
|
||||||
// MANDATORY BEFORE SETTING WEIGHTS
|
// MANDATORY BEFORE SETTING WEIGHTS
|
||||||
// ENSURE ONLY EVER CALLED ONCE PER SET CYCLE
|
// ENSURE ONLY EVER CALLED ONCE PER SET CYCLE
|
||||||
void normalisePayload(paxPayloadData_t* const targetPayload, const bool isImperial) {
|
void normalisePayload(paxPayloadData_t* const targetPayload, const bool isImperial) {
|
||||||
|
targetPayload->empty = TO_POUNDS(isImperial, targetPayload->empty);
|
||||||
|
targetPayload->pilot = TO_POUNDS(isImperial, targetPayload->pilot);
|
||||||
|
targetPayload->firstOfficer = TO_POUNDS(isImperial, targetPayload->firstOfficer);
|
||||||
|
targetPayload->engineer = TO_POUNDS(isImperial, targetPayload->engineer);
|
||||||
|
targetPayload->cabinCrewFront = TO_POUNDS(isImperial, targetPayload->cabinCrewFront);
|
||||||
targetPayload->business1Left = TO_POUNDS(isImperial, targetPayload->business1Left);
|
targetPayload->business1Left = TO_POUNDS(isImperial, targetPayload->business1Left);
|
||||||
targetPayload->business1Center = TO_POUNDS(isImperial, targetPayload->business1Center);
|
targetPayload->business1Center = TO_POUNDS(isImperial, targetPayload->business1Center);
|
||||||
targetPayload->business1Right = TO_POUNDS(isImperial, targetPayload->business1Right);
|
targetPayload->business1Right = TO_POUNDS(isImperial, targetPayload->business1Right);
|
||||||
@ -237,27 +252,32 @@ void normalisePayload(paxPayloadData_t* const targetPayload, const bool isImperi
|
|||||||
targetPayload->economy2Left = TO_POUNDS(isImperial, targetPayload->economy2Left);
|
targetPayload->economy2Left = TO_POUNDS(isImperial, targetPayload->economy2Left);
|
||||||
targetPayload->economy2Center = TO_POUNDS(isImperial, targetPayload->economy2Center);
|
targetPayload->economy2Center = TO_POUNDS(isImperial, targetPayload->economy2Center);
|
||||||
targetPayload->economy2Right = TO_POUNDS(isImperial, targetPayload->economy2Right);
|
targetPayload->economy2Right = TO_POUNDS(isImperial, targetPayload->economy2Right);
|
||||||
|
targetPayload->cabinCrewRear = TO_POUNDS(isImperial, targetPayload->cabinCrewRear);
|
||||||
|
targetPayload->forwardCargo = TO_POUNDS(isImperial, targetPayload->forwardCargo);
|
||||||
|
targetPayload->rearCargo = TO_POUNDS(isImperial, targetPayload->rearCargo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculateCGs(const paxPayloadData_t* const targetPayload, const FuelData_t* fuel, double* const ZFWCG, double* const TOCG, const bool isImperial) {
|
void calculateCGs(const paxPayloadData_t* const targetPayload, const FuelData_t* const fuel, double* const ZFWCG, double* const TOCG, const bool isImperial) {
|
||||||
double totalMoment = targetPayload->empty * ARM_EMPTY + targetPayload->pilot * ARM_PILOT + targetPayload->firstOfficer * ARM_FIRST_OFFICER +
|
paxPayloadData_t localPayload = {};
|
||||||
targetPayload->engineer * ARM_ENGINEER + targetPayload->cabinCrewFront * ARM_PAX_CABIN_CREW_FRONT +
|
memcpy(&localPayload, targetPayload, sizeof(localPayload));
|
||||||
targetPayload->business1Left * ARM_PAX_BUSINESS1_LEFT + targetPayload->business1Center * ARM_PAX_BUSINESS1_CENTER +
|
normalisePayload(&localPayload, isImperial);
|
||||||
targetPayload->business1Right * ARM_PAX_BUSINESS1_RIGHT + targetPayload->business2Left * ARM_PAX_BUSINESS2_LEFT +
|
|
||||||
targetPayload->business2Center * ARM_PAX_BUSINESS2_CENTER + targetPayload->business2Right * ARM_PAX_BUSINESS2_RIGHT +
|
|
||||||
targetPayload->economy1Left * ARM_PAX_ECONOMY1_LEFT + targetPayload->economy1Center * ARM_PAX_ECONOMY1_CENTER +
|
|
||||||
targetPayload->economy1Right * ARM_PAX_ECONOMY1_RIGHT + targetPayload->economy2Left * ARM_PAX_ECONOMY2_LEFT +
|
|
||||||
targetPayload->economy2Center * ARM_PAX_ECONOMY2_CENTER + targetPayload->economy2Right * ARM_PAX_ECONOMY2_RIGHT +
|
|
||||||
targetPayload->cabinCrewRear * ARM_PAX_CABIN_CREW_REAR + targetPayload->forwardCargo * ARM_FORWARD_CARGO +
|
|
||||||
targetPayload->rearCargo * ARM_REAR_CARGO + targetPayload->leftAux * ARM_LEFT_AUX + targetPayload->rightAux * ARM_RIGHT_AUX;
|
|
||||||
|
|
||||||
double totalWeight = targetPayload->empty + targetPayload->pilot + targetPayload->firstOfficer + targetPayload->engineer +
|
double totalMoment = localPayload.empty * ARM_EMPTY + localPayload.pilot * ARM_PILOT + localPayload.firstOfficer * ARM_FIRST_OFFICER +
|
||||||
targetPayload->cabinCrewFront + targetPayload->business1Left + targetPayload->business1Center +
|
localPayload.engineer * ARM_ENGINEER + localPayload.cabinCrewFront * ARM_PAX_CABIN_CREW_FRONT +
|
||||||
targetPayload->business1Right + targetPayload->business2Left + targetPayload->business2Center +
|
localPayload.business1Left * ARM_PAX_BUSINESS1_LEFT + localPayload.business1Center * ARM_PAX_BUSINESS1_CENTER +
|
||||||
targetPayload->business2Right + targetPayload->economy1Left + targetPayload->economy1Center +
|
localPayload.business1Right * ARM_PAX_BUSINESS1_RIGHT + localPayload.business2Left * ARM_PAX_BUSINESS2_LEFT +
|
||||||
targetPayload->economy1Right + targetPayload->economy2Left + targetPayload->economy2Center +
|
localPayload.business2Center * ARM_PAX_BUSINESS2_CENTER + localPayload.business2Right * ARM_PAX_BUSINESS2_RIGHT +
|
||||||
targetPayload->economy2Right + targetPayload->cabinCrewRear + targetPayload->forwardCargo +
|
localPayload.economy1Left * ARM_PAX_ECONOMY1_LEFT + localPayload.economy1Center * ARM_PAX_ECONOMY1_CENTER +
|
||||||
targetPayload->rearCargo + targetPayload->leftAux + targetPayload->rightAux;
|
localPayload.economy1Right * ARM_PAX_ECONOMY1_RIGHT + localPayload.economy2Left * ARM_PAX_ECONOMY2_LEFT +
|
||||||
|
localPayload.economy2Center * ARM_PAX_ECONOMY2_CENTER + localPayload.economy2Right * ARM_PAX_ECONOMY2_RIGHT +
|
||||||
|
localPayload.cabinCrewRear * ARM_PAX_CABIN_CREW_REAR + localPayload.forwardCargo * ARM_FORWARD_CARGO +
|
||||||
|
localPayload.rearCargo * ARM_REAR_CARGO + localPayload.leftAux * ARM_LEFT_AUX + localPayload.rightAux * ARM_RIGHT_AUX;
|
||||||
|
|
||||||
|
double totalWeight = localPayload.empty + localPayload.pilot + localPayload.firstOfficer + localPayload.engineer + localPayload.cabinCrewFront +
|
||||||
|
localPayload.business1Left + localPayload.business1Center + localPayload.business1Right + localPayload.business2Left +
|
||||||
|
localPayload.business2Center + localPayload.business2Right + localPayload.economy1Left + localPayload.economy1Center +
|
||||||
|
localPayload.economy1Right + localPayload.economy2Left + localPayload.economy2Center + localPayload.economy2Right +
|
||||||
|
localPayload.cabinCrewRear + localPayload.forwardCargo + localPayload.rearCargo + localPayload.leftAux + localPayload.rightAux;
|
||||||
|
|
||||||
*ZFWCG = TO_PERCENT_MAC(totalMoment / totalWeight);
|
*ZFWCG = TO_PERCENT_MAC(totalMoment / totalWeight);
|
||||||
|
|
||||||
|
|||||||
@ -27,4 +27,4 @@ void generatePayload(paxPayloadData_t* const targetPayload, const bool isImperia
|
|||||||
// Normalise to Pounds
|
// Normalise to Pounds
|
||||||
// For Station Entry: CALL AFTER `generatePayload`
|
// For Station Entry: CALL AFTER `generatePayload`
|
||||||
void normalisePayload(paxPayloadData_t* const targetPayload, const bool isImperial);
|
void normalisePayload(paxPayloadData_t* const targetPayload, const bool isImperial);
|
||||||
void calculateCGs(const paxPayloadData_t* const targetPayload, const FuelData_t* fuel, double* const ZFWCG, double* const TOCG, const bool isImperial);
|
void calculateCGs(const paxPayloadData_t* const targetPayload, const FuelData_t* const fuel, double* const ZFWCG, double* const TOCG, const bool isImperial);
|
||||||
|
|||||||
@ -31,6 +31,17 @@
|
|||||||
// Total
|
// Total
|
||||||
#define MAX_PAX 298
|
#define MAX_PAX 298
|
||||||
|
|
||||||
|
// Max ZFW
|
||||||
|
#define MAX_PAX_ZFW(IS_IMPERIAL) ((IS_IMPERIAL) ? (400000) : (181437))
|
||||||
|
|
||||||
|
// Max TOW
|
||||||
|
#define MAX_TOW(IS_IMPERIAL) ((IS_IMPERIAL) ? (625500) : (283722))
|
||||||
|
#define MAX_TOW_ER(IS_IMPERIAL) ((IS_IMPERIAL) ? (630500) : (285990))
|
||||||
|
|
||||||
|
// Max Fuel
|
||||||
|
#define MAX_FUEL(IS_IMPERIAL) ((IS_IMPERIAL) ? (256207) : (116213))
|
||||||
|
#define MAX_FUEL_ER(IS_IMPERIAL) ((IS_IMPERIAL) ? (282619) : (128193))
|
||||||
|
|
||||||
// Arms
|
// Arms
|
||||||
// Shared part 1
|
// Shared part 1
|
||||||
#define ARM_EMPTY -159.6
|
#define ARM_EMPTY -159.6
|
||||||
@ -132,10 +143,9 @@ typedef struct {
|
|||||||
|
|
||||||
// Additional properties
|
// Additional properties
|
||||||
double empty;
|
double empty;
|
||||||
|
double total;
|
||||||
double ZFWCG;
|
double ZFWCG;
|
||||||
double TOCG;
|
double TOCG;
|
||||||
|
|
||||||
struct paxCount {
|
struct paxCount {
|
||||||
unsigned char business1;
|
unsigned char business1;
|
||||||
unsigned char business2;
|
unsigned char business2;
|
||||||
@ -165,7 +175,7 @@ typedef struct {
|
|||||||
|
|
||||||
// Additional properties
|
// Additional properties
|
||||||
double empty;
|
double empty;
|
||||||
|
double total;
|
||||||
double ZFWCG;
|
double ZFWCG;
|
||||||
double TOCG;
|
double TOCG;
|
||||||
} fPayloadData_t;
|
} fPayloadData_t;
|
||||||
|
|||||||
15
README.md
15
README.md
@ -5,6 +5,17 @@
|
|||||||
- https://www.satco-inc.com/product-pallet/?part_number=31086-595
|
- https://www.satco-inc.com/product-pallet/?part_number=31086-595
|
||||||
- https://www.satco-inc.com/product-container/?part_number=34124-901
|
- https://www.satco-inc.com/product-container/?part_number=34124-901
|
||||||
|
|
||||||
Coherent.call("COMM_BUS_WASM_CALLBACK", "khofmann_tfdi_md-11_load_manager_update_target", '{"value" : 42}');
|
|
||||||
|
|
||||||
Coherent.call("COMM_BUS_WASM_CALLBACK", "khofmann_tfdi_md-11_load_manager_update_target", '{"mode" : 1, "ZFWTarget": 162000, "CGTarget": 20.5}');
|
Coherent.call("COMM_BUS_WASM_CALLBACK", "khofmann_tfdi_md-11_load_manager_update_target", '{"mode" : 1, "ZFWTarget": 162000, "CGTarget": 20.5}');
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
- JS
|
||||||
|
- Connect to WASM as Data Source (sans SB username)
|
||||||
|
- Setting target
|
||||||
|
- SB
|
||||||
|
- Stations
|
||||||
|
- GSX State?
|
||||||
|
- Duplicate Input pages for F
|
||||||
|
- WASM
|
||||||
|
- Setting of payload
|
||||||
|
- GSX synced setting
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user