Added lockout and delay support to the scanner

This commit is contained in:
ezratl 2020-02-10 15:02:53 -05:00
parent 77f96b5871
commit bef4efa5b3
17 changed files with 272 additions and 113 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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<int> index = std::vector<int>());
void stopScanner();
void manualEntry(uint32_t* freq);
void manualEntry(ManualEntryData* freq);
ScannerContext getScannerContext();
/* demod functions */

View File

@ -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<int> index){
void ScannerSM::holdScan(vector<int> index){
_externalHold.store(true);
{
std::lock_guard<std::mutex> lock(_holdMutex);
lock_guard<mutex> 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<ControllerMessage>(SCANNER_SM, ControllerMessage::NOTIFY_READY);
//auto message = make_shared<ControllerMessage>(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<milliseconds>(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<milliseconds>(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<uint32_t*>(data->data);
app::ManualEntryData* freq = reinterpret_cast<app::ManualEntryData*>(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<FMChannel>(*freq, "", false, false);
//TODO will replace with a function map probably
if(freq->modulation == "FM")
_manualEntry = make_shared<FMChannel>(freq->freq, "", false, 0);
else if(freq->modulation == "AM")
_manualEntry = make_shared<AMChannel>(freq->freq, "", false, 0);
else{
LOG_F(WARNING, "Invalid manual entry modulation: %s", freq->modulation.c_str());
_manualEntry = make_shared<FMChannel>(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<ControllerMessage>(SCANNER_SM, ControllerMessage::NOTIFY_STOPPED);
//auto message = make_shared<ControllerMessage>(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<std::mutex> lock(_contextMutex);
lock_guard<mutex> 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<ServerMessage>(SCANNER_SM, ServerMessage::CONTEXT_UPDATE, new ScannerContext(_currentContext));
//auto message = make_shared<ServerMessage>(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> message) {
auto msg = std::dynamic_pointer_cast<ScannerMessage>(message);
void ScannerSM::giveMessage(shared_ptr<Message> message) {
auto msg = dynamic_pointer_cast<ScannerMessage>(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<int>* indexData = reinterpret_cast<std::vector<int>*>(request.pData);
vector<int>* indexData = reinterpret_cast<vector<int>*>(request.pData);
holdScan(*indexData);
delete indexData;
}
else
holdScan();
break;
case SCANNER_STATE_MANUAL:
/*case SCANNER_STATE_MANUAL:
manualEntry(reinterpret_cast<uint32_t*>(rq->pData));
break;
break;*/
default:
break;
}
}
else if (rq->rqInfo.type == GET_CONTEXT){
std::unique_lock<std::mutex> lock(_contextMutex);
unique_lock<mutex> 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<std::mutex> lock(_contextMutex);
unique_lock<mutex> lock(_contextMutex);
return ScannerContext(_currentContext);
}

View File

@ -9,6 +9,7 @@
#define SERVER_SCANNERSTATEMACHINE_H_
#include <ctime>
#include <chrono>
#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<int> index = std::vector<int>());
void stopScanner();
void manualEntry(uint32_t* freq);
void manualEntry(app::ManualEntryData* freq);
void giveMessage(std::shared_ptr<Message> message);
ScannerContext getCurrentContext();
@ -67,17 +76,17 @@ private:
//moodycamel::ReaderWriterQueue<Message> _msgQueue;
SystemList& _systems;
//RadioSystem* _currentSystem;
std::shared_ptr<Entry> _currentEntry;
std::shared_ptr<Entry> _manualEntry;
shared_ptr<Entry> _currentEntry;
shared_ptr<Entry> _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<int> _holdIndex;
std::time_t timeoutStart = 0;
atomic_bool _externalHold;
atomic_bool _manualMode;
mutex _holdMutex;
vector<int> _holdIndex;
time_point<system_clock, milliseconds> timeoutStart;
int _squelchHits = 0;

View File

@ -54,6 +54,7 @@ struct ScannerContext {
std::string modulation;
std::string entryIndex;
int delayMS = 0;
bool lockout = false;
};

View File

@ -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,

View File

@ -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<ServerMessage>(SCANNER_SM, ServerMessage::CONTEXT_UPDATE, new ScannerContext(ctx)));
}
void app::demodContextUpdate(DemodContext ctx){
connectionManager.giveMessage(make_shared<ServerMessage>(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);

View File

@ -8,6 +8,7 @@
#ifndef SCAN_ENTRY_H_
#define SCAN_ENTRY_H_
#include <exception>
#include <boost/property_tree/ptree.hpp>
#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<LockoutType> _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 */

View File

@ -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<PLChannel>(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<DCChannel>(freq, code, tag, lockout, delay);
}

View File

@ -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<std::string>& 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<FMChannel>(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<FMChannel>(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<PLChannel>(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<DCChannel>(freq, tone, s_tag, lockout, delayMS);
}
else{
LOG_F(5, "Unknown code, default to CSQ");
newEntry = std::make_shared<FMChannel>(freq, s_tag, lockout, delayMS);
}
}
}
else if(!s_mode.compare(SENTINEL_AM)){
newEntry = std::make_shared<AMChannel>(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;

View File

@ -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<int> index){
}
EntryPtr SystemList::getNextEntry(){
if(_entryNum == 0 && _retune){
_retune = false;
//if(_bins[_binNum]->size() > 1)
return std::make_shared<DummyChannel>(_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<DummyChannel>(
_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]);
}

View File

@ -49,6 +49,10 @@ private:
void sort();
long getCenterFreq();
bool entriesLockedOut(){ return (lockedEntries == size()); };
size_t lockedEntries = 0;
};
ptree _jsonTree;

View File

@ -93,10 +93,11 @@ int Connection::scanHoldEntry(std::vector<int> 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;
}

View File

@ -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;

View File

@ -109,7 +109,7 @@ protected:
int scanStart();
int scanHold();
int scanHoldEntry(std::vector<int> 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();

View File

@ -7,6 +7,7 @@
#include <unistd.h>
#include "PiScan.h"
#include "Demodulator.h"
#include "loguru.hpp"
@ -29,19 +30,19 @@ void Demodulator::start(){
std::vector<SDRDeviceInfo*>* 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<ServerMessage>(DEMOD, ServerMessage::CONTEXT_UPDATE, context));
//DemodContext* context = new DemodContext(_gain, _squelchLevel);
//_centralQueue.giveMessage(std::make_shared<ServerMessage>(DEMOD, ServerMessage::CONTEXT_UPDATE, context));
app::demodContextUpdate(DemodContext(_gain, _squelchLevel));
}
void Demodulator::setTunerGain(float gain){