1
0
mirror of synced 2024-06-17 11:27:38 +00:00

Refactored to single task

This commit is contained in:
Mark van Renswoude 2012-01-04 21:18:12 +00:00
parent 3b34cdef39
commit caec794f3b
9 changed files with 729 additions and 544 deletions

View File

@ -15,7 +15,9 @@ uses
OtlTaskControl,
pngimage,
CustomLEDStateProvider;
LEDFunctionMap,
LEDStateConsumer,
LEDStateProvider;
type
@ -59,10 +61,7 @@ type
// procedure tmrG940InitTimer(Sender: TObject);
private
FEventMonitor: TOmniEventMonitor;
FProviderConsumerChannel: IOmniTwoWayChannel;
FStateConsumerTask: IOmniTaskControl;
FStateProviderWorker: IOmniWorker;
FStateProviderTask: IOmniTaskControl;
// FInitCounter: Integer;
// FInitRedState: Byte;
@ -70,20 +69,17 @@ type
protected
procedure SetDeviceState(const AMessage: string; AFound: Boolean);
procedure InitializeStateProvider(AProviderClass: TCustomLEDStateProviderClass);
procedure InitializeStateProvider(AProviderClass: TLEDStateProviderClass);
procedure FinalizeStateProvider;
procedure UpdateMapping;
procedure UpdateMappingFSX(AFunctionMap: TLEDFunctionMap);
procedure UpdateMappingFSX;
procedure EventMonitorMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
procedure HandleDeviceStateMessage(ATask: IOmniTaskControl; AMessage: TOmniMessage);
property EventMonitor: TOmniEventMonitor read FEventMonitor;
property ProviderConsumerChannel: IOmniTwoWayChannel read FProviderConsumerChannel;
property StateConsumerTask: IOmniTaskControl read FStateConsumerTask;
property StateProviderWorker: IOmniWorker read FStateProviderWorker;
property StateProviderTask: IOmniTaskControl read FStateProviderTask;
end;
@ -96,7 +92,7 @@ uses
OtlTask,
FSXLEDStateProvider,
LEDStateConsumer;
G940LEDStateConsumer;
{$R *.dfm}
@ -122,10 +118,9 @@ var
begin
FEventMonitor := TOmniEventMonitor.Create(Self);
FProviderConsumerChannel := CreateTwoWayChannel(1024);
consumer := TG940LEDStateConsumer.Create(ProviderConsumerChannel.Endpoint1);
FStateConsumerTask := FEventMonitor.Monitor(CreateTask(consumer));
consumer := TG940LEDStateConsumer.Create;
FStateConsumerTask := FEventMonitor.Monitor(CreateTask(consumer)).MsgWait;
// ToDo handle OnTerminate, check exit code for initialization errors
EventMonitor.OnTaskMessage := EventMonitorMessage;
@ -201,55 +196,32 @@ end;
*)
procedure TMainForm.InitializeStateProvider(AProviderClass: TCustomLEDStateProviderClass);
begin
if Assigned(StateProviderTask) then
FinalizeStateProvider;
FStateProviderWorker := AProviderClass.Create(ProviderConsumerChannel.Endpoint2);
FStateProviderTask := CreateTask(StateProviderWorker);
StateProviderTask.Run;
StateProviderTask.WaitForInit;
procedure TMainForm.InitializeStateProvider(AProviderClass: TLEDStateProviderClass);
begin
UpdateMapping;
TLEDStateConsumer.InitializeStateProvider(StateConsumerTask, AProviderClass);
end;
procedure TMainForm.FinalizeStateProvider;
begin
FStateProviderWorker := nil;
if Assigned(StateProviderTask) then
StateProviderTask.Terminate;
FStateProviderTask := nil;
TLEDStateConsumer.FinalizeStateProvider(StateConsumerTask);
end;
procedure TMainForm.UpdateMapping;
var
provider: TCustomLEDStateProvider;
functionMap: TLEDFunctionMap;
begin
if not Assigned(StateProviderWorker) then
if not Assigned(StateConsumerTask) then
Exit;
provider := (StateProviderWorker.Implementor as TCustomLEDStateProvider);
functionMap := provider.LockFunctionMap;
try
UpdateMappingFSX(functionMap);
finally
provider.UnlockFunctionMap;
end;
TLEDStateConsumer.ClearFunctions(StateConsumerTask);
UpdateMappingFSX;
end;
procedure TMainForm.UpdateMappingFSX(AFunctionMap: TLEDFunctionMap);
procedure TMainForm.UpdateMappingFSX;
begin
AFunctionMap.Clear;
AFunctionMap.SetFunction(4, FUNCTION_FSX_GEAR);
TLEDStateConsumer.SetFunction(StateConsumerTask, 3, FUNCTION_FSX_GEAR);
end;
@ -279,24 +251,6 @@ begin
end;
(*
procedure TMainForm.DoStateChange(Sender: TObject; ALEDPosition: Integer; AState: TLEDState);
begin
if not Assigned(ThrottleDevice) then
exit;
// (MvR) 2-1-2012: dit moet slimmer zodra we lsWarning/lsError willen ondersteunen
case AState of
lsOff: SetButtonColor(ThrottleDevice, TLogiPanelButton(Pred(ALEDPosition)), LOGI_OFF);
lsGreen: SetButtonColor(ThrottleDevice, TLogiPanelButton(Pred(ALEDPosition)), LOGI_GREEN);
lsAmber: SetButtonColor(ThrottleDevice, TLogiPanelButton(Pred(ALEDPosition)), LOGI_AMBER);
lsRed: SetButtonColor(ThrottleDevice, TLogiPanelButton(Pred(ALEDPosition)), LOGI_RED);
end;
end;
*)
procedure TMainForm.btnFSXConnectClick(Sender: TObject);
begin
InitializeStateProvider(TFSXLEDStateProvider);

