Added signal strength indication

This commit is contained in:
ezratl 2020-02-22 12:16:22 -05:00
parent bef4efa5b3
commit be6d69ee8a
20 changed files with 271 additions and 9 deletions

View File

@ -87,7 +87,8 @@ include_directories(
external
scan
server
sigproc
sigproc
util
external/PiScan-protobuf
external/loguru
external/tinyxml

View File

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

View File

@ -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) {

View File

@ -114,6 +114,7 @@ struct ServerMessage : public Message {
~ServerMessage() {};
enum {
CONTEXT_UPDATE,
SIGNAL_LEVEL,
NOTIFY_ALL_CLIENTS,
NOTIFY_USERS,

View File

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

View File

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

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

76
src/tests/test_utils.cpp Normal file
View File

@ -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
src/util/CMakeLists.txt Normal file
View File

133
src/util/IntervalTimer.h Normal file
View File

@ -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 */