Split RF and network statues for all modes.

This commit is contained in:
Jonathan Naylor
2016-02-25 19:54:18 +00:00
parent 7822758043
commit ddcde1d8e3
7 changed files with 545 additions and 437 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -51,20 +51,26 @@ public:
private: private:
unsigned int m_slotNo; unsigned int m_slotNo;
CRingBuffer<unsigned char> m_queue; CRingBuffer<unsigned char> m_queue;
RPT_STATE m_state; RPT_RF_STATE m_rfState;
RPT_NET_STATE m_netState;
CDMREmbeddedLC m_embeddedLC; CDMREmbeddedLC m_embeddedLC;
CDMRLC* m_lc; CDMRLC* m_rfLC;
CDMRLC* m_netLC;
unsigned char m_seqNo; unsigned char m_seqNo;
unsigned char m_n; unsigned char m_n;
CTimer m_networkWatchdog; CTimer m_networkWatchdog;
CTimer m_timeoutTimer; CTimer m_rfTimeoutTimer;
CTimer m_netTimeoutTimer;
CTimer m_packetTimer; CTimer m_packetTimer;
CStopWatch m_elapsed; CStopWatch m_elapsed;
unsigned int m_frames; unsigned int m_rfFrames;
unsigned int m_lost; unsigned int m_netFrames;
unsigned int m_netLost;
CAMBEFEC m_fec; CAMBEFEC m_fec;
unsigned int m_bits; unsigned int m_rfBits;
unsigned int m_errs; unsigned int m_netBits;
unsigned int m_rfErrs;
unsigned int m_netErrs;
unsigned char* m_lastFrame; unsigned char* m_lastFrame;
CDMREMB m_lastEMB; CDMREMB m_lastEMB;
FILE* m_fp; FILE* m_fp;
@@ -84,11 +90,13 @@ private:
static unsigned char m_id2; static unsigned char m_id2;
static bool m_voice2; static bool m_voice2;
void writeQueue(const unsigned char* data); void writeQueueRF(const unsigned char* data);
void writeNetwork(const unsigned char* data, unsigned char dataType); void writeQueueNet(const unsigned char* data);
void writeNetwork(const unsigned char* data, unsigned char dataType, FLCO flco, unsigned int srcId, unsigned int dstId); 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 openFile();
bool writeFile(const unsigned char* data); bool writeFile(const unsigned char* data);

View File

