Merge pull request #561 from jg1uaa/userdb

UserDB support (NXDN/DMR)
This commit is contained in:
Jonathan Naylor 2020-03-24 22:19:04 +00:00 committed by GitHub
commit 6d27b8d957
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 541 additions and 211 deletions

View file

@ -30,7 +30,6 @@ CThread(),
m_filename(filename),
m_reloadTime(reloadTime),
m_table(),
m_mutex(),
m_stop(false)
{
}
@ -41,7 +40,7 @@ CDMRLookup::~CDMRLookup()
bool CDMRLookup::read()
{
bool ret = load();
bool ret = m_table.load(m_filename);
if (m_reloadTime > 0U)
run();
@ -61,7 +60,7 @@ void CDMRLookup::entry()
timer.clock();
if (timer.hasExpired()) {
load();
m_table.load(m_filename);
timer.start();
}
}
@ -81,118 +80,47 @@ void CDMRLookup::stop()
wait();
}
std::string CDMRLookup::findWithName(unsigned int id)
void CDMRLookup::findWithName(unsigned int id, class CUserDBentry *entry)
{
std::string callsign;
if (id == 0xFFFFFFU)
return std::string("ALL");
m_mutex.lock();
try {
callsign = m_table.at(id);
LogDebug("FindWithName =%s",callsign.c_str());
} catch (...) {
char text[10U];
::sprintf(text, "%u", id);
callsign = std::string(text);
if (id == 0xFFFFFFU) {
entry->clear();
entry->set(keyCALLSIGN, "ALL");
return;
}
m_mutex.unlock();
if (m_table.lookup(id, entry)) {
LogDebug("FindWithName =%s %s", entry->get(keyCALLSIGN).c_str(), entry->get(keyFIRST_NAME).c_str());
} else {
entry->clear();
return callsign;
char text[10U];
::snprintf(text, sizeof(text), "%u", id);
entry->set(keyCALLSIGN, text);
}
return;
}
std::string CDMRLookup::find(unsigned int id)
{
std::string callsign;
std::string b;
if (id == 0xFFFFFFU)
return std::string("ALL");
m_mutex.lock();
try {
b = m_table.at(id);
size_t n = b.find(" ");
if (n > 0) {
callsign = b.substr(0,n);
} else {
LogDebug("b=%s",b.c_str());
callsign = b;
}
} catch (...) {
class CUserDBentry entry;
if (m_table.lookup(id, &entry)) {
callsign = entry.get(keyCALLSIGN);
} else {
char text[10U];
::sprintf(text, "%u", id);
::snprintf(text, sizeof(text), "%u", id);
callsign = std::string(text);
}
m_mutex.unlock();
return callsign;
}
bool CDMRLookup::exists(unsigned int id)
{
m_mutex.lock();
bool found = m_table.count(id) == 1U;
m_mutex.unlock();
return found;
return m_table.lookup(id, NULL);
}
bool CDMRLookup::load()
{
FILE* fp = ::fopen(m_filename.c_str(), "rt");
if (fp == NULL) {
LogWarning("Cannot open the DMR Id lookup file - %s", m_filename.c_str());
return false;
}
m_mutex.lock();
// Remove the old entries
m_table.clear();
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, " \t\r\n");
char* p2 = ::strtok(NULL, " \r\n"); // tokenize to eol to capture name as well
if (p1 != NULL && p2 != NULL) {
unsigned int id = (unsigned int)::atoi(p1);
for (char* p = p2; *p != 0x00U; p++) {
if(*p == 0x09U)
*p = 0x20U;
else
*p = ::toupper(*p);
}
m_table[id] = std::string(p2);
}
}
m_mutex.unlock();
::fclose(fp);
size_t size = m_table.size();
if (size == 0U)
return false;
LogInfo("Loaded %u Ids to the DMR callsign lookup table", size);
return true;
}

View file

@ -20,10 +20,9 @@
#define DMRLookup_H
#include "Thread.h"
#include "Mutex.h"
#include "UserDB.h"
#include <string>
#include <unordered_map>
class CDMRLookup : public CThread {
public:
@ -35,20 +34,17 @@ public:
virtual void entry();
std::string find(unsigned int id);
std::string findWithName(unsigned int id);
void findWithName(unsigned int id, class CUserDBentry *entry);
bool exists(unsigned int id);
void stop();
private:
std::string m_filename;
unsigned int m_reloadTime;
std::unordered_map<unsigned int, std::string> m_table;
CMutex m_mutex;
bool m_stop;
bool load();
std::string m_filename;
unsigned int m_reloadTime;
class CUserDB m_table;
bool m_stop;
};
#endif