View File

@ -3,9 +3,11 @@ program G940LEDControl;
uses
Forms,
MainFrm in 'Forms\MainFrm.pas' {MainForm},
CustomLEDStateProvider in 'Units\CustomLEDStateProvider.pas',
FSXLEDStateProvider in 'Units\FSXLEDStateProvider.pas',
LEDStateConsumer in 'Units\LEDStateConsumer.pas';
LEDStateConsumer in 'Units\LEDStateConsumer.pas',
LEDStateProvider in 'Units\LEDStateProvider.pas',
LEDFunctionMap in 'Units\LEDFunctionMap.pas',
G940LEDStateConsumer in 'Units\G940LEDStateConsumer.pas';
{$R *.res}

View File

@ -33,106 +33,7 @@
<Borland.Personality>Delphi.Personality</Borland.Personality>
<Borland.ProjectType />
<BorlandProject>
<BorlandProject><Delphi.Personality><Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1043</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Source><Source Name="MainSource">G940LEDControl.dpr</Source></Source> <Excluded_Packages>
<BorlandProject><Delphi.Personality><Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1043</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Source><Source Name="MainSource">G940LEDControl.dpr</Source></Source><Excluded_Packages>
@ -508,8 +409,7 @@
<Excluded_Packages Name="P:\algemeen\bin\D2007\wpViewPDF_D2007.bpl">WPViewPDF - PDFViewClass</Excluded_Packages>
<Excluded_Packages Name="P:\algemeen\bin\D2007\madExceptVcl_.bpl">madExceptVcl 2.0c - www.madshi.net</Excluded_Packages>
<Excluded_Packages Name="D:\Program Files\Developer Express.VCL\Library\Delphi11\dclcxPivotGridOLAPD11.bpl">ExpressPivotGrid 2 OLAP by Developer Express Inc.</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality></BorlandProject></BorlandProject>
</Excluded_Packages></Delphi.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Import Project="$(MSBuildBinPath)\Borland.Delphi.Targets" />
<ItemGroup>
@ -519,8 +419,10 @@
<DCCReference Include="Forms\MainFrm.pas">
<Form>MainForm</Form>
</DCCReference>
<DCCReference Include="Units\CustomLEDStateProvider.pas" />
<DCCReference Include="Units\FSXLEDStateProvider.pas" />
<DCCReference Include="Units\G940LEDStateConsumer.pas" />
<DCCReference Include="Units\LEDFunctionMap.pas" />
<DCCReference Include="Units\LEDStateConsumer.pas" />
<DCCReference Include="Units\LEDStateProvider.pas" />
</ItemGroup>
</Project>

View File

