1
0
mirror of synced 2024-06-26 07:07:38 +00:00

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:
Mark van Renswoude 2013-02-19 22:22:15 +00:00
parent b66659cd95
commit f1b9a63fda
15 changed files with 305 additions and 862 deletions

View File

@ -19,9 +19,7 @@ uses
pngimage, pngimage,
X2UtPersistIntf, X2UtPersistIntf,
LEDFunctionMap,
LEDStateConsumer, LEDStateConsumer,
LEDStateProvider,
Profile; Profile;
@ -95,7 +93,6 @@ type
procedure FormCreate(Sender: TObject); procedure FormCreate(Sender: TObject);
procedure btnRetryClick(Sender: TObject); procedure btnRetryClick(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FunctionComboBoxChange(Sender: TObject);
procedure lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType); procedure lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType);
procedure btnCheckUpdatesClick(Sender: TObject); procedure btnCheckUpdatesClick(Sender: TObject);
procedure LEDButtonClick(Sender: TObject); procedure LEDButtonClick(Sender: TObject);
@ -109,15 +106,8 @@ type
FProfiles: TProfileList; FProfiles: TProfileList;
FActiveProfile: TProfile; FActiveProfile: TProfile;
FLoadingProfiles: Boolean; FLoadingProfiles: Boolean;
// FStateConsumerTask: IOmniTaskControl; FStateConsumerTask: IOmniTaskControl;
protected 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 FindLEDControls;
procedure LoadProfiles; procedure LoadProfiles;
procedure SaveProfiles; procedure SaveProfiles;
@ -129,11 +119,6 @@ type
procedure SetDeviceState(const AMessage: string; AFound: Boolean); procedure SetDeviceState(const AMessage: string; AFound: Boolean);
// procedure SetFSXToggleZoomButton(const ADeviceGUID: TGUID; AButtonIndex: Integer; const ADisplayText: string); // procedure SetFSXToggleZoomButton(const ADeviceGUID: TGUID; AButtonIndex: Integer; const ADisplayText: string);
// procedure InitializeStateProvider(AProviderClass: TLEDStateProviderClass);
// procedure FinalizeStateProvider;
// procedure UpdateMapping;
procedure CheckForUpdatesThread(const ATask: IOmniTask); procedure CheckForUpdatesThread(const ATask: IOmniTask);
procedure CheckForUpdates(AReportNoUpdates: Boolean); procedure CheckForUpdates(AReportNoUpdates: Boolean);
@ -150,7 +135,7 @@ type
property ActiveProfile: TProfile read FActiveProfile; property ActiveProfile: TProfile read FActiveProfile;
property EventMonitor: TOmniEventMonitor read FEventMonitor; property EventMonitor: TOmniEventMonitor read FEventMonitor;
property Profiles: TProfileList read FProfiles; property Profiles: TProfileList read FProfiles;
// property StateConsumerTask: IOmniTaskControl read FStateConsumerTask; property StateConsumerTask: IOmniTaskControl read FStateConsumerTask;
end; end;
@ -170,7 +155,6 @@ uses
ButtonFunctionFrm, ButtonFunctionFrm,
ConfigConversion, ConfigConversion,
FSXLEDStateProvider,
G940LEDStateConsumer, G940LEDStateConsumer,
LEDColorIntf, LEDColorIntf,
LEDFunctionIntf, LEDFunctionIntf,
@ -193,28 +177,13 @@ const
TEXT_STATE_FOUND = 'Connected'; 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 } { TMainForm }
procedure TMainForm.FormCreate(Sender: TObject); procedure TMainForm.FormCreate(Sender: TObject);
//var var
// consumer: IOmniWorker; consumer: IOmniWorker;
//
begin begin
lblVersion.Caption := App.Version.FormatVersion(False); lblVersion.Caption := App.Version.FormatVersion(False);
@ -222,12 +191,12 @@ begin
FEventMonitor := TOmniEventMonitor.Create(Self); FEventMonitor := TOmniEventMonitor.Create(Self);
// consumer := TG940LEDStateConsumer.Create; consumer := TG940LEDStateConsumer.Create;
// FStateConsumerTask := FEventMonitor.Monitor(CreateTask(consumer)).MsgWait; FStateConsumerTask := FEventMonitor.Monitor(CreateTask(consumer)).MsgWait;
EventMonitor.OnTaskMessage := EventMonitorMessage; EventMonitor.OnTaskMessage := EventMonitorMessage;
EventMonitor.OnTaskTerminated := EventMonitorTerminated; EventMonitor.OnTaskTerminated := EventMonitorTerminated;
// StateConsumerTask.Run; StateConsumerTask.Run;
FindLEDControls; FindLEDControls;
@ -235,6 +204,7 @@ begin
FProfiles := TProfileList.Create(True); FProfiles := TProfileList.Create(True);
LoadProfiles; LoadProfiles;
FStateConsumerTask.Comm.Send(TM_LOADPROFILE, ActiveProfile);
// LoadFunctions(TFSXLEDStateProvider, FFSXComboBoxes); // LoadFunctions(TFSXLEDStateProvider, FFSXComboBoxes);
// LoadDefaultProfile; // LoadDefaultProfile;
end; end;
@ -549,6 +519,7 @@ begin
if TButtonFunctionForm.Execute(ActiveProfile, buttonIndex) then if TButtonFunctionForm.Execute(ActiveProfile, buttonIndex) then
begin begin
UpdateButton(ActiveProfile, buttonIndex); UpdateButton(ActiveProfile, buttonIndex);
FStateConsumerTask.Comm.Send(TM_LOADPROFILE, ActiveProfile);
SaveProfiles; SaveProfiles;
end; end;
end; end;
@ -657,20 +628,20 @@ end;
procedure TMainForm.EventMonitorMessage(const task: IOmniTaskControl; const msg: TOmniMessage); procedure TMainForm.EventMonitorMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
begin begin
case msg.MsgID of case msg.MsgID of
MSG_NOTIFY_DEVICESTATE: HandleDeviceStateMessage(task, msg); TM_NOTIFY_DEVICESTATE: HandleDeviceStateMessage(task, msg);
MSG_RUN_IN_MAINTHREAD: HandleRunInMainThreadMessage(task, msg); // MSG_RUN_IN_MAINTHREAD: HandleRunInMainThreadMessage(task, msg);
MSG_PROVIDER_KILLED: HandleProviderKilled(task, msg); // MSG_PROVIDER_KILLED: HandleProviderKilled(task, msg);
MSG_UPDATE: 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?', 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 'Update available', MB_YESNO or MB_ICONINFORMATION) = ID_YES then
ShellExecute(Self.Handle, 'open', PChar('http://g940.x2software.net/#download'), nil, nil, SW_SHOWNORMAL); ShellExecute(Self.Handle, 'open', PChar('http://g940.x2software.net/#download'), nil, nil, SW_SHOWNORMAL);
MSG_NOUPDATE: // MSG_NOUPDATE:
if msg.MsgData.AsBoolean then // if msg.MsgData.AsBoolean then
MessageBox(Self.Handle, 'You are using the latest version.', 'No update available', MB_OK or MB_ICONINFORMATION) // MessageBox(Self.Handle, 'You are using the latest version.', 'No update available', MB_OK or MB_ICONINFORMATION)
else // else
MessageBox(Self.Handle, 'Failed to check for updates. Maybe try again later?', 'Uh-oh', MB_OK or MB_ICONWARNING); // MessageBox(Self.Handle, 'Failed to check for updates. Maybe try again later?', 'Uh-oh', MB_OK or MB_ICONWARNING);
end; end;
end; end;
@ -748,53 +719,9 @@ begin
end; 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); procedure TMainForm.lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType);
begin begin
ShellExecute(Self.Handle, 'open', PChar(Link), nil, nil, SW_SHOWNORMAL); ShellExecute(Self.Handle, 'open', PChar(Link), nil, nil, SW_SHOWNORMAL);
end; 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. end.