View file

@ -1108,7 +1108,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
setShortLC(m_slotNo, dstId, flco, ACTIVITY_VOICE);
std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId);
std::string cn = m_lookup->findWithName(srcId);
class CUserDBentry cn;
m_lookup->findWithName(srcId, &cn);
m_display->writeDMR(m_slotNo, cn, flco == FLCO_GROUP, dst, "N");
#if defined(DUMP_DMR)
@ -1177,7 +1178,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
setShortLC(m_slotNo, dstId, m_netLC->getFLCO(), ACTIVITY_VOICE);
std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId);
std::string cn = m_lookup->findWithName(srcId);
class CUserDBentry cn;
m_lookup->findWithName(srcId, &cn);
m_display->writeDMR(m_slotNo, cn, m_netLC->getFLCO() == FLCO_GROUP, dst, "N");
@ -1373,7 +1375,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
std::string src = m_lookup->find(srcId);
std::string dst = m_lookup->find(dstId);
std::string cn = m_lookup->findWithName(srcId);
class CUserDBentry cn;
m_lookup->findWithName(srcId, &cn);
m_display->writeDMR(m_slotNo, cn, m_netLC->getFLCO() == FLCO_GROUP, dst, "N");

View file

@ -151,6 +151,29 @@ void CDisplay::writeDMR(unsigned int slotNo, const std::string& src, bool group,
writeDMRInt(slotNo, src, group, dst, type);
}
void CDisplay::writeDMR(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type)
{
assert(type != NULL);
if (slotNo == 1U) {
m_timer1.start();
m_mode1 = MODE_IDLE;
} else {
m_timer2.start();
m_mode2 = MODE_IDLE;
}
if (int err = writeDMRIntEx(slotNo, src, group, dst, type)) {
std::string src_str = src.get(keyCALLSIGN);
if (err < 0 && !src.get(keyFIRST_NAME).empty()) {
// emulate the result of old CDMRLookup::findWithName()
// (it returned callsign and firstname)
src_str += " " + src.get(keyFIRST_NAME);
}
writeDMRInt(slotNo, src_str, group, dst, type);
}
}
void CDisplay::writeDMRRSSI(unsigned int slotNo, unsigned char rssi)
{
if (rssi != 0U)
@ -267,6 +290,17 @@ void CDisplay::writeNXDN(const char* source, bool group, unsigned int dest, cons
writeNXDNInt(source, group, dest, type);
}
void CDisplay::writeNXDN(const class CUserDBentry& source, bool group, unsigned int dest, const char* type)
{
assert(type != NULL);
m_timer1.start();
m_mode1 = MODE_IDLE;
if (writeNXDNIntEx(source, group, dest, type))
writeNXDNInt(source.get(keyCALLSIGN).c_str(), group, dest, type);
}
void CDisplay::writeNXDNRSSI(unsigned char rssi)
{
if (rssi != 0U)
@ -386,6 +420,20 @@ void CDisplay::writeDStarBERInt(float ber)
{
}
int CDisplay::writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type)
{
/*
* return value:
* < 0 error condition (i.e. not supported)
* -> call writeXXXXInt() to display
* = 0 no error, writeXXXXIntEx() displayed whole status
* = 1 no error, writeXXXXIntEx() displayed partial status
* -> call writeXXXXInt() to display remain part
* > 1 reserved for future use
*/
return -1; // not supported
}
void CDisplay::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
{
}
@ -421,6 +469,13 @@ void CDisplay::writeNXDNRSSIInt(unsigned char rssi)
void CDisplay::writeNXDNBERInt(float ber)
{
}
int CDisplay::writeNXDNIntEx(const class CUserDBentry& source, bool group, unsigned int dest, const char* type)
{
/* return value definition is same as writeDMRIntEx() */
return -1; // not supported
}
/* Factory method extracted from MMDVMHost.cpp - BG5HHP */
CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem)

View file

@ -20,6 +20,7 @@
#define DISPLAY_H
#include "Timer.h"
#include "UserDBentry.h"
#include <string>
@ -48,6 +49,7 @@ public:
void clearDStar();
void writeDMR(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
void writeDMR(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type);
void writeDMRRSSI(unsigned int slotNo, unsigned char rssi);
void writeDMRBER(unsigned int slotNo, float ber);
void writeDMRTA(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
@ -64,6 +66,7 @@ public:
void clearP25();
void writeNXDN(const char* source, bool group, unsigned int dest, const char* type);
void writeNXDN(const class CUserDBentry& source, bool group, unsigned int dest, const char* type);
void writeNXDNRSSI(unsigned char rssi);
void writeNXDNBER(float ber);
void clearNXDN();
@ -91,6 +94,7 @@ protected:
virtual void clearDStarInt() = 0;
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) = 0;
virtual int writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type);
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
virtual void writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
virtual void writeDMRBERInt(unsigned int slotNo, float ber);
@ -107,6 +111,7 @@ protected:
virtual void clearP25Int() = 0;
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type) = 0;
virtual int writeNXDNIntEx(const class CUserDBentry& source, bool group, unsigned int dest, const char* type);
virtual void writeNXDNRSSIInt(unsigned char rssi);
virtual void writeNXDNBERInt(float ber);
virtual void clearNXDNInt() = 0;

View file

@ -13,7 +13,7 @@ OBJECTS = \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o \
NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \
POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o \
TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

View file

@ -13,7 +13,7 @@ OBJECTS = \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \
NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o \
UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

View file

@ -14,7 +14,7 @@ OBJECTS = \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \
NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

View file

@ -13,7 +13,7 @@ OBJECTS = \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \
NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

View file

@ -13,7 +13,7 @@ OBJECTS = \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \
NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

View file

@ -14,7 +14,7 @@ OBJECTS = \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \
NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \
Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

View file

@ -13,7 +13,7 @@ OBJECTS = \
NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \
NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o \
QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \
UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
UMP.o UserDB.o UserDBebtry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

View file

