* rework modem protocol to support variable length frames up to 64k; refactor P25 PDU handling to support TIA-102 minimum 512 byte frames;

* ensure length accounts for frame header;

* fix support for incoming long frames;
pull/5/head
Bryan Biedenkapp 2 years ago committed by GitHub
parent 07ec4612fc
commit 8d6611ef70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -12,7 +12,7 @@
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2016,2017,2018,2019 Andy Uribe, CA6JAU
* Copyright (C) 2019 Florian Wolters, DF2ET
* Copyright (C) 2017-2022 Bryan Biedenkapp, N2PLL
* Copyright (C) 2017-2024 Bryan Biedenkapp, N2PLL
*
*/
#include "Globals.h"
@ -25,7 +25,7 @@
#define concat(a, b, c) a " (build " b " " c ")"
const char HARDWARE[] = concat(DESCRIPTION, __TIME__, __DATE__);
const uint8_t PROTOCOL_VERSION = 3U;
const uint8_t PROTOCOL_VERSION = 4U;
// ---------------------------------------------------------------------------
// Public Class Members
@ -38,6 +38,7 @@ SerialPort::SerialPort() :
m_buffer(),
m_ptr(0U),
m_len(0U),
m_dblFrame(false),
m_debug(false)
{
// stub
@ -60,11 +61,19 @@ void SerialPort::process()
uint8_t c = readInt(1U);
if (m_ptr == 0U) {
if (c == DVM_FRAME_START) {
if (c == DVM_SHORT_FRAME_START) {
// Handle the frame start correctly
m_buffer[0U] = c;
m_ptr = 1U;
m_len = 0U;
m_dblFrame = false;
}
else if (c == DVM_LONG_FRAME_START) {
// Handle the frame start correctly
m_buffer[0U] = c;
m_ptr = 1U;
m_len = 0U;
m_dblFrame = true;
}
else {
m_ptr = 0U;
@ -73,9 +82,20 @@ void SerialPort::process()
}
else if (m_ptr == 1U) {
// Handle the frame length
m_len = m_buffer[m_ptr] = c;
if (m_dblFrame) {
m_buffer[m_ptr] = c;
m_len = ((c & 0xFFU) << 8);
} else {
m_len = m_buffer[m_ptr] = c;
}
m_ptr = 2U;
}
else if (m_ptr == 2U && m_dblFrame) {
// Handle the frame length
m_buffer[m_ptr] = c;
m_len = (m_len + (c & 0xFFU));
m_ptr = 3U;
}
else {
// Any other bytes are added to the buffer
m_buffer[m_ptr] = c;
@ -377,6 +397,7 @@ void SerialPort::process()
m_ptr = 0U;
m_len = 0U;
m_dblFrame = false;
}
}
}
@ -384,6 +405,7 @@ void SerialPort::process()
if (io.getWatchdog() >= 48000U) {
m_ptr = 0U;
m_len = 0U;
m_dblFrame = false;
}
}
@ -444,19 +466,22 @@ void SerialPort::writeDMRData(bool slot, const uint8_t* data, uint8_t length)
if (!m_dmrEnable)
return;
if (length + 3U > 40U) {
m_buffer[2U] = slot ? CMD_DMR_DATA2 : CMD_DMR_DATA1;
sendNAK(RSN_ILLEGAL_LENGTH);
return;
}
uint8_t reply[40U];
::memset(reply, 0x00U, 40U);
reply[0U] = DVM_FRAME_START;
reply[1U] = 0U;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = length + 3U;
reply[2U] = slot ? CMD_DMR_DATA2 : CMD_DMR_DATA1;
uint8_t count = 3U;
for (uint8_t i = 0U; i < length; i++, count++)
reply[count] = data[i];
reply[1U] = count;
::memcpy(reply + 3U, data, length);
writeInt(1U, reply, count);
writeInt(1U, reply, length + 3U);
}
/// <summary>
@ -473,7 +498,7 @@ void SerialPort::writeDMRLost(bool slot)
uint8_t reply[3U];
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 3U;
reply[2U] = slot ? CMD_DMR_LOST2 : CMD_DMR_LOST1;
@ -485,7 +510,7 @@ void SerialPort::writeDMRLost(bool slot)
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
void SerialPort::writeP25Data(const uint8_t* data, uint8_t length)
void SerialPort::writeP25Data(const uint8_t* data, uint16_t length)
{
if (m_modemState != STATE_P25 && m_modemState != STATE_IDLE)
return;
@ -493,19 +518,33 @@ void SerialPort::writeP25Data(const uint8_t* data, uint8_t length)
if (!m_p25Enable)
return;
uint8_t reply[250U];
if (length + 4U > 520U) {
m_buffer[2U] = CMD_P25_DATA;
sendNAK(RSN_ILLEGAL_LENGTH);
return;
}
reply[0U] = DVM_FRAME_START;
reply[1U] = 0U;
reply[2U] = CMD_P25_DATA;
uint8_t reply[520U];
::memset(reply, 0x00U, 520U);
uint8_t count = 3U;
for (uint8_t i = 0U; i < length; i++, count++)
reply[count] = data[i];
if (length < 252U) {
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = length + 3U;
reply[2U] = CMD_P25_DATA;
::memcpy(reply + 3U, data, length);
reply[1U] = count;
writeInt(1U, reply, length + 3U);
}
else {
length += 4U;
reply[0U] = DVM_LONG_FRAME_START;
reply[1U] = (length >> 8U) & 0xFFU;
reply[2U] = (length & 0xFFU);
reply[3U] = CMD_P25_DATA;
::memcpy(reply + 4U, data, length);
writeInt(1U, reply, count);
writeInt(1U, reply, length + 4U);
}
}
/// <summary>
@ -521,7 +560,7 @@ void SerialPort::writeP25Lost()
uint8_t reply[3U];
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 3U;
reply[2U] = CMD_P25_LOST;
@ -541,19 +580,22 @@ void SerialPort::writeNXDNData(const uint8_t* data, uint8_t length)
if (!m_nxdnEnable)
return;
if (length + 3U > 130U) {
m_buffer[2U] = CMD_NXDN_DATA;
sendNAK(RSN_ILLEGAL_LENGTH);
return;
}
uint8_t reply[130U];
::memset(reply, 0x00U, 130U);
reply[0U] = DVM_FRAME_START;
reply[1U] = 0U;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = length + 3U;
reply[2U] = CMD_NXDN_DATA;
uint8_t count = 3U;
for (uint8_t i = 0U; i < length; i++, count++)
reply[count] = data[i];
reply[1U] = count;
::memcpy(reply + 3U, data, length);
writeInt(1U, reply, count);
writeInt(1U, reply, length + 3U);
}
/// <summary>
@ -569,7 +611,7 @@ void SerialPort::writeNXDNLost()
uint8_t reply[3U];
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 3U;
reply[2U] = CMD_NXDN_LOST;
@ -583,19 +625,22 @@ void SerialPort::writeNXDNLost()
/// <param name="length"></param>
void SerialPort::writeCalData(const uint8_t* data, uint8_t length)
{
if (length + 3U > 130U) {
m_buffer[2U] = CMD_CAL_DATA;
sendNAK(RSN_ILLEGAL_LENGTH);
return;
}
uint8_t reply[130U];
::memset(reply, 0x00U, 130U);
reply[0U] = DVM_FRAME_START;
reply[1U] = 0U;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = length + 3U;
reply[2U] = CMD_CAL_DATA;
uint8_t count = 3U;
for (uint8_t i = 0U; i < length; i++, count++)
reply[count] = data[i];
::memcpy(reply + 3U, data, length);
reply[1U] = count;
writeInt(1U, reply, count);
writeInt(1U, reply, length + 3U);
}
/// <summary>
@ -608,19 +653,22 @@ void SerialPort::writeRSSIData(const uint8_t* data, uint8_t length)
if (m_modemState != STATE_RSSI_CAL)
return;
if (length + 3U > 30U) {
m_buffer[2U] = CMD_RSSI_DATA;
sendNAK(RSN_ILLEGAL_LENGTH);
return;
}
uint8_t reply[30U];
::memset(reply, 0x00U, 30U);
reply[0U] = DVM_FRAME_START;
reply[1U] = 0U;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = length + 3U;
reply[2U] = CMD_RSSI_DATA;
uint8_t count = 3U;
for (uint8_t i = 0U; i < length; i++, count++)
reply[count] = data[i];
reply[1U] = count;
::memcpy(reply + 3U, data, length);
writeInt(1U, reply, count);
writeInt(1U, reply, length + 3U);
}
/// <summary>
@ -633,8 +681,9 @@ void SerialPort::writeDebug(const char* text)
return;
uint8_t reply[130U];
::memset(reply, 0x00U, 130U);
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 0U;
reply[2U] = CMD_DEBUG1;
@ -658,8 +707,9 @@ void SerialPort::writeDebug(const char* text, int16_t n1)
return;
uint8_t reply[130U];
::memset(reply, 0x00U, 130U);
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 0U;
reply[2U] = CMD_DEBUG2;
@ -687,8 +737,9 @@ void SerialPort::writeDebug(const char* text, int16_t n1, int16_t n2)
return;
uint8_t reply[130U];
::memset(reply, 0x00U, 130U);
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 0U;
reply[2U] = CMD_DEBUG3;
@ -720,8 +771,9 @@ void SerialPort::writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3
return;
uint8_t reply[130U];
::memset(reply, 0x00U, 130U);
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 0U;
reply[2U] = CMD_DEBUG4;
@ -757,8 +809,9 @@ void SerialPort::writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3
return;
uint8_t reply[130U];
::memset(reply, 0x00U, 130U);
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 0U;
reply[2U] = CMD_DEBUG5;
@ -793,13 +846,19 @@ void SerialPort::writeDump(const uint8_t* data, uint16_t length)
if (!m_debug)
return;
uint8_t reply[512U];
if (length + 4U > 516U) {
m_buffer[2U] = CMD_DEBUG_DUMP;
sendNAK(RSN_ILLEGAL_LENGTH);
return;
}
reply[0U] = DVM_FRAME_START;
uint8_t reply[516U];
::memset(reply, 0x00U, 516U);
if (length > 252U) {
reply[1U] = 0U;
reply[2U] = (length + 4U) - 255U;
reply[0U] = DVM_LONG_FRAME_START;
reply[1U] = (length >> 8U) & 0xFFU;
reply[2U] = (length & 0xFFU);
reply[3U] = CMD_DEBUG_DUMP;
for (uint8_t i = 0U; i < length; i++)
@ -808,6 +867,7 @@ void SerialPort::writeDump(const uint8_t* data, uint16_t length)
writeInt(1U, reply, length + 4U);
}
else {
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = length + 3U;
reply[2U] = CMD_DEBUG_DUMP;
@ -829,7 +889,7 @@ void SerialPort::sendACK()
{
uint8_t reply[4U];
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 4U;
reply[2U] = CMD_ACK;
reply[3U] = m_buffer[2U];
@ -845,7 +905,7 @@ void SerialPort::sendNAK(uint8_t err)
{
uint8_t reply[5U];
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 5U;
reply[2U] = CMD_NAK;
reply[3U] = m_buffer[2U];
@ -864,7 +924,7 @@ void SerialPort::getStatus()
uint8_t reply[15U];
// send all sorts of interesting internal values
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 12U;
reply[2U] = CMD_GET_STATUS;
@ -930,7 +990,7 @@ void SerialPort::getVersion()
{
uint8_t reply[200U];
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 0U;
reply[2U] = CMD_GET_VERSION;

@ -10,7 +10,7 @@
*
* Copyright (C) 2015,2016,2018,2020,2021 Jonathan Naylor, G4KLX
* Copyright (C) 2018 Andy Uribe, CA6JAU
* Copyright (C) 2018,2021-2022 Bryan Biedenkapp, N2PLL
* Copyright (C) 2018,2021-2024 Bryan Biedenkapp, N2PLL
*
*/
#if !defined(__SERIAL_PORT_H__)
@ -132,7 +132,8 @@ enum CMD_REASON_CODE {
RSN_NXDN_DISABLED = 65U
};
const uint8_t DVM_FRAME_START = 0xFEU;
const uint8_t DVM_SHORT_FRAME_START = 0xFEU;
const uint8_t DVM_LONG_FRAME_START = 0xFDU;
#define SERIAL_SPEED 115200
@ -163,7 +164,7 @@ public:
void writeDMRLost(bool slot);
/// <summary>Write P25 frame data to serial port.</summary>
void writeP25Data(const uint8_t* data, uint8_t length);
void writeP25Data(const uint8_t* data, uint16_t length);
/// <summary>Write lost P25 frame data to serial port.</summary>
void writeP25Lost();
@ -193,7 +194,8 @@ public:
private:
uint8_t m_buffer[256U];
uint8_t m_ptr;
uint8_t m_len;
uint16_t m_len;
bool m_dblFrame;
bool m_debug;

@ -10,7 +10,7 @@
*
* Copyright (C) 2016 Jim McLaughlin, KI6ZUM
* Copyright (C) 2016,2017,2018,2019 Andy Uribe, CA6JAU
* Copyright (C) 2021,2022 Bryan Biedenkapp, N2PLL
* Copyright (C) 2021,2022,2024 Bryan Biedenkapp, N2PLL
*
*/
#include "Globals.h"
@ -187,7 +187,7 @@ void SerialPort::flashRead()
{
uint8_t reply[249U];
reply[0U] = DVM_FRAME_START;
reply[0U] = DVM_SHORT_FRAME_START;
reply[1U] = 249U;
reply[2U] = CMD_FLSH_READ;

@ -10,7 +10,7 @@
*
* Copyright (C) 2009-2016 Jonathan Naylor, G4KLX
* Copyright (C) 2018 Andy Uribe, CA6JAU
* Copyright (C) 2017-2018 Bryan Biedenkapp, N2PLL
* Copyright (C) 2017-2024 Bryan Biedenkapp, N2PLL
*
*/
#if !defined(__P25_DEFINES_H__)
@ -46,6 +46,11 @@ namespace p25
const uint32_t P25_TSDU_FRAME_LENGTH_SYMBOLS = P25_TSDU_FRAME_LENGTH_BYTES * 4U;
const uint32_t P25_TSDU_FRAME_LENGTH_SAMPLES = P25_TSDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
const uint32_t P25_PDU_FRAME_LENGTH_BYTES = 512U;
const uint32_t P25_PDU_FRAME_LENGTH_BITS = P25_PDU_FRAME_LENGTH_BYTES * 8U;
const uint32_t P25_PDU_FRAME_LENGTH_SYMBOLS = P25_PDU_FRAME_LENGTH_BYTES * 4U;
const uint32_t P25_PDU_FRAME_LENGTH_SAMPLES = P25_PDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
const uint32_t P25_TDULC_FRAME_LENGTH_BYTES = 54U;
const uint32_t P25_TDULC_FRAME_LENGTH_BITS = P25_TDULC_FRAME_LENGTH_BYTES * 8U;
const uint32_t P25_TDULC_FRAME_LENGTH_SYMBOLS = P25_TDULC_FRAME_LENGTH_BYTES * 4U;
@ -61,11 +66,6 @@ namespace p25
const uint32_t P25_NID_LENGTH_SYMBOLS = P25_NID_LENGTH_BYTES * 4U;
const uint32_t P25_NID_LENGTH_SAMPLES = P25_NID_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
const uint32_t P25_PDU_HDU_FRAME_LENGTH_BYTES = 39U;
const uint32_t P25_PDU_HDU_FRAME_LENGTH_BITS = P25_PDU_HDU_FRAME_LENGTH_BYTES * 8U;
const uint32_t P25_PDU_HDU_FRAME_LENGTH_SYMBOLS = P25_PDU_HDU_FRAME_LENGTH_BYTES * 4U;
const uint32_t P25_PDU_HDU_FRAME_LENGTH_SAMPLES = P25_PDU_HDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
const uint8_t P25_SYNC_BYTES[] = { 0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU };
const uint8_t P25_SYNC_BYTES_LENGTH = 6U;
const uint8_t P25_START_SYNC = 0x5FU;
@ -86,8 +86,8 @@ namespace p25
const uint32_t P25_SYNC_SYMBOLS = 0x00FB30A0U;
const uint32_t P25_SYNC_SYMBOLS_MASK = 0x00FFFFFFU;
// 442 = P25_LDU_FRAME_LENGTH_BYTES * 2 + 10 (BUFFER_LEN = P25_LDU_FRAME_LENGTH_BYTES * NO_OF_FRAMES + 10)
const uint32_t P25_TX_BUFFER_LEN = 442U; // 2 frames + pad
// 522 = P25_PDU_FRAME_LENGTH_BYTES + 10 (BUFFER_LEN = P25_PDU_FRAME_LENGTH_BYTES + 10)
const uint32_t P25_TX_BUFFER_LEN = 522U;
// Data Unit ID(s)
const uint8_t P25_DUID_HDU = 0x00U; // Header Data Unit

@ -10,7 +10,7 @@
*
* Copyright (C) 2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
* Copyright (C) 2021-2024 Bryan Biedenkapp, N2PLL
*
*/
#include "Globals.h"
@ -42,6 +42,7 @@ P25RX::P25RX() :
m_buffer(),
m_dataPtr(0U),
m_endPtr(NOENDPTR),
m_pduEndPtr(NOENDPTR),
m_lostCount(0U),
m_nac(0xF7EU),
m_state(P25RXS_NONE),
@ -61,6 +62,7 @@ void P25RX::reset()
::memset(m_buffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 3U);
m_endPtr = NOENDPTR;
m_pduEndPtr = NOENDPTR;
m_lostCount = 0U;
@ -83,8 +85,14 @@ void P25RX::databit(bool bit)
_WRITE_BIT(m_buffer, m_dataPtr, bit);
m_dataPtr++;
if (m_dataPtr > P25_LDU_FRAME_LENGTH_BITS) {
reset();
if (m_state != P25RXS_DATA) {
if (m_dataPtr > P25_LDU_FRAME_LENGTH_BITS) {
reset();
}
} else {
if (m_dataPtr > P25_PDU_FRAME_LENGTH_BITS) {
reset();
}
}
}
@ -169,7 +177,7 @@ void P25RX::processBit(bool bit)
return;
case P25_DUID_PDU:
m_state = P25RXS_DATA;
m_endPtr = P25_LDU_FRAME_LENGTH_BITS;
m_endPtr = m_pduEndPtr = P25_PDU_FRAME_LENGTH_BITS;
return;
case P25_DUID_TDULC:
{
@ -328,7 +336,7 @@ void P25RX::processData(bool bit)
// process NID
if (m_dataPtr == P25_SYNC_LENGTH_BITS + P25_NID_LENGTH_BITS + 1) {
DEBUG3("P25RX::processData() dataPtr/endPtr", m_dataPtr, m_endPtr);
DEBUG3("P25RX::processData() dataPtr/pduEndPtr", m_dataPtr, m_pduEndPtr);
if (!decodeNid()) {
io.setDecode(false);
@ -339,7 +347,7 @@ void P25RX::processData(bool bit)
else {
switch (m_duid) {
case P25_DUID_PDU:
m_endPtr = P25_LDU_FRAME_LENGTH_BITS;
m_endPtr = m_pduEndPtr = P25_PDU_FRAME_LENGTH_BITS;
return;
default:
{
@ -351,8 +359,8 @@ void P25RX::processData(bool bit)
}
}
// process voice frame
if (m_dataPtr == m_endPtr) {
// process data frame
if (m_dataPtr == m_pduEndPtr) {
m_lostCount--;
// we've not seen a data sync for too long, signal sync lost and change to P25RXS_NONE
@ -367,11 +375,11 @@ void P25RX::processData(bool bit)
else {
DEBUG2("P25RX::processData() sync found in PDU pos", m_dataPtr);
uint8_t frame[P25_LDU_FRAME_LENGTH_BYTES + 1U];
::memcpy(frame + 1U, m_buffer, m_endPtr / 8U);
uint8_t frame[P25_PDU_FRAME_LENGTH_BYTES + 1U];
::memcpy(frame + 1U, m_buffer, m_pduEndPtr / 8U);
frame[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U; // set sync flag
serial.writeP25Data(frame, P25_LDU_FRAME_LENGTH_BYTES + 1U);
serial.writeP25Data(frame, P25_PDU_FRAME_LENGTH_BYTES + 1U);
}
}
}
@ -416,11 +424,14 @@ bool P25RX::correlateSync()
m_endPtr = m_dataPtr + P25_LDU_FRAME_LENGTH_BITS - P25_SYNC_LENGTH_BITS;
if (m_endPtr >= P25_LDU_FRAME_LENGTH_BITS)
m_endPtr -= P25_LDU_FRAME_LENGTH_BITS;
m_pduEndPtr = m_dataPtr + P25_PDU_FRAME_LENGTH_BITS - P25_SYNC_LENGTH_BITS;
if (m_pduEndPtr >= P25_PDU_FRAME_LENGTH_BITS)
m_pduEndPtr -= P25_PDU_FRAME_LENGTH_BITS;
m_lostCount = MAX_SYNC_FRAMES;
m_dataPtr = P25_SYNC_LENGTH_BITS;
DEBUG3("P25RX::correlateSync() dataPtr/endPtr", m_dataPtr, m_endPtr);
DEBUG4("P25RX::correlateSync() dataPtr/endPtr/pduEndPtr", m_dataPtr, m_endPtr, m_pduEndPtr);
return true;
}

@ -10,7 +10,7 @@
*
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
* Copyright (C) 2021-2024 Bryan Biedenkapp, N2PLL
*
*/
#if !defined(__P25_RX_H__)
@ -53,11 +53,12 @@ namespace p25
private:
uint64_t m_bitBuffer;
uint8_t m_buffer[P25_LDU_FRAME_LENGTH_BYTES + 3U];
uint8_t m_buffer[P25_PDU_FRAME_LENGTH_BYTES + 3U];
uint16_t m_dataPtr;
uint16_t m_endPtr;
uint16_t m_pduEndPtr;
uint16_t m_lostCount;

Loading…
Cancel
Save

Powered by TurnKey Linux.