ensure the lookup table thread is named; don't display the not transmitting CC messages unless the test timer is not paused; add aggressive watchdog logging for when timers exceed 1s intervals; split adj. site and affiliation updating into a separate thread (huge adj. site updates could be the cause of main loop processing delays); ensure threads are properly shutdown; increase P25 adj site update timer from 30 seconds to 60 seconds (5 minutes of no updates will now FAIL an adj. site);

pull/55/head
Bryan Biedenkapp 2 years ago
parent 36099367c8
commit 9b828fe7a4

@ -91,6 +91,7 @@ namespace lookups
if (m_reloadTime > 0U) if (m_reloadTime > 0U)
run(); run();
setName("host:lookup-tbl");
return ret; return ret;
} }

@ -141,7 +141,7 @@ void Host::writeFramesDMR1(dmr::Control* control, std::function<void()>&& afterW
if (ret) { if (ret) {
uint32_t nextLen = control->peekFrameLength(1U); uint32_t nextLen = control->peekFrameLength(1U);
if (m_dmrCtrlChannel) { if (m_dmrCtrlChannel) {
if (m_dmrDedicatedTxTestTimer.hasExpired()) { if (m_dmrDedicatedTxTestTimer.hasExpired() && !m_dmrDedicatedTxTestTimer.isPaused()) {
m_dmrDedicatedTxTestTimer.pause(); m_dmrDedicatedTxTestTimer.pause();
if (!m_modem->hasTX() && m_modem->gotModemStatus() && m_state == STATE_DMR && (control->getTSCCSlotNo() == 1U) && control->getCCRunning()) { if (!m_modem->hasTX() && m_modem->gotModemStatus() && m_state == STATE_DMR && (control->getTSCCSlotNo() == 1U) && control->getCCRunning()) {
LogError(LOG_HOST, "DMR dedicated control not transmitting, running = %u, halted = %u, frameLength1 = %u", control->getCCRunning(), control->getCCHalted(), nextLen); LogError(LOG_HOST, "DMR dedicated control not transmitting, running = %u, halted = %u, frameLength1 = %u", control->getCCRunning(), control->getCCHalted(), nextLen);
@ -273,7 +273,7 @@ void Host::writeFramesDMR2(dmr::Control* control, std::function<void()>&& afterW
if (ret) { if (ret) {
uint32_t nextLen = control->peekFrameLength(1U); uint32_t nextLen = control->peekFrameLength(1U);
if (m_dmrCtrlChannel) { if (m_dmrCtrlChannel) {
if (m_dmrDedicatedTxTestTimer.hasExpired()) { if (m_dmrDedicatedTxTestTimer.hasExpired() && !m_dmrDedicatedTxTestTimer.isPaused()) {
m_dmrDedicatedTxTestTimer.pause(); m_dmrDedicatedTxTestTimer.pause();
if (!m_modem->hasTX() && m_modem->gotModemStatus() && m_state == STATE_DMR && (control->getTSCCSlotNo() == 2U) && control->getCCRunning()) { if (!m_modem->hasTX() && m_modem->gotModemStatus() && m_state == STATE_DMR && (control->getTSCCSlotNo() == 2U) && control->getCCRunning()) {
LogError(LOG_HOST, "DMR dedicated control not transmitting, running = %u, halted = %u, frameLength2 = %u", control->getCCRunning(), control->getCCHalted(), nextLen); LogError(LOG_HOST, "DMR dedicated control not transmitting, running = %u, halted = %u, frameLength2 = %u", control->getCCRunning(), control->getCCHalted(), nextLen);

@ -90,7 +90,7 @@ void Host::writeFramesNXDN(nxdn::Control* control, std::function<void()>&& after
if (ret) { if (ret) {
uint32_t nextLen = control->peekFrameLength(); uint32_t nextLen = control->peekFrameLength();
if (m_nxdnCtrlChannel) { if (m_nxdnCtrlChannel) {
if (m_nxdnDedicatedTxTestTimer.hasExpired()) { if (m_nxdnDedicatedTxTestTimer.hasExpired() && !m_nxdnDedicatedTxTestTimer.isPaused()) {
m_nxdnDedicatedTxTestTimer.pause(); m_nxdnDedicatedTxTestTimer.pause();
if (!m_modem->hasTX() && m_modem->gotModemStatus() && m_state == STATE_NXDN && control->getCCRunning()) { if (!m_modem->hasTX() && m_modem->gotModemStatus() && m_state == STATE_NXDN && control->getCCRunning()) {
LogError(LOG_HOST, "NXDN dedicated control stopped transmitting, running = %u, halted = %u, frameLength = %u", control->getCCRunning(), control->getCCHalted(), nextLen); LogError(LOG_HOST, "NXDN dedicated control stopped transmitting, running = %u, halted = %u, frameLength = %u", control->getCCRunning(), control->getCCHalted(), nextLen);

@ -132,7 +132,7 @@ void Host::writeFramesP25(p25::Control* control, std::function<void()>&& afterWr
if (control != nullptr) { if (control != nullptr) {
uint8_t nextLen = control->peekFrameLength(); uint8_t nextLen = control->peekFrameLength();
if (m_p25CtrlChannel) { if (m_p25CtrlChannel) {
if (m_p25DedicatedTxTestTimer.hasExpired()) { if (m_p25DedicatedTxTestTimer.hasExpired() && !m_p25DedicatedTxTestTimer.isPaused()) {
m_p25DedicatedTxTestTimer.pause(); m_p25DedicatedTxTestTimer.pause();
if (!m_modem->hasTX() && m_modem->gotModemStatus() && m_state == STATE_P25 && control->getCCRunning()) { if (!m_modem->hasTX() && m_modem->gotModemStatus() && m_state == STATE_P25 && control->getCCRunning()) {
LogError(LOG_HOST, "P25 dedicated control not transmitting, running = %u, halted = %u, frameLength = %u", control->getCCRunning(), control->getCCHalted(), nextLen); LogError(LOG_HOST, "P25 dedicated control not transmitting, running = %u, halted = %u, frameLength = %u", control->getCCRunning(), control->getCCHalted(), nextLen);

@ -122,6 +122,19 @@ Host::Host(const std::string& confFile) :
m_p25DedicatedTxTestTimer(1000U, 0U, 125U), m_p25DedicatedTxTestTimer(1000U, 0U, 125U),
m_nxdnBcastDurationTimer(1000U), m_nxdnBcastDurationTimer(1000U),
m_nxdnDedicatedTxTestTimer(1000U, 0U, 125U), m_nxdnDedicatedTxTestTimer(1000U, 0U, 125U),
m_dmrTx1WatchdogTimer(1000U, 1U),
m_dmrTx1LoopMS(0U),
m_dmrTx2WatchdogTimer(1000U, 1U),
m_dmrTx2LoopMS(0U),
m_p25TxWatchdogTimer(1000U, 1U),
m_p25TxLoopMS(0U),
m_nxdnTxWatchdogTimer(1000U, 1U),
m_nxdnTxLoopMS(0U),
m_mainLoopStage(0U),
m_mainLoopMS(0U),
m_mainLoopWatchdogTimer(1000U, 1U),
m_adjSiteLoopMS(0U),
m_adjSiteLoopWatchdogTimer(1000U, 1U),
m_activeTickDelay(5U), m_activeTickDelay(5U),
m_idleTickDelay(5U), m_idleTickDelay(5U),
m_restAddress("0.0.0.0"), m_restAddress("0.0.0.0"),
@ -733,15 +746,102 @@ int Host::run()
} \ } \
} }
// setup protocol processor threads /** Watchdog */
ThreadFunc watchdogThread([&, this]() {
if (g_killed)
return;
StopWatch stopWatch;
stopWatch.start();
LogDebug(LOG_HOST, "started watchdog");
while (!g_killed) {
uint32_t ms = stopWatch.elapsed();
stopWatch.start();
// scope is intentional
{
/** Digital Mobile Radio */ /** Digital Mobile Radio */
if (dmr != nullptr) {
if (m_dmrTx1WatchdogTimer.isRunning())
m_dmrTx1WatchdogTimer.clock(ms);
if (m_dmrTx1WatchdogTimer.isRunning() && m_dmrTx1WatchdogTimer.hasExpired() && !m_dmrTx1WatchdogTimer.isPaused()) {
m_dmrTx1WatchdogTimer.pause();
LogError(LOG_HOST, "DMR, slot 1 frame processor hung >%us, ms = %u", m_dmrTx1WatchdogTimer.getTimeout(), m_dmrTx1LoopMS);
}
if (m_dmrTx2WatchdogTimer.isRunning())
m_dmrTx2WatchdogTimer.clock(ms);
if (m_dmrTx2WatchdogTimer.isRunning() && m_dmrTx2WatchdogTimer.hasExpired() && !m_dmrTx2WatchdogTimer.isPaused()) {
m_dmrTx2WatchdogTimer.pause();
LogError(LOG_HOST, "DMR, slot 2 frame processor hung >%us, ms = %u", m_dmrTx2WatchdogTimer.getTimeout(), m_dmrTx2LoopMS);
}
}
/** Project 25 */
if (p25 != nullptr) {
if (m_p25TxWatchdogTimer.isRunning())
m_p25TxWatchdogTimer.clock(ms);
if (m_p25TxWatchdogTimer.isRunning() && m_p25TxWatchdogTimer.hasExpired() && !m_p25TxWatchdogTimer.isPaused()) {
m_p25TxWatchdogTimer.pause();
LogError(LOG_HOST, "P25, frame processor hung >%us, ms = %u", m_p25TxWatchdogTimer.getTimeout(), m_p25TxLoopMS);
}
}
/** Next Generation Digital Narrowband */
if (nxdn != nullptr) {
if (m_nxdnTxWatchdogTimer.isRunning())
m_nxdnTxWatchdogTimer.clock(ms);
if (m_nxdnTxWatchdogTimer.isRunning() && m_nxdnTxWatchdogTimer.hasExpired() && !m_nxdnTxWatchdogTimer.isPaused()) {
m_nxdnTxWatchdogTimer.pause();
LogError(LOG_HOST, "NXDN, frame processor hung >%us, ms = %u", m_nxdnTxWatchdogTimer.getTimeout(), m_nxdnTxLoopMS);
}
}
}
// scope is intentional
{
if (m_mainLoopWatchdogTimer.isRunning())
m_mainLoopWatchdogTimer.clock(ms);
if (m_mainLoopWatchdogTimer.isRunning() && m_mainLoopWatchdogTimer.hasExpired() && !m_mainLoopWatchdogTimer.isPaused()) {
m_mainLoopWatchdogTimer.pause();
LogError(LOG_HOST, "main processor hung >%us, stage = %u, ms = %u", m_mainLoopWatchdogTimer.getTimeout(), m_mainLoopStage, m_mainLoopMS);
}
if (m_adjSiteLoopWatchdogTimer.isRunning())
m_adjSiteLoopWatchdogTimer.clock(ms);
if (m_adjSiteLoopWatchdogTimer.isRunning() && m_adjSiteLoopWatchdogTimer.hasExpired() && !m_adjSiteLoopWatchdogTimer.isPaused()) {
m_adjSiteLoopWatchdogTimer.pause();
LogError(LOG_HOST, "adj. site update hung >%us, ms = %u", m_adjSiteLoopWatchdogTimer.getTimeout(), m_adjSiteLoopMS);
}
}
if (m_state != STATE_IDLE)
Thread::sleep(m_activeTickDelay);
if (m_state == STATE_IDLE)
Thread::sleep(m_idleTickDelay);
}
});
watchdogThread.run();
watchdogThread.setName("host:watchdog");
/** Digital Mobile Radio Frame Processor */
ThreadFunc dmrFrame1WriteThread([&, this]() { ThreadFunc dmrFrame1WriteThread([&, this]() {
if (g_killed) if (g_killed)
return; return;
StopWatch stopWatch;
stopWatch.start();
if (dmr != nullptr) { if (dmr != nullptr) {
LogDebug(LOG_HOST, "DMR, started slot 1 frame processor (modem write)"); LogDebug(LOG_HOST, "DMR, started slot 1 frame processor (modem write)");
while (!g_killed) { while (!g_killed) {
m_dmrTx1WatchdogTimer.start();
uint32_t ms = stopWatch.elapsed();
stopWatch.start();
m_dmrTx1LoopMS = ms;
// scope is intentional // scope is intentional
{ {
std::lock_guard<std::mutex> lock(clockingMutex); std::lock_guard<std::mutex> lock(clockingMutex);
@ -782,9 +882,18 @@ int Host::run()
if (g_killed) if (g_killed)
return; return;
StopWatch stopWatch;
stopWatch.start();
if (dmr != nullptr) { if (dmr != nullptr) {
LogDebug(LOG_HOST, "DMR, started slot 2 frame processor (modem write)"); LogDebug(LOG_HOST, "DMR, started slot 2 frame processor (modem write)");
while (!g_killed) { while (!g_killed) {
m_dmrTx2WatchdogTimer.start();
uint32_t ms = stopWatch.elapsed();
stopWatch.start();
m_dmrTx2LoopMS = ms;
// scope is intentional // scope is intentional
{ {
std::lock_guard<std::mutex> lock(clockingMutex); std::lock_guard<std::mutex> lock(clockingMutex);
@ -821,14 +930,23 @@ int Host::run()
dmrFrame2WriteThread.run(); dmrFrame2WriteThread.run();
dmrFrame2WriteThread.setName("dmr:frame2-w"); dmrFrame2WriteThread.setName("dmr:frame2-w");
/** Project 25 */ /** Project 25 Frame Processor */
ThreadFunc p25FrameWriteThread([&, this]() { ThreadFunc p25FrameWriteThread([&, this]() {
if (g_killed) if (g_killed)
return; return;
StopWatch stopWatch;
stopWatch.start();
if (p25 != nullptr) { if (p25 != nullptr) {
LogDebug(LOG_HOST, "P25, started frame processor (modem write)"); LogDebug(LOG_HOST, "P25, started frame processor (modem write)");
while (!g_killed) { while (!g_killed) {
m_p25TxWatchdogTimer.start();
uint32_t ms = stopWatch.elapsed();
stopWatch.start();
m_p25TxLoopMS = ms;
// scope is intentional // scope is intentional
{ {
std::lock_guard<std::mutex> lock(clockingMutex); std::lock_guard<std::mutex> lock(clockingMutex);
@ -862,14 +980,23 @@ int Host::run()
p25FrameWriteThread.run(); p25FrameWriteThread.run();
p25FrameWriteThread.setName("p25:frame-w"); p25FrameWriteThread.setName("p25:frame-w");
/** Next Generation Digital Narrowband */ /** Next Generation Digital Narrowband Frame Processor */
ThreadFunc nxdnFrameWriteThread([&, this]() { ThreadFunc nxdnFrameWriteThread([&, this]() {
if (g_killed) if (g_killed)
return; return;
StopWatch stopWatch;
stopWatch.start();
if (nxdn != nullptr) { if (nxdn != nullptr) {
LogDebug(LOG_HOST, "NXDN, started frame processor (modem write)"); LogDebug(LOG_HOST, "NXDN, started frame processor (modem write)");
while (!g_killed) { while (!g_killed) {
m_nxdnTxWatchdogTimer.start();
uint32_t ms = stopWatch.elapsed();
stopWatch.start();
m_nxdnTxLoopMS = ms;
// scope is intentional // scope is intentional
{ {
std::lock_guard<std::mutex> lock(clockingMutex); std::lock_guard<std::mutex> lock(clockingMutex);
@ -903,6 +1030,38 @@ int Host::run()
nxdnFrameWriteThread.run(); nxdnFrameWriteThread.run();
nxdnFrameWriteThread.setName("nxdn:frame-w"); nxdnFrameWriteThread.setName("nxdn:frame-w");
/** Adjacent Site and Affiliation Update */
ThreadFunc siteDataUpdateThread([&, this]() {
if (g_killed)
return;
StopWatch stopWatch;
stopWatch.start();
LogDebug(LOG_HOST, "started adj. site and affiliation processor");
while (!g_killed) {
m_nxdnTxWatchdogTimer.start();
uint32_t ms = stopWatch.elapsed();
stopWatch.start();
m_adjSiteLoopMS = ms;
if (dmr != nullptr)
dmr->clockSiteData(ms);
if (p25 != nullptr)
p25->clockSiteData(ms);
if (nxdn != nullptr)
nxdn->clockSiteData(ms);
if (m_state != STATE_IDLE)
Thread::sleep(m_activeTickDelay);
if (m_state == STATE_IDLE)
Thread::sleep(m_idleTickDelay);
}
});
siteDataUpdateThread.run();
siteDataUpdateThread.setName("host:site-data");
/** Network Presence Notification */ /** Network Presence Notification */
ThreadFunc presenceThread([&, this]() { ThreadFunc presenceThread([&, this]() {
if (g_killed) if (g_killed)
@ -915,6 +1074,7 @@ int Host::run()
StopWatch stopWatch; StopWatch stopWatch;
stopWatch.start(); stopWatch.start();
LogDebug(LOG_HOST, "started presence notifier");
while (!g_killed) { while (!g_killed) {
// scope is intentional // scope is intentional
{ {
@ -1026,6 +1186,9 @@ int Host::run()
} }
} }
m_mainLoopWatchdogTimer.start();
m_mainLoopStage = 0U; // intentional magic number
// scope is intentional // scope is intentional
{ {
std::lock_guard<std::mutex> lock(clockingMutex); std::lock_guard<std::mutex> lock(clockingMutex);
@ -1038,14 +1201,19 @@ int Host::run()
stopWatch.start(); stopWatch.start();
m_modem->clock(ms); m_modem->clock(ms);
m_mainLoopStage = 1U; // intentional magic number
} }
m_mainLoopMS = ms;
// ------------------------------------------------------ // ------------------------------------------------------
// -- Read from Modem Processing -- // -- Read from Modem Processing --
// ------------------------------------------------------ // ------------------------------------------------------
/** Digital Mobile Radio */ /** Digital Mobile Radio */
if (dmr != nullptr) { if (dmr != nullptr) {
m_mainLoopStage = 2U; // intentional magic number
// read DMR slot 1 frames from modem // read DMR slot 1 frames from modem
readFramesDMR1(dmr.get(), [&, this]() { readFramesDMR1(dmr.get(), [&, this]() {
if (dmr != nullptr) { if (dmr != nullptr) {
@ -1091,6 +1259,8 @@ int Host::run()
/** Project 25 */ /** Project 25 */
if (p25 != nullptr) { if (p25 != nullptr) {
m_mainLoopStage = 3U; // intentional magic number
// read P25 frames from modem // read P25 frames from modem
readFramesP25(p25.get(), [&, this]() { readFramesP25(p25.get(), [&, this]() {
if (dmr != nullptr) { if (dmr != nullptr) {
@ -1108,6 +1278,8 @@ int Host::run()
/** Next Generation Digital Narrowband */ /** Next Generation Digital Narrowband */
if (nxdn != nullptr) { if (nxdn != nullptr) {
m_mainLoopStage = 4U; // intentional magic number
// read NXDN frames from modem // read NXDN frames from modem
readFramesNXDN(nxdn.get(), [&, this]() { readFramesNXDN(nxdn.get(), [&, this]() {
if (dmr != nullptr) { if (dmr != nullptr) {
@ -1127,11 +1299,14 @@ int Host::run()
// -- Network, DMR, and P25 Clocking -- // -- Network, DMR, and P25 Clocking --
// ------------------------------------------------------ // ------------------------------------------------------
if (m_network != nullptr) if (m_network != nullptr) {
m_mainLoopStage = 5U; // intentional magic number
m_network->clock(ms); m_network->clock(ms);
}
if (dmr != nullptr) { if (dmr != nullptr) {
dmr->clock(ms); m_mainLoopStage = 6U; // intentional magic number
dmr->clock();
if (m_dmrCtrlChannel) { if (m_dmrCtrlChannel) {
if (!m_dmrDedicatedTxTestTimer.isRunning()) { if (!m_dmrDedicatedTxTestTimer.isRunning()) {
@ -1143,7 +1318,8 @@ int Host::run()
} }
if (p25 != nullptr) { if (p25 != nullptr) {
p25->clock(ms); m_mainLoopStage = 7U; // intentional magic number
p25->clock();
if (m_p25CtrlChannel) { if (m_p25CtrlChannel) {
if (!m_p25DedicatedTxTestTimer.isRunning()) { if (!m_p25DedicatedTxTestTimer.isRunning()) {
@ -1155,7 +1331,8 @@ int Host::run()
} }
if (nxdn != nullptr) { if (nxdn != nullptr) {
nxdn->clock(ms); m_mainLoopStage = 8U; // intentional magic number
nxdn->clock();
if (m_nxdnCtrlChannel) { if (m_nxdnCtrlChannel) {
if (!m_nxdnDedicatedTxTestTimer.isRunning()) { if (!m_nxdnDedicatedTxTestTimer.isRunning()) {
@ -1173,6 +1350,7 @@ int Host::run()
// clock and check CW timer // clock and check CW timer
m_cwIdTimer.clock(ms); m_cwIdTimer.clock(ms);
if (m_cwIdTimer.isRunning() && m_cwIdTimer.hasExpired()) { if (m_cwIdTimer.isRunning() && m_cwIdTimer.hasExpired()) {
m_mainLoopStage = 9U; // intentional magic number
if (!m_modem->hasTX() && !m_p25CtrlChannel && !m_dmrCtrlChannel && !m_nxdnCtrlChannel) { if (!m_modem->hasTX() && !m_p25CtrlChannel && !m_dmrCtrlChannel && !m_nxdnCtrlChannel) {
if (m_dmrBeaconDurationTimer.isRunning() || m_p25BcastDurationTimer.isRunning() || if (m_dmrBeaconDurationTimer.isRunning() || m_p25BcastDurationTimer.isRunning() ||
m_nxdnBcastDurationTimer.isRunning()) { m_nxdnBcastDurationTimer.isRunning()) {
@ -1222,6 +1400,8 @@ int Host::run()
} }
} }
m_mainLoopStage = 10U; // intentional magic number
/** Digial Mobile Radio */ /** Digial Mobile Radio */
if (dmr != nullptr) { if (dmr != nullptr) {
if (m_dmrTSCCData && m_dmrCtrlChannel) { if (m_dmrTSCCData && m_dmrCtrlChannel) {
@ -1411,12 +1591,21 @@ int Host::run()
} }
if (g_killed) { if (g_killed) {
// shutdown writer threads // shutdown helper threads
presenceThread.wait();
siteDataUpdateThread.wait();
if (dmr != nullptr) {
dmrFrame1WriteThread.wait(); dmrFrame1WriteThread.wait();
dmrFrame2WriteThread.wait(); dmrFrame2WriteThread.wait();
}
if (p25 != nullptr)
p25FrameWriteThread.wait(); p25FrameWriteThread.wait();
if (nxdn != nullptr)
nxdnFrameWriteThread.wait(); nxdnFrameWriteThread.wait();
watchdogThread.wait();
if (dmr != nullptr) { if (dmr != nullptr) {
if (m_state == STATE_DMR && m_duplex && m_modem->hasTX()) { if (m_state == STATE_DMR && m_duplex && m_modem->hasTX()) {
m_modem->writeDMRStart(false); m_modem->writeDMRStart(false);

@ -149,6 +149,20 @@ private:
Timer m_nxdnBcastDurationTimer; Timer m_nxdnBcastDurationTimer;
Timer m_nxdnDedicatedTxTestTimer; Timer m_nxdnDedicatedTxTestTimer;
Timer m_dmrTx1WatchdogTimer;
uint32_t m_dmrTx1LoopMS;
Timer m_dmrTx2WatchdogTimer;
uint32_t m_dmrTx2LoopMS;
Timer m_p25TxWatchdogTimer;
uint32_t m_p25TxLoopMS;
Timer m_nxdnTxWatchdogTimer;
uint32_t m_nxdnTxLoopMS;
uint8_t m_mainLoopStage;
uint32_t m_mainLoopMS;
Timer m_mainLoopWatchdogTimer;
uint32_t m_adjSiteLoopMS;
Timer m_adjSiteLoopWatchdogTimer;
uint8_t m_activeTickDelay; uint8_t m_activeTickDelay;
uint8_t m_idleTickDelay; uint8_t m_idleTickDelay;

@ -371,29 +371,28 @@ uint32_t Control::getFrame(uint32_t slotNo, uint8_t* data)
} }
/// <summary> /// <summary>
/// Updates the processor by the passed number of milliseconds. /// Updates the processor.
/// </summary> /// </summary>
/// <param name="ms"></param> void Control::clock()
void Control::clock(uint32_t ms)
{ {
if (m_network != nullptr) { if (m_network != nullptr) {
processNetwork(); processNetwork();
} }
m_tsccCntInterval.clock(ms);
if (m_tsccCntInterval.isRunning() && m_tsccCntInterval.hasExpired()) {
m_tsccCnt++;
if (m_tsccCnt == TSCC_MAX_CSC_CNT) {
m_tsccCnt = 0U;
}
m_tsccCntInterval.start();
}
m_slot1->clock(); m_slot1->clock();
m_slot2->clock(); m_slot2->clock();
} }
/// <summary>
/// Updates the adj. site tables.
/// </summary>
/// <param name="ms"></param>
void Control::clockSiteData(uint32_t ms)
{
m_slot1->clockSiteData(ms);
m_slot2->clockSiteData(ms);
}
/// <summary> /// <summary>
/// Sets a flag indicating whether DMR has supervisory functions and can send permit TG to voice channels. /// Sets a flag indicating whether DMR has supervisory functions and can send permit TG to voice channels.
/// </summary> /// </summary>

@ -75,7 +75,9 @@ namespace dmr
uint32_t getFrame(uint32_t slotNo, uint8_t* data); uint32_t getFrame(uint32_t slotNo, uint8_t* data);
/// <summary>Updates the processor.</summary> /// <summary>Updates the processor.</summary>
void clock(uint32_t ms); void clock();
/// <summary>Updates the adj. site tables.</summary>
void clockSiteData(uint32_t ms);
/// <summary>Sets a flag indicating whether DMR has supervisory functions and can send permit TG to voice channels.</summary> /// <summary>Sets a flag indicating whether DMR has supervisory functions and can send permit TG to voice channels.</summary>
void setSupervisor(bool supervisor); void setSupervisor(bool supervisor);

@ -469,10 +469,17 @@ void Slot::clock()
// if we have control enabled; do clocking to generate a CC data stream // if we have control enabled; do clocking to generate a CC data stream
if (m_enableTSCC) { if (m_enableTSCC) {
m_modem->setDMRIgnoreCACH_AT(m_slotNo); m_dmr->m_tsccCntInterval.clock(ms);
if (m_dmr->m_tsccCntInterval.isRunning() && m_dmr->m_tsccCntInterval.hasExpired()) {
m_dmr->m_tsccCnt++;
if (m_dmr->m_tsccCnt == TSCC_MAX_CSC_CNT) {
m_dmr->m_tsccCnt = 0U;
}
// clock all the grant timers m_dmr->m_tsccCntInterval.start();
m_affiliations->clock(ms); }
m_modem->setDMRIgnoreCACH_AT(m_slotNo);
if (m_ccRunning && !m_ccPacketInterval.isRunning()) { if (m_ccRunning && !m_ccPacketInterval.isRunning()) {
m_ccPacketInterval.start(); m_ccPacketInterval.start();
@ -515,50 +522,6 @@ void Slot::clock()
} }
} }
// do we need to network announce ourselves?
if (!m_adjSiteUpdateTimer.isRunning()) {
m_control->writeAdjSSNetwork();
m_adjSiteUpdateTimer.start();
}
m_adjSiteUpdateTimer.clock(ms);
if (m_adjSiteUpdateTimer.isRunning() && m_adjSiteUpdateTimer.hasExpired()) {
if (m_rfState == RS_RF_LISTENING && m_netState == RS_NET_IDLE) {
m_control->writeAdjSSNetwork();
if (m_network != nullptr) {
if (m_affiliations->grpAffSize() > 0) {
auto affs = m_affiliations->grpAffTable();
m_network->announceAffiliationUpdate(affs);
}
}
m_adjSiteUpdateTimer.start();
}
}
// clock adjacent site and SCCB update timers
m_adjSiteUpdateTimer.clock(ms);
if (m_adjSiteUpdateTimer.isRunning() && m_adjSiteUpdateTimer.hasExpired()) {
// update adjacent site data
for (auto& entry : m_adjSiteUpdateCnt) {
uint8_t siteId = entry.first;
uint8_t updateCnt = entry.second;
if (updateCnt > 0U) {
updateCnt--;
}
if (updateCnt == 0U) {
AdjSiteData siteData = m_adjSiteTable[siteId];
LogWarning(LOG_NET, "DMR, Adjacent Site Status Expired, no data [FAILED], sysId = $%03X, chNo = %u",
siteData.systemIdentity, siteData.channelNo);
}
entry.second = updateCnt;
}
m_adjSiteUpdateTimer.setTimeout(m_adjSiteUpdateInterval);
m_adjSiteUpdateTimer.start();
}
if (m_ccPrevRunning && !m_ccRunning) { if (m_ccPrevRunning && !m_ccRunning) {
m_txQueue.clear(); // clear the frame buffer m_txQueue.clear(); // clear the frame buffer
m_ccPrevRunning = m_ccRunning; m_ccPrevRunning = m_ccRunning;
@ -709,6 +672,62 @@ void Slot::clock()
} }
} }
/// <summary>
/// Updates the adj. site tables.
/// </summary>
/// <param name="ms"></param>
void Slot::clockSiteData(uint32_t ms)
{
if (m_enableTSCC) {
// clock all the grant timers
m_affiliations->clock(ms);
// do we need to network announce ourselves?
if (!m_adjSiteUpdateTimer.isRunning()) {
m_control->writeAdjSSNetwork();
m_adjSiteUpdateTimer.start();
}
m_adjSiteUpdateTimer.clock(ms);
if (m_adjSiteUpdateTimer.isRunning() && m_adjSiteUpdateTimer.hasExpired()) {
if (m_rfState == RS_RF_LISTENING && m_netState == RS_NET_IDLE) {
m_control->writeAdjSSNetwork();
if (m_network != nullptr) {
if (m_affiliations->grpAffSize() > 0) {
auto affs = m_affiliations->grpAffTable();
m_network->announceAffiliationUpdate(affs);
}
}
m_adjSiteUpdateTimer.start();
}
}
// clock adjacent site update timers
m_adjSiteUpdateTimer.clock(ms);
if (m_adjSiteUpdateTimer.isRunning() && m_adjSiteUpdateTimer.hasExpired()) {
// update adjacent site data
for (auto& entry : m_adjSiteUpdateCnt) {
uint8_t siteId = entry.first;
uint8_t updateCnt = entry.second;
if (updateCnt > 0U) {
updateCnt--;
}
if (updateCnt == 0U) {
AdjSiteData siteData = m_adjSiteTable[siteId];
LogWarning(LOG_NET, "DMR, Adjacent Site Status Expired, no data [FAILED], sysId = $%03X, chNo = %u",
siteData.systemIdentity, siteData.channelNo);
}
entry.second = updateCnt;
}
m_adjSiteUpdateTimer.setTimeout(m_adjSiteUpdateInterval);
m_adjSiteUpdateTimer.start();
}
}
}
/// <summary> /// <summary>
/// Permits a TGID on a non-authoritative host. /// Permits a TGID on a non-authoritative host.
/// </summary> /// </summary>

@ -93,8 +93,10 @@ namespace dmr
/// <summary>Process a data frames from the network.</summary> /// <summary>Process a data frames from the network.</summary>
void processNetwork(const data::Data& data); void processNetwork(const data::Data& data);
/// <summary>Updates the slot processor.</summary> /// <summary>Updates the DMR slot processor.</summary>
void clock(); void clock();
/// <summary>Updates the adj. site tables.</summary>
void clockSiteData(uint32_t ms);
/// <summary>Permits a TGID on a non-authoritative host.</summary> /// <summary>Permits a TGID on a non-authoritative host.</summary>
void permittedTG(uint32_t dstId); void permittedTG(uint32_t dstId);

@ -116,6 +116,7 @@ Control::Control(bool authoritative, uint32_t ran, uint32_t callHang, uint32_t q
m_netTGHang(1000U, 2U), m_netTGHang(1000U, 2U),
m_networkWatchdog(1000U, 0U, 1500U), m_networkWatchdog(1000U, 0U, 1500U),
m_ccPacketInterval(1000U, 0U, 80U), m_ccPacketInterval(1000U, 0U, 80U),
m_interval(),
m_frameLossCnt(0U), m_frameLossCnt(0U),
m_frameLossThreshold(DEFAULT_FRAME_LOSS_THRESHOLD), m_frameLossThreshold(DEFAULT_FRAME_LOSS_THRESHOLD),
m_ccFrameCnt(0U), m_ccFrameCnt(0U),
@ -138,6 +139,8 @@ Control::Control(bool authoritative, uint32_t ran, uint32_t callHang, uint32_t q
assert(idenTable != nullptr); assert(idenTable != nullptr);
assert(rssiMapper != nullptr); assert(rssiMapper != nullptr);
m_interval.start();
acl::AccessControl::init(m_ridLookup, m_tidLookup); acl::AccessControl::init(m_ridLookup, m_tidLookup);
m_voice = new Voice(this, debug, verbose); m_voice = new Voice(this, debug, verbose);
@ -530,11 +533,13 @@ uint32_t Control::getFrame(uint8_t* data)
} }
/// <summary> /// <summary>
/// Updates the processor by the passed number of milliseconds. /// Updates the processor.
/// </summary> /// </summary>
/// <param name="ms"></param> void Control::clock()
void Control::clock(uint32_t ms)
{ {
uint32_t ms = m_interval.elapsed();
m_interval.start();
if (m_network != nullptr) { if (m_network != nullptr) {
processNetwork(); processNetwork();
@ -701,10 +706,17 @@ void Control::clock(uint32_t ms)
if (m_frameLossCnt >= m_frameLossThreshold && (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA)) { if (m_frameLossCnt >= m_frameLossThreshold && (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA)) {
processFrameLoss(); processFrameLoss();
} }
}
// clock data and trunking /// <summary>
if (m_control != nullptr) { /// Updates the adj. site tables and affiliations.
m_control->clock(ms); /// </summary>
/// <param name="ms"></param>
void Control::clockSiteData(uint32_t ms)
{
if (m_enableControl) {
// clock all the grant timers
m_affiliations.clock(ms);
} }
} }

@ -26,6 +26,7 @@
#include "common/lookups/TalkgroupRulesLookup.h" #include "common/lookups/TalkgroupRulesLookup.h"
#include "common/lookups/AffiliationLookup.h" #include "common/lookups/AffiliationLookup.h"
#include "common/RingBuffer.h" #include "common/RingBuffer.h"
#include "common/StopWatch.h"
#include "common/Timer.h" #include "common/Timer.h"
#include "common/yaml/Yaml.h" #include "common/yaml/Yaml.h"
#include "nxdn/packet/Voice.h" #include "nxdn/packet/Voice.h"
@ -85,8 +86,10 @@ namespace nxdn
/// <summary>Get frame data from data ring buffer.</summary> /// <summary>Get frame data from data ring buffer.</summary>
uint32_t getFrame(uint8_t* data); uint32_t getFrame(uint8_t* data);
/// <summary>Updates the processor by the passed number of milliseconds.</summary> /// <summary>Updates the processor.</summary>
void clock(uint32_t ms); void clock();
/// <summary>Updates the adj. site tables and affiliations.</summary>
void clockSiteData(uint32_t ms);
/// <summary>Sets a flag indicating whether NXDN has supervisory functions and can send permit TG to voice channels.</summary> /// <summary>Sets a flag indicating whether NXDN has supervisory functions and can send permit TG to voice channels.</summary>
void setSupervisor(bool supervisor) { m_supervisor = supervisor; } void setSupervisor(bool supervisor) { m_supervisor = supervisor; }
@ -184,6 +187,8 @@ namespace nxdn
Timer m_ccPacketInterval; Timer m_ccPacketInterval;
StopWatch m_interval;
uint8_t m_frameLossCnt; uint8_t m_frameLossCnt;
uint8_t m_frameLossThreshold; uint8_t m_frameLossThreshold;

@ -291,18 +291,6 @@ bool ControlSignaling::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& net
return true; return true;
} }
/// <summary>
/// Updates the processor by the passed number of milliseconds.
/// </summary>
/// <param name="ms"></param>
void ControlSignaling::clock(uint32_t ms)
{
if (m_nxdn->m_enableControl) {
// clock all the grant timers
m_nxdn->m_affiliations.clock(ms);
}
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Protected Class Members // Protected Class Members
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

@ -44,9 +44,6 @@ namespace nxdn
/// <summary>Process a data frame from the network.</summary> /// <summary>Process a data frame from the network.</summary>
bool processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t* data, uint32_t len); bool processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t* data, uint32_t len);
/// <summary>Updates the processor by the passed number of milliseconds.</summary>
void clock(uint32_t ms);
protected: protected:
friend class nxdn::packet::Data; friend class nxdn::packet::Data;
friend class nxdn::packet::Voice; friend class nxdn::packet::Voice;

@ -118,6 +118,7 @@ Control::Control(bool authoritative, uint32_t nac, uint32_t callHang, uint32_t q
m_networkWatchdog(1000U, 0U, 1500U), m_networkWatchdog(1000U, 0U, 1500U),
m_adjSiteUpdate(1000U, 75U), m_adjSiteUpdate(1000U, 75U),
m_ccPacketInterval(1000U, 0U, 10U), m_ccPacketInterval(1000U, 0U, 10U),
m_interval(),
m_hangCount(3U * 8U), m_hangCount(3U * 8U),
m_tduPreambleCount(8U), m_tduPreambleCount(8U),
m_frameLossCnt(0U), m_frameLossCnt(0U),
@ -147,6 +148,8 @@ Control::Control(bool authoritative, uint32_t nac, uint32_t callHang, uint32_t q
assert(idenTable != nullptr); assert(idenTable != nullptr);
assert(rssiMapper != nullptr); assert(rssiMapper != nullptr);
m_interval.start();
acl::AccessControl::init(m_ridLookup, m_tidLookup); acl::AccessControl::init(m_ridLookup, m_tidLookup);
m_hangCount = callHang * 4U; m_hangCount = callHang * 4U;
@ -753,11 +756,13 @@ bool Control::writeRF_VoiceEnd()
} }
/// <summary> /// <summary>
/// Updates the processor by the passed number of milliseconds. /// Updates the processor.
/// </summary> /// </summary>
/// <param name="ms"></param> void Control::clock()
void Control::clock(uint32_t ms)
{ {
uint32_t ms = m_interval.elapsed();
m_interval.start();
if (m_network != nullptr) { if (m_network != nullptr) {
processNetwork(); processNetwork();
@ -803,26 +808,6 @@ void Control::clock(uint32_t ms)
writeRF_ControlEnd(); writeRF_ControlEnd();
m_ccPrevRunning = m_ccRunning; m_ccPrevRunning = m_ccRunning;
} }
// do we need to network announce ourselves?
if (!m_adjSiteUpdate.isRunning()) {
m_control->writeAdjSSNetwork();
m_adjSiteUpdate.start();
}
m_adjSiteUpdate.clock(ms);
if (m_adjSiteUpdate.isRunning() && m_adjSiteUpdate.hasExpired()) {
if (m_rfState == RS_RF_LISTENING && m_netState == RS_NET_IDLE) {
m_control->writeAdjSSNetwork();
if (m_network != nullptr) {
if (m_affiliations.grpAffSize() > 0) {
auto affs = m_affiliations.grpAffTable();
m_network->announceAffiliationUpdate(affs);
}
}
m_adjSiteUpdate.start();
}
}
} }
// handle timeouts and hang timers // handle timeouts and hang timers
@ -933,9 +918,86 @@ void Control::clock(uint32_t ms)
if (m_data != nullptr) { if (m_data != nullptr) {
m_data->clock(ms); m_data->clock(ms);
} }
}
/// <summary>
/// Updates the adj. site tables and affiliations.
/// </summary>
/// <param name="ms"></param>
void Control::clockSiteData(uint32_t ms)
{
if (m_enableControl) {
// clock all the grant timers
m_affiliations.clock(ms);
}
if (m_control != nullptr) { if (m_control != nullptr) {
m_control->clock(ms); // do we need to network announce ourselves?
if (!m_adjSiteUpdate.isRunning()) {
m_control->writeAdjSSNetwork();
m_adjSiteUpdate.start();
}
m_adjSiteUpdate.clock(ms);
if (m_adjSiteUpdate.isRunning() && m_adjSiteUpdate.hasExpired()) {
if (m_rfState == RS_RF_LISTENING && m_netState == RS_NET_IDLE) {
m_control->writeAdjSSNetwork();
if (m_network != nullptr) {
if (m_affiliations.grpAffSize() > 0) {
auto affs = m_affiliations.grpAffTable();
m_network->announceAffiliationUpdate(affs);
}
}
m_adjSiteUpdate.start();
}
}
if (m_enableControl) {
// clock adjacent site and SCCB update timers
m_control->m_adjSiteUpdateTimer.clock(ms);
if (m_control->m_adjSiteUpdateTimer.isRunning() && m_control->m_adjSiteUpdateTimer.hasExpired()) {
if (m_control->m_adjSiteUpdateCnt.size() > 0) {
// update adjacent site data
for (auto &entry : m_control->m_adjSiteUpdateCnt) {
uint8_t siteId = entry.first;
uint8_t updateCnt = entry.second;
if (updateCnt > 0U) {
updateCnt--;
}
if (updateCnt == 0U) {
SiteData siteData = m_control->m_adjSiteTable[siteId];
LogWarning(LOG_NET, "P25, Adjacent Site Status Expired, no data [FAILED], sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u, svcClass = $%02X",
siteData.sysId(), siteData.rfssId(), siteData.siteId(), siteData.channelId(), siteData.channelNo(), siteData.serviceClass());
}
entry.second = updateCnt;
}
}
if (m_control->m_sccbUpdateCnt.size() > 0) {
// update SCCB data
for (auto& entry : m_control->m_sccbUpdateCnt) {
uint8_t rfssId = entry.first;
uint8_t updateCnt = entry.second;
if (updateCnt > 0U) {
updateCnt--;
}
if (updateCnt == 0U) {
SiteData siteData = m_control->m_sccbTable[rfssId];
LogWarning(LOG_NET, "P25, Secondary Control Channel Expired, no data [FAILED], sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u, svcClass = $%02X",
siteData.sysId(), siteData.rfssId(), siteData.siteId(), siteData.channelId(), siteData.channelNo(), siteData.serviceClass());
}
entry.second = updateCnt;
}
}
m_control->m_adjSiteUpdateTimer.setTimeout(m_control->m_adjSiteUpdateInterval);
m_control->m_adjSiteUpdateTimer.start();
}
}
} }
} }

@ -23,6 +23,7 @@
#include "common/lookups/TalkgroupRulesLookup.h" #include "common/lookups/TalkgroupRulesLookup.h"
#include "common/p25/SiteData.h" #include "common/p25/SiteData.h"
#include "common/RingBuffer.h" #include "common/RingBuffer.h"
#include "common/StopWatch.h"
#include "common/Timer.h" #include "common/Timer.h"
#include "common/yaml/Yaml.h" #include "common/yaml/Yaml.h"
#include "p25/packet/Data.h" #include "p25/packet/Data.h"
@ -89,8 +90,10 @@ namespace p25
/// <summary>Helper to write end of voice call frame data.</summary> /// <summary>Helper to write end of voice call frame data.</summary>
bool writeRF_VoiceEnd(); bool writeRF_VoiceEnd();
/// <summary>Updates the processor by the passed number of milliseconds.</summary> /// <summary>Updates the processor.</summary>
void clock(uint32_t ms); void clock();
/// <summary>Updates the adj. site tables and affiliations.</summary>
void clockSiteData(uint32_t ms);
/// <summary>Sets a flag indicating whether P25 has supervisory functions and can send permit TG to voice channels.</summary> /// <summary>Sets a flag indicating whether P25 has supervisory functions and can send permit TG to voice channels.</summary>
void setSupervisor(bool supervisor) { m_supervisor = supervisor; } void setSupervisor(bool supervisor) { m_supervisor = supervisor; }
@ -195,6 +198,8 @@ namespace p25
Timer m_ccPacketInterval; Timer m_ccPacketInterval;
StopWatch m_interval;
uint32_t m_hangCount; uint32_t m_hangCount;
uint32_t m_tduPreambleCount; uint32_t m_tduPreambleCount;

@ -148,7 +148,7 @@ using namespace p25::packet;
// Constants // Constants
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const uint32_t ADJ_SITE_TIMER_TIMEOUT = 30U; const uint32_t ADJ_SITE_TIMER_TIMEOUT = 60U;
const uint32_t ADJ_SITE_UPDATE_CNT = 5U; const uint32_t ADJ_SITE_UPDATE_CNT = 5U;
const uint32_t TSDU_CTRL_BURST_COUNT = 2U; const uint32_t TSDU_CTRL_BURST_COUNT = 2U;
const uint32_t TSBK_MBF_CNT = 3U; const uint32_t TSBK_MBF_CNT = 3U;
@ -997,59 +997,6 @@ void ControlSignaling::writeAdjSSNetwork()
} }
} }
/// <summary>
/// Updates the processor by the passed number of milliseconds.
/// </summary>
/// <param name="ms"></param>
void ControlSignaling::clock(uint32_t ms)
{
if (m_p25->m_enableControl) {
// clock all the grant timers
m_p25->m_affiliations.clock(ms);
// clock adjacent site and SCCB update timers
m_adjSiteUpdateTimer.clock(ms);
if (m_adjSiteUpdateTimer.isRunning() && m_adjSiteUpdateTimer.hasExpired()) {
// update adjacent site data
for (auto& entry : m_adjSiteUpdateCnt) {
uint8_t siteId = entry.first;
uint8_t updateCnt = entry.second;
if (updateCnt > 0U) {
updateCnt--;
}
if (updateCnt == 0U) {
SiteData siteData = m_adjSiteTable[siteId];
LogWarning(LOG_NET, "P25, Adjacent Site Status Expired, no data [FAILED], sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u, svcClass = $%02X",
siteData.sysId(), siteData.rfssId(), siteData.siteId(), siteData.channelId(), siteData.channelNo(), siteData.serviceClass());
}
entry.second = updateCnt;
}
// update SCCB data
for (auto& entry : m_sccbUpdateCnt) {
uint8_t rfssId = entry.first;
uint8_t updateCnt = entry.second;
if (updateCnt > 0U) {
updateCnt--;
}
if (updateCnt == 0U) {
SiteData siteData = m_sccbTable[rfssId];
LogWarning(LOG_NET, "P25, Secondary Control Channel Expired, no data [FAILED], sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u, svcClass = $%02X",
siteData.sysId(), siteData.rfssId(), siteData.siteId(), siteData.channelId(), siteData.channelNo(), siteData.serviceClass());
}
entry.second = updateCnt;
}
m_adjSiteUpdateTimer.setTimeout(m_adjSiteUpdateInterval);
m_adjSiteUpdateTimer.start();
}
}
}
/// <summary> /// <summary>
/// Helper to write a call alert packet. /// Helper to write a call alert packet.
/// </summary> /// </summary>

@ -58,9 +58,6 @@ namespace p25
/// <summary>Helper to write P25 adjacent site information to the network.</summary> /// <summary>Helper to write P25 adjacent site information to the network.</summary>
void writeAdjSSNetwork(); void writeAdjSSNetwork();
/// <summary>Updates the processor by the passed number of milliseconds.</summary>
void clock(uint32_t ms);
/// <summary>Helper to write a call alert packet.</summary> /// <summary>Helper to write a call alert packet.</summary>
void writeRF_TSDU_Call_Alrt(uint32_t srcId, uint32_t dstId); void writeRF_TSDU_Call_Alrt(uint32_t srcId, uint32_t dstId);
/// <summary>Helper to write a radio monitor packet.</summary> /// <summary>Helper to write a radio monitor packet.</summary>

Loading…
Cancel
Save

Powered by TurnKey Linux.