fix(dmr): track voice state per timeslot

This commit is contained in:
2026-07-14 18:56:33 +03:00
parent 28c434d9a7
commit 70486d901b
2 changed files with 40 additions and 12 deletions
+38 -11
View File
@@ -113,11 +113,12 @@ type
FCurrentBurstPos: Integer;
FLastBurst: TDMRDibitBurst;
FLastBurstInfo: TDMRBurstInfo;
FLastLinkControl: TDMRLinkControl;
FLinkControl: array[0..1] of TDMRLinkControl;
FLastLCSlot: Integer;
FColorCodeValid: Boolean;
FColorCode, FLastDataType, FSlotTypeCorrectedBits: Integer;
FSelectedSlot: Integer;
FLastSelectedVoiceTick: QWord;
FVoiceFrameCount, FVoiceErrorCount: QWord;
FOnAudio: TDMRAudioEvent;
FBurstCount: QWord;
@@ -280,13 +281,14 @@ begin
FillChar(FCurrentBurst, SizeOf(FCurrentBurst), 0);
FillChar(FLastBurst, SizeOf(FLastBurst), 0);
FillChar(FLastBurstInfo, SizeOf(FLastBurstInfo), 0);
FillChar(FLastLinkControl, SizeOf(FLastLinkControl), 0);
FillChar(FLinkControl, SizeOf(FLinkControl), 0);
FLastLCSlot := -1;
FColorCodeValid := False;
FColorCode := 0;
FLastDataType := 0;
FSlotTypeCorrectedBits := 0;
FSelectedSlot := -1;
FLastSelectedVoiceTick := 0;
FVoiceFrameCount := 0;
FVoiceErrorCount := 0;
DMRMbeReset(FMbe);
@@ -487,7 +489,6 @@ begin
end;
if FLastBurstInfo.LinkControl.Decoded then
begin
FLastLinkControl := FLastBurstInfo.LinkControl;
if (FSyncKind in [dskBSData, dskBSVoice]) and
FLastBurstInfo.CACH.Valid then
FLastLCSlot := FLastBurstInfo.CACH.Slot
@@ -495,7 +496,12 @@ begin
FLastLCSlot := 1
else
FLastLCSlot := 0;
if FSelectedSlot < 0 then FSelectedSlot := FLastLCSlot;
FLinkControl[FLastLCSlot] := FLastBurstInfo.LinkControl;
if FSelectedSlot < 0 then
begin
FSelectedSlot := FLastLCSlot;
FLastSelectedVoiceTick := GetTickCount64;
end;
end;
DecodeVoiceBurst;
Inc(FBurstCount);
@@ -508,6 +514,7 @@ var
PCM: array[0..DMR_PCM_SAMPLES - 1] of Single;
MbeResult: TDMRMbeResult;
Slot, FrameIndex, RC: Integer;
NowTick: QWord;
begin
if (FMbe = nil) or (FLastSyncTick = 0) or
(GetTickCount64 - FLastSyncTick > DMR_SYNC_HOLD_MS) then Exit;
@@ -521,8 +528,20 @@ begin
end
else if FSyncKind = dskDirectTS2Voice then Slot := 1
else Slot := 0;
if FSelectedSlot < 0 then FSelectedSlot := Slot;
NowTick := GetTickCount64;
if (FSelectedSlot < 0) or
((Slot <> FSelectedSlot) and (FLastSelectedVoiceTick <> 0) and
(NowTick - FLastSelectedVoiceTick > 1000)) then
begin
FSelectedSlot := Slot;
DMRMbeReset(FMbe);
end;
if Slot <> FSelectedSlot then Exit;
FLastSelectedVoiceTick := NowTick;
// Service Options bit 6 denotes privacy/encryption. mbelib cannot decrypt
// it, so suppress the characteristic digital noise while retaining IDs.
if FLinkControl[Slot].Decoded and
((FLinkControl[Slot].ServiceOptions and $40) <> 0) then Exit;
DMRExtractAMBEFrames(FLastBurst, Frames);
for FrameIndex := 0 to 2 do
@@ -576,6 +595,7 @@ end;
procedure TDMRDecoder.GetStatus(out S: TDMRStatus);
var
NowTick: QWord;
LCStatusSlot: Integer;
begin
FillChar(S, SizeOf(S), 0);
NowTick := GetTickCount64;
@@ -608,12 +628,19 @@ begin
S.ColorCode := FColorCode;
S.DataType := FLastDataType;
S.SlotTypeCorrectedBits := FSlotTypeCorrectedBits;
S.LinkControlValid := FLastLinkControl.Decoded;
S.LCSlot := FLastLCSlot;
S.LCOpcode := FLastLinkControl.Opcode;
S.ServiceOptions := FLastLinkControl.ServiceOptions;
S.TargetID := FLastLinkControl.TargetID;
S.SourceID := FLastLinkControl.SourceID;
LCStatusSlot := FSelectedSlot;
if (LCStatusSlot < 0) or not FLinkControl[LCStatusSlot].Decoded then
LCStatusSlot := FLastLCSlot;
S.LinkControlValid := (LCStatusSlot >= 0) and
FLinkControl[LCStatusSlot].Decoded;
S.LCSlot := LCStatusSlot;
if S.LinkControlValid then
begin
S.LCOpcode := FLinkControl[LCStatusSlot].Opcode;
S.ServiceOptions := FLinkControl[LCStatusSlot].ServiceOptions;
S.TargetID := FLinkControl[LCStatusSlot].TargetID;
S.SourceID := FLinkControl[LCStatusSlot].SourceID;
end;
S.SelectedSlot := FSelectedSlot;
S.VoiceFrameCount := FVoiceFrameCount;
S.VoiceErrorCount := FVoiceErrorCount;
+2 -1
View File
@@ -3594,7 +3594,8 @@ begin
if not S.Synced then Exit(Format('DMR sync... %.3f', [S.SignalRMS]));
if S.Inverted then Inv := ' INV' else Inv := '';
Details := '';
if S.CACHValid then Details := Format(' TS%d', [S.Slot + 1]);
if S.LinkControlValid then Details := Format(' TS%d', [S.LCSlot + 1])
else if S.CACHValid then Details := Format(' TS%d', [S.Slot + 1]);
if S.SlotTypeValid then
Details := Details + Format(' CC%d/DT%d', [S.ColorCode, S.DataType]);
if S.LinkControlValid then Details := Details + Format(' TG%d', [S.TargetID]);