correct bad handling for signal and compact fields of the TIA-102 control octet; enhance how the length of a TIA-102 full rate voice frame is determined; better handle initialization of the additional data fields for a TIA-102 full rate voice frame; correct bug using LDU2 frame 10 vs LDU2 frame 18 for LSD data on a full rate voice frame; implement a naive approach to performing superframe counting; correct bug causing the first full rate voice frames to never be transmitted for LDU1 or LDU2; remove assertion check for control port;

82-dvmbridge---implement-notch-filter-for-2175hz-trc-guard-tone
Bryan Biedenkapp 1 year ago
parent 95a8d269be
commit a82f848de4

@ -49,8 +49,8 @@ bool ControlOctet::decode(const uint8_t* data)
{ {
assert(data != nullptr); assert(data != nullptr);
m_signal = (data[0U] & 0x07U) == 0x07U; // Signal Flag m_signal = (data[0U] & 0x80U) == 0x80U; // Signal Flag
m_compact = (data[0U] & 0x06U) == 0x06U; // Compact Flag m_compact = (data[0U] & 0x40U) == 0x40U; // Compact Flag
m_blockHeaderCnt = (uint8_t)(data[0U] & 0x3FU); // Block Header Count m_blockHeaderCnt = (uint8_t)(data[0U] & 0x3FU); // Block Header Count
return true; return true;
@ -62,7 +62,7 @@ void ControlOctet::encode(uint8_t* data)
{ {
assert(data != nullptr); assert(data != nullptr);
data[0U] = (uint8_t)((m_signal ? 0x07U : 0x00U) + // Signal Flag data[0U] = (uint8_t)((m_signal ? 0x80U : 0x00U) + // Signal Flag
(m_compact ? 0x06U : 0x00U) + // Control Flag (m_compact ? 0x40U : 0x00U) + // Control Flag
(m_blockHeaderCnt & 0x3F)); (m_blockHeaderCnt & 0x3F));
} }

@ -38,6 +38,8 @@ FullRateVoice::FullRateVoice() :
{ {
imbeData = new uint8_t[IMBE_BUF_LEN]; imbeData = new uint8_t[IMBE_BUF_LEN];
::memset(imbeData, 0x00U, IMBE_BUF_LEN); ::memset(imbeData, 0x00U, IMBE_BUF_LEN);
additionalData = new uint8_t[ADDITIONAL_LENGTH];
::memset(additionalData, 0x00U, ADDITIONAL_LENGTH);
} }
/* Initializes a instance of the FullRateVoice class. */ /* Initializes a instance of the FullRateVoice class. */
@ -65,6 +67,21 @@ FullRateVoice::~FullRateVoice()
delete[] additionalData; delete[] additionalData;
} }
/* */
uint8_t FullRateVoice::getLength()
{
if (isVoice9or18()) {
return LENGTH_918;
}
if (isVoice3thru8() || isVoice12thru17()) {
return LENGTH;
}
return LENGTH_121011;
}
/* Decode a full rate voice frame. */ /* Decode a full rate voice frame. */
bool FullRateVoice::decode(const uint8_t* data) bool FullRateVoice::decode(const uint8_t* data)
@ -85,25 +102,14 @@ bool FullRateVoice::decode(const uint8_t* data)
m_superframeCnt = (uint8_t)((data[13U] >> 2) & 0x03U); // Superframe Counter m_superframeCnt = (uint8_t)((data[13U] >> 2) & 0x03U); // Superframe Counter
m_busy = (uint8_t)(data[13U] & 0x03U); m_busy = (uint8_t)(data[13U] & 0x03U);
if (isVoice3thru8() || isVoice12thru17() || isVoice9or10()) { if (isVoice3thru8() || isVoice12thru17() || isVoice9or18()) {
if (additionalData != nullptr)
delete additionalData;
additionalData = new uint8_t[ADDITIONAL_LENGTH];
::memset(additionalData, 0x00U, ADDITIONAL_LENGTH); ::memset(additionalData, 0x00U, ADDITIONAL_LENGTH);
if (isVoice9or10()) { if (isVoice9or18()) {
// CAI 9 and 10 are 3 bytes of additional data not 4 // CAI 9 and 18 are 3 bytes of additional data not 4
::memcpy(additionalData, data + 14U, ADDITIONAL_LENGTH - 1U); ::memcpy(additionalData, data + 14U, ADDITIONAL_LENGTH - 1U);
} else { } else {
uint8_t buffer[ADDITIONAL_LENGTH - 1U]; ::memcpy(additionalData, data + 14U, ADDITIONAL_LENGTH);
::memset(buffer, 0x00U, ADDITIONAL_LENGTH - 1U);
::memcpy(buffer, data + 14U, ADDITIONAL_LENGTH - 1U);
buffer[2U] &= 0xC0U; // mask low bits
uint32_t offset = 0;
for (uint8_t i = 0; i < ADDITIONAL_LENGTH - 1U; i++, offset += 6) {
Utils::hex2Bin(additionalData[i], buffer, offset);
}
} }
} else { } else {
if (additionalData != nullptr) if (additionalData != nullptr)
@ -130,22 +136,12 @@ void FullRateVoice::encode(uint8_t* data)
data[13U] = (uint8_t)(((m_superframeCnt & 0x03U) << 2) + // Superframe Count data[13U] = (uint8_t)(((m_superframeCnt & 0x03U) << 2) + // Superframe Count
(m_busy & 0x03U)); // Busy Status (m_busy & 0x03U)); // Busy Status
if ((isVoice3thru8() || isVoice12thru17() || isVoice9or10()) && if (isVoice3thru8() || isVoice12thru17() || isVoice9or18()) {
additionalData != nullptr) { if (isVoice9or18()) {
if (isVoice9or10()) { // CAI 9 and 18 are 3 bytes of additional data not 4
// CAI 9 and 10 are 3 bytes of additional data not 4
::memcpy(data + 14U, additionalData, ADDITIONAL_LENGTH - 1U); ::memcpy(data + 14U, additionalData, ADDITIONAL_LENGTH - 1U);
} else { } else {
uint8_t buffer[ADDITIONAL_LENGTH - 1U]; ::memcpy(data + 14U, additionalData, ADDITIONAL_LENGTH);
::memset(buffer, 0x00U, ADDITIONAL_LENGTH - 1U);
::memcpy(buffer, additionalData, ADDITIONAL_LENGTH - 1U);
uint32_t offset = 0;
for (uint8_t i = 0; i < ADDITIONAL_LENGTH - 1U; i++, offset += 6) {
buffer[i] = Utils::bin2Hex(additionalData, offset);
}
::memcpy(data + 14U, buffer, ADDITIONAL_LENGTH - 1U);
} }
} }
} }
@ -180,9 +176,9 @@ bool FullRateVoice::isVoice12thru17()
/* Helper indicating if the frame is voice 9 or 10. */ /* Helper indicating if the frame is voice 9 or 10. */
bool FullRateVoice::isVoice9or10() bool FullRateVoice::isVoice9or18()
{ {
if ( (m_frameType == DFSIFrameType::LDU1_VOICE9) || (m_frameType == DFSIFrameType::LDU2_VOICE10) ) { if ( (m_frameType == DFSIFrameType::LDU1_VOICE9) || (m_frameType == DFSIFrameType::LDU2_VOICE18) ) {
return true; return true;
} else { } else {
return false; return false;

@ -37,6 +37,7 @@ namespace p25
* @brief Implements a P25 full rate voice packet. * @brief Implements a P25 full rate voice packet.
* \code{.unparsed} * \code{.unparsed}
* CAI Frames 1, 2, 10 and 11. * CAI Frames 1, 2, 10 and 11.
* 14 bytes
* *
* Byte 0 1 2 3 * Byte 0 1 2 3
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 * Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
@ -52,6 +53,7 @@ namespace p25
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* *
* CAI Frames 3 - 8. * CAI Frames 3 - 8.
* 18 bytes
* *
* Byte 0 1 2 3 * Byte 0 1 2 3
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 * Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
@ -69,6 +71,7 @@ namespace p25
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* *
* CAI Frames 12 - 17. * CAI Frames 12 - 17.
* 18 bytes
* *
* Byte 0 1 2 3 * Byte 0 1 2 3
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 * Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
@ -86,6 +89,7 @@ namespace p25
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* *
* CAI Frames 9 and 10. * CAI Frames 9 and 10.
* 17 bytes
* *
* Byte 0 1 2 3 * Byte 0 1 2 3
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 * Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
@ -108,6 +112,7 @@ namespace p25
* the layout with 8-bit aligned IMBE blocks instead of message vectors: * the layout with 8-bit aligned IMBE blocks instead of message vectors:
* *
* CAI Frames 1, 2, 10 and 11. * CAI Frames 1, 2, 10 and 11.
* 14 bytes
* *
* Byte 0 1 2 3 * Byte 0 1 2 3
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 * Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
@ -123,6 +128,7 @@ namespace p25
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* *
* CAI Frames 3 - 8. * CAI Frames 3 - 8.
* 18 bytes
* *
* Byte 0 1 2 3 * Byte 0 1 2 3
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 * Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
@ -140,6 +146,7 @@ namespace p25
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* *
* CAI Frames 12 - 17. * CAI Frames 12 - 17.
* 18 bytes
* *
* Byte 0 1 2 3 * Byte 0 1 2 3
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 * Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
@ -156,7 +163,8 @@ namespace p25
* |Syn|R| Status | Rsvd | * |Syn|R| Status | Rsvd |
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* *
* CAI Frames 9 and 10. * CAI Frames 9 and 18.
* 17 bytes
* *
* Byte 0 1 2 3 * Byte 0 1 2 3
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 * Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
@ -177,6 +185,9 @@ namespace p25
*/ */
class HOST_SW_API FullRateVoice { class HOST_SW_API FullRateVoice {
public: public:
static const uint8_t LENGTH_121011 = 14U;
static const uint8_t LENGTH_918 = 17U;
static const uint8_t LENGTH = 18U; static const uint8_t LENGTH = 18U;
static const uint8_t ADDITIONAL_LENGTH = 4U; static const uint8_t ADDITIONAL_LENGTH = 4U;
static const uint8_t IMBE_BUF_LEN = 11U; static const uint8_t IMBE_BUF_LEN = 11U;
@ -195,9 +206,16 @@ namespace p25
*/ */
~FullRateVoice(); ~FullRateVoice();
/**
* @brief
* @returns uint8_t
*/
uint8_t getLength();
/** /**
* @brief Decode a full rate voice frame. * @brief Decode a full rate voice frame.
* @param[in] data Buffer to containing FullRateVoice to decode. * @param[in] data Buffer to containing FullRateVoice to decode.
* @returns bool
*/ */
bool decode(const uint8_t* data); bool decode(const uint8_t* data);
/** /**
@ -247,10 +265,10 @@ namespace p25
*/ */
bool isVoice12thru17(); bool isVoice12thru17();
/** /**
* @brief Helper indicating if the frame is voice 9 or 10. * @brief Helper indicating if the frame is voice 9 or 18.
* @returns bool True, if frame is voice 9, or 10, otherwise false. * @returns bool True, if frame is voice 9, or 18, otherwise false.
*/ */
bool isVoice9or10(); bool isVoice9or18();
}; };
} // namespace frames } // namespace frames
} // namespace dfsi } // namespace dfsi

@ -585,7 +585,7 @@ bool Host::createModem()
LogInfo(" DFSI Use FSC: %s", useFSCForUDP ? "yes" : "no"); LogInfo(" DFSI Use FSC: %s", useFSCForUDP ? "yes" : "no");
LogInfo(" DFSI FSC Heartbeat: %us", fscHeartbeat); LogInfo(" DFSI FSC Heartbeat: %us", fscHeartbeat);
LogInfo(" DFSI FSC Initiator: %s", fscInitiator ? "yes" : "no"); LogInfo(" DFSI FSC Initiator: %s", fscInitiator ? "yes" : "no");
LogInfo(" DFSI FSC TIA Frames: %s", dfsiTIAMode ? "yes" : "no"); LogInfo(" DFSI TIA-102 Frames: %s", dfsiTIAMode ? "yes" : "no");
} }
} }

