diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index df5e13c..2c80502 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -113,12 +113,12 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wxGetApp().getAudioVisualQueue()->pop(demodAudioData); if (demodAudioData.data.size()) { - if (scopeCanvas->waveform_points.size() != demodAudioData.data.size()) { - scopeCanvas->waveform_points.resize(demodAudioData.data.size()); + if (scopeCanvas->waveform_points.size() != demodAudioData.data.size()*2) { + scopeCanvas->waveform_points.resize(demodAudioData.data.size()*2); } - for (int i = 0, iMax = demodAudioData.data.size() / 2; i < iMax; i++) { - scopeCanvas->waveform_points[i * 2 + 1] = demodAudioData.data[i * 2] * 0.5f; + for (int i = 0, iMax = demodAudioData.data.size(); i < iMax; i++) { + scopeCanvas->waveform_points[i * 2 + 1] = demodAudioData.data[i] * 0.5f; scopeCanvas->waveform_points[i * 2] = ((double) i / (double) iMax); } diff --git a/src/demod/DemodDefs.h b/src/demod/DemodDefs.h index 9e6ea0c..edcfae2 100644 --- a/src/demod/DemodDefs.h +++ b/src/demod/DemodDefs.h @@ -38,6 +38,21 @@ public: int int_value; }; +class DemodulatorThreadControlCommand { +public: + enum DemodulatorThreadControlCommandEnum { + DEMOD_THREAD_CMD_CTL_NULL, + DEMOD_THREAD_CMD_CTL_SQUELCH_AUTO, + DEMOD_THREAD_CMD_CTL_SQUELCH_OFF + }; + + DemodulatorThreadControlCommand() : + cmd(DEMOD_THREAD_CMD_CTL_NULL) { + } + + DemodulatorThreadControlCommandEnum cmd; +}; + class DemodulatorThreadIQData { public: unsigned int frequency; @@ -106,6 +121,7 @@ public: typedef ThreadQueue DemodulatorThreadInputQueue; typedef ThreadQueue DemodulatorThreadPostInputQueue; typedef ThreadQueue DemodulatorThreadCommandQueue; +typedef ThreadQueue DemodulatorThreadControlCommandQueue; class DemodulatorThreadParameters { diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index 48297de..9d46565 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -2,17 +2,18 @@ DemodulatorInstance::DemodulatorInstance() : t_Demod(NULL), t_PreDemod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL), terminated(false), audioTerminated(false), demodTerminated( - false), preDemodTerminated(false), active(false) { + false), preDemodTerminated(false), active(false), squelch(false) { label = new std::string("Unnamed"); threadQueueDemod = new DemodulatorThreadInputQueue; threadQueuePostDemod = new DemodulatorThreadPostInputQueue; threadQueueCommand = new DemodulatorThreadCommandQueue; threadQueueNotify = new DemodulatorThreadCommandQueue; + threadQueueControl = new DemodulatorThreadControlCommandQueue; - demodulatorPreThread = new DemodulatorPreThread(threadQueueDemod, threadQueuePostDemod, threadQueueNotify); + demodulatorPreThread = new DemodulatorPreThread(threadQueueDemod, threadQueuePostDemod, threadQueueControl, threadQueueNotify); demodulatorPreThread->setCommandQueue(threadQueueCommand); - demodulatorThread = new DemodulatorThread(threadQueuePostDemod, threadQueueNotify); + demodulatorThread = new DemodulatorThread(threadQueuePostDemod, threadQueueControl, threadQueueNotify); audioInputQueue = new AudioThreadInputQueue; audioThread = new AudioThread(audioInputQueue, threadQueueNotify); @@ -144,3 +145,30 @@ void DemodulatorInstance::setActive(bool state) { active = state; audioThread->setActive(state); } + + +void DemodulatorInstance::squelchAuto() { + DemodulatorThreadControlCommand command; + command.cmd = DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_AUTO; + threadQueueControl->push(command); + squelch = true; +} + +bool DemodulatorInstance::isSquelchEnabled() { + return squelch; +} + +void DemodulatorInstance::setSquelchEnabled(bool state) { + if (!state && squelch) { + DemodulatorThreadControlCommand command; + command.cmd = DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_OFF; + threadQueueControl->push(command); + } else if (state && !squelch) { + DemodulatorThreadControlCommand command; + command.cmd = DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_AUTO; + threadQueueControl->push(command); + } + + squelch = state; +} + diff --git a/src/demod/DemodulatorInstance.h b/src/demod/DemodulatorInstance.h index 9b759ce..ccd14be 100644 --- a/src/demod/DemodulatorInstance.h +++ b/src/demod/DemodulatorInstance.h @@ -16,6 +16,8 @@ public: DemodulatorThreadCommandQueue* threadQueueNotify; DemodulatorPreThread *demodulatorPreThread; DemodulatorThread *demodulatorThread; + DemodulatorThreadControlCommandQueue *threadQueueControl; + #ifdef __APPLE__ pthread_t t_PreDemod; pthread_t t_Demod; @@ -47,6 +49,10 @@ public: bool isActive(); void setActive(bool state); + void squelchAuto(); + bool isSquelchEnabled(); + void setSquelchEnabled(bool state); + private: std::atomic label; bool terminated; @@ -54,5 +60,6 @@ private: bool audioTerminated; bool preDemodTerminated; std::atomic active; + std::atomic squelch; }; diff --git a/src/demod/DemodulatorPreThread.cpp b/src/demod/DemodulatorPreThread.cpp index b872dc5..01e4644 100644 --- a/src/demod/DemodulatorPreThread.cpp +++ b/src/demod/DemodulatorPreThread.cpp @@ -8,9 +8,9 @@ #include "DemodulatorPreThread.h" DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* pQueueIn, DemodulatorThreadPostInputQueue* pQueueOut, - DemodulatorThreadCommandQueue* threadQueueNotify) : + DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) : inputQueue(pQueueIn), postInputQueue(pQueueOut), terminated(false), initialized(false), audio_resampler(NULL), resample_ratio(1), audio_resample_ratio( - 1), resampler(NULL), commandQueue(NULL), fir_filter(NULL), audioInputQueue(NULL), threadQueueNotify(threadQueueNotify) { + 1), resampler(NULL), commandQueue(NULL), fir_filter(NULL), audioInputQueue(NULL), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl) { float kf = 0.5; // modulation factor fdem = freqdem_create(kf); diff --git a/src/demod/DemodulatorPreThread.h b/src/demod/DemodulatorPreThread.h index f11ca03..4e5b577 100644 --- a/src/demod/DemodulatorPreThread.h +++ b/src/demod/DemodulatorPreThread.h @@ -11,7 +11,7 @@ class DemodulatorPreThread { public: DemodulatorPreThread(DemodulatorThreadInputQueue* pQueueIn, DemodulatorThreadPostInputQueue* pQueueOut, - DemodulatorThreadCommandQueue* threadQueueNotify); + DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify); ~DemodulatorPreThread(); #ifdef __APPLE__ @@ -28,6 +28,11 @@ public: audioInputQueue = tQueue; } + void setDemodulatorControlQueue(DemodulatorThreadControlCommandQueue *tQueue) { + threadQueueControl = tQueue; + } + + DemodulatorThreadParameters &getParams() { return params; } @@ -71,4 +76,5 @@ protected: DemodulatorThreadWorkerCommandQueue *workerQueue; DemodulatorThreadWorkerResultQueue *workerResults; DemodulatorThreadCommandQueue* threadQueueNotify; + DemodulatorThreadControlCommandQueue *threadQueueControl; }; diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index 2c1e9b4..50dd31c 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -6,8 +6,8 @@ #include #endif -DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadCommandQueue* threadQueueNotify) : - postInputQueue(pQueue), visOutQueue(NULL), terminated(false), audioInputQueue(NULL), threadQueueNotify(threadQueueNotify) { +DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) : + postInputQueue(pQueue), visOutQueue(NULL), terminated(false), audioInputQueue(NULL), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), agc(NULL), squelch_enabled(false), squelch_level(0), squelch_tolerance(0) { float kf = 0.5; // modulation factor fdem = freqdem_create(kf); @@ -31,6 +31,9 @@ void DemodulatorThread::threadMain() { msresamp_crcf audio_resampler = NULL; msresamp_crcf resampler = NULL; + agc = agc_crcf_create(); + agc_crcf_set_bandwidth(agc, 1e-3f); + std::cout << "Demodulator thread started.." << std::endl; while (!terminated) { DemodulatorThreadPostIQData inp; @@ -54,15 +57,18 @@ void DemodulatorThread::threadMain() { int out_size = ceil((float) (bufSize) * inp.resample_ratio); liquid_float_complex resampled_data[out_size]; + liquid_float_complex agc_data[out_size]; unsigned int num_written; msresamp_crcf_execute(resampler, &inp.data[0], bufSize, resampled_data, &num_written); + agc_crcf_execute_block(agc, resampled_data, num_written, agc_data); + float audio_resample_ratio = inp.audio_resample_ratio; float demod_output[num_written]; - freqdem_demodulate_block(fdem, resampled_data, num_written, demod_output); + freqdem_demodulate_block(fdem, agc_data, num_written, demod_output); liquid_float_complex demod_audio_data[num_written]; @@ -90,18 +96,54 @@ void DemodulatorThread::threadMain() { ati.data = newBuffer; if (audioInputQueue != NULL) { - audioInputQueue->push(ati); + if (!squelch_enabled || ((agc_crcf_get_signal_level(agc)) >= 0.1)) { + audioInputQueue->push(ati); + } } if (visOutQueue != NULL && visOutQueue->empty()) { + AudioThreadInput ati_vis; + int num_vis = DEMOD_VIS_SIZE; if (num_audio_written > num_written) { - visOutQueue->push(ati); + if (num_vis > num_audio_written) { + num_vis = num_audio_written; + } + ati_vis.data.resize(num_vis); + for (int i = 0; i < num_vis; i++) { + ati_vis.data[i] = resampled_audio_output[i].real; + } } else { - AudioThreadInput ati_vis; - ati_vis.data.assign(demod_output, demod_output + num_written); - visOutQueue->push(ati_vis); + if (num_vis > num_written) { + num_vis = num_written; + } + ati_vis.data.assign(demod_output, demod_output + num_vis); + } + visOutQueue->push(ati_vis); +// std::cout << "Signal: " << agc_crcf_get_signal_level(agc) << " -- " << agc_crcf_get_rssi(agc) << "dB " << std::endl; + } + + if (!threadQueueControl->empty()) { + while (!threadQueueControl->empty()) { + DemodulatorThreadControlCommand command; + threadQueueControl->pop(command); + + switch (command.cmd) { + case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_AUTO: + squelch_level = agc_crcf_get_signal_level(agc); + squelch_tolerance = agc_crcf_get_signal_level(agc)/2.0; + squelch_enabled = true; + break; + case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_OFF: + squelch_level = 0; + squelch_tolerance = 1; + squelch_enabled = false; + break; + default: + break; + } } } + } if (resampler != NULL) { @@ -111,6 +153,8 @@ void DemodulatorThread::threadMain() { msresamp_crcf_destroy(audio_resampler); } + agc_crcf_destroy(agc); + std::cout << "Demodulator thread done." << std::endl; DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED); tCmd.context = this; diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h index 2a126a3..5327620 100644 --- a/src/demod/DemodulatorThread.h +++ b/src/demod/DemodulatorThread.h @@ -8,10 +8,12 @@ typedef ThreadQueue DemodulatorThreadOutputQueue; +#define DEMOD_VIS_SIZE 2048 + class DemodulatorThread { public: - DemodulatorThread(DemodulatorThreadPostInputQueue* pQueueIn, DemodulatorThreadCommandQueue* threadQueueNotify); + DemodulatorThread(DemodulatorThreadPostInputQueue* pQueueIn, DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify); ~DemodulatorThread(); #ifdef __APPLE__ @@ -44,8 +46,13 @@ protected: AudioThreadInputQueue *audioInputQueue; freqdem fdem; + agc_crcf agc; std::atomic terminated; DemodulatorThreadCommandQueue* threadQueueNotify; + DemodulatorThreadControlCommandQueue *threadQueueControl; + float squelch_level; + float squelch_tolerance; + bool squelch_enabled; }; diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index d493029..6318996 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -181,7 +181,16 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { wxGetApp().removeDemodulator(activeDemod); wxGetApp().getDemodMgr().deleteThread(activeDemod); break; - + case 'S': + if (!activeDemod) { + break; + } + if (activeDemod->isSquelchEnabled()) { + activeDemod->setSquelchEnabled(false); + } else { + activeDemod->squelchAuto(); + } + break; default: event.Skip(); return;