View File

@ -5,11 +5,8 @@ uses
MainFrm in 'Forms\MainFrm.pas' {MainForm}, MainFrm in 'Forms\MainFrm.pas' {MainForm},
LogiJoystickDLL in '..\Shared\LogiJoystickDLL.pas', LogiJoystickDLL in '..\Shared\LogiJoystickDLL.pas',
SimConnect in '..\Shared\SimConnect.pas', SimConnect in '..\Shared\SimConnect.pas',
FSXLEDStateProvider in 'Units\FSXLEDStateProvider.pas',
G940LEDStateConsumer in 'Units\G940LEDStateConsumer.pas', G940LEDStateConsumer in 'Units\G940LEDStateConsumer.pas',
LEDFunctionMap in 'Units\LEDFunctionMap.pas',
LEDStateConsumer in 'Units\LEDStateConsumer.pas', LEDStateConsumer in 'Units\LEDStateConsumer.pas',
LEDStateProvider in 'Units\LEDStateProvider.pas',
LEDColorIntf in 'Units\LEDColorIntf.pas', LEDColorIntf in 'Units\LEDColorIntf.pas',
LEDColor in 'Units\LEDColor.pas', LEDColor in 'Units\LEDColor.pas',
LEDFunctionIntf in 'Units\LEDFunctionIntf.pas', LEDFunctionIntf in 'Units\LEDFunctionIntf.pas',