@ -1,158 +0,0 @@
unit CustomLEDStateProvider;
interface
uses
Classes,
SyncObjs,
OtlComm,
OtlTaskControl;
const
MAX_LEDS = 8;
FUNCTION_NONE = 0;
MSG_EXECUTE = 10;
MSG_UPDATEFUNCTIONMAP = 11;
MSG_SETSTATEBYFUNCTION = 12;
type
TLEDState = (lsOff, lsGreen, lsAmber, lsRed, lsWarning, lsError);
// todo implement assign
TLEDFunctionMap = class(TPersistent)
private
FFunctions: array[0..MAX_LEDS - 1] of Integer;
function GetCount: Integer;
public
procedure Clear;
procedure SetFunction(ALEDIndex, AFunction: Integer);
function GetFunction(ALEDIndex: Integer): Integer;
property Count: Integer read GetCount;
end;
TCustomLEDStateProvider = class(TOmniWorker)
private
FConsumerChannel: IOmniCommunicationEndpoint;
FFunctionMap: TLEDFunctionMap;
FFunctionMapLock: TCriticalSection;
FState: array[0..MAX_LEDS - 1] of TLEDState;
protected
procedure MsgExecute(var msg: TOmniMessage); message MSG_EXECUTE;
protected
function Initialize: Boolean; override;
procedure Execute; virtual; abstract;
procedure SetStateByFunction(AFunction: Integer; AState: TLEDState);
property ConsumerChannel: IOmniCommunicationEndpoint read FConsumerChannel;
public
constructor Create(AConsumerChannel: IOmniCommunicationEndpoint);
destructor Destroy; override;
function LockFunctionMap: TLEDFunctionMap;
procedure UnlockFunctionMap;
end;
TCustomLEDStateProviderClass = class of TCustomLEDStateProvider;
implementation
uses
SysUtils;
{ TCustomLEDStateProvider }
constructor TCustomLEDStateProvider.Create(AConsumerChannel: IOmniCommunicationEndpoint);
var
ledIndex: Integer;
begin
inherited Create;
FConsumerChannel := AConsumerChannel;
FFunctionMap := TLEDFunctionMap.Create;
FFunctionMapLock := TCriticalSection.Create;
for ledIndex := Low(FState) to High(FState) do
FState[ledIndex] := lsGreen;
end;
destructor TCustomLEDStateProvider.Destroy;
begin
FreeAndNil(FFunctionMap);
FreeAndNil(FFunctionMapLock);
inherited;
end;
function TCustomLEDStateProvider.Initialize: Boolean;
begin
Result := True;
Task.Comm.OtherEndpoint.Send(MSG_EXECUTE);
end;
function TCustomLEDStateProvider.LockFunctionMap: TLEDFunctionMap;
begin
FFunctionMapLock.Acquire;
Result := FFunctionMap;
end;
procedure TCustomLEDStateProvider.UnlockFunctionMap;
begin
FFunctionMapLock.Release;
Task.Comm.Send(MSG_UPDATEFUNCTIONMAP, Self);
end;
procedure TCustomLEDStateProvider.SetStateByFunction(AFunction: Integer; AState: TLEDState);
begin
ConsumerChannel.Send(MSG_SETSTATEBYFUNCTION, [AFunction, Ord(AState)]);
end;
procedure TCustomLEDStateProvider.MsgExecute(var msg: TOmniMessage);
begin
Execute;
end;
{ TLEDFunctionMap }
procedure TLEDFunctionMap.Clear;
var
ledPosition: Integer;
begin
for ledPosition := Low(FFunctions) to High(FFunctions) do
FFunctions[ledPosition] := FUNCTION_NONE;
end;
procedure TLEDFunctionMap.SetFunction(ALEDIndex, AFunction: Integer);
begin
FFunctions[ALEDIndex] := AFunction;
end;
function TLEDFunctionMap.GetFunction(ALEDIndex: Integer): Integer;
begin
Result := FFunctions[ALEDIndex];
end;
function TLEDFunctionMap.GetCount: Integer;
begin
Result := Length(FFunctions);
end;
end.

View File

