743 lines
26 KiB
ObjectPascal
743 lines
26 KiB
ObjectPascal
unit FSXLEDStateProvider;
|
|
|
|
interface
|
|
uses
|
|
Classes,
|
|
Messages,
|
|
SyncObjs,
|
|
Windows,
|
|
|
|
LEDFunctionMap,
|
|
LEDStateConsumer,
|
|
LEDStateProvider,
|
|
SimConnect;
|
|
|
|
|
|
const
|
|
{ Note: do not change these values, the config demands it! }
|
|
FUNCTION_FSX_GEAR = FUNCTION_PROVIDER_OFFSET + 1;
|
|
FUNCTION_FSX_LANDINGLIGHTS = FUNCTION_PROVIDER_OFFSET + 2;
|
|
FUNCTION_FSX_INSTRUMENTLIGHTS = FUNCTION_PROVIDER_OFFSET + 3;
|
|
FUNCTION_FSX_PARKINGBRAKE = FUNCTION_PROVIDER_OFFSET + 4;
|
|
FUNCTION_FSX_ENGINE = FUNCTION_PROVIDER_OFFSET + 5;
|
|
|
|
FUNCTION_FSX_EXITDOOR = FUNCTION_PROVIDER_OFFSET + 6;
|
|
FUNCTION_FSX_STROBELIGHTS = FUNCTION_PROVIDER_OFFSET + 7;
|
|
FUNCTION_FSX_NAVLIGHTS = FUNCTION_PROVIDER_OFFSET + 8;
|
|
FUNCTION_FSX_BEACONLIGHTS = FUNCTION_PROVIDER_OFFSET + 9;
|
|
FUNCTION_FSX_FLAPS = FUNCTION_PROVIDER_OFFSET + 10;
|
|
FUNCTION_FSX_BATTERYMASTER = FUNCTION_PROVIDER_OFFSET + 11;
|
|
FUNCTION_FSX_AVIONICSMASTER = FUNCTION_PROVIDER_OFFSET + 12;
|
|
|
|
FUNCTION_FSX_SPOILERS = FUNCTION_PROVIDER_OFFSET + 13;
|
|
|
|
FUNCTION_FSX_PRESSURIZATIONDUMPSWITCH = FUNCTION_PROVIDER_OFFSET + 14;
|
|
FUNCTION_FSX_ENGINEANTIICE = FUNCTION_PROVIDER_OFFSET + 15;
|
|
FUNCTION_FSX_AUTOPILOT = FUNCTION_PROVIDER_OFFSET + 16;
|
|
FUNCTION_FSX_FUELPUMP = FUNCTION_PROVIDER_OFFSET + 17;
|
|
|
|
FUNCTION_FSX_TAILHOOK = FUNCTION_PROVIDER_OFFSET + 18;
|
|
|
|
FUNCTION_FSX_AUTOPILOT_AMBER = FUNCTION_PROVIDER_OFFSET + 19;
|
|
FUNCTION_FSX_AUTOPILOT_HEADING = FUNCTION_PROVIDER_OFFSET + 20;
|
|
FUNCTION_FSX_AUTOPILOT_APPROACH = FUNCTION_PROVIDER_OFFSET + 21;
|
|
FUNCTION_FSX_AUTOPILOT_BACKCOURSE = FUNCTION_PROVIDER_OFFSET + 22;
|
|
FUNCTION_FSX_AUTOPILOT_ALTITUDE = FUNCTION_PROVIDER_OFFSET + 23;
|
|
FUNCTION_FSX_AUTOPILOT_NAV = FUNCTION_PROVIDER_OFFSET + 24;
|
|
|
|
FUNCTION_FSX_TAXILIGHTS = FUNCTION_PROVIDER_OFFSET + 25;
|
|
FUNCTION_FSX_RECOGNITIONLIGHTS = FUNCTION_PROVIDER_OFFSET + 26;
|
|
|
|
FUNCTION_FSX_DEICE = FUNCTION_PROVIDER_OFFSET + 27;
|
|
|
|
|
|
type
|
|
TFSXLEDStateProvider = class(TLEDStateProvider)
|
|
private
|
|
FSimConnectHandle: THandle;
|
|
FDefinitions: TList;
|
|
// FLastDown: Boolean;
|
|
protected
|
|
function GetProcessMessagesInterval: Integer; override;
|
|
|
|
procedure UpdateMap;
|
|
procedure HandleDispatch(AData: PSimConnectRecv);
|
|
|
|
procedure HandleGearData(AData: Pointer);
|
|
procedure HandleLightsData(AData: Pointer);
|
|
procedure HandleParkingBrakeData(AData: Pointer);
|
|
procedure HandleEngineData(AData: Pointer);
|
|
procedure HandleExitDoorData(AData: Pointer);
|
|
procedure HandleFlapsData(AData: Pointer);
|
|
procedure HandleSwitchesData(AData: Pointer);
|
|
procedure HandleAntiIceData(AData: Pointer);
|
|
|
|
procedure AddVariable(ADefineID: Cardinal; ADatumName, AUnitsName: string;
|
|
ADatumType: SIMCONNECT_DATAType = SIMCONNECT_DATAType_FLOAT64;
|
|
AEpsilon: Single = 0; ADatumID: DWORD = SIMCONNECT_UNUSED);
|
|
procedure AddDefinition(ADefinition: Cardinal);
|
|
procedure ClearDefinitions;
|
|
|
|
procedure SetFSXLightState(AStates: Cardinal; AMask, AFunction: Integer);
|
|
|
|
property SimConnectHandle: THandle read FSimConnectHandle;
|
|
public
|
|
class procedure EnumFunctions(AConsumer: IFunctionConsumer); override;
|
|
|
|
constructor Create(AConsumer: ILEDStateConsumer); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Initialize; override;
|
|
procedure Finalize; override;
|
|
procedure ProcessMessages; override;
|
|
end;
|
|
|
|
|
|
implementation
|
|
uses
|
|
ComObj,
|
|
Math,
|
|
SysUtils;
|
|
|
|
|
|
const
|
|
APPNAME = 'G940 LED Control';
|
|
|
|
MAX_ENGINES = 4;
|
|
|
|
DEFINITION_GEAR = 1;
|
|
DEFINITION_LIGHTS = 2;
|
|
DEFINITION_INSTRUMENTLIGHTS = 3;
|
|
DEFINITION_PARKINGBRAKE = 4;
|
|
DEFINITION_ENGINE = 5;
|
|
DEFINITION_THROTTLE = 6;
|
|
DEFINITION_EXITDOOR = 7;
|
|
DEFINITION_FLAPSSPOILERS = 8;
|
|
DEFINITION_SWITCHES = 9;
|
|
DEFINITION_ANTIICE = 10;
|
|
|
|
// EVENT_ZOOM = 10;
|
|
|
|
FSX_UNIT_PERCENT = 'percent';
|
|
FSX_UNIT_MASK = 'mask';
|
|
FSX_UNIT_BOOL = 'bool';
|
|
FSX_UNIT_NUMBER = 'number';
|
|
|
|
FSX_LIGHTON_NAV = $0001;
|
|
FSX_LIGHTON_BEACON = $0002;
|
|
FSX_LIGHTON_LANDING = $0004;
|
|
FSX_LIGHTON_TAXI = $0008;
|
|
FSX_LIGHTON_STROBE = $0010;
|
|
FSX_LIGHTON_PANEL = $0020;
|
|
FSX_LIGHTON_RECOGNITION = $0040;
|
|
FSX_LIGHTON_CABIN = $0200;
|
|
|
|
|
|
type
|
|
TThrottleData = packed record
|
|
NumberOfEngines: Integer;
|
|
ThrottleLeverPos: array[1..MAX_ENGINES] of Double;
|
|
end;
|
|
|
|
|
|
|
|
{ TFSXLEDStateProvider }
|
|
class procedure TFSXLEDStateProvider.EnumFunctions(AConsumer: IFunctionConsumer);
|
|
begin
|
|
inherited;
|
|
|
|
AConsumer.SetCategory('Dynamic');
|
|
|
|
// AConsumer.AddFunction(FUNCTION_FSX_FUELPUMP, 'Fuel boost pump');
|
|
AConsumer.AddFunction(FUNCTION_FSX_AUTOPILOT, 'Auto pilot (main)');
|
|
AConsumer.AddFunction(FUNCTION_FSX_AUTOPILOT_ALTITUDE, 'Auto pilot - Altitude');
|
|
AConsumer.AddFunction(FUNCTION_FSX_AUTOPILOT_AMBER, 'Auto pilot (main - off / amber)');
|
|
AConsumer.AddFunction(FUNCTION_FSX_AUTOPILOT_APPROACH, 'Auto pilot - Approach');
|
|
AConsumer.AddFunction(FUNCTION_FSX_AUTOPILOT_BACKCOURSE, 'Auto pilot - Backcourse');
|
|
AConsumer.AddFunction(FUNCTION_FSX_AUTOPILOT_HEADING, 'Auto pilot - Heading');
|
|
AConsumer.AddFunction(FUNCTION_FSX_AUTOPILOT_NAV, 'Auto pilot - Nav');
|
|
AConsumer.AddFunction(FUNCTION_FSX_AVIONICSMASTER, 'Avionics master switch');
|
|
AConsumer.AddFunction(FUNCTION_FSX_BATTERYMASTER, 'Battery master switch');
|
|
AConsumer.AddFunction(FUNCTION_FSX_BEACONLIGHTS, 'Beacon lights');
|
|
AConsumer.AddFunction(FUNCTION_FSX_DEICE, 'De-ice');
|
|
AConsumer.AddFunction(FUNCTION_FSX_ENGINE, 'Engine');
|
|
AConsumer.AddFunction(FUNCTION_FSX_ENGINEANTIICE, 'Engine anti-ice');
|
|
AConsumer.AddFunction(FUNCTION_FSX_EXITDOOR, 'Exit door');
|
|
AConsumer.AddFunction(FUNCTION_FSX_FLAPS, 'Flaps');
|
|
AConsumer.AddFunction(FUNCTION_FSX_GEAR, 'Landing gear');
|
|
AConsumer.AddFunction(FUNCTION_FSX_INSTRUMENTLIGHTS, 'Instrument lights');
|
|
AConsumer.AddFunction(FUNCTION_FSX_LANDINGLIGHTS, 'Landing lights');
|
|
AConsumer.AddFunction(FUNCTION_FSX_NAVLIGHTS, 'Nav lights');
|
|
AConsumer.AddFunction(FUNCTION_FSX_PARKINGBRAKE, 'Parking brake');
|
|
AConsumer.AddFunction(FUNCTION_FSX_PRESSURIZATIONDUMPSWITCH, 'Pressurization dump switch');
|
|
AConsumer.AddFunction(FUNCTION_FSX_RECOGNITIONLIGHTS, 'Recognition lights');
|
|
AConsumer.AddFunction(FUNCTION_FSX_SPOILERS, 'Spoilers (air brake)');
|
|
AConsumer.AddFunction(FUNCTION_FSX_STROBELIGHTS, 'Strobe lights');
|
|
AConsumer.AddFunction(FUNCTION_FSX_TAILHOOK, 'Tail hook');
|
|
AConsumer.AddFunction(FUNCTION_FSX_TAXILIGHTS, 'Taxi lights');
|
|
end;
|
|
|
|
|
|
constructor TFSXLEDStateProvider.Create(AConsumer: ILEDStateConsumer);
|
|
begin
|
|
inherited;
|
|
|
|
FDefinitions := TList.Create;
|
|
end;
|
|
|
|
|
|
destructor TFSXLEDStateProvider.Destroy;
|
|
begin
|
|
FreeAndNil(FDefinitions);
|
|
|
|
inherited;
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.Initialize;
|
|
begin
|
|
inherited;
|
|
|
|
if not InitSimConnect then
|
|
raise EInitializeError.Create('SimConnect.dll could not be loaded');
|
|
|
|
if SimConnect_Open(FSimConnectHandle, APPNAME, 0, 0, 0, 0) <> S_OK then
|
|
raise EInitializeError.Create('Connection to Flight Simulator could not be established. Is it running?');
|
|
|
|
UpdateMap;
|
|
|
|
// SimConnect_MapClientEventToSimEvent(SimConnectHandle, EVENT_ZOOM, 'VIEW_ZOOM_SET');
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.Finalize;
|
|
begin
|
|
inherited;
|
|
|
|
ClearDefinitions;
|
|
|
|
if SimConnectHandle <> 0 then
|
|
begin
|
|
SimConnect_Close(SimConnectHandle);
|
|
FSimConnectHandle := 0;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.ProcessMessages;
|
|
var
|
|
data: PSimConnectRecv;
|
|
dataSize: Cardinal;
|
|
// down: Boolean;
|
|
// level: Integer;
|
|
// state: Integer;
|
|
|
|
begin
|
|
inherited;
|
|
|
|
while SimConnect_GetNextDispatch(SimConnectHandle, data, dataSize) = S_OK do
|
|
HandleDispatch(data);
|
|
|
|
{
|
|
state := GetKeyState(VK_CONTROL);
|
|
down := ((state and $8000) <> 0);
|
|
if down <> FLastDown then
|
|
begin
|
|
if down then
|
|
level := 4 * 64
|
|
else
|
|
level := 26;
|
|
|
|
SimConnect_TransmitClientEvent(SimConnectHandle, 0, EVENT_ZOOM, level, SIMCONNECT_GROUP_PRIORITY_STANDARD, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
|
FLastDown := down;
|
|
end;
|
|
}
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.UpdateMap;
|
|
var
|
|
engineIndex: Integer;
|
|
|
|
begin
|
|
ClearDefinitions;
|
|
|
|
{ Gear }
|
|
if Consumer.FunctionMap.HasFunction(FUNCTION_FSX_GEAR) then
|
|
begin
|
|
AddVariable(DEFINITION_GEAR, 'IS GEAR RETRACTABLE', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_GEAR, 'GEAR TOTAL PCT EXTENDED', FSX_UNIT_PERCENT, SIMCONNECT_DATAType_FLOAT64);
|
|
AddVariable(DEFINITION_GEAR, 'GEAR DAMAGE BY SPEED', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_GEAR, 'GEAR SPEED EXCEEDED', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddDefinition(DEFINITION_GEAR);
|
|
end;
|
|
|
|
{ Lights }
|
|
if Consumer.FunctionMap.HasFunction([FUNCTION_FSX_LANDINGLIGHTS, FUNCTION_FSX_INSTRUMENTLIGHTS,
|
|
FUNCTION_FSX_STROBELIGHTS, FUNCTION_FSX_NAVLIGHTS,
|
|
FUNCTION_FSX_BEACONLIGHTS, FUNCTION_FSX_TAXILIGHTS,
|
|
FUNCTION_FSX_RECOGNITIONLIGHTS]) then
|
|
begin
|
|
AddVariable(DEFINITION_LIGHTS, 'LIGHT ON STATES', FSX_UNIT_MASK, SIMCONNECT_DATATYPE_INT32);
|
|
AddDefinition(DEFINITION_LIGHTS);
|
|
end;
|
|
|
|
{ Parking brake }
|
|
if Consumer.FunctionMap.HasFunction(FUNCTION_FSX_PARKINGBRAKE) then
|
|
begin
|
|
AddVariable(DEFINITION_PARKINGBRAKE, 'BRAKE PARKING INDICATOR', FSX_UNIT_BOOL, SIMCONNECT_DATATYPE_INT32);
|
|
AddDefinition(DEFINITION_PARKINGBRAKE);
|
|
end;
|
|
|
|
{ Engine }
|
|
if Consumer.FunctionMap.HasFunction(FUNCTION_FSX_ENGINE) then
|
|
begin
|
|
AddVariable(DEFINITION_ENGINE, 'NUMBER OF ENGINES', FSX_UNIT_NUMBER, SIMCONNECT_DATAType_INT32);
|
|
|
|
for engineIndex := 1 to MAX_ENGINES do
|
|
AddVariable(DEFINITION_ENGINE, Format('GENERAL ENG COMBUSTION:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
|
|
for engineIndex := 1 to MAX_ENGINES do
|
|
AddVariable(DEFINITION_ENGINE, Format('ENG FAILED:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
|
|
for engineIndex := 1 to MAX_ENGINES do
|
|
AddVariable(DEFINITION_ENGINE, Format('ENG ON FIRE:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
|
|
AddDefinition(DEFINITION_ENGINE);
|
|
end;
|
|
|
|
{ Exit door }
|
|
if Consumer.FunctionMap.HasFunction(FUNCTION_FSX_EXITDOOR) or
|
|
Consumer.FunctionMap.HasFunction(FUNCTION_FSX_TAILHOOK) then
|
|
begin
|
|
AddVariable(DEFINITION_EXITDOOR, 'CANOPY OPEN', FSX_UNIT_PERCENT, SIMCONNECT_DATAType_FLOAT64);
|
|
AddVariable(DEFINITION_EXITDOOR, 'TAILHOOK POSITION', FSX_UNIT_PERCENT, SIMCONNECT_DATAType_FLOAT64);
|
|
AddDefinition(DEFINITION_EXITDOOR);
|
|
end;
|
|
|
|
{ Flaps & spoilers }
|
|
if Consumer.FunctionMap.HasFunction([FUNCTION_FSX_FLAPS, FUNCTION_FSX_SPOILERS]) then
|
|
begin
|
|
AddVariable(DEFINITION_FLAPSSPOILERS, 'FLAPS AVAILABLE', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_FLAPSSPOILERS, 'FLAPS HANDLE PERCENT', FSX_UNIT_PERCENT, SIMCONNECT_DATAType_FLOAT64);
|
|
AddVariable(DEFINITION_FLAPSSPOILERS, 'SPOILER AVAILABLE', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_FLAPSSPOILERS, 'SPOILERS HANDLE POSITION', FSX_UNIT_PERCENT, SIMCONNECT_DATAType_FLOAT64);
|
|
AddDefinition(DEFINITION_FLAPSSPOILERS);
|
|
end;
|
|
|
|
{ Master switches }
|
|
if Consumer.FunctionMap.HasFunction([FUNCTION_FSX_BATTERYMASTER, FUNCTION_FSX_AVIONICSMASTER,
|
|
FUNCTION_FSX_PRESSURIZATIONDUMPSWITCH,
|
|
FUNCTION_FSX_AUTOPILOT, FUNCTION_FSX_FUELPUMP,
|
|
FUNCTION_FSX_AUTOPILOT_AMBER, FUNCTION_FSX_AUTOPILOT_HEADING,
|
|
FUNCTION_FSX_AUTOPILOT_APPROACH, FUNCTION_FSX_AUTOPILOT_BACKCOURSE,
|
|
FUNCTION_FSX_AUTOPILOT_ALTITUDE, FUNCTION_FSX_AUTOPILOT_NAV]) then
|
|
begin
|
|
AddVariable(DEFINITION_SWITCHES, 'AVIONICS MASTER SWITCH', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_SWITCHES, 'ELECTRICAL MASTER BATTERY', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_SWITCHES, 'PRESSURIZATION DUMP SWITCH', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_SWITCHES, 'AUTOPILOT AVAILABLE', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_SWITCHES, 'AUTOPILOT MASTER', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
// AddVariable(DEFINITION_SWITCHES, 'fuel pump?', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_SWITCHES, 'AUTOPILOT HEADING LOCK', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_SWITCHES, 'AUTOPILOT APPROACH HOLD', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_SWITCHES, 'AUTOPILOT BACKCOURSE HOLD', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_SWITCHES, 'AUTOPILOT ALTITUDE LOCK', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddVariable(DEFINITION_SWITCHES, 'AUTOPILOT NAV1 LOCK', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
|
|
AddDefinition(DEFINITION_SWITCHES);
|
|
end;
|
|
|
|
{ Anti-ice }
|
|
if Consumer.FunctionMap.HasFunction([FUNCTION_FSX_ENGINEANTIICE, FUNCTION_FSX_DEICE]) then
|
|
begin
|
|
AddVariable(DEFINITION_ANTIICE, 'NUMBER OF ENGINES', FSX_UNIT_NUMBER, SIMCONNECT_DATAType_INT32);
|
|
|
|
// for engineIndex := 1 to MAX_ENGINES do
|
|
// AddVariable(DEFINITION_ANTIICE, Format('GENERAL ENG ANTI ICE POSITION:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
//
|
|
// for engineIndex := 1 to MAX_ENGINES do
|
|
// AddVariable(DEFINITION_ANTIICE, Format('PROP DEICE SWITCH:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
|
|
for engineIndex := 1 to MAX_ENGINES do
|
|
AddVariable(DEFINITION_ANTIICE, Format('ENG ANTI ICE:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
|
|
AddVariable(DEFINITION_ANTIICE, 'STRUCTURAL DEICE SWITCH', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
|
AddDefinition(DEFINITION_ANTIICE);
|
|
end;
|
|
|
|
|
|
{ Throttle }
|
|
{
|
|
AddVariable(DEFINITION_THROTTLE, FSX_VARIABLE_NUMBEROFENGINES, FSX_UNIT_NUMBER, SIMCONNECT_DATAType_INT32);
|
|
|
|
for engineIndex := 1 to MAX_ENGINES do
|
|
AddVariable(DEFINITION_THROTTLE, Format(FSX_VARIABLE_ENGTHROTTLELEVERPOS, [engineIndex]), FSX_UNIT_PERCENT);
|
|
|
|
AddDefinition(DEFINITION_THROTTLE);
|
|
}
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.SetFSXLightState(AStates: Cardinal; AMask: Integer; AFunction: Integer);
|
|
begin
|
|
if (AStates and AMask) <> 0 then
|
|
Consumer.SetStateByFunction(AFunction, lsGreen)
|
|
else
|
|
Consumer.SetStateByFunction(AFunction, lsRed);
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.HandleDispatch(AData: PSimConnectRecv);
|
|
var
|
|
simObjectData: PSimConnectRecvSimObjectData;
|
|
data: Pointer;
|
|
// throttleData: PThrottleData;
|
|
|
|
begin
|
|
case SIMCONNECT_RECV_ID(AData^.dwID) of
|
|
SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
|
|
begin
|
|
simObjectData := PSimConnectRecvSimObjectData(AData);
|
|
data := @simObjectData^.dwData;
|
|
|
|
case simObjectData^.dwRequestID of
|
|
DEFINITION_GEAR: HandleGearData(data);
|
|
DEFINITION_LIGHTS: HandleLightsData(data);
|
|
DEFINITION_PARKINGBRAKE: HandleParkingBrakeData(data);
|
|
DEFINITION_ENGINE: HandleEngineData(data);
|
|
DEFINITION_EXITDOOR: HandleExitDoorData(data);
|
|
DEFINITION_FLAPSSPOILERS: HandleFlapsData(data);
|
|
DEFINITION_SWITCHES: HandleSwitchesData(data);
|
|
DEFINITION_ANTIICE: HandleAntiIceData(data);
|
|
{
|
|
DEFINITION_THROTTLE:
|
|
begin
|
|
throttleData := @simObjectData^.dwData;
|
|
|
|
if throttleData^.NumberOfEngines > 2 then
|
|
begin
|
|
if (throttleData^.ThrottleLeverPos[4] <> throttleData^.ThrottleLeverPos[1]) or
|
|
(throttleData^.ThrottleLeverPos[3] <> throttleData^.ThrottleLeverPos[2]) then
|
|
begin
|
|
throttleData^.ThrottleLeverPos[4] := throttleData^.ThrottleLeverPos[1];
|
|
throttleData^.ThrottleLeverPos[3] := throttleData^.ThrottleLeverPos[2];
|
|
|
|
SimConnect_SetDataOnSimObject(SimConnectHandle, DEFINITION_THROTTLE, SIMCONNECT_OBJECT_ID_USER,
|
|
0, 0, SizeOf(throttleData^), throttleData);
|
|
end;
|
|
end;
|
|
end;
|
|
}
|
|
end;
|
|
end;
|
|
|
|
SIMCONNECT_RECV_ID_QUIT:
|
|
Terminate;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.HandleGearData(AData: Pointer);
|
|
type
|
|
PGearData = ^TGearData;
|
|
TGearData = packed record
|
|
IsGearRetractable: Cardinal;
|
|
TotalPctExtended: Double;
|
|
DamageBySpeed: Integer;
|
|
SpeedExceeded: Integer;
|
|
end;
|
|
|
|
var
|
|
gearData: PGearData;
|
|
|
|
begin
|
|
gearData := AData;
|
|
|
|
if gearData^.DamageBySpeed <> 0 then
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_GEAR, lsError)
|
|
|
|
else if gearData^.SpeedExceeded <> 0 then
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_GEAR, lsWarning)
|
|
|
|
else if gearData^.IsGearRetractable <> 0 then
|
|
begin
|
|
case Trunc(gearData ^.TotalPctExtended * 100) of
|
|
0: Consumer.SetStateByFunction(FUNCTION_FSX_GEAR, lsRed);
|
|
95..100: Consumer.SetStateByFunction(FUNCTION_FSX_GEAR, lsGreen);
|
|
else Consumer.SetStateByFunction(FUNCTION_FSX_GEAR, lsAmber);
|
|
end;
|
|
end else
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_GEAR, lsOff);
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.HandleLightsData(AData: Pointer);
|
|
var
|
|
state: Cardinal;
|
|
|
|
begin
|
|
state := PCardinal(AData)^;
|
|
|
|
SetFSXLightState(state, FSX_LIGHTON_LANDING, FUNCTION_FSX_LANDINGLIGHTS);
|
|
SetFSXLightState(state, FSX_LIGHTON_PANEL, FUNCTION_FSX_INSTRUMENTLIGHTS);
|
|
SetFSXLightState(state, FSX_LIGHTON_BEACON, FUNCTION_FSX_BEACONLIGHTS);
|
|
SetFSXLightState(state, FSX_LIGHTON_NAV, FUNCTION_FSX_NAVLIGHTS);
|
|
SetFSXLightState(state, FSX_LIGHTON_STROBE, FUNCTION_FSX_STROBELIGHTS);
|
|
SetFSXLightState(state, FSX_LIGHTON_TAXI, FUNCTION_FSX_TAXILIGHTS);
|
|
SetFSXLightState(state, FSX_LIGHTON_RECOGNITION, FUNCTION_FSX_RECOGNITIONLIGHTS);
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.HandleParkingBrakeData(AData: Pointer);
|
|
begin
|
|
if PCardinal(AData)^ <> 0 then
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_PARKINGBRAKE, lsRed)
|
|
else
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_PARKINGBRAKE, lsGreen);
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.HandleEngineData(AData: Pointer);
|
|
type
|
|
PEngineData = ^TEngineData;
|
|
TEngineData = packed record
|
|
NumberOfEngines: Integer;
|
|
Combustion: array[1..MAX_ENGINES] of Integer;
|
|
Failed: array[1..MAX_ENGINES] of Integer;
|
|
OnFire: array[1..MAX_ENGINES] of Integer;
|
|
end;
|
|
|
|
var
|
|
engineData: PEngineData;
|
|
engineIndex: Integer;
|
|
state: TLEDState;
|
|
|
|
begin
|
|
engineData := AData;
|
|
|
|
if engineData^.NumberOfEngines > 0 then
|
|
begin
|
|
state := lsGreen;
|
|
|
|
for engineIndex := 1 to Min(engineData^.NumberOfEngines, MAX_ENGINES) do
|
|
begin
|
|
if engineData^.OnFire[engineIndex] <> 0 then
|
|
begin
|
|
state := lsError;
|
|
break;
|
|
|
|
end else if engineData^.Failed[engineIndex] <> 0 then
|
|
state := lsWarning
|
|
|
|
else if (engineData^.Combustion[engineIndex] = 0) and
|
|
(state = lsGreen) then
|
|
state := lsRed;
|
|
end;
|
|
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_ENGINE, state);
|
|
end else
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_ENGINE, lsOff);
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.HandleExitDoorData(AData: Pointer);
|
|
type
|
|
PExitDoorData = ^TExitDoorData;
|
|
TExitDoorData = packed record
|
|
PercentOpen: Double;
|
|
TailHookPercent: Double;
|
|
end;
|
|
|
|
var
|
|
exitDoorData: PExitDoorData;
|
|
|
|
begin
|
|
exitDoorData := AData;
|
|
|
|
case Trunc(exitDoorData^.PercentOpen) of
|
|
0: Consumer.SetStateByFunction(FUNCTION_FSX_EXITDOOR, lsGreen);
|
|
95..100: Consumer.SetStateByFunction(FUNCTION_FSX_EXITDOOR, lsRed);
|
|
else Consumer.SetStateByFunction(FUNCTION_FSX_EXITDOOR, lsAmber);
|
|
end;
|
|
|
|
case Trunc(exitDoorData^.TailHookPercent) of
|
|
0: Consumer.SetStateByFunction(FUNCTION_FSX_TAILHOOK, lsGreen);
|
|
95..100: Consumer.SetStateByFunction(FUNCTION_FSX_TAILHOOK, lsRed);
|
|
else Consumer.SetStateByFunction(FUNCTION_FSX_TAILHOOK, lsAmber);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.HandleFlapsData(AData: Pointer);
|
|
type
|
|
PFlapsData = ^TFlapsData;
|
|
TFlapsData = packed record
|
|
FlapsAvailable: Cardinal;
|
|
FlapsHandlePercent: Double;
|
|
SpoilersAvailable: Cardinal;
|
|
SpoilersHandlePercent: Double;
|
|
end;
|
|
|
|
var
|
|
flapsData: PFlapsData;
|
|
|
|
begin
|
|
flapsData := AData;
|
|
|
|
if flapsData^.FlapsAvailable <> 0 then
|
|
begin
|
|
case Trunc(flapsData^.FlapsHandlePercent) of
|
|
0: Consumer.SetStateByFunction(FUNCTION_FSX_FLAPS, lsGreen);
|
|
95..100: Consumer.SetStateByFunction(FUNCTION_FSX_FLAPS, lsRed);
|
|
else Consumer.SetStateByFunction(FUNCTION_FSX_FLAPS, lsAmber);
|
|
end;
|
|
end else
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_FLAPS, lsOff);
|
|
|
|
if flapsData^.SpoilersAvailable <> 0 then
|
|
begin
|
|
case Trunc(flapsData^.SpoilersHandlePercent) of
|
|
0: Consumer.SetStateByFunction(FUNCTION_FSX_SPOILERS, lsGreen);
|
|
95..100: Consumer.SetStateByFunction(FUNCTION_FSX_SPOILERS, lsRed);
|
|
else Consumer.SetStateByFunction(FUNCTION_FSX_SPOILERS, lsAmber);
|
|
end;
|
|
end else
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_SPOILERS, lsOff);
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.HandleSwitchesData(AData: Pointer);
|
|
const
|
|
ONOFF_STATE: array[Boolean] of TLEDState = (lsRed, lsGreen);
|
|
AMBER_ONOFF_STATE: array[Boolean] of TLEDState = (lsOff, lsAmber);
|
|
|
|
type
|
|
PSwitchesData = ^TSwitchesData;
|
|
TSwitchesData = packed record
|
|
AvionicsSwitch: Cardinal;
|
|
BatterySwitch: Cardinal;
|
|
PressurizationDumpSwitch: Cardinal;
|
|
AutoPilotAvailable: Cardinal;
|
|
AutoPilotMaster: Cardinal;
|
|
AutoPilotHeading: Cardinal;
|
|
AutoPilotApproach: Cardinal;
|
|
AutoPilotBackcourse: Cardinal;
|
|
AutoPilotAltitude: Cardinal;
|
|
AutoPilotNav: Cardinal;
|
|
end;
|
|
|
|
var
|
|
switchesData: PSwitchesData;
|
|
|
|
begin
|
|
switchesData := AData;
|
|
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AVIONICSMASTER, ONOFF_STATE[switchesData^.AvionicsSwitch <> 0]);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_BATTERYMASTER, ONOFF_STATE[switchesData^.BatterySwitch <> 0]);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_PRESSURIZATIONDUMPSWITCH, ONOFF_STATE[switchesData^.PressurizationDumpSwitch <> 0]);
|
|
|
|
if switchesData^.AutoPilotAvailable <> 0 then
|
|
begin
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT, ONOFF_STATE[switchesData^.AutoPilotMaster <> 0]);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_AMBER, AMBER_ONOFF_STATE[switchesData^.AutoPilotMaster <> 0]);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_HEADING, AMBER_ONOFF_STATE[switchesData^.AutoPilotHeading <> 0]);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_APPROACH, AMBER_ONOFF_STATE[switchesData^.AutoPilotApproach <> 0]);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_BACKCOURSE, AMBER_ONOFF_STATE[switchesData^.AutoPilotBackcourse <> 0]);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_ALTITUDE, AMBER_ONOFF_STATE[switchesData^.AutoPilotAltitude <> 0]);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_NAV, AMBER_ONOFF_STATE[switchesData^.AutoPilotNav <> 0]);
|
|
end else
|
|
begin
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT, lsOff);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_AMBER, lsOff);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_HEADING, lsOff);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_APPROACH, lsOff);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_BACKCOURSE, lsOff);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_ALTITUDE, lsOff);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_AUTOPILOT_NAV, lsOff);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.HandleAntiIceData(AData: Pointer);
|
|
|
|
function EngineHasBoolean(AArray: array of Integer; ANumberOfEngines: Integer): Boolean;
|
|
var
|
|
engineIndex: Integer;
|
|
|
|
begin
|
|
Result := False;
|
|
|
|
for engineIndex := 1 to Max(ANumberOfEngines, MAX_ENGINES) do
|
|
if AArray[engineIndex] <> 0 then
|
|
begin
|
|
Result := True;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
const
|
|
ONOFF_STATE: array[Boolean] of TLEDState = (lsRed, lsGreen);
|
|
|
|
type
|
|
PAntiIceData = ^TAntiIceData;
|
|
TAntiIceData = packed record
|
|
NumberOfEngines: Integer;
|
|
// GeneralEngineAntiIce: array[1..MAX_ENGINES] of Integer;
|
|
// PropDeIce: array[1..MAX_ENGINES] of Integer;
|
|
EngineAntiIce: array[1..MAX_ENGINES] of Integer;
|
|
StructuralAntiIce: Integer;
|
|
end;
|
|
|
|
var
|
|
antiIceData: PAntiIceData;
|
|
|
|
begin
|
|
antiIceData := AData;
|
|
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_DEICE, ONOFF_STATE[antiIceData^.StructuralAntiIce <> 0]);
|
|
Consumer.SetStateByFunction(FUNCTION_FSX_ENGINEANTIICE, ONOFF_STATE[EngineHasBoolean(antiIceData^.EngineAntiIce, antiIceData^.NumberOfEngines)]);
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.AddDefinition(ADefinition: Cardinal);
|
|
begin
|
|
FDefinitions.Add(Pointer(ADefinition));
|
|
SimConnect_RequestDataOnSimObject(SimConnectHandle,
|
|
ADefinition,
|
|
ADefinition,
|
|
SIMCONNECT_OBJECT_ID_USER,
|
|
SIMCONNECT_PERIOD_SIM_FRAME,
|
|
SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);
|
|
end;
|
|
|
|
|
|
procedure TFSXLEDStateProvider.AddVariable(ADefineID: Cardinal; ADatumName, AUnitsName: string;
|
|
ADatumType: SIMCONNECT_DATAType; AEpsilon: Single;
|
|
ADatumID: DWORD);
|
|
begin
|
|
SimConnect_AddToDataDefinition(SimConnectHandle, ADefineID, AnsiString(ADatumName), AnsiString(AUnitsName), ADatumType, AEpsilon, ADatumID);
|
|
end;
|
|
|
|
procedure TFSXLEDStateProvider.ClearDefinitions;
|
|
var
|
|
definition: Pointer;
|
|
|
|
begin
|
|
if SimConnectHandle <> 0 then
|
|
begin
|
|
for definition in FDefinitions do
|
|
SimConnect_ClearDataDefinition(SimConnectHandle, Cardinal(definition));
|
|
end;
|
|
|
|
FDefinitions.Clear;
|
|
end;
|
|
|
|
|
|
function TFSXLEDStateProvider.GetProcessMessagesInterval: Integer;
|
|
begin
|
|
Result := 50;
|
|
end;
|
|
|
|
end.
|