diff --git a/DStarControl.cpp b/DStarControl.cpp index 28cb4eb..e0c0533 100644 --- a/DStarControl.cpp +++ b/DStarControl.cpp @@ -85,7 +85,13 @@ m_minRSSI(0U), m_aveRSSI(0U), m_rssiCount(0U), m_enabled(true), -m_fp(nullptr) +m_fp(nullptr), +m_RFdataLookBack(nullptr), +m_RFdataLookBackLen(0U), +m_RFdataLookBackIndex(0U), +m_NetdataLookBack(nullptr), +m_NetdataLookBackLen(0U), +m_NetdataLookBackIndex(0U) { assert(display != nullptr); assert(rssiMapper != nullptr); @@ -100,7 +106,7 @@ m_fp(nullptr) std::string mod = module; mod.resize(1U, ' '); call.append(mod); - + std::string gate = callsign; gate.resize(DSTAR_LONG_CALLSIGN_LENGTH - 1U, ' '); gate.append("G"); @@ -269,6 +275,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) m_rfFrames = 1U; m_rfN = 0U; + m_RFdataLookBackIndex = 0U; m_minRSSI = m_rssi; m_maxRSSI = m_rssi; @@ -350,6 +357,41 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) if (m_rfState == RPT_RF_STATE::INVALID) return true; + // The sync is regenerated by the modem so can do exact match + if (::memcmp(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES) == 0) { + m_rfSlowData.start(); + m_rfN = 0U; + } else { + m_rfSlowData.add(data + 1U); + } + + if(m_RFdataLookBackIndex == 0U) { + m_RFdataLookBack = new unsigned char[len]; + ::memcpy(m_RFdataLookBack, data, len); + m_RFdataLookBackLen = len; + m_RFdataLookBackIndex ++; + return true; + } else if (m_RFdataLookBackIndex == 1U) { + m_RFdataLookBackIndex ++; + + if (m_rfState == RPT_RF_STATE::AUDIO){ + unsigned char type = m_rfSlowData.getType(false); + // as per specs chapter 6.1.3, this could be any value bewtween 0x81 and 0x9C as one fast data block can only contain 28 bytes 0x80 + 28d = 0x9C + if ((type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK) == DSTAR_SLOW_DATA_TYPE_FASTDATA){ + LogMessage("D-Star, starting fast data mode (RF)"); + m_rfState = RPT_RF_STATE::DATA; + } + } + + LogDebug("D-Star, processing lookback data (RF)"); + bool res1 = writeModem(m_RFdataLookBack, m_RFdataLookBackLen); + bool res2 = writeModem(data, len); + delete[] m_RFdataLookBack; + m_RFdataLookBack = nullptr; + m_RFdataLookBackLen = 0U; + return res1 && res2; + } + if (m_rfState == RPT_RF_STATE::LISTENING) { // The sync is regenerated by the modem so can do exact match if (::memcmp(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES) == 0) { @@ -369,20 +411,29 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) } if (m_rfState == RPT_RF_STATE::AUDIO) { - unsigned char type = m_rfSlowData.getType(); - - if (type == DSTAR_SLOW_DATA_TYPE_FASTDATA_BEGIN) { - LogMessage("D-Star, starting fast data mode"); + unsigned char type = m_rfSlowData.getType(false); + //as per specs, this could be any value bewtween 0x80 and 0x9C + if ((type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK) == DSTAR_SLOW_DATA_TYPE_FASTDATA) { + LogMessage("D-Star, starting fast data mode (RF)"); m_rfState = RPT_RF_STATE::DATA; } } + if (m_rfState == RPT_RF_STATE::DATA) { + unsigned char type = m_rfSlowData.getType(true); + // as per specs, this could be any value bewtween 0x80 and 0x9C as one fast data block can only contain 28 bytes 0x80 + 28d = 0x9C + if(((type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK) == DSTAR_SLOW_DATA_TYPE_FASTDATA) && type > 0x9CU) { + LogMessage("Invalid fast data type 0x%02X received, returning to audio mode (RF)", type); + m_rfState = RPT_RF_STATE::AUDIO; + } + } + if (m_rfState == RPT_RF_STATE::DATA) { // Send the RSSI data to the display if (m_rfN == 0U) m_display->writeDStarRSSI(m_rssi); - LogDebug("D-Star, fast data sequence no. %u", m_rfN); + LogDebug("D-Star, RF fast data sequence no. %u", m_rfN); m_rfBits += 48U; m_rfFrames++; @@ -395,9 +446,9 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) bool complete = m_rfSlowData.isComplete(); if (complete) { - unsigned char type = m_rfSlowData.getType(); - if (type == DSTAR_SLOW_DATA_TYPE_FASTDATA_END) { - LogMessage("D-Star, leaving fast data mode"); + unsigned char type = m_rfSlowData.getType(false); + if ((type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK) != DSTAR_SLOW_DATA_TYPE_FASTDATA) { + LogMessage("D-Star, leaving fast data mode (RF)"); m_rfState = RPT_RF_STATE::AUDIO; } } @@ -410,10 +461,10 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) unsigned int errors = 0U; if (::memcmp(data + 1U, DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED, DSTAR_VOICE_FRAME_LENGTH_BYTES) == 0) { - LogDebug("D-Star, audio sequence no. %u, null audio", m_rfN); + LogDebug("D-Star, RF audio sequence no. %u, null audio", m_rfN); } else { errors = m_fec.regenerateDStar(data + 1U); - LogDebug("D-Star, audio sequence no. %u, errs: %u/48 (%.1f%%)", m_rfN, errors, float(errors) / 0.48F); + LogDebug("D-Star, RF audio sequence no. %u, errs: %u/48 (%.1f%%)", m_rfN, errors, float(errors) / 0.48F); m_display->writeDStarBER(float(errors) / 0.48F); } @@ -508,6 +559,7 @@ bool CDStarControl::writeModem(unsigned char *data, unsigned int len) m_rfN = 0U; m_rfFrames = 1U; + m_RFdataLookBackIndex = 0U; m_minRSSI = m_rssi; m_maxRSSI = m_rssi; @@ -676,6 +728,7 @@ void CDStarControl::writeNetwork() m_netFrames = 0U; m_netLost = 0U; + m_NetdataLookBackIndex = 0U; m_netN = 20U; @@ -706,7 +759,7 @@ void CDStarControl::writeNetwork() } else { m_display->writeDStar((char*)my1, (char*)my2, (char*)your, "N", (char*) " "); LogMessage("D-Star, received network header from %8.8s/%4.4s to %8.8s", my1, my2, your); - } + } m_elapsed.start(); } else if (type == TAG_EOT) { @@ -734,92 +787,145 @@ void CDStarControl::writeNetwork() writeEndNet(); } else if (type == TAG_DATA) { - if ((m_netState == RPT_NET_STATE::AUDIO) || (m_netState == RPT_NET_STATE::DATA)) { - unsigned char n = data[1U]; - - if (n == 0U) { - CSync::addDStarSync(data + 2U); - m_netSlowData.start(); - } else { - m_netSlowData.add(data + 2U); - - if (m_netState == RPT_NET_STATE::AUDIO) { - unsigned char type = m_netSlowData.getType(); - if (type == DSTAR_SLOW_DATA_TYPE_FASTDATA_BEGIN) { - LogMessage("D-Star, starting fast data mode"); - m_netState = RPT_NET_STATE::DATA; - } - } - } - } - - if (m_netState == RPT_NET_STATE::AUDIO) { - unsigned char n = data[1U]; - - unsigned int errors = 0U; - if (::memcmp(data + 2U, DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED, DSTAR_VOICE_FRAME_LENGTH_BYTES) != 0) { - errors = m_fec.regenerateDStar(data + 2U); - blankDTMF(data + 2U); - } - - data[1U] = TAG_DATA; - - // Insert silence and reject if in the past - bool ret = insertSilence(data + 1U, n); - if (!ret) - return; - - m_netErrs += errors; - m_netBits += 48U; - - m_netN = n; - - if (m_netN != 0U) { - const unsigned char* text = m_netSlowData.getText(); - if (text != nullptr) - LogMessage("D-Star, network slow data text = \"%s\"", text); - } - - m_packetTimer.start(); - m_netFrames++; - -#if defined(DUMP_DSTAR) - writeFile(data + 1U, length - 1U); -#endif - writeQueueDataNet(data + 1U); - } - - if (m_netState == RPT_NET_STATE::DATA) { - m_netN = data[1U]; - - data[1U] = TAG_DATA; - - m_netBits += 48U; - - if (m_netN != 0U) { - bool complete = m_netSlowData.isComplete(); - if (complete) { - unsigned char type = m_netSlowData.getType(); - if (type == DSTAR_SLOW_DATA_TYPE_FASTDATA_END) { - LogMessage("D-Star, leaving fast data mode"); - m_netState = RPT_NET_STATE::AUDIO; - } - } - } - - m_packetTimer.start(); - m_netFrames++; - -#if defined(DUMP_DSTAR) - writeFile(data + 1U, length - 1U); -#endif - writeQueueDataNet(data + 1U); - } + writeNetworkData(data, length); } else { CUtils::dump("D-Star, unknown data from network", data, DSTAR_FRAME_LENGTH_BYTES + 1U); } } +void CDStarControl::writeNetworkData(unsigned char* data, unsigned int length) +{ + assert(data != nullptr); + + unsigned char type = data[0U]; + assert(type == TAG_DATA); + + if (m_network == nullptr) + return; + + if ((m_netState == RPT_NET_STATE::AUDIO) || (m_netState == RPT_NET_STATE::DATA)) { + unsigned char n = data[1U]; + + if (n == 0U) { + CSync::addDStarSync(data + 2U); + m_netSlowData.start(); + } else { + m_netSlowData.add(data + 2U); + } + + if(m_NetdataLookBackIndex == 0U) { + m_NetdataLookBack = new unsigned char[length]; + ::memcpy(m_NetdataLookBack, data, length); + m_NetdataLookBackLen = length; + m_NetdataLookBackIndex ++; + return; + } else if (m_NetdataLookBackIndex == 1U) { + m_NetdataLookBackIndex ++; + + if (m_netState == RPT_NET_STATE::AUDIO){ + unsigned char type = m_netSlowData.getType(false); + LogMessage("A D-Star, slow data type: 0x%02X 0x%02X %i", type, type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK, m_netN); + // as per specs, this could be any value bewtween 0x80 and 0x9C + if ((type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK) == DSTAR_SLOW_DATA_TYPE_FASTDATA){ + LogMessage("D-Star, starting fast data mode (Net)"); + m_netState = RPT_NET_STATE::DATA; + } + } + LogDebug("D-Star, processing lookback data (Net)"); + writeNetworkData(m_NetdataLookBack, m_NetdataLookBackLen); + writeNetworkData(data, length); + delete[] m_NetdataLookBack; + m_NetdataLookBack = nullptr; + m_NetdataLookBackLen = 0U; + return; + } + } + + if (m_netState == RPT_NET_STATE::AUDIO) { + unsigned char type = m_netSlowData.getType(false); + LogMessage("A D-Star, slow data type: 0x%02X 0x%02X %i", type, type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK, m_netN); + // as per specs chapter 6.1.3, this could be any value bewtween 0x81 and 0x9C as one fast data block can only contain 28 bytes 0x80 + 28d = 0x9C + if ((type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK) == DSTAR_SLOW_DATA_TYPE_FASTDATA){ + LogMessage("D-Star, starting fast data mode (Net)"); + m_netState = RPT_NET_STATE::DATA; + } + } + + if (m_netState == RPT_NET_STATE::DATA) { + unsigned char type = m_netSlowData.getType(true); + // as per specs chapter 6.1.3, this could be any value bewtween 0x81 and 0x9C as one fast data block can only contain 28 bytes 0x80 + 28d = 0x9C + if(((type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK) == DSTAR_SLOW_DATA_TYPE_FASTDATA) && type > 0x9CU) { + LogMessage("Invalid fast data type 0x%02X received, returning to audio mode (Net)", type); + m_netState = RPT_NET_STATE::AUDIO; + } + } + + if (m_netState == RPT_NET_STATE::AUDIO) { + unsigned char n = data[1U]; + + unsigned int errors = 0U; + if (::memcmp(data + 2U, DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED, DSTAR_VOICE_FRAME_LENGTH_BYTES) != 0) { + errors = m_fec.regenerateDStar(data + 2U); + LogDebug("D-Star, Net audio sequence no. %u, errs: %u/48 (%.1f%%)", n, errors, float(errors) / 0.48F); + blankDTMF(data + 2U); + } + + data[1U] = TAG_DATA; + + // Insert silence and reject if in the past + bool ret = insertSilence(data + 1U, n); + if (!ret) + return; + + m_netErrs += errors; + m_netBits += 48U; + + m_netN = n; + + if (m_netN != 0U) { + const unsigned char* text = m_netSlowData.getText(); + if (text != nullptr) + LogMessage("D-Star, network slow data text = \"%s\"", text); + } + + m_packetTimer.start(); + m_netFrames++; + +#if defined(DUMP_DSTAR) + writeFile(data + 1U, length - 1U); +#endif + writeQueueDataNet(data + 1U); + } + + if (m_netState == RPT_NET_STATE::DATA) { + m_netN = data[1U]; + LogDebug("D-Star, Net fast data sequence no. %u", m_netN); + + data[1U] = TAG_DATA; + + m_netBits += 48U; + + if (m_netN != 0U) { + bool complete = m_netSlowData.isComplete(); + if (complete) { + unsigned char type = m_netSlowData.getType(); + if ((type & DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK) != DSTAR_SLOW_DATA_TYPE_FASTDATA) { + LogMessage("D-Star, leaving fast data mode (Net)"); + m_netState = RPT_NET_STATE::AUDIO; + } + } + } + + m_packetTimer.start(); + m_netFrames++; + +#if defined(DUMP_DSTAR) + writeFile(data + 1U, length - 1U); +#endif + writeQueueDataNet(data + 1U); + } +} + void CDStarControl::clock() { unsigned int ms = m_interval.elapsed(); diff --git a/DStarControl.h b/DStarControl.h index 1916e75..17ab58a 100644 --- a/DStarControl.h +++ b/DStarControl.h @@ -99,8 +99,15 @@ private: unsigned int m_rssiCount; bool m_enabled; FILE* m_fp; + unsigned char * m_RFdataLookBack; + unsigned int m_RFdataLookBackLen; + unsigned int m_RFdataLookBackIndex; + unsigned char * m_NetdataLookBack; + unsigned int m_NetdataLookBackLen; + unsigned int m_NetdataLookBackIndex; void writeNetwork(); + void writeNetworkData(unsigned char* data, unsigned int length); void writeQueueHeaderRF(const unsigned char* data); void writeQueueDataRF(const unsigned char* data); diff --git a/DStarDefines.h b/DStarDefines.h index 0098f9e..3df93d8 100644 --- a/DStarDefines.h +++ b/DStarDefines.h @@ -48,8 +48,8 @@ const unsigned char DSTAR_SLOW_DATA_TYPE_MASK = 0xF0U; const unsigned char DSTAR_SLOW_DATA_TYPE_GPSDATA = 0x30U; const unsigned char DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U; const unsigned char DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U; -const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA_END = 0x80U; -const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA_BEGIN = 0x90U; +const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA = 0x80U; +const unsigned char DSTAR_SLOW_DATA_TYPE_FASTDATA_MASK = 0xE0U; const unsigned char DSTAR_SLOW_DATA_TYPE_SQUELCH = 0xC0U; const unsigned char DSTAR_SLOW_DATA_LENGTH_MASK = 0x0FU; diff --git a/DStarSlowData.cpp b/DStarSlowData.cpp index c3d75f3..b14d4b2 100644 --- a/DStarSlowData.cpp +++ b/DStarSlowData.cpp @@ -67,7 +67,7 @@ void CDStarSlowData::add(const unsigned char* data) m_buffer[5U] = data[11U] ^ DSTAR_SCRAMBLER_BYTES[2U]; m_state = SDD_STATE::FIRST; m_complete = true; - CUtils::dump(1U, "D-Star slow data element", m_buffer, 6U); + ////CUtils::dump(1U, "D-Star slow data element", m_buffer, 6U); loadHeader(); loadText(); break; @@ -111,7 +111,7 @@ void CDStarSlowData::loadText() { switch (m_buffer[0U]) { case DSTAR_SLOW_DATA_TYPE_TEXT | 0U: - CUtils::dump(1U, "D-Star slow data text fragment 0", m_buffer, 6U); + //CUtils::dump(1U, "D-Star slow data text fragment 0", m_buffer, 6U); m_text[0U] = m_buffer[1U] & 0x7FU; m_text[1U] = m_buffer[2U] & 0x7FU; m_text[2U] = m_buffer[3U] & 0x7FU; @@ -121,7 +121,7 @@ void CDStarSlowData::loadText() break; case DSTAR_SLOW_DATA_TYPE_TEXT | 1U: - CUtils::dump(1U, "D-Star slow data text fragment 1", m_buffer, 6U); + //CUtils::dump(1U, "D-Star slow data text fragment 1", m_buffer, 6U); m_text[5U] = m_buffer[1U] & 0x7FU; m_text[6U] = m_buffer[2U] & 0x7FU; m_text[7U] = m_buffer[3U] & 0x7FU; @@ -131,7 +131,7 @@ void CDStarSlowData::loadText() break; case DSTAR_SLOW_DATA_TYPE_TEXT | 2U: - CUtils::dump(1U, "D-Star slow data text fragment 2", m_buffer, 6U); + //CUtils::dump(1U, "D-Star slow data text fragment 2", m_buffer, 6U); m_text[10U] = m_buffer[1U] & 0x7FU; m_text[11U] = m_buffer[2U] & 0x7FU; m_text[12U] = m_buffer[3U] & 0x7FU; @@ -141,7 +141,7 @@ void CDStarSlowData::loadText() break; case DSTAR_SLOW_DATA_TYPE_TEXT | 3U: - CUtils::dump(1U, "D-Star slow data text fragment 3", m_buffer, 6U); + //CUtils::dump(1U, "D-Star slow data text fragment 3", m_buffer, 6U); m_text[15U] = m_buffer[1U] & 0x7FU; m_text[16U] = m_buffer[2U] & 0x7FU; m_text[17U] = m_buffer[3U] & 0x7FU; @@ -161,7 +161,7 @@ const unsigned char* CDStarSlowData::getText() if (m_textBits != 0x0FU) return nullptr; - CUtils::dump(1U, "D-Star slow data text", m_text, 20U); + //CUtils::dump(1U, "D-Star slow data text", m_text, 20U); m_textBits = 0x00U; @@ -237,9 +237,9 @@ void CDStarSlowData::getSlowData(unsigned char* data) } } -unsigned char CDStarSlowData::getType() const +unsigned char CDStarSlowData::getType(bool unmasked) const { - return m_buffer[0U] & DSTAR_SLOW_DATA_TYPE_MASK; + return unmasked ? m_buffer[0U] : m_buffer[0U] & DSTAR_SLOW_DATA_TYPE_MASK ; } bool CDStarSlowData::isComplete() const diff --git a/DStarSlowData.h b/DStarSlowData.h index 5b8b737..4353bf9 100644 --- a/DStarSlowData.h +++ b/DStarSlowData.h @@ -30,7 +30,7 @@ public: CDStarHeader* getHeader(); const unsigned char* getText(); - unsigned char getType() const; + unsigned char getType(bool unmasked = false) const; bool isComplete() const;