View File

@ -165,11 +165,8 @@
</DCCReference> </DCCReference>
<DCCReference Include="..\Shared\LogiJoystickDLL.pas"/> <DCCReference Include="..\Shared\LogiJoystickDLL.pas"/>
<DCCReference Include="..\Shared\SimConnect.pas"/> <DCCReference Include="..\Shared\SimConnect.pas"/>
<DCCReference Include="Units\FSXLEDStateProvider.pas"/>
<DCCReference Include="Units\G940LEDStateConsumer.pas"/> <DCCReference Include="Units\G940LEDStateConsumer.pas"/>
<DCCReference Include="Units\LEDFunctionMap.pas"/>
<DCCReference Include="Units\LEDStateConsumer.pas"/> <DCCReference Include="Units\LEDStateConsumer.pas"/>
<DCCReference Include="Units\LEDStateProvider.pas"/>
<DCCReference Include="Units\LEDColorIntf.pas"/> <DCCReference Include="Units\LEDColorIntf.pas"/>
<DCCReference Include="Units\LEDColor.pas"/> <DCCReference Include="Units\LEDColor.pas"/>
<DCCReference Include="Units\LEDFunctionIntf.pas"/> <DCCReference Include="Units\LEDFunctionIntf.pas"/>

View File

@ -12,23 +12,24 @@ const
type type
TLEDColorDynArray = array of TLEDColor; TStaticLEDColorDynArray = array of TStaticLEDColor;
TDynamicLEDColor = class(TCustomDynamicLEDColor) TDynamicLEDColor = class(TCustomLEDStateDynamicColor)
private private
FCycleColors: TLEDColorDynArray; FCycleColors: TStaticLEDColorDynArray;
FCycleIndex: Integer; FCycleIndex: Integer;
FTickInterval: Integer; FTickInterval: Integer;
FTickCount: Integer; FTickCount: Integer;
protected protected
{ ILEDState } { ILEDState }
function GetColor: TLEDColor; override; function GetCurrentColor: TStaticLEDColor; override;
{ ITickLEDState } { ITickLEDState }
procedure Reset; override;
procedure Tick; override; procedure Tick; override;
public public
constructor Create(ACycleColors: TLEDColorDynArray; ATickInterval: Integer = TICKINTERVAL_NORMAL); constructor Create(ACycleColors: TStaticLEDColorDynArray; ATickInterval: Integer = TICKINTERVAL_NORMAL);
end; end;
@ -39,7 +40,7 @@ uses
{ TDynamicLEDState } { TDynamicLEDState }
constructor TDynamicLEDColor.Create(ACycleColors: TLEDColorDynArray; ATickInterval: Integer); constructor TDynamicLEDColor.Create(ACycleColors: TStaticLEDColorDynArray; ATickInterval: Integer);
begin begin
inherited Create; inherited Create;
@ -49,16 +50,22 @@ begin
FCycleColors := ACycleColors; FCycleColors := ACycleColors;
FCycleIndex := Low(FCycleColors); FCycleIndex := Low(FCycleColors);
FTickInterval := ATickInterval; FTickInterval := ATickInterval;
FTickCount := 0; Reset;
end; end;
function TDynamicLEDColor.GetColor: TLEDColor; function TDynamicLEDColor.GetCurrentColor: TStaticLEDColor;
begin begin
Result := FCycleColors[FCycleIndex]; Result := FCycleColors[FCycleIndex];
end; end;
procedure TDynamicLEDColor.Reset;
begin
FCycleIndex := 0;
end;
procedure TDynamicLEDColor.Tick; procedure TDynamicLEDColor.Tick;
begin begin
Inc(FTickCount); Inc(FTickCount);

View File

@ -8,46 +8,31 @@ uses
OtlComm, OtlComm,
OtlTaskControl, OtlTaskControl,
LEDFunctionMap, LEDStateConsumer;
LEDStateConsumer,
LEDStateProvider;
const const
MSG_FINDTHROTTLEDEVICE = MSG_CONSUMER_OFFSET + 1; TM_FINDTHROTTLEDEVICE = 2001;
MSG_NOTIFY_DEVICESTATE = MSG_CONSUMER_OFFSET + 2; TM_NOTIFY_DEVICESTATE = 2002;
MSG_TIMER_BLINK = MSG_CONSUMER_OFFSET + 3;
TIMER_BLINK = TIMER_CONSUMER_OFFSET + 1;
type type
TG940LEDStateConsumer = class(TLEDStateConsumer) TG940LEDStateConsumer = class(TLEDStateConsumer)
private private
FDirectInput: IDirectInput8; FDirectInput: IDirectInput8;
FThrottleDevice: IDirectInputDevice8; FThrottleDevice: IDirectInputDevice8;
FRed: Byte;
FGreen: Byte;
FBlinkTimerStarted: Boolean;
FBlinkCounter: Integer;
protected protected
procedure MsgFindThrottleDevice(var msg: TOmniMessage); message MSG_FINDTHROTTLEDEVICE; procedure MsgFindThrottleDevice(var msg: TOmniMessage); message TM_FINDTHROTTLEDEVICE;
procedure MsgTimerBlink(var msg: TOmniMessage); message MSG_TIMER_BLINK;
protected protected
function Initialize: Boolean; override; function Initialize: Boolean; override;
procedure ResetLEDState; override;
procedure LEDStateChanged(ALEDIndex: Integer; AState: TLEDState); override;
procedure Changed; override;
procedure StartBlinkTimer;
procedure StopBlinkTimer;
procedure FindThrottleDevice; procedure FindThrottleDevice;
procedure FoundThrottleDevice(ADeviceGUID: TGUID); procedure FoundThrottleDevice(ADeviceGUID: TGUID);
procedure SetDeviceState(AState: Integer); procedure SetDeviceState(AState: Integer);
procedure Update; override;
property DirectInput: IDirectInput8 read FDirectInput; property DirectInput: IDirectInput8 read FDirectInput;
property ThrottleDevice: IDirectInputDevice8 read FThrottleDevice; property ThrottleDevice: IDirectInputDevice8 read FThrottleDevice;
end; end;
@ -58,8 +43,8 @@ const
DEVICESTATE_FOUND = 1; DEVICESTATE_FOUND = 1;
DEVICESTATE_NOTFOUND = 2; DEVICESTATE_NOTFOUND = 2;
EXIT_ERROR_LOGIJOYSTICKDLL = EXIT_CONSUMER_OFFSET + 1; EXIT_ERROR_LOGIJOYSTICKDLL = 9001;
EXIT_ERROR_DIRECTINPUT = EXIT_CONSUMER_OFFSET + 2; EXIT_ERROR_DIRECTINPUT = 9002;
implementation implementation
@ -68,15 +53,18 @@ uses
Windows, Windows,
OtlCommon, OtlCommon,
OtlTask,
LEDColorIntf,
LogiJoystickDLL; LogiJoystickDLL;
const const
BLINK_INTERVAL = 500; G940_BUTTONCOUNT = 8;
(*
type type
TRunInMainThreadSetLEDs = class(TOmniWaitableValue, IRunInMainThread) TRunInMainThreadSetLEDs = class(TOmniWaitableValue, IRunInMainThread)
private private
@ -89,6 +77,7 @@ type
public public
constructor Create(ADevice: IDirectInputDevice8; ARed, AGreen: Byte); constructor Create(ADevice: IDirectInputDevice8; ARed, AGreen: Byte);
end; end;
*)
function EnumDevicesProc(var lpddi: TDIDeviceInstanceW; pvRef: Pointer): BOOL; stdcall; function EnumDevicesProc(var lpddi: TDIDeviceInstanceW; pvRef: Pointer): BOOL; stdcall;
@ -134,10 +123,11 @@ begin
end; end;
Result := True; Result := True;
Task.Comm.OtherEndpoint.Send(MSG_FINDTHROTTLEDEVICE); Task.Comm.OtherEndpoint.Send(TM_FINDTHROTTLEDEVICE);
end; end;
{
procedure TG940LEDStateConsumer.ResetLEDState; procedure TG940LEDStateConsumer.ResetLEDState;
begin begin
FRed := 0; FRed := 0;
@ -200,36 +190,18 @@ begin
inherited; inherited;
end; end;
}
{
procedure TG940LEDStateConsumer.Changed; procedure TG940LEDStateConsumer.Changed;
begin begin
inherited; inherited;
if Assigned(ThrottleDevice) then 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); RunInMainThread(TRunInMainThreadSetLEDs.Create(ThrottleDevice, FRed, FGreen), Destroying);
end; 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; procedure TG940LEDStateConsumer.FindThrottleDevice;
@ -243,7 +215,7 @@ begin
if not Assigned(ThrottleDevice) then if not Assigned(ThrottleDevice) then
SetDeviceState(DEVICESTATE_NOTFOUND) SetDeviceState(DEVICESTATE_NOTFOUND)
else else
Changed; Update;
end; end;
@ -256,7 +228,54 @@ end;
procedure TG940LEDStateConsumer.SetDeviceState(AState: Integer); procedure TG940LEDStateConsumer.SetDeviceState(AState: Integer);
begin 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; end;
@ -266,52 +285,8 @@ begin
end; 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 } { TRunInMainThreadSetLEDs }
(*
constructor TRunInMainThreadSetLEDs.Create(ADevice: IDirectInputDevice8; ARed, AGreen: Byte); constructor TRunInMainThreadSetLEDs.Create(ADevice: IDirectInputDevice8; ARed, AGreen: Byte);
begin begin
inherited Create; inherited Create;
@ -326,5 +301,6 @@ procedure TRunInMainThreadSetLEDs.Execute;
begin begin
SetLEDs(FDevice, FRed, FGreen); SetLEDs(FDevice, FRed, FGreen);
end; end;
*)
end. end.

