diff --git a/DMRDecoder.pas b/DMRDecoder.pas index b1d9eb3..f75312a 100644 --- a/DMRDecoder.pas +++ b/DMRDecoder.pas @@ -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; diff --git a/MainForm.pas b/MainForm.pas index 32881bd..8f22a94 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -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]);