From 0fef073c13044343782553749f995106aba1d8cc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 3 Apr 2020 16:54:35 +0100 Subject: [PATCH] Add dynamic TG voice prompts and status TG. --- Conf.cpp | 80 +++++---- Conf.h | 1 + DMRGateway.cpp | 169 ++++++++++-------- DMRGateway.h | 13 +- DMRGateway.ini | 4 +- DMRGateway.vcxproj | 2 + DMRGateway.vcxproj.filters | 6 + DynVoice.cpp | 345 +++++++++++++++++++++++++++++++++++++ DynVoice.h | 81 +++++++++ Makefile | 6 +- RewriteDynTGNet.cpp | 4 +- RewriteDynTGRF.cpp | 50 ++++-- RewriteDynTGRF.h | 5 +- Version.h | 2 +- XLXVoice.cpp | 20 +-- XLXVoice.h | 14 +- 16 files changed, 651 insertions(+), 151 deletions(-) create mode 100644 DynVoice.cpp create mode 100644 DynVoice.h diff --git a/Conf.cpp b/Conf.cpp index 6e966dd..bf020ef 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -410,14 +410,16 @@ bool CConf::read() char* p2 = ::strtok(NULL, ", "); char* p3 = ::strtok(NULL, ", "); char* p4 = ::strtok(NULL, ", "); - char* p5 = ::strtok(NULL, " \r\n"); - if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL) { + char* p5 = ::strtok(NULL, ", "); + char* p6 = ::strtok(NULL, " \r\n"); + if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL && p6 != NULL) { CTGDynRewriteStruct rewrite; - rewrite.m_slot = ::atoi(p1); - rewrite.m_fromTG = ::atoi(p2); - rewrite.m_discTG = ::atoi(p3); - rewrite.m_toTG = ::atoi(p4); - rewrite.m_range = ::atoi(p5); + rewrite.m_slot = ::atoi(p1); + rewrite.m_fromTG = ::atoi(p2); + rewrite.m_discTG = ::atoi(p3); + rewrite.m_statusTG = ::atoi(p4); + rewrite.m_toTG = ::atoi(p5); + rewrite.m_range = ::atoi(p6); m_dmrNetwork1TGDynRewrites.push_back(rewrite); } } else if (::strncmp(key, "IdRewrite", 9U) == 0) { @@ -520,14 +522,16 @@ bool CConf::read() char* p2 = ::strtok(NULL, ", "); char* p3 = ::strtok(NULL, ", "); char* p4 = ::strtok(NULL, ", "); - char* p5 = ::strtok(NULL, " \r\n"); - if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL) { + char* p5 = ::strtok(NULL, ", "); + char* p6 = ::strtok(NULL, " \r\n"); + if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL && p6 != NULL) { CTGDynRewriteStruct rewrite; - rewrite.m_slot = ::atoi(p1); - rewrite.m_fromTG = ::atoi(p2); - rewrite.m_discTG = ::atoi(p3); - rewrite.m_toTG = ::atoi(p4); - rewrite.m_range = ::atoi(p5); + rewrite.m_slot = ::atoi(p1); + rewrite.m_fromTG = ::atoi(p2); + rewrite.m_discTG = ::atoi(p3); + rewrite.m_statusTG = ::atoi(p4); + rewrite.m_toTG = ::atoi(p5); + rewrite.m_range = ::atoi(p6); m_dmrNetwork2TGDynRewrites.push_back(rewrite); } } else if (::strncmp(key, "IdRewrite", 9U) == 0) { @@ -630,14 +634,16 @@ bool CConf::read() char* p2 = ::strtok(NULL, ", "); char* p3 = ::strtok(NULL, ", "); char* p4 = ::strtok(NULL, ", "); - char* p5 = ::strtok(NULL, " \r\n"); - if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL) { + char* p5 = ::strtok(NULL, ", "); + char* p6 = ::strtok(NULL, " \r\n"); + if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL && p6 != NULL) { CTGDynRewriteStruct rewrite; - rewrite.m_slot = ::atoi(p1); - rewrite.m_fromTG = ::atoi(p2); - rewrite.m_discTG = ::atoi(p3); - rewrite.m_toTG = ::atoi(p4); - rewrite.m_range = ::atoi(p5); + rewrite.m_slot = ::atoi(p1); + rewrite.m_fromTG = ::atoi(p2); + rewrite.m_discTG = ::atoi(p3); + rewrite.m_statusTG = ::atoi(p4); + rewrite.m_toTG = ::atoi(p5); + rewrite.m_range = ::atoi(p6); m_dmrNetwork3TGDynRewrites.push_back(rewrite); } } else if (::strncmp(key, "IdRewrite", 9U) == 0) { @@ -740,14 +746,16 @@ bool CConf::read() char* p2 = ::strtok(NULL, ", "); char* p3 = ::strtok(NULL, ", "); char* p4 = ::strtok(NULL, ", "); - char* p5 = ::strtok(NULL, " \r\n"); - if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL) { + char* p5 = ::strtok(NULL, ", "); + char* p6 = ::strtok(NULL, " \r\n"); + if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL && p6 != NULL) { CTGDynRewriteStruct rewrite; - rewrite.m_slot = ::atoi(p1); - rewrite.m_fromTG = ::atoi(p2); - rewrite.m_discTG = ::atoi(p3); - rewrite.m_toTG = ::atoi(p4); - rewrite.m_range = ::atoi(p5); + rewrite.m_slot = ::atoi(p1); + rewrite.m_fromTG = ::atoi(p2); + rewrite.m_discTG = ::atoi(p3); + rewrite.m_statusTG = ::atoi(p4); + rewrite.m_toTG = ::atoi(p5); + rewrite.m_range = ::atoi(p6); m_dmrNetwork4TGDynRewrites.push_back(rewrite); } } else if (::strncmp(key, "IdRewrite", 9U) == 0) { @@ -850,14 +858,16 @@ bool CConf::read() char* p2 = ::strtok(NULL, ", "); char* p3 = ::strtok(NULL, ", "); char* p4 = ::strtok(NULL, ", "); - char* p5 = ::strtok(NULL, " \r\n"); - if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL) { + char* p5 = ::strtok(NULL, ", "); + char* p6 = ::strtok(NULL, " \r\n"); + if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL && p6 != NULL) { CTGDynRewriteStruct rewrite; - rewrite.m_slot = ::atoi(p1); - rewrite.m_fromTG = ::atoi(p2); - rewrite.m_discTG = ::atoi(p3); - rewrite.m_toTG = ::atoi(p4); - rewrite.m_range = ::atoi(p5); + rewrite.m_slot = ::atoi(p1); + rewrite.m_fromTG = ::atoi(p2); + rewrite.m_discTG = ::atoi(p3); + rewrite.m_statusTG = ::atoi(p4); + rewrite.m_toTG = ::atoi(p5); + rewrite.m_range = ::atoi(p6); m_dmrNetwork5TGDynRewrites.push_back(rewrite); } } else if (::strncmp(key, "IdRewrite", 9U) == 0) { diff --git a/Conf.h b/Conf.h index 1bbea8d..b73eb83 100644 --- a/Conf.h +++ b/Conf.h @@ -57,6 +57,7 @@ struct CTGDynRewriteStruct { unsigned int m_slot; unsigned int m_fromTG; unsigned int m_discTG; + unsigned int m_statusTG; unsigned int m_toTG; unsigned int m_range; }; diff --git a/DMRGateway.cpp b/DMRGateway.cpp index 073f026..30ad189 100644 --- a/DMRGateway.cpp +++ b/DMRGateway.cpp @@ -370,48 +370,17 @@ int CDMRGateway::run() bool ruleTrace = m_conf.getRuleTrace(); LogInfo("Rule trace: %s", ruleTrace ? "yes" : "no"); - if (m_conf.getDMRNetwork1Enabled()) { - ret = createDMRNetwork1(); - if (!ret) - return 1; - } - - if (m_conf.getDMRNetwork2Enabled()) { - ret = createDMRNetwork2(); - if (!ret) - return 1; - } - - if (m_conf.getDMRNetwork3Enabled()) { - ret = createDMRNetwork3(); - if (!ret) - return 1; - } - - if (m_conf.getDMRNetwork4Enabled()) { - ret = createDMRNetwork4(); - if (!ret) - return 1; - } - - if (m_conf.getDMRNetwork5Enabled()) { - ret = createDMRNetwork5(); - if (!ret) - return 1; - } - if (m_conf.getXLXNetworkEnabled()) { ret = createXLXNetwork(); if (!ret) return 1; } - unsigned int rfTimeout = m_conf.getRFTimeout(); - unsigned int netTimeout = m_conf.getNetTimeout(); + CXLXVoice* xlxVoice = NULL; + CDynVoice* dynVoice = NULL; - CXLXVoice* voice = NULL; - if (m_conf.getVoiceEnabled() && m_xlxNetwork != NULL) { - std::string language = m_conf.getVoiceLanguage(); + if (m_conf.getVoiceEnabled()) { + std::string language = m_conf.getVoiceLanguage(); std::string directory = m_conf.getVoiceDirectory(); LogInfo("Voice Parameters"); @@ -419,14 +388,56 @@ int CDMRGateway::run() LogInfo(" Language: %s", language.c_str()); LogInfo(" Directory: %s", directory.c_str()); - voice = new CXLXVoice(directory, language, m_repeater->getId(), m_xlxSlot, m_xlxTG); - bool ret = voice->open(); + if (m_xlxNetwork != NULL) { + xlxVoice = new CXLXVoice(directory, language, m_repeater->getId(), m_xlxSlot, m_xlxTG); + bool ret = xlxVoice->open(); + if (!ret) { + delete xlxVoice; + xlxVoice = NULL; + } + } + + dynVoice = new CDynVoice(directory, language, m_repeater->getId()); + bool ret = dynVoice->open(); if (!ret) { - delete voice; - voice = NULL; + delete dynVoice; + dynVoice = NULL; } } + if (m_conf.getDMRNetwork1Enabled()) { + ret = createDMRNetwork1(dynVoice); + if (!ret) + return 1; + } + + if (m_conf.getDMRNetwork2Enabled()) { + ret = createDMRNetwork2(dynVoice); + if (!ret) + return 1; + } + + if (m_conf.getDMRNetwork3Enabled()) { + ret = createDMRNetwork3(dynVoice); + if (!ret) + return 1; + } + + if (m_conf.getDMRNetwork4Enabled()) { + ret = createDMRNetwork4(dynVoice); + if (!ret) + return 1; + } + + if (m_conf.getDMRNetwork5Enabled()) { + ret = createDMRNetwork5(dynVoice); + if (!ret) + return 1; + } + + unsigned int rfTimeout = m_conf.getRFTimeout(); + unsigned int netTimeout = m_conf.getNetTimeout(); + CTimer* timer[3U]; timer[1U] = new CTimer(1000U); timer[2U] = new CTimer(1000U); @@ -468,18 +479,18 @@ int CDMRGateway::run() writeXLXLink(m_xlxId, m_xlxReflector, m_xlxNetwork); char c = ('A' + (m_xlxReflector % 100U)) - 1U; LogMessage("XLX, Linking to reflector XLX%03u %c", m_xlxNumber, c); - if (voice != NULL) - voice->linkedTo(m_xlxNumber, m_xlxReflector); + if (xlxVoice != NULL) + xlxVoice->linkedTo(m_xlxNumber, m_xlxReflector); } else if (m_xlxRoom >= 4001U && m_xlxRoom <= 4026U) { writeXLXLink(m_xlxId, m_xlxRoom, m_xlxNetwork); char c = ('A' + (m_xlxRoom % 100U)) - 1U; LogMessage("XLX, Linking to reflector XLX%03u %c", m_xlxNumber, c); - if (voice != NULL) - voice->linkedTo(m_xlxNumber, m_xlxRoom); + if (xlxVoice != NULL) + xlxVoice->linkedTo(m_xlxNumber, m_xlxRoom); m_xlxReflector = m_xlxRoom; } else { - if (voice != NULL) - voice->linkedTo(m_xlxNumber, 0U); + if (xlxVoice != NULL) + xlxVoice->linkedTo(m_xlxNumber, 0U); } m_xlxConnected = true; @@ -491,8 +502,8 @@ int CDMRGateway::run() } else if (!connected && m_xlxConnected) { LogMessage("XLX, Unlinking from XLX%03u due to loss of connection", m_xlxNumber); - if (voice != NULL) - voice->unlinked(); + if (xlxVoice != NULL) + xlxVoice->unlinked(); m_xlxConnected = false; m_xlxRelink.stop(); @@ -523,11 +534,11 @@ int CDMRGateway::run() } m_xlxReflector = m_xlxRoom; - if (voice != NULL) { + if (xlxVoice != NULL) { if (m_xlxReflector < 4001U || m_xlxReflector > 4026U) - voice->linkedTo(m_xlxNumber, 0U); + xlxVoice->linkedTo(m_xlxNumber, 0U); else - voice->linkedTo(m_xlxNumber, m_xlxReflector); + xlxVoice->linkedTo(m_xlxNumber, m_xlxReflector); } } } @@ -580,16 +591,16 @@ int CDMRGateway::run() timer[slotNo]->setTimeout(rfTimeout); timer[slotNo]->start(); - if (voice != NULL) { + if (xlxVoice != NULL) { unsigned char type = data.getDataType(); if (type == DT_TERMINATOR_WITH_LC) { if (m_xlxConnected) { if (m_xlxReflector != 4000U) - voice->linkedTo(m_xlxNumber, m_xlxReflector); + xlxVoice->linkedTo(m_xlxNumber, m_xlxReflector); else - voice->linkedTo(m_xlxNumber, 0U); + xlxVoice->linkedTo(m_xlxNumber, 0U); } else { - voice->unlinked(); + xlxVoice->unlinked(); } } } @@ -1111,8 +1122,8 @@ int CDMRGateway::run() processHomePosition(); - if (voice != NULL) { - ret = voice->read(data); + if (xlxVoice != NULL) { + ret = xlxVoice->read(data); if (ret) { m_repeater->write(data); m_status[m_xlxSlot] = DMRGWS_XLXREFLECTOR; @@ -1121,6 +1132,12 @@ int CDMRGateway::run() } } + if (dynVoice != NULL) { + ret = dynVoice->read(data); + if (ret) + m_repeater->write(data); + } + unsigned int ms = stopWatch.elapsed(); stopWatch.start(); @@ -1149,8 +1166,11 @@ int CDMRGateway::run() if (m_xlxReflectors != NULL) m_xlxReflectors->clock(ms); - if (voice != NULL) - voice->clock(ms); + if (xlxVoice != NULL) + xlxVoice->clock(ms); + + if (dynVoice != NULL) + dynVoice->clock(ms); for (unsigned int i = 1U; i < 3U; i++) { timer[i]->clock(ms); @@ -1164,7 +1184,8 @@ int CDMRGateway::run() CThread::sleep(10U); } - delete voice; + delete xlxVoice; + delete dynVoice; m_repeater->close(); delete m_repeater; @@ -1233,7 +1254,7 @@ bool CDMRGateway::createMMDVM() return true; } -bool CDMRGateway::createDMRNetwork1() +bool CDMRGateway::createDMRNetwork1(CDynVoice* voice) { std::string address = m_conf.getDMRNetwork1Address(); unsigned int port = m_conf.getDMRNetwork1Port(); @@ -1337,10 +1358,10 @@ bool CDMRGateway::createDMRNetwork1() std::vector dynRewrites = m_conf.getDMRNetwork1TGDynRewrites(); for (std::vector::const_iterator it = dynRewrites.begin(); it != dynRewrites.end(); ++it) { - LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG); + LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u) (status %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG, (*it).m_slot, (*it).m_statusTG); CRewriteDynTGNet* netRewriteDynTG = new CRewriteDynTGNet(m_dmr1Name, (*it).m_slot, (*it).m_toTG); - CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr1Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_range, netRewriteDynTG); + CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr1Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_statusTG, (*it).m_range, netRewriteDynTG, voice); m_dmr1RFRewrites.push_back(rfRewriteDynTG); m_dmr1NetRewrites.push_back(netRewriteDynTG); @@ -1382,7 +1403,7 @@ bool CDMRGateway::createDMRNetwork1() return true; } -bool CDMRGateway::createDMRNetwork2() +bool CDMRGateway::createDMRNetwork2(CDynVoice* voice) { std::string address = m_conf.getDMRNetwork2Address(); unsigned int port = m_conf.getDMRNetwork2Port(); @@ -1486,10 +1507,10 @@ bool CDMRGateway::createDMRNetwork2() std::vector dynRewrites = m_conf.getDMRNetwork2TGDynRewrites(); for (std::vector::const_iterator it = dynRewrites.begin(); it != dynRewrites.end(); ++it) { - LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG); + LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u) (status %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG, (*it).m_slot, (*it).m_statusTG); CRewriteDynTGNet* netRewriteDynTG = new CRewriteDynTGNet(m_dmr2Name, (*it).m_slot, (*it).m_toTG); - CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr2Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_range, netRewriteDynTG); + CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr2Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_statusTG, (*it).m_range, netRewriteDynTG, voice); m_dmr2RFRewrites.push_back(rfRewriteDynTG); m_dmr2NetRewrites.push_back(netRewriteDynTG); @@ -1531,7 +1552,7 @@ bool CDMRGateway::createDMRNetwork2() return true; } -bool CDMRGateway::createDMRNetwork3() +bool CDMRGateway::createDMRNetwork3(CDynVoice* voice) { std::string address = m_conf.getDMRNetwork3Address(); unsigned int port = m_conf.getDMRNetwork3Port(); @@ -1635,10 +1656,10 @@ bool CDMRGateway::createDMRNetwork3() std::vector dynRewrites = m_conf.getDMRNetwork3TGDynRewrites(); for (std::vector::const_iterator it = dynRewrites.begin(); it != dynRewrites.end(); ++it) { - LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG); + LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u) (status %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG, (*it).m_slot, (*it).m_statusTG); CRewriteDynTGNet* netRewriteDynTG = new CRewriteDynTGNet(m_dmr3Name, (*it).m_slot, (*it).m_toTG); - CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr3Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_range, netRewriteDynTG); + CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr3Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_statusTG, (*it).m_range, netRewriteDynTG, voice); m_dmr3RFRewrites.push_back(rfRewriteDynTG); m_dmr3NetRewrites.push_back(netRewriteDynTG); @@ -1680,7 +1701,7 @@ bool CDMRGateway::createDMRNetwork3() return true; } -bool CDMRGateway::createDMRNetwork4() +bool CDMRGateway::createDMRNetwork4(CDynVoice* voice) { std::string address = m_conf.getDMRNetwork4Address(); unsigned int port = m_conf.getDMRNetwork4Port(); @@ -1784,10 +1805,10 @@ bool CDMRGateway::createDMRNetwork4() std::vector dynRewrites = m_conf.getDMRNetwork4TGDynRewrites(); for (std::vector::const_iterator it = dynRewrites.begin(); it != dynRewrites.end(); ++it) { - LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG); + LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u) (status %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG, (*it).m_slot, (*it).m_statusTG); CRewriteDynTGNet* netRewriteDynTG = new CRewriteDynTGNet(m_dmr4Name, (*it).m_slot, (*it).m_toTG); - CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr4Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_range, netRewriteDynTG); + CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr4Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_statusTG, (*it).m_range, netRewriteDynTG, voice); m_dmr4RFRewrites.push_back(rfRewriteDynTG); m_dmr4NetRewrites.push_back(netRewriteDynTG); @@ -1829,7 +1850,7 @@ bool CDMRGateway::createDMRNetwork4() return true; } -bool CDMRGateway::createDMRNetwork5() +bool CDMRGateway::createDMRNetwork5(CDynVoice* voice) { std::string address = m_conf.getDMRNetwork5Address(); unsigned int port = m_conf.getDMRNetwork5Port(); @@ -1933,10 +1954,10 @@ bool CDMRGateway::createDMRNetwork5() std::vector dynRewrites = m_conf.getDMRNetwork5TGDynRewrites(); for (std::vector::const_iterator it = dynRewrites.begin(); it != dynRewrites.end(); ++it) { - LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG); + LogInfo(" Dyn Rewrite: %u:TG%u-%u:TG%u <-> %u:TG%u (disc %u:TG%u) (status %u:TG%u)", (*it).m_slot, (*it).m_fromTG, (*it).m_slot, (*it).m_fromTG + (*it).m_range - 1U, (*it).m_slot, (*it).m_toTG, (*it).m_slot, (*it).m_discTG, (*it).m_slot, (*it).m_statusTG); CRewriteDynTGNet* netRewriteDynTG = new CRewriteDynTGNet(m_dmr5Name, (*it).m_slot, (*it).m_toTG); - CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr5Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_range, netRewriteDynTG); + CRewriteDynTGRF* rfRewriteDynTG = new CRewriteDynTGRF(m_dmr5Name, (*it).m_slot, (*it).m_fromTG, (*it).m_toTG, (*it).m_discTG, (*it).m_statusTG, (*it).m_range, netRewriteDynTG, voice); m_dmr5RFRewrites.push_back(rfRewriteDynTG); m_dmr5NetRewrites.push_back(netRewriteDynTG); diff --git a/DMRGateway.h b/DMRGateway.h index becc3a7..f8debbd 100644 --- a/DMRGateway.h +++ b/DMRGateway.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2019,2020 by 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 @@ -24,6 +24,7 @@ #include "DMRNetwork.h" #include "Reflectors.h" #include "RewriteTG.h" +#include "DynVoice.h" #include "Rewrite.h" #include "Timer.h" #include "Conf.h" @@ -106,11 +107,11 @@ private: std::vector m_dmr5Passalls; bool createMMDVM(); - bool createDMRNetwork1(); - bool createDMRNetwork2(); - bool createDMRNetwork3(); - bool createDMRNetwork4(); - bool createDMRNetwork5(); + bool createDMRNetwork1(CDynVoice* voice); + bool createDMRNetwork2(CDynVoice* voice); + bool createDMRNetwork3(CDynVoice* voice); + bool createDMRNetwork4(CDynVoice* voice); + bool createDMRNetwork5(CDynVoice* voice); bool createXLXNetwork(); bool linkXLX(unsigned int number); diff --git a/DMRGateway.ini b/DMRGateway.ini index b888949..6789f4e 100644 --- a/DMRGateway.ini +++ b/DMRGateway.ini @@ -54,7 +54,7 @@ UserControl=1 # BrandMeister [DMR Network 1] -Enabled=1 +Enabled=0 Name=BM Address=44.131.4.1 Port=62031 @@ -71,7 +71,7 @@ SrcRewrite=1,9990,1,9990,1 # Reflector status returns SrcRewrite=2,4000,2,9,1001 # Dynamic rewriting of slot 2 TGs 23500-23599 to TG9 to emulate reflector behaviour -TGDynRewrite=2,23500,4000,9,100 +TGDynRewrite=2,23500,4000,5000,9,100 # Pass all of the other private traffic on slot 1 and slot 2 PassAllPC=1 PassAllPC=2 diff --git a/DMRGateway.vcxproj b/DMRGateway.vcxproj index 3485b79..fb7a833 100644 --- a/DMRGateway.vcxproj +++ b/DMRGateway.vcxproj @@ -166,6 +166,7 @@ + @@ -210,6 +211,7 @@ + diff --git a/DMRGateway.vcxproj.filters b/DMRGateway.vcxproj.filters index 91c4c0a..63ad046 100644 --- a/DMRGateway.vcxproj.filters +++ b/DMRGateway.vcxproj.filters @@ -140,6 +140,9 @@ Header Files + + Header Files + @@ -262,5 +265,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/DynVoice.cpp b/DynVoice.cpp new file mode 100644 index 0000000..bb32dc0 --- /dev/null +++ b/DynVoice.cpp @@ -0,0 +1,345 @@ +/* +* Copyright (C) 2017,2020 by 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; either version 2 of the License, or +* (at your option) any later version. +* +* 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. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "DMRSlotType.h" +#include "DMRFullLC.h" +#include "DynVoice.h" +#include "DMREMB.h" +#include "Sync.h" +#include "Log.h" + +#include +#include + +#include + +const unsigned char SILENCE[] = {0xACU, 0xAAU, 0x40U, 0x20U, 0x00U, 0x44U, 0x40U, 0x80U, 0x80U}; + +const unsigned char COLOR_CODE = 3U; + +const unsigned int SILENCE_LENGTH = 9U; +const unsigned int AMBE_LENGTH = 9U; + +CDynVoice::CDynVoice(const std::string& directory, const std::string& language, unsigned int id) : +m_indxFile(), +m_ambeFile(), +m_id(id), +m_slot(0U), +m_lc(), +m_embeddedLC(), +m_status(DYNVS_NONE), +m_timer(1000U, 1U), +m_stopWatch(), +m_seqNo(0U), +m_streamId(0U), +m_sent(0U), +m_ambe(NULL), +m_positions(), +m_data(), +m_it() +{ +#if defined(_WIN32) || defined(_WIN64) + m_indxFile = directory + "\\" + language + ".indx"; + m_ambeFile = directory + "\\" + language + ".ambe"; +#else + m_indxFile = directory + "/" + language + ".indx"; + m_ambeFile = directory + "/" + language + ".ambe"; +#endif +} + +CDynVoice::~CDynVoice() +{ + for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) + delete *it; + + for (std::unordered_map::iterator it = m_positions.begin(); it != m_positions.end(); ++it) + delete it->second; + + m_data.clear(); + m_positions.clear(); + + delete[] m_ambe; +} + +void CDynVoice::setSlotAndTG(unsigned int slot, unsigned int tg) +{ + m_slot = slot; + + m_lc.setFLCO(FLCO_GROUP); + m_lc.setSrcId(m_id); + m_lc.setDstId(tg); + + m_embeddedLC.setLC(m_lc); +} + +bool CDynVoice::open() +{ + FILE* fpindx = ::fopen(m_indxFile.c_str(), "rt"); + if (fpindx == NULL) { + LogError("Unable to open the index file - %s", m_indxFile.c_str()); + return false; + } + + struct stat statStruct; + int ret = ::stat(m_ambeFile.c_str(), &statStruct); + if (ret != 0) { + LogError("Unable to stat the AMBE file - %s", m_ambeFile.c_str()); + ::fclose(fpindx); + return false; + } + + FILE* fpambe = ::fopen(m_ambeFile.c_str(), "rb"); + if (fpambe == NULL) { + LogError("Unable to open the AMBE file - %s", m_ambeFile.c_str()); + ::fclose(fpindx); + return false; + } + + m_ambe = new unsigned char[statStruct.st_size]; + + size_t sizeRead = ::fread(m_ambe, 1U, statStruct.st_size, fpambe); + if (sizeRead != 0U) { + char buffer[80U]; + while (::fgets(buffer, 80, fpindx) != NULL) { + char* p1 = ::strtok(buffer, "\t\r\n"); + char* p2 = ::strtok(NULL, "\t\r\n"); + char* p3 = ::strtok(NULL, "\t\r\n"); + + if (p1 != NULL && p2 != NULL && p3 != NULL) { + std::string symbol = std::string(p1); + unsigned int start = ::atoi(p2) * AMBE_LENGTH; + unsigned int length = ::atoi(p3) * AMBE_LENGTH; + + CDynPositions* pos = new CDynPositions; + pos->m_start = start; + pos->m_length = length; + + m_positions[symbol] = pos; + } + } + } + + ::fclose(fpindx); + ::fclose(fpambe); + + return true; +} + +void CDynVoice::linkedTo(unsigned int number) +{ + char letters[10U]; + ::sprintf(letters, "%u", number); + + std::vector words; + if (m_positions.count("linkedto") == 0U) { + words.push_back("linked"); + words.push_back("2"); + } else { + words.push_back("linkedto"); + } + + for (unsigned int i = 0U; letters[i] != '\0'; i++) + words.push_back(std::string(1U, letters[i])); + + createVoice(words); +} + +void CDynVoice::unlinked() +{ + std::vector words; + words.push_back("notlinked"); + + createVoice(words); +} + +void CDynVoice::createVoice(const std::vector& words) +{ + unsigned int ambeLength = 0U; + for (std::vector::const_iterator it = words.begin(); it != words.end(); ++it) { + if (m_positions.count(*it) > 0U) { + CDynPositions* position = m_positions.at(*it); + ambeLength += position->m_length; + } else { + LogWarning("Unable to find character/phrase \"%s\" in the index", (*it).c_str()); + } + } + + // Ensure that the AMBE is an integer number of DMR frames + if ((ambeLength % (3U * AMBE_LENGTH)) != 0U) { + unsigned int frames = ambeLength / (3U * AMBE_LENGTH); + frames++; + ambeLength = frames * (3U * AMBE_LENGTH); + } + + // Add space for silence before and after the voice + ambeLength += SILENCE_LENGTH * AMBE_LENGTH; + ambeLength += SILENCE_LENGTH * AMBE_LENGTH; + + unsigned char* ambeData = new unsigned char[ambeLength]; + + // Fill the AMBE data with silence + for (unsigned int i = 0U; i < ambeLength; i += AMBE_LENGTH) + ::memcpy(ambeData + i, SILENCE, AMBE_LENGTH); + + // Put offset in for silence at the beginning + unsigned int pos = SILENCE_LENGTH * AMBE_LENGTH; + for (std::vector::const_iterator it = words.begin(); it != words.end(); ++it) { + if (m_positions.count(*it) > 0U) { + CDynPositions* position = m_positions.at(*it); + unsigned int start = position->m_start; + unsigned int length = position->m_length; + ::memcpy(ambeData + pos, m_ambe + start, length); + pos += length; + } + } + + for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) + delete *it; + + m_data.clear(); + + m_streamId = ::rand() + 1U; + m_seqNo = 0U; + + createHeaderTerminator(DT_VOICE_LC_HEADER); + createHeaderTerminator(DT_VOICE_LC_HEADER); + createHeaderTerminator(DT_VOICE_LC_HEADER); + + unsigned char buffer[DMR_FRAME_LENGTH_BYTES]; + + unsigned int n = 0U; + for (unsigned int i = 0U; i < ambeLength; i += (3U * AMBE_LENGTH)) { + unsigned char* p = ambeData + i; + + CDMRData* data = new CDMRData; + + data->setSlotNo(m_slot); + data->setFLCO(FLCO_GROUP); + data->setSrcId(m_lc.getSrcId()); + data->setDstId(m_lc.getDstId()); + data->setN(n); + data->setSeqNo(m_seqNo++); + data->setStreamId(m_streamId); + + ::memcpy(buffer + 0U, p + 0U, AMBE_LENGTH); + ::memcpy(buffer + 9U, p + 9U, AMBE_LENGTH); + ::memcpy(buffer + 15U, p + 9U, AMBE_LENGTH); + ::memcpy(buffer + 24U, p + 18U, AMBE_LENGTH); + + if (n == 0U) { + CSync::addDMRAudioSync(buffer, true); + data->setDataType(DT_VOICE_SYNC); + } else { + unsigned char lcss = m_embeddedLC.getData(buffer, n); + + CDMREMB emb; + emb.setColorCode(COLOR_CODE); + emb.setPI(false); + emb.setLCSS(lcss); + emb.getData(buffer); + + data->setDataType(DT_VOICE); + } + + n++; + if (n >= 6U) + n = 0U; + + data->setData(buffer); + + m_data.push_back(data); + } + + createHeaderTerminator(DT_TERMINATOR_WITH_LC); + createHeaderTerminator(DT_TERMINATOR_WITH_LC); + + delete[] ambeData; + + m_status = DYNVS_WAITING; + m_timer.start(); +} + +bool CDynVoice::read(CDMRData& data) +{ + if (m_status != DYNVS_SENDING) + return false; + + unsigned int count = m_stopWatch.elapsed() / DMR_SLOT_TIME; + + if (m_sent < count) { + data = *(*m_it); + + ++m_sent; + ++m_it; + + if (m_it == m_data.end()) { + for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) + delete *it; + m_data.clear(); + m_timer.stop(); + m_status = DYNVS_NONE; + } + + return true; + } + + return false; +} + +void CDynVoice::clock(unsigned int ms) +{ + m_timer.clock(ms); + if (m_timer.isRunning() && m_timer.hasExpired()) { + if (m_status == DYNVS_WAITING) { + m_stopWatch.start(); + m_status = DYNVS_SENDING; + m_it = m_data.begin(); + m_sent = 0U; + } + } +} + +void CDynVoice::createHeaderTerminator(unsigned char type) +{ + CDMRData* data = new CDMRData; + + data->setSlotNo(m_slot); + data->setFLCO(FLCO_GROUP); + data->setSrcId(m_lc.getSrcId()); + data->setDstId(m_lc.getDstId()); + data->setDataType(type); + data->setN(0U); + data->setSeqNo(m_seqNo++); + data->setStreamId(m_streamId); + + unsigned char buffer[DMR_FRAME_LENGTH_BYTES]; + + CDMRFullLC fullLC; + fullLC.encode(m_lc, buffer, type); + + CDMRSlotType slotType; + slotType.setColorCode(COLOR_CODE); + slotType.setDataType(type); + slotType.getData(buffer); + + CSync::addDMRDataSync(buffer, true); + + data->setData(buffer); + + m_data.push_back(data); +} diff --git a/DynVoice.h b/DynVoice.h new file mode 100644 index 0000000..755145e --- /dev/null +++ b/DynVoice.h @@ -0,0 +1,81 @@ +/* +* Copyright (C) 2017,2020 by 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; either version 2 of the License, or +* (at your option) any later version. +* +* 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. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#if !defined(DynVoice_H) +#define DynVoice_H + +#include "DMREmbeddedData.h" +#include "StopWatch.h" +#include "DMRData.h" +#include "DMRLC.h" +#include "Timer.h" + +#include +#include +#include + +enum DYNVOICE_STATUS { + DYNVS_NONE, + DYNVS_WAITING, + DYNVS_SENDING +}; + +struct CDynPositions { + unsigned int m_start; + unsigned int m_length; +}; + +class CDynVoice { +public: + CDynVoice(const std::string& directory, const std::string& language, unsigned int id); + ~CDynVoice(); + + void setSlotAndTG(unsigned int slot, unsigned int tg); + + bool open(); + + void linkedTo(unsigned int number); + void unlinked(); + + bool read(CDMRData& data); + + void clock(unsigned int ms); + +private: + std::string m_indxFile; + std::string m_ambeFile; + unsigned int m_id; + unsigned int m_slot; + CDMRLC m_lc; + CDMREmbeddedData m_embeddedLC; + DYNVOICE_STATUS m_status; + CTimer m_timer; + CStopWatch m_stopWatch; + unsigned int m_seqNo; + unsigned int m_streamId; + unsigned int m_sent; + unsigned char* m_ambe; + std::unordered_map m_positions; + std::vector m_data; + std::vector::const_iterator m_it; + + void createHeaderTerminator(unsigned char type); + void createVoice(const std::vector& words); +}; + +#endif diff --git a/Makefile b/Makefile index 4fc7e45..22656d1 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,9 @@ LIBS = -lpthread LDFLAGS = -g OBJECTS = BPTC19696.o Conf.o CRC.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREmbeddedData.o DMREMB.o DMRFullLC.o DMRGateway.o DMRLC.o DMRNetwork.o DMRSlotType.o \ - Golay2087.o Hamming.o Log.o MMDVMNetwork.o PassAllPC.o PassAllTG.o QR1676.o Reflectors.o RepeaterProtocol.o Rewrite.o RewriteDstId.o RewriteDynTGNet.o \ - RewriteDynTGRF.o RewritePC.o RewriteSrc.o RewriteSrcId.o RewriteTG.o RewriteType.o RS129.o SHA256.o StopWatch.o Sync.o Thread.o Timer.o UDPSocket.o \ - Utils.o XLXVoice.o + DynVoice.o Golay2087.o Hamming.o Log.o MMDVMNetwork.o PassAllPC.o PassAllTG.o QR1676.o Reflectors.o RepeaterProtocol.o Rewrite.o RewriteDstId.o \ + RewriteDynTGNet.o RewriteDynTGRF.o RewritePC.o RewriteSrc.o RewriteSrcId.o RewriteTG.o RewriteType.o RS129.o SHA256.o StopWatch.o Sync.o Thread.o \ + Timer.o UDPSocket.o Utils.o XLXVoice.o all: DMRGateway diff --git a/RewriteDynTGNet.cpp b/RewriteDynTGNet.cpp index 8854e34..fde2ffc 100644 --- a/RewriteDynTGNet.cpp +++ b/RewriteDynTGNet.cpp @@ -40,8 +40,8 @@ CRewriteDynTGNet::~CRewriteDynTGNet() PROCESS_RESULT CRewriteDynTGNet::process(CDMRData& data, bool trace) { - FLCO flco = data.getFLCO(); - unsigned int dstId = data.getDstId(); + FLCO flco = data.getFLCO(); + unsigned int dstId = data.getDstId(); unsigned int slotNo = data.getSlotNo(); if (flco != FLCO_GROUP || slotNo != m_slot || dstId != m_currentTG) { diff --git a/RewriteDynTGRF.cpp b/RewriteDynTGRF.cpp index c0abf4b..dfd7bb5 100644 --- a/RewriteDynTGRF.cpp +++ b/RewriteDynTGRF.cpp @@ -24,7 +24,7 @@ #include #include -CRewriteDynTGRF::CRewriteDynTGRF(const std::string& name, unsigned int slot, unsigned int fromTG, unsigned int toTG, unsigned int discTG, unsigned int range, CRewriteDynTGNet* rewriteNet) : +CRewriteDynTGRF::CRewriteDynTGRF(const std::string& name, unsigned int slot, unsigned int fromTG, unsigned int toTG, unsigned int discTG, unsigned int statusTG, unsigned int range, CRewriteDynTGNet* rewriteNet, CDynVoice* voice) : CRewrite(), m_name(name), m_slot(slot), @@ -32,11 +32,16 @@ m_fromTGStart(fromTG), m_fromTGEnd(fromTG + range - 1U), m_toTG(toTG), m_discTG(discTG), +m_statusTG(statusTG), m_rewriteNet(rewriteNet), +m_voice(voice), m_currentTG(0U) { assert(slot == 1U || slot == 2U); assert(rewriteNet != NULL); + + if (voice != NULL) + voice->setSlotAndTG(slot, toTG); } CRewriteDynTGRF::~CRewriteDynTGRF() @@ -45,9 +50,10 @@ CRewriteDynTGRF::~CRewriteDynTGRF() PROCESS_RESULT CRewriteDynTGRF::process(CDMRData& data, bool trace) { - FLCO flco = data.getFLCO(); - unsigned int dstId = data.getDstId(); + FLCO flco = data.getFLCO(); + unsigned int dstId = data.getDstId(); unsigned int slotNo = data.getSlotNo(); + unsigned char type = data.getDataType(); if (flco == FLCO_GROUP && slotNo == m_slot && dstId == m_toTG && m_currentTG != 0U) { data.setDstId(m_currentTG); @@ -64,13 +70,17 @@ PROCESS_RESULT CRewriteDynTGRF::process(CDMRData& data, bool trace) if (trace) LogDebug("Rule Trace,\tRewriteDynTGRF from %s Slot=%u Dst=TG%u: matched", m_name.c_str(), m_slot, m_discTG); - m_rewriteNet->setCurrentTG(0U); - m_currentTG = 0U; + if (type == DT_TERMINATOR_WITH_LC) { + m_rewriteNet->setCurrentTG(0U); + m_currentTG = 0U; + if (m_voice != NULL) + m_voice->unlinked(); + } return RESULT_MATCHED; } - if (flco == FLCO_GROUP && slotNo == m_slot && dstId >= m_fromTGStart && dstId <= m_fromTGEnd) { + if (slotNo == m_slot && dstId >= m_fromTGStart && dstId <= m_fromTGEnd) { if (trace) { if (m_fromTGStart == m_fromTGEnd) LogDebug("Rule Trace,\tRewriteDynTGRF from %s Slot=%u Dst=TG%u: matched", m_name.c_str(), m_slot, m_fromTGStart); @@ -78,17 +88,37 @@ PROCESS_RESULT CRewriteDynTGRF::process(CDMRData& data, bool trace) LogDebug("Rule Trace,\tRewriteDynTGRF from %s Slot=%u Dst=TG%u-TG%u: matched", m_name.c_str(), m_slot, m_fromTGStart, m_fromTGEnd); } - m_rewriteNet->setCurrentTG(dstId); - m_currentTG = dstId; + data.setFLCO(FLCO_GROUP); + + if (type == DT_TERMINATOR_WITH_LC) { + m_rewriteNet->setCurrentTG(dstId); + m_currentTG = dstId; + if (m_voice != NULL) + m_voice->linkedTo(dstId); + } return RESULT_MATCHED; } + if (flco == FLCO_GROUP && slotNo == m_slot && dstId == m_statusTG) { + if (trace) + LogDebug("Rule Trace,\tRewriteDynTGRF from %s Slot=%u Dst=TG%u: matched", m_name.c_str(), m_slot, m_statusTG); + + if (type == DT_TERMINATOR_WITH_LC && m_voice != NULL) { + if (m_currentTG == 0U) + m_voice->unlinked(); + else + m_voice->linkedTo(dstId); + } + + return RESULT_IGNORED; + } + if (trace) { if (m_fromTGStart == m_fromTGEnd) - LogDebug("Rule Trace,\tRewriteDynTGRF from %s Slot=%u Dst=TG%u or Dst=TG%u or Dst=TG%u: not matched", m_name.c_str(), m_slot, m_fromTGStart, m_toTG, m_discTG); + LogDebug("Rule Trace,\tRewriteDynTGRF from %s Slot=%u Dst=TG%u or Dst=TG%u or Dst=TG%u or Dst=TG%u: not matched", m_name.c_str(), m_slot, m_fromTGStart, m_toTG, m_discTG, m_statusTG); else - LogDebug("Rule Trace,\tRewriteDynTGRF from %s Slot=%u Dst=TG%u-TG%u or Dst=TG%u or Dst=TG%u: not matched", m_name.c_str(), m_slot, m_fromTGStart, m_fromTGEnd, m_toTG, m_discTG); + LogDebug("Rule Trace,\tRewriteDynTGRF from %s Slot=%u Dst=TG%u-TG%u or Dst=TG%u or Dst=TG%u or Dst=TG%u: not matched", m_name.c_str(), m_slot, m_fromTGStart, m_fromTGEnd, m_toTG, m_discTG, m_statusTG); } return RESULT_UNMATCHED; diff --git a/RewriteDynTGRF.h b/RewriteDynTGRF.h index 695970c..388b835 100644 --- a/RewriteDynTGRF.h +++ b/RewriteDynTGRF.h @@ -19,6 +19,7 @@ #if !defined(REWRITEDYNTGRF_H) #define REWRITEDYNTGRF_H +#include "DynVoice.h" #include "Rewrite.h" #include "DMRData.h" @@ -28,7 +29,7 @@ class CRewriteDynTGRF : public CRewrite { public: - CRewriteDynTGRF(const std::string& name, unsigned int slot, unsigned int fromTG, unsigned int toTG, unsigned int discTG, unsigned int range, CRewriteDynTGNet* rewriteNet); + CRewriteDynTGRF(const std::string& name, unsigned int slot, unsigned int fromTG, unsigned int toTG, unsigned int discTG, unsigned int statusTG, unsigned int range, CRewriteDynTGNet* rewriteNet, CDynVoice* voice); virtual ~CRewriteDynTGRF(); virtual PROCESS_RESULT process(CDMRData& data, bool trace); @@ -40,7 +41,9 @@ private: unsigned int m_fromTGEnd; unsigned int m_toTG; unsigned int m_discTG; + unsigned int m_statusTG; CRewriteDynTGNet* m_rewriteNet; + CDynVoice* m_voice; unsigned int m_currentTG; }; diff --git a/Version.h b/Version.h index 726b272..54b6d54 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200401"; +const char* VERSION = "20200403"; #endif diff --git a/XLXVoice.cpp b/XLXVoice.cpp index b0b6fe2..bcc3edb 100644 --- a/XLXVoice.cpp +++ b/XLXVoice.cpp @@ -41,7 +41,7 @@ m_ambeFile(), m_slot(slot), m_lc(FLCO_GROUP, id, tg), m_embeddedLC(), -m_status(VS_NONE), +m_status(XLXVS_NONE), m_timer(1000U, 1U), m_stopWatch(), m_seqNo(0U), @@ -68,7 +68,7 @@ CXLXVoice::~CXLXVoice() for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) delete *it; - for (std::unordered_map::iterator it = m_positions.begin(); it != m_positions.end(); ++it) + for (std::unordered_map::iterator it = m_positions.begin(); it != m_positions.end(); ++it) delete it->second; m_data.clear(); @@ -115,7 +115,7 @@ bool CXLXVoice::open() unsigned int start = ::atoi(p2) * AMBE_LENGTH; unsigned int length = ::atoi(p3) * AMBE_LENGTH; - CPositions* pos = new CPositions; + CXLXPositions* pos = new CXLXPositions; pos->m_start = start; pos->m_length = length; @@ -171,7 +171,7 @@ void CXLXVoice::createVoice(const std::vector& words) unsigned int ambeLength = 0U; for (std::vector::const_iterator it = words.begin(); it != words.end(); ++it) { if (m_positions.count(*it) > 0U) { - CPositions* position = m_positions.at(*it); + CXLXPositions* position = m_positions.at(*it); ambeLength += position->m_length; } else { LogWarning("Unable to find character/phrase \"%s\" in the index", (*it).c_str()); @@ -199,7 +199,7 @@ void CXLXVoice::createVoice(const std::vector& words) unsigned int pos = SILENCE_LENGTH * AMBE_LENGTH; for (std::vector::const_iterator it = words.begin(); it != words.end(); ++it) { if (m_positions.count(*it) > 0U) { - CPositions* position = m_positions.at(*it); + CXLXPositions* position = m_positions.at(*it); unsigned int start = position->m_start; unsigned int length = position->m_length; ::memcpy(ambeData + pos, m_ambe + start, length); @@ -269,13 +269,13 @@ void CXLXVoice::createVoice(const std::vector& words) delete[] ambeData; - m_status = VS_WAITING; + m_status = XLXVS_WAITING; m_timer.start(); } bool CXLXVoice::read(CDMRData& data) { - if (m_status != VS_SENDING) + if (m_status != XLXVS_SENDING) return false; unsigned int count = m_stopWatch.elapsed() / DMR_SLOT_TIME; @@ -291,7 +291,7 @@ bool CXLXVoice::read(CDMRData& data) delete *it; m_data.clear(); m_timer.stop(); - m_status = VS_NONE; + m_status = XLXVS_NONE; } return true; @@ -304,9 +304,9 @@ void CXLXVoice::clock(unsigned int ms) { m_timer.clock(ms); if (m_timer.isRunning() && m_timer.hasExpired()) { - if (m_status == VS_WAITING) { + if (m_status == XLXVS_WAITING) { m_stopWatch.start(); - m_status = VS_SENDING; + m_status = XLXVS_SENDING; m_it = m_data.begin(); m_sent = 0U; } diff --git a/XLXVoice.h b/XLXVoice.h index c3ec43b..186d3f6 100644 --- a/XLXVoice.h +++ b/XLXVoice.h @@ -29,13 +29,13 @@ #include #include -enum VOICE_STATUS { - VS_NONE, - VS_WAITING, - VS_SENDING +enum XLXVOICE_STATUS { + XLXVS_NONE, + XLXVS_WAITING, + XLXVS_SENDING }; -struct CPositions { +struct CXLXPositions { unsigned int m_start; unsigned int m_length; }; @@ -60,14 +60,14 @@ private: unsigned int m_slot; CDMRLC m_lc; CDMREmbeddedData m_embeddedLC; - VOICE_STATUS m_status; + XLXVOICE_STATUS m_status; CTimer m_timer; CStopWatch m_stopWatch; unsigned int m_seqNo; unsigned int m_streamId; unsigned int m_sent; unsigned char* m_ambe; - std::unordered_map m_positions; + std::unordered_map m_positions; std::vector m_data; std::vector::const_iterator m_it;