@@ -30,22 +30,28 @@ m_network(network),
m_display(display), m_display(display),
m_duplex(duplex), m_duplex(duplex),
m_queue(1000U, "D-Star Control"), m_queue(1000U, "D-Star Control"),
m_header(), m_rfHeader(),
m_state(RS_LISTENING), m_netHeader(),
m_rfState(RS_RF_LISTENING),
m_netState(RS_NET_IDLE),
m_net(false), m_net(false),
m_slowData(), m_slowData(),
m_n(0U), m_n(0U),
m_networkWatchdog(1000U, 0U, 1500U), m_networkWatchdog(1000U, 0U, 1500U),
m_holdoffTimer(1000U, 0U, 500U), m_holdoffTimer(1000U, 0U, 500U),
m_timeoutTimer(1000U, timeout), m_rfTimeoutTimer(1000U, timeout),
m_netTimeoutTimer(1000U, timeout),
m_packetTimer(1000U, 0U, 200U), m_packetTimer(1000U, 0U, 200U),
m_ackTimer(1000U, 0U, 750U), m_ackTimer(1000U, 0U, 750U),
m_elapsed(), m_elapsed(),
m_frames(0U), m_rfFrames(0U),
m_lost(0U), m_netFrames(0U),
m_netLost(0U),
m_fec(), m_fec(),
m_bits(0U), m_rfBits(0U),
m_errs(0U), m_netBits(0U),
m_rfErrs(0U),
m_netErrs(0U),
m_lastFrame(NULL), m_lastFrame(NULL),
m_fp(NULL) m_fp(NULL)
{ {
@@ -83,17 +89,16 @@ bool CDStarControl::writeModem(unsigned char *data)
{ {
unsigned char type = data[0U]; unsigned char type = data[0U];
if (type == TAG_LOST && m_state == RS_RELAYING_RF_AUDIO) { if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) {
if (m_bits == 0U) m_bits = 1U; if (m_rfBits == 0U) m_rfBits = 1U;
LogMessage("D-Star, transmission lost, %.1f seconds, BER: %.1f%%", float(m_frames) / 50.0F, float(m_errs * 100U) / float(m_bits)); LogMessage("D-Star, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits));
m_ackTimer.start(); writeEndRF();
writeEndOfTransmission();
return false; return false;
} }
if (type == TAG_LOST) { if (type == TAG_LOST) {
if (m_state == RS_LATE_ENTRY) if (m_rfState == RS_RF_LATE_ENTRY)
m_state = RS_LISTENING; m_rfState = RS_RF_LISTENING;
return false; return false;
} }
@@ -129,24 +134,19 @@ bool CDStarControl::writeModem(unsigned char *data)
m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0; m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0;
if (m_state == RS_LISTENING) {
// Only start the timeout if not already running // Only start the timeout if not already running
if (!m_timeoutTimer.isRunning()) { if (!m_rfTimeoutTimer.isRunning()) {
m_timeoutTimer.start(); m_rfTimeoutTimer.start();
m_bits = 1U; m_rfBits = 1U;
m_errs = 0U; m_rfErrs = 0U;
} }
m_header = header; m_rfHeader = header;
m_networkWatchdog.stop();
m_holdoffTimer.stop(); m_holdoffTimer.stop();
m_ackTimer.stop(); m_ackTimer.stop();
m_frames = 1U; m_rfFrames = 1U;
m_lost = 0U;
m_n = 0U;
if (m_duplex) { if (m_duplex) {
// Modify the header // Modify the header
@@ -155,7 +155,7 @@ bool CDStarControl::writeModem(unsigned char *data)
header.setRPTCall2(m_callsign); header.setRPTCall2(m_callsign);
header.get(data + 1U); header.get(data + 1U);
writeQueueHeader(data); writeQueueHeaderRF(data);
} }
if (m_net) { if (m_net) {
@@ -166,61 +166,47 @@ bool CDStarControl::writeModem(unsigned char *data)
header.get(data + 1U); header.get(data + 1U);
for (unsigned i = 0U; i < 3U; i++) for (unsigned i = 0U; i < 3U; i++)
writeNetworkHeader(data, false); writeNetworkHeaderRF(data);
} }
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); 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); 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;
}
} else if (type == TAG_EOT) { } else if (type == TAG_EOT) {
if (m_state == RS_RELAYING_RF_AUDIO) { if (m_rfState == RS_RF_AUDIO) {
if (m_net) if (m_net)
writeNetworkData(DSTAR_END_PATTERN_BYTES, 0U, true, false); writeNetworkDataRF(DSTAR_END_PATTERN_BYTES, 0U, true);
if (m_duplex) 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; writeEndRF();
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);
} }
return false; return false;
} else if (type == TAG_DATA) { } 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 // 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) { if (::memcmp(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES) == 0) {
m_slowData.start(); m_slowData.start();
m_state = RS_LATE_ENTRY; m_rfState = RS_RF_LATE_ENTRY;
} }
return false; 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); unsigned int errors = m_fec.regenerateDStar(data + 1U);
LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_n, errors); LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_n, errors);
m_errs += errors; m_rfErrs += errors;
m_bits += 48U; m_rfBits += 48U;
m_frames++; m_rfFrames++;
// The sync is regenerated by the modem so can do exact match // 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) 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; m_n = (m_n + 1U) % 21U;
if (m_net) if (m_net)
writeNetworkData(data, errors, false, false); writeNetworkDataRF(data, errors, false);
if (m_duplex) { if (m_duplex) {
blankDTMF(data + 1U); blankDTMF(data + 1U);
writeQueueData(data); writeQueueDataRF(data);
} }
} else if (m_state == RS_RELAYING_NETWORK_AUDIO) { } else if (m_rfState == RS_RF_LATE_ENTRY) {
m_fec.regenerateDStar(data + 1U);
if (m_net)
writeNetworkData(data, 0U, false, true);
return false;
} else if (m_state == RS_LATE_ENTRY) {
// The sync is regenerated by the modem so can do exact match // 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) { if (::memcmp(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES) == 0) {
m_slowData.reset(); m_slowData.reset();
@@ -287,22 +266,18 @@ bool CDStarControl::writeModem(unsigned char *data)
m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0; m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0;
// Only reset the timeout if the timeout is not running // Only reset the timeout if the timeout is not running
if (!m_timeoutTimer.isRunning()) { if (!m_rfTimeoutTimer.isRunning()) {
m_timeoutTimer.start(); m_rfTimeoutTimer.start();
m_bits = 1U; m_rfBits = 1U;
m_errs = 0U; m_rfErrs = 0U;
} }
// Create a dummy start frame to replace the received frame // Create a dummy start frame to replace the received frame
m_networkWatchdog.stop();
m_ackTimer.stop(); m_ackTimer.stop();
m_header = *header; m_rfHeader = *header;
m_frames = 1U; m_rfFrames = 1U;
m_lost = 0U;
m_n = 1U;
if (m_duplex) { if (m_duplex) {
unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U]; unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U];
@@ -314,7 +289,7 @@ bool CDStarControl::writeModem(unsigned char *data)
header->setRPTCall2(m_callsign); header->setRPTCall2(m_callsign);
header->get(start + 1U); header->get(start + 1U);
writeQueueHeader(start); writeQueueHeaderRF(start);
} }
if (m_net) { if (m_net) {
@@ -328,7 +303,7 @@ bool CDStarControl::writeModem(unsigned char *data)
header->get(start + 1U); header->get(start + 1U);
for (unsigned int i = 0U; i < 3U; i++) for (unsigned int i = 0U; i < 3U; i++)
writeNetworkHeader(start, false); writeNetworkHeaderRF(start);
} }
delete header; delete header;
@@ -336,19 +311,20 @@ bool CDStarControl::writeModem(unsigned char *data)
unsigned int errors = m_fec.regenerateDStar(data + 1U); unsigned int errors = m_fec.regenerateDStar(data + 1U);
LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_n, errors); LogDebug("D-Star, audio sequence no. %u, errs: %u/48", m_n, errors);
m_errs += errors; m_rfErrs += errors;
m_bits += 48U; m_rfBits += 48U;
if (m_net) if (m_net)
writeNetworkData(data, errors, false, false); writeNetworkDataRF(data, errors, false);
if (m_duplex) { if (m_duplex) {
blankDTMF(data + 1U); blankDTMF(data + 1U);
writeQueueData(data); writeQueueDataRF(data);
} }
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); 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); 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; 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_display->clearDStar();
m_netTimeoutTimer.stop();
m_networkWatchdog.stop(); m_networkWatchdog.stop();
m_packetTimer.stop(); m_packetTimer.stop();
@@ -403,7 +395,7 @@ void CDStarControl::writeNetwork()
if (length == 0U) if (length == 0U)
return; 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; return;
m_networkWatchdog.start(); m_networkWatchdog.start();
@@ -411,7 +403,7 @@ void CDStarControl::writeNetwork()
unsigned char type = data[0U]; unsigned char type = data[0U];
if (type == TAG_HEADER) { if (type == TAG_HEADER) {
if (m_state != RS_LISTENING) if (m_netState != RS_NET_IDLE)
return; return;
CDStarHeader header(data + 1U); CDStarHeader header(data + 1U);
@@ -425,39 +417,39 @@ void CDStarControl::writeNetwork()
unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH]; unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
header.getYourCall(your); header.getYourCall(your);
m_header = header; m_netHeader = header;
m_timeoutTimer.start(); m_netTimeoutTimer.start();
m_packetTimer.start(); m_packetTimer.start();
m_elapsed.start(); m_elapsed.start();
m_ackTimer.stop(); m_ackTimer.stop();
m_frames = 0U; m_netFrames = 0U;
m_lost = 0U; m_netLost = 0U;
m_n = 0U; m_n = 0U;
m_bits = 1U; m_netBits = 1U;
m_errs = 0U; m_netErrs = 0U;
writeQueueHeader(data); writeQueueHeaderNet(data);
#if defined(DUMP_DSTAR) #if defined(DUMP_DSTAR)
openFile(); openFile();
writeFile(data + 1U, length - 1U); writeFile(data + 1U, length - 1U);
#endif #endif
m_state = RS_RELAYING_NETWORK_AUDIO; m_netState = RS_NET_AUDIO;
m_display->writeDStar((char*)my1, (char*)my2, (char*)your); 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); LogMessage("D-Star, received network header from %8.8s/%4.4s to %8.8s", my1, my2, your);
} else if (type == TAG_EOT) { } else if (type == TAG_EOT) {
if (m_state != RS_RELAYING_NETWORK_AUDIO) if (m_netState != RS_NET_AUDIO)
return; return;
m_timeoutTimer.stop(); m_netTimeoutTimer.stop();
writeQueueEOT(); writeQueueEOTNet();
data[1U] = TAG_EOT; data[1U] = TAG_EOT;
@@ -466,13 +458,13 @@ void CDStarControl::writeNetwork()
closeFile(); closeFile();
#endif #endif
// We've received the header and EOT haven't we? // We've received the header and EOT haven't we?
m_frames += 2U; m_netFrames += 2U;
if (m_bits == 0U) m_bits = 1U; if (m_netBits == 0U) m_netBits = 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)); 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) { } else if (type == TAG_DATA) {
if (m_state != RS_RELAYING_NETWORK_AUDIO) if (m_netState != RS_NET_AUDIO)
return; return;
unsigned char n = data[1U]; unsigned char n = data[1U];
@@ -481,8 +473,8 @@ void CDStarControl::writeNetwork()
unsigned int errors = m_fec.regenerateDStar(data + 2U); unsigned int errors = m_fec.regenerateDStar(data + 2U);
m_errs += errors; m_netErrs += errors;
m_bits += 48U; m_netBits += 48U;
blankDTMF(data + 2U); blankDTMF(data + 2U);
@@ -493,14 +485,14 @@ void CDStarControl::writeNetwork()
m_n = n; m_n = n;
m_packetTimer.start(); m_packetTimer.start();
m_frames++; m_netFrames++;
data[1U] = TAG_DATA; data[1U] = TAG_DATA;
#if defined(DUMP_DSTAR) #if defined(DUMP_DSTAR)
writeFile(data + 1U, length - 1U); writeFile(data + 1U, length - 1U);
#endif #endif
writeQueueData(data + 1U); writeQueueDataNet(data + 1U);
} else { } else {
CUtils::dump("D-Star, unknown data from network", data, DSTAR_FRAME_LENGTH_BYTES + 1U); 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()) if (m_holdoffTimer.isRunning() && m_holdoffTimer.hasExpired())
m_holdoffTimer.stop(); 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); m_networkWatchdog.clock(ms);
if (m_networkWatchdog.hasExpired()) { if (m_networkWatchdog.hasExpired()) {
// We're received the header haven't we? // We're received the header haven't we?
m_frames += 1U; m_netFrames += 1U;
if (m_bits == 0U) m_bits = 1U; if (m_netBits == 0U) m_netBits = 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)); 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_timeoutTimer.stop(); m_netTimeoutTimer.stop();
writeEndOfTransmission(); writeEndNet();
#if defined(DUMP_DSTAR) #if defined(DUMP_DSTAR)
closeFile(); closeFile();
#endif #endif
} }
} }
if (m_state == RS_RELAYING_NETWORK_AUDIO) { if (m_netState == RS_NET_AUDIO) {
m_packetTimer.clock(ms); m_packetTimer.clock(ms);
if (m_packetTimer.isRunning() && m_packetTimer.hasExpired()) { if (m_packetTimer.isRunning() && m_packetTimer.hasExpired()) {
unsigned int elapsed = m_elapsed.elapsed(); unsigned int elapsed = m_elapsed.elapsed();
unsigned int frames = elapsed / DSTAR_FRAME_TIME; unsigned int frames = elapsed / DSTAR_FRAME_TIME;
if (frames > m_frames) { if (frames > m_netFrames) {
unsigned int count = frames - m_frames; unsigned int count = frames - m_netFrames;
if (count > 5U) { 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); 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); 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; return;
unsigned char len = DSTAR_HEADER_LENGTH_BYTES + 1U; unsigned char len = DSTAR_HEADER_LENGTH_BYTES + 1U;
@@ -572,11 +568,14 @@ void CDStarControl::writeQueueHeader(const unsigned char *data)
m_queue.addData(data, len); m_queue.addData(data, len);
} }
void CDStarControl::writeQueueData(const unsigned char *data) void CDStarControl::writeQueueDataRF(const unsigned char *data)
{ {
assert(data != NULL); 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; return;
unsigned char len = DSTAR_FRAME_LENGTH_BYTES + 1U; unsigned char len = DSTAR_FRAME_LENGTH_BYTES + 1U;
@@ -585,9 +584,12 @@ void CDStarControl::writeQueueData(const unsigned char *data)
m_queue.addData(data, len); 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; return;
unsigned char len = 1U; unsigned char len = 1U;
@@ -597,21 +599,45 @@ void CDStarControl::writeQueueEOT()
m_queue.addData(&data, len); m_queue.addData(&data, len);
} }
void CDStarControl::writeNetworkHeader(const unsigned char* data, bool busy) void CDStarControl::writeQueueHeaderNet(const unsigned char *data)
{ {
assert(data != NULL); assert(data != NULL);
if (m_network == NULL) if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired())
return; return;
// Don't send to the network if the timeout has expired unsigned char len = DSTAR_HEADER_LENGTH_BYTES + 1U;
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) m_queue.addData(&len, 1U);
return;
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); assert(data != NULL);
@@ -619,11 +645,24 @@ void CDStarControl::writeNetworkData(const unsigned char* data, unsigned int err
return; return;
// Don't send to the network if the timeout has expired // 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; return;
// XXX m_network->writeHeader(data + 1U, DSTAR_HEADER_LENGTH_BYTES, m_netState != RS_NET_IDLE);
m_network->writeData(data + 1U, DSTAR_FRAME_LENGTH_BYTES, errors, end, busy); }
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() bool CDStarControl::openFile()
@@ -699,18 +738,18 @@ void CDStarControl::insertSilence(unsigned int count)
for (unsigned int i = 0U; i < count; i++) { for (unsigned int i = 0U; i < count; i++) {
if (i < 3U) { if (i < 3U) {
writeQueueData(m_lastFrame); writeQueueDataNet(m_lastFrame);
} else { } else {
if (n == 0U) if (n == 0U)
writeQueueData(DSTAR_NULL_FRAME_SYNC_BYTES); writeQueueDataNet(DSTAR_NULL_FRAME_SYNC_BYTES);
else else
writeQueueData(DSTAR_NULL_FRAME_DATA_BYTES); writeQueueDataNet(DSTAR_NULL_FRAME_DATA_BYTES);
} }
m_n = n; m_n = n;
m_frames++; m_netFrames++;
m_lost++; m_netLost++;
n = (n + 1U) % 21U; n = (n + 1U) % 21U;
} }
@@ -733,10 +772,10 @@ void CDStarControl::blankDTMF(unsigned char* data) const
void CDStarControl::sendAck() void CDStarControl::sendAck()
{ {
m_timeoutTimer.stop(); m_rfTimeoutTimer.stop();
unsigned char user[DSTAR_LONG_CALLSIGN_LENGTH]; unsigned char user[DSTAR_LONG_CALLSIGN_LENGTH];
m_header.getMyCall1(user); m_rfHeader.getMyCall1(user);
CDStarHeader header; CDStarHeader header;
header.setUnavailable(true); header.setUnavailable(true);
@@ -749,9 +788,9 @@ void CDStarControl::sendAck()
header.get(data + 1U); header.get(data + 1U);
data[0U] = TAG_HEADER; 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; LINK_STATUS status = LS_NONE;
unsigned char reflector[DSTAR_LONG_CALLSIGN_LENGTH]; unsigned char reflector[DSTAR_LONG_CALLSIGN_LENGTH];
@@ -760,17 +799,17 @@ void CDStarControl::sendAck()
char text[40U]; char text[40U];
if (status == LS_LINKED_DEXTRA || status == LS_LINKED_DPLUS || status == LS_LINKED_DCS || status == LS_LINKED_CCS || status == LS_LINKED_LOOPBACK) 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 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); m_slowData.setText(text);
::memcpy(data, DSTAR_NULL_FRAME_DATA_BYTES, DSTAR_FRAME_LENGTH_BYTES + 1U); ::memcpy(data, DSTAR_NULL_FRAME_DATA_BYTES, DSTAR_FRAME_LENGTH_BYTES + 1U);
for (unsigned int i = 0U; i < 19U; i++) { for (unsigned int i = 0U; i < 19U; i++) {
m_slowData.get(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES); m_slowData.get(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES);
writeQueueData(data); writeQueueDataRF(data);
} }
writeQueueEOT(); writeQueueEOTRF();
} }

View File

@@ -51,34 +51,44 @@ private:
IDisplay* m_display; IDisplay* m_display;
bool m_duplex; bool m_duplex;
CRingBuffer<unsigned char> m_queue; CRingBuffer<unsigned char> m_queue;
CDStarHeader m_header; CDStarHeader m_rfHeader;
RPT_STATE m_state; CDStarHeader m_netHeader;
RPT_RF_STATE m_rfState;
RPT_NET_STATE m_netState;
bool m_net; bool m_net;
CDStarSlowData m_slowData; CDStarSlowData m_slowData;
unsigned char m_n; unsigned char m_n;
CTimer m_networkWatchdog; CTimer m_networkWatchdog;
CTimer m_holdoffTimer; CTimer m_holdoffTimer;
CTimer m_timeoutTimer; CTimer m_rfTimeoutTimer;
CTimer m_netTimeoutTimer;
CTimer m_packetTimer; CTimer m_packetTimer;
CTimer m_ackTimer; CTimer m_ackTimer;
CStopWatch m_elapsed; CStopWatch m_elapsed;
unsigned int m_frames; unsigned int m_rfFrames;
unsigned int m_lost; unsigned int m_netFrames;
unsigned int m_netLost;
CAMBEFEC m_fec; CAMBEFEC m_fec;
unsigned int m_bits; unsigned int m_rfBits;
unsigned int m_errs; unsigned int m_netBits;
unsigned int m_rfErrs;
unsigned int m_netErrs;
unsigned char* m_lastFrame; unsigned char* m_lastFrame;
FILE* m_fp; FILE* m_fp;
void writeNetwork(); void writeNetwork();
void writeQueueHeader(const unsigned char* data); void writeQueueHeaderRF(const unsigned char* data);
void writeQueueData(const unsigned char* data); void writeQueueDataRF(const unsigned char* data);
void writeQueueEOT(); void writeQueueEOTRF();
void writeNetworkHeader(const unsigned char* data, bool busy); void writeQueueHeaderNet(const unsigned char* data);
void writeNetworkData(const unsigned char* data, unsigned int errors, bool end, bool busy); 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 openFile();
bool writeFile(const unsigned char* data, unsigned int length); bool writeFile(const unsigned char* data, unsigned int length);

View File

@@ -29,13 +29,18 @@ const unsigned char TAG_DATA = 0x01U;
const unsigned char TAG_LOST = 0x02U; const unsigned char TAG_LOST = 0x02U;
const unsigned char TAG_EOT = 0x03U; const unsigned char TAG_EOT = 0x03U;
enum RPT_STATE { enum RPT_RF_STATE {
RS_LISTENING, RS_RF_LISTENING,
RS_LATE_ENTRY, RS_RF_LATE_ENTRY,
RS_RELAYING_RF_AUDIO, RS_RF_AUDIO,
RS_RELAYING_NETWORK_AUDIO, RS_RF_DATA,
RS_RELAYING_RF_DATA, };
RS_RELAYING_NETWORK_DATA
enum RPT_NET_STATE {
RS_NET_IDLE,
RS_NET_LATE_ENTRY,
RS_NET_AUDIO,
RS_NET_DATA
}; };
#endif #endif

View File

@@ -33,7 +33,7 @@ CYSFControl::CYSFControl(const std::string& callsign, IDisplay* display, unsigne
m_display(display), m_display(display),
m_duplex(duplex), m_duplex(duplex),
m_queue(1000U, "YSF Control"), m_queue(1000U, "YSF Control"),
m_state(RS_LISTENING), m_state(RS_RF_LISTENING),
m_timeoutTimer(1000U, timeout), m_timeoutTimer(1000U, timeout),
m_frames(0U), m_frames(0U),
m_parrot(NULL), m_parrot(NULL),
@@ -54,7 +54,7 @@ bool CYSFControl::writeModem(unsigned char *data)
{ {
unsigned char type = data[0U]; 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); LogMessage("YSF, transmission lost, %.1f seconds", float(m_frames) / 10.0F);
if (m_parrot != NULL) if (m_parrot != NULL)
@@ -71,18 +71,18 @@ bool CYSFControl::writeModem(unsigned char *data)
unsigned char fi = data[1U] & YSF_FI_MASK; unsigned char fi = data[1U] & YSF_FI_MASK;
unsigned char dt = data[1U] & YSF_DT_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_frames = 0U;
m_timeoutTimer.start(); m_timeoutTimer.start();
m_display->writeFusion("XXXXXX"); m_display->writeFusion("XXXXXX");
m_state = RS_RELAYING_RF_AUDIO; m_state = RS_RF_AUDIO;
LogMessage("YSF, received RF header"); LogMessage("YSF, received RF header");
#if defined(DUMP_YSF) #if defined(DUMP_YSF)
openFile(); openFile();
#endif #endif
} }
if (m_state != RS_RELAYING_RF_AUDIO) if (m_state != RS_RF_AUDIO)
return false; return false;
if (type == TAG_EOT) { if (type == TAG_EOT) {
@@ -168,7 +168,7 @@ unsigned int CYSFControl::readModem(unsigned char* data)
void CYSFControl::writeEndOfTransmission() void CYSFControl::writeEndOfTransmission()
{ {
m_state = RS_LISTENING; m_state = RS_RF_LISTENING;
m_timeoutTimer.stop(); m_timeoutTimer.stop();

View File

@@ -44,7 +44,7 @@ private:
IDisplay* m_display; IDisplay* m_display;
bool m_duplex; bool m_duplex;
CRingBuffer<unsigned char> m_queue; CRingBuffer<unsigned char> m_queue;
RPT_STATE m_state; RPT_RF_STATE m_state;
CTimer m_timeoutTimer; CTimer m_timeoutTimer;
unsigned int m_frames; unsigned int m_frames;
CYSFParrot* m_parrot; CYSFParrot* m_parrot;