Compare commits
7 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
c8e88e8be2 | |
|
|
2beffedeea | |
|
|
111e443ec3 | |
|
|
d6e1ba6a5f | |
|
|
41a1b7ea3f | |
|
|
52d21935f9 | |
|
|
181b4eee2b |
|
|
@ -130,6 +130,7 @@ target_include_directories(common PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cubic/sdr)
|
||||||
target_include_directories(scan PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cubic/sdr)
|
target_include_directories(scan PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cubic/sdr)
|
||||||
|
|
||||||
target_sources(piscan_server PUBLIC
|
target_sources(piscan_server PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/EventBroker.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ScannerSM.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/ScannerSM.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ServerManager.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/ServerManager.cpp
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "EventBroker.h"
|
||||||
|
#include "events.h"
|
||||||
|
#include "loguru.hpp"
|
||||||
|
|
||||||
|
namespace piscan {
|
||||||
|
namespace events {
|
||||||
|
void publish(EventPtr event) {
|
||||||
|
EventBroker::instance()->publish(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subscribe(std::string topic, int subscriber, EventHandler handler){
|
||||||
|
EventBroker::instance()->subscribe(topic, subscriber, std::move(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
void unsubscribe(std::string topic, int subscriber){
|
||||||
|
EventBroker::instance()->unsubscribe(topic, subscriber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<EventBroker> EventBroker::_instance = nullptr;
|
||||||
|
std::shared_ptr<EventBroker> EventBroker::instance() {
|
||||||
|
if(!_instance){
|
||||||
|
_instance = std::make_shared<EventBroker>();
|
||||||
|
}
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventBroker::EventBroker() : WorkerThread("Event Broker") {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventBroker::publish(events::EventPtr event) {
|
||||||
|
_eventQueue.enqueue(event);
|
||||||
|
postWorkAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventBroker::subscribe(std::string topic, int subscriber, events::EventHandler handler) {
|
||||||
|
std::unique_lock<std::mutex> lock(_handler_mutex);
|
||||||
|
if (_handlers.find(topic) == _handlers.end()) {
|
||||||
|
_handlers[topic] = std::map<int, events::EventHandler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
_handlers[topic][subscriber] = std::move(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventBroker::unsubscribe(std::string topic, int subscriber) {
|
||||||
|
std::unique_lock<std::mutex> lock(_handler_mutex);
|
||||||
|
_handlers[topic].erase(subscriber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventBroker::main() {
|
||||||
|
events::EventPtr event;
|
||||||
|
if(!_eventQueue.try_dequeue(event)) {
|
||||||
|
workAvailable = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& topic = event->topic;
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(_handler_mutex);
|
||||||
|
// Support for regex subscriptions may be added later
|
||||||
|
auto found = _handlers.find(topic);
|
||||||
|
if (found != _handlers.end()){
|
||||||
|
for (auto handler = _handlers[topic].begin(); handler != _handlers[topic].end(); handler++){
|
||||||
|
try {
|
||||||
|
if ((*handler).second == nullptr) {
|
||||||
|
_handlers[topic].erase((*handler).first);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(*handler).second(event);
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
LOG_F(WARNING, "Invalid event handler encountered, deleting");
|
||||||
|
_handlers[topic].erase((*handler).first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 'All events' subscription
|
||||||
|
found = _handlers.find("*");
|
||||||
|
if (found != _handlers.end()){
|
||||||
|
for (auto handler = _handlers["*"].begin(); handler != _handlers["*"].end(); handler++){
|
||||||
|
try {
|
||||||
|
if ((*handler).second == nullptr) {
|
||||||
|
_handlers[topic].erase((*handler).first);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(*handler).second(event);
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
LOG_F(WARNING, "Invalid event handler encountered, deleting");
|
||||||
|
_handlers[topic].erase((*handler).first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "Thread.h"
|
||||||
|
#include "events.h"
|
||||||
|
#include "concurrentqueue.h"
|
||||||
|
|
||||||
|
namespace piscan {
|
||||||
|
|
||||||
|
class EventBroker : public WorkerThread {
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<EventBroker> instance();
|
||||||
|
|
||||||
|
EventBroker();
|
||||||
|
virtual ~EventBroker(){};
|
||||||
|
|
||||||
|
void publish(events::EventPtr event);
|
||||||
|
void subscribe(std::string topic, int subscriber, events::EventHandler handler);
|
||||||
|
void unsubscribe(std::string topic, int subscriber);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//EventBroker();
|
||||||
|
|
||||||
|
void main();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::shared_ptr<EventBroker> _instance;
|
||||||
|
|
||||||
|
moodycamel::ConcurrentQueue<events::EventPtr> _eventQueue;
|
||||||
|
|
||||||
|
std::map<std::string, std::map<int, events::EventHandler>> _handlers;
|
||||||
|
std::mutex _handler_mutex;
|
||||||
|
|
||||||
|
void _subscribe(std::string topic, int subscriber, events::EventHandler handler);
|
||||||
|
void _unsubscribe(std::string topic, int subscriber);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
147
src/PiScan.h
147
src/PiScan.h
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include "messages/context.h"
|
#include "messages/context.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
|
|
@ -15,6 +16,13 @@ class DemodInterface;
|
||||||
namespace piscan {
|
namespace piscan {
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
|
enum ReturnStatus {
|
||||||
|
SUCCESS,
|
||||||
|
INVALID,
|
||||||
|
NOT_IMPLEMENTED,
|
||||||
|
};
|
||||||
|
typedef std::tuple<ReturnStatus, void*> BasicReturnTuple;
|
||||||
|
|
||||||
struct ManualEntryData {
|
struct ManualEntryData {
|
||||||
public:
|
public:
|
||||||
ManualEntryData(ManualEntryData& copy) : freq(copy.freq), modulation(copy.modulation){};
|
ManualEntryData(ManualEntryData& copy) : freq(copy.freq), modulation(copy.modulation){};
|
||||||
|
|
@ -55,9 +63,9 @@ long long getTunerSampleRate();
|
||||||
|
|
||||||
/* server functions */
|
/* server functions */
|
||||||
namespace server {
|
namespace server {
|
||||||
void scannerContextUpdate(piscan::server::context::ScannerContext ctx);
|
/*void scannerContextUpdate(piscan::server::context::ScannerContext ctx);
|
||||||
void demodContextUpdate(piscan::server::context::DemodContext ctx);
|
void demodContextUpdate(piscan::server::context::DemodContext ctx);
|
||||||
void signalLevelUpdate(int level);
|
void signalLevelUpdate(int level);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* audio related */
|
/* audio related */
|
||||||
|
|
@ -65,5 +73,140 @@ namespace audio {
|
||||||
AudioThread* getAudioController();
|
AudioThread* getAudioController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* database */
|
||||||
|
namespace data {
|
||||||
|
/*
|
||||||
|
Retrieve the entire System tree
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getScanList(); //TODO
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve list of Systems and their indices, tags, and types
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getSystemList();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve tree of System and its Entries at index
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getSystemByIndex(size_t sys_index); //TODO
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve list of Entries within indexed System and their indices and descriptors
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getEntryList(size_t sys_index);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve Entry at index
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getEntryByIndex(size_t sys_index, size_t entry_index); //TODO
|
||||||
|
|
||||||
|
namespace system {
|
||||||
|
/*
|
||||||
|
Create a new Radio System
|
||||||
|
*/
|
||||||
|
BasicReturnTuple create(/*TODO data*/);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Replace the Radio System header at index. Entries will be retained unless the system type is changed.
|
||||||
|
*/
|
||||||
|
BasicReturnTuple replace(size_t sys_index /*, TODO new*/);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove the Radio System and its Entries at index. Indices of succeeding Systems will be updated upon success
|
||||||
|
*/
|
||||||
|
BasicReturnTuple remove(size_t sys_index);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set lockout status of System at index.
|
||||||
|
- '0' for unlocked
|
||||||
|
- '-1' for persistent lock
|
||||||
|
- '>1' lock for duration in seconds
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setLockout(size_t sys_index, int duration_seconds);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Move Radio System from original index to new index. All other indices are updated upon success
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setIndex(size_t original_sys_index, size_t new_sys_index);
|
||||||
|
|
||||||
|
namespace entry {
|
||||||
|
/*
|
||||||
|
Create a new Entry within the indexed System
|
||||||
|
*/
|
||||||
|
BasicReturnTuple create(size_t sys_index /*,TODO data*/);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Replace the Entry at index
|
||||||
|
*/
|
||||||
|
BasicReturnTuple replace(size_t sys_index, size_t entry_index /*, TODO new*/);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove the Entry at index. Succeeding indices within the System are updated upon success
|
||||||
|
*/
|
||||||
|
BasicReturnTuple remove(size_t sys_index, size_t entry_index);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set lockout status of Entry at index.
|
||||||
|
- '0' for unlocked
|
||||||
|
- '-1' for persistent lock
|
||||||
|
- '>1' lock for duration in seconds
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setLockout(size_t sys_index, size_t entry_index, int duration_seconds);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Move Entry within System from original index to new index. All other indices are updated upon success
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setIndex(size_t sys_index, size_t original_entry_index, size_t new_entry_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace configuration {
|
||||||
|
/*
|
||||||
|
Retrieve the full system configuration
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getFullConfig();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set the full system configuration. Requires restart
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setConfig(/*TODO*/);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve general configuration
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getGeneralConfig();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set the general configuration
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setGeneralConfig(/*TODO*/);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve configuration for demodulators
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getDemodConfig();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set the configuration for demodulators. Restart bit required
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setDemodConfig(/*TODO*/);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve configuration for RTSP server
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getAudioServerConfig();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set the configuration for RTSP server. Requires restart
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setAudioServerConfig(/*TODO*/);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve a list of configured tuners
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getTunerList();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
} // namespace piscan
|
} // namespace piscan
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "PiScan.h"
|
#include "PiScan.h"
|
||||||
#include "ScannerSM.h"
|
#include "ScannerSM.h"
|
||||||
|
|
@ -18,7 +19,7 @@
|
||||||
#include "RadioSystem.h"
|
#include "RadioSystem.h"
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
|
#include "events.h"
|
||||||
|
|
||||||
#define DELAY_TIMEOUT 2.0
|
#define DELAY_TIMEOUT 2.0
|
||||||
|
|
||||||
|
|
@ -334,6 +335,7 @@ void ScannerSM::ST_Stopped(EventData* /* data */){
|
||||||
|
|
||||||
void ScannerSM::_broadcastContextUpdate() {
|
void ScannerSM::_broadcastContextUpdate() {
|
||||||
DLOG_F(6, "Broadcasting context");
|
DLOG_F(6, "Broadcasting context");
|
||||||
|
// TODO old context remain until new request system setup
|
||||||
lock_guard<mutex> lock(_contextMutex);
|
lock_guard<mutex> lock(_contextMutex);
|
||||||
if (_currentContext.state != piscan::server::context::ScannerContext::SCAN)
|
if (_currentContext.state != piscan::server::context::ScannerContext::SCAN)
|
||||||
{
|
{
|
||||||
|
|
@ -359,7 +361,38 @@ void ScannerSM::_broadcastContextUpdate() {
|
||||||
_currentContext.clearFields();
|
_currentContext.clearFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
app::server::scannerContextUpdate(_currentContext);
|
/*app::server::scannerContextUpdate(_currentContext);*/
|
||||||
|
|
||||||
|
/* EVENT BASED IMPLEMENTATION */
|
||||||
|
events::ScannerStateEvent event;
|
||||||
|
std::map<unsigned char, events::ScannerStateEvent::ScannerState> states = {
|
||||||
|
std::make_pair(States::ST_HOLD, events::ScannerStateEvent::ScannerState::HOLD),
|
||||||
|
std::make_pair(States::ST_SCAN, events::ScannerStateEvent::ScannerState::SCAN),
|
||||||
|
std::make_pair(States::ST_RECEIVE, events::ScannerStateEvent::ScannerState::RECEIVE),
|
||||||
|
std::make_pair(States::ST_LOAD, events::ScannerStateEvent::ScannerState::OTHER_STATE),
|
||||||
|
std::make_pair(States::ST_INVALID, events::ScannerStateEvent::ScannerState::OTHER_STATE),
|
||||||
|
};
|
||||||
|
event.state = states[currentState];
|
||||||
|
if (currentState != States::ST_SCAN) {
|
||||||
|
if (_manualMode)
|
||||||
|
{
|
||||||
|
event.systemTag = "Manual";
|
||||||
|
event.entryTag = "Manual entry";
|
||||||
|
event.entryIndex = "MAN";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//event.systemTag = _currentSystem->tag();
|
||||||
|
event.systemTag = _systems[_currentEntry->getSysIndex()]->tag();
|
||||||
|
event.entryTag = _currentEntry->tag();
|
||||||
|
event.entryIndex = to_string(_currentEntry->getSysIndex()) + "-" + to_string(_currentEntry->getEntryIndex());
|
||||||
|
}
|
||||||
|
event.frequency = _currentEntry->freq();
|
||||||
|
event.modulation = _currentEntry->modulation();
|
||||||
|
event.delayMS = _currentEntry->delayMS();
|
||||||
|
event.lockout = _currentEntry->isLockedOut();
|
||||||
|
}
|
||||||
|
events::publish(std::make_shared<events::ScannerStateEvent>(std::move(event)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScannerSM::_enableAudioOut(bool en){
|
void ScannerSM::_enableAudioOut(bool en){
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ int ServerManager::giveRequest(void* request){
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerManager::_handleMessage(std::shared_ptr<Message> message){
|
void ServerManager::_handleMessage(std::shared_ptr<Message> message){
|
||||||
assert(message->destination == SERVER_MAN);
|
//assert(message->destination == SERVER_MAN);
|
||||||
auto msg = std::dynamic_pointer_cast<ServerMessage>(message);
|
auto msg = std::dynamic_pointer_cast<ServerMessage>(message);
|
||||||
int* level = nullptr;
|
int* level = nullptr;
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
add_library(common
|
add_library(common
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/config_api.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Configuration.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Configuration.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/State.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/State.cpp
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
#include "PiScan.h"
|
||||||
|
|
||||||
|
namespace piscan::app::configuration {
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getFullConfig()
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setConfig(/*TODO*/)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getGeneralConfig()
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setGeneralConfig(/*TODO*/)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getDemodConfig()
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setDemodConfig(/*TODO*/)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getAudioServerConfig()
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setAudioServerConfig(/*TODO*/)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getTunerList()
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "loguru.hpp"
|
#include "loguru.hpp"
|
||||||
#include "threadname.h"
|
#include "threadname.h"
|
||||||
#include "PiScan.h"
|
#include "PiScan.h"
|
||||||
|
#include "events.h"
|
||||||
|
|
||||||
#define SDR_THREAD_NAME "SDR Interface"
|
#define SDR_THREAD_NAME "SDR Interface"
|
||||||
|
|
||||||
|
|
@ -116,10 +117,13 @@ bool SDRThread::init() {
|
||||||
|
|
||||||
//4. Apply other settings: Frequency, PPM correction, Gains, Device-specific settings:
|
//4. Apply other settings: Frequency, PPM correction, Gains, Device-specific settings:
|
||||||
device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load());
|
device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load());
|
||||||
|
//TEMP
|
||||||
|
piscan::events::publish(std::make_shared<piscan::events::GenericNumberEvent>("tuner_frequency_set", frequency - offset.load()));
|
||||||
|
|
||||||
if (devInfo->hasCORR(SOAPY_SDR_RX, 0)) {
|
if (devInfo->hasCORR(SOAPY_SDR_RX, 0)) {
|
||||||
hasPPM.store(true);
|
hasPPM.store(true);
|
||||||
device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm.load());
|
device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm.load());
|
||||||
|
piscan::events::publish(std::make_shared<piscan::events::GenericNumberEvent>("tuner_ppm_set", ppm.load()));
|
||||||
} else {
|
} else {
|
||||||
hasPPM.store(false);
|
hasPPM.store(false);
|
||||||
}
|
}
|
||||||
|
|
@ -514,6 +518,7 @@ void SDRThread::updateSettings() {
|
||||||
|
|
||||||
if (ppm_changed.load() && hasPPM.load()) {
|
if (ppm_changed.load() && hasPPM.load()) {
|
||||||
device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm.load());
|
device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm.load());
|
||||||
|
piscan::events::publish(std::make_shared<piscan::events::GenericNumberEvent>("tuner_ppm_set", ppm.load()));
|
||||||
ppm_changed.store(false);
|
ppm_changed.store(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -521,8 +526,10 @@ void SDRThread::updateSettings() {
|
||||||
if (frequency_locked.load() && !frequency_lock_init.load()) {
|
if (frequency_locked.load() && !frequency_lock_init.load()) {
|
||||||
device->setFrequency(SOAPY_SDR_RX,0,"RF",lock_freq.load());
|
device->setFrequency(SOAPY_SDR_RX,0,"RF",lock_freq.load());
|
||||||
frequency_lock_init.store(true);
|
frequency_lock_init.store(true);
|
||||||
|
piscan::events::publish(std::make_shared<piscan::events::GenericNumberEvent>("tuner_frequency_set", lock_freq.load()));
|
||||||
} else if (!frequency_locked.load()) {
|
} else if (!frequency_locked.load()) {
|
||||||
device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency.load() - offset.load());
|
device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency.load() - offset.load());
|
||||||
|
piscan::events::publish(std::make_shared<piscan::events::GenericNumberEvent>("tuner_frequency_set", frequency.load() - offset.load()));
|
||||||
}
|
}
|
||||||
freq_changed.store(false);
|
freq_changed.store(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace piscan {
|
||||||
|
namespace events {
|
||||||
|
struct Event {
|
||||||
|
Event(std::string topic) : topic(topic) {};
|
||||||
|
virtual ~Event(){};
|
||||||
|
|
||||||
|
inline virtual std::string to_string() {
|
||||||
|
return "Event type: " + topic + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string topic;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<Event> EventPtr;
|
||||||
|
typedef std::function<void(std::shared_ptr<Event>)> EventHandler;
|
||||||
|
//typedef std::shared_ptr<EventHandler> EventHandler;
|
||||||
|
|
||||||
|
void publish(EventPtr event);
|
||||||
|
|
||||||
|
void subscribe(std::string topic, int subscriber, EventHandler handler);
|
||||||
|
|
||||||
|
void unsubscribe(std::string topic, int subscriber);
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
struct GenericStringEvent : public Event {
|
||||||
|
GenericStringEvent(std::string topic, std::string data) : Event(topic), data(data) {};
|
||||||
|
virtual ~GenericStringEvent() {};
|
||||||
|
inline virtual std::string to_string() {
|
||||||
|
return Event::to_string() + "\tData:\t" + data + "\n";
|
||||||
|
}
|
||||||
|
std::string data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GenericNumberEvent : public Event {
|
||||||
|
GenericNumberEvent(std::string topic, long long data) : Event(topic), data(data) {};
|
||||||
|
virtual ~GenericNumberEvent() {};
|
||||||
|
inline virtual std::string to_string() {
|
||||||
|
return Event::to_string() + "\tData:\t" + std::to_string(data) + "\n";
|
||||||
|
}
|
||||||
|
long long data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GenericBoolEvent : public Event {
|
||||||
|
GenericBoolEvent(std::string topic, bool data) : Event(topic), data(data) {};
|
||||||
|
virtual ~GenericBoolEvent() {};
|
||||||
|
inline virtual std::string to_string() {
|
||||||
|
return Event::to_string() + "\tData:\t" + std::to_string(data) + "\n";
|
||||||
|
}
|
||||||
|
bool data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScannerStateEvent : public Event {
|
||||||
|
virtual ~ScannerStateEvent() {};
|
||||||
|
|
||||||
|
enum ScannerState {
|
||||||
|
OTHER_STATE,
|
||||||
|
SCAN,
|
||||||
|
HOLD,
|
||||||
|
RECEIVE,
|
||||||
|
};
|
||||||
|
|
||||||
|
ScannerStateEvent() : Event("scanner_state_change") {};
|
||||||
|
|
||||||
|
inline virtual std::string to_string() {
|
||||||
|
std::string tail = (state == HOLD || state == RECEIVE)?
|
||||||
|
"\tSystem:\t" + systemTag + "\n" +
|
||||||
|
"\tEntry:\t" + entryTag + "\n" +
|
||||||
|
"\tFrequency:\t" + std::to_string(frequency) + "\n" +
|
||||||
|
"\tModulation:\t" + modulation + "\n" +
|
||||||
|
"\tIndex:\t" + entryIndex + "\n" +
|
||||||
|
"\tDelay:\t" + std::to_string(delayMS) + "\n" +
|
||||||
|
"\tLockout:\t" + std::to_string(lockout) + "\n"
|
||||||
|
: "";
|
||||||
|
return Event::to_string() +
|
||||||
|
"\tState:\t" + std::to_string(state) + "\n" + tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO ported from context messages
|
||||||
|
ScannerState state = OTHER_STATE;
|
||||||
|
std::string systemTag = "";
|
||||||
|
std::string entryTag = "";
|
||||||
|
long long frequency = 0;
|
||||||
|
std::string modulation = "";
|
||||||
|
std::string entryIndex = "";
|
||||||
|
int delayMS = 0;
|
||||||
|
bool lockout = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DemodStateEvent : public Event {
|
||||||
|
DemodStateEvent() : Event("demod_state_change") {};
|
||||||
|
virtual ~DemodStateEvent() {};
|
||||||
|
inline virtual std::string to_string() {
|
||||||
|
return Event::to_string() +
|
||||||
|
"\tTuner gain:\t" + std::to_string(tunerGainState) + "\n"
|
||||||
|
"\tSquelch:\t" + std::to_string(squelchState) + "\n";
|
||||||
|
}
|
||||||
|
float tunerGainState;
|
||||||
|
int squelchState;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SignalLevelEvent : public Event {
|
||||||
|
SignalLevelEvent(int level) : Event("signal_level"), level(level) {};
|
||||||
|
virtual ~SignalLevelEvent(){};
|
||||||
|
inline virtual std::string to_string() {
|
||||||
|
return Event::to_string() + "\tSignal level:\t" + std::to_string(level) + "\n";
|
||||||
|
}
|
||||||
|
int level;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LoggingEvent : public Event {
|
||||||
|
LoggingEvent(int level, std::string line) : Event("log_write"), level(level), line(line) {};
|
||||||
|
virtual ~LoggingEvent(){};
|
||||||
|
inline virtual std::string to_string() {
|
||||||
|
return Event::to_string() + "\t> " + line + "\n";
|
||||||
|
}
|
||||||
|
int level;
|
||||||
|
std::string line;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include "sigproc_types.h"
|
#include "sigproc_types.h"
|
||||||
#include "Demodulator.h"
|
#include "Demodulator.h"
|
||||||
#include "Entry.h"
|
#include "Entry.h"
|
||||||
|
#include "EventBroker.h"
|
||||||
#include "loguru.hpp"
|
#include "loguru.hpp"
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "ServerManager.h"
|
#include "ServerManager.h"
|
||||||
|
|
@ -55,6 +56,7 @@ static piscan::scan::SystemList scanSystems;
|
||||||
static ScannerSM scannerInst(scanSystems);
|
static ScannerSM scannerInst(scanSystems);
|
||||||
static ServerManager connectionManager(io_service);
|
static ServerManager connectionManager(io_service);
|
||||||
static piscan::sigproc::Demodulator demodInst;
|
static piscan::sigproc::Demodulator demodInst;
|
||||||
|
static std::shared_ptr<piscan::EventBroker> eventBroker = nullptr;
|
||||||
|
|
||||||
static std::atomic_bool steadyState(false);
|
static std::atomic_bool steadyState(false);
|
||||||
|
|
||||||
|
|
@ -103,10 +105,15 @@ void exit(int code){
|
||||||
std::exit(code);
|
std::exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printEvent(events::EventPtr event) {
|
||||||
|
std::cerr << event->to_string();
|
||||||
|
}
|
||||||
|
|
||||||
bool app::system::stopSystem(){
|
bool app::system::stopSystem(){
|
||||||
if(steadyState.load()){
|
if(steadyState.load()){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
sysRun = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,7 +180,7 @@ const piscan::server::context::SystemInfo app::system::getSystemInfo(){
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void app::server::scannerContextUpdate(piscan::server::context::ScannerContext ctx){
|
/*void app::server::scannerContextUpdate(piscan::server::context::ScannerContext ctx){
|
||||||
connectionManager.giveMessage(make_shared<ServerMessage>(SCANNER_SM, ServerMessage::CONTEXT_UPDATE, new piscan::server::context::ScannerContext(ctx)));
|
connectionManager.giveMessage(make_shared<ServerMessage>(SCANNER_SM, ServerMessage::CONTEXT_UPDATE, new piscan::server::context::ScannerContext(ctx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,7 +190,7 @@ void app::server::demodContextUpdate(piscan::server::context::DemodContext ctx){
|
||||||
|
|
||||||
void app::server::signalLevelUpdate(int level){
|
void app::server::signalLevelUpdate(int level){
|
||||||
connectionManager.giveMessage(make_shared<ServerMessage>(DEMOD, ServerMessage::SIGNAL_LEVEL, new int(level)));
|
connectionManager.giveMessage(make_shared<ServerMessage>(DEMOD, ServerMessage::SIGNAL_LEVEL, new int(level)));
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,6 +206,8 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
LOG_F(INFO, "Starting PiScan, version %s", PISCAN_VERSION);
|
LOG_F(INFO, "Starting PiScan, version %s", PISCAN_VERSION);
|
||||||
|
|
||||||
|
eventBroker = EventBroker::instance();
|
||||||
|
|
||||||
piscan::config::Configuration& config = piscan::config::Configuration::getConfig();
|
piscan::config::Configuration& config = piscan::config::Configuration::getConfig();
|
||||||
piscan::config::State& state = piscan::config::State::getState();
|
piscan::config::State& state = piscan::config::State::getState();
|
||||||
bool useDebugConsole = false;
|
bool useDebugConsole = false;
|
||||||
|
|
@ -207,7 +216,7 @@ int main(int argc, char **argv) {
|
||||||
int logVerbosity = config.getGeneralConfig().logfileVerbosity;
|
int logVerbosity = config.getGeneralConfig().logfileVerbosity;
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while((c = getopt(argc,argv,"dp:f:l")) != -1){
|
while((c = getopt(argc,argv,"dp:f:le:")) != -1){
|
||||||
switch(c){
|
switch(c){
|
||||||
case 'd':
|
case 'd':
|
||||||
useDebugConsole = true;
|
useDebugConsole = true;
|
||||||
|
|
@ -223,6 +232,9 @@ int main(int argc, char **argv) {
|
||||||
case 'l':
|
case 'l':
|
||||||
spawnClient = true;
|
spawnClient = true;
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
std::cerr << "**Subscribe to event " << optarg << std::endl;
|
||||||
|
events::subscribe(optarg, 1, printEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,6 +246,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
{
|
{
|
||||||
|
eventBroker->start();
|
||||||
scannerInst.start();
|
scannerInst.start();
|
||||||
connectionManager.start(useDebugConsole, spawnClient);
|
connectionManager.start(useDebugConsole, spawnClient);
|
||||||
demodInst.start();
|
demodInst.start();
|
||||||
|
|
@ -260,6 +273,8 @@ int main(int argc, char **argv) {
|
||||||
steadyState.store(true);
|
steadyState.store(true);
|
||||||
LOG_F(INFO, "System initialized");
|
LOG_F(INFO, "System initialized");
|
||||||
|
|
||||||
|
events::publish(std::make_shared<events::Event>("system_started"));
|
||||||
|
|
||||||
while(sysRun)
|
while(sysRun)
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
|
|
||||||
|
|
@ -267,6 +282,7 @@ int main(int argc, char **argv) {
|
||||||
steadyState.store(false);
|
steadyState.store(false);
|
||||||
try {
|
try {
|
||||||
//sysControl.stop();
|
//sysControl.stop();
|
||||||
|
events::publish(std::make_shared<events::Event>("system_stopping"));
|
||||||
|
|
||||||
{
|
{
|
||||||
LOG_F(INFO, "Stopping system");
|
LOG_F(INFO, "Stopping system");
|
||||||
|
|
@ -281,6 +297,9 @@ int main(int argc, char **argv) {
|
||||||
LOG_F(4, "demod wait");
|
LOG_F(4, "demod wait");
|
||||||
demodInst.waitDeinit();
|
demodInst.waitDeinit();
|
||||||
|
|
||||||
|
eventBroker->stop();
|
||||||
|
eventBroker->join();
|
||||||
|
|
||||||
LOG_F(2, "All modules stopped");
|
LOG_F(2, "All modules stopped");
|
||||||
}
|
}
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
add_library(scan
|
add_library(scan
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/api.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Entry.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Entry.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/RadioSystem.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/RadioSystem.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/SystemList.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/SystemList.cpp
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "PiScan.h"
|
||||||
|
|
||||||
|
namespace piscan::app::data
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Retrieve the entire System tree
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getScanList()
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve list of Systems and their indices, tags, and types
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getSystemList()
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve tree of System and its Entries at index
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getSystemByIndex(size_t sys_index)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
} //TODO
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve list of Entries within indexed System and their indices and descriptors
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getEntryList(size_t sys_index)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve Entry at index
|
||||||
|
*/
|
||||||
|
BasicReturnTuple getEntryByIndex(size_t sys_index, size_t entry_index)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
} //TODO
|
||||||
|
|
||||||
|
namespace system
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Create a new Radio System
|
||||||
|
*/
|
||||||
|
BasicReturnTuple create(/*TODO data*/)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Replace the Radio System header at index. Entries will be retained unless the system type is changed.
|
||||||
|
*/
|
||||||
|
BasicReturnTuple replace(size_t sys_index /*, TODO new*/)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove the Radio System and its Entries at index. Indices of succeeding Systems will be updated upon success
|
||||||
|
*/
|
||||||
|
BasicReturnTuple remove(size_t sys_index)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set lockout status of System at index.
|
||||||
|
- '0' for unlocked
|
||||||
|
- '-1' for persistent lock
|
||||||
|
- '>1' lock for duration in seconds
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setLockout(size_t sys_index, int duration_seconds)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Move Radio System from original index to new index. All other indices are updated upon success
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setIndex(size_t original_sys_index, size_t new_sys_index)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace entry
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Create a new Entry within the indexed System
|
||||||
|
*/
|
||||||
|
BasicReturnTuple create(size_t sys_index /*,TODO data*/)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Replace the Entry at index
|
||||||
|
*/
|
||||||
|
BasicReturnTuple replace(size_t sys_index, size_t entry_index /*, TODO new*/)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove the Entry at index. Succeeding indices within the System are updated upon success
|
||||||
|
*/
|
||||||
|
BasicReturnTuple remove(size_t sys_index, size_t entry_index)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set lockout status of Entry at index.
|
||||||
|
- '0' for unlocked
|
||||||
|
- '-1' for persistent lock
|
||||||
|
- '>1' lock for duration in seconds
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setLockout(size_t sys_index, size_t entry_index, int duration_seconds)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Move Entry within System from original index to new index. All other indices are updated upon success
|
||||||
|
*/
|
||||||
|
BasicReturnTuple setIndex(size_t sys_index, size_t original_entry_index, size_t new_entry_index)
|
||||||
|
{
|
||||||
|
return std::make_tuple(NOT_IMPLEMENTED, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,9 +5,14 @@
|
||||||
* Author: ezra
|
* Author: ezra
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "PiScan.h"
|
#include "PiScan.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
|
#include "events.h"
|
||||||
|
#include "messages/context.h"
|
||||||
|
|
||||||
namespace piscan {
|
namespace piscan {
|
||||||
namespace server {
|
namespace server {
|
||||||
|
|
@ -74,6 +79,43 @@ int Connection::systemFunction(SystemFunction function) {
|
||||||
return issueRequest(params);
|
return issueRequest(params);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
// TODO temporary workaround until new connection interfaces built
|
||||||
|
bool Connection::connect() {
|
||||||
|
events::subscribe("scanner_state_change", (1000+_handle), [this](events::EventPtr event){
|
||||||
|
auto evt = std::dynamic_pointer_cast<events::ScannerStateEvent>(event);
|
||||||
|
piscan::server::context::ScannerContext ctx;
|
||||||
|
ctx.state = static_cast<context::ScannerContext::ScannerState>(evt->state);
|
||||||
|
ctx.systemTag = evt->systemTag;
|
||||||
|
ctx.entryTag = evt->entryTag;
|
||||||
|
ctx.frequency = evt->frequency;
|
||||||
|
ctx.modulation = evt->modulation;
|
||||||
|
ctx.entryIndex = evt->entryIndex;
|
||||||
|
ctx.delayMS = evt->delayMS;
|
||||||
|
ctx.lockout = evt->lockout;
|
||||||
|
|
||||||
|
contextUpdate(ctx);
|
||||||
|
});
|
||||||
|
events::subscribe("demod_state_change", (1000+_handle), [this](events::EventPtr event){
|
||||||
|
auto evt = std::dynamic_pointer_cast<events::DemodStateEvent>(event);
|
||||||
|
piscan::server::context::DemodContext ctx(evt->tunerGainState, evt->squelchState);
|
||||||
|
|
||||||
|
contextUpdate(ctx);
|
||||||
|
});
|
||||||
|
events::subscribe("signal_level", (1000+_handle), [this](events::EventPtr event){
|
||||||
|
auto evt = std::dynamic_pointer_cast<events::SignalLevelEvent>(event);
|
||||||
|
|
||||||
|
handleSignalLevel(evt->level);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::disconnect() {
|
||||||
|
events::unsubscribe("scanner_state_change", (1000+_handle));
|
||||||
|
events::unsubscribe("demod_state_change", (1000+_handle));
|
||||||
|
events::unsubscribe("signal_level", (1000+_handle));
|
||||||
|
}
|
||||||
|
|
||||||
int Connection::scanStart() {
|
int Connection::scanStart() {
|
||||||
//ClientRequest::RequestParams params = { .type = SCANNER_FUNCTION, .subType = SCANNER_STATE_SCAN };
|
//ClientRequest::RequestParams params = { .type = SCANNER_FUNCTION, .subType = SCANNER_STATE_SCAN };
|
||||||
//return issueRequest(params);
|
//return issueRequest(params);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "PiScan.h"
|
||||||
#include "DebugServer.h"
|
#include "DebugServer.h"
|
||||||
#include "loguru.hpp"
|
#include "loguru.hpp"
|
||||||
#include "threadname.h"
|
#include "threadname.h"
|
||||||
|
|
@ -24,8 +25,10 @@ namespace connection {
|
||||||
#define DS_THREAD_NAME "DebugConsole"
|
#define DS_THREAD_NAME "DebugConsole"
|
||||||
|
|
||||||
using namespace piscan;
|
using namespace piscan;
|
||||||
|
using piscan::app::BasicReturnTuple;
|
||||||
|
|
||||||
bool DebugConsole::connect(){
|
bool DebugConsole::connect(){
|
||||||
|
Connection::connect();
|
||||||
std::cerr << "\nConnecting...\n";
|
std::cerr << "\nConnecting...\n";
|
||||||
_run = true;
|
_run = true;
|
||||||
_requestThread = std::thread(&DebugConsole::_consoleInputFunc, this);
|
_requestThread = std::thread(&DebugConsole::_consoleInputFunc, this);
|
||||||
|
|
@ -33,6 +36,7 @@ bool DebugConsole::connect(){
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugConsole::disconnect(){
|
void DebugConsole::disconnect(){
|
||||||
|
Connection::disconnect();
|
||||||
_run = false;
|
_run = false;
|
||||||
|
|
||||||
std::fprintf(stdin, "\n");
|
std::fprintf(stdin, "\n");
|
||||||
|
|
@ -49,6 +53,37 @@ void DebugConsole::_consoleInputFunc() {
|
||||||
std::string intermediate;
|
std::string intermediate;
|
||||||
std::cerr << "\nConsole connected\n";
|
std::cerr << "\nConsole connected\n";
|
||||||
|
|
||||||
|
std::map<app::ReturnStatus, std::string> friendlyReturnCodes;
|
||||||
|
friendlyReturnCodes[app::SUCCESS] = "Success";
|
||||||
|
friendlyReturnCodes[app::INVALID] = "Invalid parameters";
|
||||||
|
friendlyReturnCodes[app::NOT_IMPLEMENTED] = "Function not yet implemented";
|
||||||
|
|
||||||
|
std::map<std::string, std::function<piscan::app::BasicReturnTuple()>> apiMap;
|
||||||
|
apiMap["scanlist"] = []() { return app::data::getScanList(); };
|
||||||
|
apiMap["systems"] = []() { return app::data::getSystemList(); };
|
||||||
|
apiMap["systemat"] = [tokens]() { return app::data::getSystemByIndex(std::stoi(tokens[1])); };
|
||||||
|
apiMap["entrylist"] = [tokens]() { return app::data::getEntryList(std::stoi(tokens[1])); };
|
||||||
|
apiMap["entryat"] = [tokens]() { return app::data::getEntryByIndex(std::stoi(tokens[1]), std::stoi(tokens[2])); };
|
||||||
|
apiMap["createsystem"] = [tokens]() { return app::data::system::create(/*TODO*/); };
|
||||||
|
apiMap["replacesystem"] = [tokens]() { return app::data::system::replace(std::stoi(tokens[1])/*, TODO*/); };
|
||||||
|
apiMap["removesystem"] = [tokens]() { return app::data::system::remove(std::stoi(tokens[1])); };
|
||||||
|
apiMap["locksystem"] = [tokens]() { return app::data::system::setLockout(std::stoi(tokens[1]), std::stoi(tokens[2])); };
|
||||||
|
apiMap["setsystemindex"] = [tokens]() { return app::data::system::setIndex(std::stoi(tokens[1]), std::stoi(tokens[2])); };
|
||||||
|
apiMap["createentry"] = [tokens]() { return app::data::system::entry::create(std::stoi(tokens[1])/*,TODO*/); };
|
||||||
|
apiMap["replaceentry"] = [tokens]() { return app::data::system::entry::replace(std::stoi(tokens[1]), std::stoi(tokens[2])/*, TODO*/); };
|
||||||
|
apiMap["removeentry"] = [tokens]() { return app::data::system::entry::remove(std::stoi(tokens[1]), std::stoi(tokens[2])); };
|
||||||
|
apiMap["lockentry"] = [tokens]() { return app::data::system::entry::setLockout(std::stoi(tokens[1]), std::stoi(tokens[2]), std::stoi(tokens[3])); };
|
||||||
|
apiMap["setentryindex"] = [tokens]() { return app::data::system::entry::setIndex(std::stoi(tokens[1]), std::stoi(tokens[2]), std::stoi(tokens[3])); };
|
||||||
|
apiMap["config"] = []() { return app::configuration::getFullConfig(); };
|
||||||
|
apiMap["setconfig"] = [tokens]() { return app::configuration::setConfig(); };
|
||||||
|
apiMap["generalcfg"] = []() { return app::configuration::getGeneralConfig(); };
|
||||||
|
apiMap["setgeneralcfg"] = [tokens]() { return app::configuration::setGeneralConfig(); };
|
||||||
|
apiMap["demodcfg"] = []() { return app::configuration::getDemodConfig(); };
|
||||||
|
apiMap["setdemodcfg"] = [tokens]() { return app::configuration::setDemodConfig(); };
|
||||||
|
apiMap["rtspcfg"] = []() { return app::configuration::getAudioServerConfig(); };
|
||||||
|
apiMap["setrtspcfg"] = [tokens]() { return app::configuration::setAudioServerConfig(); };
|
||||||
|
apiMap["tunerlist"] = []() { return app::configuration::getTunerList(); };
|
||||||
|
|
||||||
getSystemInfo();
|
getSystemInfo();
|
||||||
getScannerContext();
|
getScannerContext();
|
||||||
getDemodContext();
|
getDemodContext();
|
||||||
|
|
@ -64,7 +99,8 @@ void DebugConsole::_consoleInputFunc() {
|
||||||
try {
|
try {
|
||||||
if (!tokens[0].compare("exit")) {
|
if (!tokens[0].compare("exit")) {
|
||||||
_run = false;
|
_run = false;
|
||||||
systemFunction(SystemFunction::STOP);
|
//systemFunction(SystemFunction::STOP);
|
||||||
|
app::system::stopSystem();
|
||||||
}
|
}
|
||||||
else if (!tokens[0].compare("verbosity")){
|
else if (!tokens[0].compare("verbosity")){
|
||||||
loguru::g_stderr_verbosity = std::stoi(tokens[1]);
|
loguru::g_stderr_verbosity = std::stoi(tokens[1]);
|
||||||
|
|
@ -122,8 +158,16 @@ void DebugConsole::_consoleInputFunc() {
|
||||||
<< "\n\tget [subcommand]"
|
<< "\n\tget [subcommand]"
|
||||||
<< "\n\t\tcontext\t\tReturns scanner status"
|
<< "\n\t\tcontext\t\tReturns scanner status"
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
for (auto cmd = apiMap.begin(); cmd != apiMap.end(); cmd++) {
|
||||||
|
std::cerr << "\t" << cmd->first << "\n";
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
|
try {
|
||||||
|
auto ret = apiMap[tokens[0]]();
|
||||||
|
std::cerr << "Status: " << friendlyReturnCodes[std::get<0>(ret)] << "\n";
|
||||||
|
} catch (std::exception& e) {
|
||||||
std::cerr << "Invalid command\n";
|
std::cerr << "Invalid command\n";
|
||||||
|
}
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
std::cerr << "Argument missing or typo in the command\n";
|
std::cerr << "Argument missing or typo in the command\n";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,13 @@ namespace server {
|
||||||
namespace connection {
|
namespace connection {
|
||||||
|
|
||||||
bool SocketConnection::connect(){
|
bool SocketConnection::connect(){
|
||||||
|
Connection::connect();
|
||||||
_startRead();
|
_startRead();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketConnection::disconnect(){
|
void SocketConnection::disconnect(){
|
||||||
|
Connection::disconnect();
|
||||||
if (_socket.is_open()) {
|
if (_socket.is_open()) {
|
||||||
_socket.close();
|
_socket.close();
|
||||||
notifyDisconnected();
|
notifyDisconnected();
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ public:
|
||||||
_level(lvl), _audio(aud), _serverManager(nullptr), _handle(HANDLE_NULL) {}
|
_level(lvl), _audio(aud), _serverManager(nullptr), _handle(HANDLE_NULL) {}
|
||||||
virtual ~Connection() {};
|
virtual ~Connection() {};
|
||||||
|
|
||||||
virtual bool connect() = 0;
|
virtual bool connect();
|
||||||
virtual void disconnect() = 0;
|
virtual void disconnect();
|
||||||
virtual void contextUpdate(const piscan::server::context::ScannerContext context) = 0;
|
virtual void contextUpdate(const piscan::server::context::ScannerContext context) = 0;
|
||||||
virtual void contextUpdate(const piscan::server::context::DemodContext context) = 0;
|
virtual void contextUpdate(const piscan::server::context::DemodContext context) = 0;
|
||||||
virtual void handleSystemMessage(const piscan::server::context::GeneralMessage message) = 0;
|
virtual void handleSystemMessage(const piscan::server::context::GeneralMessage message) = 0;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "PiScan.h"
|
#include "PiScan.h"
|
||||||
#include "Demodulator.h"
|
#include "Demodulator.h"
|
||||||
#include "loguru.hpp"
|
#include "loguru.hpp"
|
||||||
|
#include "events.h"
|
||||||
|
|
||||||
#define INIT_FREQUENCY 100000000
|
#define INIT_FREQUENCY 100000000
|
||||||
#define NUM_RATES_DEFAULT 4
|
#define NUM_RATES_DEFAULT 4
|
||||||
|
|
@ -115,7 +116,8 @@ void Demodulator::start(){
|
||||||
int level = getSignalStrength();
|
int level = getSignalStrength();
|
||||||
|
|
||||||
LOG_F(7, "Signal strength %i", level);
|
LOG_F(7, "Signal strength %i", level);
|
||||||
app::server::signalLevelUpdate(level);
|
//app::server::signalLevelUpdate(level);
|
||||||
|
events::publish(std::make_shared<events::SignalLevelEvent>(level));
|
||||||
});
|
});
|
||||||
//_sigLevelRefresher = new IntervalTimer();
|
//_sigLevelRefresher = new IntervalTimer();
|
||||||
_sigLevelRefresher.create(SIGLEVEL_REFRESH_INTERVAL, func);
|
_sigLevelRefresher.create(SIGLEVEL_REFRESH_INTERVAL, func);
|
||||||
|
|
@ -145,6 +147,8 @@ bool Demodulator::setFrequency(long long freq) {
|
||||||
DLOG_F(9, "Frequency already set");
|
DLOG_F(9, "Frequency already set");
|
||||||
return true;
|
return true;
|
||||||
}*/
|
}*/
|
||||||
|
if(freq == _currentFreq)
|
||||||
|
return true;
|
||||||
|
|
||||||
_demodMgr.getCurrentModem()->setFrequency(freq);
|
_demodMgr.getCurrentModem()->setFrequency(freq);
|
||||||
|
|
||||||
|
|
@ -159,11 +163,12 @@ bool Demodulator::setFrequency(long long freq) {
|
||||||
_demodMgr.getCurrentModem()->setFrequency(freq);
|
_demodMgr.getCurrentModem()->setFrequency(freq);
|
||||||
//this is totally arbitrary
|
//this is totally arbitrary
|
||||||
//usleep(DEMOD_BUFFER_TIME);
|
//usleep(DEMOD_BUFFER_TIME);
|
||||||
|
events::publish(std::make_shared<events::GenericNumberEvent>("demod_frequency_set", freq));
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(app::system::getConfig().getDemodConfig().demodDelay));
|
std::this_thread::sleep_for(std::chrono::microseconds(app::system::getConfig().getDemodConfig().demodDelay));
|
||||||
|
|
||||||
_currentFreq = freq;
|
_currentFreq = freq;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -172,6 +177,7 @@ bool Demodulator::setTunerFrequency(long long freq){
|
||||||
_cubic->setFrequency(freq);
|
_cubic->setFrequency(freq);
|
||||||
_demodMgr.getCurrentModem()->setFrequency(freq);
|
_demodMgr.getCurrentModem()->setFrequency(freq);
|
||||||
//usleep(200000);
|
//usleep(200000);
|
||||||
|
events::publish(std::make_shared<events::GenericNumberEvent>("demod_frequency_set", freq));
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(app::system::getConfig().getDemodConfig().retuneDelay));
|
std::this_thread::sleep_for(std::chrono::microseconds(app::system::getConfig().getDemodConfig().retuneDelay));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -290,7 +296,11 @@ void Demodulator::_handleRequest(ClientRequest& request){
|
||||||
}
|
}
|
||||||
|
|
||||||
void Demodulator::_contextUpdate(){
|
void Demodulator::_contextUpdate(){
|
||||||
app::server::demodContextUpdate(piscan::server::context::DemodContext(_gain, _squelchLevel));
|
//app::server::demodContextUpdate(piscan::server::context::DemodContext(_gain, _squelchLevel));
|
||||||
|
events::DemodStateEvent event;
|
||||||
|
event.squelchState = _squelchLevel;
|
||||||
|
event.tunerGainState = _gain;
|
||||||
|
events::publish(std::make_shared<events::DemodStateEvent>(std::move(event)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Demodulator::setTunerGain(float gain){
|
void Demodulator::setTunerGain(float gain){
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
add_library(util
|
add_library(util
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Thread.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/StateMachine.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/StateMachine.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
#include "Thread.h"
|
||||||
|
#include "threadname.h"
|
||||||
|
#include "loguru.hpp"
|
||||||
|
|
||||||
|
namespace piscan {
|
||||||
|
ThreadBase::ThreadBase(std::string name) : name(name), _run(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadBase::initialize() {
|
||||||
|
LOG_F(1, "Initializing");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadBase::deinitialize() {
|
||||||
|
LOG_F(1, "Deinitializing");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadBase::start() {
|
||||||
|
LOG_F(1, "Starting %s", name.c_str());
|
||||||
|
_run = true;
|
||||||
|
|
||||||
|
_thread = std::thread([this]() { (*this).run(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadBase::stop() {
|
||||||
|
LOG_F(1, "Stopping %s", name.c_str());
|
||||||
|
_run = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadBase::join() {
|
||||||
|
if (_thread.joinable()) {
|
||||||
|
_thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadBase::run() {
|
||||||
|
setThreadName(name.c_str());
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
LOG_F(1, "Started");
|
||||||
|
|
||||||
|
while(isRunning()) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
|
||||||
|
deinitialize();
|
||||||
|
|
||||||
|
LOG_F(1, "Stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerThread::start() {
|
||||||
|
_stopping = false;
|
||||||
|
ThreadBase::start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerThread::stop() {
|
||||||
|
ThreadBase::stop();
|
||||||
|
std::unique_lock<std::mutex> lock(_mtx);
|
||||||
|
_stopping = true;
|
||||||
|
_cv.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerThread::run() {
|
||||||
|
setThreadName(name.c_str());
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
LOG_F(1, "Started");
|
||||||
|
|
||||||
|
while (isRunning())
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_mtx);
|
||||||
|
while(!workAvailable && !_stopping) {
|
||||||
|
_cv.wait(lock);
|
||||||
|
}
|
||||||
|
if(workAvailable){
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
else if(_stopping){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinitialize();
|
||||||
|
LOG_F(1, "Stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThreadBase::isRunning() {
|
||||||
|
return _run.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerThread::postWorkAvailable() {
|
||||||
|
std::unique_lock<std::mutex> lock(_mtx);
|
||||||
|
workAvailable = true;
|
||||||
|
_cv.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
namespace piscan {
|
||||||
|
|
||||||
|
class ThreadBase {
|
||||||
|
public:
|
||||||
|
virtual ~ThreadBase() {};
|
||||||
|
|
||||||
|
virtual void initialize();
|
||||||
|
virtual void deinitialize();
|
||||||
|
|
||||||
|
virtual void start();
|
||||||
|
virtual void stop();
|
||||||
|
|
||||||
|
virtual void join();
|
||||||
|
|
||||||
|
const std::string name;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ThreadBase(std::string name);
|
||||||
|
|
||||||
|
virtual void run();
|
||||||
|
virtual void main() = 0;
|
||||||
|
bool isRunning();
|
||||||
|
//Logger logger();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic_bool _run;
|
||||||
|
|
||||||
|
std::thread _thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WorkerThread : public ThreadBase {
|
||||||
|
public:
|
||||||
|
virtual void start();
|
||||||
|
virtual void stop();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
WorkerThread(std::string name) : ThreadBase(name) {};
|
||||||
|
virtual ~WorkerThread(){};
|
||||||
|
|
||||||
|
virtual void run();
|
||||||
|
virtual void main() = 0;
|
||||||
|
|
||||||
|
void postWorkAvailable();
|
||||||
|
bool workAvailable;
|
||||||
|
private:
|
||||||
|
std::mutex _mtx;
|
||||||
|
std::condition_variable _cv;
|
||||||
|
|
||||||
|
bool _stopping;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,4 +2,5 @@ package_add_test(util_tests
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/IntervalTimer_test.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/IntervalTimer_test.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/StateMachine_test.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/StateMachine_test.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/synchronize_test.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/synchronize_test.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Thread_test.cpp
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue