mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Phase 3 (batch 31a): shared TDeviceStore for saved+discovered devices
Introduce DeviceStore.pas (TDeviceStore) as the single source of truth for saved devices (hpsdr_devices.ini CRUD + autostart) and the current discovery list. The controller owns one instance (created/freed in its ctor/dtor); desktop and (later) web frontends edit/render through it so the lists never diverge. Refactor TDeviceDialog to use a TDeviceStore reference instead of its own arrays + ini code. MainForm wires FDeviceDialog.Store to the controller's store, routes discovery results (DoAddDevice) and the preload-rate lookup through it (TDiscoveredDevice now carries the MAC), and drops the now-unused FDevices/TDeviceItem. Behavior-preserving for the desktop dialog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
783c8976c9
commit
7f7f429515
+63
-173
@@ -6,21 +6,10 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, FlatButton, FlatEdit, FlatListBox, AppTheme, Forms, Controls, Graphics, Dialogs,
|
Classes, SysUtils, FlatButton, FlatEdit, FlatListBox, AppTheme, Forms, Controls, Graphics, Dialogs,
|
||||||
StdCtrls, ExtCtrls, ComCtrls, IniFiles,
|
StdCtrls, ExtCtrls, ComCtrls,
|
||||||
BoardUtils, PlatformUtils;
|
BoardUtils, PlatformUtils, DeviceStore;
|
||||||
|
|
||||||
const
|
|
||||||
DEVICE_CFG_NAME = 'hpsdr_devices.ini';
|
|
||||||
|
|
||||||
type
|
type
|
||||||
// Запись о сохранённом устройстве
|
|
||||||
TSavedDevice = record
|
|
||||||
Name: string; // пользовательское имя
|
|
||||||
IPAddress: string;
|
|
||||||
BoardType: Integer;
|
|
||||||
AutoStart: Boolean; // запускать автоматически при старте
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Результат диалога
|
// Результат диалога
|
||||||
TDeviceDialogResult = record
|
TDeviceDialogResult = record
|
||||||
Accepted: Boolean;
|
Accepted: Boolean;
|
||||||
@@ -31,17 +20,11 @@ type
|
|||||||
{ TDeviceDialog }
|
{ TDeviceDialog }
|
||||||
TDeviceDialog = class(TForm)
|
TDeviceDialog = class(TForm)
|
||||||
private
|
private
|
||||||
// Сохранённые устройства
|
// Общее хранилище устройств (saved+discovered) — единый источник правды,
|
||||||
FSavedDevices: array of TSavedDevice;
|
// владелец контроллер; диалог только рендерит и редактирует через него.
|
||||||
FSavedCount: Integer;
|
FStore: TDeviceStore;
|
||||||
FResult: TDeviceDialogResult;
|
FResult: TDeviceDialogResult;
|
||||||
|
|
||||||
// Discovered devices (IP strings)
|
|
||||||
FDiscoveredIPs: array of string;
|
|
||||||
FDiscoveredNames: array of string;
|
|
||||||
FDiscoveredBoardTypes: array of Integer;
|
|
||||||
FDiscoveredCount: Integer;
|
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
PanelTop: TPanel;
|
PanelTop: TPanel;
|
||||||
PanelBottom: TPanel;
|
PanelBottom: TPanel;
|
||||||
@@ -70,8 +53,7 @@ type
|
|||||||
|
|
||||||
procedure BuildUI;
|
procedure BuildUI;
|
||||||
procedure ApplyTheme;
|
procedure ApplyTheme;
|
||||||
procedure LoadSaved;
|
procedure SetStore(AStore: TDeviceStore);
|
||||||
procedure SaveSaved;
|
|
||||||
procedure RefreshSavedList;
|
procedure RefreshSavedList;
|
||||||
|
|
||||||
procedure BtnDiscoverClick(Sender: TObject);
|
procedure BtnDiscoverClick(Sender: TObject);
|
||||||
@@ -95,8 +77,10 @@ type
|
|||||||
procedure SetTheme(const T: TAppTheme);
|
procedure SetTheme(const T: TAppTheme);
|
||||||
|
|
||||||
// Добавить найденное устройство (вызывается из MainForm при discovery)
|
// Добавить найденное устройство (вызывается из MainForm при discovery)
|
||||||
procedure AddDiscovered(const IP, DisplayName: string; BoardType: Integer = 0);
|
procedure AddDiscovered(const IP, DisplayName: string; BoardType: Integer;
|
||||||
|
const MAC: array of Byte);
|
||||||
procedure ClearDiscovered;
|
procedure ClearDiscovered;
|
||||||
|
procedure NoDevicesFound; // UI-сообщение «нет устройств» в список найденных
|
||||||
|
|
||||||
// Автозапуск: возвращает IP если есть устройство с AutoStart=True
|
// Автозапуск: возвращает IP если есть устройство с AutoStart=True
|
||||||
function GetAutoStartIP: string;
|
function GetAutoStartIP: string;
|
||||||
@@ -105,9 +89,11 @@ type
|
|||||||
|
|
||||||
// Получить/сбросить результат
|
// Получить/сбросить результат
|
||||||
procedure ClearResult;
|
procedure ClearResult;
|
||||||
|
// Общее хранилище устройств — назначается владельцем (MainForm/контроллер)
|
||||||
|
// до показа диалога; диалог рендерит и редактирует через него.
|
||||||
|
property Store: TDeviceStore read FStore write SetStore;
|
||||||
property DialogResult: TDeviceDialogResult read FResult;
|
property DialogResult: TDeviceDialogResult read FResult;
|
||||||
property OnDiscover: TNotifyEvent read FOnDiscover write FOnDiscover;
|
property OnDiscover: TNotifyEvent read FOnDiscover write FOnDiscover;
|
||||||
property SavedCount: Integer read FSavedCount;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -145,14 +131,17 @@ begin
|
|||||||
Font.Size := 8;
|
Font.Size := 8;
|
||||||
Font.Color := CLR_TEXT;
|
Font.Color := CLR_TEXT;
|
||||||
|
|
||||||
FSavedCount := 0;
|
FStore := nil; // назначается владельцем через property Store до показа
|
||||||
FDiscoveredCount := 0;
|
|
||||||
FResult.Accepted := False;
|
FResult.Accepted := False;
|
||||||
|
|
||||||
BuildUI;
|
BuildUI;
|
||||||
SetTheme(DarkTheme);
|
SetTheme(DarkTheme);
|
||||||
LoadSaved;
|
end;
|
||||||
RefreshSavedList;
|
|
||||||
|
procedure TDeviceDialog.SetStore(AStore: TDeviceStore);
|
||||||
|
begin
|
||||||
|
FStore := AStore;
|
||||||
|
if FStore <> nil then RefreshSavedList;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDeviceDialog.MakeBtn(AParent: TWinControl; const Cap: string;
|
function TDeviceDialog.MakeBtn(AParent: TWinControl; const Cap: string;
|
||||||
@@ -348,80 +337,26 @@ begin
|
|||||||
Invalidate;
|
Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDeviceDialog.LoadSaved;
|
|
||||||
var
|
|
||||||
Ini: TIniFile;
|
|
||||||
I, N: Integer;
|
|
||||||
Section: string;
|
|
||||||
begin
|
|
||||||
FSavedCount := 0;
|
|
||||||
if not FileExists(GetAppCfgDir + DEVICE_CFG_NAME) then Exit;
|
|
||||||
|
|
||||||
Ini := TIniFile.Create(GetAppCfgDir + DEVICE_CFG_NAME);
|
|
||||||
try
|
|
||||||
N := Ini.ReadInteger('Devices', 'Count', 0);
|
|
||||||
SetLength(FSavedDevices, N);
|
|
||||||
for I := 0 to N - 1 do
|
|
||||||
begin
|
|
||||||
Section := 'Device' + IntToStr(I);
|
|
||||||
FSavedDevices[I].Name := Ini.ReadString (Section, 'Name', 'HPSDR');
|
|
||||||
FSavedDevices[I].IPAddress := Ini.ReadString (Section, 'IP', '');
|
|
||||||
FSavedDevices[I].BoardType := Ini.ReadInteger(Section, 'BoardType', 0);
|
|
||||||
FSavedDevices[I].AutoStart := Ini.ReadBool (Section, 'AutoStart', False);
|
|
||||||
Inc(FSavedCount);
|
|
||||||
end;
|
|
||||||
finally
|
|
||||||
Ini.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TDeviceDialog.SaveSaved;
|
|
||||||
var
|
|
||||||
Ini: TIniFile;
|
|
||||||
I: Integer;
|
|
||||||
Section: string;
|
|
||||||
begin
|
|
||||||
Ini := TIniFile.Create(GetAppCfgDir + DEVICE_CFG_NAME);
|
|
||||||
try
|
|
||||||
Ini.WriteInteger('Devices', 'Count', FSavedCount);
|
|
||||||
for I := 0 to FSavedCount - 1 do
|
|
||||||
begin
|
|
||||||
Section := 'Device' + IntToStr(I);
|
|
||||||
Ini.WriteString (Section, 'Name', FSavedDevices[I].Name);
|
|
||||||
Ini.WriteString (Section, 'IP', FSavedDevices[I].IPAddress);
|
|
||||||
Ini.WriteInteger(Section, 'BoardType', FSavedDevices[I].BoardType);
|
|
||||||
Ini.WriteBool (Section, 'AutoStart', FSavedDevices[I].AutoStart);
|
|
||||||
end;
|
|
||||||
finally
|
|
||||||
Ini.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TDeviceDialog.RefreshSavedList;
|
procedure TDeviceDialog.RefreshSavedList;
|
||||||
var
|
var
|
||||||
I: Integer;
|
I: Integer;
|
||||||
S: string;
|
|
||||||
begin
|
begin
|
||||||
LstSaved.Items.Clear;
|
LstSaved.Items.Clear;
|
||||||
for I := 0 to FSavedCount - 1 do
|
if FStore = nil then Exit;
|
||||||
begin
|
for I := 0 to FStore.SavedCount - 1 do
|
||||||
S := FSavedDevices[I].Name + ' [' + FSavedDevices[I].IPAddress + ']';
|
LstSaved.Items.Add(FStore.SavedDisplay(I));
|
||||||
if FSavedDevices[I].BoardType > 0 then
|
|
||||||
S := S + ' ' + BoardTypeName(FSavedDevices[I].BoardType);
|
|
||||||
if FSavedDevices[I].AutoStart then
|
|
||||||
S := '* ' + S;
|
|
||||||
LstSaved.Items.Add(S);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDeviceDialog.LstSavedClick(Sender: TObject);
|
procedure TDeviceDialog.LstSavedClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
Idx: Integer;
|
Idx: Integer;
|
||||||
|
Dev: TSavedDevice;
|
||||||
begin
|
begin
|
||||||
Idx := LstSaved.ItemIndex;
|
Idx := LstSaved.ItemIndex;
|
||||||
if (Idx < 0) or (Idx >= FSavedCount) then Exit;
|
if (FStore = nil) or (Idx < 0) or (Idx >= FStore.SavedCount) then Exit;
|
||||||
EdName.Text := FSavedDevices[Idx].Name;
|
Dev := FStore.Saved(Idx);
|
||||||
EdIP.Text := FSavedDevices[Idx].IPAddress;
|
EdName.Text := Dev.Name;
|
||||||
|
EdIP.Text := Dev.IPAddress;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDeviceDialog.LstSavedDblClick(Sender: TObject);
|
procedure TDeviceDialog.LstSavedDblClick(Sender: TObject);
|
||||||
@@ -444,29 +379,20 @@ end;
|
|||||||
|
|
||||||
procedure TDeviceDialog.ClearDiscovered;
|
procedure TDeviceDialog.ClearDiscovered;
|
||||||
begin
|
begin
|
||||||
FDiscoveredCount := 0;
|
if FStore <> nil then FStore.ClearDiscovered;
|
||||||
SetLength(FDiscoveredIPs, 0);
|
|
||||||
SetLength(FDiscoveredNames, 0);
|
|
||||||
SetLength(FDiscoveredBoardTypes, 0);
|
|
||||||
LstFound.Items.Clear;
|
LstFound.Items.Clear;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDeviceDialog.AddDiscovered(const IP, DisplayName: string; BoardType: Integer = 0);
|
procedure TDeviceDialog.AddDiscovered(const IP, DisplayName: string; BoardType: Integer;
|
||||||
|
const MAC: array of Byte);
|
||||||
var
|
var
|
||||||
Idx: Integer;
|
|
||||||
S: string;
|
S: string;
|
||||||
begin
|
begin
|
||||||
|
if FStore = nil then Exit;
|
||||||
if (LstFound.Items.Count = 1) and (LstFound.Items[0] = 'Searching...') then
|
if (LstFound.Items.Count = 1) and (LstFound.Items[0] = 'Searching...') then
|
||||||
LstFound.Items.Clear;
|
LstFound.Items.Clear;
|
||||||
|
|
||||||
Idx := FDiscoveredCount;
|
FStore.AddDiscovered(IP, DisplayName, BoardType, MAC);
|
||||||
Inc(FDiscoveredCount);
|
|
||||||
SetLength(FDiscoveredIPs, FDiscoveredCount);
|
|
||||||
SetLength(FDiscoveredNames, FDiscoveredCount);
|
|
||||||
SetLength(FDiscoveredBoardTypes, FDiscoveredCount);
|
|
||||||
FDiscoveredIPs[Idx] := IP;
|
|
||||||
FDiscoveredNames[Idx] := DisplayName;
|
|
||||||
FDiscoveredBoardTypes[Idx] := BoardType;
|
|
||||||
|
|
||||||
S := DisplayName;
|
S := DisplayName;
|
||||||
if BoardType > 0 then
|
if BoardType > 0 then
|
||||||
@@ -474,44 +400,34 @@ begin
|
|||||||
LstFound.Items.Add(S);
|
LstFound.Items.Add(S);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TDeviceDialog.NoDevicesFound;
|
||||||
|
begin
|
||||||
|
ClearDiscovered;
|
||||||
|
LstFound.Items.Add('-- no device found --');
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TDeviceDialog.BtnAddClick(Sender: TObject);
|
procedure TDeviceDialog.BtnAddClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
Idx: Integer;
|
Idx: Integer;
|
||||||
begin
|
begin
|
||||||
|
if FStore = nil then Exit;
|
||||||
if Trim(EdIP.Text) = '' then
|
if Trim(EdIP.Text) = '' then
|
||||||
begin
|
begin
|
||||||
ShowMessage('Enter IP address');
|
ShowMessage('Enter IP address');
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
Idx := FStore.AddSaved(EdName.Text, EdIP.Text, 0);
|
||||||
Idx := FSavedCount;
|
|
||||||
Inc(FSavedCount);
|
|
||||||
SetLength(FSavedDevices, FSavedCount);
|
|
||||||
FSavedDevices[Idx].Name := Trim(EdName.Text);
|
|
||||||
if FSavedDevices[Idx].Name = '' then
|
|
||||||
FSavedDevices[Idx].Name := 'HPSDR';
|
|
||||||
FSavedDevices[Idx].IPAddress := Trim(EdIP.Text);
|
|
||||||
FSavedDevices[Idx].BoardType := 0;
|
|
||||||
FSavedDevices[Idx].AutoStart := False;
|
|
||||||
|
|
||||||
SaveSaved;
|
|
||||||
RefreshSavedList;
|
RefreshSavedList;
|
||||||
LstSaved.ItemIndex := Idx;
|
LstSaved.ItemIndex := Idx;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDeviceDialog.BtnRemoveClick(Sender: TObject);
|
procedure TDeviceDialog.BtnRemoveClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
Idx, I: Integer;
|
Idx: Integer;
|
||||||
begin
|
begin
|
||||||
Idx := LstSaved.ItemIndex;
|
Idx := LstSaved.ItemIndex;
|
||||||
if (Idx < 0) or (Idx >= FSavedCount) then Exit;
|
if (FStore = nil) or (Idx < 0) or (Idx >= FStore.SavedCount) then Exit;
|
||||||
|
FStore.RemoveSaved(Idx);
|
||||||
for I := Idx to FSavedCount - 2 do
|
|
||||||
FSavedDevices[I] := FSavedDevices[I + 1];
|
|
||||||
Dec(FSavedCount);
|
|
||||||
SetLength(FSavedDevices, FSavedCount);
|
|
||||||
|
|
||||||
SaveSaved;
|
|
||||||
RefreshSavedList;
|
RefreshSavedList;
|
||||||
EdName.Text := '';
|
EdName.Text := '';
|
||||||
EdIP.Text := '';
|
EdIP.Text := '';
|
||||||
@@ -519,45 +435,34 @@ end;
|
|||||||
|
|
||||||
procedure TDeviceDialog.BtnSetAutoClick(Sender: TObject);
|
procedure TDeviceDialog.BtnSetAutoClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
Idx, I: Integer;
|
Idx: Integer;
|
||||||
begin
|
begin
|
||||||
Idx := LstSaved.ItemIndex;
|
Idx := LstSaved.ItemIndex;
|
||||||
if (Idx < 0) or (Idx >= FSavedCount) then
|
if (FStore = nil) or (Idx < 0) or (Idx >= FStore.SavedCount) then
|
||||||
begin
|
begin
|
||||||
ShowMessage('Select a device first');
|
ShowMessage('Select a device first');
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
FStore.SetAutoStart(Idx);
|
||||||
// Только одно устройство может быть AutoStart
|
|
||||||
for I := 0 to FSavedCount - 1 do
|
|
||||||
FSavedDevices[I].AutoStart := (I = Idx);
|
|
||||||
|
|
||||||
SaveSaved;
|
|
||||||
RefreshSavedList;
|
RefreshSavedList;
|
||||||
LstSaved.ItemIndex := Idx;
|
LstSaved.ItemIndex := Idx;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDeviceDialog.BtnAddFoundClick(Sender: TObject);
|
procedure TDeviceDialog.BtnAddFoundClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
Idx: Integer;
|
Idx, NewIdx: Integer;
|
||||||
|
D: TDiscoveredDevice;
|
||||||
begin
|
begin
|
||||||
Idx := LstFound.ItemIndex;
|
Idx := LstFound.ItemIndex;
|
||||||
if (Idx < 0) or (Idx >= FDiscoveredCount) then
|
if (FStore = nil) or (Idx < 0) or (Idx >= FStore.DiscoveredCount) then
|
||||||
begin
|
begin
|
||||||
ShowMessage('Select a discovered device first');
|
ShowMessage('Select a discovered device first');
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
EdIP.Text := FDiscoveredIPs[Idx];
|
D := FStore.Discovered(Idx);
|
||||||
EdName.Text := FDiscoveredNames[Idx];
|
NewIdx := FStore.AddSaved(D.DisplayName, D.IPAddress, D.BoardType);
|
||||||
BtnAddClick(nil);
|
|
||||||
// Обновляем BoardType только что добавленной записи
|
|
||||||
if FSavedCount > 0 then
|
|
||||||
begin
|
|
||||||
FSavedDevices[FSavedCount - 1].BoardType := FDiscoveredBoardTypes[Idx];
|
|
||||||
SaveSaved;
|
|
||||||
RefreshSavedList;
|
RefreshSavedList;
|
||||||
LstSaved.ItemIndex := FSavedCount - 1;
|
LstSaved.ItemIndex := NewIdx;
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDeviceDialog.BtnConnectClick(Sender: TObject);
|
procedure TDeviceDialog.BtnConnectClick(Sender: TObject);
|
||||||
@@ -566,20 +471,21 @@ var
|
|||||||
Idx: Integer;
|
Idx: Integer;
|
||||||
begin
|
begin
|
||||||
IP := '';
|
IP := '';
|
||||||
|
if FStore = nil then Exit;
|
||||||
|
|
||||||
// Приоритет: выбранное сохранённое > выбранное найденное > ручной IP
|
// Приоритет: выбранное сохранённое > выбранное найденное > ручной IP
|
||||||
Idx := LstSaved.ItemIndex;
|
Idx := LstSaved.ItemIndex;
|
||||||
if (Idx >= 0) and (Idx < FSavedCount) then
|
if (Idx >= 0) and (Idx < FStore.SavedCount) then
|
||||||
begin
|
begin
|
||||||
IP := FSavedDevices[Idx].IPAddress;
|
IP := FStore.Saved(Idx).IPAddress;
|
||||||
FResult.SavedIdx := Idx;
|
FResult.SavedIdx := Idx;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
Idx := LstFound.ItemIndex;
|
Idx := LstFound.ItemIndex;
|
||||||
if (Idx >= 0) and (Idx < FDiscoveredCount) then
|
if (Idx >= 0) and (Idx < FStore.DiscoveredCount) then
|
||||||
begin
|
begin
|
||||||
IP := FDiscoveredIPs[Idx];
|
IP := FStore.Discovered(Idx).IPAddress;
|
||||||
FResult.SavedIdx := -1;
|
FResult.SavedIdx := -1;
|
||||||
end
|
end
|
||||||
else if Trim(EdIP.Text) <> '' then
|
else if Trim(EdIP.Text) <> '' then
|
||||||
@@ -614,37 +520,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TDeviceDialog.GetAutoStartIP: string;
|
function TDeviceDialog.GetAutoStartIP: string;
|
||||||
var
|
|
||||||
I: Integer;
|
|
||||||
begin
|
begin
|
||||||
Result := '';
|
if FStore <> nil then Result := FStore.AutoStartIP
|
||||||
for I := 0 to FSavedCount - 1 do
|
else Result := '';
|
||||||
if FSavedDevices[I].AutoStart then
|
|
||||||
begin
|
|
||||||
Result := FSavedDevices[I].IPAddress;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDeviceDialog.GetAutoStartBoardType: Integer;
|
function TDeviceDialog.GetAutoStartBoardType: Integer;
|
||||||
var
|
|
||||||
I: Integer;
|
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
if FStore <> nil then Result := FStore.AutoStartBoardType
|
||||||
for I := 0 to FSavedCount - 1 do
|
else Result := 0;
|
||||||
if FSavedDevices[I].AutoStart then
|
|
||||||
begin
|
|
||||||
Result := FSavedDevices[I].BoardType;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDeviceDialog.GetSavedBoardType(Idx: Integer): Integer;
|
function TDeviceDialog.GetSavedBoardType(Idx: Integer): Integer;
|
||||||
begin
|
begin
|
||||||
if (Idx >= 0) and (Idx < FSavedCount) then
|
if FStore <> nil then Result := FStore.SavedBoardType(Idx)
|
||||||
Result := FSavedDevices[Idx].BoardType
|
else Result := 0;
|
||||||
else
|
|
||||||
Result := 0;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
+279
@@ -0,0 +1,279 @@
|
|||||||
|
unit DeviceStore;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
// Общее хранилище устройств — единый источник правды для десктоп-диалога
|
||||||
|
// (DeviceForm) и web-оверлея. Владеет сохранёнными устройствами (persist в
|
||||||
|
// hpsdr_devices.ini) и текущим списком найденных при discovery.
|
||||||
|
// Контроллер (TRadioController) держит один экземпляр; фронтенды работают
|
||||||
|
// через него, поэтому списки не расходятся.
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, IniFiles, BoardUtils, PlatformUtils;
|
||||||
|
|
||||||
|
const
|
||||||
|
DEVICE_CFG_NAME = 'hpsdr_devices.ini';
|
||||||
|
|
||||||
|
type
|
||||||
|
// Запись о сохранённом устройстве
|
||||||
|
TSavedDevice = record
|
||||||
|
Name: string; // пользовательское имя
|
||||||
|
IPAddress: string;
|
||||||
|
BoardType: Integer;
|
||||||
|
AutoStart: Boolean; // запускать автоматически при старте
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Найденное устройство (результат discovery)
|
||||||
|
TDiscoveredDevice = record
|
||||||
|
IPAddress: string;
|
||||||
|
DisplayName: string;
|
||||||
|
BoardType: Integer;
|
||||||
|
MAC: array[0..5] of Byte; // нужен для preload-rate lookup (LoadDevice по MAC)
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDeviceStore }
|
||||||
|
TDeviceStore = class
|
||||||
|
private
|
||||||
|
FSaved: array of TSavedDevice;
|
||||||
|
FSavedCount: Integer;
|
||||||
|
FDiscovered: array of TDiscoveredDevice;
|
||||||
|
FDiscoveredCount: Integer;
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
|
||||||
|
// ---- Сохранённые устройства ----
|
||||||
|
procedure LoadSaved;
|
||||||
|
procedure SaveSaved;
|
||||||
|
function SavedCount: Integer;
|
||||||
|
function Saved(Idx: Integer): TSavedDevice;
|
||||||
|
// Добавляет запись (Name пустое → 'HPSDR'); возвращает индекс новой записи.
|
||||||
|
function AddSaved(const AName, IP: string; BoardType: Integer): Integer;
|
||||||
|
procedure RemoveSaved(Idx: Integer);
|
||||||
|
procedure SetAutoStart(Idx: Integer); // эксклюзивно: только одно autostart
|
||||||
|
function AutoStartIP: string;
|
||||||
|
function AutoStartBoardType: Integer;
|
||||||
|
function SavedBoardType(Idx: Integer): Integer;
|
||||||
|
function SavedDisplay(Idx: Integer): string; // строка для списка (с * и board)
|
||||||
|
|
||||||
|
// ---- Найденные (discovery) ----
|
||||||
|
procedure ClearDiscovered;
|
||||||
|
procedure AddDiscovered(const IP, DisplayName: string; BoardType: Integer;
|
||||||
|
const MAC: array of Byte);
|
||||||
|
function DiscoveredCount: Integer;
|
||||||
|
function Discovered(Idx: Integer): TDiscoveredDevice;
|
||||||
|
// IP найденного устройства по IP (для preload-rate lookup и т.п.)
|
||||||
|
function FindDiscoveredByIP(const IP: string): Integer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{ TDeviceStore }
|
||||||
|
|
||||||
|
constructor TDeviceStore.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FSavedCount := 0;
|
||||||
|
FDiscoveredCount := 0;
|
||||||
|
LoadSaved;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDeviceStore.LoadSaved;
|
||||||
|
var
|
||||||
|
Ini: TIniFile;
|
||||||
|
I, N: Integer;
|
||||||
|
Section: string;
|
||||||
|
begin
|
||||||
|
FSavedCount := 0;
|
||||||
|
SetLength(FSaved, 0);
|
||||||
|
if not FileExists(GetAppCfgDir + DEVICE_CFG_NAME) then Exit;
|
||||||
|
|
||||||
|
Ini := TIniFile.Create(GetAppCfgDir + DEVICE_CFG_NAME);
|
||||||
|
try
|
||||||
|
N := Ini.ReadInteger('Devices', 'Count', 0);
|
||||||
|
SetLength(FSaved, N);
|
||||||
|
for I := 0 to N - 1 do
|
||||||
|
begin
|
||||||
|
Section := 'Device' + IntToStr(I);
|
||||||
|
FSaved[I].Name := Ini.ReadString (Section, 'Name', 'HPSDR');
|
||||||
|
FSaved[I].IPAddress := Ini.ReadString (Section, 'IP', '');
|
||||||
|
FSaved[I].BoardType := Ini.ReadInteger(Section, 'BoardType', 0);
|
||||||
|
FSaved[I].AutoStart := Ini.ReadBool (Section, 'AutoStart', False);
|
||||||
|
Inc(FSavedCount);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Ini.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDeviceStore.SaveSaved;
|
||||||
|
var
|
||||||
|
Ini: TIniFile;
|
||||||
|
I: Integer;
|
||||||
|
Section: string;
|
||||||
|
begin
|
||||||
|
Ini := TIniFile.Create(GetAppCfgDir + DEVICE_CFG_NAME);
|
||||||
|
try
|
||||||
|
Ini.WriteInteger('Devices', 'Count', FSavedCount);
|
||||||
|
for I := 0 to FSavedCount - 1 do
|
||||||
|
begin
|
||||||
|
Section := 'Device' + IntToStr(I);
|
||||||
|
Ini.WriteString (Section, 'Name', FSaved[I].Name);
|
||||||
|
Ini.WriteString (Section, 'IP', FSaved[I].IPAddress);
|
||||||
|
Ini.WriteInteger(Section, 'BoardType', FSaved[I].BoardType);
|
||||||
|
Ini.WriteBool (Section, 'AutoStart', FSaved[I].AutoStart);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Ini.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.SavedCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := FSavedCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.Saved(Idx: Integer): TSavedDevice;
|
||||||
|
begin
|
||||||
|
if (Idx >= 0) and (Idx < FSavedCount) then
|
||||||
|
Result := FSaved[Idx]
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result.Name := ''; Result.IPAddress := '';
|
||||||
|
Result.BoardType := 0; Result.AutoStart := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.AddSaved(const AName, IP: string; BoardType: Integer): Integer;
|
||||||
|
begin
|
||||||
|
Result := FSavedCount;
|
||||||
|
Inc(FSavedCount);
|
||||||
|
SetLength(FSaved, FSavedCount);
|
||||||
|
if Trim(AName) <> '' then FSaved[Result].Name := Trim(AName)
|
||||||
|
else FSaved[Result].Name := 'HPSDR';
|
||||||
|
FSaved[Result].IPAddress := Trim(IP);
|
||||||
|
FSaved[Result].BoardType := BoardType;
|
||||||
|
FSaved[Result].AutoStart := False;
|
||||||
|
SaveSaved;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDeviceStore.RemoveSaved(Idx: Integer);
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
if (Idx < 0) or (Idx >= FSavedCount) then Exit;
|
||||||
|
for I := Idx to FSavedCount - 2 do
|
||||||
|
FSaved[I] := FSaved[I + 1];
|
||||||
|
Dec(FSavedCount);
|
||||||
|
SetLength(FSaved, FSavedCount);
|
||||||
|
SaveSaved;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDeviceStore.SetAutoStart(Idx: Integer);
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
if (Idx < 0) or (Idx >= FSavedCount) then Exit;
|
||||||
|
// Только одно устройство может быть AutoStart
|
||||||
|
for I := 0 to FSavedCount - 1 do
|
||||||
|
FSaved[I].AutoStart := (I = Idx);
|
||||||
|
SaveSaved;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.AutoStartIP: string;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
for I := 0 to FSavedCount - 1 do
|
||||||
|
if FSaved[I].AutoStart then
|
||||||
|
begin
|
||||||
|
Result := FSaved[I].IPAddress;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.AutoStartBoardType: Integer;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
for I := 0 to FSavedCount - 1 do
|
||||||
|
if FSaved[I].AutoStart then
|
||||||
|
begin
|
||||||
|
Result := FSaved[I].BoardType;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.SavedBoardType(Idx: Integer): Integer;
|
||||||
|
begin
|
||||||
|
if (Idx >= 0) and (Idx < FSavedCount) then
|
||||||
|
Result := FSaved[Idx].BoardType
|
||||||
|
else
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.SavedDisplay(Idx: Integer): string;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
if (Idx < 0) or (Idx >= FSavedCount) then Exit;
|
||||||
|
Result := FSaved[Idx].Name + ' [' + FSaved[Idx].IPAddress + ']';
|
||||||
|
if FSaved[Idx].BoardType > 0 then
|
||||||
|
Result := Result + ' ' + BoardTypeName(FSaved[Idx].BoardType);
|
||||||
|
if FSaved[Idx].AutoStart then
|
||||||
|
Result := '* ' + Result;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDeviceStore.ClearDiscovered;
|
||||||
|
begin
|
||||||
|
FDiscoveredCount := 0;
|
||||||
|
SetLength(FDiscovered, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDeviceStore.AddDiscovered(const IP, DisplayName: string; BoardType: Integer;
|
||||||
|
const MAC: array of Byte);
|
||||||
|
var
|
||||||
|
Idx, J: Integer;
|
||||||
|
begin
|
||||||
|
Idx := FDiscoveredCount;
|
||||||
|
Inc(FDiscoveredCount);
|
||||||
|
SetLength(FDiscovered, FDiscoveredCount);
|
||||||
|
FDiscovered[Idx].IPAddress := IP;
|
||||||
|
FDiscovered[Idx].DisplayName := DisplayName;
|
||||||
|
FDiscovered[Idx].BoardType := BoardType;
|
||||||
|
FillChar(FDiscovered[Idx].MAC, SizeOf(FDiscovered[Idx].MAC), 0);
|
||||||
|
for J := 0 to High(MAC) do
|
||||||
|
if J <= 5 then FDiscovered[Idx].MAC[J] := MAC[J];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.DiscoveredCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := FDiscoveredCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.Discovered(Idx: Integer): TDiscoveredDevice;
|
||||||
|
begin
|
||||||
|
if (Idx >= 0) and (Idx < FDiscoveredCount) then
|
||||||
|
Result := FDiscovered[Idx]
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result.IPAddress := ''; Result.DisplayName := ''; Result.BoardType := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDeviceStore.FindDiscoveredByIP(const IP: string): Integer;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
Result := -1;
|
||||||
|
for I := 0 to FDiscoveredCount - 1 do
|
||||||
|
if SameText(FDiscovered[I].IPAddress, IP) then
|
||||||
|
begin
|
||||||
|
Result := I;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
+15
-31
@@ -41,6 +41,7 @@ uses
|
|||||||
FlatEdit, FMRepeater,
|
FlatEdit, FMRepeater,
|
||||||
ChannelStore, ChannelsForm,
|
ChannelStore, ChannelsForm,
|
||||||
PowerInhibit,
|
PowerInhibit,
|
||||||
|
DeviceStore,
|
||||||
RadioController;
|
RadioController;
|
||||||
|
|
||||||
const
|
const
|
||||||
@@ -107,11 +108,6 @@ const
|
|||||||
LEFT_PANEL_BTN_GAP = 2;
|
LEFT_PANEL_BTN_GAP = 2;
|
||||||
|
|
||||||
type
|
type
|
||||||
TDeviceItem = record
|
|
||||||
Dev: THPSDRDevice;
|
|
||||||
Display: string;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TMainForm }
|
{ TMainForm }
|
||||||
TMainForm = class(TForm)
|
TMainForm = class(TForm)
|
||||||
private
|
private
|
||||||
@@ -124,8 +120,7 @@ type
|
|||||||
FSyncingFromController: Boolean;
|
FSyncingFromController: Boolean;
|
||||||
|
|
||||||
// ---- Network ----
|
// ---- Network ----
|
||||||
FDevices: array of TDeviceItem;
|
// Список устройств (saved+discovered) → FController.FDeviceStore (общий с web).
|
||||||
FDeviceCount: Integer;
|
|
||||||
FDeviceDialog: TDeviceDialog;
|
FDeviceDialog: TDeviceDialog;
|
||||||
FPendingIP: string; // IP устройства для подключения
|
FPendingIP: string; // IP устройства для подключения
|
||||||
FVfoOverlay: TVfoOverlay; // накладка SmartSDR-стиль на спектре
|
FVfoOverlay: TVfoOverlay; // накладка SmartSDR-стиль на спектре
|
||||||
@@ -1039,8 +1034,8 @@ begin
|
|||||||
FController.FLastSupplyV:= -1;
|
FController.FLastSupplyV:= -1;
|
||||||
FController.FLastSupplyA:= -1;
|
FController.FLastSupplyA:= -1;
|
||||||
FController.FLastPLLLock:= False;
|
FController.FLastPLLLock:= False;
|
||||||
FDeviceCount := 0;
|
|
||||||
FDeviceDialog := TDeviceDialog.Create(Self);
|
FDeviceDialog := TDeviceDialog.Create(Self);
|
||||||
|
FDeviceDialog.Store := FController.FDeviceStore;
|
||||||
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
||||||
FVfoOverlay := TVfoOverlay.Create(Self);
|
FVfoOverlay := TVfoOverlay.Create(Self);
|
||||||
FVfoOverlay.OnSelect := OnModeFilterSelect;
|
FVfoOverlay.OnSelect := OnModeFilterSelect;
|
||||||
@@ -3285,18 +3280,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.DoAddDevice(const Dev: THPSDRDevice; const Entry: string);
|
procedure TMainForm.DoAddDevice(const Dev: THPSDRDevice; const Entry: string);
|
||||||
var
|
|
||||||
Idx: Integer;
|
|
||||||
begin
|
begin
|
||||||
Idx := Length(FDevices);
|
// Найденное устройство → общий store (через диалог, который пишет store +
|
||||||
SetLength(FDevices, Idx + 1);
|
// рендерит список). MAC нужен для preload-rate lookup в BtnStartStopClick.
|
||||||
FDevices[Idx].Dev := Dev;
|
|
||||||
FDevices[Idx].Display := Entry;
|
|
||||||
Inc(FDeviceCount);
|
|
||||||
|
|
||||||
if Assigned(FDeviceDialog) then
|
if Assigned(FDeviceDialog) then
|
||||||
FDeviceDialog.AddDiscovered(Dev.IPAddress, Entry, Dev.BoardType);
|
FDeviceDialog.AddDiscovered(Dev.IPAddress, Entry, Dev.BoardType, Dev.MAC);
|
||||||
|
|
||||||
SetStatusText(2, Format('Found: %s', [Dev.IPAddress]));
|
SetStatusText(2, Format('Found: %s', [Dev.IPAddress]));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -3457,10 +3445,7 @@ begin
|
|||||||
if DDCIdx = -1 then
|
if DDCIdx = -1 then
|
||||||
begin
|
begin
|
||||||
if Assigned(FDeviceDialog) then
|
if Assigned(FDeviceDialog) then
|
||||||
begin
|
FDeviceDialog.NoDevicesFound;
|
||||||
FDeviceDialog.ClearDiscovered;
|
|
||||||
FDeviceDialog.AddDiscovered('', '-- no device found --');
|
|
||||||
end;
|
|
||||||
SetStatusText(2, 'No hardware found');
|
SetStatusText(2, 'No hardware found');
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -3555,6 +3540,7 @@ begin
|
|||||||
// Открываем диалог выбора устройства
|
// Открываем диалог выбора устройства
|
||||||
if not Assigned(FDeviceDialog) then
|
if not Assigned(FDeviceDialog) then
|
||||||
FDeviceDialog := TDeviceDialog.Create(Self);
|
FDeviceDialog := TDeviceDialog.Create(Self);
|
||||||
|
FDeviceDialog.Store := FController.FDeviceStore;
|
||||||
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
||||||
if FLightTheme then FDeviceDialog.SetTheme(LightTheme)
|
if FLightTheme then FDeviceDialog.SetTheme(LightTheme)
|
||||||
else FDeviceDialog.SetTheme(DarkTheme);
|
else FDeviceDialog.SetTheme(DarkTheme);
|
||||||
@@ -3567,8 +3553,7 @@ end;
|
|||||||
procedure TMainForm.BtnDiscoverFromDialog(Sender: TObject);
|
procedure TMainForm.BtnDiscoverFromDialog(Sender: TObject);
|
||||||
// Запускается когда пользователь нажимает DISCOVER внутри диалога
|
// Запускается когда пользователь нажимает DISCOVER внутри диалога
|
||||||
begin
|
begin
|
||||||
SetLength(FDevices, 0);
|
FController.FDeviceStore.ClearDiscovered;
|
||||||
FDeviceCount := 0;
|
|
||||||
SetStatusText(2, 'Discovering...');
|
SetStatusText(2, 'Discovering...');
|
||||||
FController.FNetwork.DirectIP := '';
|
FController.FNetwork.DirectIP := '';
|
||||||
TDiscoverThread.Create(FController.FNetwork, Self);
|
TDiscoverThread.Create(FController.FNetwork, Self);
|
||||||
@@ -3576,10 +3561,8 @@ end;
|
|||||||
|
|
||||||
procedure TMainForm.BtnStartStopClick(Sender: TObject);
|
procedure TMainForm.BtnStartStopClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
Idx, i: Integer;
|
i: Integer;
|
||||||
Dev: THPSDRDevice;
|
Dev: THPSDRDevice;
|
||||||
GenPkt: TGeneralPacket;
|
|
||||||
G_Settings: TGlobalSettings;
|
|
||||||
PreG: TGlobalSettings;
|
PreG: TGlobalSettings;
|
||||||
PreBands: array[0..CFG_BAND_COUNT-1] of TBandSettings;
|
PreBands: array[0..CFG_BAND_COUNT-1] of TBandSettings;
|
||||||
PreloadRate: Integer;
|
PreloadRate: Integer;
|
||||||
@@ -3641,6 +3624,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
if not Assigned(FDeviceDialog) then
|
if not Assigned(FDeviceDialog) then
|
||||||
FDeviceDialog := TDeviceDialog.Create(Self);
|
FDeviceDialog := TDeviceDialog.Create(Self);
|
||||||
|
FDeviceDialog.Store := FController.FDeviceStore;
|
||||||
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
||||||
if FLightTheme then FDeviceDialog.SetTheme(LightTheme)
|
if FLightTheme then FDeviceDialog.SetTheme(LightTheme)
|
||||||
else FDeviceDialog.SetTheme(DarkTheme);
|
else FDeviceDialog.SetTheme(DarkTheme);
|
||||||
@@ -3664,13 +3648,13 @@ begin
|
|||||||
// создаём WDSPEngine сразу с нужной частотой.
|
// создаём WDSPEngine сразу с нужной частотой.
|
||||||
PreloadRate := FController.FSampleRate;
|
PreloadRate := FController.FSampleRate;
|
||||||
FoundByIP := False;
|
FoundByIP := False;
|
||||||
for i := 0 to High(FDevices) do
|
i := FController.FDeviceStore.FindDiscoveredByIP(Dev.IPAddress);
|
||||||
if SameText(FDevices[i].Dev.IPAddress, Dev.IPAddress) then
|
if i >= 0 then
|
||||||
begin
|
begin
|
||||||
FoundByIP := True;
|
FoundByIP := True;
|
||||||
if FController.FSettings.LoadDevice(FDevices[i].Dev.MAC, PreG, PreBands) and (PreG.SampleRate > 0) then
|
if FController.FSettings.LoadDevice(FController.FDeviceStore.Discovered(i).MAC, PreG, PreBands)
|
||||||
|
and (PreG.SampleRate > 0) then
|
||||||
PreloadRate := PreG.SampleRate;
|
PreloadRate := PreG.SampleRate;
|
||||||
Break;
|
|
||||||
end;
|
end;
|
||||||
if FoundByIP and (PreloadRate > 0) then
|
if FoundByIP and (PreloadRate > 0) then
|
||||||
begin
|
begin
|
||||||
|
|||||||
+4
-1
@@ -50,7 +50,7 @@ uses
|
|||||||
Classes, SysUtils, Math,
|
Classes, SysUtils, Math,
|
||||||
HPSDRProtocol, HPSDRNetwork,
|
HPSDRProtocol, HPSDRNetwork,
|
||||||
WDSPEngine, AudioOutput, AudioInput,
|
WDSPEngine, AudioOutput, AudioInput,
|
||||||
Settings, ChannelStore, FMRepeater, BoardUtils;
|
Settings, ChannelStore, FMRepeater, BoardUtils, DeviceStore;
|
||||||
|
|
||||||
type
|
type
|
||||||
// Поле, которое изменилось — для гранулярных уведомлений наружу.
|
// Поле, которое изменилось — для гранулярных уведомлений наружу.
|
||||||
@@ -128,6 +128,7 @@ type
|
|||||||
FAudioIn: TAudioInput;
|
FAudioIn: TAudioInput;
|
||||||
FSettings: TSettingsManager;
|
FSettings: TSettingsManager;
|
||||||
FChannelStore: TChannelStore;
|
FChannelStore: TChannelStore;
|
||||||
|
FDeviceStore: TDeviceStore; // общий список устройств (saved+discovered)
|
||||||
FWDSPReady: Boolean;
|
FWDSPReady: Boolean;
|
||||||
|
|
||||||
// ---- Частоты / режим / фильтр / AGC ----
|
// ---- Частоты / режим / фильтр / AGC ----
|
||||||
@@ -413,6 +414,7 @@ constructor TRadioController.Create;
|
|||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FSettings := TSettingsManager.Create; // владелец настроек (GUI и демон)
|
FSettings := TSettingsManager.Create; // владелец настроек (GUI и демон)
|
||||||
|
FDeviceStore := TDeviceStore.Create; // общий список устройств (desktop+web)
|
||||||
// Дефолты (дублируют TMainForm.FormCreate; в GUI перезапишутся, в демоне нужны).
|
// Дефолты (дублируют TMainForm.FormCreate; в GUI перезапишутся, в демоне нужны).
|
||||||
FVfoA := 14200000; FVfoB := 7100000; FActiveVfo := 0;
|
FVfoA := 14200000; FVfoB := 7100000; FActiveVfo := 0;
|
||||||
FMode := 1; FFilter := 5; FFilterBW := 2700;
|
FMode := 1; FFilter := 5; FFilterBW := 2700;
|
||||||
@@ -459,6 +461,7 @@ end;
|
|||||||
destructor TRadioController.Destroy;
|
destructor TRadioController.Destroy;
|
||||||
begin
|
begin
|
||||||
FreeEngines;
|
FreeEngines;
|
||||||
|
FreeAndNil(FDeviceStore);
|
||||||
FreeAndNil(FSettings);
|
FreeAndNil(FSettings);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|||||||
Reference in New Issue
Block a user