mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat(dmr): default tuning step to 12.5 kHz
This commit is contained in:
+42
-18
@@ -1535,7 +1535,8 @@ begin
|
|||||||
begin
|
begin
|
||||||
if FStepDropDown <> nil then FStepDropDown.SetItemIndex(FController.FFMStepIdx);
|
if FStepDropDown <> nil then FStepDropDown.SetItemIndex(FController.FFMStepIdx);
|
||||||
if FWebServer <> nil then FWebServer.FMStepIdx := FController.FFMStepIdx;
|
if FWebServer <> nil then FWebServer.FMStepIdx := FController.FFMStepIdx;
|
||||||
if (FController.FMode = MODE_FM) and (FSpecView <> nil) then
|
if (FController.FMode in [MODE_FM, MODE_DMR]) and
|
||||||
|
(FSpecView <> nil) then
|
||||||
FSpecView.FMGridStepHz := FM_STEP_HZ[FController.FFMStepIdx];
|
FSpecView.FMGridStepHz := FM_STEP_HZ[FController.FFMStepIdx];
|
||||||
end;
|
end;
|
||||||
rfFMStep:
|
rfFMStep:
|
||||||
@@ -3237,7 +3238,7 @@ begin
|
|||||||
FSpecView.SpanHz := ViewSpan;
|
FSpecView.SpanHz := ViewSpan;
|
||||||
FSpecView.Mode := FController.FMode;
|
FSpecView.Mode := FController.FMode;
|
||||||
FSpecView.FilterBW := FController.FFilterBW;
|
FSpecView.FilterBW := FController.FFilterBW;
|
||||||
if FController.FMode = MODE_FM then
|
if FController.FMode in [MODE_FM, MODE_DMR] then
|
||||||
FSpecView.FMGridStepHz := FM_STEP_HZ[FController.FFMStepIdx]
|
FSpecView.FMGridStepHz := FM_STEP_HZ[FController.FFMStepIdx]
|
||||||
else
|
else
|
||||||
FSpecView.FMGridStepHz := 0;
|
FSpecView.FMGridStepHz := 0;
|
||||||
@@ -4218,11 +4219,26 @@ begin
|
|||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Non-FM: restore full 2-row height and 5-column layout, hide FM panels
|
// Non-FM: restore full 2-row height and 5-column layout, hide FM panels.
|
||||||
|
// DMR reuses only the tuning STEP panel; SQL/CTCSS/repeater stay FM-only.
|
||||||
PanelFilter.Height := 74;
|
PanelFilter.Height := 74;
|
||||||
if PanelFMSQ <> nil then PanelFMSQ.Visible := False;
|
if PanelFMSQ <> nil then PanelFMSQ.Visible := False;
|
||||||
if PanelFMCTCSS <> nil then PanelFMCTCSS.Visible := False;
|
if PanelFMCTCSS <> nil then PanelFMCTCSS.Visible := False;
|
||||||
if PanelFMStep <> nil then begin CloseFMStepPopup; PanelFMStep.Visible := False; end;
|
if PanelFMStep <> nil then
|
||||||
|
begin
|
||||||
|
if FController.FMode = MODE_DMR then
|
||||||
|
begin
|
||||||
|
StyleButton(BtnFMStep, FController.FFMStepOn);
|
||||||
|
if FStepDropDown <> nil then
|
||||||
|
FStepDropDown.SetItemIndex(FController.FFMStepIdx);
|
||||||
|
PanelFMStep.Visible := True;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
CloseFMStepPopup;
|
||||||
|
PanelFMStep.Visible := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
if PanelFMRpt <> nil then PanelFMRpt.Visible := False;
|
if PanelFMRpt <> nil then PanelFMRpt.Visible := False;
|
||||||
|
|
||||||
if FController.FMode = MODE_WFM then
|
if FController.FMode = MODE_WFM then
|
||||||
@@ -4472,7 +4488,8 @@ var
|
|||||||
ViewCenter, ViewSpan: Double;
|
ViewCenter, ViewSpan: Double;
|
||||||
begin
|
begin
|
||||||
if PanelWidth <= 0 then Exit;
|
if PanelWidth <= 0 then Exit;
|
||||||
if (FController.FMode = MODE_FM) and FController.FFMStepOn then
|
if (FController.FMode in [MODE_FM, MODE_DMR]) and
|
||||||
|
FController.FFMStepOn then
|
||||||
StepHz := FM_STEP_HZ[FController.FFMStepIdx]
|
StepHz := FM_STEP_HZ[FController.FFMStepIdx]
|
||||||
else
|
else
|
||||||
StepHz := 100;
|
StepHz := 100;
|
||||||
@@ -4496,7 +4513,8 @@ begin
|
|||||||
if (FWidebandView = nil) or
|
if (FWidebandView = nil) or
|
||||||
(not FWidebandView.TryPixelToFrequency(PixelX, PanelWidth, FreqHz)) then Exit;
|
(not FWidebandView.TryPixelToFrequency(PixelX, PanelWidth, FreqHz)) then Exit;
|
||||||
|
|
||||||
if (FController.FMode = MODE_FM) and FController.FFMStepOn then
|
if (FController.FMode in [MODE_FM, MODE_DMR]) and
|
||||||
|
FController.FFMStepOn then
|
||||||
StepHz := FM_STEP_HZ[FController.FFMStepIdx]
|
StepHz := FM_STEP_HZ[FController.FFMStepIdx]
|
||||||
else
|
else
|
||||||
StepHz := 100;
|
StepHz := 100;
|
||||||
@@ -6037,28 +6055,31 @@ end;
|
|||||||
|
|
||||||
procedure TMainForm.PanClickTune(P: TPanafallPanel; X, W: Integer);
|
procedure TMainForm.PanClickTune(P: TPanafallPanel; X, W: Integer);
|
||||||
// Клик по фону доп. пана = перестроить его слайс на частоту клика (аналог
|
// Клик по фону доп. пана = перестроить его слайс на частоту клика (аналог
|
||||||
// DoSpectrumClick главного: снап к 100 Гц). Цель — активный слайс, если он
|
// DoSpectrumClick главного). Цель — активный слайс, если он живёт в этом
|
||||||
// живёт в этом пане, иначе первый слайс пана; слайсов нет — создать в точке.
|
// пане, иначе первый слайс пана; слайсов нет — создать в точке.
|
||||||
const
|
|
||||||
StepHz = 100;
|
|
||||||
var
|
var
|
||||||
VC, VS, LoHz, HiHz: Double;
|
VC, VS, LoHz, HiHz: Double;
|
||||||
Hz: Int64;
|
Hz, StepHz: Int64;
|
||||||
Id: Integer;
|
Id: Integer;
|
||||||
S: TCtrlSlice;
|
S: TCtrlSlice;
|
||||||
begin
|
begin
|
||||||
PanViewWindow(P, VC, VS);
|
PanViewWindow(P, VC, VS);
|
||||||
if (W <= 0) or (VS <= 0) then Exit;
|
if (W <= 0) or (VS <= 0) then Exit;
|
||||||
Hz := Round(VC + (X / W - 0.5) * VS);
|
|
||||||
Hz := ((Hz + StepHz div 2) div StepHz) * StepHz;
|
|
||||||
FController.CapturedSpan(LoHz, HiHz, P.PanId);
|
|
||||||
if Hz < LoHz then Hz := Round(LoHz);
|
|
||||||
if Hz > HiHz then Hz := Round(HiHz);
|
|
||||||
if (FActiveSliceId <> 0) and FController.GetSlice(FActiveSliceId, S) and
|
if (FActiveSliceId <> 0) and FController.GetSlice(FActiveSliceId, S) and
|
||||||
(S.PanId = P.PanId) then
|
(S.PanId = P.PanId) then
|
||||||
Id := FActiveSliceId
|
Id := FActiveSliceId
|
||||||
else
|
else
|
||||||
Id := P.FirstSliceId;
|
Id := P.FirstSliceId;
|
||||||
|
StepHz := 100;
|
||||||
|
if ((Id <> 0) and FController.GetSlice(Id, S) and
|
||||||
|
(S.Mode = MODE_DMR)) or
|
||||||
|
((Id = 0) and (FController.FMode = MODE_DMR)) then
|
||||||
|
StepHz := 12500;
|
||||||
|
Hz := Round(VC + (X / W - 0.5) * VS);
|
||||||
|
Hz := ((Hz + StepHz div 2) div StepHz) * StepHz;
|
||||||
|
FController.CapturedSpan(LoHz, HiHz, P.PanId);
|
||||||
|
if Hz < LoHz then Hz := Round(LoHz);
|
||||||
|
if Hz > HiHz then Hz := Round(HiHz);
|
||||||
if Id = 0 then
|
if Id = 0 then
|
||||||
begin
|
begin
|
||||||
AddSliceAtFreqPan(P, Hz);
|
AddSliceAtFreqPan(P, Hz);
|
||||||
@@ -7571,7 +7592,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
if (SliceId <> 0) and FController.GetSlice(SliceId, Sl) then
|
if (SliceId <> 0) and FController.GetSlice(SliceId, Sl) then
|
||||||
begin
|
begin
|
||||||
if (ssCtrl in Shift) and (ssShift in Shift) then Step := 1000000
|
if (Sl.Mode = MODE_DMR) and
|
||||||
|
not ((ssCtrl in Shift) or (ssShift in Shift)) then Step := 12500
|
||||||
|
else if (ssCtrl in Shift) and (ssShift in Shift) then Step := 1000000
|
||||||
else if ssCtrl in Shift then Step := 1000
|
else if ssCtrl in Shift then Step := 1000
|
||||||
else if ssShift in Shift then Step := 10
|
else if ssShift in Shift then Step := 10
|
||||||
else Step := 100;
|
else Step := 100;
|
||||||
@@ -7593,7 +7616,8 @@ begin
|
|||||||
Handled := True;
|
Handled := True;
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
if (FController.FMode = MODE_FM) and FController.FFMStepOn and
|
if (FController.FMode in [MODE_FM, MODE_DMR]) and
|
||||||
|
FController.FFMStepOn and
|
||||||
not ((ssCtrl in Shift) or (ssShift in Shift)) then
|
not ((ssCtrl in Shift) or (ssShift in Shift)) then
|
||||||
Step := FM_STEP_HZ[FController.FFMStepIdx]
|
Step := FM_STEP_HZ[FController.FFMStepIdx]
|
||||||
else if (ssCtrl in Shift) and (ssShift in Shift) then Step := 1000000
|
else if (ssCtrl in Shift) and (ssShift in Shift) then Step := 1000000
|
||||||
|
|||||||
@@ -2753,6 +2753,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
FFMStepOn := B.FMStepOn;
|
FFMStepOn := B.FMStepOn;
|
||||||
FFMStepIdx := EnsureRange(B.FMStepIdx, 0, 3);
|
FFMStepIdx := EnsureRange(B.FMStepIdx, 0, 3);
|
||||||
|
if FMode = MODE_DMR then
|
||||||
|
begin
|
||||||
|
FFMStepOn := True;
|
||||||
|
FFMStepIdx := 1; // DMR default raster: 12.5 kHz
|
||||||
|
end;
|
||||||
FFMRptDir := B.FMRptDir;
|
FFMRptDir := B.FMRptDir;
|
||||||
FFMRptOffsetHz := B.FMRptOffsetHz;
|
FFMRptOffsetHz := B.FMRptOffsetHz;
|
||||||
if FFMRptOffsetHz <= 0 then FFMRptOffsetHz := RptDefaultOffsetHz(B.VfoA);
|
if FFMRptOffsetHz <= 0 then FFMRptOffsetHz := RptDefaultOffsetHz(B.VfoA);
|
||||||
@@ -3110,6 +3115,15 @@ end;
|
|||||||
procedure TRadioController.SetMode(M: Integer);
|
procedure TRadioController.SetMode(M: Integer);
|
||||||
begin
|
begin
|
||||||
FMode := M;
|
FMode := M;
|
||||||
|
// DMR channels use a 12.5 kHz raster by default. Keep the ordinary STEP
|
||||||
|
// controls enabled so the operator can select another raster afterwards.
|
||||||
|
if FMode = MODE_DMR then
|
||||||
|
begin
|
||||||
|
FFMStepOn := True;
|
||||||
|
FFMStepIdx := 1; // 12.5 kHz
|
||||||
|
Changed(rfFMStep);
|
||||||
|
Changed(rfFMStepIdx);
|
||||||
|
end;
|
||||||
// Entering receive-only DMR on the selected main TX source immediately
|
// Entering receive-only DMR on the selected main TX source immediately
|
||||||
// releases an existing carrier. SetTune(False) also releases MOX.
|
// releases an existing carrier. SetTune(False) also releases MOX.
|
||||||
if ActiveTXMode = MODE_DMR then
|
if ActiveTXMode = MODE_DMR then
|
||||||
|
|||||||
+4
-4
@@ -817,7 +817,7 @@ begin
|
|||||||
|
|
||||||
'function drawRuler(){const w=rulerCv.clientWidth,h=rulerCv.clientHeight;rctx.fillStyle="#0c1210";rctx.fillRect(0,0,w,h);' +
|
'function drawRuler(){const w=rulerCv.clientWidth,h=rulerCv.clientHeight;rctx.fillStyle="#0c1210";rctx.fillRect(0,0,w,h);' +
|
||||||
'const st=localCenter-localSpan/2;' +
|
'const st=localCenter-localSpan/2;' +
|
||||||
'const isFM=(cur.mode===5),fmStep=FM_STEP_HZ[fmStepIdx];' +
|
'const isFM=(cur.mode===5||cur.mode===11),fmStep=FM_STEP_HZ[fmStepIdx];' +
|
||||||
'if(isFM&&fmStep>0){' +
|
'if(isFM&&fmStep>0){' +
|
||||||
'const pxPerStep=w*fmStep/localSpan;' +
|
'const pxPerStep=w*fmStep/localSpan;' +
|
||||||
'const labelMult=Math.max(1,Math.ceil((rctx.measureText("000.000").width+6)/pxPerStep));' +
|
'const labelMult=Math.max(1,Math.ceil((rctx.measureText("000.000").width+6)/pxPerStep));' +
|
||||||
@@ -832,7 +832,7 @@ begin
|
|||||||
|
|
||||||
'function drawSpec(bins){const w=specCv.clientWidth,h=specCv.clientHeight;sctx.fillStyle="#050a05";sctx.fillRect(0,0,w,h);' +
|
'function drawSpec(bins){const w=specCv.clientWidth,h=specCv.clientHeight;sctx.fillStyle="#050a05";sctx.fillRect(0,0,w,h);' +
|
||||||
'for(let i=1;i<5;i++){const y=i*h/5;sctx.strokeStyle="#121e12";sctx.lineWidth=1;sctx.beginPath();sctx.moveTo(0,y);sctx.lineTo(w,y);sctx.stroke();}' +
|
'for(let i=1;i<5;i++){const y=i*h/5;sctx.strokeStyle="#121e12";sctx.lineWidth=1;sctx.beginPath();sctx.moveTo(0,y);sctx.lineTo(w,y);sctx.stroke();}' +
|
||||||
'if(cur.mode===5&&FM_STEP_HZ[fmStepIdx]>0){' +
|
'if((cur.mode===5||cur.mode===11)&&FM_STEP_HZ[fmStepIdx]>0){' +
|
||||||
'const fmSt=FM_STEP_HZ[fmStepIdx],st2=localCenter-localSpan/2;' +
|
'const fmSt=FM_STEP_HZ[fmStepIdx],st2=localCenter-localSpan/2;' +
|
||||||
'const pxSt=w*fmSt/localSpan,gm=Math.max(1,Math.ceil(4/pxSt));' +
|
'const pxSt=w*fmSt/localSpan,gm=Math.max(1,Math.ceil(4/pxSt));' +
|
||||||
'const fn=Math.ceil(st2/fmSt);' +
|
'const fn=Math.ceil(st2/fmSt);' +
|
||||||
@@ -875,7 +875,7 @@ begin
|
|||||||
'if(smCv.width!==(sw*dpr|0)||smCv.height!==(sh*dpr|0)){smCv.width=sw*dpr|0;smCv.height=sh*dpr|0;mctx.setTransform(dpr,0,0,dpr,0,0);}' +
|
'if(smCv.width!==(sw*dpr|0)||smCv.height!==(sh*dpr|0)){smCv.width=sw*dpr|0;smCv.height=sh*dpr|0;mctx.setTransform(dpr,0,0,dpr,0,0);}' +
|
||||||
'if(wfBuf.width!==wfCv.clientWidth||wfBuf.height!==wfCv.clientHeight){wfBuf.width=wfCv.clientWidth;wfBuf.height=wfCv.clientHeight;wfBCtx.fillStyle="#000";wfBCtx.fillRect(0,0,wfBuf.width,wfBuf.height);}}' +
|
'if(wfBuf.width!==wfCv.clientWidth||wfBuf.height!==wfCv.clientHeight){wfBuf.width=wfCv.clientWidth;wfBuf.height=wfCv.clientHeight;wfBCtx.fillStyle="#000";wfBCtx.fillRect(0,0,wfBuf.width,wfBuf.height);}}' +
|
||||||
|
|
||||||
'function syncStepSel(){const isFM=(cur.mode===5);const sel=q("stepSel");if(!sel)return;' +
|
'function syncStepSel(){const isFM=(cur.mode===5||cur.mode===11);const sel=q("stepSel");if(!sel)return;' +
|
||||||
'if(isFM&&!inFMStep){lastHFStep=+sel.value||100;sel.innerHTML="";' +
|
'if(isFM&&!inFMStep){lastHFStep=+sel.value||100;sel.innerHTML="";' +
|
||||||
'FM_STEP_LBL.forEach((l,i)=>{const o=document.createElement("option");o.value=FM_STEP_HZ[i];o.textContent=l;sel.appendChild(o);});' +
|
'FM_STEP_LBL.forEach((l,i)=>{const o=document.createElement("option");o.value=FM_STEP_HZ[i];o.textContent=l;sel.appendChild(o);});' +
|
||||||
'sel.value=FM_STEP_HZ[fmStepIdx];' +
|
'sel.value=FM_STEP_HZ[fmStepIdx];' +
|
||||||
@@ -937,7 +937,7 @@ begin
|
|||||||
'if(dragging&&Math.abs(e.offsetX-dragX0)<4){' +
|
'if(dragging&&Math.abs(e.offsetX-dragX0)<4){' +
|
||||||
// клик — не трогаем localCenter: фильтр встаёт точно туда куда кликнули.
|
// клик — не трогаем localCenter: фильтр встаёт точно туда куда кликнули.
|
||||||
// Спектр остаётся на месте, сервер пришлёт center_hz через ~200ms и всё перецентрируется.
|
// Спектр остаётся на месте, сервер пришлёт center_hz через ~200ms и всё перецентрируется.
|
||||||
'const snap=(cur.mode===5&&inFMStep)?FM_STEP_HZ[fmStepIdx]:100;' +
|
'const snap=((cur.mode===5||cur.mode===11)&&inFMStep)?FM_STEP_HZ[fmStepIdx]:100;' +
|
||||||
'const nf=cl(Math.round(xToHz(e.offsetX,cv.clientWidth)/snap)*snap,vfoMin(),vfoMax());' +
|
'const nf=cl(Math.round(xToHz(e.offsetX,cv.clientWidth)/snap)*snap,vfoMin(),vfoMax());' +
|
||||||
'setActiveVfoHz(nf);' +
|
'setActiveVfoHz(nf);' +
|
||||||
'if(activeVfo==="A")cur.vfo_a_hz=nf;else cur.vfo_b_hz=nf;' +
|
'if(activeVfo==="A")cur.vfo_a_hz=nf;else cur.vfo_b_hz=nf;' +
|
||||||
|
|||||||
Reference in New Issue
Block a user