View File

@ -8,16 +8,17 @@ uses
type type
TCustomLEDColor = class(TInterfacedObject, ILEDColor) TCustomLEDStateColor = class(TInterfacedObject, ILEDStateColor)
protected protected
{ ILEDState } { ILEDState }
function GetColor: TLEDColor; virtual; abstract; function GetCurrentColor: TStaticLEDColor; virtual; abstract;
end; end;
TCustomDynamicLEDColor = class(TCustomLEDColor, IDynamicLEDColor) TCustomLEDStateDynamicColor = class(TCustomLEDStateColor, ILEDStateDynamicColor)
protected protected
{ ITickLEDState } { ITickLEDState }
procedure Reset; virtual; abstract;
procedure Tick; virtual; abstract; procedure Tick; virtual; abstract;
end; end;

View File

@ -11,14 +11,15 @@ type
ILEDColor = interface ILEDStateColor = interface
['{B40DF462-B660-4002-A6B9-DD30AC69E8DB}'] ['{B40DF462-B660-4002-A6B9-DD30AC69E8DB}']
function GetColor: TLEDColor; function GetCurrentColor: TStaticLEDColor;
end; end;
IDynamicLEDColor = interface(ILEDColor) ILEDStateDynamicColor = interface(ILEDStateColor)
['{9770E851-580D-4803-9979-0C608CB108A0}'] ['{9770E851-580D-4803-9979-0C608CB108A0}']
procedure Reset;
procedure Tick; procedure Tick;
end; end;

View File

