Added signal strength indication
This commit is contained in:
parent
bef4efa5b3
commit
be6d69ee8a
|
|
@ -87,7 +87,8 @@ include_directories(
|
|||
external
|
||||
scan
|
||||
server
|
||||
sigproc
|
||||
sigproc
|
||||
util
|
||||
external/PiScan-protobuf
|
||||
external/loguru
|
||||
external/tinyxml
|
||||
|
|
|
|||
|
|
@ -29,10 +29,11 @@ ScannerContext getScannerContext();
|
|||
void setTunerGain(float gain);
|
||||
void setDemodSquelch(float level);
|
||||
DemodContext getDemodContext();
|
||||
void audioMute(bool mute = true);
|
||||
void squelchBreak(bool mute = true);
|
||||
long long getTunerSampleRate();
|
||||
|
||||
/* server functions */
|
||||
void scannerContextUpdate(ScannerContext ctx);
|
||||
void demodContextUpdate(DemodContext ctx);
|
||||
void signalLevelUpdate(int level);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ void ScannerSM::ST_Hold(EventData* data){
|
|||
if(currentState != lastState || indexHold)
|
||||
_broadcastContextUpdate();
|
||||
|
||||
DLOG_F(6, "Ext hold: %i", _externalHold.load());
|
||||
DLOG_F(8, "Ext hold: %i", _externalHold.load());
|
||||
|
||||
/* start receive if signal active */
|
||||
if (_currentEntry->hasSignal()) {
|
||||
|
|
@ -320,7 +320,7 @@ void ScannerSM::_broadcastContextUpdate() {
|
|||
}
|
||||
|
||||
void ScannerSM::_enableAudioOut(bool en){
|
||||
app::audioMute(en);
|
||||
app::squelchBreak(en);
|
||||
}
|
||||
|
||||
void ScannerSM::giveMessage(shared_ptr<Message> message) {
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ struct ServerMessage : public Message {
|
|||
~ServerMessage() {};
|
||||
enum {
|
||||
CONTEXT_UPDATE,
|
||||
SIGNAL_LEVEL,
|
||||
|
||||
NOTIFY_ALL_CLIENTS,
|
||||
NOTIFY_USERS,
|
||||
|
|
|
|||
|
|
@ -371,8 +371,8 @@ DemodContext app::getDemodContext(){
|
|||
return DemodContext(demod.getTunerGain(), demod.getSquelch());
|
||||
}
|
||||
|
||||
void app::audioMute(bool mute){
|
||||
demod.audioMute(mute);
|
||||
void app::squelchBreak(bool mute){
|
||||
demod.squelchBreak(mute);
|
||||
}
|
||||
|
||||
long long app::getTunerSampleRate() {
|
||||
|
|
@ -397,6 +397,10 @@ void app::demodContextUpdate(DemodContext ctx){
|
|||
connectionManager.giveMessage(make_shared<ServerMessage>(DEMOD, ServerMessage::CONTEXT_UPDATE, new DemodContext(ctx)));
|
||||
}
|
||||
|
||||
void app::signalLevelUpdate(int level){
|
||||
connectionManager.giveMessage(make_shared<ServerMessage>(DEMOD, ServerMessage::SIGNAL_LEVEL, new int(level)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using namespace piscan;
|
||||
|
|
|
|||
|
|
@ -201,6 +201,10 @@ void DebugConsole::handleSystemInfo(const SystemInfo info){
|
|||
}
|
||||
}
|
||||
|
||||
void DebugConsole::handleSignalLevel(const int level){
|
||||
std::cerr << "\r" << "Signal: " << level << "\t\t\t\t";
|
||||
}
|
||||
|
||||
void DebugServer::start(){
|
||||
//this->_connection(new DebugConsole());
|
||||
this->_host.requestConnection(_connection);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public:
|
|||
void contextUpdate(const DemodContext context);
|
||||
void handleSystemMessage(const GeneralMessage message);
|
||||
void handleSystemInfo(const SystemInfo info);
|
||||
void handleSignalLevel(const int level);
|
||||
|
||||
const std::string identifier() {
|
||||
return "Debug Console";
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ int ServerManager::giveRequest(void* request){
|
|||
void ServerManager::_handleMessage(std::shared_ptr<Message> message){
|
||||
assert(message->destination == SERVER_MAN);
|
||||
auto msg = std::dynamic_pointer_cast<ServerMessage>(message);
|
||||
int* level = nullptr;
|
||||
switch (msg->type) {
|
||||
case ServerMessage::CONTEXT_UPDATE:
|
||||
switch(message->source){
|
||||
|
|
@ -247,6 +248,12 @@ void ServerManager::_handleMessage(std::shared_ptr<Message> message){
|
|||
disconnectClients();
|
||||
_run = false;
|
||||
break;
|
||||
case ServerMessage::SIGNAL_LEVEL:
|
||||
DLOG_F(7, "Broadcast siglevel update");
|
||||
level = reinterpret_cast<int*>(msg->pData);
|
||||
_broadcastSignalLevelUpdate(*level);
|
||||
delete level;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -327,3 +334,12 @@ std::shared_ptr<Message> ServerManager::_makeContextRequest(ClientRequest* rq){
|
|||
}
|
||||
}
|
||||
|
||||
void ServerManager::_broadcastSignalLevelUpdate(int level) {
|
||||
for (size_t i = 0; i < MAX_CONNECTIONS; i++) {
|
||||
if (_connections[i] != nullptr) {
|
||||
Connection* con = _connections[i].get();
|
||||
con->handleSignalLevel(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ private:
|
|||
void _broadcastGeneralMessage(unsigned char group, GeneralMessage& message);
|
||||
std::shared_ptr<Message> _makeContextRequest(ClientRequest* rq);
|
||||
|
||||
void _broadcastSignalLevelUpdate(int level);
|
||||
|
||||
};
|
||||
}
|
||||
#endif /* SERVER_SERVERMANAGER_H_ */
|
||||
|
|
|
|||
|
|
@ -134,6 +134,11 @@ void SocketConnection::handleSystemInfo(const SystemInfo info){
|
|||
delete ctx;
|
||||
}
|
||||
|
||||
void SocketConnection::handleSignalLevel(const int level){
|
||||
//TODO
|
||||
(void) level;
|
||||
}
|
||||
|
||||
void SocketConnection::_startRead() {
|
||||
_socket.async_read_some(boost::asio::buffer(_readBuffer, READ_BUFFER_LENGTH),
|
||||
boost::bind(&SocketConnection::_handleRead, shared_from_this(),
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ public:
|
|||
void contextUpdate(const DemodContext context);
|
||||
void handleSystemMessage(const GeneralMessage message);
|
||||
void handleSystemInfo(const SystemInfo info);
|
||||
void handleSignalLevel(const int level);
|
||||
|
||||
tcp::socket& socket() { return _socket; };
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ public:
|
|||
virtual void contextUpdate(const DemodContext context) = 0;
|
||||
virtual void handleSystemMessage(const GeneralMessage message) = 0;
|
||||
virtual void handleSystemInfo(const SystemInfo info) = 0;
|
||||
virtual void handleSignalLevel(const int level) = 0;
|
||||
|
||||
virtual const std::string identifier() = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <functional>
|
||||
|
||||
#include "PiScan.h"
|
||||
#include "Demodulator.h"
|
||||
|
|
@ -14,6 +15,7 @@
|
|||
#define DEFAULT_SDR_SAMPLE_RATE 2048000
|
||||
#define INIT_FREQUENCY 100000000
|
||||
#define NUM_RATES_DEFAULT 4
|
||||
#define SIGLEVEL_REFRESH_INTERVAL 250 // milliseconds
|
||||
|
||||
using namespace piscan;
|
||||
|
||||
|
|
@ -145,6 +147,14 @@ void Demodulator::start(){
|
|||
//setModem(NFM);
|
||||
_demodMgr.setActiveDemodulator(_demods[NFM], false);
|
||||
|
||||
//create signal level refresh timer
|
||||
std::function<void()> func([this](){
|
||||
int level = getSignalStrength();
|
||||
LOG_F(7, "Signal strength %i", level);
|
||||
app::signalLevelUpdate(level);
|
||||
});
|
||||
_sigLevelRefresher.create(SIGLEVEL_REFRESH_INTERVAL, func);
|
||||
|
||||
//auto message = std::make_shared<ControllerMessage>(DEMOD, ControllerMessage::NOTIFY_READY);
|
||||
//_centralQueue.giveMessage(message);
|
||||
LOG_F(1, "Demodulator started");
|
||||
|
|
@ -334,7 +344,10 @@ float Demodulator::getSquelch(){
|
|||
return _squelchLevel;
|
||||
}
|
||||
|
||||
void Demodulator::audioMute(bool mute){
|
||||
void Demodulator::squelchBreak(bool mute){
|
||||
//mute = !mute;
|
||||
mute ? _sigLevelRefresher.start() : _sigLevelRefresher.stop();
|
||||
|
||||
_demodMgr.getCurrentModem()->setMuted(!mute);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "SDRDeviceInfo.h"
|
||||
#include "Configuration.h"
|
||||
#include "synchronize.h"
|
||||
#include "IntervalTimer.h"
|
||||
|
||||
|
||||
namespace piscan {
|
||||
|
|
@ -65,7 +66,7 @@ public:
|
|||
void setTunerGain(float gain);
|
||||
float getTunerGain();
|
||||
float getSquelch();
|
||||
void audioMute(bool mute);
|
||||
void squelchBreak(bool mute);
|
||||
long long getTunerSampleRate();
|
||||
|
||||
private:
|
||||
|
|
@ -80,7 +81,7 @@ private:
|
|||
|
||||
std::map<Modulation, DemodulatorInstancePtr> _demods;
|
||||
|
||||
|
||||
IntervalTimer _sigLevelRefresher;
|
||||
|
||||
void _handleMessage(std::shared_ptr<DemodMessage> message);
|
||||
void _handleRequest(ClientRequest& request);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ project(piScan_backend_tests)
|
|||
|
||||
add_executable(piScan_backend_tests EXCLUDE_FROM_ALL test_ScannerStateMachine.cpp)
|
||||
add_executable(testclient EXCLUDE_FROM_ALL testclient.cpp)
|
||||
add_executable(test_utils EXCLUDE_FROM_ALL test_utils.cpp)
|
||||
|
||||
option(DETACH_KERNEL_DRIVER "Detach kernel driver if loaded" OFF)
|
||||
if (DETACH_KERNEL_DRIVER)
|
||||
|
|
@ -12,3 +13,4 @@ else (DETACH_KERNEL_DRIVER)
|
|||
endif (DETACH_KERNEL_DRIVER)
|
||||
|
||||
target_link_libraries(testclient server external pthread boost_system protobuf dl)
|
||||
target_link_libraries(test_utils pthread)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* test_utils.cpp
|
||||
*
|
||||
* Created on: Feb 12, 2020
|
||||
* Author: ezra
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
|
||||
#include "IntervalTimer.h"
|
||||
|
||||
using piscan::IntervalTimer;
|
||||
using std::cout;
|
||||
using std::chrono::milliseconds;
|
||||
|
||||
int main(int argc, char** argv){
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
cout << "testing IntervalTimer" << std::endl;
|
||||
size_t runCount = 0;
|
||||
auto func = std::function<void(void)>([&runCount](){
|
||||
runCount++;
|
||||
cout << "\ttimer running\n";
|
||||
});
|
||||
|
||||
IntervalTimer it;
|
||||
cout << "create 10ms timer\n";
|
||||
it.create(10, func);
|
||||
cout << "start timer\n";
|
||||
it.start();
|
||||
cout << "waiting 50ms\n";
|
||||
std::this_thread::sleep_for(milliseconds(50));
|
||||
cout << "stopping timer\n";
|
||||
it.stop();
|
||||
cout << "timer executed " << runCount << " times\n";
|
||||
|
||||
IntervalTimer& it2 = *(new IntervalTimer());
|
||||
cout << "recreating timer, 15ms\n";
|
||||
runCount = 0;
|
||||
it2.create(15, func);
|
||||
cout << "waiting 50ms before starting\n";
|
||||
std::this_thread::sleep_for(milliseconds(50));
|
||||
cout << "start timer\n";
|
||||
it2.start();
|
||||
cout << "waiting 50ms\n";
|
||||
std::this_thread::sleep_for(milliseconds(50));
|
||||
cout << "destroy while timer is running\n";
|
||||
delete &it2;
|
||||
cout << "timer destroyed\n";
|
||||
|
||||
IntervalTimer it3;
|
||||
cout << "recreating timer, 20ms\n";
|
||||
runCount = 0;
|
||||
it3.create(20, func);
|
||||
cout << "start timer, 2 runs\n";
|
||||
it3.start();
|
||||
cout << "wait 50ms\n";
|
||||
std::this_thread::sleep_for(milliseconds(50));
|
||||
cout << "stop timer\n";
|
||||
it3.stop();
|
||||
cout << "ran " << runCount << " times. wait 50ms\n";
|
||||
std::this_thread::sleep_for(milliseconds(50));
|
||||
cout << "restart timer\n";
|
||||
it3.start();
|
||||
cout << "wait 50ms\n";
|
||||
std::this_thread::sleep_for(milliseconds(50));
|
||||
cout << "stop timer\n";
|
||||
it3.stop();
|
||||
cout << "total " << runCount << " runs\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* IntervalTimer.h
|
||||
*
|
||||
* Created on: Feb 12, 2020
|
||||
* Author: ezra
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace piscan {
|
||||
|
||||
using std::thread;
|
||||
using std::mutex;
|
||||
using std::condition_variable;
|
||||
using std::atomic_bool;
|
||||
using std::function;
|
||||
using std::unique_lock;
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono::high_resolution_clock;
|
||||
using std::chrono::duration_cast;
|
||||
|
||||
class IntervalTimer {
|
||||
public:
|
||||
IntervalTimer(): _runTimer(false), _execute(false) {};
|
||||
~IntervalTimer(){
|
||||
if(_execute.load())
|
||||
destroy();
|
||||
};
|
||||
|
||||
inline void create(long long interval, function<void()> func){
|
||||
_execute = true;
|
||||
_runTimer = false;
|
||||
_ready = false;
|
||||
|
||||
_timerThread = thread([this, interval, func](){
|
||||
while(_execute){
|
||||
{
|
||||
unique_lock<std::mutex> lock(_mtx);
|
||||
while(!_runTimer.load() && _execute.load()){
|
||||
_cv.wait(lock);
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
if(!_execute.load()) break;
|
||||
}
|
||||
|
||||
auto periodStart = high_resolution_clock::now();
|
||||
|
||||
func();
|
||||
|
||||
{
|
||||
milliseconds remainingSleep(interval);
|
||||
bool sleep = true;
|
||||
|
||||
unique_lock<std::mutex> lock(_sleepMtx);
|
||||
|
||||
while(sleep){
|
||||
if(_sleepTime.wait_for(lock, remainingSleep, [this]{ return _stateChanged.load();})){
|
||||
//std::cout << "\t\ttimer state changed\n";
|
||||
_stateChanged = false;
|
||||
break;
|
||||
}
|
||||
// should account for spurious wakeup
|
||||
else{
|
||||
//std::cout << "\t\tstate change false\n";
|
||||
auto elapsed = high_resolution_clock::now() - periodStart;
|
||||
remainingSleep -= duration_cast<milliseconds>(elapsed);
|
||||
//std::cout << "\t\t" << remainingSleep.count() << "\n";
|
||||
if(remainingSleep.count() <= 0){
|
||||
sleep = false;
|
||||
//std::cout << "\t\ttimed out\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
//std::cout << "\t\twoken up\n";
|
||||
}
|
||||
}
|
||||
});
|
||||
_timerThread.detach();
|
||||
|
||||
}
|
||||
|
||||
inline void start(){
|
||||
unique_lock<mutex> lock(_mtx);
|
||||
_runTimer = true;
|
||||
_stateChanged = false;
|
||||
_cv.notify_all();
|
||||
//unique_lock<mutex> lock2(_sleepMtx);
|
||||
//_sleepTime.notify_all();
|
||||
|
||||
}
|
||||
|
||||
inline void stop(){
|
||||
//unique_lock<mutex> lock(_mtx);
|
||||
_runTimer = false;
|
||||
_stateChanged = true;
|
||||
unique_lock<mutex> lock2(_sleepMtx);
|
||||
_sleepTime.notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
inline void destroy(){
|
||||
//std::cout << "\tdestroy timer\n";
|
||||
_execute = false;
|
||||
unique_lock<mutex> lock(_mtx);
|
||||
_cv.notify_all();
|
||||
stop();
|
||||
}
|
||||
|
||||
private:
|
||||
thread _timerThread;
|
||||
atomic_bool _runTimer;
|
||||
atomic_bool _execute;
|
||||
atomic_bool _stateChanged{false};
|
||||
|
||||
mutex _mtx;
|
||||
condition_variable _cv;
|
||||
mutex _sleepMtx;
|
||||
condition_variable _sleepTime;
|
||||
bool _ready = false;
|
||||
};
|
||||
|
||||
} /* namespace piscan */
|
||||
|
||||
Loading…
Reference in New Issue