diff --git a/DMRLookup.cpp b/DMRLookup.cpp index 8fc67c3..b959950 100644 --- a/DMRLookup.cpp +++ b/DMRLookup.cpp @@ -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; -} \ No newline at end of file diff --git a/DMRLookup.h b/DMRLookup.h index 1156270..c4e5d90 100644 --- a/DMRLookup.h +++ b/DMRLookup.h @@ -20,10 +20,9 @@ #define DMRLookup_H #include "Thread.h" -#include "Mutex.h" +#include "UserDB.h" #include -#include 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 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 diff --git a/DMRSlot.cpp b/DMRSlot.cpp index f42def4..1cfecab 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -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"); diff --git a/Display.cpp b/Display.cpp index 84148b7..5a74747 100644 --- a/Display.cpp +++ b/Display.cpp @@ -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) diff --git a/Display.h b/Display.h index 65515be..74fa25b 100644 --- a/Display.h +++ b/Display.h @@ -20,6 +20,7 @@ #define DISPLAY_H #include "Timer.h" +#include "UserDBentry.h" #include @@ -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; diff --git a/Makefile b/Makefile index 9a24d1a..efdaba6 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/Makefile.Pi b/Makefile.Pi index fe7da05..640c07f 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -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 diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 1849e68..24c2907 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -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 diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index f7c0c31..c2faad2 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -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 diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index d6acd67..d2db40c 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -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 diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index c3441c6..4c5d3a3 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -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 diff --git a/Makefile.Solaris b/Makefile.Solaris index 1d94eef..c50d41e 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -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 diff --git a/NXDNControl.cpp b/NXDNControl.cpp index f36d7d0..1f3fa4c 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -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(); diff --git a/NXDNLookup.cpp b/NXDNLookup.cpp index 2c621b6..c12ed27 100644 --- a/NXDNLookup.cpp +++ b/NXDNLookup.cpp @@ -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; -} \ No newline at end of file diff --git a/NXDNLookup.h b/NXDNLookup.h index d7b0486..c53a927 100644 --- a/NXDNLookup.h +++ b/NXDNLookup.h @@ -20,10 +20,9 @@ #define NXDNLookup_H #include "Thread.h" -#include "Mutex.h" +#include "UserDB.h" #include -#include 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 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 diff --git a/TFTSurenoo.cpp b/TFTSurenoo.cpp index 5d15856..a2eba9e 100644 --- a/TFTSurenoo.cpp +++ b/TFTSurenoo.cpp @@ -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(); diff --git a/TFTSurenoo.h b/TFTSurenoo.h index 20a743a..d058c3e 100644 --- a/TFTSurenoo.h +++ b/TFTSurenoo.h @@ -23,6 +23,7 @@ #include "Display.h" #include "Defines.h" #include "SerialPort.h" +#include "UserDBentry.h" #include @@ -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); diff --git a/UserDB.cpp b/UserDB.cpp new file mode 100644 index 0000000..9984d63 --- /dev/null +++ b/UserDB.cpp @@ -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 +#include +#include + +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 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& 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& index) +{ + int i; + char *p1, *p2; + std::unordered_map 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; +} diff --git a/UserDB.h b/UserDB.h new file mode 100644 index 0000000..acae103 --- /dev/null +++ b/UserDB.h @@ -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& index); + void parse(char* buf, std::unordered_map& index); + void toupper_string(char* str); + char* tokenize(char* str, char** next); + + std::unordered_map m_table; + CMutex m_mutex; +}; + +#endif diff --git a/UserDBentry.cpp b/UserDBentry.cpp new file mode 100644 index 0000000..0121544 --- /dev/null +++ b/UserDBentry.cpp @@ -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 + +CUserDBentry::CUserDBentry() : +m_db() +{ +} + +CUserDBentry::~CUserDBentry() +{ +} + +const std::vector 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(); +} diff --git a/UserDBentry.h b/UserDBentry.h new file mode 100644 index 0000000..cbca92f --- /dev/null +++ b/UserDBentry.h @@ -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 +#include +#include + +#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 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 m_db; +}; + +#endif