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; FCurrentBurstPos: Integer;
FLastBurst: TDMRDibitBurst; FLastBurst: TDMRDibitBurst;
FLastBurstInfo: TDMRBurstInfo; FLastBurstInfo: TDMRBurstInfo;
FLastLinkControl: TDMRLinkControl; FLinkControl: array[0..1] of TDMRLinkControl;
FLastLCSlot: Integer; FLastLCSlot: Integer;
FColorCodeValid: Boolean; FColorCodeValid: Boolean;
FColorCode, FLastDataType, FSlotTypeCorrectedBits: Integer; FColorCode, FLastDataType, FSlotTypeCorrectedBits: Integer;
FSelectedSlot: Integer; FSelectedSlot: Integer;
FLastSelectedVoiceTick: QWord;
FVoiceFrameCount, FVoiceErrorCount: QWord; FVoiceFrameCount, FVoiceErrorCount: QWord;
FOnAudio: TDMRAudioEvent; FOnAudio: TDMRAudioEvent;
FBurstCount: QWord; FBurstCount: QWord;
@@ -280,13 +281,14 @@ begin
FillChar(FCurrentBurst, SizeOf(FCurrentBurst), 0); FillChar(FCurrentBurst, SizeOf(FCurrentBurst), 0);
FillChar(FLastBurst, SizeOf(FLastBurst), 0); FillChar(FLastBurst, SizeOf(FLastBurst), 0);
FillChar(FLastBurstInfo, SizeOf(FLastBurstInfo), 0); FillChar(FLastBurstInfo, SizeOf(FLastBurstInfo), 0);
FillChar(FLastLinkControl, SizeOf(FLastLinkControl), 0); FillChar(FLinkControl, SizeOf(FLinkControl), 0);
FLastLCSlot := -1; FLastLCSlot := -1;
FColorCodeValid := False; FColorCodeValid := False;
FColorCode := 0; FColorCode := 0;
FLastDataType := 0; FLastDataType := 0;
FSlotTypeCorrectedBits := 0; FSlotTypeCorrectedBits := 0;
FSelectedSlot := -1; FSelectedSlot := -1;
FLastSelectedVoiceTick := 0;
FVoiceFrameCount := 0; FVoiceFrameCount := 0;
FVoiceErrorCount := 0; FVoiceErrorCount := 0;
DMRMbeReset(FMbe); DMRMbeReset(FMbe);
@@ -487,7 +489,6 @@ begin
end; end;
if FLastBurstInfo.LinkControl.Decoded then if FLastBurstInfo.LinkControl.Decoded then
begin begin
FLastLinkControl := FLastBurstInfo.LinkControl;
if (FSyncKind in [dskBSData, dskBSVoice]) and if (FSyncKind in [dskBSData, dskBSVoice]) and
FLastBurstInfo.CACH.Valid then FLastBurstInfo.CACH.Valid then
FLastLCSlot := FLastBurstInfo.CACH.Slot FLastLCSlot := FLastBurstInfo.CACH.Slot
@@ -495,7 +496,12 @@ begin
FLastLCSlot := 1 FLastLCSlot := 1
else else
FLastLCSlot := 0; FLastLCSlot := 0;
if FSelectedSlot < 0 then FSelectedSlot := FLastLCSlot; FLinkControl[FLastLCSlot] := FLastBurstInfo.LinkControl;
if FSelectedSlot < 0 then
begin
FSelectedSlot := FLastLCSlot;
FLastSelectedVoiceTick := GetTickCount64;
end;
end; end;
DecodeVoiceBurst; DecodeVoiceBurst;
Inc(FBurstCount); Inc(FBurstCount);
@@ -508,6 +514,7 @@ var
PCM: array[0..DMR_PCM_SAMPLES - 1] of Single; PCM: array[0..DMR_PCM_SAMPLES - 1] of Single;
MbeResult: TDMRMbeResult; MbeResult: TDMRMbeResult;
Slot, FrameIndex, RC: Integer; Slot, FrameIndex, RC: Integer;
NowTick: QWord;
begin begin
if (FMbe = nil) or (FLastSyncTick = 0) or if (FMbe = nil) or (FLastSyncTick = 0) or
(GetTickCount64 - FLastSyncTick > DMR_SYNC_HOLD_MS) then Exit; (GetTickCount64 - FLastSyncTick > DMR_SYNC_HOLD_MS) then Exit;
@@ -521,8 +528,20 @@ begin
end end
else if FSyncKind = dskDirectTS2Voice then Slot := 1 else if FSyncKind = dskDirectTS2Voice then Slot := 1
else Slot := 0; 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; 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); DMRExtractAMBEFrames(FLastBurst, Frames);
for FrameIndex := 0 to 2 do for FrameIndex := 0 to 2 do
@@ -576,6 +595,7 @@ end;
procedure TDMRDecoder.GetStatus(out S: TDMRStatus); procedure TDMRDecoder.GetStatus(out S: TDMRStatus);
var var
NowTick: QWord; NowTick: QWord;
LCStatusSlot: Integer;
begin begin
FillChar(S, SizeOf(S), 0); FillChar(S, SizeOf(S), 0);
NowTick := GetTickCount64; NowTick := GetTickCount64;
@@ -608,12 +628,19 @@ begin
S.ColorCode := FColorCode; S.ColorCode := FColorCode;
S.DataType := FLastDataType; S.DataType := FLastDataType;
S.SlotTypeCorrectedBits := FSlotTypeCorrectedBits; S.SlotTypeCorrectedBits := FSlotTypeCorrectedBits;
S.LinkControlValid := FLastLinkControl.Decoded; LCStatusSlot := FSelectedSlot;
S.LCSlot := FLastLCSlot; if (LCStatusSlot < 0) or not FLinkControl[LCStatusSlot].Decoded then
S.LCOpcode := FLastLinkControl.Opcode; LCStatusSlot := FLastLCSlot;
S.ServiceOptions := FLastLinkControl.ServiceOptions; S.LinkControlValid := (LCStatusSlot >= 0) and
S.TargetID := FLastLinkControl.TargetID; FLinkControl[LCStatusSlot].Decoded;
S.SourceID := FLastLinkControl.SourceID; 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.SelectedSlot := FSelectedSlot;
S.VoiceFrameCount := FVoiceFrameCount; S.VoiceFrameCount := FVoiceFrameCount;
S.VoiceErrorCount := FVoiceErrorCount; 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 not S.Synced then Exit(Format('DMR sync... %.3f', [S.SignalRMS]));
if S.Inverted then Inv := ' INV' else Inv := ''; if S.Inverted then Inv := ' INV' else Inv := '';
Details := ''; 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 if S.SlotTypeValid then
Details := Details + Format(' CC%d/DT%d', [S.ColorCode, S.DataType]); Details := Details + Format(' CC%d/DT%d', [S.ColorCode, S.DataType]);
if S.LinkControlValid then Details := Details + Format(' TG%d', [S.TargetID]); if S.LinkControlValid then Details := Details + Format(' TG%d', [S.TargetID]);