From 4cef6e5aea34d68964b50ae45278c1e45467521f Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Mon, 8 Aug 2022 20:04:36 -0400 Subject: [PATCH] rework the NXDN "Layer 3" class; --- Makefile | 3 +- network/BaseNetwork.cpp | 30 +-- network/BaseNetwork.h | 8 +- nxdn/Control.cpp | 22 +- nxdn/Control.h | 6 +- nxdn/NXDNDefines.h | 98 ++++--- nxdn/channel/FACCH1.cpp | 29 +- nxdn/channel/FACCH1.h | 13 +- nxdn/channel/LICH.cpp | 33 ++- nxdn/channel/LICH.h | 13 +- nxdn/channel/SACCH.cpp | 33 ++- nxdn/channel/SACCH.h | 13 +- nxdn/channel/UDCH.cpp | 31 ++- nxdn/channel/UDCH.h | 13 +- nxdn/data/Layer3.cpp | 222 ---------------- nxdn/data/Layer3.h | 95 ------- nxdn/lc/LC.cpp | 480 ++++++++++++++++++++++++++++++++++ nxdn/lc/LC.h | 142 ++++++++++ nxdn/lc/PacketInformation.cpp | 187 +++++++++++++ nxdn/lc/PacketInformation.h | 83 ++++++ nxdn/packet/Data.cpp | 67 +++-- nxdn/packet/Data.h | 2 +- nxdn/packet/Voice.cpp | 171 ++++++------ nxdn/packet/Voice.h | 2 +- 24 files changed, 1237 insertions(+), 559 deletions(-) delete mode 100644 nxdn/data/Layer3.cpp delete mode 100644 nxdn/data/Layer3.h create mode 100644 nxdn/lc/LC.cpp create mode 100644 nxdn/lc/LC.h create mode 100644 nxdn/lc/PacketInformation.cpp create mode 100644 nxdn/lc/PacketInformation.h diff --git a/Makefile b/Makefile index eb6fb659..1db893d0 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,8 @@ HOST_OBJECTS = \ nxdn/channel/LICH.o \ nxdn/channel/SACCH.o \ nxdn/channel/UDCH.o \ - nxdn/data/Layer3.o \ + nxdn/lc/LC.o \ + nxdn/lc/PacketInformation.o \ nxdn/packet/Data.o \ nxdn/packet/Voice.o \ nxdn/Audio.o \ diff --git a/network/BaseNetwork.cpp b/network/BaseNetwork.cpp index 8df9c56e..b560edef 100644 --- a/network/BaseNetwork.cpp +++ b/network/BaseNetwork.cpp @@ -258,10 +258,10 @@ uint8_t* BaseNetwork::readP25(bool& ret, p25::lc::LC& control, p25::data::LowSpe /// Reads NXDN frame data from the NXDN ring buffer. /// /// -/// +/// /// /// -uint8_t* BaseNetwork::readNXDN(bool& ret, nxdn::data::Layer3& layer3, uint32_t& len) +uint8_t* BaseNetwork::readNXDN(bool& ret, nxdn::lc::LC& lc, uint32_t& len) { if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING) { ret = false; @@ -283,12 +283,12 @@ uint8_t* BaseNetwork::readNXDN(bool& ret, nxdn::data::Layer3& layer3, uint32_t& uint32_t dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); - layer3.setMessageType(messageType); - layer3.setSrcId((uint16_t)srcId & 0xFFFFU); - layer3.setDstId((uint16_t)dstId & 0xFFFFU); + lc.setMessageType(messageType); + lc.setSrcId((uint16_t)srcId & 0xFFFFU); + lc.setDstId((uint16_t)dstId & 0xFFFFU); bool group = (m_buffer[15U] & 0x40U) == 0x40U ? false : true; - layer3.setGroup(group); + lc.setGroup(group); uint8_t* data = NULL; len = m_buffer[23U]; @@ -483,11 +483,11 @@ bool BaseNetwork::writeP25PDU(const p25::data::DataHeader& header, const p25::da /// /// Writes NXDN frame data to the network. /// -/// +/// /// /// /// -bool BaseNetwork::writeNXDN(const nxdn::data::Layer3& layer3, const uint8_t* data, const uint32_t len) +bool BaseNetwork::writeNXDN(const nxdn::lc::LC& lc, const uint8_t* data, const uint32_t len) { if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING) return false; @@ -498,7 +498,7 @@ bool BaseNetwork::writeNXDN(const nxdn::data::Layer3& layer3, const uint8_t* dat m_streamId[0] = m_nxdnStreamId; - return writeNXDN(m_id, m_nxdnStreamId, layer3, data, len); + return writeNXDN(m_id, m_nxdnStreamId, lc, data, len); } /// @@ -1082,11 +1082,11 @@ bool BaseNetwork::writeP25PDU(const uint32_t id, const uint32_t streamId, const /// /// /// -/// +/// /// /// /// -bool BaseNetwork::writeNXDN(const uint32_t id, const uint32_t streamId, const nxdn::data::Layer3& layer3, const uint8_t* data, const uint32_t len) +bool BaseNetwork::writeNXDN(const uint32_t id, const uint32_t streamId, const nxdn::lc::LC& lc, const uint8_t* data, const uint32_t len) { if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING) return false; @@ -1098,15 +1098,15 @@ bool BaseNetwork::writeNXDN(const uint32_t id, const uint32_t streamId, const nx ::memcpy(buffer + 0U, TAG_NXDN_DATA, 4U); - buffer[4U] = layer3.getMessageType(); // Message Type + buffer[4U] = lc.getMessageType(); // Message Type - uint32_t srcId = layer3.getSrcId(); // Source Address + uint32_t srcId = lc.getSrcId(); // Source Address __SET_UINT16(srcId, buffer, 5U); - uint32_t dstId = layer3.getDstId(); // Target Address + uint32_t dstId = lc.getDstId(); // Target Address __SET_UINT16(dstId, buffer, 8U); - buffer[15U] |= layer3.getGroup() ? 0x00U : 0x40U; // Group + buffer[15U] |= lc.getGroup() ? 0x00U : 0x40U; // Group __SET_UINT32(streamId, buffer, 16U); // Stream ID diff --git a/network/BaseNetwork.h b/network/BaseNetwork.h index 1915f3bb..52b2bec6 100644 --- a/network/BaseNetwork.h +++ b/network/BaseNetwork.h @@ -43,7 +43,7 @@ #include "p25/lc/TSBK.h" #include "p25/lc/TDULC.h" #include "p25/Audio.h" -#include "nxdn/data/Layer3.h" +#include "nxdn/lc/LC.h" #include "network/UDPSocket.h" #include "RingBuffer.h" #include "Timer.h" @@ -141,7 +141,7 @@ namespace network /// Reads P25 frame data from the P25 ring buffer. virtual uint8_t* readP25(bool& ret, p25::lc::LC& control, p25::data::LowSpeedData& lsd, uint8_t& duid, uint32_t& len); /// Reads NXDN frame data from the NXDN ring buffer. - virtual uint8_t* readNXDN(bool& ret, nxdn::data::Layer3& layer3, uint32_t& len); + virtual uint8_t* readNXDN(bool& ret, nxdn::lc::LC& lc, uint32_t& len); /// Reads a channel grant request from the network. virtual bool readGrantRsp(bool& grp, uint32_t& srcId, uint32_t& dstId, uint32_t& grpVchNo); @@ -161,7 +161,7 @@ namespace network const uint8_t* data, const uint32_t len); /// Writes NXDN frame data to the network. - virtual bool writeNXDN(const nxdn::data::Layer3& layer3, const uint8_t* data, const uint32_t len); + virtual bool writeNXDN(const nxdn::lc::LC& lc, const uint8_t* data, const uint32_t len); /// Writes a channel grant request to the network. virtual bool writeGrantReq(const bool grp, const uint32_t srcId, const uint32_t dstId); @@ -240,7 +240,7 @@ namespace network bool writeP25PDU(const uint32_t id, const uint32_t streamId, const p25::data::DataHeader& header, const p25::data::DataHeader& secHeader, const uint8_t currentBlock, const uint8_t* data, const uint32_t len); /// Writes NXDN frame data to the network. - bool writeNXDN(const uint32_t id, const uint32_t streamId, const nxdn::data::Layer3& layer3, const uint8_t* data, const uint32_t len); + bool writeNXDN(const uint32_t id, const uint32_t streamId, const nxdn::lc::LC& layer3, const uint8_t* data, const uint32_t len); /// Writes data to the network. virtual bool write(const uint8_t* data, uint32_t length); diff --git a/nxdn/Control.cpp b/nxdn/Control.cpp index c81a2882..1bd8e265 100644 --- a/nxdn/Control.cpp +++ b/nxdn/Control.cpp @@ -93,8 +93,8 @@ Control::Control(uint32_t ran, uint32_t callHang, uint32_t queueSize, uint32_t t m_network(network), m_duplex(duplex), m_rfLastLICH(), - m_rfLayer3(), - m_netLayer3(), + m_rfLC(), + m_netLC(), m_rfMask(0U), m_netMask(0U), m_idenTable(idenTable), @@ -162,12 +162,12 @@ void Control::reset() m_queue.clear(); m_rfMask = 0x00U; - m_rfLayer3.reset(); + m_rfLC.reset(); m_netState = RS_NET_IDLE; m_netMask = 0x00U; - m_netLayer3.reset(); + m_netLC.reset(); } /// @@ -251,7 +251,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len) if (type == modem::TAG_LOST) { m_rfState = RS_RF_LISTENING; m_rfMask = 0x00U; - m_rfLayer3.reset(); + m_rfLC.reset(); return false; } @@ -463,11 +463,11 @@ void Control::processNetwork() if (m_rfState != RS_RF_LISTENING && m_netState == RS_NET_IDLE) return; - data::Layer3 layer3; + lc::LC lc; uint32_t length = 100U; bool ret = false; - uint8_t* data = m_network->readNXDN(ret, layer3, length); + uint8_t* data = m_network->readNXDN(ret, lc, length); if (!ret) return; if (length == 0U) @@ -496,10 +496,10 @@ void Control::processNetwork() switch (usc) { case NXDN_LICH_USC_UDCH: - ret = m_data->processNetwork(option, layer3, data, length); + ret = m_data->processNetwork(option, lc, data, length); break; default: - ret = m_voice->processNetwork(usc, option, layer3, data, length); + ret = m_voice->processNetwork(usc, option, lc, data, length); break; } @@ -514,7 +514,7 @@ void Control::writeEndRF() m_rfState = RS_RF_LISTENING; m_rfMask = 0x00U; - m_rfLayer3.reset(); + m_rfLC.reset(); m_rfTimeout.stop(); } @@ -527,7 +527,7 @@ void Control::writeEndNet() m_netState = RS_NET_IDLE; m_netMask = 0x00U; - m_netLayer3.reset(); + m_netLC.reset(); m_netTimeout.stop(); m_networkWatchdog.stop(); diff --git a/nxdn/Control.h b/nxdn/Control.h index 70a2c32f..63eb2688 100644 --- a/nxdn/Control.h +++ b/nxdn/Control.h @@ -34,7 +34,7 @@ #include "Defines.h" #include "nxdn/NXDNDefines.h" #include "nxdn/channel/LICH.h" -#include "nxdn/data/Layer3.h" +#include "nxdn/lc/LC.h" #include "nxdn/packet/Voice.h" #include "nxdn/packet/Data.h" #include "network/BaseNetwork.h" @@ -111,8 +111,8 @@ namespace nxdn bool m_duplex; channel::LICH m_rfLastLICH; - data::Layer3 m_rfLayer3; - data::Layer3 m_netLayer3; + lc::LC m_rfLC; + lc::LC m_netLC; uint8_t m_rfMask; uint8_t m_netMask; diff --git a/nxdn/NXDNDefines.h b/nxdn/NXDNDefines.h index d24b6ca2..a23d2743 100644 --- a/nxdn/NXDNDefines.h +++ b/nxdn/NXDNDefines.h @@ -91,44 +91,74 @@ namespace nxdn const uint8_t NXDN_SR_2_4 = 2U; const uint8_t NXDN_SR_1_4 = 3U; + const uint8_t SACCH_IDLE[] = { 0x10U, 0x00U, 0x00U }; + const uint32_t DEFAULT_SILENCE_THRESHOLD = 14U; const uint32_t MAX_NXDN_VOICE_ERRORS = 144U; const uint32_t MAX_NXDN_VOICE_ERRORS_STEAL = 94U; - // Message Types - const uint8_t MESSAGE_TYPE_VCALL = 0x01U; - const uint8_t MESSAGE_TYPE_VCALL_IV = 0x03U; - const uint8_t MESSAGE_TYPE_DCALL_HDR = 0x09U; - const uint8_t MESSAGE_TYPE_DCALL_DATA = 0x0BU; - const uint8_t MESSAGE_TYPE_DCALL_ACK = 0x0CU; - const uint8_t MESSAGE_TYPE_TX_REL = 0x08U; - const uint8_t MESSAGE_TYPE_HEAD_DLY = 0x0FU; - const uint8_t MESSAGE_TYPE_SDCALL_REQ_HDR = 0x38U; - const uint8_t MESSAGE_TYPE_SDCALL_REQ_DATA = 0x39U; - const uint8_t MESSAGE_TYPE_SDCALL_RESP = 0x3BU; - const uint8_t MESSAGE_TYPE_SDCALL_IV = 0x3AU; - const uint8_t MESSAGE_TYPE_STAT_INQ_REQ = 0x30U; - const uint8_t MESSAGE_TYPE_STAT_INQ_RESP = 0x31U; - const uint8_t MESSAGE_TYPE_STAT_REQ = 0x32U; - const uint8_t MESSAGE_TYPE_STAT_RESP = 0x33U; - const uint8_t MESSAGE_TYPE_REM_CON_REQ = 0x34U; - const uint8_t MESSAGE_TYPE_REM_CON_RESP = 0x35U; - const uint8_t MESSAGE_TYPE_IDLE = 0x10U; - const uint8_t MESSAGE_TYPE_AUTH_INQ_REQ = 0x28U; - const uint8_t MESSAGE_TYPE_AUTH_INQ_RESP = 0x29U; - const uint8_t MESSAGE_TYPE_PROP_FORM = 0x3FU; - - // Voice Call Options - const uint8_t VOICE_CALL_OPTION_HALF_DUPLEX = 0x00U; - const uint8_t VOICE_CALL_OPTION_DUPLEX = 0x10U; - - // Data Call Options - const uint8_t DATA_CALL_OPTION_HALF_DUPLEX = 0x00U; - const uint8_t DATA_CALL_OPTION_DUPLEX = 0x10U; - const uint8_t DATA_CALL_OPTION_4800 = 0x00U; - const uint8_t DATA_CALL_OPTION_9600 = 0x02U; - - const uint8_t SACCH_IDLE[] = { MESSAGE_TYPE_IDLE, 0x00U, 0x00U }; + const uint32_t NXDN_MI_LENGTH_BYTES = 8U; + const uint32_t NXDN_PCKT_INFO_LENGTH_BYTES = 3U; + + const uint8_t NXDN_CIPHER_TYPE_NONE = 0x00U; + + const uint8_t DATA_RSP_CLASS_ACK = 0x00U; + const uint8_t DATA_RSP_CLASS_ACK_S = 0x01U; + const uint8_t DATA_RSP_CLASS_NACK = 0x03U; + + const uint8_t NXDN_CAUSE_RESOURCE_NOT_AVAIL = 0x05U; + const uint8_t NXDN_CAUSE_SVC_UNAVAILABLE = 0x06U; + const uint8_t NXDN_CAUSE_PROC_ERROR = 0x07U; + + const uint8_t NXDN_CAUSE_MM_NORMAL_1 = 0x01U; + const uint8_t NXDN_CAUSE_MM_NORMAL_2 = 0x04U; + + const uint8_t NXDN_CAUSE_VD_NORMAL_1 = 0x01U; + const uint8_t NXDN_CAUSE_VD_NORMAL_2 = 0x02U; + const uint8_t NXDN_CAUSE_VD_QUEUED = 0x03U; + + const uint8_t NXDN_CAUSE_SS_NORMAL = 0x00U; + const uint8_t NXDN_CAUSE_SS_NORMAL_1 = 0x01U; + const uint8_t NXDN_CAUSE_SS_NORMAL_2 = 0x02U; + + const uint8_t NXDN_CAUSE_DREQ_NORMAL = 0x01U; + + const uint8_t NXDN_CAUSE_DISC_NORMAL = 0x01U; + const uint8_t NXDN_CAUSE_DISC_NORMAL_TC = 0x02U; + + // Common Message Types + const uint8_t MESSAGE_TYPE_IDLE = 0x10U; // IDLE - Idle + + // Traffic Channel Message Types + const uint8_t RTCH_MESSAGE_TYPE_VCALL = 0x01U; // VCALL - Voice Call + const uint8_t RTCH_MESSAGE_TYPE_VCALL_IV = 0x03U; // VCALL_IV - Voice Call Initialization Vector + const uint8_t RTCH_MESSAGE_TYPE_TX_REL_EX = 0x07U; // TX_REL_EX - Transmission Release Extension + const uint8_t RTCH_MESSAGE_TYPE_TX_REL = 0x08U; // TX_REL - Transmission Release + const uint8_t RTCH_MESSAGE_TYPE_DCALL_HDR = 0x09U; // DCALL - Data Call (Header) + const uint8_t RTCH_MESSAGE_TYPE_DCALL_DATA = 0x0BU; // DCALL - Data Call (User Data Format) + const uint8_t RTCH_MESSAGE_TYPE_DCALL_ACK = 0x0CU; // DCALL_ACK - Data Call Acknowledge + const uint8_t RTCH_MESSAGE_TYPE_HEAD_DLY = 0x0FU; // HEAD_DLY - Header Delay + const uint8_t RTCH_MESSAGE_TYPE_SDCALL_REQ_HDR = 0x38U; // SDCALL_REQ - Short Data Call Request (Header) + const uint8_t RTCH_MESSAGE_TYPE_SDCALL_REQ_DATA = 0x39U; // SDCALL_REQ - Short Data Call Request (User Data Format) + const uint8_t RTCH_MESSAGE_TYPE_SDCALL_IV = 0x3AU; // SDCALL_IV - Short Data Call Initialization Vector + const uint8_t RTCH_MESSAGE_TYPE_SDCALL_RESP = 0x3BU; // SDCALL_RESP - Short Data Call Response + + // Control Channel Message Types + const uint8_t RCCH_MESSAGE_TYPE_PROP_FORM = 0x3FU; // PROP_FORM - Proprietary Form + + // Call Types + const uint8_t CALL_TYPE_BROADCAST = 0x00U; + const uint8_t CALL_TYPE_CONFERENCE = 0x01U; + const uint8_t CALL_TYPE_UNSPECIFIED = 0x02U; + const uint8_t CALL_TYPE_INDIVIDUAL = 0x04U; + const uint8_t CALL_TYPE_INTERCONNECT = 0x06U; + const uint8_t CALL_TYPE_SPEED_DIAL = 0x07U; + + // Transmission Mode + const uint8_t TRANSMISSION_MODE_4800 = 0x00U; + const uint8_t TRANSMISSION_MODE_9600 = 0x02U; + const uint8_t TRANSMISSION_MODE_9600_EFR = 0x03U; // should never be used on data calls + } // namespace nxdn #endif // __NXDN_DEFINES_H__ diff --git a/nxdn/channel/FACCH1.cpp b/nxdn/channel/FACCH1.cpp index 80a5664c..4d79d9dd 100644 --- a/nxdn/channel/FACCH1.cpp +++ b/nxdn/channel/FACCH1.cpp @@ -69,25 +69,24 @@ const uint32_t PUNCTURE_LIST[] = { // --------------------------------------------------------------------------- /// -/// Initializes a copy instance of the FACCH1 class. +/// Initializes a new instance of the FACCH1 class. /// -/// -FACCH1::FACCH1(const FACCH1& data) : +FACCH1::FACCH1() : m_verbose(false), m_data(NULL) { m_data = new uint8_t[12U]; - ::memcpy(m_data, data.m_data, 12U); } /// -/// Initializes a new instance of the FACCH1 class. +/// Initializes a copy instance of the FACCH1 class. /// -FACCH1::FACCH1() : +/// +FACCH1::FACCH1(const FACCH1& data) : m_verbose(false), m_data(NULL) { - m_data = new uint8_t[12U]; + copy(data); } /// @@ -254,3 +253,19 @@ void FACCH1::setData(const uint8_t* data) ::memcpy(m_data, data, 10U); } + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +/// +/// Internal helper to copy the the class. +/// +/// +void FACCH1::copy(const FACCH1& data) +{ + m_data = new uint8_t[12U]; + ::memcpy(m_data, data.m_data, 12U); + + m_verbose = data.m_verbose; +} diff --git a/nxdn/channel/FACCH1.h b/nxdn/channel/FACCH1.h index c2f95a0d..64683b56 100644 --- a/nxdn/channel/FACCH1.h +++ b/nxdn/channel/FACCH1.h @@ -27,8 +27,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined(__NXDN_FACCH1_H__) -#define __NXDN_FACCH1_H__ +#if !defined(__NXDN_CHANNEL__FACCH1_H__) +#define __NXDN_CHANNEL__FACCH1_H__ #include "Defines.h" @@ -43,10 +43,10 @@ namespace nxdn class HOST_SW_API FACCH1 { public: - /// Initializes a copy instance of the FACCH1 class. - FACCH1(const FACCH1& data); /// Initializes a new instance of the FACCH1 class. FACCH1(); + /// Initializes a copy instance of the FACCH1 class. + FACCH1(const FACCH1& data); /// Finalizes a instance of the FACCH1 class. ~FACCH1(); @@ -69,8 +69,11 @@ namespace nxdn private: uint8_t* m_data; + + /// Internal helper to copy the class. + void copy(const FACCH1& data); }; } // namespace channel } // namespace nxdn -#endif // __NXDN_FACCH1_H__ +#endif // __NXDN_CHANNEL__FACCH1_H__ diff --git a/nxdn/channel/LICH.cpp b/nxdn/channel/LICH.cpp index cb0b017a..7be5b6e0 100644 --- a/nxdn/channel/LICH.cpp +++ b/nxdn/channel/LICH.cpp @@ -43,10 +43,9 @@ using namespace nxdn::channel; // --------------------------------------------------------------------------- /// -/// Initializes a copy instance of the LICH class. +/// Initializes a new instance of the LICH class. /// -/// -LICH::LICH(const LICH& data) : +LICH::LICH() : m_rfct(NXDN_LICH_RFCT_RCCH), m_fct(NXDN_LICH_USC_SACCH_NS), m_option(0U), @@ -54,25 +53,20 @@ LICH::LICH(const LICH& data) : m_data(NULL) { m_data = new uint8_t[1U]; - m_data[0U] = data.m_data[0U]; - - m_rfct = (m_data[0U] >> 6) & 0x03U; - m_fct = (m_data[0U] >> 4) & 0x03U; - m_option = (m_data[0U] >> 2) & 0x03U; - m_direction = (m_data[0U] >> 1) & 0x01U; } /// -/// Initializes a new instance of the LICH class. +/// Initializes a copy instance of the LICH class. /// -LICH::LICH() : +/// +LICH::LICH(const LICH& data) : m_rfct(NXDN_LICH_RFCT_RCCH), m_fct(NXDN_LICH_USC_SACCH_NS), m_option(0U), m_direction(NXDN_LICH_DIRECTION_OUTBOUND), m_data(NULL) { - m_data = new uint8_t[1U]; + copy(data); } /// @@ -168,6 +162,21 @@ void LICH::encode(uint8_t* data) // Private Class Members // --------------------------------------------------------------------------- +/// +/// Internal helper to copy the the class. +/// +/// +void LICH::copy(const LICH& data) +{ + m_data = new uint8_t[1U]; + m_data[0U] = data.m_data[0U]; + + m_rfct = (m_data[0U] >> 6) & 0x03U; + m_fct = (m_data[0U] >> 4) & 0x03U; + m_option = (m_data[0U] >> 2) & 0x03U; + m_direction = (m_data[0U] >> 1) & 0x01U; +} + /// /// /// diff --git a/nxdn/channel/LICH.h b/nxdn/channel/LICH.h index 5de73146..72b877c5 100644 --- a/nxdn/channel/LICH.h +++ b/nxdn/channel/LICH.h @@ -28,8 +28,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined(__NXDN_LICH_H__) -#define __NXDN_LICH_H__ +#if !defined(__NXDN_CHANNEL__LICH_H__) +#define __NXDN_CHANNEL__LICH_H__ #include "Defines.h" @@ -44,10 +44,10 @@ namespace nxdn class HOST_SW_API LICH { public: - /// Initializes a copy instance of the LICH class. - LICH(const LICH& lich); /// Initializes a new instance of the LICH class. LICH(); + /// Initializes a copy instance of the LICH class. + LICH(const LICH& lich); /// Finalizes a instance of the LICH class. ~LICH(); @@ -73,10 +73,13 @@ namespace nxdn private: uint8_t* m_data; + /// Internal helper to copy the class. + void copy(const LICH& data); + /// bool getParity() const; }; } // namespace channel } // namespace nxdn -#endif // __NXDN_LICH_H__ +#endif // __NXDN_CHANNEL__LICH_H__ diff --git a/nxdn/channel/SACCH.cpp b/nxdn/channel/SACCH.cpp index c8a75597..d79d2cc3 100644 --- a/nxdn/channel/SACCH.cpp +++ b/nxdn/channel/SACCH.cpp @@ -62,32 +62,28 @@ const uint32_t PUNCTURE_LIST[] = { 5U, 11U, 17U, 23U, 29U, 35U, 41U, 47U, 53U, 5 // --------------------------------------------------------------------------- /// -/// Initializes a copy instance of the SACCH class. +/// Initializes a new instance of the SACCH class. /// -/// -SACCH::SACCH(const SACCH& data) : +SACCH::SACCH() : m_verbose(false), m_ran(0U), m_structure(0U), m_data(NULL) { m_data = new uint8_t[5U]; - ::memcpy(m_data, data.m_data, 5U); - - m_ran = m_data[0U] & 0x3FU; - m_structure = (m_data[0U] >> 6) & 0x03U; } /// -/// Initializes a new instance of the SACCH class. +/// Initializes a copy instance of the SACCH class. /// -SACCH::SACCH() : +/// +SACCH::SACCH(const SACCH& data) : m_verbose(false), m_ran(0U), m_structure(0U), m_data(NULL) { - m_data = new uint8_t[5U]; + copy(data); } /// @@ -280,3 +276,20 @@ void SACCH::setData(const uint8_t* data) m_ran = m_data[0U] & 0x3FU; m_structure = (m_data[0U] >> 6) & 0x03U; } + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +/// +/// Internal helper to copy the the class. +/// +/// +void SACCH::copy(const SACCH& data) +{ + m_data = new uint8_t[5U]; + ::memcpy(m_data, data.m_data, 5U); + + m_ran = m_data[0U] & 0x3FU; + m_structure = (m_data[0U] >> 6) & 0x03U; +} diff --git a/nxdn/channel/SACCH.h b/nxdn/channel/SACCH.h index 9212d8e7..62640ac0 100644 --- a/nxdn/channel/SACCH.h +++ b/nxdn/channel/SACCH.h @@ -28,8 +28,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined(__NXDN_SACCH_H__) -#define __NXDN_SACCH_H__ +#if !defined(__NXDN_CHANNEL__SACCH_H__) +#define __NXDN_CHANNEL__SACCH_H__ #include "Defines.h" @@ -44,10 +44,10 @@ namespace nxdn class HOST_SW_API SACCH { public: - /// Initializes a copy instance of the SACCH class. - SACCH(const SACCH& data); /// Initializes a new instance of the SACCH class. SACCH(); + /// Initializes a copy instance of the SACCH class. + SACCH(const SACCH& data); /// Finalizes a instance of the SACCH class. ~SACCH(); @@ -76,8 +76,11 @@ namespace nxdn private: uint8_t* m_data; + + /// Internal helper to copy the class. + void copy(const SACCH& data); }; } // namespace channel } // namespace nxdn -#endif // __NXDN_SACCH_H__ +#endif // __NXDN_CHANNEL__SACCH_H__ diff --git a/nxdn/channel/UDCH.cpp b/nxdn/channel/UDCH.cpp index ae89795f..b498c7e6 100644 --- a/nxdn/channel/UDCH.cpp +++ b/nxdn/channel/UDCH.cpp @@ -91,29 +91,26 @@ const uint32_t PUNCTURE_LIST[] = { // --------------------------------------------------------------------------- /// -/// Initializes a copy instance of the UDCH class. +/// Initializes a new instance of the UDCH class. /// -/// -UDCH::UDCH(const UDCH& data) : +UDCH::UDCH() : m_verbose(false), m_ran(0U), m_data(NULL) { m_data = new uint8_t[26U]; - ::memcpy(m_data, data.m_data, 26U); - - m_ran = m_data[0U] & 0x3FU; } /// -/// Initializes a new instance of the UDCH class. +/// Initializes a copy instance of the UDCH class. /// -UDCH::UDCH() : +/// +UDCH::UDCH(const UDCH& data) : m_verbose(false), m_ran(0U), m_data(NULL) { - m_data = new uint8_t[26U]; + copy(data); } /// @@ -287,3 +284,19 @@ void UDCH::setData(const uint8_t* data) m_ran = m_data[0U] & 0x3FU; } + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +/// +/// Internal helper to copy the the class. +/// +/// +void UDCH::copy(const UDCH& data) +{ + m_data = new uint8_t[26U]; + ::memcpy(m_data, data.m_data, 26U); + + m_ran = m_data[0U] & 0x3FU; +} diff --git a/nxdn/channel/UDCH.h b/nxdn/channel/UDCH.h index cc65c5e5..26c7e2d3 100644 --- a/nxdn/channel/UDCH.h +++ b/nxdn/channel/UDCH.h @@ -28,8 +28,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined(__NXDN_UDCH_H__) -#define __NXDN_UDCH_H__ +#if !defined(__NXDN_CHANNEL__UDCH_H__) +#define __NXDN_CHANNEL__UDCH_H__ #include "Defines.h" @@ -44,10 +44,10 @@ namespace nxdn class HOST_SW_API UDCH { public: - /// Initializes a copy instance of the UDCH class. - UDCH(const UDCH& data); /// Initializes a new instance of the UDCH class. UDCH(); + /// Initializes a copy instance of the UDCH class. + UDCH(const UDCH& data); /// Finalizes a instance of the UDCH class. ~UDCH(); @@ -74,8 +74,11 @@ namespace nxdn private: uint8_t* m_data; + + /// Internal helper to copy the class. + void copy(const UDCH& data); }; } // namespace channel } // namespace nxdn -#endif // __NXDN_UDCH_H__ +#endif // __NXDN_CHANNEL__UDCH_H__ diff --git a/nxdn/data/Layer3.cpp b/nxdn/data/Layer3.cpp deleted file mode 100644 index 9a71cc20..00000000 --- a/nxdn/data/Layer3.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/** -* Digital Voice Modem - Host Software -* GPLv2 Open Source. Use is subject to license terms. -* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -* -* @package DVM / Host Software -* -*/ -// -// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) -// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) -// -/* -* Copyright (C) 2018 by Jonathan Naylor G4KLX -* Copyright (C) 2022 by Bryan Biedenkapp N2PLL -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -#include "nxdn/NXDNDefines.h" -#include "nxdn/data/Layer3.h" -#include "Utils.h" - -using namespace nxdn; -using namespace nxdn::data; - -#include -#include -#include - -// --------------------------------------------------------------------------- -// Public Class Members -// --------------------------------------------------------------------------- - -/// -/// Initializes a copy instance of the Layer3 class. -/// -/// -Layer3::Layer3(const Layer3& data) : - m_verbose(false), - m_messageType(MESSAGE_TYPE_IDLE), - m_srcId(0U), - m_dstId(0U), - m_group(true), - m_dataBlocks(0U), - m_data(NULL) -{ - m_data = new uint8_t[22U]; - ::memcpy(m_data, data.m_data, 22U); - - m_messageType = m_data[0U] & 0x3FU; // Message Type - - m_group = (m_data[2U] & 0x80U) != 0x80U; - - m_srcId = (m_data[3U] << 8) | m_data[4U]; // Source Radio Address - m_dstId = (m_data[5U] << 8) | m_data[6U]; // Target Radio Address - - m_dataBlocks = (m_data[8U] & 0x0FU) + 1U; // Data Blocks -} - -/// -/// Initializes a new instance of the Layer3 class. -/// -Layer3::Layer3() : - m_verbose(false), - m_messageType(MESSAGE_TYPE_IDLE), - m_srcId(0U), - m_dstId(0U), - m_group(true), - m_dataBlocks(0U), - m_data(NULL) -{ - m_data = new uint8_t[22U]; - ::memset(m_data, 0x00U, 22U); -} - -/// -/// Finalizes a instance of Layer3 class. -/// -Layer3::~Layer3() -{ - delete[] m_data; -} - -/// -/// Equals operator. -/// -/// -/// -Layer3& Layer3::operator=(const Layer3& data) -{ - if (&data != this) { - ::memcpy(m_data, data.m_data, 22U); - - m_verbose = data.m_verbose; - - m_messageType = data.m_messageType; - - m_group = data.m_group; - - m_srcId = data.m_srcId; - m_dstId = data.m_dstId; - - m_dataBlocks = m_dataBlocks; - } - - return *this; -} - -/// -/// Decode layer 3 data. -/// -/// -/// True, if SACCH was decoded, otherwise false. -void Layer3::decode(const uint8_t* data, uint32_t length, uint32_t offset) -{ - assert(data != NULL); - - for (uint32_t i = 0U; i < length; i++, offset++) { - bool b = READ_BIT(data, i); - WRITE_BIT(m_data, offset, b); - } - - if (m_verbose) { - Utils::dump(2U, "Decoded Layer 3 Data", m_data, 22U); - } - - m_messageType = m_data[0U] & 0x3FU; // Message Type - - m_group = (m_data[2U] & 0x80U) != 0x80U; - - m_srcId = (m_data[3U] << 8) | m_data[4U]; // Source Radio Address - m_dstId = (m_data[5U] << 8) | m_data[6U]; // Target Radio Address - - m_dataBlocks = (m_data[8U] & 0x0FU) + 1U; // Data Blocks -} - -/// -/// Encode layer 3 data. -/// -/// -void Layer3::encode(uint8_t* data, uint32_t length, uint32_t offset) -{ - assert(data != NULL); - - m_data[0U] = m_messageType & 0x3FU; // Message Type - - m_data[2U] = (m_group ? 0x80U : 0x00U); - - m_data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address - m_data[4U] = (m_srcId >> 0U) & 0xFFU; // ... - m_data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address - m_data[6U] = (m_dstId >> 0U) & 0xFFU; // ... - - m_data[8U] = m_dataBlocks & 0x0FU; // Data Blocks - - for (uint32_t i = 0U; i < length; i++, offset++) { - bool b = READ_BIT(m_data, offset); - WRITE_BIT(data, i, b); - } - - if (m_verbose) { - Utils::dump(2U, "Encoded Layer 3 Data", data, length); - } -} - -/// -/// -/// -void Layer3::reset() -{ - ::memset(m_data, 0x00U, 22U); - - m_messageType = MESSAGE_TYPE_IDLE; - - m_srcId = 0U; - m_dstId = 0U; - - m_group = true; - - m_dataBlocks = 0U; -} - -/// -/// Gets the raw layer 3 data. -/// -/// -void Layer3::getData(uint8_t* data) const -{ - ::memcpy(data, m_data, 22U); -} - -/// -/// Sets the raw layer 3 data. -/// -/// -/// -void Layer3::setData(const uint8_t* data, uint32_t length) -{ - ::memset(m_data, 0x00U, 22U); - ::memcpy(m_data, data, length); - - m_messageType = m_data[0U] & 0x3FU; - - m_group = (m_data[2U] & 0x80U) != 0x80U; - - m_srcId = (m_data[3U] << 8) | m_data[4U]; - m_dstId = (m_data[5U] << 8) | m_data[6U]; - - m_dataBlocks = (m_data[8U] & 0x0FU) + 1U; -} diff --git a/nxdn/data/Layer3.h b/nxdn/data/Layer3.h deleted file mode 100644 index 19cf7caf..00000000 --- a/nxdn/data/Layer3.h +++ /dev/null @@ -1,95 +0,0 @@ -/** -* Digital Voice Modem - Host Software -* GPLv2 Open Source. Use is subject to license terms. -* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -* -* @package DVM / Host Software -* -*/ -// -// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) -// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) -// -/* -* Copyright (C) 2018 by Jonathan Naylor G4KLX -* Copyright (C) 2022 by Bryan Biedenkapp N2PLL -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -#if !defined(__NXDN_LAYER_3_H__) -#define __NXDN_LAYER_3_H__ - -#include "Defines.h" - -namespace nxdn -{ - namespace data - { - // --------------------------------------------------------------------------- - // Class Declaration - // Implements NXDN Layer 3 Connection Control. - // --------------------------------------------------------------------------- - - class HOST_SW_API Layer3 { - public: - /// Initializes a copy instance of the Layer3 class. - Layer3(const Layer3& data); - /// Initializes a new instance of the Layer3 class. - Layer3(); - /// Finalizes a instance of the Layer3 class. - ~Layer3(); - - /// Equals operator. - Layer3& operator=(const Layer3& data); - - /// Decode layer 3 data. - void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U); - /// Encode layer 3 data. - void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U); - - /// - void reset(); - - /// Gets the raw layer 3 data. - void getData(uint8_t* data) const; - /// Sets the raw layer 3 data. - void setData(const uint8_t* data, uint32_t length); - - public: - /// Flag indicating verbose log output. - __PROPERTY(bool, verbose, Verbose); - - /** Common Data */ - /// Message Type - __PROPERTY(uint8_t, messageType, MessageType); - - /// Source ID. - __PROPERTY(uint16_t, srcId, SrcId); - /// Destination ID. - __PROPERTY(uint16_t, dstId, DstId); - - /// Flag indicating a group/talkgroup operation. - __PROPERTY(bool, group, Group); - - /// - __PROPERTY(uint8_t, dataBlocks, DataBlocks); - - private: - uint8_t* m_data; - }; - } // namespace data -} // namespace nxdn - -#endif // __NXDN_LAYER_3_H__ diff --git a/nxdn/lc/LC.cpp b/nxdn/lc/LC.cpp new file mode 100644 index 00000000..d1d2bfda --- /dev/null +++ b/nxdn/lc/LC.cpp @@ -0,0 +1,480 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +// +// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 2018 by Jonathan Naylor G4KLX +* Copyright (C) 2022 by Bryan Biedenkapp N2PLL +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "nxdn/NXDNDefines.h" +#include "nxdn/lc/LC.h" +#include "Log.h" +#include "Utils.h" + +using namespace nxdn; +using namespace nxdn::lc; + +#include +#include +#include + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/// +/// Initializes a new instance of the LC class. +/// +LC::LC() : + m_verbose(false), + m_messageType(MESSAGE_TYPE_IDLE), + m_callType(CALL_TYPE_UNSPECIFIED), + m_srcId(0U), + m_dstId(0U), + m_emergency(false), + m_encrypted(false), + m_priority(false), + m_group(true), + m_duplex(false), + m_transmissionMode(TRANSMISSION_MODE_4800), + m_packetInfo(), + m_rsp(), + m_dataFrameNumber(0U), + m_dataBlockNumber(0U), + m_delayCount(0U), + m_algId(NXDN_CIPHER_TYPE_NONE), + m_kId(0U), + m_causeRsp(NXDN_CAUSE_VD_NORMAL_1), + m_data(NULL) +{ + m_data = new uint8_t[22U]; + ::memset(m_data, 0x00U, 22U); + + m_mi = new uint8_t[NXDN_MI_LENGTH_BYTES]; + ::memset(m_mi, 0x00U, NXDN_MI_LENGTH_BYTES); +} + +/// +/// Initializes a copy instance of the LC class. +/// +/// +LC::LC(const LC& data) : + m_verbose(false), + m_messageType(MESSAGE_TYPE_IDLE), + m_callType(CALL_TYPE_UNSPECIFIED), + m_srcId(0U), + m_dstId(0U), + m_emergency(false), + m_encrypted(false), + m_priority(false), + m_group(true), + m_duplex(false), + m_transmissionMode(TRANSMISSION_MODE_4800), + m_packetInfo(), + m_rsp(), + m_dataFrameNumber(0U), + m_dataBlockNumber(0U), + m_delayCount(0U), + m_algId(NXDN_CIPHER_TYPE_NONE), + m_kId(0U), + m_causeRsp(NXDN_CAUSE_VD_NORMAL_1), + m_data(NULL) +{ + copy(data); +} + +/// +/// Finalizes a instance of LC class. +/// +LC::~LC() +{ + delete[] m_data; + delete[] m_mi; +} + +/// +/// Equals operator. +/// +/// +/// +LC& LC::operator=(const LC& data) +{ + if (&data != this) { + ::memcpy(m_data, data.m_data, 22U); + decodeLC(m_data); + } + + return *this; +} + +/// +/// Decode call link control data. +/// +/// +/// True, if LC was decoded, otherwise false. +void LC::decode(const uint8_t* data, uint32_t length, uint32_t offset) +{ + assert(data != NULL); + + for (uint32_t i = 0U; i < length; i++, offset++) { + bool b = READ_BIT(data, i); + WRITE_BIT(m_data, offset, b); + } + + if (m_verbose) { + Utils::dump(2U, "Decoded LC Data", m_data, 22U); + } + + decodeLC(m_data); +} + +/// +/// Encode call link control data. +/// +/// +/// +/// +void LC::encode(uint8_t* data, uint32_t length, uint32_t offset) +{ + assert(data != NULL); + + encodeLC(m_data); + + for (uint32_t i = 0U; i < length; i++, offset++) { + bool b = READ_BIT(m_data, offset); + WRITE_BIT(data, i, b); + } + + if (m_verbose) { + Utils::dump(2U, "Encoded LC Data", data, length); + } +} + +/// +/// +/// +void LC::reset() +{ + ::memset(m_data, 0x00U, 22U); + + m_messageType = MESSAGE_TYPE_IDLE; + m_callType = CALL_TYPE_UNSPECIFIED; + + m_srcId = 0U; + m_dstId = 0U; + + m_emergency = false; + m_encrypted = false; + m_priority = false; + m_group = true; + m_duplex = false; + m_transmissionMode = TRANSMISSION_MODE_4800; + + m_packetInfo = PacketInformation(); + m_rsp = PacketInformation(); + m_dataFrameNumber = 0U; + m_dataBlockNumber = 0U; + + m_delayCount = 0U; + + m_algId = NXDN_CIPHER_TYPE_NONE; + m_kId = 0U; + + m_causeRsp = NXDN_CAUSE_VD_NORMAL_1; +} + +/// +/// Gets the raw layer 3 data. +/// +/// +void LC::getData(uint8_t* data) const +{ + ::memcpy(data, m_data, 22U); +} + +/// +/// Sets the raw layer 3 data. +/// +/// +/// +void LC::setData(const uint8_t* data, uint32_t length) +{ + ::memset(m_data, 0x00U, 22U); + ::memcpy(m_data, data, length); + + decodeLC(m_data); +} + +/// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + + +/// +/// Decode link control. +/// +/// +/// +bool LC::decodeLC(const uint8_t* data) +{ + m_messageType = data[0U] & 0x3FU; // Message Type + + // message type opcodes + switch (m_messageType) { + case RTCH_MESSAGE_TYPE_VCALL: + m_callType = (data[2U] >> 5) & 0x07U; // Call Type + m_emergency = (data[1U] & 0x80U) == 0x80U; // Emergency Flag + m_priority = (data[1U] & 0x20U) == 0x20U; // Priority Flag + m_duplex = (data[2U] & 0x10U) == 0x10U; // Half/Full Duplex Flag + m_transmissionMode = (data[2U] & 0x07U); // Transmission Mode + m_srcId = (uint16_t)((data[3U] << 8) | data[4U]) & 0xFFFFU; // Source Radio Address + m_dstId = (uint16_t)((data[5U] << 8) | data[6U]) & 0xFFFFU; // Target Radio Address + m_algId = (data[7U] >> 6) & 0x03U; // Cipher Type + m_kId = (data[7U] & 0x3FU); // Key ID + break; + case RTCH_MESSAGE_TYPE_VCALL_IV: + case RTCH_MESSAGE_TYPE_SDCALL_IV: + if (m_algId != NXDN_CIPHER_TYPE_NONE && m_kId > 0U) { + m_mi = new uint8_t[NXDN_MI_LENGTH_BYTES]; + ::memset(m_mi, 0x00U, NXDN_MI_LENGTH_BYTES); + ::memcpy(m_mi, data + 1U, NXDN_MI_LENGTH_BYTES); // Message Indicator + } + break; + case RTCH_MESSAGE_TYPE_TX_REL: + m_callType = (data[2U] >> 5) & 0x07U; // Call Type + m_emergency = (data[1U] & 0x80U) == 0x80U; // Emergency Flag + m_priority = (data[1U] & 0x20U) == 0x20U; // Priority Flag + m_srcId = (uint16_t)((data[3U] << 8) | data[4U]) & 0xFFFFU; // Source Radio Address + m_dstId = (uint16_t)((data[5U] << 8) | data[6U]) & 0xFFFFU; // Target Radio Address + break; + case RTCH_MESSAGE_TYPE_DCALL_HDR: + m_callType = (data[2U] >> 5) & 0x07U; // Call Type + m_emergency = (data[1U] & 0x80U) == 0x80U; // Emergency Flag + m_priority = (data[1U] & 0x20U) == 0x20U; // Priority Flag + m_duplex = (data[2U] & 0x10U) == 0x10U; // Half/Full Duplex Flag + m_transmissionMode = (data[2U] & 0x07U); // Transmission Mode + m_srcId = (uint16_t)((data[3U] << 8) | data[4U]) & 0xFFFFU; // Source Radio Address + m_dstId = (uint16_t)((data[5U] << 8) | data[6U]) & 0xFFFFU; // Target Radio Address + m_algId = (data[7U] >> 6) & 0x03U; // Cipher Type + m_kId = (data[7U] & 0x3FU); // Key ID + + m_packetInfo = PacketInformation(); + m_packetInfo.decode(m_messageType, data + 8U); // Packet Information + + if (m_algId != NXDN_CIPHER_TYPE_NONE && m_kId > 0U) { + ::memset(m_mi, 0x00U, NXDN_MI_LENGTH_BYTES); + ::memcpy(m_mi, data + 11U, NXDN_MI_LENGTH_BYTES); // Message Indicator + } + break; + case RTCH_MESSAGE_TYPE_DCALL_DATA: + case RTCH_MESSAGE_TYPE_SDCALL_REQ_DATA: + m_dataFrameNumber = (data[1U] >> 4) & 0x0FU; // Frame Number + m_dataBlockNumber = (data[1U] & 0x0FU); // Block Number + break; + case RTCH_MESSAGE_TYPE_DCALL_ACK: + m_callType = (data[2U] >> 5) & 0x07U; // Call Type + m_emergency = (data[1U] & 0x80U) == 0x80U; // Emergency Flag + m_priority = (data[1U] & 0x20U) == 0x20U; // Priority Flag + m_duplex = (data[2U] & 0x10U) == 0x10U; // Half/Full Duplex Flag + m_transmissionMode = (data[2U] & 0x07U); // Transmission Mode + m_srcId = (uint16_t)((data[3U] << 8) | data[4U]) & 0xFFFFU; // Source Radio Address + m_dstId = (uint16_t)((data[5U] << 8) | data[6U]) & 0xFFFFU; // Target Radio Address + + m_rsp = PacketInformation(); + m_rsp.decode(m_messageType, data + 7U); // Response + break; + case RTCH_MESSAGE_TYPE_HEAD_DLY: + m_callType = (data[2U] >> 5) & 0x07U; // Call Type + m_emergency = (data[1U] & 0x80U) == 0x80U; // Emergency Flag + m_priority = (data[1U] & 0x20U) == 0x20U; // Priority Flag + m_srcId = (uint16_t)((data[3U] << 8) | data[4U]) & 0xFFFFU; // Source Radio Address + m_dstId = (uint16_t)((data[5U] << 8) | data[6U]) & 0xFFFFU; // Target Radio Address + m_delayCount = (uint16_t)((data[7U] << 8) | data[8U]) & 0xFFFFU; // Delay Count + break; + case MESSAGE_TYPE_IDLE: + break; + case RTCH_MESSAGE_TYPE_SDCALL_REQ_HDR: + m_callType = (data[2U] >> 5) & 0x07U; // Call Type + m_emergency = (data[1U] & 0x80U) == 0x80U; // Emergency Flag + m_priority = (data[1U] & 0x20U) == 0x20U; // Priority Flag + m_duplex = (data[2U] & 0x10U) == 0x10U; // Half/Full Duplex Flag + m_transmissionMode = (data[2U] & 0x07U); // Transmission Mode + m_srcId = (uint16_t)((data[3U] << 8) | data[4U]) & 0xFFFFU; // Source Radio Address + m_dstId = (uint16_t)((data[5U] << 8) | data[6U]) & 0xFFFFU; // Target Radio Address + m_algId = (data[7U] >> 6) & 0x03U; // Cipher Type + m_kId = (data[7U] & 0x3FU); // Key ID + + m_packetInfo = PacketInformation(); + m_packetInfo.decode(m_messageType, data + 8U); // Packet Information + break; + case RTCH_MESSAGE_TYPE_SDCALL_RESP: + m_callType = (data[2U] >> 5) & 0x07U; // Call Type + m_emergency = (data[1U] & 0x80U) == 0x80U; // Emergency Flag + m_priority = (data[1U] & 0x20U) == 0x20U; // Priority Flag + m_duplex = (data[2U] & 0x10U) == 0x10U; // Half/Full Duplex Flag + m_transmissionMode = (data[2U] & 0x07U); // Transmission Mode + m_srcId = (uint16_t)((data[3U] << 8) | data[4U]) & 0xFFFFU; // Source Radio Address + m_dstId = (uint16_t)((data[5U] << 8) | data[6U]) & 0xFFFFU; // Target Radio Address + m_causeRsp = data[7U]; // Cause (SS) + break; + default: + LogError(LOG_NXDN, "LC::decodeLC(), unknown LC value, messageType = $%02X", m_messageType); + return false; + } + + return true; +} + +/// +/// Encode link control. +/// +/// +void LC::encodeLC(uint8_t* data) +{ + m_messageType = m_data[0U] & 0x3FU; // Message Type + + // message type opcodes + switch (m_messageType) { + case RTCH_MESSAGE_TYPE_VCALL: + m_data[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag + (m_priority ? 0x20U : 0x00U); // Priority Flag + m_data[2U] = ((m_callType & 0x07U) << 5) + // Call Type + (m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag + (m_transmissionMode & 0x07U); // Transmission Mode + + m_data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address + m_data[4U] = (m_srcId >> 0U) & 0xFFU; // ... + m_data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address + m_data[6U] = (m_dstId >> 0U) & 0xFFU; // ... + + m_data[7U] = ((m_algId & 0x03U) << 6) + // Cipher Type + (m_kId & 0x3FU); // Key ID + break; + case RTCH_MESSAGE_TYPE_VCALL_IV: + if (m_algId != NXDN_CIPHER_TYPE_NONE && m_kId > 0U) { + ::memcpy(m_data + 1U, m_mi, NXDN_MI_LENGTH_BYTES); // Message Indicator + } + break; + case RTCH_MESSAGE_TYPE_TX_REL: + m_data[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag + (m_priority ? 0x20U : 0x00U); // Priority Flag + m_data[2U] = (m_callType & 0x07U) << 5; // Call Type + + m_data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address + m_data[4U] = (m_srcId >> 0U) & 0xFFU; // ... + m_data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address + m_data[6U] = (m_dstId >> 0U) & 0xFFU; // ... + break; + case RTCH_MESSAGE_TYPE_DCALL_HDR: + m_data[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag + (m_priority ? 0x20U : 0x00U); // Priority Flag + m_data[2U] = ((m_callType & 0x07U) << 5) + // Call Type + (m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag + (m_transmissionMode & 0x07U); // Transmission Mode + + m_data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address + m_data[4U] = (m_srcId >> 0U) & 0xFFU; // ... + m_data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address + m_data[6U] = (m_dstId >> 0U) & 0xFFU; // ... + + m_data[7U] = ((m_algId & 0x03U) << 6) + // Cipher Type + (m_kId & 0x3FU); // Key ID + + m_packetInfo.encode(m_messageType, data + 8U); // Packet Information + + if (m_algId != NXDN_CIPHER_TYPE_NONE && m_kId > 0U) { + ::memcpy(m_data + 11U, m_mi, NXDN_MI_LENGTH_BYTES); // Message Indicator + } + break; + case RTCH_MESSAGE_TYPE_DCALL_DATA: + case RTCH_MESSAGE_TYPE_SDCALL_REQ_DATA: + data[1U] = (m_dataFrameNumber & 0x0FU << 4) + // Frame Number + (m_dataBlockNumber & 0x0FU); // Block Number + break; + case RTCH_MESSAGE_TYPE_DCALL_ACK: + m_data[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag + (m_priority ? 0x20U : 0x00U); // Priority Flag + m_data[2U] = ((m_callType & 0x07U) << 5) + // Call Type + (m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag + (m_transmissionMode & 0x07U); // Transmission Mode + + m_data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address + m_data[4U] = (m_srcId >> 0U) & 0xFFU; // ... + m_data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address + m_data[6U] = (m_dstId >> 0U) & 0xFFU; // ... + + m_rsp.encode(m_messageType, data + 7U); // Response + break; + case RTCH_MESSAGE_TYPE_HEAD_DLY: + m_data[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag + (m_priority ? 0x20U : 0x00U); // Priority Flag + m_data[2U] = (m_callType & 0x07U) << 5; // Call Type + + m_data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address + m_data[4U] = (m_srcId >> 0U) & 0xFFU; // ... + m_data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address + m_data[6U] = (m_dstId >> 0U) & 0xFFU; // ... + + m_data[7U] = (m_delayCount >> 8U) & 0xFFU; // Delay Count + m_data[8U] = (m_delayCount >> 0U) & 0xFFU; // ... + break; + case MESSAGE_TYPE_IDLE: + break; + case RTCH_MESSAGE_TYPE_SDCALL_REQ_HDR: + m_data[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag + (m_priority ? 0x20U : 0x00U); // Priority Flag + m_data[2U] = ((m_callType & 0x07U) << 5) + // Call Type + (m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag + (m_transmissionMode & 0x07U); // Transmission Mode + + m_data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address + m_data[4U] = (m_srcId >> 0U) & 0xFFU; // ... + m_data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address + m_data[6U] = (m_dstId >> 0U) & 0xFFU; // ... + + m_data[7U] = ((m_algId & 0x03U) << 6) + // Cipher Type + (m_kId & 0x3FU); // Key ID + + m_packetInfo.encode(m_messageType, data + 8U); // Packet Information + break; + default: + LogError(LOG_NXDN, "LC::encodeLC(), unknown LC value, messageType = $%02X", m_messageType); + return; + } +} + +// +/// Internal helper to copy the the class. +/// +/// +void LC::copy(const LC& data) +{ + m_data = new uint8_t[22U]; + ::memcpy(m_data, data.m_data, 22U); + + m_verbose = data.m_verbose; + + decodeLC(m_data); +} diff --git a/nxdn/lc/LC.h b/nxdn/lc/LC.h new file mode 100644 index 00000000..1dd1a9e7 --- /dev/null +++ b/nxdn/lc/LC.h @@ -0,0 +1,142 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +// +// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 2018 by Jonathan Naylor G4KLX +* Copyright (C) 2022 by Bryan Biedenkapp N2PLL +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#if !defined(__NXDN_LC__LC_H__) +#define __NXDN_LC__LC_H__ + +#include "Defines.h" +#include "nxdn/lc/PacketInformation.h" + +namespace nxdn +{ + namespace lc + { + // --------------------------------------------------------------------------- + // Class Declaration + // Represents link control data for NXDN calls. + // --------------------------------------------------------------------------- + + class HOST_SW_API LC { + public: + /// Initializes a new instance of the LC class. + LC(); + /// Initializes a copy instance of the LC class. + LC(const LC& data); + /// Finalizes a instance of the LC class. + ~LC(); + + /// Equals operator. + LC& operator=(const LC& data); + + /// Decode layer 3 data. + void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U); + /// Encode layer 3 data. + void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U); + + /// + void reset(); + + /// Gets the raw layer 3 data. + void getData(uint8_t* data) const; + /// Sets the raw layer 3 data. + void setData(const uint8_t* data, uint32_t length); + + public: + /// Flag indicating verbose log output. + __PROPERTY(bool, verbose, Verbose); + + /** Common Data */ + /// Message Type + __PROPERTY(uint8_t, messageType, MessageType); + + /// Call Type + __PROPERTY(uint8_t, callType, CallType); + + /// Source ID. + __PROPERTY(uint16_t, srcId, SrcId); + /// Destination ID. + __PROPERTY(uint16_t, dstId, DstId); + + /** Common Call Options */ + /// Flag indicating the emergency bits are set. + __PROPERTY(bool, emergency, Emergency); + /// Flag indicating that encryption is enabled. + __PROPERTY(bool, encrypted, Encrypted); + /// Flag indicating priority paging. + __PROPERTY(bool, priority, Priority); + /// Flag indicating a group/talkgroup operation. + __PROPERTY(bool, group, Group); + /// Flag indicating a half/full duplex operation. + __PROPERTY(bool, duplex, Duplex); + + /// Transmission mode. + __PROPERTY(uint8_t, transmissionMode, TransmissionMode); + + /** Data Call Data */ + /// Data packet information. + __PROPERTY(PacketInformation, packetInfo, PacketInfo); + /// Data packet information. + __PROPERTY(PacketInformation, rsp, Response); + /// Data packet frame number. + __PROPERTY(uint8_t, dataFrameNumber, DataFrameNumber); + /// Data packet block number. + __PROPERTY(uint8_t, dataBlockNumber, DataBlockNumber); + + /** Header Delay Data */ + /// Delay count. + __PROPERTY(uint16_t, delayCount, DelayCount); + + /** Encryption data */ + /// Encryption algorithm ID. + __PROPERTY(uint8_t, algId, AlgId); + /// Encryption key ID. + __PROPERTY(uint8_t, kId, KId); + + /// Cause Response. + __PROPERTY(uint8_t, causeRsp, CauseResponse); + + private: + uint8_t* m_data; + + /** Encryption data */ + uint8_t* m_mi; + + /// Decode link control. + bool decodeLC(const uint8_t* data); + /// Encode link control. + void encodeLC(uint8_t* data); + + /// Internal helper to copy the class. + void copy(const LC& data); + }; + } // namespace lc +} // namespace nxdn + +#endif // __NXDN_LC__LC_H__ diff --git a/nxdn/lc/PacketInformation.cpp b/nxdn/lc/PacketInformation.cpp new file mode 100644 index 00000000..a4b2320b --- /dev/null +++ b/nxdn/lc/PacketInformation.cpp @@ -0,0 +1,187 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +/* +* Copyright (C) 2022 by Bryan Biedenkapp N2PLL +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "Defines.h" +#include "nxdn/NXDNDefines.h" +#include "nxdn/lc/PacketInformation.h" +#include "Log.h" +#include "Utils.h" + +using namespace nxdn::lc; +using namespace nxdn; + +#include +#include +#include + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/// +/// Initializes a new instance of the PacketInformation class. +/// +PacketInformation::PacketInformation() : + m_delivery(false), + m_selectiveRetry(false), + m_blockCount(0U), + m_padCount(0U), + m_start(true), + m_circular(false), + m_fragmentCount(0U), + m_rspClass(DATA_RSP_CLASS_ACK), + m_rspType(1U), + m_rspErrorBlock(0U) +{ + /* stub */ +} + +/// +/// Finalizes a instance of the PacketInformation class. +/// +PacketInformation::~PacketInformation() +{ + /* stub */ +} + +/// +/// Decodes packet information. +/// +/// +/// +/// True, if packet information was decoded, otherwise false. +bool PacketInformation::decode(const uint8_t messageType, const uint8_t* data) +{ + assert(data != NULL); + + switch (messageType) + { + case RTCH_MESSAGE_TYPE_DCALL_HDR: + m_delivery = (data[0U] & 0x80U) == 0x80U; // Delivery + m_selectiveRetry = (data[0U] & 0x20U) == 0x20U; // Selective Retry + m_blockCount = (data[0U] & 0x0FU); // Block Count + + m_padCount = (data[1U] >> 3) & 0x1FU; // Pad Count + m_start = (data[1U] & 0x08U) == 0x08U; // Start/First Fragment + m_circular = (data[1U] & 0x04U) == 0x04U; // Circular Fragment Count + + m_fragmentCount = ((data[1U] & 0x01U) << 8) + data[2U]; // Fragment Count + break; + case RTCH_MESSAGE_TYPE_DCALL_ACK: + m_rspClass = (data[0U] >> 4) & 0x03U; // Response Class + m_rspType = (data[0U] >> 1) & 0x07U; // Response Type + m_fragmentCount = ((data[0U] & 0x01U) << 8) + data[1U]; // Fragment Count + break; + case RTCH_MESSAGE_TYPE_SDCALL_REQ_HDR: + m_delivery = (data[0U] & 0x80U) == 0x80U; // Delivery + m_selectiveRetry = (data[0U] & 0x20U) == 0x20U; // Selective Retry + m_blockCount = (data[0U] & 0x0FU); // Block Count + + m_padCount = (data[1U] >> 3) & 0x1FU; // Pad Count + m_start = (data[1U] & 0x08U) == 0x08U; // Start/First Fragment + m_circular = (data[1U] & 0x04U) == 0x04U; // Circular Fragment Count + break; + default: + LogError(LOG_NXDN, "PacketInformation::decode(), unknown LC value, messageType = $%02X", messageType); + return false; + } + + return true; +} + +/// +/// Encodes packet information. +/// +/// +/// +void PacketInformation::encode(const uint8_t messageType, uint8_t* data) +{ + assert(data != NULL); + + switch (messageType) + { + case RTCH_MESSAGE_TYPE_DCALL_HDR: + { + ::memset(data, 0x00U, NXDN_PCKT_INFO_LENGTH_BYTES); + + data[0U] = (m_delivery ? 0x80U : 0x00U) + // Delivery + (m_selectiveRetry ? 0x20U : 0x00U) + // Selective Retry + m_blockCount; // Block Count + + data[1U] = (m_padCount << 3) + // Pad Count + (m_start ? 0x08U : 0x00U) + // Start/First Fragment + (m_circular ? 0x04U : 0x00U); // Circular Fragment Count + + bool highFragCount = (m_fragmentCount & 0x100U) == 0x100U; + data[1U] += (highFragCount ? 0x01U : 0x00U); // Fragment Count - bit 8 + data[2U] = m_fragmentCount & 0xFFU; // Fragment Count - bit 0 - 7 + } + break; + case RTCH_MESSAGE_TYPE_DCALL_ACK: + { + data[0U] = (m_rspClass & 0x03U << 4) + // Response Class + (m_rspType & 0x07U << 1); // Response Type + + bool highFragCount = (m_fragmentCount & 0x100U) == 0x100U; + data[0U] += (highFragCount ? 0x01U : 0x00U); // Fragment Count - bit 8 + data[1U] = m_fragmentCount & 0xFFU; // Fragment Count - bit 0 - 7 + } + break; + case RTCH_MESSAGE_TYPE_SDCALL_REQ_HDR: + ::memset(data, 0x00U, NXDN_PCKT_INFO_LENGTH_BYTES); + + data[0U] = (m_delivery ? 0x80U : 0x00U) + // Delivery + (m_selectiveRetry ? 0x20U : 0x00U) + // Selective Retry + m_blockCount; // Block Count + + data[1U] = (m_padCount << 3) + // Pad Count + (m_start ? 0x08U : 0x00U) + // Start/First Fragment + (m_circular ? 0x04U : 0x00U); // Circular Fragment Count + break; + default: + LogError(LOG_NXDN, "PacketInformation::encode(), unknown LC value, messageType = $%02X", messageType); + break; + } +} + +/// +/// Helper to reset data values to defaults. +/// +void PacketInformation::reset() +{ + m_delivery = false; + m_selectiveRetry = false; + m_blockCount = 0U; + + m_padCount = 0U; + m_start = true; + m_circular = false; + + m_fragmentCount = 0U; + + m_rspClass = DATA_RSP_CLASS_ACK; + m_rspType = 0U; + m_rspErrorBlock = 0U; +} diff --git a/nxdn/lc/PacketInformation.h b/nxdn/lc/PacketInformation.h new file mode 100644 index 00000000..c916126b --- /dev/null +++ b/nxdn/lc/PacketInformation.h @@ -0,0 +1,83 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +/* +* Copyright (C) 2022 by Bryan Biedenkapp N2PLL +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#if !defined(__NXDN_LC__PACKET_INFORMATION_H__) +#define __NXDN_LC__PACKET_INFORMATION_H__ + +#include "Defines.h" + +namespace nxdn +{ + namespace lc + { + // --------------------------------------------------------------------------- + // Class Declaration + // Represents the packet information data for link control data. + // --------------------------------------------------------------------------- + + class HOST_SW_API PacketInformation { + public: + /// Initializes a new instance of the PacketInformation class. + PacketInformation(); + /// Finalizes a instance of the PacketInformation class. + ~PacketInformation(); + + /// Decodes packet information. + bool decode(const uint8_t messageType, const uint8_t* data); + /// Encodes packet information. + void encode(const uint8_t messageType, uint8_t* data); + + /// Helper to reset data values to defaults. + void reset(); + + public: + /** Common Data **/ + /// Flag indicating if confirmed delivery is needed. + __PROPERTY(bool, delivery, Delivery); + /// Flag indicating if the packet is a selective retry packet. + __PROPERTY(bool, selectiveRetry, SelectiveRetry); + /// Count of data blocks in t he transmission packet. + __PROPERTY(uint8_t, blockCount, BlockCount); + /// Number of padding octets of the last block. + __PROPERTY(uint8_t, padCount, PadCount); + /// Flag indicating the first fragment. + __PROPERTY(bool, start, Start); + /// Flag indicating if the Tx fragment count circulates. + __PROPERTY(bool, circular, Circular); + /// The number and sequence of fragments. + __PROPERTY(uint16_t, fragmentCount, FragmentCount); + + /** Response Data */ + /// Response class. + __PROPERTY(uint8_t, rspClass, ResponseClass); + /// Response type. + __PROPERTY(uint8_t, rspType, ResponseType); + /// Error Block Flag. + __PROPERTY(uint16_t, rspErrorBlock, ResponseErrorBlock); + }; + } // namespace lc +} // namespace nxdn + +#endif // __NXDN_LC__PACKET_INFORMATION_H__ diff --git a/nxdn/packet/Data.cpp b/nxdn/packet/Data.cpp index 1be6fd06..77ff0b01 100644 --- a/nxdn/packet/Data.cpp +++ b/nxdn/packet/Data.cpp @@ -62,9 +62,9 @@ using namespace nxdn::packet; } \ \ if (m_nxdn->m_netState != RS_NET_IDLE) { \ - if (m_nxdn->m_netLayer3.getSrcId() == _SRC_ID && m_nxdn->m_netLastDstId == _DST_ID) { \ + if (m_nxdn->m_netLC.getSrcId() == _SRC_ID && m_nxdn->m_netLastDstId == _DST_ID) { \ LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing RF traffic (Are we in a voting condition?), rfSrcId = %u, rfDstId = %u, netSrcId = %u, netDstId = %u", srcId, dstId, \ - m_nxdn->m_netLayer3.getSrcId(), m_nxdn->m_netLastDstId); \ + m_nxdn->m_netLC.getSrcId(), m_nxdn->m_netLastDstId); \ resetRF(); \ return false; \ } \ @@ -196,15 +196,15 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len) uint8_t buffer[23U]; udch.getData(buffer); - data::Layer3 layer3; - layer3.decode(buffer, 184U); - uint16_t dstId = layer3.getDstId(); - uint16_t srcId = layer3.getSrcId(); - bool group = layer3.getGroup(); + lc::LC lc; + lc.decode(buffer, 184U); + uint16_t dstId = lc.getDstId(); + uint16_t srcId = lc.getSrcId(); + bool group = lc.getGroup(); if (m_nxdn->m_rfState == RS_RF_LISTENING) { - uint8_t type = layer3.getMessageType(); - if (type != MESSAGE_TYPE_DCALL_HDR) + uint8_t type = lc.getMessageType(); + if (type != RTCH_MESSAGE_TYPE_DCALL_HDR) return false; CHECK_TRAFFIC_COLLISION(srcId, dstId); @@ -215,16 +215,14 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len) // validate destination ID VALID_DSTID(srcId, dstId, group); - uint8_t frames = layer3.getDataBlocks(); - if (m_verbose) { - LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_DCALL ", srcId = %u, dstId = %u, blocks = %u", - srcId, dstId, frames); + LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_DCALL ", srcId = %u, dstId = %u, ack = %u, blocksToFollow = %u, padCount = %u, firstFragment = %u, fragmentCount = %u", + srcId, dstId, lc.getPacketInfo().getDelivery(), lc.getPacketInfo().getBlockCount(), lc.getPacketInfo().getPadCount(), lc.getPacketInfo().getStart(), lc.getPacketInfo().getFragmentCount()); } ::ActivityLog("NXDN", true, "RF data transmission from %u to %s%u", srcId, group ? "TG " : "", dstId); - m_nxdn->m_rfLayer3 = layer3; + m_nxdn->m_rfLC = lc; m_nxdn->m_voice->m_rfFrames = 0U; m_nxdn->m_rfState = RS_RF_DATA; @@ -244,10 +242,10 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len) lich.setDirection(NXDN_LICH_DIRECTION_INBOUND); - uint8_t type = MESSAGE_TYPE_DCALL_DATA; + uint8_t type = RTCH_MESSAGE_TYPE_DCALL_DATA; if (validUDCH) { - type = layer3.getMessageType(); - data[0U] = type == MESSAGE_TYPE_TX_REL ? modem::TAG_EOT : modem::TAG_DATA; + type = lc.getMessageType(); + data[0U] = type == RTCH_MESSAGE_TYPE_TX_REL ? modem::TAG_EOT : modem::TAG_DATA; udch.setRAN(m_nxdn->m_ran); udch.encode(data + 2U); @@ -282,10 +280,11 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len) /// Process a data frame from the RF interface. /// /// +/// /// Buffer containing data frame. /// Length of data frame. /// -bool Data::processNetwork(uint8_t option, data::Layer3& netLayer3, uint8_t* data, uint32_t len) +bool Data::processNetwork(uint8_t option, lc::LC& netLC, uint8_t* data, uint32_t len) { assert(data != NULL); @@ -305,18 +304,18 @@ bool Data::processNetwork(uint8_t option, data::Layer3& netLayer3, uint8_t* data uint8_t buffer[23U]; udch.getData(buffer); - data::Layer3 layer3; - layer3.decode(buffer, 184U); - uint16_t dstId = layer3.getDstId(); - uint16_t srcId = layer3.getSrcId(); - bool group = layer3.getGroup(); + lc::LC lc; + lc.decode(buffer, 184U); + uint16_t dstId = lc.getDstId(); + uint16_t srcId = lc.getSrcId(); + bool group = lc.getGroup(); if (m_nxdn->m_netState == RS_NET_IDLE) { - uint8_t type = layer3.getMessageType(); - if (type != MESSAGE_TYPE_DCALL_HDR) + uint8_t type = lc.getMessageType(); + if (type != RTCH_MESSAGE_TYPE_DCALL_HDR) return false; - CHECK_NET_TRAFFIC_COLLISION(layer3, srcId, dstId); + CHECK_NET_TRAFFIC_COLLISION(lc, srcId, dstId); // validate source RID VALID_SRCID(srcId, dstId, group); @@ -324,16 +323,14 @@ bool Data::processNetwork(uint8_t option, data::Layer3& netLayer3, uint8_t* data // validate destination ID VALID_DSTID(srcId, dstId, group); - uint8_t frames = layer3.getDataBlocks(); - if (m_verbose) { - LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_DCALL ", srcId = %u, dstId = %u, blocks = %u", - srcId, dstId, frames); + LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_DCALL ", srcId = %u, dstId = %u, ack = %u, blocksToFollow = %u, padCount = %u, firstFragment = %u, fragmentCount = %u", + srcId, dstId, lc.getPacketInfo().getDelivery(), lc.getPacketInfo().getBlockCount(), lc.getPacketInfo().getPadCount(), lc.getPacketInfo().getStart(), lc.getPacketInfo().getFragmentCount()); } ::ActivityLog("NXDN", false, "network data transmission from %u to %s%u", srcId, group ? "TG " : "", dstId); - m_nxdn->m_netLayer3 = layer3; + m_nxdn->m_netLC = lc; m_nxdn->m_voice->m_netFrames = 0U; m_nxdn->m_netState = RS_NET_DATA; @@ -351,10 +348,10 @@ bool Data::processNetwork(uint8_t option, data::Layer3& netLayer3, uint8_t* data lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND); lich.encode(data + 2U); - uint8_t type = MESSAGE_TYPE_DCALL_DATA; + uint8_t type = RTCH_MESSAGE_TYPE_DCALL_DATA; if (validUDCH) { - type = layer3.getMessageType(); - data[0U] = type == MESSAGE_TYPE_TX_REL ? modem::TAG_EOT : modem::TAG_DATA; + type = lc.getMessageType(); + data[0U] = type == RTCH_MESSAGE_TYPE_TX_REL ? modem::TAG_EOT : modem::TAG_DATA; udch.setRAN(m_nxdn->m_ran); udch.encode(data + 2U); @@ -427,5 +424,5 @@ void Data::writeNetwork(const uint8_t *data, uint32_t len) if (m_nxdn->m_rfTimeout.isRunning() && m_nxdn->m_rfTimeout.hasExpired()) return; - m_network->writeNXDN(m_nxdn->m_rfLayer3, data, len); + m_network->writeNXDN(m_nxdn->m_rfLC, data, len); } diff --git a/nxdn/packet/Data.h b/nxdn/packet/Data.h index 1a09a604..fbbd596d 100644 --- a/nxdn/packet/Data.h +++ b/nxdn/packet/Data.h @@ -63,7 +63,7 @@ namespace nxdn /// Process a data frame from the RF interface. virtual bool process(uint8_t option, uint8_t* data, uint32_t len); /// Process a data frame from the network. - virtual bool processNetwork(uint8_t option, data::Layer3& netLayer3, uint8_t* data, uint32_t len); + virtual bool processNetwork(uint8_t option, lc::LC& netLC, uint8_t* data, uint32_t len); protected: friend class nxdn::Control; diff --git a/nxdn/packet/Voice.cpp b/nxdn/packet/Voice.cpp index 3c5344ad..f9669be0 100644 --- a/nxdn/packet/Voice.cpp +++ b/nxdn/packet/Voice.cpp @@ -64,9 +64,9 @@ using namespace nxdn::packet; } \ \ if (m_nxdn->m_netState != RS_NET_IDLE) { \ - if (m_nxdn->m_netLayer3.getSrcId() == _SRC_ID && m_nxdn->m_netLastDstId == _DST_ID) { \ + if (m_nxdn->m_netLC.getSrcId() == _SRC_ID && m_nxdn->m_netLastDstId == _DST_ID) { \ LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing RF traffic (Are we in a voting condition?), rfSrcId = %u, rfDstId = %u, netSrcId = %u, netDstId = %u", srcId, dstId, \ - m_nxdn->m_netLayer3.getSrcId(), m_nxdn->m_netLastDstId); \ + m_nxdn->m_netLC.getSrcId(), m_nxdn->m_netLastDstId); \ resetRF(); \ return false; \ } \ @@ -210,21 +210,22 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) uint8_t buffer[10U]; facch.getData(buffer); - data::Layer3 layer3; - layer3.decode(buffer, NXDN_FACCH1_LENGTH_BITS); - uint16_t dstId = layer3.getDstId(); - uint16_t srcId = layer3.getSrcId(); - bool group = layer3.getGroup(); + lc::LC lc; + lc.decode(buffer, NXDN_FACCH1_LENGTH_BITS); + uint16_t dstId = lc.getDstId(); + uint16_t srcId = lc.getSrcId(); + bool group = lc.getGroup(); + bool encrypted = lc.getEncrypted(); - uint8_t type = layer3.getMessageType(); - if (type == MESSAGE_TYPE_TX_REL) { + uint8_t type = lc.getMessageType(); + if (type == RTCH_MESSAGE_TYPE_TX_REL) { if (m_nxdn->m_rfState != RS_RF_AUDIO) { m_nxdn->m_rfState = RS_RF_LISTENING; m_nxdn->m_rfMask = 0x00U; - m_nxdn->m_rfLayer3.reset(); + m_nxdn->m_rfLC.reset(); return false; } - } else if (type == MESSAGE_TYPE_VCALL) { + } else if (type == RTCH_MESSAGE_TYPE_VCALL) { CHECK_TRAFFIC_COLLISION(srcId, dstId); // validate source RID @@ -236,7 +237,7 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) return false; } - m_nxdn->m_rfLayer3 = layer3; + m_nxdn->m_rfLC = lc; Sync::addNXDNSync(data + 2U); @@ -250,9 +251,9 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) // generate the SACCH channel::SACCH sacch; + sacch.setData(SACCH_IDLE); sacch.setRAN(m_nxdn->m_ran); sacch.setStructure(NXDN_SR_SINGLE); - sacch.setData(SACCH_IDLE); sacch.encode(data + 2U); facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); @@ -263,7 +264,7 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) writeNetwork(data, NXDN_FRAME_LENGTH_BYTES + 2U); if (m_nxdn->m_duplex) { - data[0U] = type == MESSAGE_TYPE_TX_REL ? modem::TAG_EOT : modem::TAG_DATA; + data[0U] = type == RTCH_MESSAGE_TYPE_TX_REL ? modem::TAG_EOT : modem::TAG_DATA; data[1U] = 0x00U; m_nxdn->addFrame(data, NXDN_FRAME_LENGTH_BYTES + 2U); @@ -297,7 +298,12 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) m_nxdn->m_aveRSSI = m_nxdn->m_rssi; m_nxdn->m_rssiCount = 1U; - ::ActivityLog("NXDN", true, "RF voice transmission from %u to %s%u", srcId, group ? "TG " : "", dstId); + if (m_verbose) { + LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%02X", + srcId, dstId, group, lc.getEmergency(), encrypted, lc.getPriority(), lc.getAlgId(), lc.getKId()); + } + + ::ActivityLog("NXDN", true, "RF %svoice transmission from %u to %s%u", encrypted ? "encrypted " : "", srcId, group ? "TG " : "", dstId); } return true; @@ -326,14 +332,14 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) uint8_t buffer[10U]; facch.getData(buffer); - data::Layer3 layer3; - layer3.decode(buffer, NXDN_FACCH1_LENGTH_BITS); + lc::LC lc; + lc.decode(buffer, NXDN_FACCH1_LENGTH_BITS); - hasInfo = layer3.getMessageType() == MESSAGE_TYPE_VCALL; + hasInfo = lc.getMessageType() == RTCH_MESSAGE_TYPE_VCALL; if (!hasInfo) return false; - m_nxdn->m_rfLayer3 = layer3; + m_nxdn->m_rfLC = lc; } if (!hasInfo) { @@ -343,23 +349,23 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) uint8_t structure = sacch.getStructure(); switch (structure) { case NXDN_SR_1_4: - m_nxdn->m_rfLayer3.decode(message, 18U, 0U); - if(m_nxdn->m_rfLayer3.getMessageType() == MESSAGE_TYPE_VCALL) + m_nxdn->m_rfLC.decode(message, 18U, 0U); + if(m_nxdn->m_rfLC.getMessageType() == RTCH_MESSAGE_TYPE_VCALL) m_nxdn->m_rfMask = 0x01U; else m_nxdn->m_rfMask = 0x00U; break; case NXDN_SR_2_4: m_nxdn->m_rfMask |= 0x02U; - m_nxdn->m_rfLayer3.decode(message, 18U, 18U); + m_nxdn->m_rfLC.decode(message, 18U, 18U); break; case NXDN_SR_3_4: m_nxdn->m_rfMask |= 0x04U; - m_nxdn->m_rfLayer3.decode(message, 18U, 36U); + m_nxdn->m_rfLC.decode(message, 18U, 36U); break; case NXDN_SR_4_4: m_nxdn->m_rfMask |= 0x08U; - m_nxdn->m_rfLayer3.decode(message, 18U, 54U); + m_nxdn->m_rfLC.decode(message, 18U, 54U); break; default: break; @@ -368,14 +374,15 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) if (m_nxdn->m_rfMask != 0x0FU) return false; - uint8_t type = m_nxdn->m_rfLayer3.getMessageType(); - if (type != MESSAGE_TYPE_VCALL) + uint8_t type = m_nxdn->m_rfLC.getMessageType(); + if (type != RTCH_MESSAGE_TYPE_VCALL) return false; } - uint16_t dstId = m_nxdn->m_rfLayer3.getDstId(); - uint16_t srcId = m_nxdn->m_rfLayer3.getSrcId(); - bool group = m_nxdn->m_rfLayer3.getGroup(); + uint16_t dstId = m_nxdn->m_rfLC.getDstId(); + uint16_t srcId = m_nxdn->m_rfLC.getSrcId(); + bool group = m_nxdn->m_rfLC.getGroup(); + bool encrypted = m_nxdn->m_rfLC.getEncrypted(); CHECK_TRAFFIC_COLLISION(srcId, dstId); @@ -396,7 +403,12 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) m_nxdn->m_aveRSSI = m_nxdn->m_rssi; m_nxdn->m_rssiCount = 1U; - ::ActivityLog("NXDN", true, "RF late entry from %u to %s%u", srcId, group ? "TG " : "", dstId); + if (m_verbose) { + LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%04X", + srcId, dstId, group, m_nxdn->m_rfLC.getEmergency(), encrypted, m_nxdn->m_rfLC.getPriority(), m_nxdn->m_rfLC.getAlgId(), m_nxdn->m_rfLC.getKId()); + } + + ::ActivityLog("NXDN", true, "RF %slate entry from %u to %s%u", encrypted ? "encrypted ": "", srcId, group ? "TG " : "", dstId); // create a dummy start message uint8_t start[NXDN_FRAME_LENGTH_BYTES + 2U]; @@ -417,13 +429,13 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) // generate the SACCH channel::SACCH sacch; + sacch.setData(SACCH_IDLE); sacch.setRAN(m_nxdn->m_ran); sacch.setStructure(NXDN_SR_SINGLE); - sacch.setData(SACCH_IDLE); sacch.encode(start + 2U); uint8_t message[22U]; - m_nxdn->m_rfLayer3.getData(message); + m_nxdn->m_rfLC.getData(message); facch.setData(message); facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); @@ -482,11 +494,6 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", audio, errs = %u/141 (%.1f%%)", errors, float(errors) / 1.88F); } -/* - Audio audio; - audio.decode(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 0U, netData + 5U + 0U); - audio.decode(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U, netData + 5U + 14U); -*/ } else if (option == NXDN_LICH_STEAL_FACCH1_1) { channel::FACCH1 facch1; bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); @@ -507,10 +514,6 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", audio, errs = %u/94 (%.1f%%)", errors, float(errors) / 0.94F); } -/* - Audio audio; - audio.decode(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U, netData + 5U + 14U); -*/ } else if (option == NXDN_LICH_STEAL_FACCH1_2) { edac::AMBEFEC ambe; @@ -526,10 +529,7 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) LogMessage(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", audio, errs = %u/94 (%.1f%%)", errors, float(errors) / 0.94F); } -/* - Audio audio; - audio.decode(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 0U, netData + 5U + 0U); -*/ + channel::FACCH1 facch1; bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); if (valid) @@ -571,10 +571,11 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len) /// /// /// +/// /// Buffer containing data frame. /// Length of data frame. /// -bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, uint8_t* data, uint32_t len) +bool Voice::processNetwork(uint8_t usc, uint8_t option, lc::LC& netLC, uint8_t *data, uint32_t len) { assert(data != NULL); @@ -600,22 +601,23 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, uint8_t buffer[10U]; facch.getData(buffer); - data::Layer3 layer3; - layer3.decode(buffer, NXDN_FACCH1_LENGTH_BITS); - uint16_t dstId = layer3.getDstId(); - uint16_t srcId = layer3.getSrcId(); - bool group = layer3.getGroup(); + lc::LC lc; + lc.decode(buffer, NXDN_FACCH1_LENGTH_BITS); + uint16_t dstId = lc.getDstId(); + uint16_t srcId = lc.getSrcId(); + bool group = lc.getGroup(); + bool encrypted = lc.getEncrypted(); - uint8_t type = layer3.getMessageType(); - if (type == MESSAGE_TYPE_TX_REL) { + uint8_t type = lc.getMessageType(); + if (type == RTCH_MESSAGE_TYPE_TX_REL) { if (m_nxdn->m_netState != RS_NET_AUDIO) { m_nxdn->m_netState = RS_NET_IDLE; m_nxdn->m_netMask = 0x00U; - m_nxdn->m_netLayer3.reset(); + m_nxdn->m_netLC.reset(); return false; } - } else if (type == MESSAGE_TYPE_VCALL) { - CHECK_NET_TRAFFIC_COLLISION(layer3, srcId, dstId); + } else if (type == RTCH_MESSAGE_TYPE_VCALL) { + CHECK_NET_TRAFFIC_COLLISION(lc, srcId, dstId); // validate source RID VALID_SRCID(srcId, dstId, group); @@ -626,7 +628,7 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, return false; } - m_nxdn->m_netLayer3 = layer3; + m_nxdn->m_netLC = lc; Sync::addNXDNSync(data + 2U); @@ -640,9 +642,9 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, // generate the SACCH channel::SACCH sacch; + sacch.setData(SACCH_IDLE); sacch.setRAN(m_nxdn->m_ran); sacch.setStructure(NXDN_SR_SINGLE); - sacch.setData(SACCH_IDLE); sacch.encode(data + 2U); facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); @@ -651,7 +653,7 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, m_nxdn->scrambler(data + 2U); if (m_nxdn->m_duplex) { - data[0U] = type == MESSAGE_TYPE_TX_REL ? modem::TAG_EOT : modem::TAG_DATA; + data[0U] = type == RTCH_MESSAGE_TYPE_TX_REL ? modem::TAG_EOT : modem::TAG_DATA; data[1U] = 0x00U; m_nxdn->addFrame(data, NXDN_FRAME_LENGTH_BYTES + 2U, true); @@ -671,7 +673,12 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, m_nxdn->m_netTimeout.start(); m_nxdn->m_netState = RS_NET_AUDIO; - ::ActivityLog("NXDN", false, "network voice transmission from %u to %s%u", srcId, group ? "TG " : "", dstId); + if (m_verbose) { + LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_VCALL ", srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%02X", + srcId, dstId, group, lc.getEmergency(), encrypted, lc.getPriority(), lc.getAlgId(), lc.getKId()); + } + + ::ActivityLog("NXDN", false, "network %svoice transmission from %u to %s%u", encrypted ? "encrypted " : "", srcId, group ? "TG " : "", dstId); } return true; @@ -700,14 +707,14 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, uint8_t buffer[10U]; facch.getData(buffer); - data::Layer3 layer3; - layer3.decode(buffer, NXDN_FACCH1_LENGTH_BITS); + lc::LC lc; + lc.decode(buffer, NXDN_FACCH1_LENGTH_BITS); - hasInfo = layer3.getMessageType() == MESSAGE_TYPE_VCALL; + hasInfo = lc.getMessageType() == RTCH_MESSAGE_TYPE_VCALL; if (!hasInfo) return false; - m_nxdn->m_netLayer3 = layer3; + m_nxdn->m_netLC = lc; } if (!hasInfo) { @@ -717,23 +724,23 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, uint8_t structure = sacch.getStructure(); switch (structure) { case NXDN_SR_1_4: - m_nxdn->m_netLayer3.decode(message, 18U, 0U); - if(m_nxdn->m_netLayer3.getMessageType() == MESSAGE_TYPE_VCALL) + m_nxdn->m_netLC.decode(message, 18U, 0U); + if(m_nxdn->m_netLC.getMessageType() == RTCH_MESSAGE_TYPE_VCALL) m_nxdn->m_netMask = 0x01U; else m_nxdn->m_netMask = 0x00U; break; case NXDN_SR_2_4: m_nxdn->m_netMask |= 0x02U; - m_nxdn->m_netLayer3.decode(message, 18U, 18U); + m_nxdn->m_netLC.decode(message, 18U, 18U); break; case NXDN_SR_3_4: m_nxdn->m_netMask |= 0x04U; - m_nxdn->m_netLayer3.decode(message, 18U, 36U); + m_nxdn->m_netLC.decode(message, 18U, 36U); break; case NXDN_SR_4_4: m_nxdn->m_netMask |= 0x08U; - m_nxdn->m_netLayer3.decode(message, 18U, 54U); + m_nxdn->m_netLC.decode(message, 18U, 54U); break; default: break; @@ -742,16 +749,17 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, if (m_nxdn->m_netMask != 0x0FU) return false; - uint8_t type = m_nxdn->m_netLayer3.getMessageType(); - if (type != MESSAGE_TYPE_VCALL) + uint8_t type = m_nxdn->m_netLC.getMessageType(); + if (type != RTCH_MESSAGE_TYPE_VCALL) return false; } - uint16_t dstId = m_nxdn->m_netLayer3.getDstId(); - uint16_t srcId = m_nxdn->m_netLayer3.getSrcId(); - bool group = m_nxdn->m_netLayer3.getGroup(); + uint16_t dstId = m_nxdn->m_netLC.getDstId(); + uint16_t srcId = m_nxdn->m_netLC.getSrcId(); + bool group = m_nxdn->m_netLC.getGroup(); + bool encrypted = m_nxdn->m_netLC.getEncrypted(); - CHECK_NET_TRAFFIC_COLLISION(m_nxdn->m_netLayer3, srcId, dstId); + CHECK_NET_TRAFFIC_COLLISION(m_nxdn->m_netLC, srcId, dstId); // validate source RID VALID_SRCID(srcId, dstId, group); @@ -765,7 +773,12 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, m_nxdn->m_netTimeout.start(); m_nxdn->m_netState = RS_NET_AUDIO; - ::ActivityLog("NXDN", false, "network late entry from %u to %s%u", srcId, group ? "TG " : "", dstId); + if (m_verbose) { + LogMessage(LOG_NET, NXDN_MESSAGE_TYPE_VCALL ", srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, algo = $%02X, kid = $%04X", + srcId, dstId, group, m_nxdn->m_netLC.getEmergency(), encrypted, m_nxdn->m_netLC.getPriority(), m_nxdn->m_netLC.getAlgId(), m_nxdn->m_netLC.getKId()); + } + + ::ActivityLog("NXDN", false, "network %slate entry from %u to %s%u", encrypted ? "encrypted ": "", srcId, group ? "TG " : "", dstId); // create a dummy start message uint8_t start[NXDN_FRAME_LENGTH_BYTES + 2U]; @@ -784,13 +797,13 @@ bool Voice::processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, // generate the SACCH channel::SACCH sacch; + sacch.setData(SACCH_IDLE); sacch.setRAN(m_nxdn->m_ran); sacch.setStructure(NXDN_SR_SINGLE); - sacch.setData(SACCH_IDLE); sacch.encode(start + 2U); uint8_t message[22U]; - m_nxdn->m_rfLayer3.getData(message); + m_nxdn->m_rfLC.getData(message); facch.setData(message); facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); @@ -965,5 +978,5 @@ void Voice::writeNetwork(const uint8_t *data, uint32_t len) if (m_nxdn->m_rfTimeout.isRunning() && m_nxdn->m_rfTimeout.hasExpired()) return; - m_network->writeNXDN(m_nxdn->m_rfLayer3, data, len); + m_network->writeNXDN(m_nxdn->m_rfLC, data, len); } diff --git a/nxdn/packet/Voice.h b/nxdn/packet/Voice.h index ea0ba4f8..ca6c9cc3 100644 --- a/nxdn/packet/Voice.h +++ b/nxdn/packet/Voice.h @@ -64,7 +64,7 @@ namespace nxdn /// Process a data frame from the RF interface. virtual bool process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len); /// Process a data frame from the network. - virtual bool processNetwork(uint8_t usc, uint8_t option, data::Layer3& netLayer3, uint8_t* data, uint32_t len); + virtual bool processNetwork(uint8_t usc, uint8_t option, lc::LC& netLC, uint8_t* data, uint32_t len); protected: friend class packet::Data;