MMDVMHost-Private/DStarControl.cpp

1315 lines
35 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2015-2019 Jonathan Naylor, G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "DStarControl.h"
#include "Utils.h"
2016-02-15 21:46:57 +00:00
#include "Sync.h"
#include "Log.h"
2021-05-15 04:51:12 +00:00
#include "SMeter.h"
2016-03-07 20:21:55 +00:00
#include <cstdio>
#include <cassert>
#include <ctime>
#include <algorithm>
#include <functional>
const unsigned int MAX_SYNC_BIT_ERRORS = 2U;
const unsigned int FAST_DATA_BEEP_GRACE_FRAMES = 6U;
bool CallsignCompare(const std::string& arg, const unsigned char* my)
{
for (unsigned int i = 0U; i < (DSTAR_LONG_CALLSIGN_LENGTH - 1U); i++) {
if (arg.at(i) != my[i])
return false;
}
return true;
}
// #define DUMP_DSTAR
2021-05-15 04:51:12 +00:00
CDStarControl::CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, bool ackReply, unsigned int ackTime, DSTAR_ACK_MESSAGE ackMessage, bool errorReply, const std::vector<std::string>& blackList, const std::vector<std::string>& whiteList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper) :
m_callsign(NULL),
m_gateway(NULL),
m_selfOnly(selfOnly),
2017-06-10 12:18:18 +00:00
m_ackReply(ackReply),
m_ackMessage(ackMessage),
m_errorReply(errorReply),
m_remoteGateway(remoteGateway),
m_blackList(blackList),
2019-10-06 14:15:25 +00:00
m_whiteList(whiteList),
m_network(network),
m_display(display),
m_duplex(duplex),
2016-05-10 17:54:35 +00:00
m_queue(5000U, "D-Star Control"),
m_rfHeader(),
m_netHeader(),
m_rfState(RS_RF_LISTENING),
m_netState(RS_NET_IDLE),
m_net(false),
m_slowData(),
m_rfN(0U),
m_netN(0U),
m_networkWatchdog(1000U, 0U, 1500U),
m_rfTimeoutTimer(1000U, timeout),
m_netTimeoutTimer(1000U, timeout),
2016-09-27 05:45:42 +00:00
m_packetTimer(1000U, 0U, 300U),
2017-06-16 06:58:30 +00:00
m_ackTimer(1000U, 0U, ackTime),
m_errTimer(1000U, 0U, ackTime),
m_interval(),
m_elapsed(),
m_rfFrames(0U),
m_netFrames(0U),
m_netLost(0U),
m_fec(),
2016-07-21 16:50:13 +00:00
m_rfBits(1U),
m_netBits(1U),
m_rfErrs(0U),
m_netErrs(0U),
m_lastFrame(NULL),
2016-07-21 17:09:29 +00:00
m_lastFrameValid(false),
2017-01-05 19:15:10 +00:00
m_rssiMapper(rssiMapper),
m_rssi(0U),
m_maxRSSI(0U),
m_minRSSI(0U),
m_aveRSSI(0U),
m_rssiCount(0U),
m_enabled(true),
m_fp(NULL),
m_rfVoiceSyncData(NULL),
m_rfVoiceSyncDataLen(0U),
m_netVoiceSyncData(NULL),
m_netVoiceSyncDataLen(0U),
m_rfNextFrameIsFastData(false),
m_netNextFrameIsFastData(false),
m_rfSkipDTMFBlankingFrames(0U),
m_netSkipDTMFBlankingFrames(0U)
{
assert(display != NULL);
2017-01-05 19:15:10 +00:00
assert(rssiMapper != NULL);
m_callsign = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH];
m_gateway = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH];
m_lastFrame = new unsigned char[DSTAR_FRAME_LENGTH_BYTES + 1U];
m_rfVoiceSyncData = new unsigned char[MODEM_DATA_LEN];
m_netVoiceSyncData = new unsigned char[MODEM_DATA_LEN];
std::string call = callsign;
call.resize(DSTAR_LONG_CALLSIGN_LENGTH - 1U, ' ');
std::string mod = module;
mod.resize(1U, ' ');
call.append(mod);
std::string gate = callsign;
gate.resize(DSTAR_LONG_CALLSIGN_LENGTH - 1U, ' ');
gate.append("G");
for (unsigned int i = 0U; i < DSTAR_LONG_CALLSIGN_LENGTH; i++) {
m_callsign[i] = call.at(i);
m_gateway[i] = gate.at(i);
}
m_interval.start();
}
CDStarControl::~CDStarControl()
{
delete[] m_callsign;
delete[] m_gateway;
delete[] m_lastFrame;
delete[] m_rfVoiceSyncData;
delete[] m_netVoiceSyncData;
}
unsigned int CDStarControl::maybeFixupVoiceFrame(
unsigned char* data,
unsigned int len,
unsigned int offset,
const char* log_prefix,
unsigned char n,
bool blank_dtmf,
unsigned char* voice_sync_data,
unsigned int* voice_sync_data_len,
bool* next_frame_is_fast_data,
unsigned int* skip_dtmf_blanking_frames
)
{
unsigned int errors = 0U;
Add frame content details to D-Star debug logging Commit bf5651b deleted all log entries related to D-Star frame contents. This change adds some detail to the existing D-Star frame debugging log entries. Rather than always printing "audio", frames may be logged as one of "audio", "nullaudio", or "fastdata". A minimum width has been set for some fields so that the log messages form columns while watching a data stream. By virtue of centralizing the frame log messages, this commit also adds debugging entries for frames originating from the network. Example log entries that contain all three types as generated by a Kenwood TH-D74 using fast data: M: 2021-01-01 19:52:44.255 D-Star, received RF header from KG4BXH /D74 to CQCQCQ D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 0 D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 1 D: 2021-01-01 19:52:44.309 D-Star, RF nullaudio sequence no. 2 D: 2021-01-01 19:52:44.332 D-Star, RF nullaudio sequence no. 3 D: 2021-01-01 19:52:44.354 D-Star, RF nullaudio sequence no. 4 D: 2021-01-01 19:52:44.365 D-Star, RF nullaudio sequence no. 5 D: 2021-01-01 19:52:44.388 D-Star, RF nullaudio sequence no. 6 D: 2021-01-01 19:52:44.404 D-Star, RF nullaudio sequence no. 7 D: 2021-01-01 19:52:44.426 D-Star, RF nullaudio sequence no. 8 D: 2021-01-01 19:52:44.443 D-Star, RF nullaudio sequence no. 9 D: 2021-01-01 19:52:44.465 D-Star, RF nullaudio sequence no. 10 D: 2021-01-01 19:52:44.488 D-Star, RF nullaudio sequence no. 11 D: 2021-01-01 19:52:44.510 D-Star, RF nullaudio sequence no. 12 D: 2021-01-01 19:52:44.526 D-Star, RF nullaudio sequence no. 13 D: 2021-01-01 19:52:44.543 D-Star, RF nullaudio sequence no. 14 D: 2021-01-01 19:52:44.565 D-Star, RF nullaudio sequence no. 15 D: 2021-01-01 19:52:44.588 D-Star, RF nullaudio sequence no. 16 D: 2021-01-01 19:52:44.604 D-Star, RF nullaudio sequence no. 17 D: 2021-01-01 19:52:44.627 D-Star, RF nullaudio sequence no. 18 D: 2021-01-01 19:52:44.649 D-Star, RF nullaudio sequence no. 19 D: 2021-01-01 19:52:44.665 D-Star, RF nullaudio sequence no. 20 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:44.726 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:44.748 D-Star, RF fastdata sequence no. 3 D: 2021-01-01 19:52:44.765 D-Star, RF fastdata sequence no. 4 ... many fastdata frames elided ... D: 2021-01-01 19:52:45.486 D-Star, RF fastdata sequence no. 19 D: 2021-01-01 19:52:45.508 D-Star, RF fastdata sequence no. 20 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:45.565 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:45.587 D-Star, RF audio sequence no. 3, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.609 D-Star, RF audio sequence no. 4, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.631 D-Star, RF audio sequence no. 5, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.648 D-Star, RF audio sequence no. 6, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.670 D-Star, RF audio sequence no. 7, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.687 D-Star, RF audio sequence no. 8, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.709 D-Star, RF fastdata sequence no. 9 D: 2021-01-01 19:52:45.731 D-Star, RF fastdata sequence no. 10 D: 2021-01-01 19:52:45.753 D-Star, RF fastdata sequence no. 11 D: 2021-01-01 19:52:45.775 D-Star, RF fastdata sequence no. 12 D: 2021-01-01 19:52:45.786 D-Star, RF fastdata sequence no. 13 ... many more fastdata frames with periodic audio as above ...
2021-01-01 20:46:05 +00:00
unsigned int voice_sync_errors = 0U;
unsigned char mini_header = data[offset + 9U] ^ DSTAR_SCRAMBLER_BYTES[0U];
unsigned char mini_header_type = mini_header & DSTAR_SLOW_DATA_TYPE_MASK;
if (n == 0U) {
::memcpy(voice_sync_data, data, MODEM_DATA_LEN);
*voice_sync_data_len = len;
} else if ((n % 2U != 0U) &&
((mini_header_type == DSTAR_SLOW_DATA_TYPE_FASTDATA01) ||
(mini_header_type == DSTAR_SLOW_DATA_TYPE_FASTDATA16))) {
*next_frame_is_fast_data = true;
if (blank_dtmf)
*skip_dtmf_blanking_frames = FAST_DATA_BEEP_GRACE_FRAMES;
Add frame content details to D-Star debug logging Commit bf5651b deleted all log entries related to D-Star frame contents. This change adds some detail to the existing D-Star frame debugging log entries. Rather than always printing "audio", frames may be logged as one of "audio", "nullaudio", or "fastdata". A minimum width has been set for some fields so that the log messages form columns while watching a data stream. By virtue of centralizing the frame log messages, this commit also adds debugging entries for frames originating from the network. Example log entries that contain all three types as generated by a Kenwood TH-D74 using fast data: M: 2021-01-01 19:52:44.255 D-Star, received RF header from KG4BXH /D74 to CQCQCQ D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 0 D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 1 D: 2021-01-01 19:52:44.309 D-Star, RF nullaudio sequence no. 2 D: 2021-01-01 19:52:44.332 D-Star, RF nullaudio sequence no. 3 D: 2021-01-01 19:52:44.354 D-Star, RF nullaudio sequence no. 4 D: 2021-01-01 19:52:44.365 D-Star, RF nullaudio sequence no. 5 D: 2021-01-01 19:52:44.388 D-Star, RF nullaudio sequence no. 6 D: 2021-01-01 19:52:44.404 D-Star, RF nullaudio sequence no. 7 D: 2021-01-01 19:52:44.426 D-Star, RF nullaudio sequence no. 8 D: 2021-01-01 19:52:44.443 D-Star, RF nullaudio sequence no. 9 D: 2021-01-01 19:52:44.465 D-Star, RF nullaudio sequence no. 10 D: 2021-01-01 19:52:44.488 D-Star, RF nullaudio sequence no. 11 D: 2021-01-01 19:52:44.510 D-Star, RF nullaudio sequence no. 12 D: 2021-01-01 19:52:44.526 D-Star, RF nullaudio sequence no. 13 D: 2021-01-01 19:52:44.543 D-Star, RF nullaudio sequence no. 14 D: 2021-01-01 19:52:44.565 D-Star, RF nullaudio sequence no. 15 D: 2021-01-01 19:52:44.588 D-Star, RF nullaudio sequence no. 16 D: 2021-01-01 19:52:44.604 D-Star, RF nullaudio sequence no. 17 D: 2021-01-01 19:52:44.627 D-Star, RF nullaudio sequence no. 18 D: 2021-01-01 19:52:44.649 D-Star, RF nullaudio sequence no. 19 D: 2021-01-01 19:52:44.665 D-Star, RF nullaudio sequence no. 20 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:44.726 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:44.748 D-Star, RF fastdata sequence no. 3 D: 2021-01-01 19:52:44.765 D-Star, RF fastdata sequence no. 4 ... many fastdata frames elided ... D: 2021-01-01 19:52:45.486 D-Star, RF fastdata sequence no. 19 D: 2021-01-01 19:52:45.508 D-Star, RF fastdata sequence no. 20 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:45.565 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:45.587 D-Star, RF audio sequence no. 3, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.609 D-Star, RF audio sequence no. 4, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.631 D-Star, RF audio sequence no. 5, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.648 D-Star, RF audio sequence no. 6, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.670 D-Star, RF audio sequence no. 7, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.687 D-Star, RF audio sequence no. 8, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.709 D-Star, RF fastdata sequence no. 9 D: 2021-01-01 19:52:45.731 D-Star, RF fastdata sequence no. 10 D: 2021-01-01 19:52:45.753 D-Star, RF fastdata sequence no. 11 D: 2021-01-01 19:52:45.775 D-Star, RF fastdata sequence no. 12 D: 2021-01-01 19:52:45.786 D-Star, RF fastdata sequence no. 13 ... many more fastdata frames with periodic audio as above ...
2021-01-01 20:46:05 +00:00
if (n == 1U)
LogDebug("D-Star, %s fastdata sequence no. 0", log_prefix);
LogDebug("D-Star, %s fastdata sequence no. %2u", log_prefix, n);
} else if (*next_frame_is_fast_data == true) {
*next_frame_is_fast_data = false;
if (blank_dtmf)
*skip_dtmf_blanking_frames = FAST_DATA_BEEP_GRACE_FRAMES;
Add frame content details to D-Star debug logging Commit bf5651b deleted all log entries related to D-Star frame contents. This change adds some detail to the existing D-Star frame debugging log entries. Rather than always printing "audio", frames may be logged as one of "audio", "nullaudio", or "fastdata". A minimum width has been set for some fields so that the log messages form columns while watching a data stream. By virtue of centralizing the frame log messages, this commit also adds debugging entries for frames originating from the network. Example log entries that contain all three types as generated by a Kenwood TH-D74 using fast data: M: 2021-01-01 19:52:44.255 D-Star, received RF header from KG4BXH /D74 to CQCQCQ D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 0 D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 1 D: 2021-01-01 19:52:44.309 D-Star, RF nullaudio sequence no. 2 D: 2021-01-01 19:52:44.332 D-Star, RF nullaudio sequence no. 3 D: 2021-01-01 19:52:44.354 D-Star, RF nullaudio sequence no. 4 D: 2021-01-01 19:52:44.365 D-Star, RF nullaudio sequence no. 5 D: 2021-01-01 19:52:44.388 D-Star, RF nullaudio sequence no. 6 D: 2021-01-01 19:52:44.404 D-Star, RF nullaudio sequence no. 7 D: 2021-01-01 19:52:44.426 D-Star, RF nullaudio sequence no. 8 D: 2021-01-01 19:52:44.443 D-Star, RF nullaudio sequence no. 9 D: 2021-01-01 19:52:44.465 D-Star, RF nullaudio sequence no. 10 D: 2021-01-01 19:52:44.488 D-Star, RF nullaudio sequence no. 11 D: 2021-01-01 19:52:44.510 D-Star, RF nullaudio sequence no. 12 D: 2021-01-01 19:52:44.526 D-Star, RF nullaudio sequence no. 13 D: 2021-01-01 19:52:44.543 D-Star, RF nullaudio sequence no. 14 D: 2021-01-01 19:52:44.565 D-Star, RF nullaudio sequence no. 15 D: 2021-01-01 19:52:44.588 D-Star, RF nullaudio sequence no. 16 D: 2021-01-01 19:52:44.604 D-Star, RF nullaudio sequence no. 17 D: 2021-01-01 19:52:44.627 D-Star, RF nullaudio sequence no. 18 D: 2021-01-01 19:52:44.649 D-Star, RF nullaudio sequence no. 19 D: 2021-01-01 19:52:44.665 D-Star, RF nullaudio sequence no. 20 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:44.726 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:44.748 D-Star, RF fastdata sequence no. 3 D: 2021-01-01 19:52:44.765 D-Star, RF fastdata sequence no. 4 ... many fastdata frames elided ... D: 2021-01-01 19:52:45.486 D-Star, RF fastdata sequence no. 19 D: 2021-01-01 19:52:45.508 D-Star, RF fastdata sequence no. 20 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:45.565 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:45.587 D-Star, RF audio sequence no. 3, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.609 D-Star, RF audio sequence no. 4, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.631 D-Star, RF audio sequence no. 5, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.648 D-Star, RF audio sequence no. 6, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.670 D-Star, RF audio sequence no. 7, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.687 D-Star, RF audio sequence no. 8, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.709 D-Star, RF fastdata sequence no. 9 D: 2021-01-01 19:52:45.731 D-Star, RF fastdata sequence no. 10 D: 2021-01-01 19:52:45.753 D-Star, RF fastdata sequence no. 11 D: 2021-01-01 19:52:45.775 D-Star, RF fastdata sequence no. 12 D: 2021-01-01 19:52:45.786 D-Star, RF fastdata sequence no. 13 ... many more fastdata frames with periodic audio as above ...
2021-01-01 20:46:05 +00:00
LogDebug("D-Star, %s fastdata sequence no. %2u", log_prefix, n);
} else {
bool voice_sync_data_is_null_ambe_data = false;
bool data_is_null_ambe_data = false;
if ((n == 1U) && (::memcmp(voice_sync_data + offset, DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED, DSTAR_VOICE_FRAME_LENGTH_BYTES) == 0))
voice_sync_data_is_null_ambe_data = true;
if (::memcmp(data + offset, DSTAR_NULL_AMBE_DATA_BYTES_SCRAMBLED, DSTAR_VOICE_FRAME_LENGTH_BYTES) == 0)
data_is_null_ambe_data = true;
if ((n == 1U) && !voice_sync_data_is_null_ambe_data)
Add frame content details to D-Star debug logging Commit bf5651b deleted all log entries related to D-Star frame contents. This change adds some detail to the existing D-Star frame debugging log entries. Rather than always printing "audio", frames may be logged as one of "audio", "nullaudio", or "fastdata". A minimum width has been set for some fields so that the log messages form columns while watching a data stream. By virtue of centralizing the frame log messages, this commit also adds debugging entries for frames originating from the network. Example log entries that contain all three types as generated by a Kenwood TH-D74 using fast data: M: 2021-01-01 19:52:44.255 D-Star, received RF header from KG4BXH /D74 to CQCQCQ D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 0 D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 1 D: 2021-01-01 19:52:44.309 D-Star, RF nullaudio sequence no. 2 D: 2021-01-01 19:52:44.332 D-Star, RF nullaudio sequence no. 3 D: 2021-01-01 19:52:44.354 D-Star, RF nullaudio sequence no. 4 D: 2021-01-01 19:52:44.365 D-Star, RF nullaudio sequence no. 5 D: 2021-01-01 19:52:44.388 D-Star, RF nullaudio sequence no. 6 D: 2021-01-01 19:52:44.404 D-Star, RF nullaudio sequence no. 7 D: 2021-01-01 19:52:44.426 D-Star, RF nullaudio sequence no. 8 D: 2021-01-01 19:52:44.443 D-Star, RF nullaudio sequence no. 9 D: 2021-01-01 19:52:44.465 D-Star, RF nullaudio sequence no. 10 D: 2021-01-01 19:52:44.488 D-Star, RF nullaudio sequence no. 11 D: 2021-01-01 19:52:44.510 D-Star, RF nullaudio sequence no. 12 D: 2021-01-01 19:52:44.526 D-Star, RF nullaudio sequence no. 13 D: 2021-01-01 19:52:44.543 D-Star, RF nullaudio sequence no. 14 D: 2021-01-01 19:52:44.565 D-Star, RF nullaudio sequence no. 15 D: 2021-01-01 19:52:44.588 D-Star, RF nullaudio sequence no. 16 D: 2021-01-01 19:52:44.604 D-Star, RF nullaudio sequence no. 17 D: 2021-01-01 19:52:44.627 D-Star, RF nullaudio sequence no. 18 D: 2021-01-01 19:52:44.649 D-Star, RF nullaudio sequence no. 19 D: 2021-01-01 19:52:44.665 D-Star, RF nullaudio sequence no. 20 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:44.726 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:44.748 D-Star, RF fastdata sequence no. 3 D: 2021-01-01 19:52:44.765 D-Star, RF fastdata sequence no. 4 ... many fastdata frames elided ... D: 2021-01-01 19:52:45.486 D-Star, RF fastdata sequence no. 19 D: 2021-01-01 19:52:45.508 D-Star, RF fastdata sequence no. 20 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:45.565 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:45.587 D-Star, RF audio sequence no. 3, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.609 D-Star, RF audio sequence no. 4, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.631 D-Star, RF audio sequence no. 5, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.648 D-Star, RF audio sequence no. 6, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.670 D-Star, RF audio sequence no. 7, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.687 D-Star, RF audio sequence no. 8, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.709 D-Star, RF fastdata sequence no. 9 D: 2021-01-01 19:52:45.731 D-Star, RF fastdata sequence no. 10 D: 2021-01-01 19:52:45.753 D-Star, RF fastdata sequence no. 11 D: 2021-01-01 19:52:45.775 D-Star, RF fastdata sequence no. 12 D: 2021-01-01 19:52:45.786 D-Star, RF fastdata sequence no. 13 ... many more fastdata frames with periodic audio as above ...
2021-01-01 20:46:05 +00:00
voice_sync_errors += m_fec.regenerateDStar(voice_sync_data + offset);
if (!data_is_null_ambe_data)
errors += m_fec.regenerateDStar(data + offset);
if (blank_dtmf && (*skip_dtmf_blanking_frames > 0U)) {
(*skip_dtmf_blanking_frames)--;
} else if (blank_dtmf && (*skip_dtmf_blanking_frames == 0U)) {
if ((n == 1U) && !voice_sync_data_is_null_ambe_data)
blankDTMF(voice_sync_data + offset);
if (!data_is_null_ambe_data)
blankDTMF(data + offset);
}
Add frame content details to D-Star debug logging Commit bf5651b deleted all log entries related to D-Star frame contents. This change adds some detail to the existing D-Star frame debugging log entries. Rather than always printing "audio", frames may be logged as one of "audio", "nullaudio", or "fastdata". A minimum width has been set for some fields so that the log messages form columns while watching a data stream. By virtue of centralizing the frame log messages, this commit also adds debugging entries for frames originating from the network. Example log entries that contain all three types as generated by a Kenwood TH-D74 using fast data: M: 2021-01-01 19:52:44.255 D-Star, received RF header from KG4BXH /D74 to CQCQCQ D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 0 D: 2021-01-01 19:52:44.282 D-Star, RF nullaudio sequence no. 1 D: 2021-01-01 19:52:44.309 D-Star, RF nullaudio sequence no. 2 D: 2021-01-01 19:52:44.332 D-Star, RF nullaudio sequence no. 3 D: 2021-01-01 19:52:44.354 D-Star, RF nullaudio sequence no. 4 D: 2021-01-01 19:52:44.365 D-Star, RF nullaudio sequence no. 5 D: 2021-01-01 19:52:44.388 D-Star, RF nullaudio sequence no. 6 D: 2021-01-01 19:52:44.404 D-Star, RF nullaudio sequence no. 7 D: 2021-01-01 19:52:44.426 D-Star, RF nullaudio sequence no. 8 D: 2021-01-01 19:52:44.443 D-Star, RF nullaudio sequence no. 9 D: 2021-01-01 19:52:44.465 D-Star, RF nullaudio sequence no. 10 D: 2021-01-01 19:52:44.488 D-Star, RF nullaudio sequence no. 11 D: 2021-01-01 19:52:44.510 D-Star, RF nullaudio sequence no. 12 D: 2021-01-01 19:52:44.526 D-Star, RF nullaudio sequence no. 13 D: 2021-01-01 19:52:44.543 D-Star, RF nullaudio sequence no. 14 D: 2021-01-01 19:52:44.565 D-Star, RF nullaudio sequence no. 15 D: 2021-01-01 19:52:44.588 D-Star, RF nullaudio sequence no. 16 D: 2021-01-01 19:52:44.604 D-Star, RF nullaudio sequence no. 17 D: 2021-01-01 19:52:44.627 D-Star, RF nullaudio sequence no. 18 D: 2021-01-01 19:52:44.649 D-Star, RF nullaudio sequence no. 19 D: 2021-01-01 19:52:44.665 D-Star, RF nullaudio sequence no. 20 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:44.704 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:44.726 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:44.748 D-Star, RF fastdata sequence no. 3 D: 2021-01-01 19:52:44.765 D-Star, RF fastdata sequence no. 4 ... many fastdata frames elided ... D: 2021-01-01 19:52:45.486 D-Star, RF fastdata sequence no. 19 D: 2021-01-01 19:52:45.508 D-Star, RF fastdata sequence no. 20 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 0 D: 2021-01-01 19:52:45.548 D-Star, RF fastdata sequence no. 1 D: 2021-01-01 19:52:45.565 D-Star, RF fastdata sequence no. 2 D: 2021-01-01 19:52:45.587 D-Star, RF audio sequence no. 3, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.609 D-Star, RF audio sequence no. 4, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.631 D-Star, RF audio sequence no. 5, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.648 D-Star, RF audio sequence no. 6, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.670 D-Star, RF audio sequence no. 7, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.687 D-Star, RF audio sequence no. 8, errs: 0/48 ( 0.0%) D: 2021-01-01 19:52:45.709 D-Star, RF fastdata sequence no. 9 D: 2021-01-01 19:52:45.731 D-Star, RF fastdata sequence no. 10 D: 2021-01-01 19:52:45.753 D-Star, RF fastdata sequence no. 11 D: 2021-01-01 19:52:45.775 D-Star, RF fastdata sequence no. 12 D: 2021-01-01 19:52:45.786 D-Star, RF fastdata sequence no. 13 ... many more fastdata frames with periodic audio as above ...
2021-01-01 20:46:05 +00:00
if (n == 1U) {
if (voice_sync_data_is_null_ambe_data)
LogDebug("D-Star, %s nullaudio sequence no. 0", log_prefix);
else
LogDebug("D-Star, %s audio sequence no. 0, errs: %2u/48 (%5.1f%%)", log_prefix, voice_sync_errors,
float(voice_sync_errors) / 0.48F);
}
if (data_is_null_ambe_data)
LogDebug("D-Star, %s nullaudio sequence no. %2u", log_prefix, n);
else
LogDebug("D-Star, %s audio sequence no. %2u, errs: %2u/48 (%5.1f%%)", log_prefix, n, errors,
float(errors) / 0.48F);
}
return voice_sync_errors + errors;
}
2016-08-08 20:26:18 +00:00
bool CDStarControl::writeModem(unsigned char *data, unsigned int len)
{
2016-03-07 20:21:55 +00:00
assert(data != NULL);
if (!m_enabled)
return false;
unsigned char type = data[0U];
if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) {
unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH];
unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH];
unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
m_rfHeader.getMyCall1(my1);
m_rfHeader.getMyCall2(my2);
m_rfHeader.getYourCall(your);
if (m_rssi != 0U)
LogMessage("D-Star, transmission lost from %8.8s/%4.4s to %8.8s, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", my1, my2, your, float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
else
LogMessage("D-Star, transmission lost from %8.8s/%4.4s to %8.8s, %.1f seconds, BER: %.1f%%", my1, my2, your, float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits));
writeEndRF();
2016-02-02 18:17:36 +00:00
return false;
}
if (type == TAG_LOST && m_rfState == RS_RF_INVALID) {
m_rfState = RS_RF_LISTENING;
if (m_netState == RS_NET_IDLE) {
if (m_errorReply)
m_errTimer.start();
if (m_network != NULL)
m_network->reset();
}
return false;
}
2016-02-02 19:54:51 +00:00
if (type == TAG_LOST) {
m_rfState = RS_RF_LISTENING;
2016-02-02 18:17:36 +00:00
return false;
}
2017-01-05 19:15:10 +00:00
// Have we got RSSI bytes on the end of a D-Star header?
if (len == (DSTAR_HEADER_LENGTH_BYTES + 3U)) {
uint16_t raw = 0U;
raw |= (data[42U] << 8) & 0xFF00U;
raw |= (data[43U] << 0) & 0x00FFU;
// Convert the raw RSSI to dBm
int rssi = m_rssiMapper->interpolate(raw);
if (rssi != 0)
LogDebug("D-Star, raw RSSI: %u, reported RSSI: %d dBm", raw, rssi);
2017-01-05 19:15:10 +00:00
// RSSI is always reported as positive
m_rssi = (rssi >= 0) ? rssi : -rssi;
if (m_rssi > m_minRSSI)
m_minRSSI = m_rssi;
if (m_rssi < m_maxRSSI)
m_maxRSSI = m_rssi;
m_aveRSSI += m_rssi;
m_rssiCount++;
}
// Have we got RSSI bytes on the end of D-Star data?
if (len == (DSTAR_FRAME_LENGTH_BYTES + 3U)) {
uint16_t raw = 0U;
raw |= (data[13U] << 8) & 0xFF00U;
raw |= (data[14U] << 0) & 0x00FFU;
// Convert the raw RSSI to dBm
int rssi = m_rssiMapper->interpolate(raw);
if (rssi != 0)
LogDebug("D-Star, raw RSSI: %u, reported RSSI: %d dBm", raw, rssi);
2017-01-05 19:15:10 +00:00
// RSSI is always reported as positive
m_rssi = (rssi >= 0) ? rssi : -rssi;
if (m_rssi > m_minRSSI)
m_minRSSI = m_rssi;
if (m_rssi < m_maxRSSI)
m_maxRSSI = m_rssi;
m_aveRSSI += m_rssi;
m_rssiCount++;
}
if (type == TAG_HEADER) {
CDStarHeader header(data + 1U);
m_rfHeader = header;
2016-04-19 16:15:37 +00:00
unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH];
header.getMyCall1(my1);
// Is this a transmission destined for a repeater?
2016-04-19 16:15:37 +00:00
if (!header.isRepeater()) {
LogMessage("D-Star, non repeater RF header received from %8.8s", my1);
m_rfState = RS_RF_INVALID;
return false;
2016-04-19 16:15:37 +00:00
}
unsigned char callsign[DSTAR_LONG_CALLSIGN_LENGTH];
header.getRPTCall1(callsign);
// Is it for us?
2016-04-19 16:15:37 +00:00
if (::memcmp(callsign, m_callsign, DSTAR_LONG_CALLSIGN_LENGTH) != 0) {
LogMessage("D-Star, received RF header for wrong repeater (%8.8s) from %8.8s", callsign, my1);
m_rfState = RS_RF_INVALID;
2016-02-02 18:17:36 +00:00
return false;
2016-04-19 16:15:37 +00:00
}
2019-10-06 14:15:25 +00:00
if (m_selfOnly && ::memcmp(my1, m_callsign, DSTAR_LONG_CALLSIGN_LENGTH - 1U) != 0 && !(std::find_if(m_whiteList.begin(), m_whiteList.end(), std::bind(CallsignCompare, std::placeholders::_1, my1)) != m_whiteList.end())) {
LogMessage("D-Star, invalid access attempt from %8.8s", my1);
m_rfState = RS_RF_REJECTED;
return false;
}
if (!m_selfOnly && std::find_if(m_blackList.begin(), m_blackList.end(), std::bind(CallsignCompare, std::placeholders::_1, my1)) != m_blackList.end()) {
LogMessage("D-Star, invalid access attempt from %8.8s", my1);
m_rfState = RS_RF_REJECTED;
return false;
}
unsigned char gateway[DSTAR_LONG_CALLSIGN_LENGTH];
header.getRPTCall2(gateway);
unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH];
header.getMyCall2(my2);
unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
header.getYourCall(your);
m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0;
// Only start the timeout if not already running
if (!m_rfTimeoutTimer.isRunning())
m_rfTimeoutTimer.start();
2016-02-01 20:49:52 +00:00
m_ackTimer.stop();
m_errTimer.stop();
m_rfBits = 1U;
m_rfErrs = 0U;
m_rfFrames = 1U;
m_rfN = 0U;
2017-01-05 19:15:10 +00:00
m_minRSSI = m_rssi;
m_maxRSSI = m_rssi;
m_aveRSSI = m_rssi;
m_rssiCount = 1U;
if (m_duplex) {
// Modify the header
header.setRepeater(false);
header.setRPTCall1(m_callsign);
header.setRPTCall2(m_callsign);
header.get(data + 1U);
writeQueueHeaderRF(data);
}
if (m_net) {
// Modify the header
header.setRepeater(false);
header.setRPTCall1(m_callsign);
header.setRPTCall2(m_gateway);
header.get(data + 1U);
writeNetworkHeaderRF(data);
}
m_rfState = RS_RF_AUDIO;
if (m_netState == RS_NET_IDLE) {
m_display->writeDStar((char*)my1, (char*)my2, (char*)your, "R", " ");
m_display->writeDStarRSSI(m_rssi);
}
LogMessage("D-Star, received RF header from %8.8s/%4.4s to %8.8s", my1, my2, your);
} else if (type == TAG_EOT) {
if (m_rfState == RS_RF_REJECTED) {
m_rfState = RS_RF_LISTENING;
} else if (m_rfState == RS_RF_INVALID) {
m_rfState = RS_RF_LISTENING;
if (m_netState == RS_NET_IDLE) {
if (m_errorReply)
m_errTimer.start();
if (m_network != NULL)
m_network->reset();
}
return false;
} else if (m_rfState == RS_RF_AUDIO) {
2016-02-18 19:57:11 +00:00
if (m_net)
writeNetworkDataRF(DSTAR_END_PATTERN_BYTES, 0U, true);
if (m_duplex)
writeQueueEOTRF();
2016-02-01 20:49:52 +00:00
m_rfNextFrameIsFastData = false;
m_rfSkipDTMFBlankingFrames = 0U;
unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH];
unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH];
unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
m_rfHeader.getMyCall1(my1);
m_rfHeader.getMyCall2(my2);
m_rfHeader.getYourCall(your);
if (m_rssi != 0U)
LogMessage("D-Star, received RF end of transmission from %8.8s/%4.4s to %8.8s, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", my1, my2, your, float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
else
LogMessage("D-Star, received RF end of transmission from %8.8s/%4.4s to %8.8s, %.1f seconds, BER: %.1f%%", my1, my2, your, float(m_rfFrames) / 50.0F, float(m_rfErrs * 100U) / float(m_rfBits));
writeEndRF();
}
2016-02-02 18:17:36 +00:00
return false;
2016-02-03 07:20:48 +00:00
} else if (type == TAG_DATA) {
if (m_rfState == RS_RF_REJECTED) {
return false;
} else if (m_rfState == RS_RF_INVALID) {
return false;
} else if (m_rfState == RS_RF_LISTENING) {
2016-02-02 19:54:51 +00:00
// 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_rfState = RS_RF_LATE_ENTRY;
}
2016-02-02 18:17:36 +00:00
return false;
} else if (m_rfState == RS_RF_AUDIO) {
// 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_rfN = 0U;
// Regenerate the sync and send the RSSI data to the display
if (m_rfN == 0U) {
CSync::addDStarSync(data + 1U);
m_display->writeDStarRSSI(m_rssi);
}
unsigned int errors = 0U;
if (!m_rfHeader.isDataPacket()) {
errors = maybeFixupVoiceFrame(data, len, 1U, "RF", m_rfN, m_duplex, m_rfVoiceSyncData, &m_rfVoiceSyncDataLen,
&m_rfNextFrameIsFastData, &m_rfSkipDTMFBlankingFrames);
m_display->writeDStarBER(float(errors) / 0.48F);
m_rfErrs += errors;
}
2016-02-18 18:18:37 +00:00
m_rfBits += 48U;
m_rfFrames++;
2016-02-01 21:44:40 +00:00
if (m_net) {
if (m_rfN == 1U)
writeNetworkDataRF(m_rfVoiceSyncData, 0U, false);
if (m_rfN >= 1U)
writeNetworkDataRF(data, errors, false);
}
if (m_duplex) {
if (m_rfN == 1U)
writeQueueDataRF(m_rfVoiceSyncData);
if (m_rfN >= 1U)
writeQueueDataRF(data);
}
2016-03-21 18:13:21 +00:00
m_rfN = (m_rfN + 1U) % 21U;
} else if (m_rfState == RS_RF_LATE_ENTRY) {
2016-02-02 19:54:51 +00:00
// 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();
2016-02-02 18:17:36 +00:00
return false;
}
CDStarHeader* header = m_slowData.add(data + 1U);
if (header == NULL)
2016-02-02 18:17:36 +00:00
return false;
m_rfHeader = *header;
unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH];
header->getMyCall1(my1);
// Is this a transmission destined for a repeater?
2016-02-03 07:20:48 +00:00
if (!header->isRepeater()) {
LogMessage("D-Star, non repeater RF header received from %8.8s", my1);
m_rfState = RS_RF_INVALID;
delete header;
return false;
}
unsigned char callsign[DSTAR_LONG_CALLSIGN_LENGTH];
header->getRPTCall1(callsign);
// Is it for us?
if (::memcmp(callsign, m_callsign, DSTAR_LONG_CALLSIGN_LENGTH) != 0) {
LogMessage("D-Star, received RF header for wrong repeater (%8.8s) from %8.8s", callsign, my1);
m_rfState = RS_RF_INVALID;
delete header;
return false;
}
2019-10-06 14:15:25 +00:00
if (m_selfOnly && ::memcmp(my1, m_callsign, DSTAR_LONG_CALLSIGN_LENGTH - 1U) != 0 && !(std::find_if(m_whiteList.begin(), m_whiteList.end(), std::bind(CallsignCompare, std::placeholders::_1, my1)) != m_whiteList.end())) {
LogMessage("D-Star, invalid access attempt from %8.8s", my1);
m_rfState = RS_RF_REJECTED;
delete header;
return false;
}
if (!m_selfOnly && std::find_if(m_blackList.begin(), m_blackList.end(), std::bind(CallsignCompare, std::placeholders::_1, my1)) != m_blackList.end()) {
LogMessage("D-Star, invalid access attempt from %8.8s", my1);
m_rfState = RS_RF_REJECTED;
delete header;
2016-02-02 18:17:36 +00:00
return false;
2016-02-03 07:20:48 +00:00
}
unsigned char gateway[DSTAR_LONG_CALLSIGN_LENGTH];
header->getRPTCall2(gateway);
unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH];
header->getMyCall2(my2);
unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
header->getYourCall(your);
m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0;
2016-02-02 19:54:51 +00:00
// Only reset the timeout if the timeout is not running
if (!m_rfTimeoutTimer.isRunning())
m_rfTimeoutTimer.start();
2016-02-01 20:49:52 +00:00
// Create a dummy start frame to replace the received frame
2016-02-01 20:49:52 +00:00
m_ackTimer.stop();
m_errTimer.stop();
m_rfBits = 1U;
m_rfErrs = 0U;
m_rfN = 0U;
m_rfFrames = 1U;
2017-01-05 19:15:10 +00:00
m_minRSSI = m_rssi;
m_maxRSSI = m_rssi;
m_aveRSSI = m_rssi;
m_rssiCount = 1U;
if (m_duplex) {
unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U];
start[0U] = TAG_HEADER;
// Modify the header
header->setRepeater(false);
header->setRPTCall1(m_callsign);
header->setRPTCall2(m_callsign);
header->get(start + 1U);
writeQueueHeaderRF(start);
}
if (m_net) {
unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U];
start[0U] = TAG_HEADER;
// Modify the header
header->setRepeater(false);
header->setRPTCall1(m_callsign);
header->setRPTCall2(m_gateway);
header->get(start + 1U);
writeNetworkHeaderRF(start);
}
delete header;
unsigned int errors = 0U;
if (!m_rfHeader.isDataPacket()) {
errors = maybeFixupVoiceFrame(data, len, 1U, "RF", m_rfN, m_duplex, m_rfVoiceSyncData, &m_rfVoiceSyncDataLen,
&m_rfNextFrameIsFastData, &m_rfSkipDTMFBlankingFrames);
m_rfErrs += errors;
}
2016-02-18 18:18:37 +00:00
m_rfBits += 48U;
if (m_net)
writeNetworkDataRF(data, errors, false);
if (m_duplex)
writeQueueDataRF(data);
m_rfState = RS_RF_AUDIO;
2016-03-21 18:13:21 +00:00
m_rfN = (m_rfN + 1U) % 21U;
if (m_netState == RS_NET_IDLE) {
m_display->writeDStar((char*)my1, (char*)my2, (char*)your, "R", " ");
m_display->writeDStarRSSI(m_rssi);
m_display->writeDStarBER(float(errors) / 0.48F);
}
2016-02-01 22:33:09 +00:00
LogMessage("D-Star, received RF late entry from %8.8s/%4.4s to %8.8s", my1, my2, your);
}
2016-02-03 07:20:48 +00:00
} else {
CUtils::dump("D-Star, unknown data from modem", data, DSTAR_FRAME_LENGTH_BYTES + 1U);
}
2016-02-02 18:17:36 +00:00
return true;
}
unsigned int CDStarControl::readModem(unsigned char* data)
{
2016-03-07 20:21:55 +00:00
assert(data != NULL);
if (m_queue.isEmpty())
return 0U;
unsigned char len = 0U;
m_queue.getData(&len, 1U);
m_queue.getData(data, len);
return len;
}
void CDStarControl::writeEndRF()
{
m_rfState = RS_RF_LISTENING;
if (m_netState == RS_NET_IDLE) {
m_display->clearDStar();
2017-06-10 12:18:18 +00:00
m_ackTimer.start();
if (m_network != NULL)
m_network->reset();
} else {
m_rfTimeoutTimer.stop();
}
}
void CDStarControl::writeEndNet()
{
m_netState = RS_NET_IDLE;
2016-07-21 17:09:29 +00:00
m_lastFrameValid = false;
m_display->clearDStar();
m_netTimeoutTimer.stop();
m_networkWatchdog.stop();
2016-07-15 05:32:56 +00:00
m_packetTimer.stop();
if (m_network != NULL)
m_network->reset();
#if defined(DUMP_DSTAR)
closeFile();
#endif
}
void CDStarControl::writeNetwork()
{
assert(m_network != NULL);
unsigned char data[DSTAR_HEADER_LENGTH_BYTES + 2U];
unsigned int length = m_network->read(data, DSTAR_HEADER_LENGTH_BYTES + 2U);
if (length == 0U)
return;
if (!m_enabled)
return;
if (m_rfState == RS_RF_AUDIO && m_netState == RS_NET_IDLE)
return;
m_networkWatchdog.start();
unsigned char type = data[0U];
if (type == TAG_HEADER) {
if (m_netState != RS_NET_IDLE)
return;
2016-01-31 18:11:12 +00:00
CDStarHeader header(data + 1U);
unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH];
header.getMyCall1(my1);
unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH];
header.getMyCall2(my2);
unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
header.getYourCall(your);
m_netHeader = header;
2016-02-01 20:49:52 +00:00
m_netTimeoutTimer.start();
2016-07-15 05:32:56 +00:00
m_packetTimer.start();
2016-02-01 20:49:52 +00:00
m_ackTimer.stop();
m_errTimer.stop();
2016-07-21 17:09:29 +00:00
m_lastFrameValid = false;
m_netFrames = 0U;
m_netLost = 0U;
m_netN = 20U;
m_netBits = 1U;
m_netErrs = 0U;
if (m_remoteGateway) {
header.setRepeater(true);
header.setRPTCall1(m_callsign);
header.setRPTCall2(m_callsign);
header.get(data + 1U);
}
writeQueueHeaderNet(data);
#if defined(DUMP_DSTAR)
openFile();
writeFile(data + 1U, length - 1U);
#endif
m_netState = RS_NET_AUDIO;
LINK_STATUS status = LS_NONE;
unsigned char reflector[DSTAR_LONG_CALLSIGN_LENGTH];
m_network->getStatus(status, reflector);
if (status == LS_LINKED_DEXTRA || status == LS_LINKED_DPLUS || status == LS_LINKED_DCS || status == LS_LINKED_CCS || status == LS_LINKED_LOOPBACK) {
m_display->writeDStar((char*)my1, (char*)my2, (char*)your, "N", (char*) reflector);
LogMessage("D-Star, received network header from %8.8s/%4.4s to %8.8s via %8.8s", my1, my2, your, reflector);
} 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);
}
// Something just above here introduces a large delay forcing erroneous(?) insertion of silence packets.
// Starting the elapsed timer here instead of the commented out position above solves that.
m_elapsed.start();
} else if (type == TAG_EOT) {
if (m_netState != RS_NET_AUDIO)
return;
writeQueueEOTNet();
data[1U] = TAG_EOT;
#if defined(DUMP_DSTAR)
writeFile(data + 1U, length - 1U);
closeFile();
#endif
m_netNextFrameIsFastData = false;
m_netSkipDTMFBlankingFrames = 0U;
2016-02-18 18:18:37 +00:00
unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH];
unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH];
unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
m_netHeader.getMyCall1(my1);
m_netHeader.getMyCall2(my2);
m_netHeader.getYourCall(your);
2016-07-12 06:05:48 +00:00
// We've received the header and EOT haven't we?
m_netFrames += 2U;
LogMessage("D-Star, received network end of transmission from %8.8s/%4.4s to %8.8s, %.1f seconds, %u%% packet loss, BER: %.1f%%", my1, my2, your, float(m_netFrames) / 50.0F, (m_netLost * 100U) / m_netFrames, float(m_netErrs * 100U) / float(m_netBits));
writeEndNet();
2016-02-03 07:20:48 +00:00
} else if (type == TAG_DATA) {
if (m_netState != RS_NET_AUDIO)
return;
unsigned char n = data[1U];
data[1U] = TAG_DATA;
unsigned int errors = 0U;
if (!m_netHeader.isDataPacket())
errors = maybeFixupVoiceFrame(data, length, 2U, "Net", n, true, m_netVoiceSyncData, &m_netVoiceSyncDataLen,
&m_netNextFrameIsFastData, &m_netSkipDTMFBlankingFrames);
// 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;
2019-01-28 07:50:43 +00:00
// Regenerate the sync
if (n == 0U)
CSync::addDStarSync(data + 2U);
m_packetTimer.start();
m_netFrames++;
#if defined(DUMP_DSTAR)
if (n == 1U)
writeFile(m_netVoiceSyncData + 1U, m_netVoiceSyncDataLen - 1U);
if (n >= 1U)
writeFile(data + 1U, length - 1U);
#endif
if (n == 1U)
writeQueueDataNet(m_netVoiceSyncData + 1U);
if (n >= 1U)
writeQueueDataNet(data + 1U);
2016-02-03 07:20:48 +00:00
} else {
CUtils::dump("D-Star, unknown data from network", data, DSTAR_FRAME_LENGTH_BYTES + 1U);
}
}
void CDStarControl::clock()
{
unsigned int ms = m_interval.elapsed();
m_interval.start();
if (m_network != NULL)
writeNetwork();
2016-02-01 20:49:52 +00:00
m_ackTimer.clock(ms);
if (m_ackTimer.isRunning() && m_ackTimer.hasExpired()) {
sendAck();
m_ackTimer.stop();
}
m_errTimer.clock(ms);
if (m_errTimer.isRunning() && m_errTimer.hasExpired()) {
sendError();
m_errTimer.stop();
}
m_rfTimeoutTimer.clock(ms);
m_netTimeoutTimer.clock(ms);
if (m_netState == RS_NET_AUDIO) {
m_networkWatchdog.clock(ms);
if (m_networkWatchdog.hasExpired()) {
// We're received the header haven't we?
m_netFrames += 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));
writeEndNet();
#if defined(DUMP_DSTAR)
closeFile();
#endif
}
}
// Only insert silence on audio data
if (m_netState == RS_NET_AUDIO) {
2016-07-15 05:32:56 +00:00
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_netFrames) {
unsigned int count = frames - m_netFrames;
2016-09-26 17:10:51 +00:00
if (count > 15U) {
LogDebug("D-Star, lost audio for 300ms filling in, elapsed: %ums, expected: %u, received: %u", elapsed, frames, m_netFrames);
2016-07-15 05:32:56 +00:00
insertSilence(count - 2U);
}
}
2016-07-15 05:32:56 +00:00
m_packetTimer.start();
}
}
}
void CDStarControl::writeQueueHeaderRF(const unsigned char *data)
{
assert(data != NULL);
if (m_netState != RS_NET_IDLE)
return;
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
return;
unsigned char len = DSTAR_HEADER_LENGTH_BYTES + 1U;
unsigned int space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError("D-Star, overflow in the D-Star RF queue");
return;
}
m_queue.addData(&len, 1U);
m_queue.addData(data, len);
}
void CDStarControl::writeQueueDataRF(const unsigned char *data)
{
assert(data != NULL);
if (m_netState != RS_NET_IDLE)
return;
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
return;
unsigned char len = DSTAR_FRAME_LENGTH_BYTES + 1U;
unsigned int space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError("D-Star, overflow in the D-Star RF queue");
return;
}
m_queue.addData(&len, 1U);
m_queue.addData(data, len);
}
void CDStarControl::writeQueueEOTRF()
{
if (m_netState != RS_NET_IDLE)
return;
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
return;
unsigned char len = 1U;
unsigned int space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError("D-Star, overflow in the D-Star RF queue");
return;
}
m_queue.addData(&len, 1U);
unsigned char data = TAG_EOT;
m_queue.addData(&data, len);
}
void CDStarControl::writeQueueHeaderNet(const unsigned char *data)
{
assert(data != NULL);
if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired())
return;
unsigned char len = DSTAR_HEADER_LENGTH_BYTES + 1U;
unsigned int space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError("D-Star, overflow in the D-Star RF queue");
return;
}
m_queue.addData(&len, 1U);
m_queue.addData(data, len);
}
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;
unsigned int space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError("D-Star, overflow in the D-Star RF queue");
return;
}
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;
unsigned int space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError("D-Star, overflow in the D-Star RF queue");
return;
}
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);
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->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()
{
if (m_fp != NULL)
return true;
time_t t;
::time(&t);
struct tm* tm = ::localtime(&t);
char name[100U];
::sprintf(name, "DStar_%04d%02d%02d_%02d%02d%02d.ambe", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
m_fp = ::fopen(name, "wb");
if (m_fp == NULL)
return false;
::fwrite("DSTAR", 1U, 4U, m_fp);
return true;
}
bool CDStarControl::writeFile(const unsigned char* data, unsigned int length)
{
if (m_fp == NULL)
return false;
::fwrite(data, 1U, length, m_fp);
return true;
}
void CDStarControl::closeFile()
{
if (m_fp != NULL) {
::fclose(m_fp);
m_fp = NULL;
}
}
2016-07-12 06:05:48 +00:00
bool CDStarControl::insertSilence(const unsigned char* data, unsigned char seqNo)
{
assert(data != NULL);
// Check to see if we have any spaces to fill?
2016-07-11 19:08:14 +00:00
unsigned int oldSeqNo = (m_netN + 1U) % 21U;
if (oldSeqNo == seqNo) {
// Just copy the data, nothing else to do here
2016-07-12 06:24:07 +00:00
::memcpy(m_lastFrame, data, DSTAR_FRAME_LENGTH_BYTES + 1U);
2016-07-21 17:09:29 +00:00
m_lastFrameValid = true;
2016-07-12 06:05:48 +00:00
return true;
}
unsigned int count;
2016-07-11 19:08:14 +00:00
if (seqNo > oldSeqNo)
count = seqNo - oldSeqNo;
else
2016-07-11 19:08:14 +00:00
count = (21U + seqNo) - oldSeqNo;
2016-07-12 06:05:48 +00:00
if (count >= 10U)
return false;
insertSilence(count);
2016-07-12 06:24:07 +00:00
::memcpy(m_lastFrame, data, DSTAR_FRAME_LENGTH_BYTES + 1U);
2016-07-21 17:09:29 +00:00
m_lastFrameValid = true;
2016-07-12 06:05:48 +00:00
return true;
}
void CDStarControl::insertSilence(unsigned int count)
{
unsigned char n = (m_netN + 1U) % 21U;
for (unsigned int i = 0U; i < count; i++) {
2016-07-21 17:09:29 +00:00
if (i < 3U && m_lastFrameValid) {
2016-07-11 19:08:14 +00:00
if (n == 0U) {
::memcpy(m_lastFrame + DSTAR_VOICE_FRAME_LENGTH_BYTES + 1U, DSTAR_NULL_SLOW_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES);
writeQueueDataNet(m_lastFrame);
} else {
::memcpy(m_lastFrame + DSTAR_VOICE_FRAME_LENGTH_BYTES + 1U, DSTAR_NULL_SLOW_DATA_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES);
writeQueueDataNet(m_lastFrame);
}
} else {
2016-08-09 16:20:26 +00:00
m_lastFrameValid = false;
2016-02-01 20:49:52 +00:00
if (n == 0U)
writeQueueDataNet(DSTAR_NULL_FRAME_SYNC_BYTES);
2016-02-01 20:49:52 +00:00
else
writeQueueDataNet(DSTAR_NULL_FRAME_DATA_BYTES);
}
m_netN = n;
m_netFrames++;
m_netLost++;
n = (n + 1U) % 21U;
}
}
void CDStarControl::blankDTMF(unsigned char* data) const
{
assert(data != NULL);
// DTMF begins with these byte values
if ((data[0] & DSTAR_DTMF_MASK[0]) == DSTAR_DTMF_SIG[0] && (data[1] & DSTAR_DTMF_MASK[1]) == DSTAR_DTMF_SIG[1] &&
(data[2] & DSTAR_DTMF_MASK[2]) == DSTAR_DTMF_SIG[2] && (data[3] & DSTAR_DTMF_MASK[3]) == DSTAR_DTMF_SIG[3] &&
(data[4] & DSTAR_DTMF_MASK[4]) == DSTAR_DTMF_SIG[4] && (data[5] & DSTAR_DTMF_MASK[5]) == DSTAR_DTMF_SIG[5] &&
(data[6] & DSTAR_DTMF_MASK[6]) == DSTAR_DTMF_SIG[6] && (data[7] & DSTAR_DTMF_MASK[7]) == DSTAR_DTMF_SIG[7] &&
(data[8] & DSTAR_DTMF_MASK[8]) == DSTAR_DTMF_SIG[8])
::memcpy(data, DSTAR_NULL_AMBE_DATA_BYTES, DSTAR_VOICE_FRAME_LENGTH_BYTES);
}
2016-02-01 20:49:52 +00:00
void CDStarControl::sendAck()
{
m_rfTimeoutTimer.stop();
2016-02-02 19:54:51 +00:00
if (!m_ackReply)
return;
2016-02-01 20:49:52 +00:00
unsigned char user[DSTAR_LONG_CALLSIGN_LENGTH];
m_rfHeader.getMyCall1(user);
2016-02-01 20:49:52 +00:00
CDStarHeader header;
header.setUnavailable(true);
header.setMyCall1(m_callsign);
header.setYourCall(user);
header.setRPTCall1(m_gateway);
header.setRPTCall2(m_callsign);
unsigned char data[DSTAR_HEADER_LENGTH_BYTES + 1U];
header.get(data + 1U);
data[0U] = TAG_HEADER;
writeQueueHeaderRF(data);
2016-02-01 20:49:52 +00:00
writeQueueDataRF(DSTAR_NULL_FRAME_SYNC_BYTES);
2016-02-01 20:49:52 +00:00
LINK_STATUS status = LS_NONE;
unsigned char reflector[DSTAR_LONG_CALLSIGN_LENGTH];
if (m_network != NULL)
m_network->getStatus(status, reflector);
2016-02-01 21:44:40 +00:00
char text[40U];
2021-05-15 04:51:12 +00:00
if (m_ackMessage == DSTAR_ACK_RSSI && m_rssi != 0) {
if (status == LS_LINKED_DEXTRA || status == LS_LINKED_DPLUS || status == LS_LINKED_DCS || status == LS_LINKED_CCS || status == LS_LINKED_LOOPBACK)
2021-05-15 04:51:12 +00:00
::sprintf(text, "%-8.8s %.1f%% -%udBm ", reflector, float(m_rfErrs * 100U) / float(m_rfBits), m_aveRSSI / m_rssiCount);
else
::sprintf(text, "BER:%.1f%% -%udBm ", float(m_rfErrs * 100U) / float(m_rfBits), m_aveRSSI / m_rssiCount);
}
2021-05-15 04:51:12 +00:00
else if (m_ackMessage == DSTAR_ACK_SMETER && m_rssi != 0) {
unsigned int signal, plus;
char signalText[10U];
CSMeter::getSignal(m_aveRSSI / m_rssiCount, signal, plus);
if (plus != 0U)
::sprintf(signalText, "S%u+%u", signal, plus);
else
::sprintf(signalText, "S%u+", signal);
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 %.1f%% %s ", reflector, float(m_rfErrs * 100U) / float(m_rfBits), signalText);
else
::sprintf(text, "BER:%.1f%% -%s ", float(m_rfErrs * 100U) / float(m_rfBits), signalText);
}
else {
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_rfErrs * 100U) / float(m_rfBits));
else
::sprintf(text, "BER: %.1f%% ", float(m_rfErrs * 100U) / float(m_rfBits));
}
2016-02-01 20:49:52 +00:00
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);
writeQueueDataRF(data);
2016-02-01 20:49:52 +00:00
}
writeQueueEOTRF();
2016-02-01 20:49:52 +00:00
}
void CDStarControl::sendError()
{
unsigned char user[DSTAR_LONG_CALLSIGN_LENGTH];
m_rfHeader.getMyCall1(user);
CDStarHeader header;
header.setUnavailable(true);
header.setMyCall1(m_callsign);
header.setYourCall(user);
header.setRPTCall1(m_callsign);
header.setRPTCall2(m_callsign);
unsigned char data[DSTAR_HEADER_LENGTH_BYTES + 1U];
header.get(data + 1U);
data[0U] = TAG_HEADER;
writeQueueHeaderRF(data);
writeQueueDataRF(DSTAR_NULL_FRAME_SYNC_BYTES);
LINK_STATUS status = LS_NONE;
unsigned char reflector[DSTAR_LONG_CALLSIGN_LENGTH];
if (m_network != NULL)
m_network->getStatus(status, reflector);
char text[40U];
2021-05-15 04:51:12 +00:00
if (m_ackMessage == DSTAR_ACK_RSSI && m_rssi != 0) {
if (status == LS_LINKED_DEXTRA || status == LS_LINKED_DPLUS || status == LS_LINKED_DCS || status == LS_LINKED_CCS || status == LS_LINKED_LOOPBACK)
2021-05-15 04:51:12 +00:00
::sprintf(text, "%-8.8s %.1f%% -%udBm ", reflector, float(m_rfErrs * 100U) / float(m_rfBits), m_aveRSSI / m_rssiCount);
else
::sprintf(text, "BER:%.1f%% -%udBm ", float(m_rfErrs * 100U) / float(m_rfBits), m_aveRSSI / m_rssiCount);
}
2021-05-15 04:51:12 +00:00
else if (m_ackMessage == DSTAR_ACK_SMETER && m_rssi != 0) {
unsigned int signal, plus;
char signalText[10U];
CSMeter::getSignal(m_aveRSSI / m_rssiCount, signal, plus);
if (plus != 0U)
::sprintf(signalText, "S%u+%u", signal, plus);
else
::sprintf(signalText, "S%u+", signal);
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 %.1f%% %s ", reflector, float(m_rfErrs * 100U) / float(m_rfBits), signalText);
else
::sprintf(text, "BER:%.1f%% -%s ", float(m_rfErrs * 100U) / float(m_rfBits), signalText);
}
else {
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_rfErrs * 100U) / float(m_rfBits));
else
::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);
writeQueueDataRF(data);
}
writeQueueEOTRF();
}
bool CDStarControl::isBusy() const
{
return m_rfState != RS_RF_LISTENING || m_netState != RS_NET_IDLE;
}
void CDStarControl::enable(bool enabled)
{
if (!enabled && m_enabled) {
m_queue.clear();
// Reset the RF section
m_rfState = RS_RF_LISTENING;
m_rfTimeoutTimer.stop();
// Reset the networking section
m_netState = RS_NET_IDLE;
m_lastFrameValid = false;
m_netTimeoutTimer.stop();
m_networkWatchdog.stop();
m_packetTimer.stop();
}
m_enabled = enabled;
}