You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

468 lines
21 KiB

// SPDX-License-Identifier: AGPL-3.0-only
/**
* Digital Voice Modem - Audio Bridge
* AGPLv3 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Audio Bridge
* @license AGPLv3 License (https://opensource.org/licenses/AGPL-3.0)
*
* Copyright (C) 2022-2024 Bryan Biedenkapp, N2PLL
*
*/
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Serilog;
using fnecore;
using fnecore.P25;
using NAudio.Wave;
using System.Windows.Threading;
namespace WhackerLinkConsoleV2
{
/// <summary>
/// Implements a FNE system base.
/// </summary>
public abstract partial class FneSystemBase : fnecore.FneSystemBase
{
public const int IMBE_BUF_LEN = 11;
/*
** Methods
*/
/// <summary>
/// Callback used to validate incoming P25 data.
/// </summary>
/// <param name="peerId">Peer ID</param>
/// <param name="srcId">Source Address</param>
/// <param name="dstId">Destination Address</param>
/// <param name="callType">Call Type (Group or Private)</param>
/// <param name="duid">P25 DUID</param>
/// <param name="frameType">Frame Type</param>
/// <param name="streamId">Stream ID</param>
/// <param name="message">Raw message data</param>
/// <returns>True, if data stream is valid, otherwise false.</returns>
protected override bool P25DataValidate(uint peerId, uint srcId, uint dstId, CallType callType, P25DUID duid, FrameType frameType, uint streamId, byte[] message)
{
return true;
}
/// <summary>
/// Event handler used to pre-process incoming P25 data.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected override void P25DataPreprocess(object sender, P25DataReceivedEvent e)
{
return;
}
public void CreateNewP25MessageHdr(byte duid, RemoteCallData callData, ref byte[] data)
{
CreateP25MessageHdr(duid, callData, ref data);
}
/// <summary>
/// Helper to send a P25 TDU message.
/// </summary>
/// <param name="grantDemand"></param>
public void SendP25TDU(uint srcId, uint dstId, bool grantDemand = false)
{
RemoteCallData callData = new RemoteCallData()
{
SrcId = srcId,
DstId = dstId,
LCO = P25Defines.LC_GROUP
};
SendP25TDU(callData, grantDemand);
}
/// <summary>
/// Encode a logical link data unit 1.
/// </summary>
/// <param name="data"></param>
/// <param name="offset"></param>
/// <param name="imbe"></param>
/// <param name="frameType"></param>
/// <param name="srcIdOverride"></param>
private void EncodeLDU1(ref byte[] data, int offset, byte[] imbe, byte frameType, uint srcId, uint dstId)
{
if (data == null)
throw new ArgumentNullException("data");
if (imbe == null)
throw new ArgumentNullException("imbe");
// determine the LDU1 DFSI frame length, its variable
uint frameLength = P25DFSI.P25_DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES;
switch (frameType)
{
case P25DFSI.P25_DFSI_LDU1_VOICE1:
frameLength = P25DFSI.P25_DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU1_VOICE2:
frameLength = P25DFSI.P25_DFSI_LDU1_VOICE2_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU1_VOICE3:
frameLength = P25DFSI.P25_DFSI_LDU1_VOICE3_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU1_VOICE4:
frameLength = P25DFSI.P25_DFSI_LDU1_VOICE4_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU1_VOICE5:
frameLength = P25DFSI.P25_DFSI_LDU1_VOICE5_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU1_VOICE6:
frameLength = P25DFSI.P25_DFSI_LDU1_VOICE6_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU1_VOICE7:
frameLength = P25DFSI.P25_DFSI_LDU1_VOICE7_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU1_VOICE8:
frameLength = P25DFSI.P25_DFSI_LDU1_VOICE8_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU1_VOICE9:
frameLength = P25DFSI.P25_DFSI_LDU1_VOICE9_FRAME_LENGTH_BYTES;
break;
default:
return;
}
byte[] dfsiFrame = new byte[frameLength];
dfsiFrame[0U] = frameType; // Frame Type
// different frame types mean different things
switch (frameType)
{
case P25DFSI.P25_DFSI_LDU1_VOICE2:
{
Buffer.BlockCopy(imbe, 0, dfsiFrame, 1, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU1_VOICE3:
{
dfsiFrame[1U] = P25Defines.LC_GROUP; // LCO
dfsiFrame[2U] = 0; // MFId
dfsiFrame[3U] = 0; // Service Options
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU1_VOICE4:
{
dfsiFrame[1U] = (byte)((dstId >> 16) & 0xFFU); // Talkgroup Address
dfsiFrame[2U] = (byte)((dstId >> 8) & 0xFFU);
dfsiFrame[3U] = (byte)((dstId >> 0) & 0xFFU);
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU1_VOICE5:
{
dfsiFrame[1U] = (byte)((srcId >> 16) & 0xFFU); // Source Address
dfsiFrame[2U] = (byte)((srcId >> 8) & 0xFFU);
dfsiFrame[3U] = (byte)((srcId >> 0) & 0xFFU);
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU1_VOICE6:
{
dfsiFrame[1U] = 0; // RS (24,12,13)
dfsiFrame[2U] = 0; // RS (24,12,13)
dfsiFrame[3U] = 0; // RS (24,12,13)
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU1_VOICE7:
{
dfsiFrame[1U] = 0; // RS (24,12,13)
dfsiFrame[2U] = 0; // RS (24,12,13)
dfsiFrame[3U] = 0; // RS (24,12,13)
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU1_VOICE8:
{
dfsiFrame[1U] = 0; // RS (24,12,13)
dfsiFrame[2U] = 0; // RS (24,12,13)
dfsiFrame[3U] = 0; // RS (24,12,13)
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU1_VOICE9:
{
dfsiFrame[1U] = 0; // LSD MSB
dfsiFrame[2U] = 0; // LSD LSB
Buffer.BlockCopy(imbe, 0, dfsiFrame, 4, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU1_VOICE1:
default:
{
dfsiFrame[6U] = 0; // RSSI
Buffer.BlockCopy(imbe, 0, dfsiFrame, 10, IMBE_BUF_LEN); // IMBE
}
break;
}
Buffer.BlockCopy(dfsiFrame, 0, data, offset, (int)frameLength);
}
/// <summary>
/// Creates an P25 LDU1 frame message.
/// </summary>
/// <param name="data"></param>
/// <param name="srcId"></param>
public void CreateP25LDU1Message(in byte[] netLDU1, ref byte[] data, uint srcId, uint dstId)
{
// pack DFSI data
int count = P25_MSG_HDR_SIZE;
byte[] imbe = new byte[IMBE_BUF_LEN];
Buffer.BlockCopy(netLDU1, 10, imbe, 0, IMBE_BUF_LEN);
EncodeLDU1(ref data, 24, imbe, P25DFSI.P25_DFSI_LDU1_VOICE1, srcId, dstId);
count += (int)P25DFSI.P25_DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU1, 26, imbe, 0, IMBE_BUF_LEN);
EncodeLDU1(ref data, 46, imbe, P25DFSI.P25_DFSI_LDU1_VOICE2, srcId, dstId);
count += (int)P25DFSI.P25_DFSI_LDU1_VOICE2_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU1, 55, imbe, 0, IMBE_BUF_LEN);
EncodeLDU1(ref data, 60, imbe, P25DFSI.P25_DFSI_LDU1_VOICE3, srcId, dstId);
count += (int)P25DFSI.P25_DFSI_LDU1_VOICE3_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU1, 80, imbe, 0, IMBE_BUF_LEN);
EncodeLDU1(ref data, 77, imbe, P25DFSI.P25_DFSI_LDU1_VOICE4, srcId, dstId);
count += (int)P25DFSI.P25_DFSI_LDU1_VOICE4_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU1, 105, imbe, 0, IMBE_BUF_LEN);
EncodeLDU1(ref data, 94, imbe, P25DFSI.P25_DFSI_LDU1_VOICE5, srcId, dstId);
count += (int)P25DFSI.P25_DFSI_LDU1_VOICE5_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU1, 130, imbe, 0, IMBE_BUF_LEN);
EncodeLDU1(ref data, 111, imbe, P25DFSI.P25_DFSI_LDU1_VOICE6, srcId, dstId);
count += (int)P25DFSI.P25_DFSI_LDU1_VOICE6_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU1, 155, imbe, 0, IMBE_BUF_LEN);
EncodeLDU1(ref data, 128, imbe, P25DFSI.P25_DFSI_LDU1_VOICE7, srcId, dstId);
count += (int)P25DFSI.P25_DFSI_LDU1_VOICE7_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU1, 180, imbe, 0, IMBE_BUF_LEN);
EncodeLDU1(ref data, 145, imbe, P25DFSI.P25_DFSI_LDU1_VOICE8, srcId, dstId);
count += (int)P25DFSI.P25_DFSI_LDU1_VOICE8_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU1, 204, imbe, 0, IMBE_BUF_LEN);
EncodeLDU1(ref data, 162, imbe, P25DFSI.P25_DFSI_LDU1_VOICE9, srcId, dstId);
count += (int)P25DFSI.P25_DFSI_LDU1_VOICE9_FRAME_LENGTH_BYTES;
data[23U] = (byte)count;
}
/// <summary>
/// Encode a logical link data unit 2.
/// </summary>
/// <param name="data"></param>
/// <param name="offset"></param>
/// <param name="imbe"></param>
/// <param name="frameType"></param>
private void EncodeLDU2(ref byte[] data, int offset, byte[] imbe, byte frameType)
{
if (data == null)
throw new ArgumentNullException("data");
if (imbe == null)
throw new ArgumentNullException("imbe");
// determine the LDU2 DFSI frame length, its variable
uint frameLength = P25DFSI.P25_DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES;
switch (frameType)
{
case P25DFSI.P25_DFSI_LDU2_VOICE10:
frameLength = P25DFSI.P25_DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU2_VOICE11:
frameLength = P25DFSI.P25_DFSI_LDU2_VOICE11_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU2_VOICE12:
frameLength = P25DFSI.P25_DFSI_LDU2_VOICE12_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU2_VOICE13:
frameLength = P25DFSI.P25_DFSI_LDU2_VOICE13_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU2_VOICE14:
frameLength = P25DFSI.P25_DFSI_LDU2_VOICE14_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU2_VOICE15:
frameLength = P25DFSI.P25_DFSI_LDU2_VOICE15_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU2_VOICE16:
frameLength = P25DFSI.P25_DFSI_LDU2_VOICE16_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU2_VOICE17:
frameLength = P25DFSI.P25_DFSI_LDU2_VOICE17_FRAME_LENGTH_BYTES;
break;
case P25DFSI.P25_DFSI_LDU2_VOICE18:
frameLength = P25DFSI.P25_DFSI_LDU2_VOICE18_FRAME_LENGTH_BYTES;
break;
default:
return;
}
byte[] dfsiFrame = new byte[frameLength];
dfsiFrame[0U] = frameType; // Frame Type
// different frame types mean different things
switch (frameType)
{
case P25DFSI.P25_DFSI_LDU2_VOICE11:
{
Buffer.BlockCopy(imbe, 0, dfsiFrame, 1, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU2_VOICE12:
{
dfsiFrame[1U] = 0; // Message Indicator
dfsiFrame[2U] = 0;
dfsiFrame[3U] = 0;
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU2_VOICE13:
{
dfsiFrame[1U] = 0; // Message Indicator
dfsiFrame[2U] = 0;
dfsiFrame[3U] = 0;
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU2_VOICE14:
{
dfsiFrame[1U] = 0; // Message Indicator
dfsiFrame[2U] = 0;
dfsiFrame[3U] = 0;
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU2_VOICE15:
{
dfsiFrame[1U] = P25Defines.P25_ALGO_UNENCRYPT; // Algorithm ID
dfsiFrame[2U] = 0; // Key ID
dfsiFrame[3U] = 0;
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU2_VOICE16:
{
// first 3 bytes of frame are supposed to be
// part of the RS(24, 16, 9) of the VOICE12, 13, 14, 15
// control bytes
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU2_VOICE17:
{
// first 3 bytes of frame are supposed to be
// part of the RS(24, 16, 9) of the VOICE12, 13, 14, 15
// control bytes
Buffer.BlockCopy(imbe, 0, dfsiFrame, 5, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU2_VOICE18:
{
dfsiFrame[1U] = 0; // LSD MSB
dfsiFrame[2U] = 0; // LSD LSB
Buffer.BlockCopy(imbe, 0, dfsiFrame, 4, IMBE_BUF_LEN); // IMBE
}
break;
case P25DFSI.P25_DFSI_LDU2_VOICE10:
default:
{
dfsiFrame[6U] = 0; // RSSI
Buffer.BlockCopy(imbe, 0, dfsiFrame, 10, IMBE_BUF_LEN); // IMBE
}
break;
}
Buffer.BlockCopy(dfsiFrame, 0, data, offset, (int)frameLength);
}
/// <summary>
/// Creates an P25 LDU2 frame message.
/// </summary>
/// <param name="netLDU2">Input LDU data array</param>
/// <param name="data">Output data array</param>
public void CreateP25LDU2Message(in byte[] netLDU2, ref byte[] data)
{
// pack DFSI data
int count = P25_MSG_HDR_SIZE;
byte[] imbe = new byte[IMBE_BUF_LEN];
Buffer.BlockCopy(netLDU2, 10, imbe, 0, IMBE_BUF_LEN);
EncodeLDU2(ref data, 24, imbe, P25DFSI.P25_DFSI_LDU2_VOICE10);
count += (int)P25DFSI.P25_DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU2, 26, imbe, 0, IMBE_BUF_LEN);
EncodeLDU2(ref data, 46, imbe, P25DFSI.P25_DFSI_LDU2_VOICE11);
count += (int)P25DFSI.P25_DFSI_LDU2_VOICE11_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU2, 55, imbe, 0, IMBE_BUF_LEN);
EncodeLDU2(ref data, 60, imbe, P25DFSI.P25_DFSI_LDU2_VOICE12);
count += (int)P25DFSI.P25_DFSI_LDU2_VOICE12_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU2, 80, imbe, 0, IMBE_BUF_LEN);
EncodeLDU2(ref data, 77, imbe, P25DFSI.P25_DFSI_LDU2_VOICE13);
count += (int)P25DFSI.P25_DFSI_LDU2_VOICE13_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU2, 105, imbe, 0, IMBE_BUF_LEN);
EncodeLDU2(ref data, 94, imbe, P25DFSI.P25_DFSI_LDU2_VOICE14);
count += (int)P25DFSI.P25_DFSI_LDU2_VOICE14_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU2, 130, imbe, 0, IMBE_BUF_LEN);
EncodeLDU2(ref data, 111, imbe, P25DFSI.P25_DFSI_LDU2_VOICE15);
count += (int)P25DFSI.P25_DFSI_LDU2_VOICE15_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU2, 155, imbe, 0, IMBE_BUF_LEN);
EncodeLDU2(ref data, 128, imbe, P25DFSI.P25_DFSI_LDU2_VOICE16);
count += (int)P25DFSI.P25_DFSI_LDU2_VOICE16_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU2, 180, imbe, 0, IMBE_BUF_LEN);
EncodeLDU2(ref data, 145, imbe, P25DFSI.P25_DFSI_LDU2_VOICE17);
count += (int)P25DFSI.P25_DFSI_LDU2_VOICE17_FRAME_LENGTH_BYTES;
Buffer.BlockCopy(netLDU2, 204, imbe, 0, IMBE_BUF_LEN);
EncodeLDU2(ref data, 162, imbe, P25DFSI.P25_DFSI_LDU2_VOICE18);
count += (int)P25DFSI.P25_DFSI_LDU2_VOICE18_FRAME_LENGTH_BYTES;
data[23U] = (byte)count;
}
/// <summary>
/// Event handler used to process incoming P25 data.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected override void P25DataReceived(object sender, P25DataReceivedEvent e)
{
DateTime pktTime = DateTime.Now;
if (e.DUID == P25DUID.HDU || e.DUID == P25DUID.TSDU || e.DUID == P25DUID.PDU)
return;
if (e.CallType == CallType.GROUP)
{
if (e.SrcId == 0)
return;
mainWindow.P25DataReceived(e, pktTime);
}
}
} // public abstract partial class FneSystemBase : fnecore.FneSystemBase
}

Powered by TurnKey Linux.