diff --git a/G940LEDControl/Forms/MainFrm.pas b/G940LEDControl/Forms/MainFrm.pas
index 928190e..4bff79c 100644
--- a/G940LEDControl/Forms/MainFrm.pas
+++ b/G940LEDControl/Forms/MainFrm.pas
@@ -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);
diff --git a/G940LEDControl/G940LEDControl.dpr b/G940LEDControl/G940LEDControl.dpr
index 117f33c..afd24b9 100644
--- a/G940LEDControl/G940LEDControl.dpr
+++ b/G940LEDControl/G940LEDControl.dpr
@@ -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}
diff --git a/G940LEDControl/G940LEDControl.dproj b/G940LEDControl/G940LEDControl.dproj
index 210224b..29bf0e4 100644
--- a/G940LEDControl/G940LEDControl.dproj
+++ b/G940LEDControl/G940LEDControl.dproj
@@ -33,106 +33,7 @@
Delphi.Personality
-FalseTrueFalseFalseFalse1000FalseFalseFalseFalseFalse104312521.0.0.01.0.0.0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+FalseTrueFalseFalseFalse1000FalseFalseFalseFalseFalse104312521.0.0.01.0.0.0G940LEDControl.dpr
@@ -508,8 +409,7 @@
WPViewPDF - PDFViewClass
madExceptVcl 2.0c - www.madshi.net
ExpressPivotGrid 2 OLAP by Developer Express Inc.
-
-
+
@@ -519,8 +419,10 @@
-
+
+
+
\ No newline at end of file
diff --git a/G940LEDControl/Units/CustomLEDStateProvider.pas b/G940LEDControl/Units/CustomLEDStateProvider.pas
deleted file mode 100644
index 55de30b..0000000
--- a/G940LEDControl/Units/CustomLEDStateProvider.pas
+++ /dev/null
@@ -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.
diff --git a/G940LEDControl/Units/FSXLEDStateProvider.pas b/G940LEDControl/Units/FSXLEDStateProvider.pas
index 3b7e876..e5da18f 100644
--- a/G940LEDControl/Units/FSXLEDStateProvider.pas
+++ b/G940LEDControl/Units/FSXLEDStateProvider.pas
@@ -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.
diff --git a/G940LEDControl/Units/G940LEDStateConsumer.pas b/G940LEDControl/Units/G940LEDStateConsumer.pas
new file mode 100644
index 0000000..7f46f71
--- /dev/null
+++ b/G940LEDControl/Units/G940LEDStateConsumer.pas
@@ -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.
diff --git a/G940LEDControl/Units/LEDFunctionMap.pas b/G940LEDControl/Units/LEDFunctionMap.pas
new file mode 100644
index 0000000..134f871
--- /dev/null
+++ b/G940LEDControl/Units/LEDFunctionMap.pas
@@ -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.
diff --git a/G940LEDControl/Units/LEDStateConsumer.pas b/G940LEDControl/Units/LEDStateConsumer.pas
index 5f428c9..7b474b8 100644
--- a/G940LEDControl/Units/LEDStateConsumer.pas
+++ b/G940LEDControl/Units/LEDStateConsumer.pas
@@ -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.
diff --git a/G940LEDControl/Units/LEDStateProvider.pas b/G940LEDControl/Units/LEDStateProvider.pas
new file mode 100644
index 0000000..b7df4c6
--- /dev/null
+++ b/G940LEDControl/Units/LEDStateProvider.pas
@@ -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.