Setting of payload

This commit is contained in:
Kilian Hofmann 2025-06-12 14:30:00 +02:00
parent 8975ea17af
commit f7304c5c7b
13 changed files with 142 additions and 84 deletions

View File

@ -1,5 +1,5 @@
import { FC, useEffect, useRef, useState } from 'react'; import { FC, useEffect, useRef, useState } from 'react';
import { emptyAircraft } from '../../configs/shared'; import { unloadAircraft } from '../../configs/shared';
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants'; import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants';
import { WASMDataPax } from '../../types/WASMData'; import { WASMDataPax } from '../../types/WASMData';
import { LoadingState } from '../../types/general'; import { LoadingState } from '../../types/general';
@ -214,9 +214,7 @@ const SBEntryPax: FC<SBEntryProps> = ({ WASMData, loadingState, username, setLoa
<ActionBar <ActionBar
loadingState={loadingState} loadingState={loadingState}
acceptDisabled={!GWValid() || SBInFlight} loadDisabled={!GWValid() || SBInFlight}
accept={() => setLoadingState('loaded')}
reject={() => setLoadingState('preview')}
importSB={handleSB} importSB={handleSB}
load={() => { load={() => {
setLoadingState('loaded'); setLoadingState('loaded');
@ -226,7 +224,7 @@ const SBEntryPax: FC<SBEntryProps> = ({ WASMData, loadingState, username, setLoa
unload={() => { unload={() => {
setLoadingState('preview'); setLoadingState('preview');
emptyAircraft(); unloadAircraft();
}} }}
/> />
</> </>

View File

@ -3,35 +3,34 @@ import { LoadingState } from '../../types/general';
interface ActionBarProps { interface ActionBarProps {
loadingState: LoadingState; loadingState: LoadingState;
acceptDisabled: boolean; loadDisabled: boolean;
accept: () => void;
reject: () => void;
importSB?: () => void; importSB?: () => void;
load: () => void; load: () => void;
unload: () => void; unload: () => void;
} }
const ActionBar: FC<ActionBarProps> = ({ loadingState, acceptDisabled, accept, reject, importSB, load, unload }) => { const ActionBar: FC<ActionBarProps> = ({ loadingState, loadDisabled, importSB, load, unload }) => {
return ( return (
<div className="relative flex w-full items-center justify-start gap-x-6"> <div className="relative flex w-full items-center justify-start gap-x-6">
{/*TODO: HIDE FOR GSX SYNCED */}
{loadingState === 'preview' && ( {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={accept} onClick={load}
disabled={acceptDisabled} disabled={loadDisabled}
> >
Accept Load
</button> </button>
)} )}
{/*TODO: Make GSX optional (accepted state for NON GSX) */} {/*TODO: HIDE FOR GSX SYNCED */}
{loadingState === 'loaded' && ( {loadingState === 'loaded' && (
<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" 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" data-ripple-light="true"
onClick={reject} onClick={unload}
> >
Reject Unload
</button> </button>
)} )}
@ -46,27 +45,6 @@ const ActionBar: FC<ActionBarProps> = ({ loadingState, acceptDisabled, accept, r
Import from SimBrief Import from SimBrief
</button> </button>
)} )}
{/*TODO: Make GSX optional */}
{/*
{loadingState === 'accepted' && (
<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={load}
>
Load
</button>
)}
{loadingState === 'loaded' && (
<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={unload}
>
Unload
</button>
)}
*/}
</div> </div>
); );
}; };

View File

@ -1,4 +1,5 @@
import { FC, useState } from 'react'; import { FC, useState } from 'react';
import { loadAircraft } from '../../configs/shared';
import { LoadingState } from '../../types/general'; import { LoadingState } from '../../types/general';
import { WASMDataPax } from '../../types/WASMData'; import { WASMDataPax } from '../../types/WASMData';
import Profile from '../profile/Profile'; import Profile from '../profile/Profile';
@ -109,9 +110,7 @@ const Pax: FC<PaxProps> = ({ WASMData, username }) => {
loadingState={loadingState} loadingState={loadingState}
username={username} username={username}
setLoadingState={setLoadingState} setLoadingState={setLoadingState}
loadAircraft={() => { loadAircraft={loadAircraft}
console.log('SET WEIGHT SB');
}}
/> />
)} )}
{((username && selectedTab === 1) || (!username && selectedTab === 0)) && ( {((username && selectedTab === 1) || (!username && selectedTab === 0)) && (
@ -119,9 +118,7 @@ const Pax: FC<PaxProps> = ({ WASMData, username }) => {
WASMData={WASMData} WASMData={WASMData}
loadingState={loadingState} loadingState={loadingState}
setLoadingState={setLoadingState} setLoadingState={setLoadingState}
loadAircraft={() => { loadAircraft={loadAircraft}
console.log('SET WEIGHT ZFW');
}}
/> />
)} )}
{((username && selectedTab === 2) || (!username && selectedTab === 1)) && ( {((username && selectedTab === 2) || (!username && selectedTab === 1)) && (
@ -129,9 +126,7 @@ const Pax: FC<PaxProps> = ({ WASMData, username }) => {
WASMData={WASMData} WASMData={WASMData}
loadingState={loadingState} loadingState={loadingState}
setLoadingState={setLoadingState} setLoadingState={setLoadingState}
loadAircraft={() => { loadAircraft={loadAircraft}
console.log('SET WEIGHT STATIONS');
}}
/> />
)} )}
</> </>

View File

@ -1,5 +1,5 @@
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { emptyAircraft } from '../../configs/shared'; import { unloadAircraft } from '../../configs/shared';
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants'; import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants';
import { LoadingState } from '../../types/general'; import { LoadingState } from '../../types/general';
import { WASMDataPax } from '../../types/WASMData'; import { WASMDataPax } from '../../types/WASMData';
@ -210,9 +210,7 @@ const StationEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoa
<ActionBar <ActionBar
loadingState={loadingState} loadingState={loadingState}
acceptDisabled={!ZFWValid() || !GWValid()} loadDisabled={!ZFWValid() || !GWValid()}
accept={() => setLoadingState('accepted')}
reject={() => setLoadingState('preview')}
load={() => { load={() => {
setLoadingState('loaded'); setLoadingState('loaded');
@ -221,7 +219,7 @@ const StationEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoa
unload={() => { unload={() => {
setLoadingState('preview'); setLoadingState('preview');
emptyAircraft(); unloadAircraft();
}} }}
/> />
</> </>

View File

@ -1,5 +1,5 @@
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { emptyAircraft } from '../../configs/shared'; import { unloadAircraft } from '../../configs/shared';
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants'; import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants';
import { WASMDataPax } from '../../types/WASMData'; import { WASMDataPax } from '../../types/WASMData';
import { LoadingState } from '../../types/general'; import { LoadingState } from '../../types/general';
@ -200,9 +200,7 @@ const ZFWEntryPax: FC<ZFWEntryProps> = ({ WASMData, loadingState, setLoadingStat
<ActionBar <ActionBar
loadingState={loadingState} loadingState={loadingState}
acceptDisabled={!GWValid()} loadDisabled={!GWValid()}
accept={() => setLoadingState('accepted')}
reject={() => setLoadingState('preview')}
load={() => { load={() => {
setLoadingState('loaded'); setLoadingState('loaded');
@ -211,7 +209,7 @@ const ZFWEntryPax: FC<ZFWEntryProps> = ({ WASMData, loadingState, setLoadingStat
unload={() => { unload={() => {
setLoadingState('preview'); setLoadingState('preview');
emptyAircraft(); unloadAircraft();
}} }}
/> />
</> </>

View File

@ -1,11 +1,21 @@
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_LIVE_DATA_EVENT } from '../constants'; import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../constants';
export const emptyAircraft = () => { export const loadAircraft = () => {
Coherent.call( Coherent.call(
COHERENT_COMBUS_WASM_CALL, COHERENT_COMBUS_WASM_CALL,
COMM_BUS_LIVE_DATA_EVENT, COMM_BUS_UPDATE_TARGET_EVENT,
JSON.stringify({ JSON.stringify({
mode: 3, mode: 3,
}) })
); );
}; };
export const unloadAircraft = () => {
Coherent.call(
COHERENT_COMBUS_WASM_CALL,
COMM_BUS_UPDATE_TARGET_EVENT,
JSON.stringify({
mode: 4,
})
);
};

View File

@ -1 +1 @@
export type LoadingState = 'preview' | 'accepted' | 'loaded'; export type LoadingState = 'preview' | 'loaded';

View File

@ -500,6 +500,28 @@ int receiveData(const char* buf) {
} }
break; break;
} }
// Trigger load
case 3: {
if (UserData->isCargo) {
}
else {
load(targetPaxPayloadData, simConnect, UserData->isImperial);
}
break;
}
// Trigger unload
case 4: {
if (UserData->isCargo) {
}
else {
unload(simConnect, UserData->isImperial);
}
break;
}
default: default:
break; break;
} }

View File

@ -12,8 +12,6 @@
#include <MSFS/MSFS.h> #include <MSFS/MSFS.h>
#include <MSFS/MSFS_CommBus.h> #include <MSFS/MSFS_CommBus.h>
#include <MSFS/MSFS_Core.h>
#include <MSFS/MSFS_Render.h>
#include <MSFS/Legacy/gauges.h> #include <MSFS/Legacy/gauges.h>
#include <rapidjson/document.h> #include <rapidjson/document.h>
@ -29,25 +27,6 @@
#define COMM_BUS_LIVE_DATA_EVENT "khofmann_tfdi_md-11_load_manager_live_data" #define COMM_BUS_LIVE_DATA_EVENT "khofmann_tfdi_md-11_load_manager_live_data"
#define COMM_BUS_UPDATE_TARGET_EVENT "khofmann_tfdi_md-11_load_manager_update_target" #define COMM_BUS_UPDATE_TARGET_EVENT "khofmann_tfdi_md-11_load_manager_update_target"
// SimConnect ENUMs
enum DATA_DEFINITIONS {
DATA_DEFINITION_EMPTY_WEIGHT,
DATA_DEFINITION_PAYLOAD_PAX,
DATA_DEFINITION_PAYLOAD_F,
DATA_DEFINITION_FUEL,
DATA_DEFINITION_GSX,
DATA_DEFINITION_USER_DATA,
};
enum DATA_REQUESTS {
DATA_REQUEST_EMPTY_WEIGHT,
DATA_REQUEST_PAYLOAD_PAX,
DATA_REQUEST_PAYLOAD_F,
DATA_REQUEST_FUEL,
DATA_REQUEST_GSX,
DATA_REQUEST_USER_DATA,
};
void commBusUpdateTargetCallback(const char* args, unsigned int size, void* ctx); void commBusUpdateTargetCallback(const char* args, unsigned int size, void* ctx);
int receiveData(const char* buf); int receiveData(const char* buf);
void sendData(); void sendData();

View File

@ -5,13 +5,13 @@ void distribute(paxPayloadData_t* const targetPayload, const FuelData_t* const f
// Find payload, num pax and extra cargo // Find payload, num pax and extra cargo
double payload = ZFWTarget - targetPayload->empty - targetPayload->pilot - targetPayload->firstOfficer - targetPayload->engineer - double payload = ZFWTarget - targetPayload->empty - targetPayload->pilot - targetPayload->firstOfficer - targetPayload->engineer -
targetPayload->cabinCrewFront - targetPayload->cabinCrewRear - targetPayload->leftAux - targetPayload->rightAux; targetPayload->cabinCrewFront - targetPayload->cabinCrewRear - targetPayload->leftAux - targetPayload->rightAux;
unsigned short numPax = std::max(0.0, std::min((double)MAX_PAX, floor(payload / (PAX_WEIGHT(isImperial) + BAG_WEIGHT(isImperial))))); unsigned short numPax = max(0.0, min((double)MAX_PAX, floor(payload / (PAX_WEIGHT(isImperial) + BAG_WEIGHT(isImperial)))));
unsigned int cargo = round(payload - numPax * PAX_WEIGHT(isImperial) - numPax * BAG_WEIGHT(isImperial)); unsigned int cargo = round(payload - numPax * PAX_WEIGHT(isImperial) - numPax * BAG_WEIGHT(isImperial));
distribute(targetPayload, fuel, numPax, cargo, isImperial); distribute(targetPayload, fuel, numPax, cargo, isImperial);
} }
//SimBrief Entry, SB pax count and total cargo //SimBrief Entry, SB pax count and extra cargo
void distribute(paxPayloadData_t* const targetPayload, const FuelData_t* const fuel, unsigned short numPax, unsigned int cargo, const bool isImperial) { void distribute(paxPayloadData_t* const targetPayload, const FuelData_t* const fuel, unsigned short numPax, unsigned int cargo, const bool isImperial) {
// Clear // Clear
targetPayload->paxCount.business1 = targetPayload->paxCount.business2 = targetPayload->paxCount.economy1 = targetPayload->paxCount.economy2 = targetPayload->paxCount.business1 = targetPayload->paxCount.business2 = targetPayload->paxCount.economy1 = targetPayload->paxCount.economy2 =
@ -289,3 +289,18 @@ void calculateCGs(const paxPayloadData_t* const targetPayload, const FuelData_t*
*TOCG = TO_PERCENT_MAC(totalMoment / totalWeight); *TOCG = TO_PERCENT_MAC(totalMoment / totalWeight);
} }
void load(const paxPayloadData_t* const targetPayload, const HANDLE simConnect, const bool isImperial) {
paxPayloadData_t localPayload = {};
memcpy(&localPayload, targetPayload, sizeof(localPayload));
normalisePayload(&localPayload, isImperial);
SimConnect_SetDataOnSimObject(simConnect, DATA_DEFINITION_PAYLOAD_PAX, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(paxPayloadDataSet_t), &localPayload);
}
void unload(const HANDLE simConnect, const bool isImperial) {
paxPayloadDataSet_t localPayload = {};
SimConnect_SetDataOnSimObject(simConnect, DATA_DEFINITION_PAYLOAD_PAX, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(localPayload), &localPayload);
}

View File

@ -10,10 +10,14 @@
# define __restrict__ # define __restrict__
#endif #endif
#include <MSFS/MSFS_WindowsTypes.h>
#include <math.h> #include <math.h>
#include <algorithm> #include <algorithm>
#include <SimConnect.h>
#include "types.h" #include "types.h"
//ZFW Entry, fill pax first (pax+bag), rest is cargo //ZFW Entry, fill pax first (pax+bag), rest is cargo
@ -28,3 +32,5 @@ void generatePayload(paxPayloadData_t* const targetPayload, const bool isImperia
// 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* const 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);
void load(const paxPayloadData_t* const targetPayload, const HANDLE simConnect, const bool isImperial);
void unload(const HANDLE simConnect, const bool isImperial);

View File

@ -101,6 +101,25 @@
#define TO_POUNDS(IS_IMPERIAL, VALUE) ((IS_IMPERIAL) ? (VALUE) : (VALUE) * 2.20462262185) #define TO_POUNDS(IS_IMPERIAL, VALUE) ((IS_IMPERIAL) ? (VALUE) : (VALUE) * 2.20462262185)
#define FROM_POUNDS(IS_IMPERIAL, VALUE) ((IS_IMPERIAL) ? (VALUE) : (VALUE) * (1.0 / 2.20462262185)) #define FROM_POUNDS(IS_IMPERIAL, VALUE) ((IS_IMPERIAL) ? (VALUE) : (VALUE) * (1.0 / 2.20462262185))
// SimConnect ENUMs
enum DATA_DEFINITIONS {
DATA_DEFINITION_EMPTY_WEIGHT,
DATA_DEFINITION_PAYLOAD_PAX,
DATA_DEFINITION_PAYLOAD_F,
DATA_DEFINITION_FUEL,
DATA_DEFINITION_GSX,
DATA_DEFINITION_USER_DATA,
};
enum DATA_REQUESTS {
DATA_REQUEST_EMPTY_WEIGHT,
DATA_REQUEST_PAYLOAD_PAX,
DATA_REQUEST_PAYLOAD_F,
DATA_REQUEST_FUEL,
DATA_REQUEST_GSX,
DATA_REQUEST_USER_DATA,
};
// Data // Data
typedef struct { typedef struct {
double isCargo; double isCargo;
@ -155,6 +174,29 @@ typedef struct {
unsigned short total; unsigned short total;
} paxCount; } paxCount;
} paxPayloadData_t; } paxPayloadData_t;
typedef struct {
double pilot;
double firstOfficer;
double engineer;
double cabinCrewFront;
double business1Left;
double business1Center;
double business1Right;
double business2Left;
double business2Center;
double business2Right;
double economy1Left;
double economy1Center;
double economy1Right;
double economy2Left;
double economy2Center;
double economy2Right;
double cabinCrewRear;
double forwardCargo;
double rearCargo;
double leftAux;
double rightAux;
} paxPayloadDataSet_t;
typedef struct { typedef struct {
// SimConnect mapped // SimConnect mapped
@ -181,6 +223,24 @@ typedef struct {
double ZFWCG; double ZFWCG;
double TOCG; double TOCG;
} fPayloadData_t; } fPayloadData_t;
typedef struct {
// SimConnect mapped
double pilot;
double firstOfficer;
double engineer;
double upper1Left;
double upper1Right;
double upper2Left;
double upper2Right;
double upper3Left;
double upper3Right;
double upper4Left;
double upper4Right;
double lowerForward;
double lowerRear;
double leftAux;
double rightAux;
} fPayloadDataSet_t;
typedef struct { typedef struct {
// SimConnect mapped // SimConnect mapped

View File

@ -14,5 +14,4 @@ TODO:
- Persist SB data across page changes - Persist SB data across page changes
- Duplicate Input pages for F - Duplicate Input pages for F
- WASM - WASM
- Setting of payload
- GSX synced setting of payload - GSX synced setting of payload