diff --git a/configs/config.example.yml b/configs/config.example.yml index d9e0e06b..be6f6f2f 100644 --- a/configs/config.example.yml +++ b/configs/config.example.yml @@ -9,6 +9,7 @@ daemon: true # # Logging Configuration +# # Logging Levels: # 1 - Debug # 2 - Message @@ -392,6 +393,17 @@ system: # DMR/P25/NXDN Site ID. siteId: 1 + # + # CW ID Configuration + # + cwId: + # Flag indicating whether or not CWID is enabled. + enable: true + # Amount of time between CWID transmissions. (minutes) + time: 15 + # Callsign to be transmitted. + callsign: ABCD123 + # # Modem Configuration # @@ -525,17 +537,6 @@ system: # Flag indicating whether or not debug logging is enabled. debug: false - # - # CW ID Configuration - # - cwId: - # Flag indicating whether or not CWID is enabled. - enable: true - # Amount of time between CWID transmissions. (minutes) - time: 15 - # Callsign to be transmitted. - callsign: ABCD123 - # # Channel Identity Table Configuration # diff --git a/src/network/BaseNetwork.cpp b/src/network/BaseNetwork.cpp index f93112ae..84eb00a8 100644 --- a/src/network/BaseNetwork.cpp +++ b/src/network/BaseNetwork.cpp @@ -645,6 +645,8 @@ UInt8Array BaseNetwork::createDMR_Message(uint32_t& length, const uint32_t strea uint32_t slotNo = data.getSlotNo(); + buffer[14U] = 0U; // Control Bits + // Individual slot disabling if (slotNo == 1U && !m_slot1) return nullptr; @@ -685,52 +687,54 @@ UInt8Array BaseNetwork::createDMR_Message(uint32_t& length, const uint32_t strea /// /// Creates an P25 frame message header. /// -/// +/// /// /// /// /// -void BaseNetwork::createP25_MessageHdr(uint8_t* data, uint8_t duid, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, +void BaseNetwork::createP25_MessageHdr(uint8_t* buffer, uint8_t duid, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, uint8_t frameType) { - assert(data != nullptr); + assert(buffer != nullptr); // construct P25 message header - ::memcpy(data + 0U, TAG_P25_DATA, 4U); + ::memcpy(buffer + 0U, TAG_P25_DATA, 4U); - data[4U] = control.getLCO(); // LCO + buffer[4U] = control.getLCO(); // LCO uint32_t srcId = control.getSrcId(); // Source Address - __SET_UINT16(srcId, data, 5U); + __SET_UINT16(srcId, buffer, 5U); uint32_t dstId = control.getDstId(); // Target Address - __SET_UINT16(dstId, data, 8U); + __SET_UINT16(dstId, buffer, 8U); uint16_t sysId = control.getSiteData().sysId(); // System ID - data[11U] = (sysId >> 8) & 0xFFU; - data[12U] = (sysId >> 0) & 0xFFU; + buffer[11U] = (sysId >> 8) & 0xFFU; + buffer[12U] = (sysId >> 0) & 0xFFU; - data[15U] = control.getMFId(); // MFId + buffer[14U] = 0U; // Control Bits + + buffer[15U] = control.getMFId(); // MFId uint32_t netId = control.getSiteData().netId(); // Network ID - __SET_UINT16(netId, data, 16U); + __SET_UINT16(netId, buffer, 16U); - data[20U] = lsd.getLSD1(); // LSD 1 - data[21U] = lsd.getLSD2(); // LSD 2 + buffer[20U] = lsd.getLSD1(); // LSD 1 + buffer[21U] = lsd.getLSD2(); // LSD 2 - data[22U] = duid; // DUID + buffer[22U] = duid; // DUID if (frameType != p25::P25_FT_TERMINATOR) { - data[180U] = frameType; // DVM Frame Type + buffer[180U] = frameType; // DVM Frame Type } // is this the first frame of a call? if (frameType == p25::P25_FT_HDU_VALID) { - data[181U] = control.getAlgId(); // Algorithm ID + buffer[181U] = control.getAlgId(); // Algorithm ID uint32_t kid = control.getKId(); - data[182U] = (kid >> 8) & 0xFFU; // Key ID - data[183U] = (kid >> 0) & 0xFFU; + buffer[182U] = (kid >> 8) & 0xFFU; // Key ID + buffer[183U] = (kid >> 0) & 0xFFU; // copy MI data uint8_t mi[p25::P25_MI_LENGTH_BYTES]; @@ -742,7 +746,7 @@ void BaseNetwork::createP25_MessageHdr(uint8_t* data, uint8_t duid, const p25::l } for (uint8_t i = 0; i < p25::P25_MI_LENGTH_BYTES; i++) { - data[184U + i] = mi[i]; // Message Indicator + buffer[184U + i] = mi[i]; // Message Indicator } } } @@ -1043,6 +1047,8 @@ UInt8Array BaseNetwork::createNXDN_Message(uint32_t& length, const nxdn::lc::RTC uint32_t dstId = lc.getDstId(); // Target Address __SET_UINT16(dstId, buffer, 8U); + buffer[14U] = 0U; // Control Bits + buffer[15U] |= lc.getGroup() ? 0x00U : 0x40U; // Group // pack raw NXDN message bytes diff --git a/src/network/BaseNetwork.h b/src/network/BaseNetwork.h index d1088ce8..618bb56f 100644 --- a/src/network/BaseNetwork.h +++ b/src/network/BaseNetwork.h @@ -275,7 +275,7 @@ namespace network UInt8Array createDMR_Message(uint32_t& length, const uint32_t streamId, const dmr::data::Data& data); /// Creates an P25 frame message header. - void createP25_MessageHdr(uint8_t* data, uint8_t duid, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, + void createP25_MessageHdr(uint8_t* buffer, uint8_t duid, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, uint8_t frameType = p25::P25_FT_DATA_UNIT); /// Creates an P25 LDU1 frame message. diff --git a/src/p25/Control.cpp b/src/p25/Control.cpp index 4f7681e9..39c3a15d 100644 --- a/src/p25/Control.cpp +++ b/src/p25/Control.cpp @@ -1077,6 +1077,8 @@ void Control::processNetwork() return; } + bool grantDemand = (buffer[14U] & 0x80U) == 0x80U; + // process network message header uint8_t duid = buffer[22U]; uint8_t MFId = buffer[15U]; @@ -1218,11 +1220,30 @@ void Control::processNetwork() } break; } - ret = m_voice->processNetwork(data.get(), frameLength, control, lsd, duid, frameType); + + if (m_dedicatedControl && m_voiceOnControl) { + ret = m_voice->processNetwork(data.get(), frameLength, control, lsd, duid, frameType); + } break; case P25_DUID_TDU: case P25_DUID_TDULC: + // is this an TDU with a grant demand? + if (duid == P25_DUID_TDU && grantDemand) { + uint8_t serviceOptions = (control.getEmergency() ? 0x80U : 0x00U) + // Emergency Flag + (control.getEncrypted() ? 0x40U : 0x00U) + // Encrypted Flag + (control.getPriority() & 0x07U); // Priority + + if (m_verbose) { + LogMessage(LOG_NET, P25_TSDU_STR " remote grant demand, srcId = %u, dstId = %u", srcId, dstId); + } + + if (!m_trunk->writeRF_TSDU_Grant(srcId, dstId, serviceOptions, true, true)) { + LogError(LOG_NET, P25_TSDU_STR " call failure, network call not granted, dstId = %u", dstId); + return; + } + } + m_voice->processNetwork(data.get(), frameLength, control, lsd, duid, frameType); break;