diff --git a/dmr/acl/AccessControl.cpp b/dmr/acl/AccessControl.cpp
index 627db247..8c71500c 100644
--- a/dmr/acl/AccessControl.cpp
+++ b/dmr/acl/AccessControl.cpp
@@ -65,6 +65,11 @@ bool AccessControl::validateSrcId(uint32_t id)
{
// check if RID ACLs are enabled
if (m_ridLookup->getACL() == false) {
+ RadioId rid = m_ridLookup->find(id);
+ if (!rid.radioDefault() && !rid.radioEnabled()) {
+ return false;
+ }
+
return true;
}
diff --git a/p25/P25Defines.h b/p25/P25Defines.h
index 4225c6a9..160106ad 100644
--- a/p25/P25Defines.h
+++ b/p25/P25Defines.h
@@ -103,6 +103,7 @@ namespace p25
const uint32_t P25_PDU_FEC_LENGTH_BITS = P25_PDU_FEC_LENGTH_BYTES * 8U - 4U; // Trellis is actually 196 bits
const uint32_t P25_MI_LENGTH_BYTES = 9U;
+ const uint32_t P25_RAW_IMBE_LENGTH_BYTES = 11U;
const uint32_t P25_SS0_START = 70U;
const uint32_t P25_SS1_START = 71U;
diff --git a/p25/TrunkPacket.cpp b/p25/TrunkPacket.cpp
index cb61041f..1c2fa0b9 100644
--- a/p25/TrunkPacket.cpp
+++ b/p25/TrunkPacket.cpp
@@ -1530,7 +1530,7 @@ void TrunkPacket::writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite, bool f
// Generate TSBK block
m_rfTSBK.setLastBlock(true); // always set last block -- this a Single Block TSDU
- m_rfTSBK.encode(data + 2U, true);
+ m_rfTSBK.encode(data + 2U);
if (m_debug) {
Utils::dump(1U, "!!! *TSDU (SBF) TSBK Block Data", data + P25_PREAMBLE_LENGTH_BYTES + 2U, P25_TSBK_FEC_LENGTH_BYTES);
@@ -1602,7 +1602,7 @@ void TrunkPacket::writeRF_TSDU_MBF(bool clearBeforeWrite)
if (m_mbfCnt + 1U == TSBK_MBF_CNT) {
// Generate TSBK block
m_rfTSBK.setLastBlock(true); // set last block
- m_rfTSBK.encode(tsbk, false);
+ m_rfTSBK.encode(tsbk, true);
if (m_debug) {
Utils::dump(1U, "!!! *TSDU MBF Last TSBK Block", tsbk, P25_TSBK_FEC_LENGTH_BYTES);
@@ -1666,7 +1666,7 @@ void TrunkPacket::writeRF_TSDU_MBF(bool clearBeforeWrite)
// Generate TSBK block
m_rfTSBK.setLastBlock(false); // clear last block
- m_rfTSBK.encode(tsbk, false);
+ m_rfTSBK.encode(tsbk, true);
if (m_debug) {
Utils::dump(1U, "!!! *TSDU MBF Block Data", tsbk, P25_TSBK_FEC_LENGTH_BYTES);
@@ -2410,7 +2410,7 @@ void TrunkPacket::writeNet_TSDU_From_RF(uint8_t* data)
// Regenerate TSDU Data
m_rfTSBK.setLastBlock(true); // always set last block -- this a Single Block TSDU
- m_rfTSBK.encode(data, true);
+ m_rfTSBK.encode(data);
// Add busy bits
m_p25->addBusyBits(data, P25_TSDU_FRAME_LENGTH_BYTES, true, false);
@@ -2485,7 +2485,7 @@ void TrunkPacket::writeNet_TSDU()
// Regenerate TSDU Data
m_netTSBK.setLastBlock(true); // always set last block -- this a Single Block TSDU
- m_netTSBK.encode(buffer + 2U, true);
+ m_netTSBK.encode(buffer + 2U);
// Add busy bits
m_p25->addBusyBits(buffer + 2U, P25_TSDU_FRAME_LENGTH_BYTES, true, false);
diff --git a/p25/VoicePacket.cpp b/p25/VoicePacket.cpp
index 507d5d6c..7851471c 100644
--- a/p25/VoicePacket.cpp
+++ b/p25/VoicePacket.cpp
@@ -729,6 +729,18 @@ bool VoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
m_netLastLDU1 = control;
+ if (m_p25->m_netState == RS_NET_IDLE) {
+ // are we interrupting a running CC?
+ if (m_p25->m_ccRunning) {
+ g_interruptP25Control = true;
+ }
+
+ // single-channel trunking or voice on control support?
+ if (m_p25->m_control && m_p25->m_voiceOnControl) {
+ m_p25->m_ccRunning = false; // otherwise the grant will be bundled with other packets
+ }
+ }
+
checkNet_LDU2(control, lsd);
if (m_p25->m_netState != RS_NET_IDLE) {
writeNet_LDU1(control, lsd);
@@ -779,17 +791,9 @@ bool VoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
count += 16U;
if (m_p25->m_netState == RS_NET_IDLE) {
- // are we interrupting a running CC?
- if (m_p25->m_ccRunning) {
- g_interruptP25Control = true;
- }
-
- // single-channel trunking or voice on control support?
- if (m_p25->m_control && m_p25->m_voiceOnControl) {
- m_p25->m_ccRunning = false; // otherwise the grant will be bundled with other packets
+ if (!m_p25->m_voiceOnControl) {
+ m_p25->m_modem->clearP25Data();
}
-
- m_p25->m_modem->clearP25Data();
m_p25->m_queue.clear();
resetRF();
diff --git a/p25/acl/AccessControl.cpp b/p25/acl/AccessControl.cpp
index b598b635..9fc23a75 100644
--- a/p25/acl/AccessControl.cpp
+++ b/p25/acl/AccessControl.cpp
@@ -65,6 +65,11 @@ bool AccessControl::validateSrcId(uint32_t id)
{
// check if RID ACLs are enabled
if (m_ridLookup->getACL() == false) {
+ RadioId rid = m_ridLookup->find(id);
+ if (!rid.radioDefault() && !rid.radioEnabled()) {
+ return false;
+ }
+
return true;
}
diff --git a/p25/dfsi/DFSIDefines.h b/p25/dfsi/DFSIDefines.h
index 4707ab12..baaf0d41 100644
--- a/p25/dfsi/DFSIDefines.h
+++ b/p25/dfsi/DFSIDefines.h
@@ -73,6 +73,8 @@ namespace p25
const uint32_t P25_DFSI_TSBK_FRAME_LENGTH_BYTES = 25U;
+ const uint8_t P25_DFSI_STATUS = 0x02U; //
+
const uint8_t P25_DFSI_RT_ENABLED = 0x02U; //
const uint8_t P25_DFSI_RT_DISABLED = 0x04U; //
diff --git a/p25/dfsi/LC.cpp b/p25/dfsi/LC.cpp
index 59ba12ce..e73c6e4d 100644
--- a/p25/dfsi/LC.cpp
+++ b/p25/dfsi/LC.cpp
@@ -54,9 +54,11 @@ LC::LC() :
m_source(P25_DFSI_DEF_SOURCE),
m_control(),
m_tsbk(),
- m_lsd()
+ m_lsd(),
+ m_mi(NULL)
{
- /* stub */
+ m_mi = new uint8_t[P25_MI_LENGTH_BYTES];
+ ::memset(m_mi, 0x00U, P25_MI_LENGTH_BYTES);
}
///
@@ -64,7 +66,7 @@ LC::LC() :
///
LC::~LC()
{
- /* stub */
+ delete[] m_mi;
}
///
@@ -87,6 +89,13 @@ LC& LC::operator=(const LC& data)
m_control = data.m_control;
m_tsbk = data.m_tsbk;
m_lsd = data.m_lsd;
+
+ delete[] m_mi;
+
+ uint8_t* mi = new uint8_t[P25_MI_LENGTH_BYTES];
+ ::memcpy(mi, data.m_mi, P25_MI_LENGTH_BYTES);
+
+ m_mi = mi;
}
return *this;
@@ -135,6 +144,11 @@ bool LC::decodeVHDR1(const uint8_t* data)
assert(data != NULL);
m_frameType = data[0U]; // Frame Type
+ if (m_frameType != P25_DFSI_VHDR1) {
+ LogError(LOG_P25, "LC::decodeVHDR1(), invalid frametype, frameType = $%02X", m_frameType);
+ return false;
+ }
+
if (!decodeStart(data + 1U)) {
LogError(LOG_P25, "LC::decodeVHDR1(), failed to decode start record");
return false;
@@ -157,7 +171,7 @@ void LC::encodeVHDR1(uint8_t* data)
uint8_t rawFrame[P25_DFSI_VHDR1_FRAME_LENGTH_BYTES];
::memset(rawFrame, 0x00U, P25_DFSI_VHDR1_FRAME_LENGTH_BYTES);
- rawFrame[0U] = m_frameType; // Frame Type
+ rawFrame[0U] = P25_DFSI_VHDR1; // Frame Type
// encode start record
encodeStart(rawFrame + 1U);
@@ -179,6 +193,10 @@ bool LC::decodeVHDR2(const uint8_t* data)
m_control = lc::LC();
m_frameType = data[0U]; // Frame Type
+ if (m_frameType != P25_DFSI_VHDR2) {
+ LogError(LOG_P25, "LC::decodeVHDR2(), invalid frametype, frameType = $%02X", m_frameType);
+ return false;
+ }
uint32_t dstId = (data[1U] << 16) | (data[2U] << 8) | (data[3U] << 0);
m_control.setDstId(dstId); // Talkgroup Address
@@ -194,16 +212,17 @@ void LC::encodeVHDR2(uint8_t* data)
{
assert(data != NULL);
- uint8_t rawFrame[P25_DFSI_VHDR2_FRAME_LENGTH_BYTES];
- ::memset(rawFrame, 0x00U, P25_DFSI_VHDR2_FRAME_LENGTH_BYTES);
+ uint8_t dfsiFrame[P25_DFSI_VHDR2_FRAME_LENGTH_BYTES];
+ ::memset(dfsiFrame, 0x00U, P25_DFSI_VHDR2_FRAME_LENGTH_BYTES);
- rawFrame[0U] = m_frameType; // Frame Type
+ dfsiFrame[0U] = P25_DFSI_VHDR2; // Frame Type
- rawFrame[1U] = (m_control.getDstId() >> 16) & 0xFFU; // Talkgroup Address
- rawFrame[2U] = (m_control.getDstId() >> 8) & 0xFFU;
- rawFrame[3U] = (m_control.getDstId() >> 0) & 0xFFU;
+ uint32_t dstId = m_control.getDstId();
+ dfsiFrame[1U] = (dstId >> 16) & 0xFFU; // Talkgroup Address
+ dfsiFrame[2U] = (dstId >> 8) & 0xFFU;
+ dfsiFrame[3U] = (dstId >> 0) & 0xFFU;
- ::memcpy(data, rawFrame, P25_DFSI_VHDR2_FRAME_LENGTH_BYTES);
+ ::memcpy(data, dfsiFrame, P25_DFSI_VHDR2_FRAME_LENGTH_BYTES);
}
///
@@ -214,7 +233,87 @@ void LC::encodeVHDR2(uint8_t* data)
/// True, if decoded, otherwise false.
bool LC::decodeLDU1(const uint8_t* data, uint8_t* imbe)
{
- // TODO TODO TODO
+ assert(data != NULL);
+ assert(imbe != NULL);
+
+ m_frameType = data[0U]; // Frame Type
+
+ // different frame types mean different things
+ switch (m_frameType)
+ {
+ case P25_DFSI_LDU1_VOICE1:
+ {
+ m_control = p25::lc::LC();
+ m_lsd = p25::data::LowSpeedData();
+
+ decodeStart(data + 1U); // Start Record
+ m_icwFlag = data[5U]; // ICW Flag
+ m_rssi = data[6U]; // RSSI
+ ::memcpy(imbe, data + 10U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ m_source = data[21U]; // Source
+ }
+ break;
+ case P25_DFSI_LDU1_VOICE2:
+ {
+ ::memcpy(imbe, data + 1U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ m_source = data[12U]; // Source
+ }
+ break;
+ case P25_DFSI_LDU1_VOICE3:
+ {
+ m_control.setLCO(data[1U]); // LCO
+ m_control.setMFId(data[2U]); // MFId
+ uint8_t serviceOptions = (uint8_t)(data[3U]); // Service Options
+ m_control.setEmergency((serviceOptions & 0x80U) == 0x80U);
+ m_control.setEncrypted((serviceOptions & 0x40U) == 0x40U);
+ m_control.setPriority((serviceOptions & 0x07U));
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU1_VOICE4:
+ {
+ uint32_t dstId = (data[1U] << 16) | (data[2U] << 8) | (data[3U] << 0);
+ m_control.setDstId(dstId); // Talkgroup Address
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU1_VOICE5:
+ {
+ uint32_t srcId = (data[1U] << 16) | (data[2U] << 8) | (data[3U] << 0);
+ m_control.setSrcId(srcId); // Source Address
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU1_VOICE6:
+ {
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU1_VOICE7:
+ {
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU1_VOICE8:
+ {
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU1_VOICE9:
+ {
+ m_lsd.setLSD1(data[1U]); // LSD MSB
+ m_lsd.setLSD2(data[2U]); // LSD LSB
+ ::memcpy(imbe, data + 4U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ default:
+ {
+ LogError(LOG_P25, "LC::decodeLDU1(), invalid frametype, frameType = $%02X", m_frameType);
+ return false;
+ }
+ break;
+ }
+
return true;
}
@@ -226,11 +325,20 @@ bool LC::decodeLDU1(const uint8_t* data, uint8_t* imbe)
void LC::encodeLDU1(uint8_t* data, const uint8_t* imbe)
{
assert(data != NULL);
+ assert(imbe != NULL);
+
+ uint8_t serviceOptions =
+ (m_control.getEmergency() ? 0x80U : 0x00U) +
+ (m_control.getEncrypted() ? 0x40U : 0x00U) +
+ (m_control.getPriority() & 0x07U);
// determine the LDU1 DFSI frame length, its variable
uint32_t frameLength = P25_DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES;
switch (m_frameType)
{
+ case P25_DFSI_LDU1_VOICE1:
+ frameLength = P25_DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES;
+ break;
case P25_DFSI_LDU1_VOICE2:
frameLength = P25_DFSI_LDU1_VOICE2_FRAME_LENGTH_BYTES;
break;
@@ -255,61 +363,96 @@ void LC::encodeLDU1(uint8_t* data, const uint8_t* imbe)
case P25_DFSI_LDU1_VOICE9:
frameLength = P25_DFSI_LDU1_VOICE9_FRAME_LENGTH_BYTES;
break;
-
- case P25_DFSI_LDU1_VOICE1:
default:
- frameLength = P25_DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES;
+ {
+ LogError(LOG_P25, "LC::encodeLDU1(), invalid frametype, frameType = $%02X", m_frameType);
+ return;
+ }
break;
}
- uint8_t rawFrame[frameLength];
- ::memset(rawFrame, 0x00U, frameLength);
+ uint8_t dfsiFrame[frameLength];
+ ::memset(dfsiFrame, 0x00U, frameLength);
- rawFrame[0U] = m_frameType; // Frame Type
+ dfsiFrame[0U] = m_frameType; // Frame Type
// different frame types mean different things
switch (m_frameType)
{
case P25_DFSI_LDU1_VOICE2:
- // TODO TODO TODO
+ {
+ ::memcpy(dfsiFrame + 1U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[12U] = m_source; // Source
+ }
break;
case P25_DFSI_LDU1_VOICE3:
- // TODO TODO TODO
+ {
+ dfsiFrame[1U] = m_control.getLCO(); // LCO
+ dfsiFrame[2U] = m_control.getMFId(); // MFId
+ dfsiFrame[3U] = serviceOptions; // Service Options
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU1_VOICE4:
- // TODO TODO TODO
+ {
+ uint32_t dstId = m_control.getDstId();
+ dfsiFrame[1U] = (dstId >> 16) & 0xFFU; // Target Address
+ dfsiFrame[2U] = (dstId >> 8) & 0xFFU;
+ dfsiFrame[3U] = (dstId >> 0) & 0xFFU;
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU1_VOICE5:
- // TODO TODO TODO
+ {
+ uint32_t srcId = m_control.getSrcId();
+ dfsiFrame[1U] = (srcId >> 16) & 0xFFU; // Source Address
+ dfsiFrame[2U] = (srcId >> 8) & 0xFFU;
+ dfsiFrame[3U] = (srcId >> 0) & 0xFFU;
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU1_VOICE6:
- // TODO TODO TODO
+ {
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU1_VOICE7:
- // TODO TODO TODO
+ {
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU1_VOICE8:
- // TODO TODO TODO
+ {
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU1_VOICE9:
- // TODO TODO TODO
+ {
+ dfsiFrame[1U] = m_lsd.getLSD1(); // LSD MSB
+ dfsiFrame[2U] = m_lsd.getLSD2(); // LSD LSB
+ ::memcpy(dfsiFrame + 4U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
break;
case P25_DFSI_LDU1_VOICE1:
default:
{
- // encode start record
- encodeStart(rawFrame + 1U);
-
- rawFrame[5U] = m_icwFlag; // ICW Flag
- rawFrame[6U] = m_rssi; // RSSI
-
- // TODO TODO TODO
+ encodeStart(dfsiFrame + 1U); // Start Record
+ dfsiFrame[5U] = m_icwFlag; // ICW Flag
+ dfsiFrame[6U] = m_rssi; // RSSI
+ ::memcpy(dfsiFrame + 10U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[21U] = m_source; // Source
}
break;
}
- ::memcpy(data, rawFrame, frameLength);
+ ::memcpy(data, dfsiFrame, frameLength);
}
///
@@ -320,7 +463,89 @@ void LC::encodeLDU1(uint8_t* data, const uint8_t* imbe)
/// True, if decoded, otherwise false.
bool LC::decodeLDU2(const uint8_t* data, uint8_t* imbe)
{
- // TODO TODO TODO
+ assert(data != NULL);
+ assert(imbe != NULL);
+
+ m_frameType = data[0U]; // Frame Type
+
+ // different frame types mean different things
+ switch (m_frameType)
+ {
+ case P25_DFSI_LDU2_VOICE10:
+ {
+ ::memset(m_mi, 0x00U, P25_MI_LENGTH_BYTES);
+ m_lsd = p25::data::LowSpeedData();
+
+ decodeStart(data + 1U); // Start Record
+ m_icwFlag = data[5U]; // ICW Flag
+ m_rssi = data[6U]; // RSSI
+ ::memcpy(imbe, data + 10U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ m_source = data[21U]; // Source
+ }
+ break;
+ case P25_DFSI_LDU2_VOICE11:
+ {
+ ::memcpy(imbe, data + 1U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU2_VOICE12:
+ {
+ m_mi[0U] = data[1U]; // Message Indicator
+ m_mi[1U] = data[2U];
+ m_mi[2U] = data[3U];
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU2_VOICE13:
+ {
+ m_mi[3U] = data[1U]; // Message Indicator
+ m_mi[4U] = data[2U];
+ m_mi[5U] = data[3U];
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU2_VOICE14:
+ {
+ m_mi[6U] = data[1U]; // Message Indicator
+ m_mi[7U] = data[2U];
+ m_mi[8U] = data[3U];
+ m_control.setMI(m_mi);
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU2_VOICE15:
+ {
+ m_control.setAlgId(data[1U]); // Algorithm ID
+ uint32_t kid = (data[2U] << 8) | (data[3U] << 0); // Key ID
+ m_control.setKId(kid);
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU2_VOICE16:
+ {
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU2_VOICE17:
+ {
+ ::memcpy(imbe, data + 5U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ case P25_DFSI_LDU2_VOICE18:
+ {
+ m_lsd.setLSD1(data[1U]); // LSD MSB
+ m_lsd.setLSD2(data[2U]); // LSD LSB
+ ::memcpy(imbe, data + 4U, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
+ break;
+ default:
+ {
+ LogError(LOG_P25, "LC::decodeLDU1(), invalid frametype, frameType = $%02X", m_frameType);
+ return false;
+ }
+ break;
+ }
+
return true;
}
@@ -332,11 +557,19 @@ bool LC::decodeLDU2(const uint8_t* data, uint8_t* imbe)
void LC::encodeLDU2(uint8_t* data, const uint8_t* imbe)
{
assert(data != NULL);
+ assert(imbe != NULL);
+
+ // generate MI data
+ uint8_t mi[p25::P25_MI_LENGTH_BYTES];
+ m_control.getMI(mi);
// determine the LDU2 DFSI frame length, its variable
uint32_t frameLength = P25_DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES;
switch (m_frameType)
{
+ case P25_DFSI_LDU2_VOICE10:
+ frameLength = P25_DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES;
+ break;
case P25_DFSI_LDU2_VOICE11:
frameLength = P25_DFSI_LDU2_VOICE11_FRAME_LENGTH_BYTES;
break;
@@ -361,76 +594,138 @@ void LC::encodeLDU2(uint8_t* data, const uint8_t* imbe)
case P25_DFSI_LDU2_VOICE18:
frameLength = P25_DFSI_LDU2_VOICE18_FRAME_LENGTH_BYTES;
break;
-
- case P25_DFSI_LDU2_VOICE10:
default:
- frameLength = P25_DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES;
+ {
+ LogError(LOG_P25, "LC::encodeLDU1(), invalid frametype, frameType = $%02X", m_frameType);
+ return;
+ }
break;
}
+ uint8_t dfsiFrame[frameLength];
+ ::memset(dfsiFrame, 0x00U, frameLength);
- uint8_t rawFrame[frameLength];
- ::memset(rawFrame, 0x00U, frameLength);
-
- rawFrame[0U] = m_frameType; // Frame Type
+ dfsiFrame[0U] = m_frameType; // Frame Type
// different frame types mean different things
switch (m_frameType)
{
case P25_DFSI_LDU2_VOICE11:
- // TODO TODO TODO
+ {
+ ::memcpy(dfsiFrame + 1U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[12U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU2_VOICE12:
- // TODO TODO TODO
+ {
+ dfsiFrame[1U] = mi[0U]; // Message Indicator
+ dfsiFrame[2U] = mi[1U];
+ dfsiFrame[3U] = mi[2U];
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU2_VOICE13:
- // TODO TODO TODO
+ {
+ dfsiFrame[1U] = mi[3U]; // Message Indicator
+ dfsiFrame[2U] = mi[4U];
+ dfsiFrame[3U] = mi[5U];
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU2_VOICE14:
- // TODO TODO TODO
+ {
+ dfsiFrame[1U] = mi[6U]; // Message Indicator
+ dfsiFrame[2U] = mi[7U];
+ dfsiFrame[3U] = mi[8U];
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU2_VOICE15:
- // TODO TODO TODO
+ {
+ dfsiFrame[1U] = m_control.getAlgId(); // Algorithm ID
+ uint32_t kid = m_control.getKId();
+ dfsiFrame[2U] = (kid >> 8) & 0xFFU; // Key ID
+ dfsiFrame[3U] = (kid >> 0) & 0xFFU;
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU2_VOICE16:
- // TODO TODO TODO
+ {
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU2_VOICE17:
- // TODO TODO TODO
+ {
+ ::memcpy(dfsiFrame + 5U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[16U] = P25_DFSI_STATUS; // Status
+ }
break;
case P25_DFSI_LDU2_VOICE18:
- // TODO TODO TODO
+ {
+ dfsiFrame[1U] = m_lsd.getLSD1(); // LSD MSB
+ dfsiFrame[2U] = m_lsd.getLSD2(); // LSD LSB
+ ::memcpy(dfsiFrame + 4U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ }
break;
case P25_DFSI_LDU2_VOICE10:
default:
- // TODO TODO TODO
+ {
+ encodeStart(dfsiFrame + 1U); // Start Record
+ dfsiFrame[5U] = m_icwFlag; // ICW Flag
+ dfsiFrame[6U] = m_rssi; // RSSI
+ ::memcpy(dfsiFrame + 10U, imbe, P25_RAW_IMBE_LENGTH_BYTES); // IMBE
+ dfsiFrame[21U] = m_source; // Source
+ }
break;
}
- ::memcpy(data, rawFrame, frameLength);
+ ::memcpy(data, dfsiFrame, frameLength);
}
///
/// Decode a logical link data unit 2.
///
///
-///
/// True, if decoded, otherwise false.
bool LC::decodeTSBK(const uint8_t* data)
{
- // TODO TODO TODO
- return true;
+ assert(data != NULL);
+ m_tsbk = lc::TSBK();
+
+ m_frameType = data[0U]; // Frame Type
+ if (m_frameType != P25_DFSI_TSBK) {
+ LogError(LOG_P25, "LC::decodeTSBK(), invalid frametype, frameType = $%02X", m_frameType);
+ return false;
+ }
+
+ decodeStart(data + 1U); // Start Record
+
+ uint8_t tsbk[P25_TSBK_LENGTH_BYTES];
+ ::memcpy(tsbk, data + 9U, P25_TSBK_LENGTH_BYTES); // Raw TSBK + CRC
+ return m_tsbk.decode(tsbk, true);
}
///
/// Encode a TSBK.
///
///
-///
-void LC::encodeTSBK(uint8_t* data, const uint8_t* tsbk)
+void LC::encodeTSBK(uint8_t* data)
{
- // TODO TODO TODO
+ uint8_t tsbk[P25_TSBK_LENGTH_BYTES];
+ m_tsbk.encode(tsbk, true, true);
+
+ uint8_t dfsiFrame[P25_DFSI_TSBK_FRAME_LENGTH_BYTES];
+ ::memset(dfsiFrame, 0x00U, P25_DFSI_TSBK_FRAME_LENGTH_BYTES);
+
+ dfsiFrame[0U] = P25_DFSI_TSBK; // Frame Type
+ encodeStart(dfsiFrame + 1U); // Start Record
+ ::memcpy(dfsiFrame + 9U, tsbk, P25_TSBK_LENGTH_BYTES); // Raw TSBK + CRC
}
// ---------------------------------------------------------------------------
@@ -445,9 +740,9 @@ bool LC::decodeStart(const uint8_t* data)
{
assert(data != NULL);
- m_rtModeFlag = data[1U]; // RT Mode Flag
- m_startStopFlag = data[2U]; // Start/Stop Flag
- m_typeFlag = data[3U]; // Type Flag
+ m_rtModeFlag = data[0U]; // RT Mode Flag
+ m_startStopFlag = data[1U]; // Start/Stop Flag
+ m_typeFlag = data[2U]; // Type Flag
return true;
}
diff --git a/p25/dfsi/LC.h b/p25/dfsi/LC.h
index 2407d6ee..4d3e522c 100644
--- a/p25/dfsi/LC.h
+++ b/p25/dfsi/LC.h
@@ -80,7 +80,7 @@ namespace p25
/// Decode a TSBK.
bool decodeTSBK(const uint8_t* data);
/// Encode a TSBK.
- void encodeTSBK(uint8_t* data, const uint8_t* tsbk);
+ void encodeTSBK(uint8_t* data);
public:
/** Common Data */
@@ -109,6 +109,9 @@ namespace p25
__PROPERTY(p25::data::LowSpeedData, lsd, LSD);
private:
+ /** Encryption data */
+ uint8_t* m_mi;
+
/// Decode start record data.
bool decodeStart(const uint8_t* data);
/// Encode start record data.
diff --git a/p25/lc/TSBK.cpp b/p25/lc/TSBK.cpp
index 2fc802be..e6d20936 100644
--- a/p25/lc/TSBK.cpp
+++ b/p25/lc/TSBK.cpp
@@ -294,7 +294,7 @@ bool TSBK::decodeMBT(const data::DataHeader dataHeader, const uint8_t* block)
m_response = (uint8_t)((tsbkValue >> 48) & 0xFFU); // Reason
m_netId = (uint32_t)((tsbkValue >> 20) & 0xFFFFFU); // Network ID
m_sysId = (uint32_t)((tsbkValue >> 8) & 0xFFFU); // System ID
- m_dstId = (uint32_t)(((tsbkValue) & 0xFFU) << 16 + // Target Radio Address
+ m_dstId = (uint32_t)((((tsbkValue) & 0xFFU) << 16) + // Target Radio Address
(block[6U] << 8) + (block[7U]));
m_srcId = dataHeader.getLLId(); // Source Radio Address
break;
@@ -316,43 +316,60 @@ bool TSBK::decodeMBT(const data::DataHeader dataHeader, const uint8_t* block)
/// Decode a trunking signalling block.
///
///
+///
/// True, if TSBK was decoded, otherwise false.
-bool TSBK::decode(const uint8_t* data)
+bool TSBK::decode(const uint8_t* data, bool rawTSBK)
{
assert(data != NULL);
- // deinterleave
uint8_t tsbk[P25_TSBK_LENGTH_BYTES + 1U];
- uint8_t raw[P25_TSBK_FEC_LENGTH_BYTES];
- P25Utils::decode(data, raw, 114U, 318U);
-
- // decode 1/2 rate Trellis & check CRC-CCITT 16
- try {
- bool ret = m_trellis.decode12(raw, tsbk);
+ if (rawTSBK) {
+ ::memcpy(tsbk, data, P25_TSBK_LENGTH_BYTES);
+
+ bool ret = edac::CRC::checkCCITT162(tsbk, P25_TSBK_LENGTH_BYTES);
if (!ret) {
- LogError(LOG_P25, "TSBK::decode(), failed to decode Trellis 1/2 rate coding");
+ if (m_warnCRC) {
+ LogWarning(LOG_P25, "TSBK::decode(), failed CRC CCITT-162 check");
+ ret = true; // ignore CRC error
+ }
+ else {
+ LogError(LOG_P25, "TSBK::decode(), failed CRC CCITT-162 check");
+ }
}
+ }
+ else {
+ // deinterleave
+ uint8_t raw[P25_TSBK_FEC_LENGTH_BYTES];
+ P25Utils::decode(data, raw, 114U, 318U);
- if (ret) {
- ret = edac::CRC::checkCCITT162(tsbk, P25_TSBK_LENGTH_BYTES);
+ // decode 1/2 rate Trellis & check CRC-CCITT 16
+ try {
+ bool ret = m_trellis.decode12(raw, tsbk);
if (!ret) {
- if (m_warnCRC) {
- LogWarning(LOG_P25, "TSBK::decode(), failed CRC CCITT-162 check");
- ret = true; // ignore CRC error
- }
- else {
- LogError(LOG_P25, "TSBK::decode(), failed CRC CCITT-162 check");
+ LogError(LOG_P25, "TSBK::decode(), failed to decode Trellis 1/2 rate coding");
+ }
+
+ if (ret) {
+ ret = edac::CRC::checkCCITT162(tsbk, P25_TSBK_LENGTH_BYTES);
+ if (!ret) {
+ if (m_warnCRC) {
+ LogWarning(LOG_P25, "TSBK::decode(), failed CRC CCITT-162 check");
+ ret = true; // ignore CRC error
+ }
+ else {
+ LogError(LOG_P25, "TSBK::decode(), failed CRC CCITT-162 check");
+ }
}
}
- }
- if (!ret)
+ if (!ret)
+ return false;
+ }
+ catch (...) {
+ Utils::dump(2U, "P25, decoding excepted with input data", tsbk, P25_TSBK_LENGTH_BYTES);
return false;
- }
- catch (...) {
- Utils::dump(2U, "P25, decoding excepted with input data", tsbk, P25_TSBK_LENGTH_BYTES);
- return false;
- }
+ }
+ }
if (m_verbose) {
Utils::dump(2U, "Decoded TSBK", tsbk, P25_TSBK_LENGTH_BYTES);
@@ -574,7 +591,9 @@ bool TSBK::decode(const uint8_t* data)
/// Encode a trunking signalling block.
///
///
-void TSBK::encode(uint8_t * data, bool singleBlock)
+///
+///
+void TSBK::encode(uint8_t * data, bool rawTSBK, bool noTrellis)
{
assert(data != NULL);
@@ -1040,16 +1059,21 @@ void TSBK::encode(uint8_t * data, bool singleBlock)
// encode 1/2 rate Trellis
m_trellis.encode12(tsbk, raw);
- // is this a single block TSBK?
- if (singleBlock) {
+ // are we encoding a raw TSBK?
+ if (rawTSBK) {
+ if (noTrellis) {
+ ::memcpy(data, tsbk, P25_TSBK_LENGTH_BYTES);
+ }
+ else {
+ ::memcpy(data, raw, P25_TSBK_FEC_LENGTH_BYTES);
+ }
+ }
+ else {
// interleave
P25Utils::encode(raw, data, 114U, 318U);
// Utils::dump(2U, "TSBK Interleave", data, P25_TSBK_FEC_LENGTH_BYTES + P25_PREAMBLE_LENGTH_BYTES);
}
- else {
- ::memcpy(data, raw, P25_TSBK_FEC_LENGTH_BYTES);
- }
}
///
diff --git a/p25/lc/TSBK.h b/p25/lc/TSBK.h
index fa6bf474..122fd908 100644
--- a/p25/lc/TSBK.h
+++ b/p25/lc/TSBK.h
@@ -81,9 +81,9 @@ namespace p25
bool decodeMBT(const data::DataHeader dataHeader, const uint8_t* block);
/// Decode a trunking signalling block.
- bool decode(const uint8_t* data);
+ bool decode(const uint8_t* data, bool rawTSBK = false);
/// Encode a trunking signalling block.
- void encode(uint8_t* data, bool singleBlock);
+ void encode(uint8_t* data, bool rawTSBK = false, bool noTrellis = false);
/// Sets the flag to skip vendor opcode processing.
void setVendorSkip(bool skip);