Refactored: ILEDColor to ILEDStateColor (to prevent conflicts with the TLEDColor enum)
Reanimated: LEDStateConsumer and G940LEDStateConsumer; all LED state colors (including flashing) work and update properly after changing the profile - FSX functions crash horribly
This commit is contained in:
parent
b66659cd95
commit
f1b9a63fda
@ -19,9 +19,7 @@ uses
|
||||
pngimage,
|
||||
X2UtPersistIntf,
|
||||
|
||||
LEDFunctionMap,
|
||||
LEDStateConsumer,
|
||||
LEDStateProvider,
|
||||
Profile;
|
||||
|
||||
|
||||
@ -95,7 +93,6 @@ type
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure btnRetryClick(Sender: TObject);
|
||||
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||||
procedure FunctionComboBoxChange(Sender: TObject);
|
||||
procedure lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType);
|
||||
procedure btnCheckUpdatesClick(Sender: TObject);
|
||||
procedure LEDButtonClick(Sender: TObject);
|
||||
@ -109,15 +106,8 @@ type
|
||||
FProfiles: TProfileList;
|
||||
FActiveProfile: TProfile;
|
||||
FLoadingProfiles: Boolean;
|
||||
// FStateConsumerTask: IOmniTaskControl;
|
||||
FStateConsumerTask: IOmniTaskControl;
|
||||
protected
|
||||
// procedure ReadFunctions(AReader: IX2PersistReader; AComboBoxes: TComboBoxArray);
|
||||
// procedure ReadFSXExtra(AReader: IX2PersistReader);
|
||||
// procedure ReadAutoUpdate(AReader: IX2PersistReader);
|
||||
// procedure WriteFunctions(AWriter: IX2PersistWriter; AComboBoxes: TComboBoxArray);
|
||||
// procedure WriteFSXExtra(AWriter: IX2PersistWriter);
|
||||
// procedure WriteAutoUpdate(AWriter: IX2PersistWriter);
|
||||
|
||||
procedure FindLEDControls;
|
||||
procedure LoadProfiles;
|
||||
procedure SaveProfiles;
|
||||
@ -129,11 +119,6 @@ type
|
||||
procedure SetDeviceState(const AMessage: string; AFound: Boolean);
|
||||
// procedure SetFSXToggleZoomButton(const ADeviceGUID: TGUID; AButtonIndex: Integer; const ADisplayText: string);
|
||||
|
||||
// procedure InitializeStateProvider(AProviderClass: TLEDStateProviderClass);
|
||||
// procedure FinalizeStateProvider;
|
||||
|
||||
// procedure UpdateMapping;
|
||||
|
||||
procedure CheckForUpdatesThread(const ATask: IOmniTask);
|
||||
procedure CheckForUpdates(AReportNoUpdates: Boolean);
|
||||
|
||||
@ -150,7 +135,7 @@ type
|
||||
property ActiveProfile: TProfile read FActiveProfile;
|
||||
property EventMonitor: TOmniEventMonitor read FEventMonitor;
|
||||
property Profiles: TProfileList read FProfiles;
|
||||
// property StateConsumerTask: IOmniTaskControl read FStateConsumerTask;
|
||||
property StateConsumerTask: IOmniTaskControl read FStateConsumerTask;
|
||||
end;
|
||||
|
||||
|
||||
@ -170,7 +155,6 @@ uses
|
||||
|
||||
ButtonFunctionFrm,
|
||||
ConfigConversion,
|
||||
FSXLEDStateProvider,
|
||||
G940LEDStateConsumer,
|
||||
LEDColorIntf,
|
||||
LEDFunctionIntf,
|
||||
@ -193,28 +177,13 @@ const
|
||||
TEXT_STATE_FOUND = 'Connected';
|
||||
|
||||
|
||||
type
|
||||
TComboBoxFunctionConsumer = class(TInterfacedObject, IFunctionConsumer)
|
||||
private
|
||||
FComboBox: TComboBoxEx;
|
||||
protected
|
||||
{ IFunctionConsumer }
|
||||
procedure SetCategory(const ACategory: string);
|
||||
procedure AddFunction(AFunction: Integer; const ADescription: string);
|
||||
|
||||
property ComboBox: TComboBoxEx read FComboBox;
|
||||
public
|
||||
constructor Create(AComboBox: TComboBoxEx);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
{ TMainForm }
|
||||
procedure TMainForm.FormCreate(Sender: TObject);
|
||||
//var
|
||||
// consumer: IOmniWorker;
|
||||
//
|
||||
var
|
||||
consumer: IOmniWorker;
|
||||
|
||||
begin
|
||||
lblVersion.Caption := App.Version.FormatVersion(False);
|
||||
|
||||
@ -222,12 +191,12 @@ begin
|
||||
|
||||
FEventMonitor := TOmniEventMonitor.Create(Self);
|
||||
|
||||
// consumer := TG940LEDStateConsumer.Create;
|
||||
// FStateConsumerTask := FEventMonitor.Monitor(CreateTask(consumer)).MsgWait;
|
||||
consumer := TG940LEDStateConsumer.Create;
|
||||
FStateConsumerTask := FEventMonitor.Monitor(CreateTask(consumer)).MsgWait;
|
||||
|
||||
EventMonitor.OnTaskMessage := EventMonitorMessage;
|
||||
EventMonitor.OnTaskTerminated := EventMonitorTerminated;
|
||||
// StateConsumerTask.Run;
|
||||
StateConsumerTask.Run;
|
||||
|
||||
FindLEDControls;
|
||||
|
||||
@ -235,6 +204,7 @@ begin
|
||||
FProfiles := TProfileList.Create(True);
|
||||
LoadProfiles;
|
||||
|
||||
FStateConsumerTask.Comm.Send(TM_LOADPROFILE, ActiveProfile);
|
||||
// LoadFunctions(TFSXLEDStateProvider, FFSXComboBoxes);
|
||||
// LoadDefaultProfile;
|
||||
end;
|
||||
@ -549,6 +519,7 @@ begin
|
||||
if TButtonFunctionForm.Execute(ActiveProfile, buttonIndex) then
|
||||
begin
|
||||
UpdateButton(ActiveProfile, buttonIndex);
|
||||
FStateConsumerTask.Comm.Send(TM_LOADPROFILE, ActiveProfile);
|
||||
SaveProfiles;
|
||||
end;
|
||||
end;
|
||||
@ -657,20 +628,20 @@ end;
|
||||
procedure TMainForm.EventMonitorMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
|
||||
begin
|
||||
case msg.MsgID of
|
||||
MSG_NOTIFY_DEVICESTATE: HandleDeviceStateMessage(task, msg);
|
||||
MSG_RUN_IN_MAINTHREAD: HandleRunInMainThreadMessage(task, msg);
|
||||
MSG_PROVIDER_KILLED: HandleProviderKilled(task, msg);
|
||||
TM_NOTIFY_DEVICESTATE: HandleDeviceStateMessage(task, msg);
|
||||
// MSG_RUN_IN_MAINTHREAD: HandleRunInMainThreadMessage(task, msg);
|
||||
// MSG_PROVIDER_KILLED: HandleProviderKilled(task, msg);
|
||||
|
||||
MSG_UPDATE:
|
||||
if MessageBox(Self.Handle, 'An update is available on the G940 LED Control website.'#13#10'Do you want to go there now?',
|
||||
'Update available', MB_YESNO or MB_ICONINFORMATION) = ID_YES then
|
||||
ShellExecute(Self.Handle, 'open', PChar('http://g940.x2software.net/#download'), nil, nil, SW_SHOWNORMAL);
|
||||
|
||||
MSG_NOUPDATE:
|
||||
if msg.MsgData.AsBoolean then
|
||||
MessageBox(Self.Handle, 'You are using the latest version.', 'No update available', MB_OK or MB_ICONINFORMATION)
|
||||
else
|
||||
MessageBox(Self.Handle, 'Failed to check for updates. Maybe try again later?', 'Uh-oh', MB_OK or MB_ICONWARNING);
|
||||
// MSG_NOUPDATE:
|
||||
// if msg.MsgData.AsBoolean then
|
||||
// MessageBox(Self.Handle, 'You are using the latest version.', 'No update available', MB_OK or MB_ICONINFORMATION)
|
||||
// else
|
||||
// MessageBox(Self.Handle, 'Failed to check for updates. Maybe try again later?', 'Uh-oh', MB_OK or MB_ICONWARNING);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -748,53 +719,9 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.FunctionComboBoxChange(Sender: TObject);
|
||||
var
|
||||
comboBox: TComboBoxEx;
|
||||
|
||||
begin
|
||||
comboBox := TComboBoxEx(Sender);
|
||||
if comboBox.ItemIndex > -1 then
|
||||
begin
|
||||
if not Assigned(comboBox.ItemsEx[comboBox.ItemIndex].Data) then
|
||||
comboBox.ItemIndex := Succ(comboBox.ItemIndex);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType);
|
||||
begin
|
||||
ShellExecute(Self.Handle, 'open', PChar(Link), nil, nil, SW_SHOWNORMAL);
|
||||
end;
|
||||
|
||||
|
||||
{ TComboBoxFunctionConsumer }
|
||||
constructor TComboBoxFunctionConsumer.Create(AComboBox: TComboBoxEx);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
FComboBox := AComboBox;
|
||||
end;
|
||||
|
||||
|
||||
procedure TComboBoxFunctionConsumer.SetCategory(const ACategory: string);
|
||||
begin
|
||||
with ComboBox.ItemsEx.Add do
|
||||
begin
|
||||
Caption := ACategory;
|
||||
Data := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TComboBoxFunctionConsumer.AddFunction(AFunction: Integer; const ADescription: string);
|
||||
begin
|
||||
with ComboBox.ItemsEx.Add do
|
||||
begin
|
||||
Caption := ADescription;
|
||||
Indent := 1;
|
||||
Data := Pointer(AFunction);
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -5,11 +5,8 @@ uses
|
||||
MainFrm in 'Forms\MainFrm.pas' {MainForm},
|
||||
LogiJoystickDLL in '..\Shared\LogiJoystickDLL.pas',
|
||||
SimConnect in '..\Shared\SimConnect.pas',
|
||||
FSXLEDStateProvider in 'Units\FSXLEDStateProvider.pas',
|
||||
G940LEDStateConsumer in 'Units\G940LEDStateConsumer.pas',
|
||||
LEDFunctionMap in 'Units\LEDFunctionMap.pas',
|
||||
LEDStateConsumer in 'Units\LEDStateConsumer.pas',
|
||||
LEDStateProvider in 'Units\LEDStateProvider.pas',
|
||||
LEDColorIntf in 'Units\LEDColorIntf.pas',
|
||||
LEDColor in 'Units\LEDColor.pas',
|
||||
LEDFunctionIntf in 'Units\LEDFunctionIntf.pas',
|
||||
|
@ -165,11 +165,8 @@
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\Shared\LogiJoystickDLL.pas"/>
|
||||
<DCCReference Include="..\Shared\SimConnect.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"/>
|
||||
<DCCReference Include="Units\LEDColorIntf.pas"/>
|
||||
<DCCReference Include="Units\LEDColor.pas"/>
|
||||
<DCCReference Include="Units\LEDFunctionIntf.pas"/>
|
||||
|
@ -12,23 +12,24 @@ const
|
||||
|
||||
|
||||
type
|
||||
TLEDColorDynArray = array of TLEDColor;
|
||||
TStaticLEDColorDynArray = array of TStaticLEDColor;
|
||||
|
||||
|
||||
TDynamicLEDColor = class(TCustomDynamicLEDColor)
|
||||
TDynamicLEDColor = class(TCustomLEDStateDynamicColor)
|
||||
private
|
||||
FCycleColors: TLEDColorDynArray;
|
||||
FCycleColors: TStaticLEDColorDynArray;
|
||||
FCycleIndex: Integer;
|
||||
FTickInterval: Integer;
|
||||
FTickCount: Integer;
|
||||
protected
|
||||
{ ILEDState }
|
||||
function GetColor: TLEDColor; override;
|
||||
function GetCurrentColor: TStaticLEDColor; override;
|
||||
|
||||
{ ITickLEDState }
|
||||
procedure Reset; override;
|
||||
procedure Tick; override;
|
||||
public
|
||||
constructor Create(ACycleColors: TLEDColorDynArray; ATickInterval: Integer = TICKINTERVAL_NORMAL);
|
||||
constructor Create(ACycleColors: TStaticLEDColorDynArray; ATickInterval: Integer = TICKINTERVAL_NORMAL);
|
||||
end;
|
||||
|
||||
|
||||
@ -39,7 +40,7 @@ uses
|
||||
|
||||
|
||||
{ TDynamicLEDState }
|
||||
constructor TDynamicLEDColor.Create(ACycleColors: TLEDColorDynArray; ATickInterval: Integer);
|
||||
constructor TDynamicLEDColor.Create(ACycleColors: TStaticLEDColorDynArray; ATickInterval: Integer);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
@ -49,16 +50,22 @@ begin
|
||||
FCycleColors := ACycleColors;
|
||||
FCycleIndex := Low(FCycleColors);
|
||||
FTickInterval := ATickInterval;
|
||||
FTickCount := 0;
|
||||
Reset;
|
||||
end;
|
||||
|
||||
|
||||
function TDynamicLEDColor.GetColor: TLEDColor;
|
||||
function TDynamicLEDColor.GetCurrentColor: TStaticLEDColor;
|
||||
begin
|
||||
Result := FCycleColors[FCycleIndex];
|
||||
end;
|
||||
|
||||
|
||||
procedure TDynamicLEDColor.Reset;
|
||||
begin
|
||||
FCycleIndex := 0;
|
||||
end;
|
||||
|
||||
|
||||
procedure TDynamicLEDColor.Tick;
|
||||
begin
|
||||
Inc(FTickCount);
|
||||
|
@ -8,46 +8,31 @@ uses
|
||||
OtlComm,
|
||||
OtlTaskControl,
|
||||
|
||||
LEDFunctionMap,
|
||||
LEDStateConsumer,
|
||||
LEDStateProvider;
|
||||
LEDStateConsumer;
|
||||
|
||||
|
||||
const
|
||||
MSG_FINDTHROTTLEDEVICE = MSG_CONSUMER_OFFSET + 1;
|
||||
MSG_NOTIFY_DEVICESTATE = MSG_CONSUMER_OFFSET + 2;
|
||||
MSG_TIMER_BLINK = MSG_CONSUMER_OFFSET + 3;
|
||||
TM_FINDTHROTTLEDEVICE = 2001;
|
||||
TM_NOTIFY_DEVICESTATE = 2002;
|
||||
|
||||
TIMER_BLINK = TIMER_CONSUMER_OFFSET + 1;
|
||||
|
||||
type
|
||||
TG940LEDStateConsumer = class(TLEDStateConsumer)
|
||||
private
|
||||
FDirectInput: IDirectInput8;
|
||||
FThrottleDevice: IDirectInputDevice8;
|
||||
|
||||
FRed: Byte;
|
||||
FGreen: Byte;
|
||||
|
||||
FBlinkTimerStarted: Boolean;
|
||||
FBlinkCounter: Integer;
|
||||
protected
|
||||
procedure MsgFindThrottleDevice(var msg: TOmniMessage); message MSG_FINDTHROTTLEDEVICE;
|
||||
procedure MsgTimerBlink(var msg: TOmniMessage); message MSG_TIMER_BLINK;
|
||||
procedure MsgFindThrottleDevice(var msg: TOmniMessage); message TM_FINDTHROTTLEDEVICE;
|
||||
protected
|
||||
function Initialize: Boolean; override;
|
||||
procedure ResetLEDState; override;
|
||||
procedure LEDStateChanged(ALEDIndex: Integer; AState: TLEDState); override;
|
||||
procedure Changed; override;
|
||||
|
||||
procedure StartBlinkTimer;
|
||||
procedure StopBlinkTimer;
|
||||
|
||||
procedure FindThrottleDevice;
|
||||
procedure FoundThrottleDevice(ADeviceGUID: TGUID);
|
||||
|
||||
procedure SetDeviceState(AState: Integer);
|
||||
|
||||
procedure Update; override;
|
||||
|
||||
property DirectInput: IDirectInput8 read FDirectInput;
|
||||
property ThrottleDevice: IDirectInputDevice8 read FThrottleDevice;
|
||||
end;
|
||||
@ -58,8 +43,8 @@ const
|
||||
DEVICESTATE_FOUND = 1;
|
||||
DEVICESTATE_NOTFOUND = 2;
|
||||
|
||||
EXIT_ERROR_LOGIJOYSTICKDLL = EXIT_CONSUMER_OFFSET + 1;
|
||||
EXIT_ERROR_DIRECTINPUT = EXIT_CONSUMER_OFFSET + 2;
|
||||
EXIT_ERROR_LOGIJOYSTICKDLL = 9001;
|
||||
EXIT_ERROR_DIRECTINPUT = 9002;
|
||||
|
||||
|
||||
implementation
|
||||
@ -68,15 +53,18 @@ uses
|
||||
Windows,
|
||||
|
||||
OtlCommon,
|
||||
OtlTask,
|
||||
|
||||
LEDColorIntf,
|
||||
LogiJoystickDLL;
|
||||
|
||||
|
||||
|
||||
const
|
||||
BLINK_INTERVAL = 500;
|
||||
G940_BUTTONCOUNT = 8;
|
||||
|
||||
|
||||
|
||||
(*
|
||||
type
|
||||
TRunInMainThreadSetLEDs = class(TOmniWaitableValue, IRunInMainThread)
|
||||
private
|
||||
@ -89,6 +77,7 @@ type
|
||||
public
|
||||
constructor Create(ADevice: IDirectInputDevice8; ARed, AGreen: Byte);
|
||||
end;
|
||||
*)
|
||||
|
||||
|
||||
function EnumDevicesProc(var lpddi: TDIDeviceInstanceW; pvRef: Pointer): BOOL; stdcall;
|
||||
@ -134,10 +123,11 @@ begin
|
||||
end;
|
||||
|
||||
Result := True;
|
||||
Task.Comm.OtherEndpoint.Send(MSG_FINDTHROTTLEDEVICE);
|
||||
Task.Comm.OtherEndpoint.Send(TM_FINDTHROTTLEDEVICE);
|
||||
end;
|
||||
|
||||
|
||||
{
|
||||
procedure TG940LEDStateConsumer.ResetLEDState;
|
||||
begin
|
||||
FRed := 0;
|
||||
@ -200,36 +190,18 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
procedure TG940LEDStateConsumer.Changed;
|
||||
begin
|
||||
inherited;
|
||||
|
||||
if Assigned(ThrottleDevice) then
|
||||
{ Logitech SDK will not change the color outside of the main thread }
|
||||
{ Logitech SDK will not change the color outside of the main thread
|
||||
RunInMainThread(TRunInMainThreadSetLEDs.Create(ThrottleDevice, FRed, FGreen), Destroying);
|
||||
end;
|
||||
|
||||
|
||||
procedure TG940LEDStateConsumer.StartBlinkTimer;
|
||||
begin
|
||||
if FBlinkTimerStarted then
|
||||
exit;
|
||||
|
||||
FBlinkCounter := 0;
|
||||
Task.SetTimer(TIMER_BLINK, BLINK_INTERVAL, MSG_TIMER_BLINK);
|
||||
FBlinkTimerStarted := True;
|
||||
end;
|
||||
|
||||
|
||||
procedure TG940LEDStateConsumer.StopBlinkTimer;
|
||||
begin
|
||||
if not FBlinkTimerStarted then
|
||||
exit;
|
||||
|
||||
Task.ClearTimer(TIMER_BLINK);
|
||||
FBlinkTimerStarted := False;
|
||||
end;
|
||||
}
|
||||
|
||||
|
||||
procedure TG940LEDStateConsumer.FindThrottleDevice;
|
||||
@ -243,7 +215,7 @@ begin
|
||||
if not Assigned(ThrottleDevice) then
|
||||
SetDeviceState(DEVICESTATE_NOTFOUND)
|
||||
else
|
||||
Changed;
|
||||
Update;
|
||||
end;
|
||||
|
||||
|
||||
@ -256,7 +228,54 @@ end;
|
||||
|
||||
procedure TG940LEDStateConsumer.SetDeviceState(AState: Integer);
|
||||
begin
|
||||
Task.Comm.Send(MSG_NOTIFY_DEVICESTATE, AState);
|
||||
Task.Comm.Send(TM_NOTIFY_DEVICESTATE, AState);
|
||||
end;
|
||||
|
||||
|
||||
procedure TG940LEDStateConsumer.Update;
|
||||
|
||||
procedure SetBit(var AMask: Byte; ABit: Integer); inline;
|
||||
begin
|
||||
AMask := AMask or (1 shl ABit)
|
||||
end;
|
||||
|
||||
|
||||
var
|
||||
red: Byte;
|
||||
green: Byte;
|
||||
buttonIndex: Integer;
|
||||
buttonColor: TStaticLEDColor;
|
||||
|
||||
begin
|
||||
if not Assigned(ThrottleDevice) then
|
||||
exit;
|
||||
|
||||
red := 0;
|
||||
green := 0;
|
||||
|
||||
for buttonIndex := 0 to Pred(G940_BUTTONCOUNT) do
|
||||
begin
|
||||
if buttonIndex >= ButtonColors.Count then
|
||||
buttonColor := lcOff
|
||||
else
|
||||
buttonColor := (ButtonColors[buttonIndex] as ILEDStateColor).GetCurrentColor;
|
||||
|
||||
case buttonColor of
|
||||
lcGreen:
|
||||
SetBit(green, buttonIndex);
|
||||
|
||||
lcAmber:
|
||||
begin
|
||||
SetBit(green, buttonIndex);
|
||||
SetBit(red, buttonIndex);
|
||||
end;
|
||||
|
||||
lcRed:
|
||||
SetBit(red, buttonIndex);
|
||||
end;
|
||||
end;
|
||||
|
||||
SetLEDs(ThrottleDevice, red, green);
|
||||
end;
|
||||
|
||||
|
||||
@ -266,52 +285,8 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TG940LEDStateConsumer.MsgTimerBlink(var msg: TOmniMessage);
|
||||
var
|
||||
warningState: TLEDState;
|
||||
errorState: TLEDState;
|
||||
ledIndex: Integer;
|
||||
state: TLEDState;
|
||||
|
||||
begin
|
||||
Inc(FBlinkCounter);
|
||||
if FBlinkCounter > 3 then
|
||||
FBlinkCounter := 0;
|
||||
|
||||
warningState := lsOff;
|
||||
errorState := lsOff;
|
||||
|
||||
{ Error lights blink twice as fast }
|
||||
if (FBlinkCounter in [0, 1]) then
|
||||
warningState := lsAmber;
|
||||
|
||||
if (FBlinkCounter in [0, 2]) then
|
||||
errorState := lsRed;
|
||||
|
||||
if StateMap.FindFirst([lsWarning, lsError], ledIndex, state) then
|
||||
begin
|
||||
BeginUpdate;
|
||||
try
|
||||
repeat
|
||||
case state of
|
||||
lsWarning:
|
||||
if StateMap.GetState(ledIndex) <> warningState then
|
||||
LEDStateChanged(ledIndex, warningState);
|
||||
|
||||
lsError:
|
||||
if StateMap.GetState(ledIndex) <> errorState then
|
||||
LEDStateChanged(ledIndex, errorState);
|
||||
end;
|
||||
until not StateMap.FindNext([lsWarning, lsError], ledIndex, state);
|
||||
finally
|
||||
EndUpdate;
|
||||
end;
|
||||
end else
|
||||
StopBlinkTimer;
|
||||
end;
|
||||
|
||||
|
||||
{ TRunInMainThreadSetLEDs }
|
||||
(*
|
||||
constructor TRunInMainThreadSetLEDs.Create(ADevice: IDirectInputDevice8; ARed, AGreen: Byte);
|
||||
begin
|
||||
inherited Create;
|
||||
@ -326,5 +301,6 @@ procedure TRunInMainThreadSetLEDs.Execute;
|
||||
begin
|
||||
SetLEDs(FDevice, FRed, FGreen);
|
||||
end;
|
||||
*)
|
||||
|
||||
end.
|
||||
|
@ -8,16 +8,17 @@ uses
|
||||
|
||||
|
||||
type
|
||||
TCustomLEDColor = class(TInterfacedObject, ILEDColor)
|
||||
TCustomLEDStateColor = class(TInterfacedObject, ILEDStateColor)
|
||||
protected
|
||||
{ ILEDState }
|
||||
function GetColor: TLEDColor; virtual; abstract;
|
||||
function GetCurrentColor: TStaticLEDColor; virtual; abstract;
|
||||
end;
|
||||
|
||||
|
||||
TCustomDynamicLEDColor = class(TCustomLEDColor, IDynamicLEDColor)
|
||||
TCustomLEDStateDynamicColor = class(TCustomLEDStateColor, ILEDStateDynamicColor)
|
||||
protected
|
||||
{ ITickLEDState }
|
||||
procedure Reset; virtual; abstract;
|
||||
procedure Tick; virtual; abstract;
|
||||
end;
|
||||
|
||||
|
@ -11,14 +11,15 @@ type
|
||||
|
||||
|
||||
|
||||
ILEDColor = interface
|
||||
ILEDStateColor = interface
|
||||
['{B40DF462-B660-4002-A6B9-DD30AC69E8DB}']
|
||||
function GetColor: TLEDColor;
|
||||
function GetCurrentColor: TStaticLEDColor;
|
||||
end;
|
||||
|
||||
|
||||
IDynamicLEDColor = interface(ILEDColor)
|
||||
ILEDStateDynamicColor = interface(ILEDStateColor)
|
||||
['{9770E851-580D-4803-9979-0C608CB108A0}']
|
||||
procedure Reset;
|
||||
procedure Tick;
|
||||
end;
|
||||
|
||||
|
@ -8,13 +8,13 @@ uses
|
||||
type
|
||||
TLEDColorPool = class(TObject)
|
||||
private
|
||||
FStates: array[TLEDColor] of ILEDColor;
|
||||
FStates: array[TLEDColor] of ILEDStateColor;
|
||||
protected
|
||||
class function Instance: TLEDColorPool;
|
||||
|
||||
function DoGetColor(AColor: TLEDColor): ILEDColor;
|
||||
function DoGetColor(AColor: TLEDColor): ILEDStateColor;
|
||||
public
|
||||
class function GetColor(AColor: TLEDColor): ILEDColor; overload;
|
||||
class function GetColor(AColor: TLEDColor): ILEDStateColor; overload;
|
||||
end;
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ var
|
||||
|
||||
|
||||
{ TLEDStatePool }
|
||||
class function TLEDColorPool.GetColor(AColor: TLEDColor): ILEDColor;
|
||||
class function TLEDColorPool.GetColor(AColor: TLEDColor): ILEDStateColor;
|
||||
begin
|
||||
Result := Instance.DoGetColor(AColor);
|
||||
end;
|
||||
@ -46,9 +46,9 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
function TLEDColorPool.DoGetColor(AColor: TLEDColor): ILEDColor;
|
||||
function TLEDColorPool.DoGetColor(AColor: TLEDColor): ILEDStateColor;
|
||||
|
||||
function GetFlashingCycle(AColor: TLEDColor): TLEDColorDynArray;
|
||||
function GetFlashingCycle(AColor: TLEDColor): TStaticLEDColorDynArray;
|
||||
begin
|
||||
SetLength(Result, 2);
|
||||
Result[0] := AColor;
|
||||
@ -56,16 +56,16 @@ function TLEDColorPool.DoGetColor(AColor: TLEDColor): ILEDColor;
|
||||
end;
|
||||
|
||||
var
|
||||
state: ILEDColor;
|
||||
state: ILEDStateColor;
|
||||
|
||||
begin
|
||||
if not Assigned(FStates[AColor]) then
|
||||
begin
|
||||
case AColor of
|
||||
lcOff: state := TStaticLEDColor.Create(lcOff);
|
||||
lcGreen: state := TStaticLEDColor.Create(lcGreen);
|
||||
lcAmber: state := TStaticLEDColor.Create(lcAmber);
|
||||
lcRed: state := TStaticLEDColor.Create(lcRed);
|
||||
lcOff: state := TLEDStateStaticColor.Create(lcOff);
|
||||
lcGreen: state := TLEDStateStaticColor.Create(lcGreen);
|
||||
lcAmber: state := TLEDStateStaticColor.Create(lcAmber);
|
||||
lcRed: state := TLEDStateStaticColor.Create(lcRed);
|
||||
|
||||
lcFlashingGreenFast: state := TDynamicLEDColor.Create(GetFlashingCycle(lcGreen), TICKINTERVAL_FAST);
|
||||
lcFlashingGreenNormal: state := TDynamicLEDColor.Create(GetFlashingCycle(lcGreen), TICKINTERVAL_NORMAL);
|
||||
|
@ -1,228 +0,0 @@
|
||||
unit LEDFunctionMap;
|
||||
|
||||
interface
|
||||
uses
|
||||
Classes,
|
||||
SyncObjs,
|
||||
|
||||
X2UtHashes;
|
||||
|
||||
|
||||
type
|
||||
TLEDState = (lsOff, lsGreen, lsAmber, lsRed, lsWarning, lsError);
|
||||
TLEDStateSet = set of TLEDState;
|
||||
|
||||
|
||||
TLEDFunctionMap = class(TObject)
|
||||
private
|
||||
FFunctions: TX2IIHash;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
|
||||
procedure Clear;
|
||||
|
||||
procedure SetFunction(ALEDIndex, AFunction: Integer);
|
||||
function GetFunction(ALEDIndex: Integer): Integer;
|
||||
|
||||
function HasFunction(AFunction: Integer): Boolean; overload;
|
||||
function HasFunction(AFunctions: array of Integer): Boolean; overload;
|
||||
|
||||
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;
|
||||
|
||||
function HasStates(AStates: TLEDStateSet): Boolean;
|
||||
function FindFirst(AStates: TLEDStateSet; out ALEDIndex: Integer; out AState: TLEDState): Boolean;
|
||||
function FindNext(AStates: TLEDStateSet; out ALEDIndex: Integer; out AState: TLEDState): Boolean;
|
||||
end;
|
||||
|
||||
|
||||
const
|
||||
FUNCTION_NONE = 0;
|
||||
FUNCTION_OFF = 1;
|
||||
FUNCTION_RED = 2;
|
||||
FUNCTION_AMBER = 3;
|
||||
FUNCTION_GREEN = 4;
|
||||
|
||||
{ Note: if this offset ever changes, make sure to write a conversion for
|
||||
existing configurations. And probably reserve a bit more. }
|
||||
FUNCTION_PROVIDER_OFFSET = FUNCTION_GREEN;
|
||||
|
||||
|
||||
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(AFunctions: array of Integer): Boolean;
|
||||
var
|
||||
functionNo: Integer;
|
||||
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
for functionNo in AFunctions do
|
||||
begin
|
||||
Result := HasFunction(functionNo);
|
||||
if Result then
|
||||
break;
|
||||
end;
|
||||
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 := FindNext(AFunction, ALEDIndex);
|
||||
end;
|
||||
|
||||
|
||||
function TLEDFunctionMap.FindNext(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;
|
||||
|
||||
|
||||
function TLEDStateMap.HasStates(AStates: TLEDStateSet): Boolean;
|
||||
var
|
||||
ledIndex: Integer;
|
||||
state: TLEDState;
|
||||
|
||||
begin
|
||||
Result := FindFirst(AStates, ledIndex, state);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
function TLEDStateMap.FindFirst(AStates: TLEDStateSet; out ALEDIndex: Integer; out AState: TLEDState): Boolean;
|
||||
begin
|
||||
FStates.First;
|
||||
Result := FindNext(AStates, ALEDIndex, AState);
|
||||
end;
|
||||
|
||||
|
||||
function TLEDStateMap.FindNext(AStates: TLEDStateSet; out ALEDIndex: Integer; out AState: TLEDState): Boolean;
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
while FStates.Next do
|
||||
if TLEDState(FStates.CurrentValue) in AStates then
|
||||
begin
|
||||
ALEDIndex := FStates.CurrentKey;
|
||||
AState := TLEDState(FStates.CurrentValue);
|
||||
Result := True;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
@ -33,12 +33,12 @@ type
|
||||
|
||||
TLEDStateWorker = class(TCustomLEDState, ILEDStateWorker)
|
||||
private
|
||||
FColor: ILEDColor;
|
||||
FColor: ILEDStateColor;
|
||||
protected
|
||||
{ ILEDStateWorker }
|
||||
function GetColor: ILEDColor;
|
||||
function GetColor: ILEDStateColor;
|
||||
public
|
||||
constructor Create(const AUID: string; AColor: ILEDColor);
|
||||
constructor Create(const AUID: string; AColor: ILEDStateColor);
|
||||
end;
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ end;
|
||||
|
||||
|
||||
{ TLEDStateWorker }
|
||||
constructor TLEDStateWorker.Create(const AUID: string; AColor: ILEDColor);
|
||||
constructor TLEDStateWorker.Create(const AUID: string; AColor: ILEDStateColor);
|
||||
begin
|
||||
inherited Create(AUID);
|
||||
|
||||
@ -91,7 +91,7 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
function TLEDStateWorker.GetColor: ILEDColor;
|
||||
function TLEDStateWorker.GetColor: ILEDStateColor;
|
||||
begin
|
||||
Result := FColor;
|
||||
end;
|
||||
|
@ -2,29 +2,22 @@ unit LEDStateConsumer;
|
||||
|
||||
interface
|
||||
uses
|
||||
System.Classes,
|
||||
|
||||
OtlComm,
|
||||
OtlCommon,
|
||||
OtlTaskControl,
|
||||
|
||||
LEDFunctionMap,
|
||||
LEDStateProvider;
|
||||
LEDColorIntf,
|
||||
LEDFunctionIntf,
|
||||
Profile;
|
||||
|
||||
|
||||
const
|
||||
MSG_CLEAR_FUNCTIONS = 1001;
|
||||
MSG_SET_FUNCTION = 1002;
|
||||
MSG_INITIALIZE_PROVIDER = 1003;
|
||||
MSG_FINALIZE_PROVIDER = 1004;
|
||||
MSG_PROCESS_MESSAGES = 1005;
|
||||
MSG_FINALIZE = 1006;
|
||||
TM_LOADPROFILE = 1001;
|
||||
TM_TICK = 1002;
|
||||
|
||||
MSG_PROVIDER_KILLED = 1007;
|
||||
MSG_RUN_IN_MAINTHREAD = 1008;
|
||||
|
||||
MSG_CONSUMER_OFFSET = MSG_RUN_IN_MAINTHREAD;
|
||||
|
||||
TIMER_PROCESSMESSAGES = 1001;
|
||||
TIMER_CONSUMER_OFFSET = TIMER_PROCESSMESSAGES;
|
||||
TIMER_TICK = 101;
|
||||
|
||||
|
||||
type
|
||||
@ -32,320 +25,219 @@ type
|
||||
['{68B8F2F7-ED40-4078-9D99-503D7AFA068B}']
|
||||
procedure Execute;
|
||||
end;
|
||||
|
||||
|
||||
TLEDStateConsumer = class(TOmniWorker, ILEDStateConsumer)
|
||||
|
||||
TLEDStateConsumer = class(TOmniWorker)
|
||||
private
|
||||
FFunctionMap: TLEDFunctionMap;
|
||||
FStateMap: TLEDStateMap;
|
||||
FProvider: TLEDStateProvider;
|
||||
FTimerSet: Boolean;
|
||||
FChanged: Boolean;
|
||||
FUpdateCount: Integer;
|
||||
FDestroying: Boolean;
|
||||
FButtonWorkers: TInterfaceList;
|
||||
FButtonColors: TInterfaceList;
|
||||
FHasTickTimer: Boolean;
|
||||
protected
|
||||
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 MsgFinalize(var msg: TOmniMessage); message MSG_FINALIZE;
|
||||
|
||||
function Initialize: Boolean; override;
|
||||
procedure Cleanup; override;
|
||||
|
||||
procedure InitializeProvider(AProviderClass: TLEDStateProviderClass);
|
||||
procedure FinalizeProvider;
|
||||
function CreateWorker(AProfileButton: TProfileButton): ILEDFunctionWorker;
|
||||
|
||||
procedure RunInMainThread(AExecutor: IRunInMainThread; AWait: Boolean = False);
|
||||
procedure InitializeLEDState; virtual;
|
||||
procedure ResetLEDState; virtual;
|
||||
procedure LEDStateChanged(ALEDIndex: Integer; AState: TLEDState); virtual;
|
||||
property ButtonWorkers: TInterfaceList read FButtonWorkers;
|
||||
property ButtonColors: TInterfaceList read FButtonColors;
|
||||
property HasTickTimer: Boolean read FHasTickTimer;
|
||||
protected
|
||||
procedure Changed; virtual;
|
||||
|
||||
{ ILEDStateConsumer }
|
||||
function GetFunctionMap: TLEDFunctionMap;
|
||||
procedure SetStateByFunction(AFunction: Integer; AState: TLEDState);
|
||||
|
||||
property Destroying: Boolean read FDestroying;
|
||||
property FunctionMap: TLEDFunctionMap read GetFunctionMap;
|
||||
property StateMap: TLEDStateMap read FStateMap;
|
||||
property Provider: TLEDStateProvider read FProvider;
|
||||
property UpdateCount: Integer read FUpdateCount write FUpdateCount;
|
||||
public
|
||||
constructor Create;
|
||||
|
||||
procedure BeginUpdate;
|
||||
procedure EndUpdate;
|
||||
procedure Update; virtual; abstract;
|
||||
protected
|
||||
procedure TMLoadProfile(var Msg: TOmniMessage); message TM_LOADPROFILE;
|
||||
procedure TMTick(var Msg: TOmniMessage); message TM_TICK;
|
||||
end;
|
||||
|
||||
|
||||
procedure ClearFunctions(AConsumer: IOmniTaskControl);
|
||||
procedure SetFunction(AConsumer: IOmniTaskControl; ALEDIndex, AFunction: Integer);
|
||||
procedure InitializeStateProvider(AConsumer: IOmniTaskControl; AProviderClass: TLEDStateProviderClass);
|
||||
procedure FinalizeStateProvider(AConsumer: IOmniTaskControl);
|
||||
procedure Finalize(AConsumer: IOmniTaskControl);
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
SysUtils,
|
||||
Windows;
|
||||
System.SysUtils,
|
||||
Winapi.Windows,
|
||||
|
||||
LEDFunctionRegistry,
|
||||
LEDStateIntf;
|
||||
|
||||
|
||||
const
|
||||
G940_LED_COUNT = 8;
|
||||
INTERVAL_TICK = 500;
|
||||
|
||||
|
||||
type
|
||||
TProfileButtonWorkerSettings = class(TInterfacedObject, ILEDFunctionWorkerSettings)
|
||||
private
|
||||
FProfileButton: TProfileButton;
|
||||
protected
|
||||
{ ILEDFunctionWorkerSettings }
|
||||
function GetStateColor(const AUID: string; out AColor: TLEDColor): Boolean;
|
||||
|
||||
property ProfileButton: TProfileButton read FProfileButton;
|
||||
public
|
||||
constructor Create(AProfileButton: TProfileButton);
|
||||
end;
|
||||
|
||||
|
||||
{ TLEDStateConsumer }
|
||||
constructor TLEDStateConsumer.Create;
|
||||
function TLEDStateConsumer.Initialize: Boolean;
|
||||
begin
|
||||
inherited;
|
||||
Result := inherited Initialize;
|
||||
if not Result then
|
||||
exit;
|
||||
|
||||
FFunctionMap := TLEDFunctionMap.Create;
|
||||
FStateMap := TLEDStateMap.Create;
|
||||
|
||||
InitializeLEDState;
|
||||
FButtonWorkers := TInterfaceList.Create;
|
||||
FButtonColors := TInterfaceList.Create;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.Cleanup;
|
||||
begin
|
||||
inherited;
|
||||
FreeAndNil(FButtonColors);
|
||||
FreeAndNil(FButtonWorkers);
|
||||
|
||||
FreeAndNil(FStateMap);
|
||||
FreeAndNil(FFunctionMap);
|
||||
inherited Cleanup;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.BeginUpdate;
|
||||
begin
|
||||
if FUpdateCount = 0 then
|
||||
FChanged := False;
|
||||
|
||||
Inc(FUpdateCount);
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.EndUpdate;
|
||||
begin
|
||||
if FUpdateCount > 0 then
|
||||
Dec(FUpdateCount);
|
||||
|
||||
if (FUpdateCount = 0) and FChanged then
|
||||
Changed;
|
||||
end;
|
||||
|
||||
|
||||
function TLEDStateConsumer.GetFunctionMap: TLEDFunctionMap;
|
||||
begin
|
||||
Result := FFunctionMap;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.SetStateByFunction(AFunction: Integer; AState: TLEDState);
|
||||
function TLEDStateConsumer.CreateWorker(AProfileButton: TProfileButton): ILEDFunctionWorker;
|
||||
var
|
||||
ledIndex: Integer;
|
||||
provider: ILEDFunctionProvider;
|
||||
ledFunction: ILEDFunction;
|
||||
|
||||
begin
|
||||
if FunctionMap.FindFirst(AFunction, ledIndex) then
|
||||
repeat
|
||||
if StateMap.SetState(ledIndex, AState) then
|
||||
LEDStateChanged(ledIndex, AState);
|
||||
until not FunctionMap.FindNext(AFunction, ledIndex);
|
||||
end;
|
||||
Result := nil;
|
||||
|
||||
|
||||
|
||||
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
|
||||
BeginUpdate;
|
||||
try
|
||||
Provider.ProcessMessages;
|
||||
|
||||
if Provider.Terminated then
|
||||
begin
|
||||
FinalizeProvider;
|
||||
Task.Comm.Send(MSG_PROVIDER_KILLED, '');
|
||||
end;
|
||||
finally
|
||||
EndUpdate;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.MsgFinalize(var msg: TOmniMessage);
|
||||
begin
|
||||
FDestroying := True;
|
||||
FinalizeProvider;
|
||||
Task.Terminate;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.InitializeProvider(AProviderClass: TLEDStateProviderClass);
|
||||
begin
|
||||
FinalizeProvider;
|
||||
|
||||
FProvider := AProviderClass.Create(Self);
|
||||
try
|
||||
Provider.Initialize;
|
||||
|
||||
if Provider.ProcessMessagesInterval > -1 then
|
||||
begin
|
||||
Task.SetTimer(TIMER_PROCESSMESSAGES, Provider.ProcessMessagesInterval, MSG_PROCESS_MESSAGES);
|
||||
FTimerSet := True;
|
||||
end;
|
||||
|
||||
InitializeLEDState;
|
||||
except
|
||||
on E:Exception do
|
||||
begin
|
||||
FProvider := nil;
|
||||
Task.Comm.Send(MSG_PROVIDER_KILLED, E.Message);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.FinalizeProvider;
|
||||
begin
|
||||
if Assigned(Provider) then
|
||||
provider := TLEDFunctionRegistry.Find(AProfileButton.ProviderUID);
|
||||
if Assigned(provider) then
|
||||
begin
|
||||
if FTimerSet then
|
||||
begin
|
||||
Task.ClearTimer(TIMER_PROCESSMESSAGES);
|
||||
FTimerSet := False;
|
||||
end;
|
||||
|
||||
Provider.Terminate;
|
||||
Provider.Finalize;
|
||||
FreeAndNil(FProvider);
|
||||
|
||||
StateMap.Clear;
|
||||
ResetLEDState;
|
||||
ledFunction := provider.Find(AProfileButton.FunctionUID);
|
||||
if Assigned(ledFunction) then
|
||||
Result := ledFunction.CreateWorker(TProfileButtonWorkerSettings.Create(AProfileButton));
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.RunInMainThread(AExecutor: IRunInMainThread; AWait: Boolean);
|
||||
begin
|
||||
Task.Comm.Send(MSG_RUN_IN_MAINTHREAD, AExecutor);
|
||||
if AWait then
|
||||
AExecutor.WaitFor(INFINITE);
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.InitializeLEDState;
|
||||
var
|
||||
ledIndex: Integer;
|
||||
state: TLEDState;
|
||||
newState: TLEDState;
|
||||
|
||||
begin
|
||||
BeginUpdate;
|
||||
try
|
||||
ResetLEDState;
|
||||
|
||||
for ledIndex := 0 to Pred(G940_LED_COUNT) do
|
||||
begin
|
||||
state := StateMap.GetState(ledIndex, lsGreen);
|
||||
newState := state;
|
||||
|
||||
case FunctionMap.GetFunction(ledIndex) of
|
||||
FUNCTION_OFF: newState := lsOff;
|
||||
FUNCTION_RED: newState := lsRed;
|
||||
FUNCTION_AMBER: newState := lsAmber;
|
||||
FUNCTION_GREEN: newState := lsGreen;
|
||||
end;
|
||||
|
||||
if state <> newState then
|
||||
LEDStateChanged(ledIndex, newState);
|
||||
end;
|
||||
finally
|
||||
EndUpdate;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.ResetLEDState;
|
||||
begin
|
||||
if UpdateCount = 0 then
|
||||
Changed
|
||||
else
|
||||
FChanged := True;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.LEDStateChanged(ALEDIndex: Integer; AState: TLEDState);
|
||||
begin
|
||||
if UpdateCount = 0 then
|
||||
Changed
|
||||
else
|
||||
FChanged := True;
|
||||
end;
|
||||
|
||||
|
||||
procedure TLEDStateConsumer.Changed;
|
||||
var
|
||||
hasDynamicColors: Boolean;
|
||||
buttonIndex: Integer;
|
||||
state: ILEDStateWorker;
|
||||
color: ILEDStateColor;
|
||||
dynamicColor: ILEDStateDynamicColor;
|
||||
|
||||
begin
|
||||
FChanged := False;
|
||||
hasDynamicColors := False;
|
||||
ButtonColors.Clear;
|
||||
|
||||
for buttonIndex := 0 to Pred(ButtonWorkers.Count) do
|
||||
begin
|
||||
color := nil;
|
||||
|
||||
if Assigned(ButtonWorkers[buttonIndex]) then
|
||||
begin
|
||||
state := (ButtonWorkers[buttonIndex] as ILEDFunctionWorker).GetCurrentState;
|
||||
if Assigned(state) then
|
||||
begin
|
||||
color := state.GetColor;
|
||||
if Assigned(color) then
|
||||
begin
|
||||
if (hasDynamicColors = False) and Supports(color, ILEDStateDynamicColor, dynamicColor) then
|
||||
begin
|
||||
{ If the tick timer isn't currently running, there were no
|
||||
dynamic colors before. Reset each dynamic colors now. }
|
||||
if not HasTickTimer then
|
||||
dynamicColor.Reset;
|
||||
|
||||
hasDynamicColors := True;
|
||||
end;
|
||||
|
||||
ButtonColors.Add(color as ILEDStateColor);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
if not Assigned(color) then
|
||||
ButtonColors.Add(nil);
|
||||
end;
|
||||
|
||||
if hasDynamicColors <> HasTickTimer then
|
||||
begin
|
||||
if hasDynamicColors then
|
||||
Task.SetTimer(TIMER_TICK, INTERVAL_TICK, TM_TICK)
|
||||
else
|
||||
Task.ClearTimer(TIMER_TICK);
|
||||
end;
|
||||
|
||||
Update;
|
||||
end;
|
||||
|
||||
|
||||
{ Helpers }
|
||||
procedure ClearFunctions(AConsumer: IOmniTaskControl);
|
||||
procedure TLEDStateConsumer.TMLoadProfile(var Msg: TOmniMessage);
|
||||
var
|
||||
profile: TProfile;
|
||||
buttonIndex: Integer;
|
||||
|
||||
begin
|
||||
AConsumer.Comm.Send(MSG_CLEAR_FUNCTIONS);
|
||||
profile := Msg.MsgData;
|
||||
ButtonWorkers.Clear;
|
||||
|
||||
for buttonIndex := 0 to Pred(profile.ButtonCount) do
|
||||
begin
|
||||
if profile.HasButton(buttonIndex) then
|
||||
ButtonWorkers.Add(CreateWorker(profile.Buttons[buttonIndex]) as ILEDFunctionWorker)
|
||||
else
|
||||
ButtonWorkers.Add(nil);
|
||||
end;
|
||||
|
||||
Changed;
|
||||
end;
|
||||
|
||||
|
||||
procedure SetFunction(AConsumer: IOmniTaskControl; ALEDIndex, AFunction: Integer);
|
||||
procedure TLEDStateConsumer.TMTick(var Msg: TOmniMessage);
|
||||
var
|
||||
buttonIndex: Integer;
|
||||
checkButtonIndex: Integer;
|
||||
alreadyTicked: Boolean;
|
||||
color: ILEDStateColor;
|
||||
dynamicColor: ILEDStateDynamicColor;
|
||||
|
||||
begin
|
||||
AConsumer.Comm.Send(MSG_SET_FUNCTION, [ALEDIndex, AFunction]);
|
||||
// (MvR) 19-2-2013: I could pass a tick count to Tick() so that they can all use modulus to blink synchronously... think about it.
|
||||
|
||||
for buttonIndex := 0 to Pred(ButtonColors.Count) do
|
||||
begin
|
||||
alreadyTicked := False;
|
||||
color := (ButtonColors[buttonIndex] as ILEDStateColor);
|
||||
|
||||
if Supports(color, ILEDStateDynamicColor, dynamicColor) then
|
||||
begin
|
||||
{ Check if this color has already been ticked }
|
||||
for checkButtonIndex := Pred(buttonIndex) downto 0 do
|
||||
if (ButtonColors[checkButtonIndex] as ILEDStateColor) = color then
|
||||
begin
|
||||
alreadyTicked := True;
|
||||
break;
|
||||
end;
|
||||
|
||||
if not alreadyTicked then
|
||||
dynamicColor.Tick;
|
||||
end;
|
||||
end;
|
||||
|
||||
Update;
|
||||
end;
|
||||
|
||||
|
||||
procedure InitializeStateProvider(AConsumer: IOmniTaskControl; AProviderClass: TLEDStateProviderClass);
|
||||
{ TProfileButtonWorkerSettings }
|
||||
constructor TProfileButtonWorkerSettings.Create(AProfileButton: TProfileButton);
|
||||
begin
|
||||
AConsumer.Comm.Send(MSG_INITIALIZE_PROVIDER, Pointer(AProviderClass));
|
||||
inherited Create;
|
||||
|
||||
FProfileButton := AProfileButton;
|
||||
end;
|
||||
|
||||
|
||||
procedure FinalizeStateProvider(AConsumer: IOmniTaskControl);
|
||||
function TProfileButtonWorkerSettings.GetStateColor(const AUID: string; out AColor: TLEDColor): Boolean;
|
||||
begin
|
||||
AConsumer.Comm.Send(MSG_FINALIZE_PROVIDER);
|
||||
end;
|
||||
|
||||
|
||||
procedure Finalize(AConsumer: IOmniTaskControl);
|
||||
begin
|
||||
AConsumer.Comm.Send(MSG_FINALIZE);
|
||||
Result := ProfileButton.GetStateColor(AUID, AColor);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -21,7 +21,7 @@ type
|
||||
|
||||
ILEDStateWorker = interface(ICustomLEDState)
|
||||
['{0361CBD5-E64E-4972-A8A4-D5FE0B0DFB1C}']
|
||||
function GetColor: ILEDColor;
|
||||
function GetColor: ILEDStateColor;
|
||||
end;
|
||||
|
||||
|
||||
|
@ -1,127 +0,0 @@
|
||||
unit LEDStateProvider;
|
||||
|
||||
interface
|
||||
uses
|
||||
Classes,
|
||||
SyncObjs,
|
||||
SysUtils,
|
||||
|
||||
LEDFunctionMap;
|
||||
|
||||
type
|
||||
EInitializeError = class(Exception);
|
||||
|
||||
ILEDStateConsumer = interface
|
||||
['{6E630C92-7C5C-4D16-8BED-AE27559FA584}']
|
||||
function GetFunctionMap: TLEDFunctionMap;
|
||||
procedure SetStateByFunction(AFunction: Integer; AState: TLEDState);
|
||||
|
||||
property FunctionMap: TLEDFunctionMap read GetFunctionMap;
|
||||
end;
|
||||
|
||||
|
||||
IFunctionConsumer = interface
|
||||
['{97B47A29-BA7F-4C48-934D-EB66D2741647}']
|
||||
procedure SetCategory(const ACategory: string);
|
||||
procedure AddFunction(AFunction: Integer; const ADescription: string);
|
||||
end;
|
||||
|
||||
|
||||
TLEDStateProvider = class(TObject)
|
||||
private
|
||||
FConsumer: ILEDStateConsumer;
|
||||
FTerminated: Boolean;
|
||||
protected
|
||||
procedure Execute; virtual; abstract;
|
||||
|
||||
function GetProcessMessagesInterval: Integer; virtual;
|
||||
|
||||
property Consumer: ILEDStateConsumer read FConsumer;
|
||||
public
|
||||
class procedure EnumFunctions(AConsumer: IFunctionConsumer); virtual;
|
||||
|
||||
constructor Create(AConsumer: ILEDStateConsumer); virtual;
|
||||
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;
|
||||
|
||||
|
||||
const
|
||||
EXIT_SUCCESS = 0;
|
||||
EXIT_ERROR = 1;
|
||||
|
||||
EXIT_CONSUMER_OFFSET = 100;
|
||||
EXIT_PROVIDER_OFFSET = 200;
|
||||
|
||||
implementation
|
||||
const
|
||||
CATEGORY_STATIC = 'Static';
|
||||
|
||||
FUNCTION_DESC_OFF = 'Light off';
|
||||
FUNCTION_DESC_GREEN = 'Green';
|
||||
FUNCTION_DESC_AMBER = 'Amber';
|
||||
FUNCTION_DESC_RED = 'Red';
|
||||
|
||||
|
||||
{ TCustomLEDStateProvider }
|
||||
class procedure TLEDStateProvider.EnumFunctions(AConsumer: IFunctionConsumer);
|
||||
begin
|
||||
AConsumer.SetCategory(CATEGORY_STATIC);
|
||||
AConsumer.AddFunction(FUNCTION_OFF, FUNCTION_DESC_OFF);
|
||||
AConsumer.AddFunction(FUNCTION_GREEN, FUNCTION_DESC_GREEN);
|
||||
AConsumer.AddFunction(FUNCTION_AMBER, FUNCTION_DESC_AMBER);
|
||||
AConsumer.AddFunction(FUNCTION_RED, FUNCTION_DESC_RED);
|
||||
end;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
end.
|
@ -3,6 +3,7 @@ unit Profile;
|
||||
interface
|
||||
uses
|
||||
Generics.Collections,
|
||||
System.Classes,
|
||||
|
||||
X2UtPersistIntf,
|
||||
|
||||
@ -12,7 +13,7 @@ uses
|
||||
type
|
||||
TProfileButtonStateColors = TDictionary<string,TLEDColor>;
|
||||
|
||||
TProfileButton = class(TObject)
|
||||
TProfileButton = class(TPersistent)
|
||||
private
|
||||
FProviderUID: string;
|
||||
FFunctionUID: string;
|
||||
@ -39,7 +40,7 @@ type
|
||||
TProfileButtonList = class(TObjectList<TProfileButton>);
|
||||
|
||||
|
||||
TProfile = class(TObject)
|
||||
TProfile = class(TPersistent)
|
||||
private
|
||||
FName: string;
|
||||
FButtons: TProfileButtonList;
|
||||
@ -71,8 +72,7 @@ type
|
||||
|
||||
implementation
|
||||
uses
|
||||
Classes,
|
||||
SysUtils,
|
||||
System.SysUtils,
|
||||
|
||||
LEDResources;
|
||||
|
||||
|
@ -7,13 +7,13 @@ uses
|
||||
|
||||
|
||||
type
|
||||
TStaticLEDColor = class(TCustomLEDColor)
|
||||
TLEDStateStaticColor = class(TCustomLEDStateColor)
|
||||
private
|
||||
FColor: TLEDColor;
|
||||
FColor: TStaticLEDColor;
|
||||
protected
|
||||
function GetColor: TLEDColor; override;
|
||||
function GetCurrentColor: TStaticLEDColor; override;
|
||||
public
|
||||
constructor Create(AColor: TLEDColor);
|
||||
constructor Create(AColor: TStaticLEDColor);
|
||||
end;
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ implementation
|
||||
|
||||
|
||||
{ TStaticLEDState }
|
||||
constructor TStaticLEDColor.Create(AColor: TLEDColor);
|
||||
constructor TLEDStateStaticColor.Create(AColor: TStaticLEDColor);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
@ -29,7 +29,7 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
function TStaticLEDColor.GetColor: TLEDColor;
|
||||
function TLEDStateStaticColor.GetCurrentColor: TStaticLEDColor;
|
||||
begin
|
||||
Result := FColor;
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user