From ddcde1d8e374733f1e9dbbedd1821375b6c3dde4 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 25 Feb 2016 19:54:18 +0000 Subject: [PATCH] Split RF and network statues for all modes. --- DMRSlot.cpp | 510 ++++++++++++++++++++++++++--------------------- DMRSlot.h | 30 ++- DStarControl.cpp | 373 ++++++++++++++++++---------------- DStarControl.h | 36 ++-- Defines.h | 19 +- YSFControl.cpp | 12 +- YSFControl.h | 2 +- 7 files changed, 545 insertions(+), 437 deletions(-) diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 908a7cb..c992aef 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -46,20 +46,26 @@ bool CDMRSlot::m_voice2 = true; CDMRSlot::CDMRSlot(unsigned int slotNo, unsigned int timeout) : m_slotNo(slotNo), m_queue(1000U, "DMR Slot"), -m_state(RS_LISTENING), +m_rfState(RS_RF_LISTENING), +m_netState(RS_NET_IDLE), m_embeddedLC(), -m_lc(NULL), +m_rfLC(NULL), +m_netLC(NULL), m_seqNo(0U), m_n(0U), m_networkWatchdog(1000U, 0U, 1500U), -m_timeoutTimer(1000U, timeout), +m_rfTimeoutTimer(1000U, timeout), +m_netTimeoutTimer(1000U, timeout), m_packetTimer(1000U, 0U, 300U), m_elapsed(), -m_frames(0U), -m_lost(0U), +m_rfFrames(0U), +m_netFrames(0U), +m_netLost(0U), m_fec(), -m_bits(0U), -m_errs(0U), +m_rfBits(0U), +m_netBits(0U), +m_rfErrs(0U), +m_netErrs(0U), m_lastFrame(NULL), m_lastEMB(), m_fp(NULL) @@ -74,27 +80,24 @@ CDMRSlot::~CDMRSlot() void CDMRSlot::writeModem(unsigned char *data) { - if (data[0U] == TAG_LOST && m_state == RS_RELAYING_RF_AUDIO) { - if (m_bits == 0U) m_bits = 1U; - LogMessage("DMR Slot %u, transmission lost, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_frames) / 16.667F, float(m_errs * 100U) / float(m_bits)); - writeEndOfTransmission(true); + if (data[0U] == TAG_LOST && m_rfState == RS_RF_AUDIO) { + if (m_rfBits == 0U) m_rfBits = 1U; + LogMessage("DMR Slot %u, RF transmission lost, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits)); + writeEndRF(true); return; } - if (data[0U] == TAG_LOST && m_state == RS_RELAYING_RF_DATA) { - LogMessage("DMR Slot %u, transmission lost", m_slotNo); - writeEndOfTransmission(); + if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) { + LogMessage("DMR Slot %u, RF transmission lost", m_slotNo); + writeEndRF(); return; } if (data[0U] == TAG_LOST) { - m_state = RS_LISTENING; + m_rfState = RS_RF_LISTENING; return; } - if (m_state == RS_RELAYING_NETWORK_AUDIO || m_state == RS_RELAYING_NETWORK_DATA) - return; - bool dataSync = (data[1U] & DMR_SYNC_DATA) == DMR_SYNC_DATA; bool audioSync = (data[1U] & DMR_SYNC_AUDIO) == DMR_SYNC_AUDIO; @@ -105,18 +108,18 @@ void CDMRSlot::writeModem(unsigned char *data) unsigned char dataType = slotType.getDataType(); if (dataType == DT_VOICE_LC_HEADER) { - if (m_state == RS_RELAYING_RF_AUDIO) + if (m_rfState == RS_RF_AUDIO) return; CDMRFullLC fullLC; - m_lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER); - if (m_lc == NULL) { - LogMessage("DMR Slot %u: unable to decode the LC", m_slotNo); + m_rfLC = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER); + if (m_rfLC == NULL) { + LogMessage("DMR Slot %u: unable to decode the RF LC", m_slotNo); return; } // Regenerate the LC data - fullLC.encode(*m_lc, data + 2U, DT_VOICE_LC_HEADER); + fullLC.encode(*m_rfLC, data + 2U, DT_VOICE_LC_HEADER); // Regenerate the Slot Type slotType.getData(data + 2U); @@ -127,32 +130,30 @@ void CDMRSlot::writeModem(unsigned char *data) data[0U] = TAG_DATA; data[1U] = 0x00U; - m_networkWatchdog.stop(); - m_timeoutTimer.start(); + m_rfTimeoutTimer.start(); - m_seqNo = 0U; - m_n = 0U; - - m_bits = 1U; - m_errs = 0U; + m_rfFrames = 0U; + m_rfBits = 1U; + m_rfErrs = 0U; if (m_duplex) { for (unsigned i = 0U; i < 3U; i++) - writeQueue(data); + writeQueueRF(data); } for (unsigned i = 0U; i < 3U; i++) - writeNetwork(data, DT_VOICE_LC_HEADER); + writeNetworkRF(data, DT_VOICE_LC_HEADER); - m_state = RS_RELAYING_RF_AUDIO; + m_rfState = RS_RF_AUDIO; - setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO(), true); + if (m_netState == RS_NET_IDLE) { + setShortLC(m_slotNo, m_rfLC->getDstId(), m_rfLC->getFLCO(), true); + m_display->writeDMR(m_slotNo, m_rfLC->getSrcId(), m_rfLC->getFLCO() == FLCO_GROUP, m_rfLC->getDstId(), "RV"); + } - m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId(), "RV"); - - LogMessage("DMR Slot %u, received RF voice header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId()); + LogMessage("DMR Slot %u, received RF voice header from %u to %s%u", m_slotNo, m_rfLC->getSrcId(), m_rfLC->getFLCO() == FLCO_GROUP ? "TG " : "", m_rfLC->getDstId()); } else if (dataType == DT_VOICE_PI_HEADER) { - if (m_state != RS_RELAYING_RF_AUDIO) + if (m_rfState != RS_RF_AUDIO) return; // Regenerate the Slot Type @@ -164,19 +165,17 @@ void CDMRSlot::writeModem(unsigned char *data) data[0U] = TAG_DATA; data[1U] = 0x00U; - m_n = 0U; - if (m_duplex) - writeQueue(data); + writeQueueRF(data); - writeNetwork(data, DT_VOICE_PI_HEADER); + writeNetworkRF(data, DT_VOICE_PI_HEADER); } else if (dataType == DT_TERMINATOR_WITH_LC) { - if (m_state != RS_RELAYING_RF_AUDIO) + if (m_rfState != RS_RF_AUDIO) return; // Regenerate the LC data CDMRFullLC fullLC; - fullLC.encode(*m_lc, data + 2U, DT_TERMINATOR_WITH_LC); + fullLC.encode(*m_rfLC, data + 2U, DT_TERMINATOR_WITH_LC); // Regenerate the Slot Type slotType.getData(data + 2U); @@ -188,20 +187,20 @@ void CDMRSlot::writeModem(unsigned char *data) data[1U] = 0x00U; for (unsigned int i = 0U; i < 2U; i++) - writeNetwork(data, DT_TERMINATOR_WITH_LC); + writeNetworkRF(data, DT_TERMINATOR_WITH_LC); // 480ms of terminator to space things out if (m_duplex) { for (unsigned int i = 0U; i < 8U; i++) - writeQueue(data); + writeQueueRF(data); } - if (m_bits == 0U) m_bits = 1U; - LogMessage("DMR Slot %u, received RF end of voice transmission, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_frames) / 16.667F, float(m_errs * 100U) / float(m_bits)); + if (m_rfBits == 0U) m_rfBits = 1U; + LogMessage("DMR Slot %u, received RF end of voice transmission, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits)); - writeEndOfTransmission(); + writeEndRF(); } else if (dataType == DT_DATA_HEADER) { - if (m_state == RS_RELAYING_RF_DATA) + if (m_rfState == RS_RF_DATA) return; CDMRDataHeader dataHeader; @@ -215,9 +214,9 @@ void CDMRSlot::writeModem(unsigned char *data) unsigned int srcId = dataHeader.getSrcId(); unsigned int dstId = dataHeader.getDstId(); - m_frames = dataHeader.getBlocks(); + m_rfFrames = dataHeader.getBlocks(); - m_lc = new CDMRLC(gi ? FLCO_GROUP : FLCO_USER_USER, srcId, dstId); + m_rfLC = new CDMRLC(gi ? FLCO_GROUP : FLCO_USER_USER, srcId, dstId); // Regenerate the data header dataHeader.get(data + 2U); @@ -231,26 +230,22 @@ void CDMRSlot::writeModem(unsigned char *data) data[0U] = TAG_DATA; data[1U] = 0x00U; - m_networkWatchdog.stop(); - - m_seqNo = 0U; - m_n = 0U; - if (m_duplex) { for (unsigned i = 0U; i < 3U; i++) - writeQueue(data); + writeQueueRF(data); } for (unsigned i = 0U; i < 3U; i++) - writeNetwork(data, DT_DATA_HEADER); + writeNetworkRF(data, DT_DATA_HEADER); - m_state = RS_RELAYING_RF_DATA; + m_rfState = RS_RF_DATA; - setShortLC(m_slotNo, dstId, gi ? FLCO_GROUP : FLCO_USER_USER, false); + if (m_netState == RS_NET_IDLE) { + setShortLC(m_slotNo, dstId, gi ? FLCO_GROUP : FLCO_USER_USER, false); + m_display->writeDMR(m_slotNo, srcId, gi, dstId, "RD"); + } - m_display->writeDMR(m_slotNo, srcId, gi, dstId, "RD"); - - LogMessage("DMR Slot %u, received RF data header from %u to %s%u, %u blocks", m_slotNo, srcId, gi ? "TG ": "", dstId, m_frames); + LogMessage("DMR Slot %u, received RF data header from %u to %s%u, %u blocks", m_slotNo, srcId, gi ? "TG ": "", dstId, m_rfFrames); } else if (dataType == DT_CSBK) { CDMRCSBK csbk; bool valid = csbk.put(data + 2U); @@ -280,12 +275,10 @@ void CDMRSlot::writeModem(unsigned char *data) data[0U] = TAG_DATA; data[1U] = 0x00U; - m_seqNo = 0U; - if (m_duplex) - writeQueue(data); + writeQueueRF(data); - writeNetwork(data, DT_CSBK, FLCO_USER_USER, csbk.getSrcId(), csbk.getDstId()); + writeNetworkRF(data, DT_CSBK, FLCO_USER_USER, csbk.getSrcId(), csbk.getDstId()); LogMessage("DMR Slot %u, received RF CSBK from %u to %u", m_slotNo, csbk.getSrcId(), csbk.getDstId()); } @@ -296,7 +289,7 @@ void CDMRSlot::writeModem(unsigned char *data) break; } } else if (dataType == DT_RATE_12_DATA || dataType == DT_RATE_34_DATA || dataType == DT_RATE_1_DATA) { - if (m_state != RS_RELAYING_RF_DATA) + if (m_rfState != RS_RF_DATA) return; // Regenerate the payload if possible @@ -313,52 +306,50 @@ void CDMRSlot::writeModem(unsigned char *data) // Convert the Data Sync to be from the BS CSync::addDMRDataSync(data + 2U); - m_frames--; + m_rfFrames--; - data[0U] = m_frames == 0U ? TAG_EOT : TAG_DATA; + data[0U] = m_rfFrames == 0U ? TAG_EOT : TAG_DATA; data[1U] = 0x00U; if (m_duplex) - writeQueue(data); + writeQueueRF(data); - writeNetwork(data, dataType); + writeNetworkRF(data, dataType); - if (m_frames == 0U) { + if (m_rfFrames == 0U) { LogMessage("DMR Slot %u, ended RF data transmission", m_slotNo); - writeEndOfTransmission(); + writeEndRF(); } } else { // Unhandled data type LogWarning("DMR Slot %u, unhandled RF data type - 0x%02X", m_slotNo, dataType); } } else if (audioSync) { - if (m_state == RS_RELAYING_RF_AUDIO) { + if (m_rfState == RS_RF_AUDIO) { // Convert the Audio Sync to be from the BS CSync::addDMRAudioSync(data + 2U); - unsigned char fid = m_lc->getFID(); + unsigned char fid = m_rfLC->getFID(); if (fid == FID_ETSI || fid == FID_DMRA) { unsigned int errors = m_fec.regenerateDMR(data + 2U); LogDebug("DMR Slot %u, audio sequence no. 0, errs: %u/141", m_slotNo, errors); - m_errs += errors; + m_rfErrs += errors; } - m_bits += 141U; + m_rfBits += 141U; data[0U] = TAG_DATA; data[1U] = 0x00U; - m_n = 0U; - if (m_duplex) - writeQueue(data); + writeQueueRF(data); - writeNetwork(data, DT_VOICE_SYNC); - } else if (m_state == RS_LISTENING) { - m_state = RS_LATE_ENTRY; + writeNetworkRF(data, DT_VOICE_SYNC); + } else if (m_rfState == RS_RF_LISTENING) { + m_rfState = RS_RF_LATE_ENTRY; } } else { - if (m_state == RS_RELAYING_RF_DATA) { + if (m_rfState == RS_RF_DATA) { CDMRSlotType slotType; slotType.putData(data + 2U); @@ -376,25 +367,25 @@ void CDMRSlot::writeModem(unsigned char *data) // Regenerate the Slot Type slotType.getData(data + 2U); - m_frames--; + m_rfFrames--; - data[0U] = m_frames == 0U ? TAG_EOT : TAG_DATA; + data[0U] = m_rfFrames == 0U ? TAG_EOT : TAG_DATA; data[1U] = 0x00U; if (m_duplex) - writeQueue(data); + writeQueueRF(data); - writeNetwork(data, dataType); + writeNetworkRF(data, dataType); - if (m_frames == 0U) { + if (m_rfFrames == 0U) { LogMessage("DMR Slot %u, ended RF data transmission", m_slotNo); - writeEndOfTransmission(); + writeEndRF(); } } else { // Unhandled data type LogWarning("DMR Slot %u, unhandled RF data type - 0x%02X", m_slotNo, dataType); } - } else if (m_state == RS_RELAYING_RF_AUDIO) { + } else if (m_rfState == RS_RF_AUDIO) { CDMREMB emb; emb.putData(data + 2U); @@ -402,26 +393,24 @@ void CDMRSlot::writeModem(unsigned char *data) emb.setColorCode(m_colorCode); emb.getData(data + 2U); - unsigned char fid = m_lc->getFID(); + unsigned char fid = m_rfLC->getFID(); if (fid == FID_ETSI || fid == FID_DMRA) { unsigned int errors = m_fec.regenerateDMR(data + 2U); unsigned char n = data[1U] & 0x0FU; LogDebug("DMR Slot %u, audio sequence no. %u, errs: %u/141", m_slotNo, n, errors); - m_errs += errors; + m_rfErrs += errors; } - m_bits += 141U; + m_rfBits += 141U; data[0U] = TAG_DATA; data[1U] = 0x00U; - m_n++; - if (m_duplex) - writeQueue(data); + writeQueueRF(data); - writeNetwork(data, DT_VOICE); - } else if (m_state == RS_LATE_ENTRY) { + writeNetworkRF(data, DT_VOICE); + } else if (m_rfState == RS_RF_LATE_ENTRY) { CDMREMB emb; emb.putData(data + 2U); @@ -430,15 +419,15 @@ void CDMRSlot::writeModem(unsigned char *data) if (colorCode != m_colorCode) return; - m_lc = m_embeddedLC.addData(data + 2U, emb.getLCSS()); - if (m_lc != NULL) { + m_rfLC = m_embeddedLC.addData(data + 2U, emb.getLCSS()); + if (m_rfLC != NULL) { // Create a dummy start frame to replace the received frame unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U]; CSync::addDMRDataSync(data + 2U); CDMRFullLC fullLC; - fullLC.encode(*m_lc, start + 2U, DT_VOICE_LC_HEADER); + fullLC.encode(*m_rfLC, start + 2U, DT_VOICE_LC_HEADER); CDMRSlotType slotType; slotType.setColorCode(m_colorCode); @@ -448,54 +437,50 @@ void CDMRSlot::writeModem(unsigned char *data) start[0U] = TAG_DATA; start[1U] = 0x00U; - m_networkWatchdog.stop(); - m_timeoutTimer.start(); + m_rfTimeoutTimer.start(); - m_seqNo = 0U; - m_n = 0U; - - m_bits = 1U; - m_errs = 0U; + m_rfFrames = 0U; + m_rfBits = 1U; + m_rfErrs = 0U; if (m_duplex) { for (unsigned int i = 0U; i < 3U; i++) - writeQueue(start); + writeQueueRF(start); } for (unsigned int i = 0U; i < 3U; i++) - writeNetwork(start, DT_VOICE_LC_HEADER); + writeNetworkRF(start, DT_VOICE_LC_HEADER); // Regenerate the EMB emb.getData(data + 2U); // Send the original audio frame out - unsigned char fid = m_lc->getFID(); + unsigned char fid = m_rfLC->getFID(); if (fid == FID_ETSI || fid == FID_DMRA) { unsigned int errors = m_fec.regenerateDMR(data + 2U); unsigned char n = data[1U] & 0x0FU; LogDebug("DMR Slot %u, audio sequence no. %u, errs: %u/141", m_slotNo, n, errors); - m_errs += errors; + m_rfErrs += errors; } - m_bits += 141U; + m_rfBits += 141U; data[0U] = TAG_DATA; data[1U] = 0x00U; - m_n++; - if (m_duplex) - writeQueue(data); + writeQueueRF(data); - writeNetwork(data, DT_VOICE); + writeNetworkRF(data, DT_VOICE); - m_state = RS_RELAYING_RF_AUDIO; + m_rfState = RS_RF_AUDIO; - setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO(), true); + if (m_netState == RS_NET_IDLE) { + setShortLC(m_slotNo, m_rfLC->getDstId(), m_rfLC->getFLCO(), true); + m_display->writeDMR(m_slotNo, m_rfLC->getSrcId(), m_rfLC->getFLCO() == FLCO_GROUP, m_rfLC->getDstId(), "RV"); + } - m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId(), "RV"); - - LogMessage("DMR Slot %u, received RF late entry from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId()); + LogMessage("DMR Slot %u, received RF late entry from %u to %s%u", m_slotNo, m_rfLC->getSrcId(), m_rfLC->getFLCO() == FLCO_GROUP ? "TG " : "", m_rfLC->getDstId()); } } } @@ -514,33 +499,30 @@ unsigned int CDMRSlot::readModem(unsigned char* data) return len; } -void CDMRSlot::writeEndOfTransmission(bool writeEnd) +void CDMRSlot::writeEndRF(bool writeEnd) { - m_state = RS_LISTENING; + m_rfState = RS_RF_LISTENING; - setShortLC(m_slotNo, 0U); + if (m_netState == RS_NET_IDLE) { + setShortLC(m_slotNo, 0U); + m_display->clearDMR(m_slotNo); + } - m_display->clearDMR(m_slotNo); + m_rfTimeoutTimer.stop(); - m_networkWatchdog.stop(); - m_timeoutTimer.stop(); - m_packetTimer.stop(); - - m_frames = 0U; - m_lost = 0U; - - m_errs = 0U; - m_bits = 0U; + m_rfFrames = 0U; + m_rfErrs = 0U; + m_rfBits = 0U; if (writeEnd) { - if (m_state == RS_RELAYING_NETWORK_AUDIO || (m_state == RS_RELAYING_RF_AUDIO && m_duplex)) { + if (m_netState == RS_NET_IDLE && m_duplex) { // Create a dummy start end frame unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U]; CSync::addDMRDataSync(data + 2U); CDMRFullLC fullLC; - fullLC.encode(*m_lc, data + 2U, DT_TERMINATOR_WITH_LC); + fullLC.encode(*m_rfLC, data + 2U, DT_TERMINATOR_WITH_LC); CDMRSlotType slotType; slotType.setColorCode(m_colorCode); @@ -552,12 +534,56 @@ void CDMRSlot::writeEndOfTransmission(bool writeEnd) // 480ms of terminator to space things out for (unsigned int i = 0U; i < 8U; i++) - writeQueue(data); + writeQueueRF(data); } } - delete m_lc; - m_lc = NULL; + delete m_rfLC; + m_rfLC = NULL; +} + +void CDMRSlot::writeEndNet(bool writeEnd) +{ + m_netState = RS_NET_IDLE; + + setShortLC(m_slotNo, 0U); + + m_display->clearDMR(m_slotNo); + + m_networkWatchdog.stop(); + m_netTimeoutTimer.stop(); + m_packetTimer.stop(); + + m_netFrames = 0U; + m_netLost = 0U; + + m_netErrs = 0U; + m_netBits = 0U; + + if (writeEnd) { + // Create a dummy start end frame + unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U]; + + CSync::addDMRDataSync(data + 2U); + + CDMRFullLC fullLC; + fullLC.encode(*m_netLC, data + 2U, DT_TERMINATOR_WITH_LC); + + CDMRSlotType slotType; + slotType.setColorCode(m_colorCode); + slotType.setDataType(DT_TERMINATOR_WITH_LC); + slotType.getData(data + 2U); + + data[0U] = TAG_DATA; + data[1U] = 0x00U; + + // 480ms of terminator to space things out + for (unsigned int i = 0U; i < 8U; i++) + writeQueueNet(data); + } + + delete m_netLC; + m_netLC = NULL; #if defined(DUMP_DMR) closeFile(); @@ -566,7 +592,7 @@ void CDMRSlot::writeEndOfTransmission(bool writeEnd) void CDMRSlot::writeNetwork(const CDMRData& dmrData) { - if (m_state == RS_RELAYING_RF_AUDIO || m_state == RS_RELAYING_RF_DATA || m_state == RS_LATE_ENTRY) + if (m_rfState != RS_RF_LISTENING && m_netState == RS_NET_IDLE) return; m_networkWatchdog.start(); @@ -577,18 +603,18 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) dmrData.getData(data + 2U); if (dataType == DT_VOICE_LC_HEADER) { - if (m_state == RS_RELAYING_NETWORK_AUDIO) + if (m_netState == RS_NET_AUDIO) return; CDMRFullLC fullLC; - m_lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER); - if (m_lc == NULL) { + m_netLC = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER); + if (m_netLC == NULL) { LogMessage("DMR Slot %u, bad LC received from the network", m_slotNo); return; } // Regenerate the LC data - fullLC.encode(*m_lc, data + 2U, DT_VOICE_LC_HEADER); + fullLC.encode(*m_netLC, data + 2U, DT_VOICE_LC_HEADER); // Regenerate the Slot Type CDMRSlotType slotType; @@ -602,33 +628,34 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = TAG_DATA; data[1U] = 0x00U; - m_timeoutTimer.start(); + m_netTimeoutTimer.start(); - m_frames = 0U; + m_netFrames = 0U; + m_netLost = 0U; - m_bits = 1U; - m_errs = 0U; + m_netBits = 1U; + m_netErrs = 0U; // 300ms of idle to give breathing space for lost frames for (unsigned int i = 0U; i < 5U; i++) - writeQueue(m_idle); + writeQueueNet(m_idle); for (unsigned int i = 0U; i < 3U; i++) - writeQueue(data); + writeQueueNet(data); - m_state = RS_RELAYING_NETWORK_AUDIO; + m_netState = RS_NET_AUDIO; - setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO(), true); + setShortLC(m_slotNo, m_netLC->getDstId(), m_netLC->getFLCO(), true); - m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId(), "NV"); + m_display->writeDMR(m_slotNo, m_netLC->getSrcId(), m_netLC->getFLCO() == FLCO_GROUP, m_netLC->getDstId(), "NV"); #if defined(DUMP_DMR) openFile(); writeFile(data); #endif - LogMessage("DMR Slot %u, received network voice header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId()); + LogMessage("DMR Slot %u, received network voice header from %u to %s%u", m_slotNo, m_netLC->getSrcId(), m_netLC->getFLCO() == FLCO_GROUP ? "TG " : "", m_netLC->getDstId()); } else if (dataType == DT_VOICE_PI_HEADER) { - if (m_state != RS_RELAYING_NETWORK_AUDIO) + if (m_netState != RS_NET_AUDIO) return; // Regenerate the Slot Type @@ -643,18 +670,18 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = TAG_DATA; data[1U] = 0x00U; - writeQueue(data); + writeQueueNet(data); #if defined(DUMP_DMR) writeFile(data); #endif } else if (dataType == DT_TERMINATOR_WITH_LC) { - if (m_state != RS_RELAYING_NETWORK_AUDIO) + if (m_netState != RS_NET_AUDIO) return; // Regenerate the LC data CDMRFullLC fullLC; - fullLC.encode(*m_lc, data + 2U, DT_TERMINATOR_WITH_LC); + fullLC.encode(*m_netLC, data + 2U, DT_TERMINATOR_WITH_LC); // Regenerate the Slot Type CDMRSlotType slotType; @@ -670,20 +697,20 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // 480ms of terminator to space things out for (unsigned int i = 0U; i < 8U; i++) - writeQueue(data); + writeQueueNet(data); - writeEndOfTransmission(); + writeEndNet(); #if defined(DUMP_DMR) writeFile(data); closeFile(); #endif // We've received the voice header and terminator haven't we? - m_frames += 2U; - if (m_bits == 0U) m_bits = 1U; - LogMessage("DMR Slot %u, received network end of voice transmission, %.1f seconds, %u%% packet loss, BER: %.1f%%", m_slotNo, float(m_frames) / 16.667F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits)); + m_netFrames += 2U; + if (m_netBits == 0U) m_netBits = 1U; + LogMessage("DMR Slot %u, received network end of voice transmission, %.1f seconds, %u%% packet loss, BER: %.1f%%", m_slotNo, float(m_netFrames) / 16.667F, (m_netLost * 100U) / m_netFrames, float(m_netErrs * 100U) / float(m_netBits)); } else if (dataType == DT_DATA_HEADER) { - if (m_state == RS_RELAYING_NETWORK_DATA) + if (m_netState == RS_NET_DATA) return; CDMRDataHeader dataHeader; @@ -697,9 +724,9 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) unsigned int srcId = dataHeader.getSrcId(); unsigned int dstId = dataHeader.getDstId(); - m_frames = dataHeader.getBlocks(); + m_netFrames = dataHeader.getBlocks(); - m_lc = new CDMRLC(gi ? FLCO_GROUP : FLCO_USER_USER, srcId, dstId); + m_netLC = new CDMRLC(gi ? FLCO_GROUP : FLCO_USER_USER, srcId, dstId); // Regenerate the data header dataHeader.get(data + 2U); @@ -717,66 +744,66 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[1U] = 0x00U; // Put a small delay into starting transmission - writeQueue(m_idle); - writeQueue(m_idle); + writeQueueNet(m_idle); + writeQueueNet(m_idle); for (unsigned i = 0U; i < 3U; i++) - writeQueue(data); + writeQueueNet(data); - m_state = RS_RELAYING_NETWORK_DATA; + m_netState = RS_NET_DATA; setShortLC(m_slotNo, dmrData.getDstId(), gi ? FLCO_GROUP : FLCO_USER_USER, false); m_display->writeDMR(m_slotNo, dmrData.getSrcId(), gi, dmrData.getDstId(), "ND"); - LogMessage("DMR Slot %u, received network data header from %u to %s%u, %u blocks", m_slotNo, dmrData.getSrcId(), gi ? "TG ": "", dmrData.getDstId(), m_frames); + LogMessage("DMR Slot %u, received network data header from %u to %s%u, %u blocks", m_slotNo, dmrData.getSrcId(), gi ? "TG ": "", dmrData.getDstId(), m_netFrames); } else if (dataType == DT_VOICE_SYNC) { - if (m_state == RS_LISTENING) { - m_lc = new CDMRLC(dmrData.getFLCO(), dmrData.getSrcId(), dmrData.getDstId()); + if (m_netState == RS_NET_IDLE) { + m_netLC = new CDMRLC(dmrData.getFLCO(), dmrData.getSrcId(), dmrData.getDstId()); - m_timeoutTimer.start(); + m_netTimeoutTimer.start(); // 540ms of idle to give breathing space for lost frames for (unsigned int i = 0U; i < 9U; i++) - writeQueue(m_idle); + writeQueueNet(m_idle); #if defined(DUMP_DMR) openFile(); #endif - m_frames = 0U; + m_netFrames = 0U; + m_netLost = 0U; + m_netBits = 1U; + m_netErrs = 0U; - m_bits = 1U; - m_errs = 0U; + m_netState = RS_NET_AUDIO; - m_state = RS_RELAYING_NETWORK_AUDIO; + setShortLC(m_slotNo, m_netLC->getDstId(), m_netLC->getFLCO(), true); - setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO(), true); + m_display->writeDMR(m_slotNo, m_netLC->getSrcId(), m_netLC->getFLCO() == FLCO_GROUP, m_netLC->getDstId(), "NV"); - m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId(), "NV"); - - LogMessage("DMR Slot %u, received network late entry from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId()); + LogMessage("DMR Slot %u, received network late entry from %u to %s%u", m_slotNo, m_netLC->getSrcId(), m_netLC->getFLCO() == FLCO_GROUP ? "TG " : "", m_netLC->getDstId()); } - if (m_state == RS_RELAYING_NETWORK_AUDIO) { - unsigned char fid = m_lc->getFID(); + if (m_netState == RS_NET_AUDIO) { + unsigned char fid = m_netLC->getFID(); if (fid == FID_ETSI || fid == FID_DMRA) { unsigned int errors = m_fec.regenerateDMR(data + 2U); LogDebug("DMR Slot %u, audio, errs: %u/141", m_slotNo, errors); - m_errs += errors; + m_netErrs += errors; } - m_bits += 141U; + m_netBits += 141U; data[0U] = TAG_DATA; data[1U] = 0x00U; // Initialise the lost packet data - if (m_frames == 0U) { + if (m_netFrames == 0U) { ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); m_seqNo = dmrData.getSeqNo(); m_n = dmrData.getN(); m_elapsed.start(); - m_lost = 0U; + m_netLost = 0U; } else { insertSilence(data, dmrData.getSeqNo()); } @@ -784,10 +811,10 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // Convert the Audio Sync to be from the BS CSync::addDMRAudioSync(data + 2U); - writeQueue(data); + writeQueueNet(data); m_packetTimer.start(); - m_frames++; + m_netFrames++; // Save details in case we need to infill data m_seqNo = dmrData.getSeqNo(); @@ -798,17 +825,17 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) #endif } } else if (dataType == DT_VOICE) { - if (m_state != RS_RELAYING_NETWORK_AUDIO) + if (m_netState != RS_NET_AUDIO) return; - unsigned char fid = m_lc->getFID(); + unsigned char fid = m_netLC->getFID(); if (fid == FID_ETSI || fid == FID_DMRA) { unsigned int errors = m_fec.regenerateDMR(data + 2U); LogDebug("DMR Slot %u, audio, errs: %u/141", m_slotNo, errors); - m_errs += errors; + m_netErrs += errors; } - m_bits += 141U; + m_netBits += 141U; // Change the color code in the EMB m_lastEMB.putData(data + 2U); @@ -819,20 +846,20 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[1U] = 0x00U; // Initialise the lost packet data - if (m_frames == 0U) { + if (m_netFrames == 0U) { ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); m_seqNo = dmrData.getSeqNo(); m_n = dmrData.getN(); m_elapsed.start(); - m_lost = 0U; + m_netLost = 0U; } else { insertSilence(data, dmrData.getSeqNo()); } - writeQueue(data); + writeQueueNet(data); m_packetTimer.start(); - m_frames++; + m_netFrames++; // Save details in case we need to infill data m_seqNo = dmrData.getSeqNo(); @@ -873,7 +900,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = TAG_DATA; data[1U] = 0x00U; - writeQueue(data); + writeQueueNet(data); #if defined(DUMP_DMR) openFile(); @@ -889,7 +916,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) break; } } else if (dataType == DT_RATE_12_DATA || dataType == DT_RATE_34_DATA || dataType == DT_RATE_1_DATA) { - if (m_state != RS_RELAYING_NETWORK_DATA) + if (m_netState != RS_NET_DATA) return; // Regenerate the payload if possible @@ -909,19 +936,19 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // Convert the Data Sync to be from the BS CSync::addDMRDataSync(data + 2U); - m_frames--; + m_netFrames--; - data[0U] = m_frames == 0U ? TAG_EOT : TAG_DATA; + data[0U] = m_netFrames == 0U ? TAG_EOT : TAG_DATA; data[1U] = 0x00U; #if defined(DUMP_DMR) writeFile(data); #endif - writeQueue(data); + writeQueueNet(data); - if (m_frames == 0U) { + if (m_netFrames == 0U) { LogMessage("DMR Slot %u, ended network data transmission", m_slotNo); - writeEndOfTransmission(); + writeEndNet(); } } else { // Unhandled data type @@ -931,24 +958,25 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) void CDMRSlot::clock(unsigned int ms) { - m_timeoutTimer.clock(ms); + m_rfTimeoutTimer.clock(ms); + m_netTimeoutTimer.clock(ms); - if (m_state == RS_RELAYING_NETWORK_AUDIO || m_state == RS_RELAYING_NETWORK_DATA) { + if (m_netState == RS_NET_AUDIO || m_netState == RS_NET_DATA) { m_networkWatchdog.clock(ms); if (m_networkWatchdog.hasExpired()) { - if (m_state == RS_RELAYING_NETWORK_AUDIO) { + if (m_netState == RS_NET_AUDIO) { // We've received the voice header haven't we? - m_frames += 1U; - if (m_bits == 0U) m_bits = 1U; - LogMessage("DMR Slot %u, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %.1f%%", m_slotNo, float(m_frames) / 16.667F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits)); - writeEndOfTransmission(true); + m_netFrames += 1U; + if (m_netBits == 0U) m_netBits = 1U; + LogMessage("DMR Slot %u, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %.1f%%", m_slotNo, float(m_netFrames) / 16.667F, (m_netLost * 100U) / m_netFrames, float(m_netErrs * 100U) / float(m_netBits)); + writeEndNet(true); #if defined(DUMP_DMR) closeFile(); #endif } else { LogMessage("DMR Slot %u, network watchdog has expired", m_slotNo); - writeEndOfTransmission(); + writeEndNet(); #if defined(DUMP_DMR) closeFile(); #endif @@ -956,17 +984,17 @@ void CDMRSlot::clock(unsigned int ms) } } - if (m_state == RS_RELAYING_NETWORK_AUDIO) { + if (m_netState == RS_NET_AUDIO) { m_packetTimer.clock(ms); if (m_packetTimer.isRunning() && m_packetTimer.hasExpired()) { unsigned int elapsed = m_elapsed.elapsed(); unsigned int frames = elapsed / DMR_SLOT_TIME; - if (frames > m_frames) { - unsigned int count = frames - m_frames; + if (frames > m_netFrames) { + unsigned int count = frames - m_netFrames; if (count > 3U) { - LogMessage("DMR Slot %u, lost audio for 300ms filling in, elapsed: %ums, expected: %u, received: %u", m_slotNo, elapsed, frames, m_frames); + LogMessage("DMR Slot %u, lost audio for 300ms filling in, elapsed: %ums, expected: %u, received: %u", m_slotNo, elapsed, frames, m_netFrames); insertSilence(count - 1U); } } @@ -976,27 +1004,33 @@ void CDMRSlot::clock(unsigned int ms) } } -void CDMRSlot::writeQueue(const unsigned char *data) +void CDMRSlot::writeQueueRF(const unsigned char *data) { + if (m_netState != RS_NET_IDLE) + return; + unsigned char len = DMR_FRAME_LENGTH_BYTES + 2U; m_queue.addData(&len, 1U); // If the timeout has expired, replace the audio with idles to keep the slot busy - if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) + if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) m_queue.addData(m_idle, len); else m_queue.addData(data, len); } -void CDMRSlot::writeNetwork(const unsigned char* data, unsigned char dataType, FLCO flco, unsigned int srcId, unsigned int dstId) +void CDMRSlot::writeNetworkRF(const unsigned char* data, unsigned char dataType, FLCO flco, unsigned int srcId, unsigned int dstId) { assert(data != NULL); + if (m_netState != RS_NET_IDLE) + return; + if (m_network == NULL) return; // Don't send to the network if the timeout has expired - if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) + if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) return; CDMRData dmrData; @@ -1015,12 +1049,24 @@ void CDMRSlot::writeNetwork(const unsigned char* data, unsigned char dataType, F m_network->write(dmrData); } -void CDMRSlot::writeNetwork(const unsigned char* data, unsigned char dataType) +void CDMRSlot::writeNetworkRF(const unsigned char* data, unsigned char dataType) { assert(data != NULL); - assert(m_lc != NULL); + assert(m_rfLC != NULL); - writeNetwork(data, dataType, m_lc->getFLCO(), m_lc->getSrcId(), m_lc->getDstId()); + writeNetworkRF(data, dataType, m_rfLC->getFLCO(), m_rfLC->getSrcId(), m_rfLC->getDstId()); +} + +void CDMRSlot::writeQueueNet(const unsigned char *data) +{ + unsigned char len = DMR_FRAME_LENGTH_BYTES + 2U; + m_queue.addData(&len, 1U); + + // If the timeout has expired, replace the audio with idles to keep the slot busy + if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired()) + m_queue.addData(m_idle, len); + else + m_queue.addData(data, len); } void CDMRSlot::init(unsigned int colorCode, CModem* modem, CDMRIPSC* network, IDisplay* display, bool duplex) @@ -1220,13 +1266,13 @@ void CDMRSlot::insertSilence(unsigned int count) m_lastEMB.getData(data + 2U); } - writeQueue(data); + writeQueueNet(data); m_seqNo = seqNo; m_n = n; - m_frames++; - m_lost++; + m_netFrames++; + m_netLost++; seqNo++; n = (n + 1U) % 6U; diff --git a/DMRSlot.h b/DMRSlot.h index 10ec0db..149c155 100644 --- a/DMRSlot.h +++ b/DMRSlot.h @@ -51,20 +51,26 @@ public: private: unsigned int m_slotNo; CRingBuffer m_queue; - RPT_STATE m_state; + RPT_RF_STATE m_rfState; + RPT_NET_STATE m_netState; CDMREmbeddedLC m_embeddedLC; - CDMRLC* m_lc; + CDMRLC* m_rfLC; + CDMRLC* m_netLC; unsigned char m_seqNo; unsigned char m_n; CTimer m_networkWatchdog; - CTimer m_timeoutTimer; + CTimer m_rfTimeoutTimer; + CTimer m_netTimeoutTimer; CTimer m_packetTimer; CStopWatch m_elapsed; - unsigned int m_frames; - unsigned int m_lost; + unsigned int m_rfFrames; + unsigned int m_netFrames; + unsigned int m_netLost; CAMBEFEC m_fec; - unsigned int m_bits; - unsigned int m_errs; + unsigned int m_rfBits; + unsigned int m_netBits; + unsigned int m_rfErrs; + unsigned int m_netErrs; unsigned char* m_lastFrame; CDMREMB m_lastEMB; FILE* m_fp; @@ -84,11 +90,13 @@ private: static unsigned char m_id2; static bool m_voice2; - void writeQueue(const unsigned char* data); - void writeNetwork(const unsigned char* data, unsigned char dataType); - void writeNetwork(const unsigned char* data, unsigned char dataType, FLCO flco, unsigned int srcId, unsigned int dstId); + void writeQueueRF(const unsigned char* data); + void writeQueueNet(const unsigned char* data); + void writeNetworkRF(const unsigned char* data, unsigned char dataType); + void writeNetworkRF(const unsigned char* data, unsigned char dataType, FLCO flco, unsigned int srcId, unsigned int dstId); - void writeEndOfTransmission(bool writeEnd = false); + void writeEndRF(bool writeEnd = false); + void writeEndNet(bool writeEnd = false); bool openFile(); bool writeFile(const unsigned char* data); diff --git a/DStarControl.cpp b/DStarControl.cpp index b08a719..2793c02 100644 --- a/DStarControl.cpp +++ b/DStarControl.cpp @@ -30,22 +30,28 @@ m_network(network), m_display(display), m_duplex(duplex), m_queue(1000U, "D-Star Control"), -m_header(), -m_state(RS_LISTENING), +m_rfHeader(), +m_netHeader(), +m_rfState(RS_RF_LISTENING), +m_netState(RS_NET_IDLE), m_net(false), m_slowData(), m_n(0U), m_networkWatchdog(1000U, 0U, 1500U), m_holdoffTimer(1000U, 0U, 500U), -m_timeoutTimer(1000U, timeout), +m_rfTimeoutTimer(1000U, timeout), +m_netTimeoutTimer(1000U, timeout), m_packetTimer(1000U, 0U, 200U), m_ackTimer(1000U, 0U, 750U), m_elapsed(), -m_frames(0U), -m_lost(0U), +m_rfFrames(0U), +m_netFrames(0U), +m_netLost(0U), m_fec(), -m_bits(0U), -m_errs(0U), +m_rfBits(0U), +m_netBits(0U), +m_rfErrs(0U), +m_netErrs(0U), m_lastFrame(NULL), m_fp(NULL) { @@ -83,17 +89,16 @@ bool CDStarControl::writeModem(unsigned char *data) { unsigned char type = data[0U]; - if (type == TAG_LOST && m_state == RS_RELAYING_RF_AUDIO) { - if (m_bits == 0U) m_bits = 1U; - LogMessage("D-Star, transmission lost, %.1f seconds, BER: %.1f%%", float(m_frames) / 50.0F, float(m_errs * 100U) / float(m_bits)); - m_ackTimer.start(); - writeEndOfTransmission(); + if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) { + if (m_rfBits == 0U) m_rfBits = 1U; + LogMessage("D-Star, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits)); + writeEndRF(); return false; } if (type == TAG_LOST) { - if (m_state == RS_LATE_ENTRY) - m_state = RS_LISTENING; + if (m_rfState == RS_RF_LATE_ENTRY) + m_rfState = RS_RF_LISTENING; return false; } @@ -129,98 +134,79 @@ bool CDStarControl::writeModem(unsigned char *data) m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0; - if (m_state == RS_LISTENING) { - // Only start the timeout if not already running - if (!m_timeoutTimer.isRunning()) { - m_timeoutTimer.start(); - m_bits = 1U; - m_errs = 0U; - } + // Only start the timeout if not already running + if (!m_rfTimeoutTimer.isRunning()) { + m_rfTimeoutTimer.start(); + m_rfBits = 1U; + m_rfErrs = 0U; + } - m_header = header; + m_rfHeader = header; - m_networkWatchdog.stop(); - m_holdoffTimer.stop(); - m_ackTimer.stop(); + m_holdoffTimer.stop(); + m_ackTimer.stop(); - m_frames = 1U; - m_lost = 0U; + m_rfFrames = 1U; - m_n = 0U; + if (m_duplex) { + // Modify the header + header.setRepeater(false); + header.setRPTCall1(m_callsign); + header.setRPTCall2(m_callsign); + header.get(data + 1U); - if (m_duplex) { - // Modify the header - header.setRepeater(false); - header.setRPTCall1(m_callsign); - header.setRPTCall2(m_callsign); - header.get(data + 1U); + writeQueueHeaderRF(data); + } - writeQueueHeader(data); - } + if (m_net) { + // Modify the header + header.setRepeater(false); + header.setRPTCall1(m_callsign); + header.setRPTCall2(m_gateway); + header.get(data + 1U); - if (m_net) { - // Modify the header - header.setRepeater(false); - header.setRPTCall1(m_callsign); - header.setRPTCall2(m_gateway); - header.get(data + 1U); + for (unsigned i = 0U; i < 3U; i++) + writeNetworkHeaderRF(data); + } - for (unsigned i = 0U; i < 3U; i++) - writeNetworkHeader(data, false); - } - - m_state = RS_RELAYING_RF_AUDIO; + m_rfState = RS_RF_AUDIO; + if (m_netState == RS_NET_IDLE) m_display->writeDStar((char*)my1, (char*)my2, (char*)your); - LogMessage("D-Star, received RF header from %8.8s/%4.4s to %8.8s", my1, my2, your); - } else if (m_state == RS_RELAYING_NETWORK_AUDIO) { - if (m_net) { - for (unsigned i = 0U; i < 3U; i++) - writeNetworkHeader(data, true); - } - - LogMessage("D-Star, received RF busy header from %8.8s/%4.4s to %8.8s", my1, my2, your); - - return false; - } + LogMessage("D-Star, received RF header from %8.8s/%4.4s to %8.8s", my1, my2, your); } else if (type == TAG_EOT) { - if (m_state == RS_RELAYING_RF_AUDIO) { + if (m_rfState == RS_RF_AUDIO) { if (m_net) - writeNetworkData(DSTAR_END_PATTERN_BYTES, 0U, true, false); + writeNetworkDataRF(DSTAR_END_PATTERN_BYTES, 0U, true); if (m_duplex) - writeQueueEOT(); + writeQueueEOTRF(); - m_ackTimer.start(); + if (m_rfBits == 0U) m_rfBits = 1U; + LogMessage("D-Star, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits)); - if (m_bits == 0U) m_bits = 1U; - LogMessage("D-Star, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_frames) / 50.0F, float(m_errs * 100U) / float(m_bits)); - - writeEndOfTransmission(); - } else if (m_state == RS_RELAYING_NETWORK_AUDIO) { - if (m_net) - writeNetworkData(DSTAR_END_PATTERN_BYTES, 0U, true, true); + writeEndRF(); } return false; } else if (type == TAG_DATA) { - if (m_state == RS_LISTENING) { + if (m_rfState == RS_RF_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) { m_slowData.start(); - m_state = RS_LATE_ENTRY; + m_rfState = RS_RF_LATE_ENTRY; } return false; - } else if (m_state == RS_RELAYING_RF_AUDIO) { + } else if (m_rfState == RS_RF_AUDIO) { unsigned int errors = m_fec.regenerateDStar(data + 1U); LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_n, errors); - m_errs += errors; - m_bits += 48U; + m_rfErrs += errors; + m_rfBits += 48U; - m_frames++; + m_rfFrames++; // 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) @@ -233,20 +219,13 @@ bool CDStarControl::writeModem(unsigned char *data) m_n = (m_n + 1U) % 21U; if (m_net) - writeNetworkData(data, errors, false, false); + writeNetworkDataRF(data, errors, false); if (m_duplex) { blankDTMF(data + 1U); - writeQueueData(data); + writeQueueDataRF(data); } - } else if (m_state == RS_RELAYING_NETWORK_AUDIO) { - m_fec.regenerateDStar(data + 1U); - - if (m_net) - writeNetworkData(data, 0U, false, true); - - return false; - } else if (m_state == RS_LATE_ENTRY) { + } else if (m_rfState == RS_RF_LATE_ENTRY) { // 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_slowData.reset(); @@ -287,22 +266,18 @@ bool CDStarControl::writeModem(unsigned char *data) m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0; // Only reset the timeout if the timeout is not running - if (!m_timeoutTimer.isRunning()) { - m_timeoutTimer.start(); - m_bits = 1U; - m_errs = 0U; + if (!m_rfTimeoutTimer.isRunning()) { + m_rfTimeoutTimer.start(); + m_rfBits = 1U; + m_rfErrs = 0U; } // Create a dummy start frame to replace the received frame - m_networkWatchdog.stop(); m_ackTimer.stop(); - m_header = *header; + m_rfHeader = *header; - m_frames = 1U; - m_lost = 0U; - - m_n = 1U; + m_rfFrames = 1U; if (m_duplex) { unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U]; @@ -314,7 +289,7 @@ bool CDStarControl::writeModem(unsigned char *data) header->setRPTCall2(m_callsign); header->get(start + 1U); - writeQueueHeader(start); + writeQueueHeaderRF(start); } if (m_net) { @@ -328,7 +303,7 @@ bool CDStarControl::writeModem(unsigned char *data) header->get(start + 1U); for (unsigned int i = 0U; i < 3U; i++) - writeNetworkHeader(start, false); + writeNetworkHeaderRF(start); } delete header; @@ -336,20 +311,21 @@ bool CDStarControl::writeModem(unsigned char *data) unsigned int errors = m_fec.regenerateDStar(data + 1U); LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_n, errors); - m_errs += errors; - m_bits += 48U; + m_rfErrs += errors; + m_rfBits += 48U; if (m_net) - writeNetworkData(data, errors, false, false); + writeNetworkDataRF(data, errors, false); if (m_duplex) { blankDTMF(data + 1U); - writeQueueData(data); + writeQueueDataRF(data); } - m_state = RS_RELAYING_RF_AUDIO; + m_rfState = RS_RF_AUDIO; - m_display->writeDStar((char*)my1, (char*)my2, (char*)your); + if (m_netState == RS_NET_IDLE) + m_display->writeDStar((char*)my1, (char*)my2, (char*)your); LogMessage("D-Star, received RF late entry from %8.8s/%4.4s to %8.8s", my1, my2, your); } @@ -377,12 +353,28 @@ unsigned int CDStarControl::readModem(unsigned char* data) return len; } -void CDStarControl::writeEndOfTransmission() +void CDStarControl::writeEndRF() { - m_state = RS_LISTENING; + m_rfState = RS_RF_LISTENING; + + if (m_netState == RS_NET_IDLE) { + m_display->clearDStar(); + m_ackTimer.start(); + + if (m_network != NULL) + m_network->reset(); + } else { + m_rfTimeoutTimer.stop(); + } +} + +void CDStarControl::writeEndNet() +{ + m_netState = RS_NET_IDLE; m_display->clearDStar(); + m_netTimeoutTimer.stop(); m_networkWatchdog.stop(); m_packetTimer.stop(); @@ -403,7 +395,7 @@ void CDStarControl::writeNetwork() if (length == 0U) return; - if (m_state == RS_RELAYING_RF_AUDIO || m_state == RS_LATE_ENTRY) + if (m_rfState != RS_RF_LISTENING && m_netState == RS_NET_IDLE) return; m_networkWatchdog.start(); @@ -411,7 +403,7 @@ void CDStarControl::writeNetwork() unsigned char type = data[0U]; if (type == TAG_HEADER) { - if (m_state != RS_LISTENING) + if (m_netState != RS_NET_IDLE) return; CDStarHeader header(data + 1U); @@ -425,39 +417,39 @@ void CDStarControl::writeNetwork() unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH]; header.getYourCall(your); - m_header = header; + m_netHeader = header; - m_timeoutTimer.start(); + m_netTimeoutTimer.start(); m_packetTimer.start(); m_elapsed.start(); m_ackTimer.stop(); - m_frames = 0U; - m_lost = 0U; + m_netFrames = 0U; + m_netLost = 0U; m_n = 0U; - m_bits = 1U; - m_errs = 0U; + m_netBits = 1U; + m_netErrs = 0U; - writeQueueHeader(data); + writeQueueHeaderNet(data); #if defined(DUMP_DSTAR) openFile(); writeFile(data + 1U, length - 1U); #endif - m_state = RS_RELAYING_NETWORK_AUDIO; + m_netState = RS_NET_AUDIO; m_display->writeDStar((char*)my1, (char*)my2, (char*)your); LogMessage("D-Star, received network header from %8.8s/%4.4s to %8.8s", my1, my2, your); } else if (type == TAG_EOT) { - if (m_state != RS_RELAYING_NETWORK_AUDIO) + if (m_netState != RS_NET_AUDIO) return; - m_timeoutTimer.stop(); + m_netTimeoutTimer.stop(); - writeQueueEOT(); + writeQueueEOTNet(); data[1U] = TAG_EOT; @@ -466,13 +458,13 @@ void CDStarControl::writeNetwork() closeFile(); #endif // We've received the header and EOT haven't we? - m_frames += 2U; - if (m_bits == 0U) m_bits = 1U; - LogMessage("D-Star, received network end of transmission, %.1f seconds, %u%% packet loss, BER: %.1f%%", float(m_frames) / 50.0F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits)); + m_netFrames += 2U; + if (m_netBits == 0U) m_netBits = 1U; + LogMessage("D-Star, received network end of transmission, %.1f seconds, %u%% packet loss, BER: %.1f%%", float(m_netFrames) / 50.0F, (m_netLost * 100U) / m_netFrames, float(m_netErrs * 100U) / float(m_netBits)); - writeEndOfTransmission(); + writeEndNet(); } else if (type == TAG_DATA) { - if (m_state != RS_RELAYING_NETWORK_AUDIO) + if (m_netState != RS_NET_AUDIO) return; unsigned char n = data[1U]; @@ -481,8 +473,8 @@ void CDStarControl::writeNetwork() unsigned int errors = m_fec.regenerateDStar(data + 2U); - m_errs += errors; - m_bits += 48U; + m_netErrs += errors; + m_netBits += 48U; blankDTMF(data + 2U); @@ -493,14 +485,14 @@ void CDStarControl::writeNetwork() m_n = n; m_packetTimer.start(); - m_frames++; + m_netFrames++; data[1U] = TAG_DATA; #if defined(DUMP_DSTAR) writeFile(data + 1U, length - 1U); #endif - writeQueueData(data + 1U); + writeQueueDataNet(data + 1U); } else { CUtils::dump("D-Star, unknown data from network", data, DSTAR_FRAME_LENGTH_BYTES + 1U); } @@ -521,35 +513,36 @@ void CDStarControl::clock(unsigned int ms) if (m_holdoffTimer.isRunning() && m_holdoffTimer.hasExpired()) m_holdoffTimer.stop(); - m_timeoutTimer.clock(ms); + m_rfTimeoutTimer.clock(ms); + m_netTimeoutTimer.clock(ms); - if (m_state == RS_RELAYING_NETWORK_AUDIO) { + if (m_netState == RS_NET_AUDIO) { m_networkWatchdog.clock(ms); if (m_networkWatchdog.hasExpired()) { // We're received the header haven't we? - m_frames += 1U; - if (m_bits == 0U) m_bits = 1U; - LogMessage("D-Star, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %.1f%%", float(m_frames) / 50.0F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits)); - m_timeoutTimer.stop(); - writeEndOfTransmission(); + m_netFrames += 1U; + if (m_netBits == 0U) m_netBits = 1U; + LogMessage("D-Star, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %.1f%%", float(m_netFrames) / 50.0F, (m_netLost * 100U) / m_netFrames, float(m_netErrs * 100U) / float(m_netBits)); + m_netTimeoutTimer.stop(); + writeEndNet(); #if defined(DUMP_DSTAR) closeFile(); #endif } } - if (m_state == RS_RELAYING_NETWORK_AUDIO) { + if (m_netState == RS_NET_AUDIO) { m_packetTimer.clock(ms); if (m_packetTimer.isRunning() && m_packetTimer.hasExpired()) { unsigned int elapsed = m_elapsed.elapsed(); unsigned int frames = elapsed / DSTAR_FRAME_TIME; - if (frames > m_frames) { - unsigned int count = frames - m_frames; + if (frames > m_netFrames) { + unsigned int count = frames - m_netFrames; if (count > 5U) { - LogMessage("D-Star, lost audio for 200ms filling in, elapsed: %ums, expected: %u, received: %u", elapsed, frames, m_frames); + LogMessage("D-Star, lost audio for 200ms filling in, elapsed: %ums, expected: %u, received: %u", elapsed, frames, m_netFrames); insertSilence(count - 2U); } } @@ -559,11 +552,14 @@ void CDStarControl::clock(unsigned int ms) } } -void CDStarControl::writeQueueHeader(const unsigned char *data) +void CDStarControl::writeQueueHeaderRF(const unsigned char *data) { assert(data != NULL); - if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) + if (m_netState != RS_NET_IDLE) + return; + + if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) return; unsigned char len = DSTAR_HEADER_LENGTH_BYTES + 1U; @@ -572,11 +568,14 @@ void CDStarControl::writeQueueHeader(const unsigned char *data) m_queue.addData(data, len); } -void CDStarControl::writeQueueData(const unsigned char *data) +void CDStarControl::writeQueueDataRF(const unsigned char *data) { assert(data != NULL); - if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) + if (m_netState != RS_NET_IDLE) + return; + + if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) return; unsigned char len = DSTAR_FRAME_LENGTH_BYTES + 1U; @@ -585,9 +584,12 @@ void CDStarControl::writeQueueData(const unsigned char *data) m_queue.addData(data, len); } -void CDStarControl::writeQueueEOT() +void CDStarControl::writeQueueEOTRF() { - if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) + if (m_netState != RS_NET_IDLE) + return; + + if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) return; unsigned char len = 1U; @@ -597,21 +599,45 @@ void CDStarControl::writeQueueEOT() m_queue.addData(&data, len); } -void CDStarControl::writeNetworkHeader(const unsigned char* data, bool busy) +void CDStarControl::writeQueueHeaderNet(const unsigned char *data) { assert(data != NULL); - if (m_network == NULL) + if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired()) return; - // Don't send to the network if the timeout has expired - if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) - return; + unsigned char len = DSTAR_HEADER_LENGTH_BYTES + 1U; + m_queue.addData(&len, 1U); - m_network->writeHeader(data + 1U, DSTAR_HEADER_LENGTH_BYTES, busy); + m_queue.addData(data, len); } -void CDStarControl::writeNetworkData(const unsigned char* data, unsigned int errors, bool end, bool busy) +void CDStarControl::writeQueueDataNet(const unsigned char *data) +{ + assert(data != NULL); + + if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired()) + return; + + unsigned char len = DSTAR_FRAME_LENGTH_BYTES + 1U; + m_queue.addData(&len, 1U); + + m_queue.addData(data, len); +} + +void CDStarControl::writeQueueEOTNet() +{ + if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired()) + return; + + unsigned char len = 1U; + m_queue.addData(&len, 1U); + + unsigned char data = TAG_EOT; + m_queue.addData(&data, len); +} + +void CDStarControl::writeNetworkHeaderRF(const unsigned char* data) { assert(data != NULL); @@ -619,11 +645,24 @@ void CDStarControl::writeNetworkData(const unsigned char* data, unsigned int err return; // Don't send to the network if the timeout has expired - if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) + if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) return; - // XXX - m_network->writeData(data + 1U, DSTAR_FRAME_LENGTH_BYTES, errors, end, busy); + m_network->writeHeader(data + 1U, DSTAR_HEADER_LENGTH_BYTES, m_netState != RS_NET_IDLE); +} + +void CDStarControl::writeNetworkDataRF(const unsigned char* data, unsigned int errors, bool end) +{ + assert(data != NULL); + + if (m_network == NULL) + return; + + // Don't send to the network if the timeout has expired + if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) + return; + + m_network->writeData(data + 1U, DSTAR_FRAME_LENGTH_BYTES, errors, end, m_netState != RS_NET_IDLE); } bool CDStarControl::openFile() @@ -699,18 +738,18 @@ void CDStarControl::insertSilence(unsigned int count) for (unsigned int i = 0U; i < count; i++) { if (i < 3U) { - writeQueueData(m_lastFrame); + writeQueueDataNet(m_lastFrame); } else { if (n == 0U) - writeQueueData(DSTAR_NULL_FRAME_SYNC_BYTES); + writeQueueDataNet(DSTAR_NULL_FRAME_SYNC_BYTES); else - writeQueueData(DSTAR_NULL_FRAME_DATA_BYTES); + writeQueueDataNet(DSTAR_NULL_FRAME_DATA_BYTES); } m_n = n; - m_frames++; - m_lost++; + m_netFrames++; + m_netLost++; n = (n + 1U) % 21U; } @@ -733,10 +772,10 @@ void CDStarControl::blankDTMF(unsigned char* data) const void CDStarControl::sendAck() { - m_timeoutTimer.stop(); + m_rfTimeoutTimer.stop(); unsigned char user[DSTAR_LONG_CALLSIGN_LENGTH]; - m_header.getMyCall1(user); + m_rfHeader.getMyCall1(user); CDStarHeader header; header.setUnavailable(true); @@ -749,9 +788,9 @@ void CDStarControl::sendAck() header.get(data + 1U); data[0U] = TAG_HEADER; - writeQueueHeader(data); + writeQueueHeaderRF(data); - writeQueueData(DSTAR_NULL_FRAME_SYNC_BYTES); + writeQueueDataRF(DSTAR_NULL_FRAME_SYNC_BYTES); LINK_STATUS status = LS_NONE; unsigned char reflector[DSTAR_LONG_CALLSIGN_LENGTH]; @@ -760,17 +799,17 @@ void CDStarControl::sendAck() char text[40U]; if (status == LS_LINKED_DEXTRA || status == LS_LINKED_DPLUS || status == LS_LINKED_DCS || status == LS_LINKED_CCS || status == LS_LINKED_LOOPBACK) - ::sprintf(text, "%-8.8s BER: %.1f%% ", reflector, float(m_errs * 100U) / float(m_bits)); + ::sprintf(text, "%-8.8s BER: %.1f%% ", reflector, float(m_rfErrs * 100U) / float(m_rfBits)); else - ::sprintf(text, "BER: %.1f%% ", float(m_errs * 100U) / float(m_bits)); + ::sprintf(text, "BER: %.1f%% ", float(m_rfErrs * 100U) / float(m_rfBits)); m_slowData.setText(text); ::memcpy(data, DSTAR_NULL_FRAME_DATA_BYTES, DSTAR_FRAME_LENGTH_BYTES + 1U); for (unsigned int i = 0U; i < 19U; i++) { m_slowData.get(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES); - writeQueueData(data); + writeQueueDataRF(data); } - writeQueueEOT(); + writeQueueEOTRF(); } diff --git a/DStarControl.h b/DStarControl.h index b10eedb..ac16768 100644 --- a/DStarControl.h +++ b/DStarControl.h @@ -51,34 +51,44 @@ private: IDisplay* m_display; bool m_duplex; CRingBuffer m_queue; - CDStarHeader m_header; - RPT_STATE m_state; + CDStarHeader m_rfHeader; + CDStarHeader m_netHeader; + RPT_RF_STATE m_rfState; + RPT_NET_STATE m_netState; bool m_net; CDStarSlowData m_slowData; unsigned char m_n; CTimer m_networkWatchdog; CTimer m_holdoffTimer; - CTimer m_timeoutTimer; + CTimer m_rfTimeoutTimer; + CTimer m_netTimeoutTimer; CTimer m_packetTimer; CTimer m_ackTimer; CStopWatch m_elapsed; - unsigned int m_frames; - unsigned int m_lost; + unsigned int m_rfFrames; + unsigned int m_netFrames; + unsigned int m_netLost; CAMBEFEC m_fec; - unsigned int m_bits; - unsigned int m_errs; + unsigned int m_rfBits; + unsigned int m_netBits; + unsigned int m_rfErrs; + unsigned int m_netErrs; unsigned char* m_lastFrame; FILE* m_fp; void writeNetwork(); - void writeQueueHeader(const unsigned char* data); - void writeQueueData(const unsigned char* data); - void writeQueueEOT(); - void writeNetworkHeader(const unsigned char* data, bool busy); - void writeNetworkData(const unsigned char* data, unsigned int errors, bool end, bool busy); + void writeQueueHeaderRF(const unsigned char* data); + void writeQueueDataRF(const unsigned char* data); + void writeQueueEOTRF(); + void writeQueueHeaderNet(const unsigned char* data); + void writeQueueDataNet(const unsigned char* data); + void writeQueueEOTNet(); + void writeNetworkHeaderRF(const unsigned char* data); + void writeNetworkDataRF(const unsigned char* data, unsigned int errors, bool end); - void writeEndOfTransmission(); + void writeEndRF(); + void writeEndNet(); bool openFile(); bool writeFile(const unsigned char* data, unsigned int length); diff --git a/Defines.h b/Defines.h index fddd005..c050cc6 100644 --- a/Defines.h +++ b/Defines.h @@ -29,13 +29,18 @@ const unsigned char TAG_DATA = 0x01U; const unsigned char TAG_LOST = 0x02U; const unsigned char TAG_EOT = 0x03U; -enum RPT_STATE { - RS_LISTENING, - RS_LATE_ENTRY, - RS_RELAYING_RF_AUDIO, - RS_RELAYING_NETWORK_AUDIO, - RS_RELAYING_RF_DATA, - RS_RELAYING_NETWORK_DATA +enum RPT_RF_STATE { + RS_RF_LISTENING, + RS_RF_LATE_ENTRY, + RS_RF_AUDIO, + RS_RF_DATA, +}; + +enum RPT_NET_STATE { + RS_NET_IDLE, + RS_NET_LATE_ENTRY, + RS_NET_AUDIO, + RS_NET_DATA }; #endif diff --git a/YSFControl.cpp b/YSFControl.cpp index edee01a..2ffce75 100644 --- a/YSFControl.cpp +++ b/YSFControl.cpp @@ -33,7 +33,7 @@ CYSFControl::CYSFControl(const std::string& callsign, IDisplay* display, unsigne m_display(display), m_duplex(duplex), m_queue(1000U, "YSF Control"), -m_state(RS_LISTENING), +m_state(RS_RF_LISTENING), m_timeoutTimer(1000U, timeout), m_frames(0U), m_parrot(NULL), @@ -54,7 +54,7 @@ bool CYSFControl::writeModem(unsigned char *data) { unsigned char type = data[0U]; - if (type == TAG_LOST && m_state == RS_RELAYING_RF_AUDIO) { + if (type == TAG_LOST && m_state == RS_RF_AUDIO) { LogMessage("YSF, transmission lost, %.1f seconds", float(m_frames) / 10.0F); if (m_parrot != NULL) @@ -71,18 +71,18 @@ bool CYSFControl::writeModem(unsigned char *data) unsigned char fi = data[1U] & YSF_FI_MASK; unsigned char dt = data[1U] & YSF_DT_MASK; - if (type == TAG_DATA && valid && m_state == RS_LISTENING) { + if (type == TAG_DATA && valid && m_state == RS_RF_LISTENING) { m_frames = 0U; m_timeoutTimer.start(); m_display->writeFusion("XXXXXX"); - m_state = RS_RELAYING_RF_AUDIO; + m_state = RS_RF_AUDIO; LogMessage("YSF, received RF header"); #if defined(DUMP_YSF) openFile(); #endif } - if (m_state != RS_RELAYING_RF_AUDIO) + if (m_state != RS_RF_AUDIO) return false; if (type == TAG_EOT) { @@ -168,7 +168,7 @@ unsigned int CYSFControl::readModem(unsigned char* data) void CYSFControl::writeEndOfTransmission() { - m_state = RS_LISTENING; + m_state = RS_RF_LISTENING; m_timeoutTimer.stop(); diff --git a/YSFControl.h b/YSFControl.h index 5fabdc1..0deb410 100644 --- a/YSFControl.h +++ b/YSFControl.h @@ -44,7 +44,7 @@ private: IDisplay* m_display; bool m_duplex; CRingBuffer m_queue; - RPT_STATE m_state; + RPT_RF_STATE m_state; CTimer m_timeoutTimer; unsigned int m_frames; CYSFParrot* m_parrot;