Added lockout and delay support to the scanner
This commit is contained in:
parent
77f96b5871
commit
bef4efa5b3
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ struct ScannerContext {
|
|||
std::string modulation;
|
||||
std::string entryIndex;
|
||||
int delayMS = 0;
|
||||
bool lockout = false;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ private:
|
|||
|
||||
void sort();
|
||||
long getCenterFreq();
|
||||
|
||||
bool entriesLockedOut(){ return (lockedEntries == size()); };
|
||||
|
||||
size_t lockedEntries = 0;
|
||||
};
|
||||
|
||||
ptree _jsonTree;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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){
|
||||
|
|
|
|||
Loading…
Reference in New Issue