@ -4,8 +4,9 @@ interface
uses
Classes,
SyncObjs,
CustomLEDStateProvider,
LEDStateConsumer,
LEDStateProvider,
SimConnect;
@ -17,25 +18,33 @@ const
type
TFSXLEDStateProvider = class(TCustomLEDStateProvider)
TFSXLEDStateProvider = class(TLEDStateProvider)
private
FSimConnectHandle: THandle;
FUseFunctionGear: Boolean;
protected
procedure Execute; override;
function GetProcessMessagesInterval: Integer; override;
procedure UpdateMap(AConnection: THandle);
procedure SetInitialState;
procedure UpdateMap;
procedure HandleDispatch(AData: PSimConnectRecv);
function GetDataDouble(var AData: Cardinal): Double;
property SimConnectHandle: THandle read FSimConnectHandle;
public
procedure Initialize; override;
procedure Finalize; override;
procedure ProcessMessages; override;
end;
implementation
uses
ComObj,
SysUtils;
SysUtils,
LEDFunctionMap;
const
@ -52,80 +61,73 @@ const
{ TFSXLEDStateProvider }
procedure TFSXLEDStateProvider.Execute;
var
connection: THandle;
data: PSimConnectRecv;
dataSize: Cardinal;
procedure TFSXLEDStateProvider.Initialize;
begin
if not InitSimConnect then
raise EInitializeError.Create('SimConnect.dll could not be loaded', EXIT_ERROR_INITSIMCONNECT);
if SimConnect_Open(FSimConnectHandle, APPNAME, 0, 0, 0, 0) <> S_OK then
raise EInitializeError.Create('Connection to Flight Simulator could not be established', EXIT_ERROR_CONNECT);
UpdateMap;
SetInitialState;
end;
procedure TFSXLEDStateProvider.Finalize;
begin
inherited;
if SimConnectHandle <> 0 then
begin
Task.SetExitStatus(EXIT_ERROR_INITSIMCONNECT, 'SimConnect.dll could not be loaded');
Task.Terminate;
exit;
end;
if SimConnect_Open(connection, APPNAME, 0, 0, 0, 0) = S_OK then
try
UpdateMap(connection);
while not Task.Terminated do
begin
if SimConnect_GetNextDispatch(connection, data, dataSize) = S_OK then
HandleDispatch(data);
ProcessMessages;
Sleep(1);
end;
finally
SimConnect_Close(connection);
end else
begin
Task.SetExitStatus(EXIT_ERROR_CONNECT, 'Connection to Flight Simulator could not be established');
Task.Terminate;
SimConnect_Close(SimConnectHandle);
FSimConnectHandle := 0;
end;
end;
procedure TFSXLEDStateProvider.UpdateMap(AConnection: THandle);
procedure TFSXLEDStateProvider.ProcessMessages;
var
functionMap: TLEDFunctionMap;
data: PSimConnectRecv;
dataSize: Cardinal;
function HasFunction(AFunction: Integer): Boolean;
var
ledIndex: Integer;
begin
Result := False;
for ledIndex := 0 to Pred(functionMap.Count) do
if functionMap.GetFunction(ledIndex) = AFunction then
begin
Result := True;
break;
end;
end;
begin
SimConnect_ClearDataDefinition(AConnection, DEFINITION_GEAR);
inherited;
functionMap := LockFunctionMap;
try
if HasFunction(FUNCTION_FSX_GEAR) then
begin
SimConnect_AddToDataDefinition(AConnection, DEFINITION_GEAR,
FSX_VARIABLE_GEARTOTALPCTEXTENDED,
FSX_UNIT_PERCENT);
SimConnect_RequestDataOnSimObject(AConnection, REQUEST_GEAR,
DEFINITION_GEAR,
SIMCONNECT_OBJECT_ID_USER,
SIMCONNECT_PERIOD_SIM_FRAME,
SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);
end;
finally
UnlockFunctionMap;
while SimConnect_GetNextDispatch(SimConnectHandle, data, dataSize) = S_OK do
HandleDispatch(data);
end;
procedure TFSXLEDStateProvider.SetInitialState;
begin
// if FUseFunctionGear then
// begin
// SimConnect_RequestDataOnSimObject(SimConnectHandle, REQUEST_GEAR,
// DEFINITION_GEAR,
// SIMCONNECT_OBJECT_ID_USER,
// SIMCONNECT_PERIOD_ONCE,
// SIMCONNECT_DATA_REQUEST_FLAG_DEFAULT);
// end;
end;
procedure TFSXLEDStateProvider.UpdateMap;
begin
if FUseFunctionGear then
SimConnect_ClearDataDefinition(SimConnectHandle, DEFINITION_GEAR);
FUseFunctionGear := Consumer.FunctionMap.HasFunction(FUNCTION_FSX_GEAR);
if FUseFunctionGear then
begin
SimConnect_AddToDataDefinition(SimConnectHandle, DEFINITION_GEAR,
FSX_VARIABLE_GEARTOTALPCTEXTENDED,
FSX_UNIT_PERCENT);
SimConnect_RequestDataOnSimObject(SimConnectHandle, REQUEST_GEAR,
DEFINITION_GEAR,
SIMCONNECT_OBJECT_ID_USER,
SIMCONNECT_PERIOD_SECOND,
SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);
end;
end;
@ -144,16 +146,16 @@ begin
REQUEST_GEAR:
begin
case Trunc(GetDataDouble(simObjectData^.dwData) * 100) of
0: SetStateByFunction(FUNCTION_FSX_GEAR, lsRed);
100: SetStateByFunction(FUNCTION_FSX_GEAR, lsGreen);
else SetStateByFunction(FUNCTION_FSX_GEAR, lsAmber);
0: Consumer.SetStateByFunction(FUNCTION_FSX_GEAR, lsRed);
100: Consumer.SetStateByFunction(FUNCTION_FSX_GEAR, lsGreen);
else Consumer.SetStateByFunction(FUNCTION_FSX_GEAR, lsAmber);
end;
end;
end;
end;
SIMCONNECT_RECV_ID_QUIT:
Task.Terminate;
Terminate;
end;
end;
@ -163,4 +165,10 @@ begin
Result := PDouble(@AData)^;
end;
function TFSXLEDStateProvider.GetProcessMessagesInterval: Integer;
begin
Result := 50;
end;
end.

View File

