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.
fnecore/P25/lc/TSBKBase.cs

147 lines
4.6 KiB

// SPDX-License-Identifier: AGPL-3.0-only
/**
* Digital Voice Modem - Fixed Network Equipment Core Library
* AGPLv3 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Fixed Network Equipment Core Library
* @license AGPLv3 License (https://opensource.org/licenses/AGPL-3.0)
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
* Copyright (C) 2024 Caleb, K4PHP
*
*/
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;
protected internal byte[] Payload = new byte[P25Defines.P25_TSBK_LENGTH_BYTES - 4];
/// <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, 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, Payload.Length);
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, 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, Payload.Length);
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

Powered by TurnKey Linux.