@ -8,13 +8,13 @@ uses
type type
TLEDColorPool = class(TObject) TLEDColorPool = class(TObject)
private private
FStates: array[TLEDColor] of ILEDColor; FStates: array[TLEDColor] of ILEDStateColor;
protected protected
class function Instance: TLEDColorPool; class function Instance: TLEDColorPool;
function DoGetColor(AColor: TLEDColor): ILEDColor; function DoGetColor(AColor: TLEDColor): ILEDStateColor;
public public
class function GetColor(AColor: TLEDColor): ILEDColor; overload; class function GetColor(AColor: TLEDColor): ILEDStateColor; overload;
end; end;
@ -31,7 +31,7 @@ var
{ TLEDStatePool } { TLEDStatePool }
class function TLEDColorPool.GetColor(AColor: TLEDColor): ILEDColor; class function TLEDColorPool.GetColor(AColor: TLEDColor): ILEDStateColor;
begin begin
Result := Instance.DoGetColor(AColor); Result := Instance.DoGetColor(AColor);
end; end;
@ -46,9 +46,9 @@ begin
end; end;
function TLEDColorPool.DoGetColor(AColor: TLEDColor): ILEDColor; function TLEDColorPool.DoGetColor(AColor: TLEDColor): ILEDStateColor;
function GetFlashingCycle(AColor: TLEDColor): TLEDColorDynArray; function GetFlashingCycle(AColor: TLEDColor): TStaticLEDColorDynArray;
begin begin
SetLength(Result, 2); SetLength(Result, 2);
Result[0] := AColor; Result[0] := AColor;
@ -56,16 +56,16 @@ function TLEDColorPool.DoGetColor(AColor: TLEDColor): ILEDColor;
end; end;
var var
state: ILEDColor; state: ILEDStateColor;
begin begin
if not Assigned(FStates[AColor]) then if not Assigned(FStates[AColor]) then
begin begin
case AColor of case AColor of
lcOff: state := TStaticLEDColor.Create(lcOff); lcOff: state := TLEDStateStaticColor.Create(lcOff);
lcGreen: state := TStaticLEDColor.Create(lcGreen); lcGreen: state := TLEDStateStaticColor.Create(lcGreen);
lcAmber: state := TStaticLEDColor.Create(lcAmber); lcAmber: state := TLEDStateStaticColor.Create(lcAmber);
lcRed: state := TStaticLEDColor.Create(lcRed); lcRed: state := TLEDStateStaticColor.Create(lcRed);
lcFlashingGreenFast: state := TDynamicLEDColor.Create(GetFlashingCycle(lcGreen), TICKINTERVAL_FAST); lcFlashingGreenFast: state := TDynamicLEDColor.Create(GetFlashingCycle(lcGreen), TICKINTERVAL_FAST);
lcFlashingGreenNormal: state := TDynamicLEDColor.Create(GetFlashingCycle(lcGreen), TICKINTERVAL_NORMAL); lcFlashingGreenNormal: state := TDynamicLEDColor.Create(GetFlashingCycle(lcGreen), TICKINTERVAL_NORMAL);

View File

@ -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.

View File

@ -33,12 +33,12 @@ type
TLEDStateWorker = class(TCustomLEDState, ILEDStateWorker) TLEDStateWorker = class(TCustomLEDState, ILEDStateWorker)
private private
FColor: ILEDColor; FColor: ILEDStateColor;
protected protected
{ ILEDStateWorker } { ILEDStateWorker }
function GetColor: ILEDColor; function GetColor: ILEDStateColor;
public public
constructor Create(const AUID: string; AColor: ILEDColor); constructor Create(const AUID: string; AColor: ILEDStateColor);
end; end;
@ -83,7 +83,7 @@ end;
{ TLEDStateWorker } { TLEDStateWorker }
constructor TLEDStateWorker.Create(const AUID: string; AColor: ILEDColor); constructor TLEDStateWorker.Create(const AUID: string; AColor: ILEDStateColor);
begin begin
inherited Create(AUID); inherited Create(AUID);
@ -91,7 +91,7 @@ begin
end; end;
function TLEDStateWorker.GetColor: ILEDColor; function TLEDStateWorker.GetColor: ILEDStateColor;
begin begin
Result := FColor; Result := FColor;
end; end;

View File

