diff --git a/NXDNControl.cpp b/NXDNControl.cpp index cb697ba..74b2991 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -63,7 +63,7 @@ m_rfBits(1U), m_netErrs(0U), m_netBits(1U), m_rfLastLICH(), -m_rfSACCHMessage(), +m_rfLayer3(), m_rfMask(0x00U), m_netN(0U), m_rssiMapper(rssiMapper), @@ -103,13 +103,9 @@ bool CNXDNControl::writeModem(unsigned char *data, unsigned int len) return false; } - if (type == TAG_LOST && m_rfState == RS_RF_REJECTED) { - m_rfState = RS_RF_LISTENING; - return false; - } - if (type == TAG_LOST) { m_rfState = RS_RF_LISTENING; + m_rfMask = 0x00U; return false; } @@ -180,11 +176,117 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne return false; } - // if (m_rfState == RS_RF_LISTENING && !valid) - // return false; + // XXX Reconstruct invalid LICH - // XXX the FACCH1 data in the header may also be useful - if (m_rfState == RS_RF_LISTENING) { + if (usc == NXDN_LICH_USC_SACCH_NS) { + // The SACCH on a non-superblock frame is usually an idle and not interesting apart from the RAN. + CNXDNFACCH1 facch11; + bool valid1 = facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + + CNXDNFACCH1 facch12; + bool valid2 = facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + + unsigned char buffer[10U]; + if (valid1) + facch11.getData(buffer); + else if (valid2) + facch12.getData(buffer); + + if (valid1 || valid2) { + CNXDNLayer3 layer3; + layer3.decode(buffer, NXDN_FACCH1_LENGTH_BITS); + + unsigned char type = layer3.getMessageType(); + if (type == NXDN_MESSAGE_TYPE_TX_REL) { + if (m_rfState != RS_RF_AUDIO) { + m_rfState = RS_RF_LISTENING; + m_rfMask = 0x00U; + return false; + } + } else { + if (m_selfOnly) { + unsigned short srcId = layer3.getSourceUnitId(); + if (srcId != m_id) { + m_rfState = RS_RF_REJECTED; + return false; + } + } + } + + data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA; + data[1U] = 0x00U; + + CSync::addNXDNSync(data + 2U); + + CNXDNLICH lich = m_rfLastLICH; + lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND); + lich.encode(data + 2U); + + CNXDNSACCH sacch; + sacch.setRAN(m_ran); + sacch.setStructure(NXDN_SR_SINGLE); + sacch.setData(SACCH_IDLE); + sacch.encode(data + 2U); + + if (valid1) { + facch11.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + facch11.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + } else { + facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + } + + scrambler(data + 2U); + + // writeNetwork(data, m_rfFrames, ); + +#if defined(DUMP_NXDN) + writeFile(data + 2U); +#endif + + if (m_duplex) + writeQueueRF(data); + + if (type == NXDN_MESSAGE_TYPE_TX_REL) { + m_rfFrames++; + if (m_rssi != 0U) + LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); + else + LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits)); + writeEndRF(); + return true; + } else { + m_rfFrames = 0U; + m_rfErrs = 0U; + m_rfBits = 1U; + m_rfTimeoutTimer.start(); + m_rfState = RS_RF_AUDIO; + + m_minRSSI = m_rssi; + m_maxRSSI = m_rssi; + m_aveRSSI = m_rssi; + m_rssiCount = 1U; +#if defined(DUMP_NXDN) + openFile(); +#endif + m_rfLayer3 = layer3; + + unsigned short srcId = m_rfLayer3.getSourceUnitId(); + unsigned short dstId = m_rfLayer3.getDestinationGroupId(); + bool grp = m_rfLayer3.getIsGroup(); + + std::string source = m_lookup->find(srcId); + LogMessage("NXDN, received RF voice transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId); + m_display->writeNXDN(source.c_str(), grp, dstId, "R"); + + m_rfState = RS_RF_AUDIO; + + return true; + } + } + + return false; + } else { unsigned char message[3U]; sacch.getData(message); @@ -192,19 +294,19 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne switch (structure) { case NXDN_SR_1_4: m_rfMask |= 0x01U; - m_rfSACCHMessage.decode(message, 18U, 0U); + m_rfLayer3.decode(message, 18U, 0U); break; case NXDN_SR_2_4: m_rfMask |= 0x02U; - m_rfSACCHMessage.decode(message, 18U, 18U); + m_rfLayer3.decode(message, 18U, 18U); break; case NXDN_SR_3_4: m_rfMask |= 0x04U; - m_rfSACCHMessage.decode(message, 18U, 36U); + m_rfLayer3.decode(message, 18U, 36U); break; case NXDN_SR_4_4: m_rfMask |= 0x08U; - m_rfSACCHMessage.decode(message, 18U, 54U); + m_rfLayer3.decode(message, 18U, 54U); break; default: break; @@ -213,13 +315,13 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne if (m_rfMask != 0x0FU) return false; - unsigned char messageType = m_rfSACCHMessage.getMessageType(); + unsigned char messageType = m_rfLayer3.getMessageType(); if (messageType != NXDN_MESSAGE_TYPE_VCALL) return false; - unsigned short srcId = m_rfSACCHMessage.getSourceUnitId(); - unsigned short dstId = m_rfSACCHMessage.getDestinationGroupId(); - bool grp = m_rfSACCHMessage.getIsGroup(); + unsigned short srcId = m_rfLayer3.getSourceUnitId(); + unsigned short dstId = m_rfLayer3.getDestinationGroupId(); + bool grp = m_rfLayer3.getIsGroup(); if (m_selfOnly) { if (srcId != m_id) { @@ -263,7 +365,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne // XXX Regenerate SACCH here // Regenerate the audio and interpret the FACCH1 data - unsigned char voiceMode = m_rfSACCHMessage.getCallOptions() & 0x07U; + unsigned char voiceMode = m_rfLayer3.getCallOptions() & 0x07U; if (option == NXDN_LICH_STEAL_NONE) { CAMBEFEC ambe; @@ -358,7 +460,6 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne m_rfFrames++; m_display->writeNXDNRSSI(m_rssi); - // } #ifdef notdef // Process end of audio here @@ -835,9 +936,9 @@ void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count, b if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) return; - unsigned short srcId = m_rfSACCHMessage.getSourceUnitId(); - unsigned short dstId = m_rfSACCHMessage.getDestinationGroupId(); - bool grp = m_rfSACCHMessage.getIsGroup(); + unsigned short srcId = m_rfLayer3.getSourceUnitId(); + unsigned short dstId = m_rfLayer3.getDestinationGroupId(); + bool grp = m_rfLayer3.getIsGroup(); m_network->write(data + 2U, srcId, grp, dstId, count % 256U, end); } diff --git a/NXDNControl.h b/NXDNControl.h index da97aeb..5f000e7 100644 --- a/NXDNControl.h +++ b/NXDNControl.h @@ -70,7 +70,7 @@ private: unsigned int m_netErrs; unsigned int m_netBits; CNXDNLICH m_rfLastLICH; - CNXDNLayer3 m_rfSACCHMessage; + CNXDNLayer3 m_rfLayer3; unsigned char m_rfMask; unsigned char m_netN; CRSSIInterpolator* m_rssiMapper; diff --git a/NXDNDefines.h b/NXDNDefines.h index 79f6a2d..463ca61 100644 --- a/NXDNDefines.h +++ b/NXDNDefines.h @@ -101,4 +101,6 @@ const unsigned char NXDN_DATA_CALL_OPTION_DUPLEX = 0x10U; const unsigned char NXDN_DATA_CALL_OPTION_4800 = 0x00U; const unsigned char NXDN_DATA_CALL_OPTION_9600 = 0x02U; +const unsigned char SACCH_IDLE[] = { NXDN_MESSAGE_TYPE_IDLE, 0x00U, 0x00U }; + #endif diff --git a/NXDNFACCH1.cpp b/NXDNFACCH1.cpp index 4e14eb7..48f4639 100644 --- a/NXDNFACCH1.cpp +++ b/NXDNFACCH1.cpp @@ -71,7 +71,7 @@ bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset) { assert(data != NULL); - CUtils::dump("NXDN, FACCH1 input", data, 18U); + // CUtils::dump("NXDN, FACCH1 input", data, 18U); unsigned char temp1[18U]; @@ -81,7 +81,7 @@ bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset) WRITE_BIT1(temp1, i, b); } - CUtils::dump("NXDN, FACCH1 de-interleaved", temp1, 18U); + // CUtils::dump("NXDN, FACCH1 de-interleaved", temp1, 18U); uint8_t temp2[192U]; @@ -129,14 +129,14 @@ void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const CNXDNCRC::encodeCRC12(temp1, 80U); - CUtils::dump("NXDN, FACCH1 encoded with CRC", temp1, 12U); + // CUtils::dump("NXDN, FACCH1 encoded with CRC", temp1, 12U); unsigned char temp2[24U]; CNXDNConvolution conv; conv.encode(temp1, temp2, 96U); - CUtils::dump("NXDN, FACCH1 convolved", temp2, 24U); + // CUtils::dump("NXDN, FACCH1 convolved", temp2, 24U); unsigned char temp3[18U]; @@ -152,7 +152,7 @@ void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const } } - CUtils::dump("NXDN, FACCH1 punctured", temp3, 18U); + // CUtils::dump("NXDN, FACCH1 punctured", temp3, 18U); for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) { unsigned int n = INTERLEAVE_TABLE[i] + offset; diff --git a/NXDNLICH.cpp b/NXDNLICH.cpp index b5e363c..df735b9 100644 --- a/NXDNLICH.cpp +++ b/NXDNLICH.cpp @@ -61,7 +61,7 @@ bool CNXDNLICH::decode(const unsigned char* bytes) bool parity = b[7U] ^ b[6U] ^ b[5U] ^ b[4U]; - LogMessage("NXDN, LICH bits: %d%d %d%d %d%d %d - %d, parity: %d", b[7U] ? 1 : 0, b[6U] ? 1 : 0, b[5U] ? 1 : 0, b[4U] ? 1 : 0, b[3U] ? 1 : 0, b[2U] ? 1 : 0, b[1U] ? 1 : 0, b[0U] ? 1 : 0, parity ? 1 : 0); + // LogMessage("NXDN, LICH bits: %d%d %d%d %d%d %d - %d, parity: %d", b[7U] ? 1 : 0, b[6U] ? 1 : 0, b[5U] ? 1 : 0, b[4U] ? 1 : 0, b[3U] ? 1 : 0, b[2U] ? 1 : 0, b[1U] ? 1 : 0, b[0U] ? 1 : 0, parity ? 1 : 0); if (parity != b[0U]) return false; diff --git a/NXDNSACCH.cpp b/NXDNSACCH.cpp index 94fee46..304b20d 100755 --- a/NXDNSACCH.cpp +++ b/NXDNSACCH.cpp @@ -65,7 +65,7 @@ bool CNXDNSACCH::decode(const unsigned char* data) { assert(data != NULL); - CUtils::dump("NXDN, SACCH input", data, 12U); + // CUtils::dump("NXDN, SACCH input", data, 12U); unsigned char temp1[8U]; @@ -75,7 +75,7 @@ bool CNXDNSACCH::decode(const unsigned char* data) WRITE_BIT1(temp1, i, b); } - CUtils::dump("NXDN, SACCH de-interleaved", temp1, 8U); + // CUtils::dump("NXDN, SACCH de-interleaved", temp1, 8U); uint8_t temp2[72U]; @@ -130,7 +130,7 @@ void CNXDNSACCH::encode(unsigned char* data) const CNXDNConvolution conv; conv.encode(temp1, temp2, 36U); - CUtils::dump("NXDN, SACCH convolved", temp2, 8U); + // CUtils::dump("NXDN, SACCH convolved", temp2, 8U); unsigned char temp3[8U]; @@ -146,7 +146,7 @@ void CNXDNSACCH::encode(unsigned char* data) const } } - CUtils::dump("NXDN, SACCH punctured", temp3, 8U); + // CUtils::dump("NXDN, SACCH punctured", temp3, 8U); for (unsigned int i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) { unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;