@ -0,0 +1,190 @@
unit G940LEDStateConsumer;
interface
uses
Classes,
DirectInput,
OtlComm,
OtlTaskControl,
LEDFunctionMap,
LEDStateConsumer;
const
MSG_FINDTHROTTLEDEVICE = MSG_CONSUMER_OFFSET + 1;
type
TG940LEDStateConsumer = class(TLEDStateConsumer)
private
FDirectInput: IDirectInput8;
FThrottleDevice: IDirectInputDevice8;
protected
procedure MsgFindThrottleDevice(var msg: TOmniMessage); message MSG_FINDTHROTTLEDEVICE;
protected
function Initialize: Boolean; override;
procedure LEDStateChanged(ALEDIndex: Integer; AState: TLEDState); override;
procedure FindThrottleDevice;
procedure FoundThrottleDevice(ADeviceGUID: TGUID);
procedure SetDeviceState(AState: Integer);
property DirectInput: IDirectInput8 read FDirectInput;
property ThrottleDevice: IDirectInputDevice8 read FThrottleDevice;
end;
const
MSG_NOTIFY_DEVICESTATE = 1;
DEVICESTATE_SEARCHING = 0;
DEVICESTATE_FOUND = 1;
DEVICESTATE_NOTFOUND = 2;
EXIT_ERROR_LOGIJOYSTICKDLL = 1;
EXIT_ERROR_DIRECTINPUT = 2;
implementation
uses
SysUtils,
Windows,
LogiJoystickDLL;
function EnumDevicesProc(var lpddi: TDIDeviceInstanceA; pvRef: Pointer): BOOL; stdcall;
var
vendorID: Word;
productID: Word;
begin
Result := True;
vendorID := LOWORD(lpddi.guidProduct.D1);
productID := HIWORD(lpddi.guidProduct.D1);
if (vendorID = VENDOR_LOGITECH) and
(productID = PRODUCT_G940_THROTTLE) then
begin
TG940LEDStateConsumer(pvRef).FoundThrottleDevice(lpddi.guidInstance);
Result := False;
end;
end;
{ TG940LEDStateConsumer }
function TG940LEDStateConsumer.Initialize: Boolean;
begin
Result := inherited Initialize;
if not Result then
exit;
Result := False;
if not LogiJoystickDLLInitialized then
begin
Task.SetExitStatus(EXIT_ERROR_LOGIJOYSTICKDLL, 'Could not load LogiJoystickDLL.dll');
exit;
end;
// btnRetry.Visible := False;
// SetState(STATE_SEARCHING, False);
if DirectInput8Create(SysInit.HInstance, DIRECTINPUT_VERSION, IDirectInput8, FDirectInput, nil) <> S_OK then
begin
Task.SetExitStatus(EXIT_ERROR_DIRECTINPUT, 'Failed to initialize DirectInput');
exit;
end;
Result := True;
Task.Comm.OtherEndpoint.Send(MSG_FINDTHROTTLEDEVICE);
end;
procedure TG940LEDStateConsumer.LEDStateChanged(ALEDIndex: Integer; AState: TLEDState);
var
color: TLogiColor;
begin
// ToDo SetLEDs gebruiken (vereist override van SetStateByFunction om te groeperen)
if Assigned(ThrottleDevice) then
begin
color := LOGI_GREEN;
case AState of
lsOff: color := LOGI_OFF;
lsGreen: color := LOGI_GREEN;
lsAmber: color := LOGI_AMBER;
lsRed: color := LOGI_RED;
// ToDo timers voor warning / error
lsWarning: color := LOGI_RED;
lsError: color := LOGI_RED;
end;
SetButtonColor(ThrottleDevice, TLogiPanelButton(ALEDIndex), color);
ProcessMessages;
end;
end;
procedure TG940LEDStateConsumer.FindThrottleDevice;
begin
SetDeviceState(DEVICESTATE_SEARCHING);
DirectInput.EnumDevices(DI8DEVCLASS_GAMECTRL,
EnumDevicesProc,
Pointer(Self),
DIEDFL_ATTACHEDONLY);
if not Assigned(ThrottleDevice) then
SetDeviceState(DEVICESTATE_NOTFOUND);
end;
procedure TG940LEDStateConsumer.FoundThrottleDevice(ADeviceGUID: TGUID);
begin
if DirectInput.CreateDevice(ADeviceGUID, FThrottleDevice, nil) = S_OK then
SetDeviceState(DEVICESTATE_FOUND);
end;
procedure TG940LEDStateConsumer.SetDeviceState(AState: Integer);
begin
Task.Comm.Send(MSG_NOTIFY_DEVICESTATE, AState);
end;
procedure TG940LEDStateConsumer.MsgFindThrottleDevice(var msg: TOmniMessage);
begin
FindThrottleDevice;
end;
//procedure TCustomLEDStateProvider.SetStateByFunction(AFunction: Integer; AState: TLEDState);
//var
// functionMap: TLEDFunctionMap;
// ledIndex: Integer;
//
//begin
// functionMap := LockFunctionMap;
// try
// for ledIndex := 0 to Pred(functionMap.Count) do
// if functionMap.GetFunction(ledIndex) = AFunction then
// begin
// if AState <> FState[ledIndex] then
// begin
// FState[ledIndex] := AState;
// ConsumerChannel.Send(MSG_STATECHANGED, [ledIndex, Ord(AState)]);
// end;
// end;
// finally
// UnlockFunctionMap;
// end;
//end;
end.

View File

