diff --git a/DMRDecoder.pas b/DMRDecoder.pas index 0458209..3c0f7f5 100644 --- a/DMRDecoder.pas +++ b/DMRDecoder.pas @@ -166,6 +166,7 @@ type function GetLastBurst(var Dibits: array of Byte; out Sequence: QWord): Boolean; class function SyncKindName(Kind: TDMRSyncKind): string; static; + class function LinkControlTargetText(const S: TDMRStatus): string; static; property Enabled: Boolean read FEnabled; property OnAudio: TDMRAudioEvent read FOnAudio write FOnAudio; end; @@ -580,6 +581,17 @@ begin FFixedNegativeOuter := 0; FFixedCenter := 0; FMobileActiveBurst := True; + // LC belongs to a call/slot, not to the tuned frequency forever. Keeping it + // across carrier loss made a newly acquired call briefly inherit the old + // target and display the same apparent TG on unrelated transmissions. + FillChar(FLinkControl, SizeOf(FLinkControl), 0); + FLastLCSlot := -1; + FSelectedSlot := -1; + FLastSelectedVoiceTick := 0; + FColorCodeValid := False; + FColorCode := 0; + FLastDataType := 0; + FSlotTypeCorrectedBits := 0; DMRMbeReset(FMbe); end; @@ -947,4 +959,18 @@ begin end; end; +class function TDMRDecoder.LinkControlTargetText( + const S: TDMRStatus): string; +begin + Result := ''; + if not S.LinkControlValid or (S.TargetID = 0) then Exit; + // ETSI Full Link Control opcode 0 is Group Voice Channel User; opcode 3 is + // Unit-to-Unit Voice Channel User. Other/vendor opcodes may reuse these 24 + // bits for different data, so do not mislabel them as a talkgroup. + case S.LCOpcode of + 0: Result := 'TG' + IntToStr(S.TargetID); + 3: Result := 'ID' + IntToStr(S.TargetID); + end; +end; + end. diff --git a/MainForm.pas b/MainForm.pas index f764670..3194020 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -3606,7 +3606,7 @@ end; function TMainForm.DMRStatusText: string; var S: TDMRStatus; - Inv, Details: string; + Inv, Details, TargetText: string; begin if not FController.GetDMRStatus(S) then Exit('DMR unavailable'); if not S.Enabled then Exit('DMR off'); @@ -3617,7 +3617,8 @@ begin 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]); + TargetText := TDMRDecoder.LinkControlTargetText(S); + if TargetText <> '' then Details := Details + ' ' + TargetText; Result := Format('DMR %s%s%s #%d', [TDMRDecoder.SyncKindName(S.SyncKind), Details, Inv, S.SyncCount]); diff --git a/PanafallPanel.pas b/PanafallPanel.pas index 6636451..74c4bc5 100644 --- a/PanafallPanel.pas +++ b/PanafallPanel.pas @@ -1382,7 +1382,7 @@ var I, Slot: Integer; O: TVfoOverlay; S: TDMRStatus; - Txt: string; + Txt, TargetText: string; begin if FController = nil then Exit; for I := 0 to High(FSliceFlags) do @@ -1401,8 +1401,8 @@ begin else if S.CACHValid then Slot := S.Slot; if Slot in [0, 1] then Txt := 'DMR TS' + IntToStr(Slot + 1); if S.SlotTypeValid then Txt := Txt + ' CC' + IntToStr(S.ColorCode); - if S.LinkControlValid and (S.TargetID <> 0) then - Txt := Txt + ' TG' + IntToStr(S.TargetID); + TargetText := TDMRDecoder.LinkControlTargetText(S); + if TargetText <> '' then Txt := Txt + ' ' + TargetText; O.UpdateDMRStatus(Txt, True); end; end;