mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat(fm): add universal FM RAW decoder output
This commit is contained in:
+39
-29
@@ -17,18 +17,22 @@ unit VfoOverlay;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Controls, Graphics, Types, Math, FlatButton, AppTheme;
|
||||
Classes, SysUtils, Controls, Graphics, Types, Math, FlatButton, AppTheme,
|
||||
RadioModes;
|
||||
|
||||
const
|
||||
VFO_OVERLAY_ALPHA = 210;
|
||||
OVL_W = 280; // ширина карточки
|
||||
|
||||
// Индексы совпадают с MODE_* контроллера (WDSPEngine.pas).
|
||||
OVL_MODE_COUNT = 12;
|
||||
OVL_MODE_COUNT = RadioModes.MODE_COUNT;
|
||||
OVL_MODE_FM = RadioModes.MODE_FM;
|
||||
OVL_MODE_DMR = RadioModes.MODE_DMR;
|
||||
OVL_MODE_FMRAW = RadioModes.MODE_FMRAW;
|
||||
OVL_MODE_COLS = 4;
|
||||
OVL_MODE_ROWS = (OVL_MODE_COUNT + OVL_MODE_COLS - 1) div OVL_MODE_COLS;
|
||||
OVL_MODE_NAMES: array[0..OVL_MODE_COUNT-1] of string = (
|
||||
'LSB','USB','DSB','CWL','CWU','FM','AM','SAM','DIGU','DIGL','WFM','DMR');
|
||||
'LSB','USB','DSB','CWL','CWU','FM','AM','SAM','DIGU','DIGL','WFM','DMR','FMRAW');
|
||||
|
||||
// Палитра слайсов (TColor = $00BBGGRR): одна на букву — общий цвет для
|
||||
// бейджа-карточки во флаге и для буквы на полосе фильтра в спектре.
|
||||
@@ -307,6 +311,8 @@ const
|
||||
WFM_LBL: array[0..2] of string = ('200K', '160K', '120K');
|
||||
DIGI_BW: array[0..5] of Integer = (300, 600, 1200, 1800, 2400, 3000);
|
||||
DIGI_LBL: array[0..5] of string = ('300','600','1.2K','1.8K','2.4K','3.0K');
|
||||
RAW_BW: array[0..4] of Integer = (6250,10000,12500,20000,25000);
|
||||
RAW_LBL: array[0..4] of string = ('6.25K','10K','12.5K','20K','25K');
|
||||
|
||||
DB_S: array[1..9] of Double = (-121,-115,-109,-103,-97,-91,-85,-79,-73);
|
||||
|
||||
@@ -400,13 +406,14 @@ end;
|
||||
function TVfoOverlay.GetFilterBWForMode(ModeIdx, FilterIdx: Integer): Integer;
|
||||
begin
|
||||
case ModeIdx of
|
||||
0,1: Result := SSB_BW[FilterIdx];
|
||||
2: Result := DSB_BW[FilterIdx];
|
||||
3,4: Result := CW_BW[FilterIdx];
|
||||
5: Result := FM_BW[FilterIdx];
|
||||
8,9: Result := DIGI_BW[FilterIdx]; // DIGU/DIGL — полоса от нуля
|
||||
10: Result := WFM_BW[FilterIdx];
|
||||
11: Result := 12500;
|
||||
MODE_LSB, MODE_USB: Result := SSB_BW[FilterIdx];
|
||||
MODE_DSB: Result := DSB_BW[FilterIdx];
|
||||
MODE_CWL, MODE_CWU: Result := CW_BW[FilterIdx];
|
||||
OVL_MODE_FM: Result := FM_BW[FilterIdx];
|
||||
MODE_DIGU, MODE_DIGL: Result := DIGI_BW[FilterIdx]; // полоса от нуля
|
||||
MODE_WFM: Result := WFM_BW[FilterIdx];
|
||||
OVL_MODE_DMR: Result := 12500;
|
||||
OVL_MODE_FMRAW: Result := RAW_BW[FilterIdx];
|
||||
else Result := AM_BW[FilterIdx];
|
||||
end;
|
||||
end;
|
||||
@@ -414,13 +421,14 @@ end;
|
||||
function TVfoOverlay.GetFilterLblForMode(ModeIdx, FilterIdx: Integer): string;
|
||||
begin
|
||||
case ModeIdx of
|
||||
0,1: Result := SSB_LBL[FilterIdx];
|
||||
2: Result := DSB_LBL[FilterIdx];
|
||||
3,4: Result := CW_LBL[FilterIdx];
|
||||
5: Result := FM_LBL[FilterIdx];
|
||||
8,9: Result := DIGI_LBL[FilterIdx];
|
||||
10: Result := WFM_LBL[FilterIdx];
|
||||
11: Result := '12.5k';
|
||||
MODE_LSB, MODE_USB: Result := SSB_LBL[FilterIdx];
|
||||
MODE_DSB: Result := DSB_LBL[FilterIdx];
|
||||
MODE_CWL, MODE_CWU: Result := CW_LBL[FilterIdx];
|
||||
OVL_MODE_FM: Result := FM_LBL[FilterIdx];
|
||||
MODE_DIGU, MODE_DIGL: Result := DIGI_LBL[FilterIdx];
|
||||
MODE_WFM: Result := WFM_LBL[FilterIdx];
|
||||
OVL_MODE_DMR: Result := '12.5k';
|
||||
OVL_MODE_FMRAW: Result := RAW_LBL[FilterIdx];
|
||||
else Result := AM_LBL[FilterIdx];
|
||||
end;
|
||||
end;
|
||||
@@ -428,9 +436,10 @@ end;
|
||||
function TVfoOverlay.GetFilterCountForMode(ModeIdx: Integer): Integer;
|
||||
begin
|
||||
case ModeIdx of
|
||||
5: Result := 2; // FM: NFM/FM
|
||||
10: Result := 3; // WFM: 200K/160K/120K
|
||||
11: Result := 0; // DMR: fixed 12.5 kHz, no redundant selector
|
||||
OVL_MODE_FM: Result := 2; // FM: NFM/FM
|
||||
MODE_WFM: Result := 3; // WFM: 200K/160K/120K
|
||||
OVL_MODE_DMR: Result := 0; // DMR: fixed 12.5 kHz, no redundant selector
|
||||
OVL_MODE_FMRAW: Result := 5; // FM RAW decoder channel widths
|
||||
else Result := 6;
|
||||
end;
|
||||
end;
|
||||
@@ -438,7 +447,7 @@ end;
|
||||
function TVfoOverlay.TxSelectionAllowed: Boolean;
|
||||
begin
|
||||
// Main A remains the normal TX source. Additional DMR slices are RX-only.
|
||||
Result := FIsMain or (FMode <> 11);
|
||||
Result := FIsMain or not (FMode in [OVL_MODE_DMR, OVL_MODE_FMRAW]);
|
||||
end;
|
||||
|
||||
{ ---- Lifecycle ---- }
|
||||
@@ -447,7 +456,7 @@ constructor TVfoOverlay.Create(AOwner: TComponent);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
ControlStyle := ControlStyle + [csOpaque];
|
||||
FMode := 1;
|
||||
FMode := MODE_USB;
|
||||
FFilterBW := 2700;
|
||||
FVfoHz := 14200000;
|
||||
FSMeterDB := -121;
|
||||
@@ -457,6 +466,7 @@ begin
|
||||
FModeFilter[3] := 500; FModeFilter[4] := 500; FModeFilter[5] := 11000;
|
||||
FModeFilter[6] := 8000; FModeFilter[7] := 8000; FModeFilter[8] := 3000;
|
||||
FModeFilter[9] := 3000; FModeFilter[10] := 160000;
|
||||
FModeFilter[11] := 12500; FModeFilter[12] := 12500;
|
||||
FNRMode := 0; FNBMode := 0; FSNBOn := False; FANFOn := False; FAGCMode := 0;
|
||||
FSQLOn := False; FSQLLevel := 40; FSqlDrag := False;
|
||||
FVolume := 70; FMuted := False; FSplit := False; FTx := False;
|
||||
@@ -594,7 +604,7 @@ end;
|
||||
|
||||
function TVfoOverlay.IsFM: Boolean;
|
||||
begin
|
||||
Result := FMode = 5; // индекс FM в OVL_MODE_NAMES (= MODE_FM контроллера)
|
||||
Result := FMode = OVL_MODE_FM;
|
||||
end;
|
||||
|
||||
function TVfoOverlay.PanelContentH: Integer;
|
||||
@@ -1039,7 +1049,7 @@ begin
|
||||
// Краткий статус дополнительного DMR-слайса. Он обновляется только при
|
||||
// устойчивом изменении sync/slot/CC/TG, поэтому не заставляет GL-текстуру
|
||||
// перезаливаться на каждом burst.
|
||||
if (not FIsMain) and (FMode = 11) and (FDMRText <> '') then
|
||||
if (not FIsMain) and (FMode = OVL_MODE_DMR) and (FDMRText <> '') then
|
||||
begin
|
||||
DMRStr := FDMRText;
|
||||
DMRX := X + 22 + C.TextWidth(BWStr) + 8;
|
||||
@@ -1276,7 +1286,7 @@ begin
|
||||
begin
|
||||
FModeFilter[FMode] := FFilterBW;
|
||||
FMode := NewMode;
|
||||
if FMode = 11 then FFilterBW := 12500
|
||||
if FMode = OVL_MODE_DMR then FFilterBW := 12500
|
||||
else FFilterBW := FModeFilter[FMode];
|
||||
Height := ComputeHeight; // число фильтров могло смениться (FM=2, WFM=3)
|
||||
RequestInvalidate;
|
||||
@@ -1449,19 +1459,19 @@ var
|
||||
OldMode: Integer;
|
||||
begin
|
||||
OldMode := FMode;
|
||||
FMode := Max(0, Min(OVL_MODE_COUNT - 1, AMode));
|
||||
FMode := EnsureRange(AMode, MODE_MIN, MODE_MAX);
|
||||
FFilterBW := ABW;
|
||||
FModeFilter[FMode] := ABW;
|
||||
FVfoHz := AVfoHz;
|
||||
FSMeterDB := ASMeterDB;
|
||||
if FMode <> 11 then
|
||||
if FMode <> OVL_MODE_DMR then
|
||||
begin
|
||||
FDMRText := '';
|
||||
FDMRSynced := False;
|
||||
FDMRCandidateText := '';
|
||||
FDMRCandidateSince := 0;
|
||||
end
|
||||
else if OldMode <> 11 then
|
||||
else if OldMode <> OVL_MODE_DMR then
|
||||
begin
|
||||
FDMRText := 'DMR...';
|
||||
FDMRSynced := False;
|
||||
@@ -1555,7 +1565,7 @@ procedure TVfoOverlay.UpdateDMRStatus(const AText: string; Synced: Boolean);
|
||||
var
|
||||
NowTick, HoldMs: QWord;
|
||||
begin
|
||||
if FMode <> 11 then Exit;
|
||||
if FMode <> OVL_MODE_DMR then Exit;
|
||||
if (FDMRText = AText) and (FDMRSynced = Synced) then
|
||||
begin
|
||||
FDMRCandidateText := '';
|
||||
|
||||
Reference in New Issue
Block a user