From bef4efa5b39f9dce3cf254349ee01d081d50d792 Mon Sep 17 00:00:00 2001 From: ezratl Date: Mon, 10 Feb 2020 15:02:53 -0500 Subject: [PATCH] Added lockout and delay support to the scanner --- src/core/Configuration.cpp | 24 +++++++--- src/core/Configuration.h | 12 ++--- src/core/PiScan.h | 11 ++++- src/core/ScannerSM.cpp | 87 +++++++++++++++++++++++++------------ src/core/ScannerSM.h | 27 ++++++++---- src/core/clientmessage.h | 1 + src/core/constants.h | 2 +- src/piScan_backend.cpp | 17 ++++++-- src/scan/Entry.h | 34 +++++++++++---- src/scan/RadioSystem.cpp | 12 ++--- src/scan/SentinelFile.cpp | 62 ++++++++++++++++++++------ src/scan/SystemList.cpp | 44 ++++++++++++------- src/scan/SystemList.h | 4 ++ src/server/Connection.cpp | 7 +-- src/server/DebugServer.cpp | 11 +++-- src/server/connection.h | 2 +- src/sigproc/Demodulator.cpp | 28 ++++++++---- 17 files changed, 272 insertions(+), 113 deletions(-) diff --git a/src/core/Configuration.cpp b/src/core/Configuration.cpp index 9924375..4148c40 100644 --- a/src/core/Configuration.cpp +++ b/src/core/Configuration.cpp @@ -36,7 +36,7 @@ Configuration::~Configuration() { // TODO Auto-generated destructor stub } -void Configuration::setWorkingPath(std::string path){ +void Configuration::setWorkingDirectory(std::string path){ filesystem::path configPath(path); if(!filesystem::exists(configPath)) if(!filesystem::create_directory(configPath)){ @@ -49,7 +49,7 @@ void Configuration::setWorkingPath(std::string path){ LOG_F(INFO, "Config directory: %s", path.c_str()); } -std::string Configuration::getWorkingPath() { +std::string Configuration::getWorkingDirectory() { return _configPath; } @@ -139,17 +139,22 @@ void Configuration::saveState(){ write_json(path.c_str(), pt); } -std::string Configuration::getLogfilePath(){ +std::string Configuration::getLogDirectory(){ filesystem::path path(_configPath); path += filesystem::path::preferred_separator; path += LOG_FOLDER; - if(!filesystem::exists(path)){ - if(!filesystem::create_directory(path)){ + if (!filesystem::exists(path)) { + if (!filesystem::create_directory(path)) { LOG_F(ERROR, "Error creating logfile directory"); path = DATABASE_PATH; } } + return path; +} + +std::string Configuration::getDatedLogPath(){ + filesystem::path path(getLogDirectory()); auto t = std::time(nullptr); auto tm = *std::localtime(&t); @@ -161,6 +166,13 @@ std::string Configuration::getLogfilePath(){ path += filesystem::path::preferred_separator; path += str; path += LOGFILE_EXT; - return path.string(); + return path; +} + +std::string Configuration::getLatestLogPath(){ + filesystem::path path(getLogDirectory()); + path += filesystem::path::preferred_separator; + path += LOG_PATH; + return path; } diff --git a/src/core/Configuration.h b/src/core/Configuration.h index 421e7c4..34cd1bc 100644 --- a/src/core/Configuration.h +++ b/src/core/Configuration.h @@ -14,7 +14,7 @@ #ifndef NDEBUG #define DEFAULT_LOGFILE_VERBOSITY 3 -#define LOG_PATH "log.txt" +#define LOG_PATH "latest.log" #else #define DEFAULT_LOGFILE_VERBOSITY 0 #define LOG_PATH "~/piscan.log" @@ -22,7 +22,7 @@ #define DATABASE_PATH "../data" #define LOG_FOLDER "logs" -#define LOGFILE_EXT ".txt" +#define LOGFILE_EXT ".log" #define CONFIG_FILE "config.json" #define STATE_FILE "state.json" @@ -63,8 +63,8 @@ public: static Configuration& getConfig(); - void setWorkingPath(std::string path); - std::string getWorkingPath(); + void setWorkingDirectory(std::string path); + std::string getWorkingDirectory(); void loadConfig(); void loadState(); void saveConfig(); @@ -74,7 +74,9 @@ public: SocketServerConfig& getSocketConfig() { return _socketConfig; }; DemodState& getDemodState() { return _demodState; }; - std::string getLogfilePath(); + std::string getLogDirectory(); + std::string getDatedLogPath(); + std::string getLatestLogPath(); private: static Configuration* _config; diff --git a/src/core/PiScan.h b/src/core/PiScan.h index 7ac8d43..7adb21d 100644 --- a/src/core/PiScan.h +++ b/src/core/PiScan.h @@ -5,6 +5,15 @@ #include "clientmessage.h" namespace piscan::app { +struct ManualEntryData { +public: + ManualEntryData(ManualEntryData& copy) : freq(copy.freq), modulation(copy.modulation){}; + ManualEntryData(long long freq, std::string mode): freq(freq), modulation(mode){}; + + long long freq; + std::string modulation; +}; + /* system functions */ bool stopSystem(); const SystemInfo getSystemInfo(); @@ -13,7 +22,7 @@ const SystemInfo getSystemInfo(); void startScan(); void holdScan(std::vector index = std::vector()); void stopScanner(); -void manualEntry(uint32_t* freq); +void manualEntry(ManualEntryData* freq); ScannerContext getScannerContext(); /* demod functions */ diff --git a/src/core/ScannerSM.cpp b/src/core/ScannerSM.cpp index a964198..0b3f92f 100644 --- a/src/core/ScannerSM.cpp +++ b/src/core/ScannerSM.cpp @@ -20,6 +20,7 @@ #define SCANNER_THREAD_NAME "Scanner" using namespace piscan; +using namespace std; ScannerSM::ScannerSM(MessageReceiver& central, SystemList& dataSource) : StateMachine(7), _centralQueue(central), _systems(dataSource), _externalHold(false), _manualMode(false) { @@ -38,10 +39,10 @@ void ScannerSM::startScan(){ END_TRANSITION_MAP(NULL) } -void ScannerSM::holdScan(std::vector index){ +void ScannerSM::holdScan(vector index){ _externalHold.store(true); { - std::lock_guard lock(_holdMutex); + lock_guard lock(_holdMutex); _holdIndex = index; } LOG_F(1, "ExtEvent: holdScan"); @@ -69,7 +70,7 @@ void ScannerSM::stopScanner(){ END_TRANSITION_MAP(NULL) } -void ScannerSM::manualEntry(uint32_t* freq){ +void ScannerSM::manualEntry(app::ManualEntryData* freq){ LOG_F(1, "ExtEvent: manualEntry"); BEGIN_TRANSITION_MAP TRANSITION_MAP_ENTRY(EVENT_IGNORED) @@ -93,7 +94,7 @@ void ScannerSM::ST_Load(EventData* data){ // do not issue event - SM will wait until an event is generated before proceeding //InternalEvent(ST_SCAN); - //auto message = std::make_shared(SCANNER_SM, ControllerMessage::NOTIFY_READY); + //auto message = make_shared(SCANNER_SM, ControllerMessage::NOTIFY_READY); //_centralQueue.giveMessage(message); LOG_F(1, "ScannerSM ready"); notifyReady(); @@ -102,10 +103,16 @@ void ScannerSM::ST_Load(EventData* data){ void ScannerSM::ST_Scan(EventData* data){ DLOG_F(9, "ST_Scan"); if(currentState != lastState){ - //_squelchHits = 0; + _squelchHits = 0; DLOG_F(6, "State change: %i -> %i", lastState, currentState); } + if(_systems.size() == 0){ + LOG_F(INFO, "Database is empty, no entries to scan - defaulting to manual entry"); + InternalEvent(ST_MANUAL, new EventData(new uint32_t(100000000))); + return; + } + _enableAudioOut(false); _currentContext.state = ScannerContext::SCAN; _manualMode = false; @@ -113,11 +120,11 @@ void ScannerSM::ST_Scan(EventData* data){ if(currentState != lastState){ _broadcastContextUpdate(); - _currentEntry = _systems.getNextEntry(); } if (!_squelchHits || (currentState != lastState)) { _currentEntry = _systems.getNextEntry(); + DLOG_F(7, (_currentEntry->isDummy() ? "retune %lli" : "getNextEntry %lli"), _currentEntry->freq()); } if (_currentEntry->hasSignal()) { @@ -128,7 +135,7 @@ void ScannerSM::ST_Scan(EventData* data){ } else { InternalEvent(ST_SCAN); } - } else if(!evtSrcExternal){ + } else /*if(!evtSrcExternal)*/{ _squelchHits = 0; InternalEvent(ST_SCAN); } @@ -143,7 +150,7 @@ void ScannerSM::ST_Hold(EventData* data){ bool indexHold = false; { - std::lock_guard < std::mutex > lock(_holdMutex); + lock_guard < mutex > lock(_holdMutex); if (_externalHold.load() && _holdIndex.size() > 0) { _currentEntry = _systems.getEntryByIndex(_holdIndex); LOG_F(1, "Index hold"); @@ -174,18 +181,25 @@ void ScannerSM::ST_Hold(EventData* data){ else if(_externalHold.load()){ InternalEvent(ST_HOLD); } + /* check if entry was locked while holding */ + else if(_currentEntry->isLockedOut()){ + LOG_F(3, "Locked out during hold, resume scan"); + InternalEvent(ST_SCAN); + } /* check timeout counter if entry has resume delay enabled */ - else if(_currentEntry->delay() && timeoutStart != 0){ - if(std::difftime(std::time(nullptr), timeoutStart) < _currentEntry->delay()){ + else if(_currentEntry->delayMS()){ + auto current = time_point_cast(system_clock::now()); + + if((current- timeoutStart).count() < _currentEntry->delayMS()){ InternalEvent(ST_HOLD); } - else { + else if(!evtSrcExternal){ LOG_F(3, "Delay timed out, resuming scan"); InternalEvent(ST_SCAN); } } /* entry does not have delay and hold was internal */ - else{ + else if(!evtSrcExternal){ LOG_F(3, "Resuming scan"); InternalEvent(ST_SCAN); } @@ -199,6 +213,12 @@ void ScannerSM::ST_Receive(EventData* data){ if(currentState != lastState) DLOG_F(6, "State change: %i -> %i", lastState, currentState); + /* check if entry was locked while holding */ + if (_currentEntry->isLockedOut()) { + LOG_F(3, "Locked out during hold, resume scan"); + InternalEvent(ST_SCAN); + } + _enableAudioOut(true); _currentContext.state = ScannerContext::RECEIVE; if(currentState != lastState) @@ -210,7 +230,7 @@ void ScannerSM::ST_Receive(EventData* data){ else{ LOG_F(5, "Signal lost"); InternalEvent(ST_HOLD); - timeoutStart = std::time(nullptr); + timeoutStart = time_point_cast(system_clock::now()); return; } @@ -223,15 +243,23 @@ void ScannerSM::ST_Manual(EventData* data){ if(currentState != lastState) DLOG_F(6, "State change: %i -> %i", lastState, currentState); - uint32_t* freq = reinterpret_cast(data->data); + app::ManualEntryData* freq = reinterpret_cast(data->data); - LOG_F(1, "Setting manual frequency to %.4lfMHz", (*freq / 1E6)); + LOG_F(1, "Setting manual frequency to %.4lfMHz", (freq->freq / 1E6)); /* delete old manual entry */ //if(_manualEntry != nullptr) //delete _manualEntry; - _manualEntry = std::make_shared(*freq, "", false, false); + //TODO will replace with a function map probably + if(freq->modulation == "FM") + _manualEntry = make_shared(freq->freq, "", false, 0); + else if(freq->modulation == "AM") + _manualEntry = make_shared(freq->freq, "", false, 0); + else{ + LOG_F(WARNING, "Invalid manual entry modulation: %s", freq->modulation.c_str()); + _manualEntry = make_shared(freq->freq, "", false, 0); + } delete freq; _currentEntry = _manualEntry; _externalHold = true; @@ -252,7 +280,7 @@ void ScannerSM::ST_SaveAll(EventData* data){ void ScannerSM::ST_Stopped(EventData* data){ DLOG_F(9, "ST_Stopped"); stop(false); - //auto message = std::make_shared(SCANNER_SM, ControllerMessage::NOTIFY_STOPPED); + //auto message = make_shared(SCANNER_SM, ControllerMessage::NOTIFY_STOPPED); //_centralQueue.giveMessage(message); LOG_F(1, "ScannerSM stopped"); notifyDeinit(); @@ -260,7 +288,7 @@ void ScannerSM::ST_Stopped(EventData* data){ void ScannerSM::_broadcastContextUpdate() { DLOG_F(6, "Broadcasting context"); - std::lock_guard lock(_contextMutex); + lock_guard lock(_contextMutex); if (_currentContext.state != ScannerContext::SCAN) { if (_manualMode) @@ -274,26 +302,29 @@ void ScannerSM::_broadcastContextUpdate() { //_currentContext.systemTag = _currentSystem->tag(); _currentContext.systemTag = _systems[_currentEntry->getSysIndex()]->tag(); _currentContext.entryTag = _currentEntry->tag(); - _currentContext.entryIndex = std::to_string(_currentEntry->getSysIndex()) + "-" + std::to_string(_currentEntry->getEntryIndex()); + _currentContext.entryIndex = to_string(_currentEntry->getSysIndex()) + "-" + to_string(_currentEntry->getEntryIndex()); } _currentContext.frequency = _currentEntry->freq(); _currentContext.modulation = _currentEntry->modulation(); + _currentContext.delayMS = _currentEntry->delayMS(); + _currentContext.lockout = _currentEntry->isLockedOut(); } else { _currentContext.clearFields(); } - auto message = std::make_shared(SCANNER_SM, ServerMessage::CONTEXT_UPDATE, new ScannerContext(_currentContext)); + //auto message = make_shared(SCANNER_SM, ServerMessage::CONTEXT_UPDATE, new ScannerContext(_currentContext)); - _centralQueue.giveMessage(message); + //_centralQueue.giveMessage(message); + app::scannerContextUpdate(_currentContext); } void ScannerSM::_enableAudioOut(bool en){ app::audioMute(en); } -void ScannerSM::giveMessage(std::shared_ptr message) { - auto msg = std::dynamic_pointer_cast(message); +void ScannerSM::giveMessage(shared_ptr message) { + auto msg = dynamic_pointer_cast(message); DLOG_F(7, "Message rcv - src:%i | type:%i", msg->source, msg->type); @@ -336,22 +367,22 @@ void ScannerSM::_handleRequest(ClientRequest& request) { break; case SCANNER_STATE_HOLD: if(request.pData != nullptr){ - std::vector* indexData = reinterpret_cast*>(request.pData); + vector* indexData = reinterpret_cast*>(request.pData); holdScan(*indexData); delete indexData; } else holdScan(); break; - case SCANNER_STATE_MANUAL: + /*case SCANNER_STATE_MANUAL: manualEntry(reinterpret_cast(rq->pData)); - break; + break;*/ default: break; } } else if (rq->rqInfo.type == GET_CONTEXT){ - std::unique_lock lock(_contextMutex); + unique_lock lock(_contextMutex); ScannerContext* context = new ScannerContext(_currentContext); lock.unlock(); rq->connection->scannerContextRequestCallback(rq->rqHandle, context); @@ -364,6 +395,6 @@ void ScannerSM::_handleRequest(ClientRequest& request) { } ScannerContext ScannerSM::getCurrentContext(){ - std::unique_lock lock(_contextMutex); + unique_lock lock(_contextMutex); return ScannerContext(_currentContext); } diff --git a/src/core/ScannerSM.h b/src/core/ScannerSM.h index e69b987..2fa3c7f 100644 --- a/src/core/ScannerSM.h +++ b/src/core/ScannerSM.h @@ -9,6 +9,7 @@ #define SERVER_SCANNERSTATEMACHINE_H_ #include +#include #include "StateMachine.h" #include "SystemList.h" @@ -19,6 +20,14 @@ namespace piscan { +using namespace std; +using namespace std::chrono; + +// forward declaration +namespace app{ + struct ManualEntryData; +}; + class ScannerSM: public MessageReceiver, public StateMachine, public Synchronizable { public: ScannerSM(MessageReceiver& central, SystemList& dataSource); @@ -27,7 +36,7 @@ public: void startScan(); void holdScan(std::vector index = std::vector()); void stopScanner(); - void manualEntry(uint32_t* freq); + void manualEntry(app::ManualEntryData* freq); void giveMessage(std::shared_ptr message); ScannerContext getCurrentContext(); @@ -67,17 +76,17 @@ private: //moodycamel::ReaderWriterQueue _msgQueue; SystemList& _systems; //RadioSystem* _currentSystem; - std::shared_ptr _currentEntry; - std::shared_ptr _manualEntry; + shared_ptr _currentEntry; + shared_ptr _manualEntry; //size_t _sysCounter = 0, _entryCounter = 0; ScannerContext _currentContext; - std::mutex _contextMutex; + mutex _contextMutex; - std::atomic_bool _externalHold; - std::atomic_bool _manualMode; - std::mutex _holdMutex; - std::vector _holdIndex; - std::time_t timeoutStart = 0; + atomic_bool _externalHold; + atomic_bool _manualMode; + mutex _holdMutex; + vector _holdIndex; + time_point timeoutStart; int _squelchHits = 0; diff --git a/src/core/clientmessage.h b/src/core/clientmessage.h index 0dbde95..d940fe3 100644 --- a/src/core/clientmessage.h +++ b/src/core/clientmessage.h @@ -54,6 +54,7 @@ struct ScannerContext { std::string modulation; std::string entryIndex; int delayMS = 0; + bool lockout = false; }; diff --git a/src/core/constants.h b/src/core/constants.h index 46d2e00..44e76dd 100644 --- a/src/core/constants.h +++ b/src/core/constants.h @@ -13,7 +13,7 @@ namespace piscan { #define TUNER_RETUNE_TIME 225000 -#define DEMOD_BUFFER_TIME 7000 +#define DEMOD_BUFFER_TIME 10000 enum ConnectionLevel { RECEIVE_ONLY = 0, VIEWER, FULL_CONTROL, diff --git a/src/piScan_backend.cpp b/src/piScan_backend.cpp index 6250038..6c5fc6c 100644 --- a/src/piScan_backend.cpp +++ b/src/piScan_backend.cpp @@ -351,7 +351,7 @@ void app::stopScanner(){ scanner.stopScanner(); } -void app::manualEntry(uint32_t* freq){ +void app::manualEntry(app::ManualEntryData* freq){ scanner.manualEntry(freq); } @@ -383,12 +383,20 @@ const SystemInfo app::getSystemInfo(){ SystemInfo info = { .version = "debug", .buildNumber = 0, - .squelchRange = {-100, 0}, + .squelchRange = {0, 100}, .supportedModulations = {"FM", "AM"}, }; return info; } +void app::scannerContextUpdate(ScannerContext ctx){ + connectionManager.giveMessage(make_shared(SCANNER_SM, ServerMessage::CONTEXT_UPDATE, new ScannerContext(ctx))); +} + +void app::demodContextUpdate(DemodContext ctx){ + connectionManager.giveMessage(make_shared(DEMOD, ServerMessage::CONTEXT_UPDATE, new DemodContext(ctx))); +} + } using namespace piscan; @@ -417,7 +425,7 @@ int main(int argc, char **argv) { break; case 'p': if(optarg) - config.setWorkingPath(std::string(optarg)); + config.setWorkingDirectory(std::string(optarg)); break; case 'f': if(optarg) @@ -433,7 +441,8 @@ int main(int argc, char **argv) { config.loadConfig(); config.loadState(); - loguru::add_file(config.getLogfilePath().c_str(), loguru::Truncate, logVerbosity); + loguru::add_file(config.getDatedLogPath().c_str(), loguru::Truncate, logVerbosity); + loguru::add_file(config.getLatestLogPath().c_str(), loguru::Truncate, logVerbosity); messageManager.setReceiver(SYSTEM_CONTROL, &sysControl); messageManager.setReceiver(SCANNER_SM, &scanner); diff --git a/src/scan/Entry.h b/src/scan/Entry.h index 824341b..bb6bb71 100644 --- a/src/scan/Entry.h +++ b/src/scan/Entry.h @@ -8,6 +8,7 @@ #ifndef SCAN_ENTRY_H_ #define SCAN_ENTRY_H_ +#include #include #include "scandefs.h" @@ -54,8 +55,9 @@ public: std::string tag() { return _tag; } virtual std::string modulation() = 0; - bool isLockedOut() { return _lockout != LOCKOUT_NONE; } - int delay() { return _scanDelayMS; } + bool isLockedOut() { return _lockout.load() != LOCKOUT_NONE; } + double delay() { return _scanDelayMS/1000.0; } + int delayMS() { return _scanDelayMS; } void lockout(bool val = true) { //_lockedOut = val; _lockout = (val) ? LOCKOUT_PERSIST : LOCKOUT_NONE; @@ -76,7 +78,7 @@ public: private: std::string _tag; - LockoutType _lockout; + std::atomic _lockout; int _scanDelayMS; size_t _sysIndex = 0; size_t _entryIndex = 0; @@ -135,31 +137,45 @@ public: /* for analog FM channels utilizing CTCSS tones */ class PLChannel: public FMChannel { public: - PLChannel(long long freq, float tn, std::string tag, bool lo, int del) : - FMChannel(freq, tag, lo, del), tone(tn) { + PLChannel(long long freq, std::string tn, std::string tag, bool lo, int del) : + FMChannel(freq, tag, lo, del), s_tone(tn) { + try{ + tone = std::stof(tn); + } catch (std::exception& e) { + tone = 0; + } propertyTree.put(CHAN_TYPE_KEY, PL_CHANNEL_HASH); propertyTree.put(TONE_KEY, tn); } ~PLChannel() {}; //bool hasSignal(); + + virtual std::string modulation() { + return "PL" + s_tone; + } protected: - const float tone; + std::string s_tone; + float tone; }; /* for analog FM channels uitlizing DCS squelch */ class DCChannel : public FMChannel { public: - DCChannel(long long freq, unsigned int tn, std::string tag, bool lo, int del) : - FMChannel(freq, tag, lo, del), code(tn) { + DCChannel(long long freq, std::string tn, std::string tag, bool lo, int del) : + FMChannel(freq, tag, lo, del), s_code(tn) { propertyTree.put(CHAN_TYPE_KEY, DC_CHANNEL_HASH); propertyTree.put(CODE_KEY, tn); } ~DCChannel() {}; //bool hasSignal(); + + virtual std::string modulation() { + return "DC" + s_code; + } protected: - const unsigned int code; + const std::string s_code; }; /* for analog AM channels, does not include SSB, DSB or CW modes */ diff --git a/src/scan/RadioSystem.cpp b/src/scan/RadioSystem.cpp index c9bbfb5..0925737 100644 --- a/src/scan/RadioSystem.cpp +++ b/src/scan/RadioSystem.cpp @@ -24,7 +24,7 @@ EntryPtr RadioSystem::makeFMChannel(ptree& pt) { std::string tag = pt.get(TAG_KEY, ""); long long freq = pt.get(FREQ_KEY, 0); bool lockout = pt.get(LOCKOUT_KEY, false); - int delay = pt.get(DELAY_KEY, 0.0); + int delay = pt.get(DELAY_KEY, 0); if(freq == 0) return nullptr; @@ -35,7 +35,7 @@ EntryPtr RadioSystem::makeAMChannel(ptree& pt) { std::string tag = pt.get(TAG_KEY, ""); long long freq = pt.get(FREQ_KEY, 0); bool lockout = pt.get(LOCKOUT_KEY, false); - int delay = pt.get(DELAY_KEY, 0.0); + int delay = pt.get(DELAY_KEY, 0); if(freq == 0) return nullptr; @@ -46,11 +46,11 @@ EntryPtr RadioSystem::makePLChannel(ptree& pt) { std::string tag = pt.get(TAG_KEY, ""); long long freq = pt.get(FREQ_KEY, 0); bool lockout = pt.get(LOCKOUT_KEY, false); - int delay = pt.get(DELAY_KEY, 0.0); + int delay = pt.get(DELAY_KEY, 0); if(freq == 0) return nullptr; - float tone = pt.get(TONE_KEY, 0.0); + std::string tone = pt.get(TONE_KEY, ""); return std::make_shared(freq, tone, tag, lockout, delay); } @@ -58,11 +58,11 @@ EntryPtr RadioSystem::makeDCChannel(ptree& pt) { std::string tag = pt.get(TAG_KEY, ""); long long freq = pt.get(FREQ_KEY, 0); bool lockout = pt.get(LOCKOUT_KEY, false); - int delay = pt.get(DELAY_KEY, 0.0); + int delay = pt.get(DELAY_KEY, 0); if(freq == 0) return nullptr; - unsigned int code = pt.get(CODE_KEY, 0); + std::string code = pt.get(CODE_KEY, ""); return std::make_shared(freq, code, tag, lockout, delay); } diff --git a/src/scan/SentinelFile.cpp b/src/scan/SentinelFile.cpp index 72973c1..34019ac 100644 --- a/src/scan/SentinelFile.cpp +++ b/src/scan/SentinelFile.cpp @@ -21,6 +21,9 @@ #define SENTINEL_NFM "NFM" #define SENTINEL_FM "FM" #define SENTINEL_AUTO "AUTO" +#define SENTINEL_AM "AM" +#define SENTINEL_CSQ "" +#define SENTINEL_TONE_PRE "TONE=" #define C_GROUP "C-Group" #define C_GROUP_TAG_POS 1 @@ -93,23 +96,54 @@ void SentinelFile::_newAnalogEntry(std::vector& tokens){ if(_system == nullptr) return; - std::string& tag = tokens[C_FREQ_TAG_POS]; - std::string& lockout = tokens[C_FREQ_LO_POS]; - std::string& freq = tokens[C_FREQ_FREQ_POS]; - std::string& mode = tokens[C_FREQ_MODE_POS]; - //std::string& tone = tokens[C_FREQ_TONE_POS]; - std::string& delay = tokens[C_FREQ_DELAY_POS]; + std::string& s_tag = tokens[C_FREQ_TAG_POS]; + std::string& s_lockout = tokens[C_FREQ_LO_POS]; + std::string& s_freq = tokens[C_FREQ_FREQ_POS]; + std::string& s_mode = tokens[C_FREQ_MODE_POS]; + std::string& s_tone = tokens[C_FREQ_TONE_POS]; + std::string& s_delay = tokens[C_FREQ_DELAY_POS]; - LOG_F(4, "Entry: %s - Freq: %s", tag.c_str(), freq.c_str()); + LOG_F(4, "Entry: %s - Freq: %s", s_tag.c_str(), s_freq.c_str()); - if(!mode.compare(SENTINEL_NFM) || !mode.compare(SENTINEL_FM) || !mode.compare(SENTINEL_AUTO)) { - auto entry = std::make_shared(std::stoul(freq), tag, - (!lockout.compare(SENTINEL_TRUE)), (delay.compare("0"))); + long long freq = std::stoll(s_freq); + bool lockout = !s_lockout.compare(SENTINEL_TRUE); + int delayMS = std::stoi(s_delay) * 1000; - entry->setSysIndex(_list->size() - 1); - entry->setEntryIndex(_system->size()); + EntryPtr newEntry; - _system->addEntry(entry); + if(!s_mode.compare(SENTINEL_NFM) || !s_mode.compare(SENTINEL_FM) || !s_mode.compare(SENTINEL_AUTO)) { + if(!s_tone.compare(SENTINEL_CSQ)){ + LOG_F(5, "Using CSQ"); + newEntry = std::make_shared(freq, s_tag, lockout, delayMS); + } + else if (!s_tone.substr(0, 5).compare(SENTINEL_TONE_PRE)){ + std::string tone_coded = s_tone.substr(5); + std::string tone = tone_coded.substr(1); + LOG_F(5, "Found tone %s", tone_coded.c_str()); + if(tone_coded.at(0) == 'C'){ + LOG_F(5, "CTCSS tone %s", tone.c_str()); + newEntry = std::make_shared(freq, tone, s_tag, lockout, delayMS); + } + else if(tone_coded.at(0) == 'D'){ + LOG_F(5, "DCS tone %s", tone.c_str()); + newEntry = std::make_shared(freq, tone, s_tag, lockout, delayMS); + } + else{ + LOG_F(5, "Unknown code, default to CSQ"); + newEntry = std::make_shared(freq, s_tag, lockout, delayMS); + } + } + + } + else if(!s_mode.compare(SENTINEL_AM)){ + newEntry = std::make_shared(freq, s_tag, lockout, delayMS); + } + + if (newEntry) + { + newEntry->setSysIndex(_list->size() - 1); + newEntry->setEntryIndex(_system->size()); + _system->addEntry(newEntry); } } @@ -142,7 +176,7 @@ int main(int argc, char** argv){ break; case 'o': if(optarg) - config.setWorkingPath(std::string(optarg)); + config.setWorkingDirectory(std::string(optarg)); else usage(); break; diff --git a/src/scan/SystemList.cpp b/src/scan/SystemList.cpp index c4e7bfa..4378cbe 100644 --- a/src/scan/SystemList.cpp +++ b/src/scan/SystemList.cpp @@ -31,7 +31,7 @@ SystemList::~SystemList() { } void SystemList::populateFromFile(){ - filesystem::path path(Configuration::getConfig().getWorkingPath()); + filesystem::path path(Configuration::getConfig().getWorkingDirectory()); path += filesystem::path::preferred_separator; path += SYSTEMS_FILE; if(!filesystem::exists(path)){ @@ -58,7 +58,7 @@ void SystemList::populateFromFile(){ try{ system = _makeSystem[sysType](newSystem, size()); - LOG_F(1, "Added %s system %s", sysType.c_str(), system->tag()); + LOG_F(1, "Added %s system %s", sysType.c_str(), system->tag().c_str()); } catch (std::exception& e) { LOG_F(WARNING, "Unrecognized or unsupported system type: %s", sysType.c_str()); continue; @@ -71,7 +71,7 @@ void SystemList::populateFromFile(){ } bool SystemList::writeToFile(){ - filesystem::path path(Configuration::getConfig().getWorkingPath()); + filesystem::path path(Configuration::getConfig().getWorkingDirectory()); path += filesystem::path::preferred_separator; path += SYSTEMS_FILE; @@ -99,21 +99,28 @@ EntryPtr SystemList::getEntryByIndex(std::vector index){ } EntryPtr SystemList::getNextEntry(){ - if(_entryNum == 0 && _retune){ - _retune = false; - //if(_bins[_binNum]->size() > 1) - return std::make_shared(_bins[_binNum]->getCenterFreq()); - } + EntryPtr entry; - auto entry = _bins[_binNum]->at(_entryNum); + /* TODO this will run infinitely if everything is locked out */ + do { + if (_entryNum == 0 && _retune) { + _retune = false; + //if(_bins[_binNum]->size() > 1) + for(;_bins[_binNum]->entriesLockedOut();_binNum = (_binNum + 1) % _bins.size()); - _entryNum = (_entryNum + 1) % _bins[_binNum]->size(); + entry = std::make_shared( + _bins[_binNum]->getCenterFreq()); + } else { + entry = _bins[_binNum]->at(_entryNum); - if(_entryNum == 0){ - _binNum = (_binNum + 1) % _bins.size(); - _retune = true; - } + _entryNum = (_entryNum + 1) % _bins[_binNum]->size(); + if (_entryNum == 0) { + _binNum = (_binNum + 1) % _bins.size(); + _retune = true; + } + } + } while (entry->isLockedOut() || _systems[entry->getSysIndex()]->lockedOut()); return entry; } @@ -121,6 +128,11 @@ EntryPtr SystemList::getNextEntry(){ void SystemList::sortBins(long long bandwidth){ LOG_F(1, "Sorting bandwidth chunks..."); + if(this->size() == 0){ + LOG_F(1, "System list is empty, nothing to sort"); + return; + } + size_t numEntries = 0; for(size_t i = 0; i < _systems.size(); i++) for(size_t k = 0; k < _systems[i]->size(); k++) @@ -132,7 +144,7 @@ void SystemList::sortBins(long long bandwidth){ for(size_t i = 0; i < _systems.size(); i++) for(size_t k = 0; k < _systems[i]->size(); k++){ //entries.push_back(_systems[i]->operator [](k)); - entries[numEntries] = _systems[i]->operator [](k); + entries[numEntries] = (*_systems[i])[k]; numEntries++; } @@ -150,6 +162,8 @@ void SystemList::sortBins(long long bandwidth){ if(entries[i]->freq() < lastFreq) LOG_F(WARNING, "Entries not sorted properly!"); lastFreq = entries[i]->freq(); + if(entries[i]->isLockedOut() || _systems[entries[i]->getSysIndex()]->lockedOut()) + newBin->lockedEntries++; newBin->push_back(entries[i]); } diff --git a/src/scan/SystemList.h b/src/scan/SystemList.h index 05bf77c..17e8f7a 100644 --- a/src/scan/SystemList.h +++ b/src/scan/SystemList.h @@ -49,6 +49,10 @@ private: void sort(); long getCenterFreq(); + + bool entriesLockedOut(){ return (lockedEntries == size()); }; + + size_t lockedEntries = 0; }; ptree _jsonTree; diff --git a/src/server/Connection.cpp b/src/server/Connection.cpp index 96072b0..2e189b0 100644 --- a/src/server/Connection.cpp +++ b/src/server/Connection.cpp @@ -93,10 +93,11 @@ int Connection::scanHoldEntry(std::vector index) { return 0; } -int Connection::scanManualEntry(long freq, Modulation mode) { +int Connection::scanManualEntry(long freq, std::string mode) { //ClientRequest::RequestParams params = { .type = SCANNER_FUNCTION, .subType = SCANNER_STATE_MANUAL }; - //return issueRequest(params, new uint32_t(freq)); - app::manualEntry(new uint32_t(freq)); + //return issueRequest(params, new uint32_t(freq));3 + auto data = new app::ManualEntryData(freq, mode); + app::manualEntry(data); return 0; } diff --git a/src/server/DebugServer.cpp b/src/server/DebugServer.cpp index ffcaf22..12a6e81 100644 --- a/src/server/DebugServer.cpp +++ b/src/server/DebugServer.cpp @@ -99,7 +99,10 @@ void DebugConsole::_consoleInputFunc() { else getDemodContext(); } else if (!tokens[0].compare("manual")) { - scanManualEntry(std::stof(tokens[1])); + if(tokens.size() > 2) + scanManualEntry(std::stof(tokens[1]), tokens[2]); + else + scanManualEntry(std::stof(tokens[1])); } else if (!tokens[0].compare("get")){ if(!tokens[1].compare("context")) @@ -139,12 +142,14 @@ void DebugConsole::contextUpdate(ScannerContext context){ case ScannerContext::HOLD: std::cerr << "\rHold: " << context.entryIndex << " | " << context.systemTag << " | " - << context.entryTag << " | " << (context.frequency / 1E6) << "MHz\n"; + << context.entryTag << " | " << (context.frequency / 1E6) << "MHz | " + << "LO: " << context.lockout << "\n"; break; case ScannerContext::RECEIVE: std::cerr << "\rReceive: " << context.entryIndex << " | " << context.systemTag << " | " - << context.entryTag << " | " << (context.frequency / 1E6) << "MHz\n"; + << context.entryTag << " | " << (context.frequency / 1E6) << "MHz | " + << "LO: " << context.lockout << "\n"; break; default: break; diff --git a/src/server/connection.h b/src/server/connection.h index d17ea85..0bcd2b4 100644 --- a/src/server/connection.h +++ b/src/server/connection.h @@ -109,7 +109,7 @@ protected: int scanStart(); int scanHold(); int scanHoldEntry(std::vector index); - int scanManualEntry(long freq, Modulation mode = FM); + int scanManualEntry(long freq, std::string mode = "FM"); int setDemodSquelch(int level); int setDemodGain(float level); int getScannerContext(); diff --git a/src/sigproc/Demodulator.cpp b/src/sigproc/Demodulator.cpp index 7afcd2e..b264c89 100644 --- a/src/sigproc/Demodulator.cpp +++ b/src/sigproc/Demodulator.cpp @@ -7,6 +7,7 @@ #include +#include "PiScan.h" #include "Demodulator.h" #include "loguru.hpp" @@ -29,19 +30,19 @@ void Demodulator::start(){ std::vector* devs = _cubic->getDevices(); - CHECK_F(devs->size() > 0); + CHECK_F(devs->size() > 0, "No SDR devices are available"); //TODO config file for this LOG_F(INFO, "Auto-selecting SDR device"); size_t i; for(i = 0; i < devs->size();){ - if(devs->at(i)->getDriver() != "audio") + if(devs->at(i)->getDriver() != "audio" && devs->at(i)->isAvailable()) break; i++; } - CHECK_F(i < devs->size()); + CHECK_F(i < devs->size(), "No valid or available devices found"); auto dev = devs->at(i); @@ -205,7 +206,12 @@ float Demodulator::getDecodedPL() { return 0; } unsigned int Demodulator::getDecodedDC() { return 0; } bool Demodulator::squelchThresholdMet() { - return (getSignalLevel() >= _squelchLevel); + //return (getSignalLevel() >= _squelchLevel); //dBm comparison + //return (getSignalStrength() >= _squelchLevel); //SNR + return (std::abs( + _demodMgr.getActiveContextModem()->getSignalLevel() + - _demodMgr.getActiveContextModem()->getSignalFloor()) + >= _squelchLevel); } bool Demodulator::setModem(Modulation mode) { @@ -214,6 +220,7 @@ bool Demodulator::setModem(Modulation mode) { _demods[mode]->setActive(true); _demodMgr.setActiveDemodulator(_demods[mode], false); + _demods[_currentModem]->setActive(false); _currentModem = mode; return true; } @@ -225,7 +232,11 @@ void Demodulator::setSquelch(float level) { } float Demodulator::getSNR() { - return (_demodMgr.getActiveContextModem()->getSignalFloor()/_demodMgr.getActiveContextModem()->getSignalLevel()); + float level = _demodMgr.getActiveContextModem()->getSignalLevel(); + float floor = _demodMgr.getActiveContextModem()->getSignalFloor(); + DRAW_LOG_F(7, "\t\t\tsiglevel %.1f\tfloor %.1f", level, floor); + return (100+level)/(100+floor); + //return (_demodMgr.getActiveContextModem()->getSignalFloor()/_demodMgr.getActiveContextModem()->getSignalLevel()); } int Demodulator::getSignalStrength() { @@ -233,7 +244,7 @@ int Demodulator::getSignalStrength() { int percent = 100*fractional; if(percent >= 100) return 100; - + DRAW_LOG_F(7, "\t\t\tsigstrength %i", percent); return percent; } @@ -293,8 +304,9 @@ void Demodulator::_handleRequest(ClientRequest& request){ } void Demodulator::_contextUpdate(){ - DemodContext* context = new DemodContext(_gain, _squelchLevel); - _centralQueue.giveMessage(std::make_shared(DEMOD, ServerMessage::CONTEXT_UPDATE, context)); + //DemodContext* context = new DemodContext(_gain, _squelchLevel); + //_centralQueue.giveMessage(std::make_shared(DEMOD, ServerMessage::CONTEXT_UPDATE, context)); + app::demodContextUpdate(DemodContext(_gain, _squelchLevel)); } void Demodulator::setTunerGain(float gain){