diff --git a/DeviceForm.pas b/DeviceForm.pas index d445273..92d5f9a 100644 --- a/DeviceForm.pas +++ b/DeviceForm.pas @@ -6,21 +6,10 @@ interface uses Classes, SysUtils, FlatButton, FlatEdit, FlatListBox, AppTheme, Forms, Controls, Graphics, Dialogs, - StdCtrls, ExtCtrls, ComCtrls, IniFiles, - BoardUtils, PlatformUtils; - -const - DEVICE_CFG_NAME = 'hpsdr_devices.ini'; + StdCtrls, ExtCtrls, ComCtrls, + BoardUtils, PlatformUtils, DeviceStore; type - // Запись о сохранённом устройстве - TSavedDevice = record - Name: string; // пользовательское имя - IPAddress: string; - BoardType: Integer; - AutoStart: Boolean; // запускать автоматически при старте - end; - // Результат диалога TDeviceDialogResult = record Accepted: Boolean; @@ -31,17 +20,11 @@ type { TDeviceDialog } TDeviceDialog = class(TForm) private - // Сохранённые устройства - FSavedDevices: array of TSavedDevice; - FSavedCount: Integer; + // Общее хранилище устройств (saved+discovered) — единый источник правды, + // владелец контроллер; диалог только рендерит и редактирует через него. + FStore: TDeviceStore; FResult: TDeviceDialogResult; - // Discovered devices (IP strings) - FDiscoveredIPs: array of string; - FDiscoveredNames: array of string; - FDiscoveredBoardTypes: array of Integer; - FDiscoveredCount: Integer; - // UI PanelTop: TPanel; PanelBottom: TPanel; @@ -70,8 +53,7 @@ type procedure BuildUI; procedure ApplyTheme; - procedure LoadSaved; - procedure SaveSaved; + procedure SetStore(AStore: TDeviceStore); procedure RefreshSavedList; procedure BtnDiscoverClick(Sender: TObject); @@ -95,8 +77,10 @@ type procedure SetTheme(const T: TAppTheme); // Добавить найденное устройство (вызывается из 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 NoDevicesFound; // UI-сообщение «нет устройств» в список найденных // Автозапуск: возвращает IP если есть устройство с AutoStart=True function GetAutoStartIP: string; @@ -105,9 +89,11 @@ type // Получить/сбросить результат procedure ClearResult; + // Общее хранилище устройств — назначается владельцем (MainForm/контроллер) + // до показа диалога; диалог рендерит и редактирует через него. + property Store: TDeviceStore read FStore write SetStore; property DialogResult: TDeviceDialogResult read FResult; property OnDiscover: TNotifyEvent read FOnDiscover write FOnDiscover; - property SavedCount: Integer read FSavedCount; end; implementation @@ -145,14 +131,17 @@ begin Font.Size := 8; Font.Color := CLR_TEXT; - FSavedCount := 0; - FDiscoveredCount := 0; + FStore := nil; // назначается владельцем через property Store до показа FResult.Accepted := False; BuildUI; SetTheme(DarkTheme); - LoadSaved; - RefreshSavedList; +end; + +procedure TDeviceDialog.SetStore(AStore: TDeviceStore); +begin + FStore := AStore; + if FStore <> nil then RefreshSavedList; end; function TDeviceDialog.MakeBtn(AParent: TWinControl; const Cap: string; @@ -348,80 +337,26 @@ begin Invalidate; 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; var I: Integer; - S: string; begin LstSaved.Items.Clear; - for I := 0 to FSavedCount - 1 do - begin - S := FSavedDevices[I].Name + ' [' + FSavedDevices[I].IPAddress + ']'; - if FSavedDevices[I].BoardType > 0 then - S := S + ' ' + BoardTypeName(FSavedDevices[I].BoardType); - if FSavedDevices[I].AutoStart then - S := '* ' + S; - LstSaved.Items.Add(S); - end; + if FStore = nil then Exit; + for I := 0 to FStore.SavedCount - 1 do + LstSaved.Items.Add(FStore.SavedDisplay(I)); end; procedure TDeviceDialog.LstSavedClick(Sender: TObject); var Idx: Integer; + Dev: TSavedDevice; begin Idx := LstSaved.ItemIndex; - if (Idx < 0) or (Idx >= FSavedCount) then Exit; - EdName.Text := FSavedDevices[Idx].Name; - EdIP.Text := FSavedDevices[Idx].IPAddress; + if (FStore = nil) or (Idx < 0) or (Idx >= FStore.SavedCount) then Exit; + Dev := FStore.Saved(Idx); + EdName.Text := Dev.Name; + EdIP.Text := Dev.IPAddress; end; procedure TDeviceDialog.LstSavedDblClick(Sender: TObject); @@ -444,29 +379,20 @@ end; procedure TDeviceDialog.ClearDiscovered; begin - FDiscoveredCount := 0; - SetLength(FDiscoveredIPs, 0); - SetLength(FDiscoveredNames, 0); - SetLength(FDiscoveredBoardTypes, 0); + if FStore <> nil then FStore.ClearDiscovered; LstFound.Items.Clear; 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 - Idx: Integer; - S: string; + S: string; begin + if FStore = nil then Exit; if (LstFound.Items.Count = 1) and (LstFound.Items[0] = 'Searching...') then LstFound.Items.Clear; - Idx := FDiscoveredCount; - Inc(FDiscoveredCount); - SetLength(FDiscoveredIPs, FDiscoveredCount); - SetLength(FDiscoveredNames, FDiscoveredCount); - SetLength(FDiscoveredBoardTypes, FDiscoveredCount); - FDiscoveredIPs[Idx] := IP; - FDiscoveredNames[Idx] := DisplayName; - FDiscoveredBoardTypes[Idx] := BoardType; + FStore.AddDiscovered(IP, DisplayName, BoardType, MAC); S := DisplayName; if BoardType > 0 then @@ -474,44 +400,34 @@ begin LstFound.Items.Add(S); end; +procedure TDeviceDialog.NoDevicesFound; +begin + ClearDiscovered; + LstFound.Items.Add('-- no device found --'); +end; + procedure TDeviceDialog.BtnAddClick(Sender: TObject); var Idx: Integer; begin + if FStore = nil then Exit; if Trim(EdIP.Text) = '' then begin ShowMessage('Enter IP address'); Exit; end; - - 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; + Idx := FStore.AddSaved(EdName.Text, EdIP.Text, 0); RefreshSavedList; LstSaved.ItemIndex := Idx; end; procedure TDeviceDialog.BtnRemoveClick(Sender: TObject); var - Idx, I: Integer; + Idx: Integer; begin Idx := LstSaved.ItemIndex; - if (Idx < 0) or (Idx >= FSavedCount) then Exit; - - for I := Idx to FSavedCount - 2 do - FSavedDevices[I] := FSavedDevices[I + 1]; - Dec(FSavedCount); - SetLength(FSavedDevices, FSavedCount); - - SaveSaved; + if (FStore = nil) or (Idx < 0) or (Idx >= FStore.SavedCount) then Exit; + FStore.RemoveSaved(Idx); RefreshSavedList; EdName.Text := ''; EdIP.Text := ''; @@ -519,45 +435,34 @@ end; procedure TDeviceDialog.BtnSetAutoClick(Sender: TObject); var - Idx, I: Integer; + Idx: Integer; begin Idx := LstSaved.ItemIndex; - if (Idx < 0) or (Idx >= FSavedCount) then + if (FStore = nil) or (Idx < 0) or (Idx >= FStore.SavedCount) then begin ShowMessage('Select a device first'); Exit; end; - - // Только одно устройство может быть AutoStart - for I := 0 to FSavedCount - 1 do - FSavedDevices[I].AutoStart := (I = Idx); - - SaveSaved; + FStore.SetAutoStart(Idx); RefreshSavedList; LstSaved.ItemIndex := Idx; end; procedure TDeviceDialog.BtnAddFoundClick(Sender: TObject); var - Idx: Integer; + Idx, NewIdx: Integer; + D: TDiscoveredDevice; begin Idx := LstFound.ItemIndex; - if (Idx < 0) or (Idx >= FDiscoveredCount) then + if (FStore = nil) or (Idx < 0) or (Idx >= FStore.DiscoveredCount) then begin ShowMessage('Select a discovered device first'); Exit; end; - EdIP.Text := FDiscoveredIPs[Idx]; - EdName.Text := FDiscoveredNames[Idx]; - BtnAddClick(nil); - // Обновляем BoardType только что добавленной записи - if FSavedCount > 0 then - begin - FSavedDevices[FSavedCount - 1].BoardType := FDiscoveredBoardTypes[Idx]; - SaveSaved; - RefreshSavedList; - LstSaved.ItemIndex := FSavedCount - 1; - end; + D := FStore.Discovered(Idx); + NewIdx := FStore.AddSaved(D.DisplayName, D.IPAddress, D.BoardType); + RefreshSavedList; + LstSaved.ItemIndex := NewIdx; end; procedure TDeviceDialog.BtnConnectClick(Sender: TObject); @@ -566,20 +471,21 @@ var Idx: Integer; begin IP := ''; + if FStore = nil then Exit; // Приоритет: выбранное сохранённое > выбранное найденное > ручной IP Idx := LstSaved.ItemIndex; - if (Idx >= 0) and (Idx < FSavedCount) then + if (Idx >= 0) and (Idx < FStore.SavedCount) then begin - IP := FSavedDevices[Idx].IPAddress; + IP := FStore.Saved(Idx).IPAddress; FResult.SavedIdx := Idx; end else begin Idx := LstFound.ItemIndex; - if (Idx >= 0) and (Idx < FDiscoveredCount) then + if (Idx >= 0) and (Idx < FStore.DiscoveredCount) then begin - IP := FDiscoveredIPs[Idx]; + IP := FStore.Discovered(Idx).IPAddress; FResult.SavedIdx := -1; end else if Trim(EdIP.Text) <> '' then @@ -614,37 +520,21 @@ begin end; function TDeviceDialog.GetAutoStartIP: string; -var - I: Integer; begin - Result := ''; - for I := 0 to FSavedCount - 1 do - if FSavedDevices[I].AutoStart then - begin - Result := FSavedDevices[I].IPAddress; - Exit; - end; + if FStore <> nil then Result := FStore.AutoStartIP + else Result := ''; end; function TDeviceDialog.GetAutoStartBoardType: Integer; -var - I: Integer; begin - Result := 0; - for I := 0 to FSavedCount - 1 do - if FSavedDevices[I].AutoStart then - begin - Result := FSavedDevices[I].BoardType; - Exit; - end; + if FStore <> nil then Result := FStore.AutoStartBoardType + else Result := 0; end; function TDeviceDialog.GetSavedBoardType(Idx: Integer): Integer; begin - if (Idx >= 0) and (Idx < FSavedCount) then - Result := FSavedDevices[Idx].BoardType - else - Result := 0; + if FStore <> nil then Result := FStore.SavedBoardType(Idx) + else Result := 0; end; end. diff --git a/DeviceStore.pas b/DeviceStore.pas new file mode 100644 index 0000000..bf77747 --- /dev/null +++ b/DeviceStore.pas @@ -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. diff --git a/MainForm.pas b/MainForm.pas index d9313be..66b6ac5 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -41,6 +41,7 @@ uses FlatEdit, FMRepeater, ChannelStore, ChannelsForm, PowerInhibit, + DeviceStore, RadioController; const @@ -107,11 +108,6 @@ const LEFT_PANEL_BTN_GAP = 2; type - TDeviceItem = record - Dev: THPSDRDevice; - Display: string; - end; - { TMainForm } TMainForm = class(TForm) private @@ -124,8 +120,7 @@ type FSyncingFromController: Boolean; // ---- Network ---- - FDevices: array of TDeviceItem; - FDeviceCount: Integer; + // Список устройств (saved+discovered) → FController.FDeviceStore (общий с web). FDeviceDialog: TDeviceDialog; FPendingIP: string; // IP устройства для подключения FVfoOverlay: TVfoOverlay; // накладка SmartSDR-стиль на спектре @@ -1039,8 +1034,8 @@ begin FController.FLastSupplyV:= -1; FController.FLastSupplyA:= -1; FController.FLastPLLLock:= False; - FDeviceCount := 0; FDeviceDialog := TDeviceDialog.Create(Self); + FDeviceDialog.Store := FController.FDeviceStore; FDeviceDialog.OnDiscover := BtnDiscoverFromDialog; FVfoOverlay := TVfoOverlay.Create(Self); FVfoOverlay.OnSelect := OnModeFilterSelect; @@ -3285,19 +3280,12 @@ begin end; procedure TMainForm.DoAddDevice(const Dev: THPSDRDevice; const Entry: string); -var - Idx: Integer; begin - Idx := Length(FDevices); - SetLength(FDevices, Idx + 1); - FDevices[Idx].Dev := Dev; - FDevices[Idx].Display := Entry; - Inc(FDeviceCount); - + // Найденное устройство → общий store (через диалог, который пишет store + + // рендерит список). MAC нужен для preload-rate lookup в BtnStartStopClick. if Assigned(FDeviceDialog) then - FDeviceDialog.AddDiscovered(Dev.IPAddress, Entry, Dev.BoardType); - - SetStatusText(2, Format('Found: %s', [Dev.IPAddress])); + FDeviceDialog.AddDiscovered(Dev.IPAddress, Entry, Dev.BoardType, Dev.MAC); + SetStatusText(2, Format('Found: %s', [Dev.IPAddress])); end; @@ -3457,10 +3445,7 @@ begin if DDCIdx = -1 then begin if Assigned(FDeviceDialog) then - begin - FDeviceDialog.ClearDiscovered; - FDeviceDialog.AddDiscovered('', '-- no device found --'); - end; + FDeviceDialog.NoDevicesFound; SetStatusText(2, 'No hardware found'); end else @@ -3555,6 +3540,7 @@ begin // Открываем диалог выбора устройства if not Assigned(FDeviceDialog) then FDeviceDialog := TDeviceDialog.Create(Self); + FDeviceDialog.Store := FController.FDeviceStore; FDeviceDialog.OnDiscover := BtnDiscoverFromDialog; if FLightTheme then FDeviceDialog.SetTheme(LightTheme) else FDeviceDialog.SetTheme(DarkTheme); @@ -3567,8 +3553,7 @@ end; procedure TMainForm.BtnDiscoverFromDialog(Sender: TObject); // Запускается когда пользователь нажимает DISCOVER внутри диалога begin - SetLength(FDevices, 0); - FDeviceCount := 0; + FController.FDeviceStore.ClearDiscovered; SetStatusText(2, 'Discovering...'); FController.FNetwork.DirectIP := ''; TDiscoverThread.Create(FController.FNetwork, Self); @@ -3576,10 +3561,8 @@ end; procedure TMainForm.BtnStartStopClick(Sender: TObject); var - Idx, i: Integer; + i: Integer; Dev: THPSDRDevice; - GenPkt: TGeneralPacket; - G_Settings: TGlobalSettings; PreG: TGlobalSettings; PreBands: array[0..CFG_BAND_COUNT-1] of TBandSettings; PreloadRate: Integer; @@ -3641,6 +3624,7 @@ begin begin if not Assigned(FDeviceDialog) then FDeviceDialog := TDeviceDialog.Create(Self); + FDeviceDialog.Store := FController.FDeviceStore; FDeviceDialog.OnDiscover := BtnDiscoverFromDialog; if FLightTheme then FDeviceDialog.SetTheme(LightTheme) else FDeviceDialog.SetTheme(DarkTheme); @@ -3664,14 +3648,14 @@ begin // создаём WDSPEngine сразу с нужной частотой. PreloadRate := FController.FSampleRate; FoundByIP := False; - for i := 0 to High(FDevices) do - if SameText(FDevices[i].Dev.IPAddress, Dev.IPAddress) then - begin - FoundByIP := True; - if FController.FSettings.LoadDevice(FDevices[i].Dev.MAC, PreG, PreBands) and (PreG.SampleRate > 0) then - PreloadRate := PreG.SampleRate; - Break; - end; + i := FController.FDeviceStore.FindDiscoveredByIP(Dev.IPAddress); + if i >= 0 then + begin + FoundByIP := True; + if FController.FSettings.LoadDevice(FController.FDeviceStore.Discovered(i).MAC, PreG, PreBands) + and (PreG.SampleRate > 0) then + PreloadRate := PreG.SampleRate; + end; if FoundByIP and (PreloadRate > 0) then begin FController.FSampleRate := PreloadRate; diff --git a/RadioController.pas b/RadioController.pas index df44ee6..37999c4 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -50,7 +50,7 @@ uses Classes, SysUtils, Math, HPSDRProtocol, HPSDRNetwork, WDSPEngine, AudioOutput, AudioInput, - Settings, ChannelStore, FMRepeater, BoardUtils; + Settings, ChannelStore, FMRepeater, BoardUtils, DeviceStore; type // Поле, которое изменилось — для гранулярных уведомлений наружу. @@ -128,6 +128,7 @@ type FAudioIn: TAudioInput; FSettings: TSettingsManager; FChannelStore: TChannelStore; + FDeviceStore: TDeviceStore; // общий список устройств (saved+discovered) FWDSPReady: Boolean; // ---- Частоты / режим / фильтр / AGC ---- @@ -413,6 +414,7 @@ constructor TRadioController.Create; begin inherited Create; FSettings := TSettingsManager.Create; // владелец настроек (GUI и демон) + FDeviceStore := TDeviceStore.Create; // общий список устройств (desktop+web) // Дефолты (дублируют TMainForm.FormCreate; в GUI перезапишутся, в демоне нужны). FVfoA := 14200000; FVfoB := 7100000; FActiveVfo := 0; FMode := 1; FFilter := 5; FFilterBW := 2700; @@ -459,6 +461,7 @@ end; destructor TRadioController.Destroy; begin FreeEngines; + FreeAndNil(FDeviceStore); FreeAndNil(FSettings); inherited Destroy; end;