@ -44,6 +44,7 @@ ModemV24::ModemV24(port::IModemPort* port, bool duplex, uint32_t p25QueueSize, u
false, false, dumpModemStatus, trace, debug), false, false, dumpModemStatus, trace, debug),
m_rtrt(rtrt), m_rtrt(rtrt),
m_diu(diu), m_diu(diu),
m_superFrameCnt(0U),
m_audio(), m_audio(),
m_nid(nullptr), m_nid(nullptr),
m_txP25Queue(p25TxQueueSize, "TX P25 Queue"), m_txP25Queue(p25TxQueueSize, "TX P25 Queue"),
@ -1253,6 +1254,7 @@ void ModemV24::convertToAirTIA(const uint8_t *data, uint32_t length)
case BlockType::FULL_RATE_VOICE: case BlockType::FULL_RATE_VOICE:
{ {
FullRateVoice voice = FullRateVoice(); FullRateVoice voice = FullRateVoice();
//m_superFrameCnt = voice.getSuperframeCnt();
voice.decode(dfsiData + dataOffs); voice.decode(dfsiData + dataOffs);
DFSIFrameType::E frameType = voice.getFrameType(); DFSIFrameType::E frameType = voice.getFrameType();
@ -1742,6 +1744,7 @@ uint16_t ModemV24::generateNID(DUID::E duid)
void ModemV24::startOfStreamTIA(const p25::lc::LC& control) void ModemV24::startOfStreamTIA(const p25::lc::LC& control)
{ {
m_txCallInProgress = true; m_txCallInProgress = true;
m_superFrameCnt = 0U;
p25::lc::LC lc = p25::lc::LC(control); p25::lc::LC lc = p25::lc::LC(control);
@ -1864,6 +1867,8 @@ void ModemV24::startOfStreamTIA(const p25::lc::LC& control)
void ModemV24::endOfStreamTIA() void ModemV24::endOfStreamTIA()
{ {
m_superFrameCnt = 0U;
uint16_t length = 0U; uint16_t length = 0U;
uint8_t buffer[2U]; uint8_t buffer[2U];
::memset(buffer, 0x00U, 2U); ::memset(buffer, 0x00U, 2U);
@ -2474,37 +2479,24 @@ void ModemV24::convertFromAirTIA(uint8_t* data, uint32_t length)
break; break;
} }
// For n=0 (VHDR1/10) case we create the buffer in the switch, for all other frame types we do that here buffer = new uint8_t[P25_PDU_FRAME_LENGTH_BYTES];
if (n != 0) { ::memset(buffer, 0x00U, P25_PDU_FRAME_LENGTH_BYTES);
buffer = new uint8_t[P25_PDU_FRAME_LENGTH_BYTES];
::memset(buffer, 0x00U, P25_PDU_FRAME_LENGTH_BYTES); // generate control octet
ControlOctet ctrl = ControlOctet();
// generate control octet ctrl.setBlockHeaderCnt(1U);
ControlOctet ctrl = ControlOctet(); ctrl.encode(buffer);
ctrl.setBlockHeaderCnt(2U); bufferSize += ControlOctet::LENGTH;
ctrl.encode(buffer);
bufferSize += ControlOctet::LENGTH; // generate block header
BlockHeader hdr = BlockHeader();
// generate block header hdr.setBlockType(BlockType::FULL_RATE_VOICE);
BlockHeader hdr = BlockHeader(); hdr.encode(buffer + 1U);
hdr.setBlockType(BlockType::FULL_RATE_VOICE); bufferSize += BlockHeader::LENGTH;
hdr.encode(buffer + 1U);
bufferSize += BlockHeader::LENGTH; voice.setSuperframeCnt(m_superFrameCnt);
voice.encode(buffer + bufferSize);
// generate block header bufferSize += voice.getLength(); // 18, 17 or 14 depending on voice frame type
hdr.setBlockType(BlockType::START_OF_STREAM);
hdr.encode(buffer + 2U);
bufferSize += BlockHeader::LENGTH;
voice.encode(buffer + bufferSize);
bufferSize += FullRateVoice::LENGTH;
// generate start of stream
StartOfStream start = StartOfStream();
start.setNID(generateNID());
start.encode(buffer + bufferSize);
bufferSize += StartOfStream::LENGTH;
}
if (buffer != nullptr) { if (buffer != nullptr) {
if (m_trace) { if (m_trace) {
@ -2515,5 +2507,14 @@ void ModemV24::convertFromAirTIA(uint8_t* data, uint32_t length)
delete[] buffer; delete[] buffer;
} }
} }
// bryanb: this is a naive way of incrementing the superframe counter, we basically just increment it after
// processing and LDU2
if (duid == DUID::LDU2) {
if (m_superFrameCnt == 255U)
m_superFrameCnt = 0U;
else
m_superFrameCnt++;
}
} }
} }

@ -302,6 +302,8 @@ namespace modem
bool m_rtrt; bool m_rtrt;
bool m_diu; bool m_diu;
uint8_t m_superFrameCnt;
p25::Audio m_audio; p25::Audio m_audio;
p25::NID* m_nid; p25::NID* m_nid;

@ -79,7 +79,6 @@ V24UDPPort::V24UDPPort(uint32_t peerId, const std::string& address, uint16_t mod
assert(peerId > 0U); assert(peerId > 0U);
assert(!address.empty()); assert(!address.empty());
assert(modemPort > 0U); assert(modemPort > 0U);
assert(controlPort > 0U);
if (controlPort > 0U && useFSC) { if (controlPort > 0U && useFSC) {
m_controlSocket = new Socket(controlPort); m_controlSocket = new Socket(controlPort);

Loading…
Cancel
Save

Powered by TurnKey Linux.