SNDCPv1 Trunked Packet Data (#134)
* add SNDCP data page TSBKs, correct PDU disassembly with a header offset and clear autonomous access in the SNDCP channel announcement; - add ISP_SNDCP_DATA_PAGE_RES ($13) and OSP_SNDCP_DATA_PAGE_REQ ($15) - Assembler::disassemble no longer shifts the coded block stream by the data header offset; the offset counts octets of reassembled user data - OSP_SNDCP_CH_ANN no longer sets autonomous access; the announced channel is the control channel, which receives no SN-Data * echo data service options in SNDCP grants, handle SNDCP data pages and relay SNDCP grants to the FNE; - the SNDCP data channel grant echoes the Data Service Options of the request; an SU ignores a grant whose options differ - transmit an SNDCP data page request received from the FNE and answer a "proceed" page response with a data channel grant - pass the first copy of each SNDCP grant to the network, so the FNE knows the SU has been directed to a data channel - read the SNDCP reconnect request as an ISP_SNDCP_REC_REQ, the class the factory builds for it * implement trunked SNDCP packet data in the FNE: activation ACK, SN-Data uplink and downlink, data paging and downlink retransmission; - send the link-layer ACK for the SNDCP context activation request - strip the SNDCP header from SN-Data received on the user data SAP and handle the IPv4 datagram as packet data - frame downlink datagrams as SN-Data for an SU with an SNDCP context - raise the standby timer in the context accept from 1 minute to 4 hours - page an SU that has left the data channel through the control channel that last granted it one, and hold the PDU until the grant is reported - retransmit a confirmed downlink the SU does not acknowledge, up to twice, with the same N(S) --------- Co-authored-by: David Andrzejewski <181952+dandrzejewski@users.noreply.github.com>pull/135/head
parent
080d4d5714
commit
50cf3b5e7e
@ -0,0 +1,86 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Digital Voice Modem - Common Library
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* Copyright (C) 2026 David Andrzejewski
|
||||
*
|
||||
*/
|
||||
#include "Defines.h"
|
||||
#include "p25/lc/tsbk/ISP_SNDCP_DATA_PAGE_RES.h"
|
||||
|
||||
using namespace p25;
|
||||
using namespace p25::defines;
|
||||
using namespace p25::lc;
|
||||
using namespace p25::lc::tsbk;
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* Initializes a new instance of the ISP_SNDCP_DATA_PAGE_RES class. */
|
||||
|
||||
ISP_SNDCP_DATA_PAGE_RES::ISP_SNDCP_DATA_PAGE_RES() : TSBK(),
|
||||
m_dataServiceOptions(0U),
|
||||
m_answerResponse(0U),
|
||||
m_dataAccessControl(0U)
|
||||
{
|
||||
m_lco = TSBKO::ISP_SNDCP_DATA_PAGE_RES;
|
||||
}
|
||||
|
||||
/* Decode a trunking signalling block. */
|
||||
|
||||
bool ISP_SNDCP_DATA_PAGE_RES::decode(const uint8_t* data, bool rawTSBK)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
uint8_t tsbk[P25_TSBK_LENGTH_BYTES + 1U];
|
||||
::memset(tsbk, 0x00U, P25_TSBK_LENGTH_BYTES);
|
||||
|
||||
bool ret = TSBK::decode(data, tsbk, rawTSBK);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
ulong64_t tsbkValue = TSBK::toValue(tsbk);
|
||||
|
||||
m_dataServiceOptions = (uint8_t)((tsbkValue >> 56) & 0xFFU); // Data Service Options
|
||||
m_answerResponse = (uint8_t)((tsbkValue >> 48) & 0xFFU); // Answer Response
|
||||
m_dataAccessControl = (uint16_t)((tsbkValue >> 32) & 0xFFFFU); // Data Access Control
|
||||
m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Encode a trunking signalling block. */
|
||||
|
||||
void ISP_SNDCP_DATA_PAGE_RES::encode(uint8_t* data, bool rawTSBK, bool noTrellis)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
/* stub -- inbound only; an SU sends this, the FNE and hosts never encode it */
|
||||
}
|
||||
|
||||
/* Returns a string that represents the current TSBK. */
|
||||
|
||||
std::string ISP_SNDCP_DATA_PAGE_RES::toString(bool isp)
|
||||
{
|
||||
return std::string("TSBKO, ISP_SNDCP_DATA_PAGE_RES (SNDCP Data Page Response)");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Private Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* Internal helper to copy the the class. */
|
||||
|
||||
void ISP_SNDCP_DATA_PAGE_RES::copy(const ISP_SNDCP_DATA_PAGE_RES& data)
|
||||
{
|
||||
TSBK::copy(data);
|
||||
|
||||
m_dataServiceOptions = data.m_dataServiceOptions;
|
||||
m_answerResponse = data.m_answerResponse;
|
||||
m_dataAccessControl = data.m_dataAccessControl;
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Digital Voice Modem - Common Library
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* Copyright (C) 2026 David Andrzejewski
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @file ISP_SNDCP_DATA_PAGE_RES.h
|
||||
* @ingroup p25_tsbk
|
||||
* @file ISP_SNDCP_DATA_PAGE_RES.cpp
|
||||
* @ingroup p25_tsbk
|
||||
*/
|
||||
#if !defined(__P25_LC_TSBK__ISP_SNDCP_DATA_PAGE_RES_H__)
|
||||
#define __P25_LC_TSBK__ISP_SNDCP_DATA_PAGE_RES_H__
|
||||
|
||||
#include "common/Defines.h"
|
||||
#include "common/p25/lc/TSBK.h"
|
||||
|
||||
namespace p25
|
||||
{
|
||||
namespace lc
|
||||
{
|
||||
namespace tsbk
|
||||
{
|
||||
// ---------------------------------------------------------------------------
|
||||
// Class Declaration
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Implements SNDCP DATA PAGE RES - SNDCP Data Page Response (ISP)
|
||||
* @ingroup p25_tsbk
|
||||
*/
|
||||
class DVM_COMMON_API ISP_SNDCP_DATA_PAGE_RES : public TSBK {
|
||||
public:
|
||||
/**
|
||||
* @brief Initializes a new instance of the ISP_SNDCP_DATA_PAGE_RES class.
|
||||
*/
|
||||
ISP_SNDCP_DATA_PAGE_RES();
|
||||
|
||||
/**
|
||||
* @brief Decode a trunking signalling block.
|
||||
* @param[in] data Buffer containing a TSBK to decode.
|
||||
* @param rawTSBK Flag indicating whether or not the passed buffer is raw.
|
||||
* @returns bool True, if TSBK decoded, otherwise false.
|
||||
*/
|
||||
bool decode(const uint8_t* data, bool rawTSBK = false) override;
|
||||
/**
|
||||
* @brief Encode a trunking signalling block.
|
||||
* @param[out] data Buffer to encode a TSBK.
|
||||
* @param rawTSBK Flag indicating whether or not the output buffer is raw.
|
||||
* @param noTrellis Flag indicating whether or not the encoded data should be Trellis encoded.
|
||||
*/
|
||||
void encode(uint8_t* data, bool rawTSBK = false, bool noTrellis = false) override;
|
||||
|
||||
/**
|
||||
* @brief Returns a string that represents the current TSBK.
|
||||
* @returns std::string String representation of the TSBK.
|
||||
*/
|
||||
std::string toString(bool isp = false) override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief SNDCP Data Service Options (the low nibble is the NSAPI)
|
||||
*/
|
||||
DECLARE_PROPERTY(uint8_t, dataServiceOptions, DataServiceOptions);
|
||||
/**
|
||||
* @brief Answer Response (proceed, deny or wait)
|
||||
*/
|
||||
DECLARE_PROPERTY(uint8_t, answerResponse, AnswerResponse);
|
||||
/**
|
||||
* @brief SNDCP Data Access Control
|
||||
*/
|
||||
DECLARE_PROPERTY(uint16_t, dataAccessControl, DataAccessControl);
|
||||
|
||||
DECLARE_COPY(ISP_SNDCP_DATA_PAGE_RES);
|
||||
};
|
||||
} // namespace tsbk
|
||||
} // namespace lc
|
||||
} // namespace p25
|
||||
|
||||
#endif // __P25_LC_TSBK__ISP_SNDCP_DATA_PAGE_RES_H__
|
||||
@ -0,0 +1,91 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Digital Voice Modem - Common Library
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* Copyright (C) 2026 David Andrzejewski
|
||||
*
|
||||
*/
|
||||
#include "Defines.h"
|
||||
#include "p25/lc/tsbk/OSP_SNDCP_DATA_PAGE_REQ.h"
|
||||
|
||||
using namespace p25;
|
||||
using namespace p25::defines;
|
||||
using namespace p25::lc;
|
||||
using namespace p25::lc::tsbk;
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* Initializes a new instance of the OSP_SNDCP_DATA_PAGE_REQ class. */
|
||||
|
||||
OSP_SNDCP_DATA_PAGE_REQ::OSP_SNDCP_DATA_PAGE_REQ() : TSBK(),
|
||||
m_dataServiceOptions(0U),
|
||||
m_dataAccessControl(1U)
|
||||
{
|
||||
m_lco = TSBKO::OSP_SNDCP_DATA_PAGE_REQ;
|
||||
}
|
||||
|
||||
/* Decode a trunking signalling block. */
|
||||
|
||||
bool OSP_SNDCP_DATA_PAGE_REQ::decode(const uint8_t* data, bool rawTSBK)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
uint8_t tsbk[P25_TSBK_LENGTH_BYTES + 1U];
|
||||
::memset(tsbk, 0x00U, P25_TSBK_LENGTH_BYTES);
|
||||
|
||||
bool ret = TSBK::decode(data, tsbk, rawTSBK);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
ulong64_t tsbkValue = TSBK::toValue(tsbk);
|
||||
|
||||
m_dataServiceOptions = (uint8_t)((tsbkValue >> 56) & 0xFFU); // Data Service Options
|
||||
m_dataAccessControl = (uint16_t)((tsbkValue >> 24) & 0xFFFFU); // Data Access Control
|
||||
m_dstId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Target Radio Address
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Encode a trunking signalling block. */
|
||||
|
||||
void OSP_SNDCP_DATA_PAGE_REQ::encode(uint8_t* data, bool rawTSBK, bool noTrellis)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
ulong64_t tsbkValue = 0U;
|
||||
|
||||
tsbkValue = m_dataServiceOptions; // Data Service Options
|
||||
tsbkValue = (tsbkValue << 16); // Reserved
|
||||
tsbkValue = (tsbkValue << 16) + m_dataAccessControl; // Data Access Control
|
||||
tsbkValue = (tsbkValue << 24) + m_dstId; // Target Radio Address
|
||||
|
||||
std::unique_ptr<uint8_t[]> tsbk = TSBK::fromValue(tsbkValue);
|
||||
TSBK::encode(data, tsbk.get(), rawTSBK, noTrellis);
|
||||
}
|
||||
|
||||
/* Returns a string that represents the current TSBK. */
|
||||
|
||||
std::string OSP_SNDCP_DATA_PAGE_REQ::toString(bool isp)
|
||||
{
|
||||
return std::string("TSBKO, OSP_SNDCP_DATA_PAGE_REQ (SNDCP Data Page Request)");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Private Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* Internal helper to copy the the class. */
|
||||
|
||||
void OSP_SNDCP_DATA_PAGE_REQ::copy(const OSP_SNDCP_DATA_PAGE_REQ& data)
|
||||
{
|
||||
TSBK::copy(data);
|
||||
|
||||
m_dataServiceOptions = data.m_dataServiceOptions;
|
||||
m_dataAccessControl = data.m_dataAccessControl;
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Digital Voice Modem - Common Library
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* Copyright (C) 2026 David Andrzejewski
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @file OSP_SNDCP_DATA_PAGE_REQ.h
|
||||
* @ingroup p25_tsbk
|
||||
* @file OSP_SNDCP_DATA_PAGE_REQ.cpp
|
||||
* @ingroup p25_tsbk
|
||||
*/
|
||||
#if !defined(__P25_LC_TSBK__OSP_SNDCP_DATA_PAGE_REQ_H__)
|
||||
#define __P25_LC_TSBK__OSP_SNDCP_DATA_PAGE_REQ_H__
|
||||
|
||||
#include "common/Defines.h"
|
||||
#include "common/p25/lc/TSBK.h"
|
||||
|
||||
namespace p25
|
||||
{
|
||||
namespace lc
|
||||
{
|
||||
namespace tsbk
|
||||
{
|
||||
// ---------------------------------------------------------------------------
|
||||
// Class Declaration
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Implements SNDCP DATA PAGE REQ - SNDCP Data Page Request (OSP)
|
||||
* @ingroup p25_tsbk
|
||||
*/
|
||||
class DVM_COMMON_API OSP_SNDCP_DATA_PAGE_REQ : public TSBK {
|
||||
public:
|
||||
/**
|
||||
* @brief Initializes a new instance of the OSP_SNDCP_DATA_PAGE_REQ class.
|
||||
*/
|
||||
OSP_SNDCP_DATA_PAGE_REQ();
|
||||
|
||||
/**
|
||||
* @brief Decode a trunking signalling block.
|
||||
* @param[in] data Buffer containing a TSBK to decode.
|
||||
* @param rawTSBK Flag indicating whether or not the passed buffer is raw.
|
||||
* @returns bool True, if TSBK decoded, otherwise false.
|
||||
*/
|
||||
bool decode(const uint8_t* data, bool rawTSBK = false) override;
|
||||
/**
|
||||
* @brief Encode a trunking signalling block.
|
||||
* @param[out] data Buffer to encode a TSBK.
|
||||
* @param rawTSBK Flag indicating whether or not the output buffer is raw.
|
||||
* @param noTrellis Flag indicating whether or not the encoded data should be Trellis encoded.
|
||||
*/
|
||||
void encode(uint8_t* data, bool rawTSBK = false, bool noTrellis = false) override;
|
||||
|
||||
/**
|
||||
* @brief Returns a string that represents the current TSBK.
|
||||
* @returns std::string String representation of the TSBK.
|
||||
*/
|
||||
std::string toString(bool isp = false) override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief SNDCP Data Service Options (the low nibble is the NSAPI)
|
||||
*/
|
||||
DECLARE_PROPERTY(uint8_t, dataServiceOptions, DataServiceOptions);
|
||||
/**
|
||||
* @brief SNDCP Data Access Control
|
||||
*/
|
||||
DECLARE_PROPERTY(uint16_t, dataAccessControl, DataAccessControl);
|
||||
|
||||
DECLARE_COPY(OSP_SNDCP_DATA_PAGE_REQ);
|
||||
};
|
||||
} // namespace tsbk
|
||||
} // namespace lc
|
||||
} // namespace p25
|
||||
|
||||
#endif // __P25_LC_TSBK__OSP_SNDCP_DATA_PAGE_REQ_H__
|
||||
Loading…
Reference in new issue