mirror of
https://github.com/g4klx/DMRGateway
synced 2025-12-22 06:05:36 +08:00
Add dynamic TG voice prompts and status TG.
This commit is contained in:
50
Conf.cpp
50
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_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_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_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_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_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) {
|
||||
|
||||
1
Conf.h
1
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;
|
||||
};
|
||||
|
||||
167
DMRGateway.cpp
167
DMRGateway.cpp
@@ -370,47 +370,16 @@ 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) {
|
||||
if (m_conf.getVoiceEnabled()) {
|
||||
std::string language = m_conf.getVoiceLanguage();
|
||||
std::string directory = m_conf.getVoiceDirectory();
|
||||
|
||||
@@ -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 voice;
|
||||
voice = NULL;
|
||||
delete xlxVoice;
|
||||
xlxVoice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dynVoice = new CDynVoice(directory, language, m_repeater->getId());
|
||||
bool ret = dynVoice->open();
|
||||
if (!ret) {
|
||||
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<CTGDynRewriteStruct> dynRewrites = m_conf.getDMRNetwork1TGDynRewrites();
|
||||
for (std::vector<CTGDynRewriteStruct>::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<CTGDynRewriteStruct> dynRewrites = m_conf.getDMRNetwork2TGDynRewrites();
|
||||
for (std::vector<CTGDynRewriteStruct>::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<CTGDynRewriteStruct> dynRewrites = m_conf.getDMRNetwork3TGDynRewrites();
|
||||
for (std::vector<CTGDynRewriteStruct>::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<CTGDynRewriteStruct> dynRewrites = m_conf.getDMRNetwork4TGDynRewrites();
|
||||
for (std::vector<CTGDynRewriteStruct>::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<CTGDynRewriteStruct> dynRewrites = m_conf.getDMRNetwork5TGDynRewrites();
|
||||
for (std::vector<CTGDynRewriteStruct>::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);
|
||||
|
||||
13
DMRGateway.h
13
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<CRewrite*> 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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -166,6 +166,7 @@
|
||||
<ClInclude Include="DMRLC.h" />
|
||||
<ClInclude Include="DMRNetwork.h" />
|
||||
<ClInclude Include="DMRSlotType.h" />
|
||||
<ClInclude Include="DynVoice.h" />
|
||||
<ClInclude Include="Golay2087.h" />
|
||||
<ClInclude Include="Hamming.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
@@ -210,6 +211,7 @@
|
||||
<ClCompile Include="DMRLC.cpp" />
|
||||
<ClCompile Include="DMRNetwork.cpp" />
|
||||
<ClCompile Include="DMRSlotType.cpp" />
|
||||
<ClCompile Include="DynVoice.cpp" />
|
||||
<ClCompile Include="Golay2087.cpp" />
|
||||
<ClCompile Include="Hamming.cpp" />
|
||||
<ClCompile Include="Log.cpp" />
|
||||
|
||||
@@ -140,6 +140,9 @@
|
||||
<ClInclude Include="XLXVoice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DynVoice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Conf.cpp">
|
||||
@@ -262,5 +265,8 @@
|
||||
<ClCompile Include="XLXVoice.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DynVoice.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
345
DynVoice.cpp
Normal file
345
DynVoice.cpp
Normal file
@@ -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 <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
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<CDMRData*>::iterator it = m_data.begin(); it != m_data.end(); ++it)
|
||||
delete *it;
|
||||
|
||||
for (std::unordered_map<std::string, CDynPositions*>::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<std::string> 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<std::string> words;
|
||||
words.push_back("notlinked");
|
||||
|
||||
createVoice(words);
|
||||
}
|
||||
|
||||
void CDynVoice::createVoice(const std::vector<std::string>& words)
|
||||
{
|
||||
unsigned int ambeLength = 0U;
|
||||
for (std::vector<std::string>::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<std::string>::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<CDMRData*>::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<CDMRData*>::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);
|
||||
}
|
||||
81
DynVoice.h
Normal file
81
DynVoice.h
Normal file
@@ -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 <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
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<std::string, CDynPositions*> m_positions;
|
||||
std::vector<CDMRData*> m_data;
|
||||
std::vector<CDMRData*>::const_iterator m_it;
|
||||
|
||||
void createHeaderTerminator(unsigned char type);
|
||||
void createVoice(const std::vector<std::string>& words);
|
||||
};
|
||||
|
||||
#endif
|
||||
6
Makefile
6
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
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
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()
|
||||
@@ -48,6 +53,7 @@ PROCESS_RESULT CRewriteDynTGRF::process(CDMRData& data, bool trace)
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
#if !defined(VERSION_H)
|
||||
#define VERSION_H
|
||||
|
||||
const char* VERSION = "20200401";
|
||||
const char* VERSION = "20200403";
|
||||
|
||||
#endif
|
||||
|
||||
20
XLXVoice.cpp
20
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<CDMRData*>::iterator it = m_data.begin(); it != m_data.end(); ++it)
|
||||
delete *it;
|
||||
|
||||
for (std::unordered_map<std::string, CPositions*>::iterator it = m_positions.begin(); it != m_positions.end(); ++it)
|
||||
for (std::unordered_map<std::string, CXLXPositions*>::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<std::string>& words)
|
||||
unsigned int ambeLength = 0U;
|
||||
for (std::vector<std::string>::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<std::string>& words)
|
||||
unsigned int pos = SILENCE_LENGTH * AMBE_LENGTH;
|
||||
for (std::vector<std::string>::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<std::string>& 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;
|
||||
}
|
||||
|
||||
14
XLXVoice.h
14
XLXVoice.h
@@ -29,13 +29,13 @@
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
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<std::string, CPositions*> m_positions;
|
||||
std::unordered_map<std::string, CXLXPositions*> m_positions;
|
||||
std::vector<CDMRData*> m_data;
|
||||
std::vector<CDMRData*>::const_iterator m_it;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user