Add initial support for TSBK encode/decode

4.32j_maint
php 1 year ago
parent c4f2fe35cb
commit d9995b8712

@ -0,0 +1,130 @@
using System;
using fnecore.EDAC;
namespace fnecore.P25.LC
{
/// <summary>
/// Base TSBK Encode/Decode class
/// </summary>
public abstract class TSBKBase
{
protected bool LastBlock;
protected byte Lco;
protected byte MfId;
/// <summary>
/// Creates an instance of <see cref="TSBKBase"/>
/// </summary>
protected TSBKBase()
{
MfId = P25Defines.P25_MFG_STANDARD;
}
/// <summary>
/// Decode a TSBK
/// </summary>
/// <param name="data"></param>
/// <param name="payload"></param>
/// <param name="rawTSBK"></param>
/// <returns></returns>
public virtual bool Decode(byte[] data, ref byte[] payload, bool rawTSBK)
{
byte[] tsbk = new byte[P25Defines.P25_TSBK_LENGTH_BYTES];
FneUtils.Memset(tsbk, 0x00, tsbk.Length);
if (rawTSBK)
{
Array.Copy(data, tsbk, P25Defines.P25_TSBK_LENGTH_BYTES);
if (!CRC.CheckCCITT162(tsbk, P25Defines.P25_TSBK_LENGTH_BYTES))
{
if ((tsbk[P25Defines.P25_TSBK_LENGTH_BYTES - 2U] != 0x00U) && (tsbk[P25Defines.P25_TSBK_LENGTH_BYTES - 1U] != 0x00U))
{
Console.WriteLine("TSBK failed CRC CCITT-162 check");
return false;
}
}
}
else
{
byte[] raw = new byte[P25Defines.P25_TSBK_FEC_LENGTH_BYTES];
P25Interleaver.Decode(data, ref raw, 114, 318);
EDAC.Trellis trellis = new EDAC.Trellis();
if (!trellis.Decode12(raw, ref tsbk))
{
Console.WriteLine("TSBK Failed Trellis decode");
return false;
}
if (!CRC.CheckCCITT162(tsbk, P25Defines.P25_TSBK_LENGTH_BYTES))
{
Console.WriteLine("TSBK Failed CRC check after Trellis");
return false;
}
}
Lco = (byte)(tsbk[0] & 0x3F); // LCO
LastBlock = (tsbk[0] & 0x80) == 0x80; // Last Block Marker
MfId = tsbk[1]; // Manufacturer ID
Array.Copy(tsbk, 1, payload, 0, P25Defines.P25_TSBK_LENGTH_BYTES - 4);
return true;
}
/// <summary>
/// Encode a TSBK
/// </summary>
/// <param name="data"></param>
/// <param name="payload"></param>
/// <param name="rawTSBK"></param>
/// <param name="noTrellis"></param>
public virtual void Encode(ref byte[] data, ref byte[] payload, bool rawTSBK, bool noTrellis)
{
byte[] tsbk = new byte[P25Defines.P25_TSBK_LENGTH_BYTES];
FneUtils.Memset(tsbk, 0x00, tsbk.Length);
Array.Copy(payload, 0, tsbk, 2, P25Defines.P25_TSBK_LENGTH_BYTES - 4);
tsbk[0] = Lco; // LCO
tsbk[0] |= LastBlock ? (byte)0x80 : (byte)0x00; // Last Block Marker
tsbk[1] = MfId; // Manufacturer ID
CRC.AddCCITT162(ref tsbk, P25Defines.P25_TSBK_LENGTH_BYTES);
byte[] raw = new byte[P25Defines.P25_TSBK_FEC_LENGTH_BYTES];
FneUtils.Memset(raw, 0x00, raw.Length);
EDAC.Trellis trellis = new EDAC.Trellis();
trellis.Encode12(tsbk, ref raw);
if (rawTSBK)
{
if (noTrellis)
{
Array.Copy(tsbk, 0, data, 0, P25Defines.P25_TSBK_LENGTH_BYTES);
}
else
{
Array.Copy(raw, 0, data, 0, P25Defines.P25_TSBK_FEC_LENGTH_BYTES);
}
}
else
{
P25Interleaver.Encode(raw, ref data, 114, 318);
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "UNKNOWN TSBK";
}
} // public abstract class TSBKBase
} // namespace fnecore.P25.LC

@ -0,0 +1,91 @@
namespace fnecore.P25.LC.TSBK
{
/// <summary>
/// IOSP_ACK_RSP TSBK
/// </summary>
public class IOSP_ACK_RSP : TSBKBase
{
public uint DstId;
public uint SrcId;
public uint SysId;
public uint Wacn;
public bool Aiv;
public bool ExtendedAddr;
public byte Service;
/// <summary>
/// Creates an instance of <see cref="IOSP_ACK_RSP"/>
/// </summary>
/// <param name="dstId"></param>
/// <param name="srcId"></param>
/// <param name="aivFlag"></param>
/// <param name="service"></param>
public IOSP_ACK_RSP(uint dstId, uint srcId, bool aivFlag, byte service)
{
DstId = dstId;
SrcId = srcId;
Aiv = aivFlag;
Service = service;
Lco = P25Defines.TSBK_IOSP_ACK_RSP;
}
/// <summary>
/// Decode ACK_RSP TSBK
/// </summary>
/// <param name="data"></param>
/// <param name="rawTSBK"></param>
/// <returns></returns>
public bool Decode(byte[] data, bool rawTSBK)
{
byte[] tsbk = new byte[P25Defines.P25_TSBK_LENGTH_BYTES];
FneUtils.Memset(tsbk, 0x00, tsbk.Length);
bool ret = base.Decode(data, ref tsbk, rawTSBK);
if (!ret)
return false;
ulong tsbkValue = FneUtils.ToUInt64(tsbk, 0);
Aiv = ((tsbkValue >> 56) & 0x80U) == 0x80U; // Additional Info Flag
Service = (byte)((tsbkValue >> 56) & 0x3FU); // Service Type
DstId = FneUtils.Bytes3ToUInt32(tsbk, 3); // Target Radio Address
SrcId = FneUtils.Bytes3ToUInt32(tsbk, 0); // Source Radio Address
return true;
}
/// <summary>
/// Encode ACK_RSP TSBK
/// </summary>
/// <param name="data"></param>
/// <param name="payload"></param>
/// <param name="rawTSBK"></param>
/// <param name="noTrellis"></param>
public override void Encode(ref byte[] data, ref byte[] payload, bool rawTSBK, bool noTrellis)
{
ulong tsbkValue = 0;
tsbkValue = Service & 0x3FU; // Service Type
tsbkValue |= Aiv ? 0x80UL : 0x00UL; // Additional Info Flag
tsbkValue |= ExtendedAddr ? 0x40UL : 0x00UL; // Extended Addressing Flag
if (Aiv && ExtendedAddr)
{
tsbkValue = (tsbkValue << 20) + Wacn; // Network ID
tsbkValue = (tsbkValue << 12) + SysId; // System ID
}
else
{
tsbkValue = (tsbkValue << 32) + DstId; // Target Radio Address
}
tsbkValue = (tsbkValue << 24) + SrcId; // Source Radio Address
FneUtils.Memset(payload, 0x00, payload.Length);
FneUtils.WriteBytes(tsbkValue, ref payload, 0);
base.Encode(ref data, ref payload, rawTSBK, noTrellis);
}
} // public class IOSP_ACK_RSP
} // namespace fnecore.P25.LC.TSBK

@ -0,0 +1,63 @@
namespace fnecore.P25.LC.TSBK
{
/// <summary>
/// IOSP_CALL_ALRT TSBK
/// </summary>
public class IOSP_CALL_ALRT : TSBKBase
{
public uint DstId;
public uint SrcId;
/// <summary>
/// Creates an instance of <see cref="IOSP_CALL_ALRT"/>
/// </summary>
/// <param name="dstId"></param>
/// <param name="srcId"></param>
public IOSP_CALL_ALRT(uint dstId, uint srcId)
{
DstId = dstId;
SrcId = srcId;
Lco = P25Defines.TSBK_IOSP_CALL_ALRT;
}
/// <summary>
/// Decode CALL_ALRT TSBK
/// </summary>
/// <param name="data"></param>
/// <param name="rawTSBK"></param>
/// <returns></returns>
public bool Decode(byte[] data, bool rawTSBK)
{
byte[] tsbk = new byte[P25Defines.P25_TSBK_LENGTH_BYTES];
FneUtils.Memset(tsbk, 0x00, tsbk.Length);
bool ret = base.Decode(data, ref tsbk, rawTSBK);
if (!ret)
return false;
DstId = FneUtils.Bytes3ToUInt32(tsbk, 3); // Target Radio Address
SrcId = FneUtils.Bytes3ToUInt32(tsbk, 0); // Source Radio Address
return true;
}
/// <summary>
/// Encode CALL_ALRT TSBK
/// </summary>
/// <param name="data"></param>
/// <param name="payload"></param>
/// <param name="rawTSBK"></param>
/// <param name="noTrellis"></param>
public override void Encode(ref byte[] data, ref byte[] payload, bool rawTSBK, bool noTrellis)
{
ulong tsbkValue = 0;
tsbkValue = (tsbkValue << 40) + DstId; // Target Radio Address
tsbkValue = (tsbkValue << 24) + SrcId; // Source Radio Address
FneUtils.Memset(payload, 0x00, payload.Length);
FneUtils.WriteBytes(tsbkValue, ref payload, 0);
base.Encode(ref data, ref payload, rawTSBK, noTrellis);
}
} // public class IOSP_CALL_ALRT
} // namespace fnecore.P25.LC.TSBK
Loading…
Cancel
Save

Powered by TurnKey Linux.