diff --git a/CMakeLists.txt b/CMakeLists.txt index c0a4b31..e7e1d17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ SET (cubicsdr_sources src/IQBufferThread.cpp src/PrimaryGLContext.cpp src/AppFrame.cpp + src/SDRThreadQueue.cpp ) SET (cubicsdr_headers @@ -87,6 +88,7 @@ SET (cubicsdr_headers src/PrimaryGLContext.h src/AppFrame.h src/CubicSDRDefs.h + src/SDRThreadQueue.h ) #configure_files(${PROJECT_SOURCE_DIR}/shaders ${PROJECT_BINARY_DIR}/shaders COPYONLY) #configure_files(${PROJECT_SOURCE_DIR}/png ${PROJECT_BINARY_DIR}/png COPYONLY) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 91a9def..52724a1 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -42,8 +42,9 @@ AppFrame::AppFrame() : Centre(); Show(); + m_pQueue = new SDRThreadQueue(this); - t_SDR = new SDRThread(appframe); + t_SDR = new SDRThread(m_pQueue); if (t_SDR->Run() != wxTHREAD_NO_ERROR) { wxLogError ("Can't create the thread!"); @@ -51,42 +52,48 @@ AppFrame::AppFrame() : t_SDR = NULL; } - t_IQBuffer = new IQBufferThread(this); - if (t_IQBuffer->Run() != wxTHREAD_NO_ERROR) { - wxLogError - ("Can't create the thread!"); - delete t_IQBuffer; +// t_IQBuffer = new IQBufferThread(this); +// if (t_IQBuffer->Run() != wxTHREAD_NO_ERROR) { +// wxLogError +// ("Can't create the thread!"); +// delete t_IQBuffer; t_IQBuffer = NULL; - } +// } // static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 }; // wxLogStatus("Double-buffered display %s supported", wxGLCanvas::IsDisplaySupported(attribs) ? "is" : "not"); // ShowFullScreen(true); } +AppFrame::~AppFrame() { + delete t_SDR; +// delete t_IQBuffer; + delete m_pQueue; +} + void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) { - { - wxCriticalSectionLocker enter(m_pThreadCS); - if (t_SDR) { - wxMessageOutputDebug().Printf("CubicSDR: deleting thread"); - if (t_SDR->Delete() != wxTHREAD_NO_ERROR) { - wxLogError - ("Can't delete the thread!"); - } - } - } + { + wxCriticalSectionLocker enter(m_pThreadCS); + if (t_SDR) { + wxMessageOutputDebug().Printf("CubicSDR: deleting thread"); + if (t_SDR->Delete() != wxTHREAD_NO_ERROR) { + wxLogError + ("Can't delete the thread!"); + } + } + } - { - wxCriticalSectionLocker enter(m_pThreadCS); - if (t_IQBuffer) { - wxMessageOutputDebug().Printf("CubicSDR: deleting thread"); - if (t_IQBuffer->Delete() != wxTHREAD_NO_ERROR) { - wxLogError - ("Can't delete the thread!"); - } - } - } + { + wxCriticalSectionLocker enter(m_pThreadCS); + if (t_IQBuffer) { + wxMessageOutputDebug().Printf("CubicSDR: deleting thread"); + if (t_IQBuffer->Delete() != wxTHREAD_NO_ERROR) { + wxLogError + ("Can't delete the thread!"); + } + } + } // true is to force the frame to close Close(true); } diff --git a/src/AppFrame.h b/src/AppFrame.h index 4a8b259..928b313 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -2,11 +2,13 @@ #include "wx/frame.h" #include "PrimaryGLContext.h" +#include "SDRThread.h" // Define a new frame type class AppFrame: public wxFrame { public: AppFrame(); + ~AppFrame(); void OnEventInput(wxThreadEvent& event); private: @@ -18,6 +20,7 @@ private: SDRThread *t_SDR; IQBufferThread *t_IQBuffer; wxCriticalSection m_pThreadCS; - + SDRThreadQueue* m_pQueue; + wxDECLARE_EVENT_TABLE(); }; diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 8708906..3ecbd5c 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -4,8 +4,6 @@ //WX_GL_MAJOR_VERSION 3 //WX_GL_MINOR_VERSION 2 -#include "SDRThread.h" -#include "IQBufferThread.h" #include "wx/glcanvas.h" #include "PrimaryGLContext.h" @@ -13,7 +11,6 @@ class CubicSDR: public wxApp { public: CubicSDR() { m_glContext = NULL; - t_SDR = NULL; } PrimaryGLContext &GetContext(wxGLCanvas *canvas); diff --git a/src/PrimaryGLContext.cpp b/src/PrimaryGLContext.cpp index ac0f2ed..59b8c28 100644 --- a/src/PrimaryGLContext.cpp +++ b/src/PrimaryGLContext.cpp @@ -67,6 +67,8 @@ void PrimaryGLContext::Plot(std::vector &points) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); +// glEnable(GL_LINE_SMOOTH); + glPushMatrix(); glTranslatef(-1.0f, -0.9f, 0.0f); glScalef(2.0f, 1.8f, 1.0f); @@ -106,6 +108,8 @@ TestGLCanvas::TestGLCanvas(wxWindow *parent, int *attribList) : out[1] = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * out_block_size); plan[0] = fftw_plan_dft_1d(out_block_size, in, out[0], FFTW_BACKWARD, FFTW_MEASURE); plan[1] = fftw_plan_dft_1d(out_block_size, in, out[1], FFTW_FORWARD, FFTW_MEASURE); + + fft_ceil_ma=fft_ceil_maa=1.0; } void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { @@ -159,45 +163,48 @@ void TestGLCanvas::setData(std::vector *data) { double fft_ceil = 0; // fft_floor, - if (fft_result.size() fft_ceil) { - fft_ceil = fft_result_maa[i]; - } + if (fft_result_maa[i] > fft_ceil) { + fft_ceil = fft_result_maa[i]; + } } + fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma)*0.05; + fft_ceil_maa = fft_ceil_maa + (fft_ceil - fft_ceil_maa)*0.05; + for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) { - points[i * 2 + 1] = fft_result_maa[i] / fft_ceil; + points[i * 2 + 1] = fft_result_maa[i] / fft_ceil_maa; points[i * 2] = ((double) i / (double) iMax); } } diff --git a/src/PrimaryGLContext.h b/src/PrimaryGLContext.h index b940a58..d87957e 100644 --- a/src/PrimaryGLContext.h +++ b/src/PrimaryGLContext.h @@ -31,6 +31,8 @@ public: fftw_complex *in, *out[2]; fftw_plan plan[2]; + float fft_ceil_ma, fft_ceil_maa; + std::vector fft_result; std::vector fft_result_ma; std::vector fft_result_maa; diff --git a/src/SDRThread.cpp b/src/SDRThread.cpp index 6144794..0b44b54 100644 --- a/src/SDRThread.cpp +++ b/src/SDRThread.cpp @@ -2,12 +2,12 @@ #include "CubicSDRDefs.h" #include - //wxDEFINE_EVENT(wxEVT_COMMAND_SDRThread_INPUT, wxThreadEvent); -SDRThread::SDRThread(SDRThreadQueue* pQueue, int id=0) : +SDRThread::SDRThread(SDRThreadQueue* pQueue, int id) : wxThread(wxTHREAD_DETACHED), m_pQueue(pQueue), m_ID(id) { dev = NULL; + sample_rate = SRATE; } SDRThread::~SDRThread() { @@ -84,11 +84,10 @@ void SDRThread::enumerate_rtl() { wxThread::ExitCode SDRThread::Entry() { signed char *buf = (signed char *) malloc(BUF_SIZE); - int use_my_dev = 1; int dev_count = rtlsdr_get_device_count(); - if (use_my_dev > dev_count-1) { + if (use_my_dev > dev_count - 1) { use_my_dev = 0; } @@ -111,28 +110,27 @@ wxThread::ExitCode SDRThread::Entry() { std::cout << "Sampling.."; while (!TestDestroy()) { - if (m_pQueue->Stacksize()) { - while (m_pQueue->Stacksize()) { - SDRThreadTask task=m_pQueue->Pop(); // pop a task from the queue. this will block the worker thread if queue is empty - switch(task.m_cmd) - { - case SDRThreadTask::SDR_THREAD_EXIT: // thread should exit - Sleep(1000); // wait a while - throw SDRThreadTask::SDR_THREAD_EXIT; // confirm exit command - case SDRThreadTask::SDR_THREAD_JOB: // process a standard task - Sleep(2000); - m_pQueue->Report(SDRThreadTask::SDR_THREAD_JOB, wxString::Format(wxT("Task #%s done."), task.m_Arg.c_str()), m_ID); // report successful completion - break; - case SDRThreadTask::SDR_THREAD_JOBERR: // process a task that terminates with an error - m_pQueue->Report(SDRThreadTask::SDR_THREAD_JOB, wxString::Format(wxT("Task #%s errorneous."), task.m_Arg.c_str()), m_ID); - Sleep(1000); - throw SDRThreadTask::SDR_THREAD_EXIT; // report exit of worker thread - break; - case SDRThreadTask::SDR_THREAD_NULL: // dummy command - default: break; // default - } // switch(task.m_cmd) - } - } + if (m_pQueue->Stacksize()) { + while (m_pQueue->Stacksize()) { + SDRThreadTask task = m_pQueue->Pop(); // pop a task from the queue. this will block the worker thread if queue is empty + switch (task.m_cmd) { +// case SDRThreadTask::SDR_THREAD_EXIT: // thread should exit +// Sleep(1000); // wait a while +// throw SDRThreadTask::SDR_THREAD_EXIT; // confirm exit command +// case SDRThreadTask::SDR_THREAD_TASK: // process a standard task +// Sleep(2000); +// m_pQueue->Report(SDRThreadTask::SDR_THREAD_TASK, wxString::Format(wxT("Task #%s done."), task.m_Arg.c_str()), m_ID); // report successful completion +// break; +// case SDRThreadTask::SDR_THREAD_JOBERR: // process a task that terminates with an error +// m_pQueue->Report(SDRThreadTask::SDR_THREAD_TASK, wxString::Format(wxT("Task #%s errorneous."), task.m_Arg.c_str()), m_ID); +// Sleep(1000); +// throw SDRThreadTask::SDR_THREAD_EXIT; // report exit of worker thread +// break; +// case SDRThreadTask::SDR_THREAD_NULL: // dummy command +// default: break; // default + } + } + } rtlsdr_read_sync(dev, buf, BUF_SIZE, &n_read); // move around @@ -147,17 +145,17 @@ wxThread::ExitCode SDRThread::Entry() { new_buffer->push_back(buf[i] - 127); } - double time_slice = (double)n_read/(double)sample_rate; + double time_slice = (double) n_read / (double) sample_rate; seconds += time_slice; // std::cout << "Time Slice: " << time_slice << std::endl; - // if (!TestDestroy()) { - // wxThreadEvent event(wxEVT_THREAD, EVENT_SDR_INPUT); - // event.SetPayload(new_buffer); - // wxQueueEvent(frame, event.Clone()); - // } else { + if (!TestDestroy()) { + wxThreadEvent event(wxEVT_THREAD, EVENT_SDR_INPUT); + event.SetPayload(new_buffer); + wxQueueEvent(m_pQueue->getHandler(), event.Clone()); + } else { delete new_buffer; - // } + } } } std::cout << std::endl << "Done." << std::endl << std::endl; diff --git a/src/SDRThread.h b/src/SDRThread.h index 3e80451..0bb13e8 100644 --- a/src/SDRThread.h +++ b/src/SDRThread.h @@ -9,7 +9,8 @@ #include "wx/thread.h" -#include "AppFrame.h" +#include "SDRThread.h" +#include "IQBufferThread.h" #include "SDRThreadQueue.h" // declare a new type of event, to be used by our SDRThread class: @@ -18,21 +19,21 @@ //wxDECLARE_EVENT(wxEVT_COMMAND_SDRThread_INPUT, wxThreadEvent); enum { - EVENT_SDR_INPUT = wxID_HIGHEST+1 + EVENT_SDR_INPUT = wxID_HIGHEST + 1 }; class SDRThread: public wxThread { public: - rtlsdr_dev_t *dev; + rtlsdr_dev_t *dev; - SDRThread(SDRThreadQueue* pQueue, int id=0); - ~SDRThread(); + SDRThread(SDRThreadQueue* pQueue, int id = 0); + ~SDRThread(); - void enumerate_rtl(); + void enumerate_rtl(); protected: - virtual ExitCode Entry(); - uint32_t sample_rate; - SDRThreadQueue* m_pQueue; - int m_ID; + virtual ExitCode Entry(); + uint32_t sample_rate; + SDRThreadQueue* m_pQueue; + int m_ID; }; diff --git a/src/SDRThreadQueue.h b/src/SDRThreadQueue.h index 59cf423..7f7e09a 100644 --- a/src/SDRThreadQueue.h +++ b/src/SDRThreadQueue.h @@ -1,60 +1,63 @@ #pragma once -class SDRThreadTask - { - public: - enum SDR_COMMAND - { - SDR_THREAD_EXIT=wxID_EXIT, - SDR_THREAD_NULL=wxID_HIGHEST+1, - SDR_THREAD_STARTED, - SDR_THREAD_PROCESS, - SDR_THREAD_ERROR, - }; +#include - SDRThreadTask() : m_cmd(eID_THREAD_NULL) {} - SDRThreadTask(SDR_COMMAND cmd, const wxString& arg) : m_cmd(cmd), m_Arg(arg) {} - SDR_COMMAND m_cmd; - wxString m_Arg; - }; - - class SDRThreadQueue - { - public: - enum SDR_PRIORITY { SDR_PRIORITY_HIGHEST, SDR_PRIORITY_HIGHER, SDR_PRIORITY_NORMAL, SDR_PRIORITY_BELOW_NORMAL, SDR_PRIORITY_LOW, SDR_PRIORITY_IDLE }; - SDRThreadQueue(wxEvtHandler* pParent) : m_pParent(pParent) {} - void AddTask(const SDRThreadTask& task, const SDR_PRIORITY& priority=SDR_PRIORITY_NORMAL) - { - wxMutexLocker lock(m_MutexQueue); - m_Tasks.insert(std::make_pair(priority, task)); - m_QueueCount.Post(); - } - SDRThreadTask Pop() - { - SDRThreadTask element; - m_QueueCount.Wait(); - m_MutexQueue.Lock(); - element=(m_Tasks.begin())->second; - m_Tasks.erase(m_Tasks.begin()); - m_MutexQueue.Unlock(); - return element; - } - void Report(const SDRThreadTask::SDR_COMMAND& cmd, const wxString& sArg=wxEmptyString, int iArg=0) - { - wxCommandEvent evt(wxEVT_THREAD, cmd); - evt.SetString(sArg); - evt.SetInt(iArg); - m_pParent->AddPendingEvent(evt); - } - size_t Stacksize() - { - wxMutexLocker lock(m_MutexQueue); - return m_Tasks.size(); - } +class SDRThreadTask { +public: + enum SDR_COMMAND { + SDR_THREAD_EXIT = wxID_EXIT, SDR_THREAD_NULL = wxID_HIGHEST + 1, SDR_THREAD_STARTED, SDR_THREAD_PROCESS, SDR_THREAD_ERROR, + }; - private: - wxEvtHandler* m_pParent; - std::multimap m_Tasks; - wxMutex m_MutexQueue; - wxSemaphore m_QueueCount; - }; \ No newline at end of file + SDRThreadTask() : + m_cmd(SDR_THREAD_NULL) { + } + SDRThreadTask(SDR_COMMAND cmd, const wxString& arg) : + m_cmd(cmd), m_Arg(arg) { + } + SDR_COMMAND m_cmd; + wxString m_Arg; +}; + +class SDRThreadQueue { +public: + enum SDR_PRIORITY { + SDR_PRIORITY_HIGHEST, SDR_PRIORITY_HIGHER, SDR_PRIORITY_NORMAL, SDR_PRIORITY_BELOW_NORMAL, SDR_PRIORITY_LOW, SDR_PRIORITY_IDLE + }; + SDRThreadQueue(wxEvtHandler* pParent) : + m_pParent(pParent) { + } + void AddTask(const SDRThreadTask& task, const SDR_PRIORITY& priority = SDR_PRIORITY_NORMAL) { + wxMutexLocker lock(m_MutexQueue); + m_Tasks.insert(std::make_pair(priority, task)); + m_QueueCount.Post(); + } + SDRThreadTask Pop() { + SDRThreadTask element; + m_QueueCount.Wait(); + m_MutexQueue.Lock(); + element = (m_Tasks.begin())->second; + m_Tasks.erase(m_Tasks.begin()); + m_MutexQueue.Unlock(); + return element; + } + void Report(const SDRThreadTask::SDR_COMMAND& cmd, const wxString& sArg = wxEmptyString, int iArg = 0) { + wxCommandEvent evt(wxEVT_THREAD, cmd); + evt.SetString(sArg); + evt.SetInt(iArg); + m_pParent->AddPendingEvent(evt); + } + size_t Stacksize() { + wxMutexLocker lock(m_MutexQueue); + return m_Tasks.size(); + } + + wxEvtHandler* getHandler() { + return m_pParent; + } + +private: + wxEvtHandler* m_pParent; + std::multimap m_Tasks; + wxMutex m_MutexQueue; + wxSemaphore m_QueueCount; +};