@ -0,0 +1,174 @@
unit LEDFunctionMap;
interface
uses
Classes,
SyncObjs,
X2UtHashes;
type
TLEDState = (lsOff, lsGreen, lsAmber, lsRed, lsWarning, lsError);
TLEDFunctionMap = class(TObject)
private
FFunctions: TX2IIHash;
protected
function Find(AFunction: Integer; out ALEDIndex: Integer): Boolean;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure SetFunction(ALEDIndex, AFunction: Integer);
function GetFunction(ALEDIndex: Integer): Integer;
function HasFunction(AFunction: Integer): Boolean;
function FindFirst(AFunction: Integer; out ALEDIndex: Integer): Boolean;
function FindNext(AFunction: Integer; out ALEDIndex: Integer): Boolean;
end;
TLEDStateMap = class(TObject)
private
FStates: TX2IIHash;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
function GetState(ALEDIndex: Integer; ADefault: TLEDState = lsGreen): TLEDState;
function SetState(ALEDIndex: Integer; AState: TLEDState): Boolean;
end;
const
FUNCTION_NONE = 0;
implementation
uses
SysUtils;
{ TLEDFunctionMap }
constructor TLEDFunctionMap.Create;
begin
inherited;
FFunctions := TX2IIHash.Create;
end;
destructor TLEDFunctionMap.Destroy;
begin
FreeAndNil(FFunctions);
inherited;
end;
procedure TLEDFunctionMap.Clear;
begin
FFunctions.Clear;
end;
procedure TLEDFunctionMap.SetFunction(ALEDIndex, AFunction: Integer);
begin
FFunctions[ALEDIndex] := AFunction;
end;
function TLEDFunctionMap.GetFunction(ALEDIndex: Integer): Integer;
begin
Result := FFunctions[ALEDIndex];
end;
function TLEDFunctionMap.HasFunction(AFunction: Integer): Boolean;
var
ledIndex: Integer;
begin
Result := FindFirst(AFunction, ledIndex);
end;
function TLEDFunctionMap.FindFirst(AFunction: Integer; out ALEDIndex: Integer): Boolean;
begin
FFunctions.First;
Result := Find(AFunction, ALEDIndex);
end;
function TLEDFunctionMap.FindNext(AFunction: Integer; out ALEDIndex: Integer): Boolean;
begin
Result := Find(AFunction, ALEDIndex);
end;
function TLEDFunctionMap.Find(AFunction: Integer; out ALEDIndex: Integer): Boolean;
begin
Result := False;
while FFunctions.Next do
begin
if FFunctions.CurrentValue = AFunction then
begin
ALEDIndex := FFunctions.CurrentKey;
Result := True;
break;
end;
end;
end;
{ TLEDStateMap }
constructor TLEDStateMap.Create;
begin
inherited;
FStates := TX2IIHash.Create;
end;
destructor TLEDStateMap.Destroy;
begin
FreeAndNil(FStates);
inherited;
end;
procedure TLEDStateMap.Clear;
begin
FStates.Clear;
end;
function TLEDStateMap.GetState(ALEDIndex: Integer; ADefault: TLEDState): TLEDState;
begin
Result := ADefault;
if FStates.Exists(ALEDIndex) then
Result := TLEDState(FStates[ALEDIndex]);
end;
function TLEDStateMap.SetState(ALEDIndex: Integer; AState: TLEDState): Boolean;
begin
if FStates.Exists(ALEDIndex) then
Result := (FStates[ALEDIndex] <> Ord(AState))
else
Result := True;
if Result then
FStates[ALEDIndex] := Ord(AState);
end;
end.

View File