@ -2,29 +2,22 @@ unit LEDStateConsumer;
interface interface
uses uses
System.Classes,
OtlComm, OtlComm,
OtlCommon, OtlCommon,
OtlTaskControl, OtlTaskControl,
LEDFunctionMap, LEDColorIntf,
LEDStateProvider; LEDFunctionIntf,
Profile;
const const
MSG_CLEAR_FUNCTIONS = 1001; TM_LOADPROFILE = 1001;
MSG_SET_FUNCTION = 1002; TM_TICK = 1002;
MSG_INITIALIZE_PROVIDER = 1003;
MSG_FINALIZE_PROVIDER = 1004;
MSG_PROCESS_MESSAGES = 1005;
MSG_FINALIZE = 1006;
MSG_PROVIDER_KILLED = 1007; TIMER_TICK = 101;
MSG_RUN_IN_MAINTHREAD = 1008;
MSG_CONSUMER_OFFSET = MSG_RUN_IN_MAINTHREAD;
TIMER_PROCESSMESSAGES = 1001;
TIMER_CONSUMER_OFFSET = TIMER_PROCESSMESSAGES;
type type
@ -32,320 +25,219 @@ type
['{68B8F2F7-ED40-4078-9D99-503D7AFA068B}'] ['{68B8F2F7-ED40-4078-9D99-503D7AFA068B}']
procedure Execute; procedure Execute;
end; end;
TLEDStateConsumer = class(TOmniWorker, ILEDStateConsumer)
TLEDStateConsumer = class(TOmniWorker)
private private
FFunctionMap: TLEDFunctionMap; FButtonWorkers: TInterfaceList;
FStateMap: TLEDStateMap; FButtonColors: TInterfaceList;
FProvider: TLEDStateProvider; FHasTickTimer: Boolean;
FTimerSet: Boolean;
FChanged: Boolean;
FUpdateCount: Integer;
FDestroying: Boolean;
protected protected
procedure MsgClearFunctions(var msg: TOmniMessage); message MSG_CLEAR_FUNCTIONS; function Initialize: Boolean; override;
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;
procedure Cleanup; override; procedure Cleanup; override;
procedure InitializeProvider(AProviderClass: TLEDStateProviderClass); function CreateWorker(AProfileButton: TProfileButton): ILEDFunctionWorker;
procedure FinalizeProvider;
procedure RunInMainThread(AExecutor: IRunInMainThread; AWait: Boolean = False); property ButtonWorkers: TInterfaceList read FButtonWorkers;
procedure InitializeLEDState; virtual; property ButtonColors: TInterfaceList read FButtonColors;
procedure ResetLEDState; virtual; property HasTickTimer: Boolean read FHasTickTimer;
procedure LEDStateChanged(ALEDIndex: Integer; AState: TLEDState); virtual; protected
procedure Changed; virtual; procedure Changed; virtual;
procedure Update; virtual; abstract;
{ ILEDStateConsumer } protected
function GetFunctionMap: TLEDFunctionMap; procedure TMLoadProfile(var Msg: TOmniMessage); message TM_LOADPROFILE;
procedure SetStateByFunction(AFunction: Integer; AState: TLEDState); procedure TMTick(var Msg: TOmniMessage); message TM_TICK;
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;
end; 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 implementation
uses uses
SysUtils, System.SysUtils,
Windows; Winapi.Windows,
LEDFunctionRegistry,
LEDStateIntf;
const 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 } { TLEDStateConsumer }
constructor TLEDStateConsumer.Create; function TLEDStateConsumer.Initialize: Boolean;
begin begin
inherited; Result := inherited Initialize;
if not Result then
exit;
FFunctionMap := TLEDFunctionMap.Create; FButtonWorkers := TInterfaceList.Create;
FStateMap := TLEDStateMap.Create; FButtonColors := TInterfaceList.Create;
InitializeLEDState;
end; end;
procedure TLEDStateConsumer.Cleanup; procedure TLEDStateConsumer.Cleanup;
begin begin
inherited; FreeAndNil(FButtonColors);
FreeAndNil(FButtonWorkers);
FreeAndNil(FStateMap); inherited Cleanup;
FreeAndNil(FFunctionMap);
end; end;
procedure TLEDStateConsumer.BeginUpdate; function TLEDStateConsumer.CreateWorker(AProfileButton: TProfileButton): ILEDFunctionWorker;
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);
var var
ledIndex: Integer; provider: ILEDFunctionProvider;
ledFunction: ILEDFunction;
begin begin
if FunctionMap.FindFirst(AFunction, ledIndex) then Result := nil;
repeat
if StateMap.SetState(ledIndex, AState) then
LEDStateChanged(ledIndex, AState);
until not FunctionMap.FindNext(AFunction, ledIndex);
end;
provider := TLEDFunctionRegistry.Find(AProfileButton.ProviderUID);
if Assigned(provider) then
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
begin begin
if FTimerSet then ledFunction := provider.Find(AProfileButton.FunctionUID);
begin if Assigned(ledFunction) then
Task.ClearTimer(TIMER_PROCESSMESSAGES); Result := ledFunction.CreateWorker(TProfileButtonWorkerSettings.Create(AProfileButton));
FTimerSet := False;
end;
Provider.Terminate;
Provider.Finalize;
FreeAndNil(FProvider);
StateMap.Clear;
ResetLEDState;
end; end;
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; procedure TLEDStateConsumer.Changed;
var
hasDynamicColors: Boolean;
buttonIndex: Integer;
state: ILEDStateWorker;
color: ILEDStateColor;
dynamicColor: ILEDStateDynamicColor;
begin 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; end;
{ Helpers } procedure TLEDStateConsumer.TMLoadProfile(var Msg: TOmniMessage);
procedure ClearFunctions(AConsumer: IOmniTaskControl); var
profile: TProfile;
buttonIndex: Integer;
begin 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; 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 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; end;
procedure InitializeStateProvider(AConsumer: IOmniTaskControl; AProviderClass: TLEDStateProviderClass); { TProfileButtonWorkerSettings }
constructor TProfileButtonWorkerSettings.Create(AProfileButton: TProfileButton);
begin begin
AConsumer.Comm.Send(MSG_INITIALIZE_PROVIDER, Pointer(AProviderClass)); inherited Create;
FProfileButton := AProfileButton;
end; end;
function TProfileButtonWorkerSettings.GetStateColor(const AUID: string; out AColor: TLEDColor): Boolean;
procedure FinalizeStateProvider(AConsumer: IOmniTaskControl);
begin begin
AConsumer.Comm.Send(MSG_FINALIZE_PROVIDER); Result := ProfileButton.GetStateColor(AUID, AColor);
end;
procedure Finalize(AConsumer: IOmniTaskControl);
begin
AConsumer.Comm.Send(MSG_FINALIZE);
end; end;
end. end.

