https://www.rtl-sdr.com/tetra-decoder-plugin-for-sdr-now-available/

SDR# 1.0.0.1715
tetra plugin msys2
dotPeek

Reverse engineer SDRSharp.Tetra.dll to Visual Studio project with dotPeek.
Fix build errors.

Change BeginInvoke((Delegate -> Action
      if (flag)
      {
        this._oneChannelIsActive = true;
        this.BeginInvoke((Action) (() => this._controlInterface.AudioIsMuted = false));
      }
      else
      {
        this._oneChannelIsActive = false;
        this.BeginInvoke((Delegate) (() => this._controlInterface.AudioIsMuted = true));   // --> (Action instead of Delegate)
      }

Fix pointer errors:

err-fix1.jpg

=>

    private unsafe int MonoToStereo(float* buffer, int monoLength)
    {
      int index1 = monoLength - 1;
      int num1 = monoLength * 2 - 1;
      for (int index2 = 0; index2 < monoLength; ++index2)
      {
        float* numPtr1 = buffer;
        int num2 = num1;
        int num3 = num2 - 1;
        IntPtr num4 = (IntPtr) (num2 * 4 + numPtr1);
        *(float*) ((IntPtr) num4) = buffer[index1];
        float* numPtr2 = buffer;
        int num5 = num3;
        num1 = num5 - 1;
        IntPtr num6 = (IntPtr) (num5 * 4 + numPtr2);
        *(float*)((IntPtr) num6) = buffer[index1];
        --index1;
      }
      return monoLength * 2;
    }

If starting MSYS2 pacman -S socat produces error:
msys2 pacman -S socat error: XXXX : signature from ...
Run in MSYS2 shell:

rm -r /etc/pacman.d/gnupg/
pacman-key --init
pacman-key --populate msys2
pacman-key --refresh

MSYS2 Tetra decoder plugin occasionally throws error:
err.jpg

Fix:
NetInfoWindow.cs -- add/modify lines which are bolded below

    private string DictToString(Dictionary<string, string> el)
    {
      string str = string.Empty;
            if (el.Count == 0) return str;
      foreach (string key in el.Keys)
      {
        switch (key)
        {
          case "CCODE":
          case "MCC":
          case "MNC":
            str = str + key + ":" + (object) int.Parse(el[key], NumberStyles.HexNumber) + " ";
            continue;
          case "FUNC":
          case "RX":
            continue;
          default:
            str = str + key + ":" + el[key] + " ";
            continue;
        }
      }
      return str;
    }

    public void ParseFunc(Dictionary<string, string> elements)
    {
      if (!elements.ContainsKey("FUNC"))
         return;

      switch (elements["FUNC"])
      {
        case "BURST":
          break;
        case "DCONNECTDEC":
          this.connectTextBox.AppendText(this.DictToString(elements) + Environment.NewLine);
          this._dconnectTime = 10;
          break;
        case "DRELEASEDEC":
          this.releaseTextBox.AppendText(this.DictToString(elements) + Environment.NewLine);
          this._dreleaseTime = 10;
          break;
        case "DSETUPDEC":
          this.setupTextBox.AppendText(this.DictToString(elements) + Environment.NewLine);
          this._dsetupTime = 10;
          break;
        case "DSTATUSDEC":
          this.statusTextBox.AppendText(this.DictToString(elements) + Environment.NewLine);
          this._dstatusTime = 10;
          break;
        case "DTXGRANTDEC":
          this.txGrantTextBox.AppendText(this.DictToString(elements) + Environment.NewLine);
          this._dtxTime = 10;
          break;
        case "FREQINFO1":
                    string dlf = string.Empty;
                    elements.TryGetValue("DLF", out dlf);

          if (this.freq1Label.Text.Contains(dlf))
            break;
          Label freq1Label = this.freq1Label;
                    string la = string.Empty;
                    elements.TryGetValue("LA", out la);
          freq1Label.Text = freq1Label.Text + dlf + " LA" + la + "; ";
          this._freqInfoTime = 10;
          break;
        case "FREQINFO2":
          break;
        case "NETINFO1":
          this.netInfoLabel.Text = this.DictToString(elements);
          this._netInfoTime = 10;
          break;
        case "SDSDEC":
          this.sdsTextBox.AppendText(this.DictToString(elements) + Environment.NewLine);
          this._sdsTime = 10;
          break;
        default:
          if (this.DictToString(elements).Length == 0)
            break;
          this.otherTextBox.AppendText(elements["FUNC"] + " " + this.DictToString(elements) + Environment.NewLine);
          this._otherTime = 10;
          break;
      }
    }


TetraPanel.cs
private unsafe void UdpReceiver()
comment out elements.ContainsValue("SDSDEC")

              string buf = Encoding.ASCII.GetString(numArray);
              int startIndex = buf.IndexOf("TETMON_begin") + "TETMON_begin".Length;
              int length = buf.IndexOf("TETMON_end") - startIndex;
              if (startIndex >= 0 && length > 0)
              {
                this._tetmonReceived = true;
                this._tetmonControl = buf.Substring(startIndex, length);
                Dictionary<string, string> elements = TetraPanel.ParseElements(buf);
                //elements.ContainsValue("SDSDEC");
                if (this._showInfo)
                  this._infoWindow?.BeginInvoke((Action) (() => this._infoWindow.ParseFunc(elements)));
              }
            }
          }
        }
      }
      udpClient.Close();
      udpClient.Dispose();
    }