@ -2,202 +2,204 @@ unit LEDStateConsumer;
interface
uses
DirectInput,
OtlComm,
OtlTaskControl,
CustomLEDStateProvider;
LEDFunctionMap,
LEDStateProvider;
const
MSG_CLEAR_FUNCTIONS = 1;
MSG_SET_FUNCTION = 2;
MSG_INITIALIZE_PROVIDER = 3;
MSG_FINALIZE_PROVIDER = 4;
MSG_PROCESS_MESSAGES = 5;
MSG_CONSUMER_OFFSET = MSG_PROCESS_MESSAGES;
TIMER_PROCESSMESSAGES = 1;
const
MSG_FINDTHROTTLEDEVICE = 1;
MSG_NOTIFY_DEVICESTATE = 2;
type
TG940LEDStateConsumer = class(TOmniWorker)
TLEDStateConsumer = class(TOmniWorker, ILEDStateConsumer)
private
FProviderChannel: IOmniCommunicationEndpoint;
FDirectInput: IDirectInput8;
FThrottleDevice: IDirectInputDevice8;
FFunctionMap: TLEDFunctionMap;
FStateMap: TLEDStateMap;
FProvider: TLEDStateProvider;
FTimerSet: Boolean;
protected
procedure MsgFindThrottleDevice(var msg: TOmniMessage); message MSG_FINDTHROTTLEDEVICE;
procedure MsgUpdateFunctionMap(var msg: TOmniMessage); message MSG_UPDATEFUNCTIONMAP;
procedure MsgSetStateByFunction(var msg: TOmniMessage); message MSG_SETSTATEBYFUNCTION;
protected
function Initialize: Boolean; override;
procedure MsgClearFunctions(var msg: TOmniMessage); message MSG_CLEAR_FUNCTIONS;
procedure MsgSetFunction(var msg: TOmniMessage); message MSG_SET_FUNCTION;
procedure MsgInitializeProvider(var msg: TOmniMessage); message MSG_INITIALIZE_PROVIDER;
procedure MsgFinalizeProvider(var msg: TOmniMessage); message MSG_FINALIZE_PROVIDER;
procedure MsgProcessMessages(var msg: TOmniMessage); message MSG_PROCESS_MESSAGES;
procedure FindThrottleDevice;
procedure FoundThrottleDevice(ADeviceGUID: TGUID);
procedure InitializeProvider(AProviderClass: TLEDStateProviderClass);
procedure FinalizeProvider;
procedure SetDeviceState(AState: Integer);
procedure LEDStateChanged(ALEDIndex: Integer; AState: TLEDState); virtual;
property DirectInput: IDirectInput8 read FDirectInput;
property ThrottleDevice: IDirectInputDevice8 read FThrottleDevice;
{ ILEDStateConsumer }
function GetFunctionMap: TLEDFunctionMap;
procedure SetStateByFunction(AFunction: Integer; AState: TLEDState);
property FunctionMap: TLEDFunctionMap read GetFunctionMap;
property StateMap: TLEDStateMap read FStateMap;
property Provider: TLEDStateProvider read FProvider;
public
constructor Create(AProviderChannel: IOmniCommunicationEndpoint);
constructor Create;
destructor Destroy; override;
class procedure ClearFunctions(AConsumer: IOmniTaskControl);
class procedure SetFunction(AConsumer: IOmniTaskControl; ALEDIndex, AFunction: Integer);
class procedure InitializeStateProvider(AConsumer: IOmniTaskControl; AProviderClass: TLEDStateProviderClass);
class procedure FinalizeStateProvider(AConsumer: IOmniTaskControl);
end;
const
EXIT_ERROR_LOGIJOYSTICKDLL = 1;
EXIT_ERROR_DIRECTINPUT = 2;
DEVICESTATE_SEARCHING = 0;
DEVICESTATE_FOUND = 1;
DEVICESTATE_NOTFOUND = 2;
implementation
uses
SysUtils,
Windows,
LogiJoystickDLL;
OtlCommon;
function EnumDevicesProc(var lpddi: TDIDeviceInstanceA; pvRef: Pointer): BOOL; stdcall;
var
vendorID: Word;
productID: Word;
{ TLEDStateConsumer }
constructor TLEDStateConsumer.Create;
begin
Result := True;
inherited;
vendorID := LOWORD(lpddi.guidProduct.D1);
productID := HIWORD(lpddi.guidProduct.D1);
if (vendorID = VENDOR_LOGITECH) and
(productID = PRODUCT_G940_THROTTLE) then
begin
TG940LEDStateConsumer(pvRef).FoundThrottleDevice(lpddi.guidInstance);
Result := False;
end;
end;
{ TG940LEDStateConsumer }
constructor TG940LEDStateConsumer.Create(AProviderChannel: IOmniCommunicationEndpoint);
begin
inherited Create;
FProviderChannel := AProviderChannel;
FFunctionMap := TLEDFunctionMap.Create;
FStateMap := TLEDStateMap.Create;
end;
destructor TG940LEDStateConsumer.Destroy;
destructor TLEDStateConsumer.Destroy;
begin
FinalizeProvider;
FreeAndNil(FStateMap);
FreeAndNil(FFunctionMap);
inherited;
end;
function TG940LEDStateConsumer.Initialize: Boolean;
function TLEDStateConsumer.GetFunctionMap: TLEDFunctionMap;
begin
Result := False;
if not LogiJoystickDLLInitialized then
begin
Task.SetExitStatus(EXIT_ERROR_LOGIJOYSTICKDLL, 'Could not load LogiJoystickDLL.dll');
exit;
end;
// btnRetry.Visible := False;
// SetState(STATE_SEARCHING, False);
if DirectInput8Create(SysInit.HInstance, DIRECTINPUT_VERSION, IDirectInput8, FDirectInput, nil) <> S_OK then
begin
Task.SetExitStatus(EXIT_ERROR_DIRECTINPUT, 'Failed to initialize DirectInput');
exit;
end;
Result := True;
Task.RegisterComm(FProviderChannel);
FindThrottleDevice;
Result := FFunctionMap;
end;
procedure TG940LEDStateConsumer.FindThrottleDevice;
begin
SetDeviceState(DEVICESTATE_SEARCHING);
DirectInput.EnumDevices(DI8DEVCLASS_GAMECTRL,
EnumDevicesProc,
Pointer(Self),
DIEDFL_ATTACHEDONLY);
if not Assigned(ThrottleDevice) then
SetDeviceState(DEVICESTATE_NOTFOUND);
end;
procedure TG940LEDStateConsumer.FoundThrottleDevice(ADeviceGUID: TGUID);
begin
if DirectInput.CreateDevice(ADeviceGUID, FThrottleDevice, nil) = S_OK then
SetDeviceState(DEVICESTATE_FOUND);
end;
procedure TG940LEDStateConsumer.SetDeviceState(AState: Integer);
begin
Task.Comm.Send(MSG_NOTIFY_DEVICESTATE, AState);
end;
procedure TG940LEDStateConsumer.MsgFindThrottleDevice(var msg: TOmniMessage);
begin
FindThrottleDevice;
end;
procedure TG940LEDStateConsumer.MsgUpdateFunctionMap(var msg: TOmniMessage);
procedure TLEDStateConsumer.SetStateByFunction(AFunction: Integer; AState: TLEDState);
var
provider: TCustomLEDStateProvider;
functionMap: TLEDFunctionMap;
ledIndex: Integer;
begin
provider := (msg.MsgData.AsObject as TCustomLEDStateProvider);
functionMap := provider.LockFunctionMap;
try
FFunctionMap.Assign(functionMap);
finally
provider.UnlockFunctionMap;
if FunctionMap.FindFirst(AFunction, ledIndex) then
repeat
if StateMap.SetState(ledIndex, AState) then
LEDStateChanged(ledIndex, AState);
until not FunctionMap.FindNext(AFunction, ledIndex);
end;
procedure TLEDStateConsumer.MsgClearFunctions(var msg: TOmniMessage);
begin
FunctionMap.Clear;
end;
procedure TLEDStateConsumer.MsgSetFunction(var msg: TOmniMessage);
var
values: TOmniValueContainer;
begin
values := msg.MsgData.AsArray;
FunctionMap.SetFunction(values[0], values[1]);
end;
procedure TLEDStateConsumer.MsgInitializeProvider(var msg: TOmniMessage);
begin
InitializeProvider(TLEDStateProviderClass(msg.MsgData.AsPointer));
end;
procedure TLEDStateConsumer.MsgFinalizeProvider(var msg: TOmniMessage);
begin
FinalizeProvider;
end;
procedure TLEDStateConsumer.MsgProcessMessages(var msg: TOmniMessage);
begin
Provider.ProcessMessages;
end;
procedure TLEDStateConsumer.InitializeProvider(AProviderClass: TLEDStateProviderClass);
begin
FinalizeProvider;
FProvider := AProviderClass.Create(Self);
// ToDo exception handlign
Provider.Initialize;
if Provider.ProcessMessagesInterval > -1 then
begin
Task.SetTimer(TIMER_PROCESSMESSAGES, Provider.ProcessMessagesInterval, MSG_PROCESS_MESSAGES);
FTimerSet := True;
end;
end;
procedure TG940LEDStateConsumer.MsgSetStateByFunction(var msg: TOmniMessage);
procedure TLEDStateConsumer.FinalizeProvider;
begin
//
if Assigned(Provider) then
begin
if FTimerSet then
begin
Task.ClearTimer(TIMER_PROCESSMESSAGES);
FTimerSet := False;
end;
Provider.Terminate;
Provider.Finalize;
FreeAndNil(FProvider);
end;
end;
//procedure TCustomLEDStateProvider.SetStateByFunction(AFunction: Integer; AState: TLEDState);
//var
// functionMap: TLEDFunctionMap;
// ledIndex: Integer;
//
//begin
// functionMap := LockFunctionMap;
// try
// for ledIndex := 0 to Pred(functionMap.Count) do
// if functionMap.GetFunction(ledIndex) = AFunction then
// begin
// if AState <> FState[ledIndex] then
// begin
// FState[ledIndex] := AState;
// ConsumerChannel.Send(MSG_STATECHANGED, [ledIndex, Ord(AState)]);
// end;
// end;
// finally
// UnlockFunctionMap;
// end;
//end;
procedure TLEDStateConsumer.LEDStateChanged(ALEDIndex: Integer; AState: TLEDState);
begin
end;
class procedure TLEDStateConsumer.ClearFunctions(AConsumer: IOmniTaskControl);
begin
AConsumer.Comm.Send(MSG_CLEAR_FUNCTIONS);
end;
class procedure TLEDStateConsumer.SetFunction(AConsumer: IOmniTaskControl; ALEDIndex, AFunction: Integer);
begin
AConsumer.Comm.Send(MSG_SET_FUNCTION, [ALEDIndex, AFunction]);
end;
class procedure TLEDStateConsumer.InitializeStateProvider(AConsumer: IOmniTaskControl; AProviderClass: TLEDStateProviderClass);
begin
AConsumer.Comm.Send(MSG_INITIALIZE_PROVIDER, Pointer(AProviderClass));
end;
class procedure TLEDStateConsumer.FinalizeStateProvider(AConsumer: IOmniTaskControl);
begin
AConsumer.Comm.Send(MSG_FINALIZE_PROVIDER);
end;
end.