@ -835,15 +835,16 @@ void CNXDNControl::writeNetwork()
unsigned short dstId = m_netLayer3.getDestinationGroupId();
bool grp = m_netLayer3.getIsGroup();
std::string source = m_lookup->find(m_netLayer3.getSourceUnitId());
class CUserDBentry source;
m_lookup->findWithName(m_netLayer3.getSourceUnitId(), &source);
if (type == NXDN_MESSAGE_TYPE_TX_REL) {
m_netFrames++;
LogMessage("NXDN, received network end of transmission from %s to %s%u, %.1f seconds", source.c_str(), grp ? "TG " : "", dstId, float(m_netFrames) / 12.5F);
LogMessage("NXDN, received network end of transmission from %s to %s%u, %.1f seconds", source.get(keyCALLSIGN).c_str(), grp ? "TG " : "", dstId, float(m_netFrames) / 12.5F);
writeEndNet();
} else if (type == NXDN_MESSAGE_TYPE_VCALL) {
LogMessage("NXDN, received network transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
m_display->writeNXDN(source.c_str(), grp, dstId, "N");
LogMessage("NXDN, received network transmission from %s to %s%u", source.get(keyCALLSIGN).c_str(), grp ? "TG " : "", dstId);
m_display->writeNXDN(source, grp, dstId, "N");
m_netTimeoutTimer.start();
m_packetTimer.start();
@ -892,9 +893,10 @@ void CNXDNControl::writeNetwork()
unsigned short dstId = m_netLayer3.getDestinationGroupId();
bool grp = m_netLayer3.getIsGroup();
std::string source = m_lookup->find(srcId);
LogMessage("NXDN, received network transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
m_display->writeNXDN(source.c_str(), grp, dstId, "N");
class CUserDBentry source;
m_lookup->findWithName(srcId, &source);
LogMessage("NXDN, received network transmission from %s to %s%u", source.get(keyCALLSIGN).c_str(), grp ? "TG " : "", dstId);
m_display->writeNXDN(source, grp, dstId, "N");
m_netTimeoutTimer.start();
m_packetTimer.start();

View file

@ -30,7 +30,6 @@ CThread(),
m_filename(filename),
m_reloadTime(reloadTime),
m_table(),
m_mutex(),
m_stop(false)
{
}
@ -41,7 +40,7 @@ CNXDNLookup::~CNXDNLookup()
bool CNXDNLookup::read()
{
bool ret = load();
bool ret = m_table.load(m_filename);
if (m_reloadTime > 0U)
run();
@ -61,7 +60,7 @@ void CNXDNLookup::entry()
timer.clock();
if (timer.hasExpired()) {
load();
m_table.load(m_filename);
timer.start();
}
}
@ -81,6 +80,27 @@ void CNXDNLookup::stop()
wait();
}
void CNXDNLookup::findWithName(unsigned int id, class CUserDBentry *entry)
{
if (id == 0xFFFFU) {
entry->clear();
entry->set(keyCALLSIGN, "ALL");
return;
}
if (m_table.lookup(id, entry)) {
LogDebug("FindWithName =%s %s", entry->get(keyCALLSIGN).c_str(), entry->get(keyFIRST_NAME).c_str());
} else {
entry->clear();
char text[10U];
::snprintf(text, sizeof(text), "%u", id);
entry->set(keyCALLSIGN, text);
}
return;
}
std::string CNXDNLookup::find(unsigned int id)
{
std::string callsign;
@ -88,73 +108,19 @@ std::string CNXDNLookup::find(unsigned int id)
if (id == 0xFFFFU)
return std::string("ALL");
m_mutex.lock();
try {
callsign = m_table.at(id);
} catch (...) {
class CUserDBentry entry;
if (m_table.lookup(id, &entry)) {
callsign = entry.get(keyCALLSIGN);
} else {
char text[10U];
::sprintf(text, "%u", id);
::snprintf(text, sizeof(text), "%u", id);
callsign = std::string(text);
}
m_mutex.unlock();
return callsign;
}
bool CNXDNLookup::exists(unsigned int id)
{
m_mutex.lock();
bool found = m_table.count(id) == 1U;
m_mutex.unlock();
return found;
return m_table.lookup(id, NULL);
}
bool CNXDNLookup::load()
{
FILE* fp = ::fopen(m_filename.c_str(), "rt");
if (fp == NULL) {
LogWarning("Cannot open the NXDN Id lookup file - %s", m_filename.c_str());
return false;
}
m_mutex.lock();
// Remove the old entries
m_table.clear();
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, ",\t\r\n");
char* p2 = ::strtok(NULL, ",\t\r\n");
if (p1 != NULL && p2 != NULL) {
unsigned int id = (unsigned int)::atoi(p1);
if (id > 0U) {
for (char* p = p2; *p != 0x00U; p++)
*p = ::toupper(*p);
m_table[id] = std::string(p2);
}
}
}
m_mutex.unlock();
::fclose(fp);
size_t size = m_table.size();
if (size == 0U)
return false;
LogInfo("Loaded %u Ids to the NXDN callsign lookup table", size);
return true;
}

View file

@ -20,10 +20,9 @@
#define NXDNLookup_H
#include "Thread.h"
#include "Mutex.h"
#include "UserDB.h"
#include <string>
#include <unordered_map>
class CNXDNLookup : public CThread {
public:
@ -35,19 +34,17 @@ public:
virtual void entry();
std::string find(unsigned int id);
void findWithName(unsigned int id, class CUserDBentry *entry);
bool exists(unsigned int id);
void stop();
private:
std::string m_filename;
unsigned int m_reloadTime;
std::unordered_map<unsigned int, std::string> m_table;
CMutex m_mutex;
bool m_stop;
bool load();
std::string m_filename;
unsigned int m_reloadTime;
class CUserDB m_table;
bool m_stop;
};
#endif

View file

@ -135,7 +135,7 @@ void CTFTSurenoo::setIdleInt()
{
setModeLine(STR_MMDVM);
::snprintf(m_temp, sizeof(m_temp), "%-6s / %u", m_callsign.c_str(), m_dmrid);
::snprintf(m_temp, sizeof(m_temp), "%s / %u", m_callsign.c_str(), m_dmrid);
setStatusLine(statusLineNo(0), m_temp);
setStatusLine(statusLineNo(1), "IDLE");
@ -184,14 +184,14 @@ void CTFTSurenoo::writeDStarInt(const char* my1, const char* my2, const char* yo
setModeLine(STR_MMDVM);
::snprintf(m_temp, sizeof(m_temp), "%s %.8s/%4.4s", type, my1, my2);
::snprintf(m_temp, sizeof(m_temp), "%s %s/%s", type, my1, my2);
setStatusLine(statusLineNo(0), m_temp);
::snprintf(m_temp, sizeof(m_temp), "%.8s", your);
::snprintf(m_temp, sizeof(m_temp), "%s", your);
setStatusLine(statusLineNo(1), m_temp);
if (::strcmp(reflector, " ") != 0)
::snprintf(m_temp, sizeof(m_temp), "via %.8s", reflector);
::snprintf(m_temp, sizeof(m_temp), "via %s", reflector);
else
::strcpy(m_temp, "");
setStatusLine(statusLineNo(2), m_temp);
@ -202,8 +202,8 @@ void CTFTSurenoo::writeDStarInt(const char* my1, const char* my2, const char* yo
void CTFTSurenoo::clearDStarInt()
{
setStatusLine(statusLineNo(0), "Listening");
setStatusLine(statusLineNo(1), "");
setStatusLine(statusLineNo(2), "");
for (int i = 1; i < STATUS_LINES; i++)
setStatusLine(statusLineNo(i), "");
}
void CTFTSurenoo::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
@ -230,6 +230,25 @@ void CTFTSurenoo::writeDMRInt(unsigned int slotNo, const std::string& src, bool
m_mode = MODE_DMR;
}
int CTFTSurenoo::writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type)
{
assert(type != NULL);
// duplex mode is not supported
if (m_duplex)
return -1;
setModeLine(STR_DMR);
setStatusLine(statusLineNo(2), (src.get(keyFIRST_NAME) + " " + src.get(keyLAST_NAME)).c_str());
setStatusLine(statusLineNo(3), src.get(keyCITY).c_str());
setStatusLine(statusLineNo(4), src.get(keySTATE).c_str());
setStatusLine(statusLineNo(5), src.get(keyCOUNTRY).c_str());
m_mode = MODE_DMR;
return 1;
}
void CTFTSurenoo::clearDMRInt(unsigned int slotNo)
{
int pos = m_duplex ? (slotNo - 1) : 0;
@ -239,7 +258,8 @@ void CTFTSurenoo::clearDMRInt(unsigned int slotNo)
::snprintf(m_temp, sizeof(m_temp), "TS%d", slotNo);
setStatusLine(statusLineNo(pos * 2 + 1), m_temp);
} else {
setStatusLine(statusLineNo(1), "");
for (int i = 1; i < STATUS_LINES; i++)
setStatusLine(statusLineNo(i), "");
}
}
@ -252,14 +272,14 @@ void CTFTSurenoo::writeFusionInt(const char* source, const char* dest, const cha
setModeLine(STR_YSF);
::snprintf(m_temp, sizeof(m_temp), "%s %.10s", type, source);
::snprintf(m_temp, sizeof(m_temp), "%s %s", type, source);
setStatusLine(statusLineNo(0), m_temp);
::snprintf(m_temp, sizeof(m_temp), " %.10s", dest);
::snprintf(m_temp, sizeof(m_temp), "%s", dest);
setStatusLine(statusLineNo(1), m_temp);
if (::strcmp(origin, " ") != 0)
::snprintf(m_temp, sizeof(m_temp), "at %.10s", origin);
::snprintf(m_temp, sizeof(m_temp), "at %s", origin);
else
::strcpy(m_temp, "");
setStatusLine(statusLineNo(2), m_temp);
@ -279,10 +299,10 @@ void CTFTSurenoo::writeP25Int(const char* source, bool group, unsigned int dest,
setModeLine(STR_P25);
::snprintf(m_temp, sizeof(m_temp), "%s %.10s", type, source);
::snprintf(m_temp, sizeof(m_temp), "%s %s", type, source);
setStatusLine(statusLineNo(0), m_temp);
::snprintf(m_temp, sizeof(m_temp), " %s%u", group ? "TG" : "", dest);
::snprintf(m_temp, sizeof(m_temp), "%s%u", group ? "TG" : "", dest);
setStatusLine(statusLineNo(1), m_temp);
m_mode = MODE_P25;
@ -298,17 +318,33 @@ void CTFTSurenoo::writeNXDNInt(const char* source, bool group, unsigned int dest
assert(source != NULL);
assert(type != NULL);
setModeLine(STR_NXDN);
if (m_mode != MODE_NXDN)
setModeLine(STR_NXDN);
::snprintf(m_temp, sizeof(m_temp), "%s %.10s", type, source);
::snprintf(m_temp, sizeof(m_temp), "%s %s", type, source);
setStatusLine(statusLineNo(0), m_temp);
::snprintf(m_temp, sizeof(m_temp), " %s%u", group ? "TG" : "", dest);
::snprintf(m_temp, sizeof(m_temp), "%s%u", group ? "TG" : "", dest);
setStatusLine(statusLineNo(1), m_temp);
m_mode = MODE_NXDN;
}
int CTFTSurenoo::writeNXDNIntEx(const class CUserDBentry& source, bool group, unsigned int dest, const char* type)
{
assert(type != NULL);
setModeLine(STR_NXDN);
setStatusLine(statusLineNo(2), (source.get(keyFIRST_NAME) + " " + source.get(keyLAST_NAME)).c_str());
setStatusLine(statusLineNo(3), source.get(keyCITY).c_str());
setStatusLine(statusLineNo(4), source.get(keySTATE).c_str());
setStatusLine(statusLineNo(5), source.get(keyCOUNTRY).c_str());
m_mode = MODE_NXDN;
return 1;
}
void CTFTSurenoo::clearNXDNInt()
{
clearDStarInt();

View file

@ -23,6 +23,7 @@
#include "Display.h"
#include "Defines.h"
#include "SerialPort.h"
#include "UserDBentry.h"
#include <string>
@ -46,6 +47,7 @@ protected:
virtual void clearDStarInt();
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
virtual int writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type);
virtual void clearDMRInt(unsigned int slotNo);
virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin);
@ -55,6 +57,7 @@ protected:
virtual void clearP25Int();
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type);
virtual int writeNXDNIntEx(const class CUserDBentry& source, bool group, unsigned int dest, const char* type);
virtual void clearNXDNInt();
virtual void writePOCSAGInt(uint32_t ric, const std::string& message);

187
UserDB.cpp Normal file
View file

@ -0,0 +1,187 @@
/*
* Copyright (C) 2020 by SASANO Takayoshi JG1UAA
*
* 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 "UserDB.h"
#include "Log.h"
#include <cstdio>
#include <cstring>
#include <cctype>
CUserDB::CUserDB() :
m_table(),
m_mutex()
{
}
CUserDB::~CUserDB()
{
}
bool CUserDB::lookup(unsigned int id, class CUserDBentry *entry)
{
bool rv;
m_mutex.lock();
try {
if (entry != NULL)
*entry = m_table.at(id);
else
m_table.at(id);
rv = true;
} catch (...) {
rv = false;
}
m_mutex.unlock();
return rv;
}
bool CUserDB::load(std::string const& filename)
{
FILE* fp = ::fopen(filename.c_str(), "r");
if (fp == NULL) {
LogWarning("Cannot open ID lookup file - %s", filename.c_str());
return false;
}
m_mutex.lock();
// Remove the old entries;
m_table.clear();
// set index for entries
char buffer[256U];
if (::fgets(buffer, sizeof(buffer), fp) == NULL) {
LogWarning("ID lookup file has no entry - %s", filename.c_str());
m_mutex.unlock();
::fclose(fp);
return false;
}
// no index - set default
std::unordered_map<std::string, int> index;
if (!makeindex(buffer, index)) {
::strncpy(buffer, keyRADIO_ID "," keyCALLSIGN "," keyFIRST_NAME, sizeof(buffer));
makeindex(buffer, index);
::rewind(fp);
}
while (::fgets(buffer, sizeof(buffer), fp) != NULL) {
if (buffer[0U] != '#')
parse(buffer, index);
}
::fclose(fp);
size_t size = m_table.size();
m_mutex.unlock();
LogInfo("Loaded %u IDs to lookup table - %s", size, filename.c_str());
return size != 0U;
}
bool CUserDB::makeindex(char* buf, std::unordered_map<std::string, int>& index)
{
int i;
char *p1, *p2;
// Remove the old index
index.clear();
for (i = 0, p1 = tokenize(buf, &p2); p1 != NULL;
i++, p1 = tokenize(p2, &p2)) {
// create [column keyword] - [column number] table
if (CUserDBentry::isValidKey(p1))
index[p1] = i;
}
try {
index.at(keyRADIO_ID);
index.at(keyCALLSIGN);
return true;
} catch (...) {
return false;
}
}
void CUserDB::parse(char* buf, std::unordered_map<std::string, int>& index)
{
int i;
char *p1, *p2;
std::unordered_map<std::string, char*> ptr;
unsigned int id;
for (i = 0, p1 = tokenize(buf, &p2); p1 != NULL;
i++, p1 = tokenize(p2, &p2)) {
for (auto it = index.begin(); it != index.end(); it++) {
// first: column keyword, second: column number
if (it->second == i) {
ptr[it->first] = p1;
break;
}
}
}
try {
ptr.at(keyRADIO_ID);
ptr.at(keyCALLSIGN);
} catch (...) {
return;
}
id = (unsigned int)::atoi(ptr[keyRADIO_ID]);
toupper_string(ptr[keyCALLSIGN]);
for (auto it = ptr.begin(); it != ptr.end(); it++) {
// no need to regist radio ID
if (it->first == keyRADIO_ID)
continue;
m_table[id].set(it->first, it->second);
}
}
void CUserDB::toupper_string(char* str)
{
while (*str != '\0') {
*str = ::toupper(*str);
str++;
}
}
char* CUserDB::tokenize(char* str, char** next)
{
if (*str == '\0')
return NULL;
char* p = ::strpbrk(str, ",\t\r\n");
if (p == NULL) {
*next = str + ::strlen(str);
} else {
*p = '\0';
*next = p + 1;
}
return str;
}

43
UserDB.h Normal file
View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2020 by SASANO Takayoshi JG1UAA
*
* 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(USERDB_H)
#define USERDB_H
#include "UserDBentry.h"
#include "Mutex.h"
class CUserDB {
public:
CUserDB();
~CUserDB();
bool lookup(unsigned int id, class CUserDBentry *entry);
bool load(std::string const& filename);
private:
bool makeindex(char* buf, std::unordered_map<std::string, int>& index);
void parse(char* buf, std::unordered_map<std::string, int>& index);
void toupper_string(char* str);
char* tokenize(char* str, char** next);
std::unordered_map<unsigned int, class CUserDBentry> m_table;
CMutex m_mutex;
};
#endif

59
UserDBentry.cpp Normal file
View file

@ -0,0 +1,59 @@
/*
* Copyright (C) 2020 by SASANO Takayoshi JG1UAA
*
* 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 "UserDBentry.h"
#include <algorithm>
CUserDBentry::CUserDBentry() :
m_db()
{
}
CUserDBentry::~CUserDBentry()
{
}
const std::vector<std::string> CUserDBentry::keyList {
keyRADIO_ID, keyCALLSIGN, keyFIRST_NAME, keyLAST_NAME,
keyCITY, keySTATE, keyCOUNTRY,
};
bool CUserDBentry::isValidKey(const std::string key)
{
auto it = std::find(keyList.begin(), keyList.end(), key);
return it != keyList.end();
}
void CUserDBentry::set(const std::string key, const std::string value)
{
if (!value.empty() && isValidKey(key))
m_db[key] = value;
}
const std::string CUserDBentry::get(const std::string key) const
{
try {
return m_db.at(key);
} catch (...) {
return "";
}
}
void CUserDBentry::clear(void)
{
m_db.clear();
}

50
UserDBentry.h Normal file
View file

@ -0,0 +1,50 @@
/*
* Copyright (C) 2020 by SASANO Takayoshi JG1UAA
*
* 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(USERDBENTRY_H)
#define USERDBENTRY_H
#include <string>
#include <unordered_map>
#include <vector>
#define keyRADIO_ID "RADIO_ID"
#define keyCALLSIGN "CALLSIGN"
#define keyFIRST_NAME "FIRST_NAME"
#define keyLAST_NAME "LAST_NAME"
#define keyCITY "CITY"
#define keySTATE "STATE"
#define keyCOUNTRY "COUNTRY"
class CUserDBentry {
public:
CUserDBentry();
~CUserDBentry();
static const std::vector<std::string> keyList;
static bool isValidKey(const std::string key);
void set(const std::string key, const std::string value);
const std::string get(const std::string key) const;
void clear(void);
private:
std::unordered_map<std::string, std::string> m_db;
};
#endif