View File

@ -21,7 +21,7 @@ type
ILEDStateWorker = interface(ICustomLEDState) ILEDStateWorker = interface(ICustomLEDState)
['{0361CBD5-E64E-4972-A8A4-D5FE0B0DFB1C}'] ['{0361CBD5-E64E-4972-A8A4-D5FE0B0DFB1C}']
function GetColor: ILEDColor; function GetColor: ILEDStateColor;
end; end;

View File

@ -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.

View File

@ -3,6 +3,7 @@ unit Profile;
interface interface
uses uses
Generics.Collections, Generics.Collections,
System.Classes,
X2UtPersistIntf, X2UtPersistIntf,
@ -12,7 +13,7 @@ uses
type type
TProfileButtonStateColors = TDictionary<string,TLEDColor>; TProfileButtonStateColors = TDictionary<string,TLEDColor>;
TProfileButton = class(TObject) TProfileButton = class(TPersistent)
private private
FProviderUID: string; FProviderUID: string;
FFunctionUID: string; FFunctionUID: string;
@ -39,7 +40,7 @@ type
TProfileButtonList = class(TObjectList<TProfileButton>); TProfileButtonList = class(TObjectList<TProfileButton>);
TProfile = class(TObject) TProfile = class(TPersistent)
private private
FName: string; FName: string;
FButtons: TProfileButtonList; FButtons: TProfileButtonList;
@ -71,8 +72,7 @@ type
implementation implementation
uses uses
Classes, System.SysUtils,
SysUtils,
LEDResources; LEDResources;

View File

@ -7,13 +7,13 @@ uses
type type
TStaticLEDColor = class(TCustomLEDColor) TLEDStateStaticColor = class(TCustomLEDStateColor)
private private
FColor: TLEDColor; FColor: TStaticLEDColor;
protected protected
function GetColor: TLEDColor; override; function GetCurrentColor: TStaticLEDColor; override;
public public
constructor Create(AColor: TLEDColor); constructor Create(AColor: TStaticLEDColor);
end; end;
@ -21,7 +21,7 @@ implementation
{ TStaticLEDState } { TStaticLEDState }
constructor TStaticLEDColor.Create(AColor: TLEDColor); constructor TLEDStateStaticColor.Create(AColor: TStaticLEDColor);
begin begin
inherited Create; inherited Create;
@ -29,7 +29,7 @@ begin
end; end;
function TStaticLEDColor.GetColor: TLEDColor; function TLEDStateStaticColor.GetCurrentColor: TStaticLEDColor;
begin begin
Result := FColor; Result := FColor;
end; end;