View File

@ -0,0 +1,111 @@
unit LEDStateProvider;
interface
uses
Classes,
SyncObjs,
SysUtils,
LEDFunctionMap;
type
EInitializeError = class(Exception)
private
FExitCode: Integer;
public
constructor Create(const Msg: string; ExitCode: Integer = 0);
property ExitCode: Integer read FExitCode write FExitCode;
end;
ILEDStateConsumer = interface
['{6E630C92-7C5C-4D16-8BED-AE27559FA584}']
function GetFunctionMap: TLEDFunctionMap;
procedure SetStateByFunction(AFunction: Integer; AState: TLEDState);
property FunctionMap: TLEDFunctionMap read GetFunctionMap;
end;
TLEDStateProvider = class(TObject)
private
FConsumer: ILEDStateConsumer;
FTerminated: Boolean;
protected
procedure Execute; virtual; abstract;
function GetProcessMessagesInterval: Integer; virtual;
property Consumer: ILEDStateConsumer read FConsumer;
public
constructor Create(AConsumer: ILEDStateConsumer);
destructor Destroy; override;
procedure Initialize; virtual;
procedure Finalize; virtual;
procedure ProcessMessages; virtual;
procedure Terminate; virtual;
property ProcessMessagesInterval: Integer read GetProcessMessagesInterval;
property Terminated: Boolean read FTerminated;
end;
TLEDStateProviderClass = class of TLEDStateProvider;
implementation
{ TCustomLEDStateProvider }
constructor TLEDStateProvider.Create(AConsumer: ILEDStateConsumer);
begin
inherited Create;
FConsumer := AConsumer;
end;
destructor TLEDStateProvider.Destroy;
begin
inherited;
end;
procedure TLEDStateProvider.Initialize;
begin
end;
procedure TLEDStateProvider.Finalize;
begin
end;
procedure TLEDStateProvider.ProcessMessages;
begin
end;
procedure TLEDStateProvider.Terminate;
begin
FTerminated := True;
end;
function TLEDStateProvider.GetProcessMessagesInterval: Integer;
begin
Result := -1;
end;
{ EInitializeError }
constructor EInitializeError.Create(const Msg: string; ExitCode: Integer);
begin
inherited Create(Msg);
FExitCode := ExitCode;
end;
end.