From 8dee90cd639fb83bada2d090b9f0eac3ec231830 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 4 Nov 2014 17:25:04 -0500 Subject: [PATCH 1/4] Starting work on threading model, incomplete Includes experimental averaging of spectrum --- src/AppFrame.cpp | 39 ++++++++++ src/AppFrame.h | 5 +- src/CubicSDR.cpp | 39 ---------- src/CubicSDR.h | 8 +- src/PrimaryGLContext.cpp | 40 +++++----- src/PrimaryGLContext.h | 5 ++ src/SDRThread.cpp | 47 ++++++++---- src/SDRThread.h | 6 +- src/SDRThreadQueue.cpp | 0 src/SDRThreadQueue.h | 60 +++++++++++++++ src/WorkerThread.cpp | 154 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 323 insertions(+), 80 deletions(-) create mode 100644 src/SDRThreadQueue.cpp create mode 100644 src/SDRThreadQueue.h create mode 100644 src/WorkerThread.cpp diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 7850262..91a9def 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -42,12 +42,51 @@ AppFrame::AppFrame() : Centre(); Show(); + + t_SDR = new SDRThread(appframe); + if (t_SDR->Run() != wxTHREAD_NO_ERROR) { + wxLogError + ("Can't create the thread!"); + delete t_SDR; + 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 = 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); } 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_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 b960df0..4a8b259 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -15,6 +15,9 @@ private: void OnIdle(wxIdleEvent& event); TestGLCanvas *canvas; - + SDRThread *t_SDR; + IQBufferThread *t_IQBuffer; + wxCriticalSection m_pThreadCS; + wxDECLARE_EVENT_TABLE(); }; diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index af726dc..1f93b67 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -21,51 +21,12 @@ bool CubicSDR::OnInit() { AppFrame *appframe = new AppFrame(); - t_SDR = new SDRThread(appframe); - if (t_SDR->Run() != wxTHREAD_NO_ERROR) { - wxLogError - ("Can't create the thread!"); - delete t_SDR; - 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 = NULL; - } - return true; } int CubicSDR::OnExit() { delete m_glContext; - { - 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!"); - } - } - } - wxThread::This()->Sleep(1); - // while (1) { // { wxCriticalSectionLocker enter(m_pThreadCS); // if (!m_pThread) diff --git a/src/CubicSDR.h b/src/CubicSDR.h index f73e5e7..8708906 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -21,15 +21,9 @@ public: virtual bool OnInit(); virtual int OnExit(); - void OnEventInput(wxEvent& event) { - std::cout << "event !" << std::endl; - } - private: PrimaryGLContext *m_glContext; - SDRThread *t_SDR; - IQBufferThread *t_IQBuffer; - wxCriticalSection m_pThreadCS; + }; DECLARE_APP(CubicSDR) diff --git a/src/PrimaryGLContext.cpp b/src/PrimaryGLContext.cpp index 984c842..ac0f2ed 100644 --- a/src/PrimaryGLContext.cpp +++ b/src/PrimaryGLContext.cpp @@ -156,8 +156,14 @@ void TestGLCanvas::setData(std::vector *data) { fftw_execute(plan[0]); fftw_execute(plan[1]); - double result[FFT_SIZE]; - double fft_floor, fft_ceil; + double fft_ceil = 0; + // fft_floor, + + if (fft_result.size() *data) { double x = out[j?0:1][j?((FFT_SIZE-1)-i):((FFT_SIZE/2)+i)][0]; double y = out[j?0:1][j?((FFT_SIZE-1)-i):((FFT_SIZE/2)+i)][1]; double z = sqrt(x * x + y * y); - - if (i == 1) { - fft_floor = fft_ceil = c; - } else if (i < FFT_SIZE - 1) { - if (c < fft_floor) { - fft_floor = c; - } - if (c > fft_ceil) { - fft_ceil = c; - } - } + + double r = (c fft_ceil) { + fft_ceil = fft_result_maa[i]; + } } for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) { - points[i * 2 + 1] = (result[i] - fft_floor) / (fft_ceil - fft_floor); + points[i * 2 + 1] = fft_result_maa[i] / fft_ceil; points[i * 2] = ((double) i / (double) iMax); } } diff --git a/src/PrimaryGLContext.h b/src/PrimaryGLContext.h index 61a4a68..b940a58 100644 --- a/src/PrimaryGLContext.h +++ b/src/PrimaryGLContext.h @@ -31,6 +31,11 @@ public: fftw_complex *in, *out[2]; fftw_plan plan[2]; + std::vector fft_result; + std::vector fft_result_ma; + std::vector fft_result_maa; + + private: void OnPaint(wxPaintEvent& event); void OnKeyDown(wxKeyEvent& event); diff --git a/src/SDRThread.cpp b/src/SDRThread.cpp index 7e5de1a..6144794 100644 --- a/src/SDRThread.cpp +++ b/src/SDRThread.cpp @@ -5,10 +5,9 @@ //wxDEFINE_EVENT(wxEVT_COMMAND_SDRThread_INPUT, wxThreadEvent); -SDRThread::SDRThread(AppFrame *frame) : - wxThread(wxTHREAD_DETACHED) { +SDRThread::SDRThread(SDRThreadQueue* pQueue, int id=0) : + wxThread(wxTHREAD_DETACHED), m_pQueue(pQueue), m_ID(id) { dev = NULL; - this->frame = frame; } SDRThread::~SDRThread() { @@ -112,12 +111,34 @@ 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) + } + } + rtlsdr_read_sync(dev, buf, BUF_SIZE, &n_read); // move around - long freq = 98000000+(20000000)*sin(seconds/50.0); - rtlsdr_set_center_freq(dev, freq); - - std::cout << "Frequency: " << freq << std::endl; + // long freq = 98000000+(20000000)*sin(seconds/50.0); + // rtlsdr_set_center_freq(dev, freq); + // std::cout << "Frequency: " << freq << std::endl; if (!TestDestroy()) { std::vector *new_buffer = new std::vector(); @@ -130,13 +151,13 @@ wxThread::ExitCode SDRThread::Entry() { 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(frame, 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 3097a7d..3e80451 100644 --- a/src/SDRThread.h +++ b/src/SDRThread.h @@ -10,6 +10,7 @@ #include "wx/thread.h" #include "AppFrame.h" +#include "SDRThreadQueue.h" // declare a new type of event, to be used by our SDRThread class: //wxDECLARE_EVENT(wxEVT_COMMAND_SDRThread_COMPLETED, wxThreadEvent); @@ -24,13 +25,14 @@ class SDRThread: public wxThread { public: rtlsdr_dev_t *dev; - SDRThread(AppFrame *appframe); + SDRThread(SDRThreadQueue* pQueue, int id=0); ~SDRThread(); void enumerate_rtl(); protected: virtual ExitCode Entry(); - AppFrame *frame; uint32_t sample_rate; + SDRThreadQueue* m_pQueue; + int m_ID; }; diff --git a/src/SDRThreadQueue.cpp b/src/SDRThreadQueue.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/SDRThreadQueue.h b/src/SDRThreadQueue.h new file mode 100644 index 0000000..59cf423 --- /dev/null +++ b/src/SDRThreadQueue.h @@ -0,0 +1,60 @@ +#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, + }; + + 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(); + } + + private: + wxEvtHandler* m_pParent; + std::multimap m_Tasks; + wxMutex m_MutexQueue; + wxSemaphore m_QueueCount; + }; \ No newline at end of file diff --git a/src/WorkerThread.cpp b/src/WorkerThread.cpp new file mode 100644 index 0000000..b2e7221 --- /dev/null +++ b/src/WorkerThread.cpp @@ -0,0 +1,154 @@ + + + + class WorkerThread : public wxThread + { + public: + WorkerThread(SDRThreadQueue* pQueue, int id=0) : m_pQueue(pQueue), m_ID(id) { assert(pQueue); wxThread::Create(); } + + private: + SDRThreadQueue* m_pQueue; + int m_ID; + + virtual wxThread::ExitCode Entry() + { + Sleep(1000); // sleep a while to simulate some time-consuming init procedure + SDRThreadTask::SDR_COMMAND iErr; + m_pQueue->Report(SDRThreadTask::SDR_THREAD_STARTED, wxEmptyString, m_ID); // tell main thread that worker thread has successfully started + try { while(true) OnTask(); } // this is the main loop: process tasks until a task handler throws + catch(SDRThreadTask::SDR_COMMAND& i) { m_pQueue->Report(iErr=i, wxEmptyString, m_ID); } // catch return value from error condition + return (wxThread::ExitCode)iErr; // and return exit code + } // virtual wxThread::ExitCode Entry() + + virtual void OnTask() + { + 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) + } // virtual void OnTask() + }; // class WorkerThread : public wxThread + + + // ---------------------------------------------------------------------------- + // main frame + // ---------------------------------------------------------------------------- + class MyFrame : public wxFrame + { + enum { eQUIT=wxID_CLOSE, eSTART_THREAD=wxID_HIGHEST+100 }; + DECLARE_DYNAMIC_CLASS(MyFrame) + public: + MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title), m_pQueue(NULL) + { + wxMenu *fileMenu=new wxMenu; + fileMenu->Append(eSTART_THREAD, _T("&Start a thread\tAlt-S"), _T("Starts one worker thread")); + fileMenu->Append(SDRThreadTask::SDR_THREAD_EXIT, _T("Sto&p a thread\tAlt-P"), _T("Stops one worker thread")); + fileMenu->Append(SDRThreadTask::SDR_THREAD_JOB, _T("&Add task to thread\tAlt-A"), _T("Adds a task to the worker thread")); + fileMenu->Append(SDRThreadTask::SDR_THREAD_JOBERR, _T("Add &errorneous task to thread\tAlt-E"), _T("Adds am errorneous task to the worker thread")); + fileMenu->Append(eQUIT, _T("E&xit\tAlt-X"), _T("Exit this program")); + wxMenuBar *menuBar=new wxMenuBar(); + menuBar->Append(fileMenu, _T("&Options")); + SetMenuBar(menuBar); + EnableThreadControls(false); // disable thread controls since worker thread isn't running yet + fileMenu->Enable(eSTART_THREAD, true); // starting threads should always be possible + CreateStatusBar(); + SetStatusText(_T("Worker thread sample")); + m_pQueue=new SDRThreadQueue(this); + } // MyFrame(const wxString& title) + ~MyFrame() { delete m_pQueue; } + void EnableThreadControls(bool bEnable) + { + wxMenu* pMenu=GetMenuBar()->GetMenu(0); + static const int MENUIDS[]={eSTART_THREAD, SDRThreadTask::SDR_THREAD_EXIT, SDRThreadTask::SDR_THREAD_JOB, SDRThreadTask::SDR_THREAD_JOBERR}; + for(int i=0; iEnable(MENUIDS[i++], bEnable)); + } + void OnStart(wxCommandEvent& WXUNUSED(event)) // start one worker thread + { + int id=m_Threads.empty()?1:m_Threads.back()+1; + m_Threads.push_back(id); + WorkerThread* pThread=new WorkerThread(m_pQueue, id); // create a new worker thread, increment thread counter (this implies, thread will start OK) + pThread->Run(); + SetStatusText(wxString::Format(wxT("[%i]: Thread started."), id)); + } + void OnStop(wxCommandEvent& WXUNUSED(event)) // stop one worker thread + { + if(m_Threads.empty()) { EnableThreadControls(false); Destroy(); return; } // no thread(s) running: frame can be destroyed right away + m_pQueue->AddTask(SDRThreadTask(SDRThreadTask::SDR_THREAD_EXIT, wxEmptyString), SDRThreadQueue::eHIGHEST); // add SDR_THREAD_EXIT notification with highest priority to bypass other running tasks + SetStatusText(_T("Stopping thread...")); + } + void OnTask(wxCommandEvent& event) // handler for launching a task for worker thread(s) + { + int iTask=rand(); + m_pQueue->AddTask(SDRThreadTask((SDRThreadTask::SDR_COMMAND)event.GetId(), wxString::Format(wxT("%u"), iTask))); + SetStatusText(wxString::Format(wxT("Task #%i started."), iTask)); // just set the status text + } + void OnThread(wxCommandEvent& event) // handler for thread notifications + { + switch(event.GetId()) + { + case SDRThreadTask::SDR_THREAD_JOB: + SetStatusText(wxString::Format(wxT("[%i]: %s"), event.GetInt(), event.GetString().c_str())); // progress display + break; + case SDRThreadTask::SDR_THREAD_EXIT: + SetStatusText(wxString::Format(wxT("[%i]: Stopped."), event.GetInt())); + m_Threads.remove(event.GetInt()); // thread has exited: remove thread ID from list + if(m_Threads.empty()) { EnableThreadControls(false); Destroy(); } // destroy main window if no more threads + break; + case SDRThreadTask::SDR_THREAD_STARTED: + SetStatusText(wxString::Format(wxT("[%i]: Ready."), event.GetInt())); + EnableThreadControls(true); // at least one thread successfully started: enable controls + break; + default: event.Skip(); + } + } + void OnQuit(wxCommandEvent& WXUNUSED(event)) + { + if(m_Threads.empty()) { Destroy(); return; } // no thread(s) running - exit right away + for(size_t t=0; tAddTask(SDRThreadTask(SDRThreadTask::SDR_THREAD_EXIT, wxEmptyString), SDRThreadQueue::eHIGHEST); } // send all running threads the "EXIT" signal + void OnClose(wxCloseEvent& WXUNUSED(event)) { wxCommandEvent e; OnQuit(e); } // just run OnQuit() which will terminate worker threads and destroy the main frame + private: + MyFrame() : wxFrame() {} + SDRThreadQueue* m_pQueue; + std::list m_Threads; + DECLARE_EVENT_TABLE() + }; // class MyFrame : public wxFrame + IMPLEMENT_DYNAMIC_CLASS(MyFrame, wxFrame) + BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(SDRThreadTask::SDR_THREAD_JOB, MyFrame::OnTask) + EVT_MENU(SDRThreadTask::SDR_THREAD_JOBERR, MyFrame::OnTask) + EVT_MENU(eSTART_THREAD, MyFrame::OnStart) + EVT_MENU(SDRThreadTask::SDR_THREAD_EXIT, MyFrame::OnStop) + EVT_COMMAND(wxID_ANY, wxEVT_THREAD, MyFrame::OnThread) + EVT_MENU(eQUIT, MyFrame::OnQuit) + EVT_CLOSE(MyFrame::OnClose) + END_EVENT_TABLE() + + // ---------------------------------------------------------------------------- + // the application + // ---------------------------------------------------------------------------- + class MyApp : public wxApp + { + public: + virtual bool OnInit() + { + if(!wxApp::OnInit()) return false; + MyFrame *frame=new MyFrame(_T("Minimal wxWidgets App")); + frame->Show(true); + return true; + } + }; // class MyApp : public wxApp + IMPLEMENT_APP(MyApp) \ No newline at end of file From 9896808b228590d5d58337029b96be99a984d399 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 4 Nov 2014 18:39:08 -0500 Subject: [PATCH 2/4] Clean-up / re-factor thread queue and task handler compiling and program functional --- CMakeLists.txt | 2 + src/AppFrame.cpp | 61 ++++++++++++--------- src/AppFrame.h | 5 +- src/CubicSDR.h | 3 - src/PrimaryGLContext.cpp | 43 +++++++++------ src/PrimaryGLContext.h | 2 + src/SDRThread.cpp | 64 +++++++++++----------- src/SDRThread.h | 21 +++---- src/SDRThreadQueue.h | 115 ++++++++++++++++++++------------------- 9 files changed, 168 insertions(+), 148 deletions(-) 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; +}; From a8f1a875059b5fd79ba07b91227b5ca854488cd8 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 4 Nov 2014 19:52:11 -0500 Subject: [PATCH 3/4] Can now control SDRThread freq. via thread task Basic left/right keys bound for shifting frequency test. --- CMakeLists.txt | 2 ++ src/AppFrame.cpp | 15 +++++++++-- src/AppFrame.h | 4 +++ src/CubicSDRDefs.h | 2 ++ src/PrimaryGLContext.cpp | 16 +++++++++--- src/PrimaryGLContext.h | 22 ++++++++-------- src/SDRThread.cpp | 38 ++++++++++++--------------- src/SDRThreadQueue.cpp | 43 +++++++++++++++++++++++++++++++ src/SDRThreadQueue.h | 55 ++++++++-------------------------------- src/SDRThreadTask.cpp | 9 +++++++ src/SDRThreadTask.h | 24 ++++++++++++++++++ 11 files changed, 145 insertions(+), 85 deletions(-) create mode 100644 src/SDRThreadTask.cpp create mode 100644 src/SDRThreadTask.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e7e1d17..89164eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ SET (cubicsdr_sources src/PrimaryGLContext.cpp src/AppFrame.cpp src/SDRThreadQueue.cpp + src/SDRThreadTask.cpp ) SET (cubicsdr_headers @@ -89,6 +90,7 @@ SET (cubicsdr_headers src/AppFrame.h src/CubicSDRDefs.h src/SDRThreadQueue.h + src/SDRThreadTask.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 52724a1..eb1046f 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -21,7 +21,7 @@ EVT_IDLE(AppFrame::OnIdle) wxEND_EVENT_TABLE() AppFrame::AppFrame() : - wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) { + wxFrame(NULL, wxID_ANY, wxT("CubicSDR")), frequency(DEFAULT_FREQ) { canvas = new TestGLCanvas(this, NULL); @@ -57,7 +57,7 @@ AppFrame::AppFrame() : // wxLogError // ("Can't create the thread!"); // delete t_IQBuffer; - t_IQBuffer = NULL; + t_IQBuffer = NULL; // } // static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 }; @@ -116,3 +116,14 @@ void AppFrame::OnIdle(wxIdleEvent& event) { event.Skip(); } + +void AppFrame::setFrequency(unsigned int freq) { + frequency = freq; + SDRThreadTask task = SDRThreadTask(SDRThreadTask::SDR_THREAD_TUNING); + task.setUInt(freq); + m_pQueue->addTask(task, SDRThreadQueue::SDR_PRIORITY_HIGHEST); +} + +int AppFrame::getFrequency() { + return frequency; +} diff --git a/src/AppFrame.h b/src/AppFrame.h index 928b313..50cfe8b 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -11,6 +11,9 @@ public: ~AppFrame(); void OnEventInput(wxThreadEvent& event); + void setFrequency(unsigned int freq); + int getFrequency(); + private: void OnClose(wxCommandEvent& event); void OnNewWindow(wxCommandEvent& event); @@ -21,6 +24,7 @@ private: IQBufferThread *t_IQBuffer; wxCriticalSection m_pThreadCS; SDRThreadQueue* m_pQueue; + unsigned int frequency; wxDECLARE_EVENT_TABLE(); }; diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index 57e90cc..94a2a04 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -4,3 +4,5 @@ #define SRATE 2500000 #define FFT_SIZE 8192 +#define DEFAULT_FREQ 105700000 + diff --git a/src/PrimaryGLContext.cpp b/src/PrimaryGLContext.cpp index 59b8c28..fde55e7 100644 --- a/src/PrimaryGLContext.cpp +++ b/src/PrimaryGLContext.cpp @@ -12,6 +12,7 @@ #include "CubicSDR.h" #include "CubicSDRDefs.h" +#include "AppFrame.h" #include wxString glGetwxString(GLenum name) { @@ -98,7 +99,7 @@ wxEND_EVENT_TABLE() TestGLCanvas::TestGLCanvas(wxWindow *parent, int *attribList) : wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, - wxFULL_REPAINT_ON_RESIZE) { + wxFULL_REPAINT_ON_RESIZE), parent(parent) { int in_block_size = BUF_SIZE / 2; int out_block_size = FFT_SIZE; @@ -109,7 +110,7 @@ TestGLCanvas::TestGLCanvas(wxWindow *parent, int *attribList) : 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; + fft_ceil_ma = fft_ceil_maa = 1.0; } void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { @@ -127,10 +128,17 @@ void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { void TestGLCanvas::OnKeyDown(wxKeyEvent& event) { float angle = 5.0; + unsigned int freq; switch (event.GetKeyCode()) { case WXK_RIGHT: + freq = ((AppFrame*) parent)->getFrequency(); + freq += 100000; + ((AppFrame*) parent)->setFrequency(freq); break; case WXK_LEFT: + freq = ((AppFrame*) parent)->getFrequency(); + freq -= 100000; + ((AppFrame*) parent)->setFrequency(freq); break; case WXK_DOWN: break; @@ -200,8 +208,8 @@ void TestGLCanvas::setData(std::vector *data) { } } - 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; + 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_maa; diff --git a/src/PrimaryGLContext.h b/src/PrimaryGLContext.h index d87957e..e9c973a 100644 --- a/src/PrimaryGLContext.h +++ b/src/PrimaryGLContext.h @@ -7,8 +7,7 @@ #include "CubicSDRDefs.h" #include "fftw3.h" -class PrimaryGLContext : public wxGLContext -{ +class PrimaryGLContext: public wxGLContext { public: PrimaryGLContext(wxGLCanvas *canvas); @@ -19,13 +18,19 @@ private: GLuint m_textures[6]; }; -class TestGLCanvas : public wxGLCanvas -{ +class TestGLCanvas: public wxGLCanvas { public: TestGLCanvas(wxWindow *parent, int *attribList = NULL); void setData(std::vector *data); +private: + void OnPaint(wxPaintEvent& event); + void OnKeyDown(wxKeyEvent& event); + + void OnIdle(wxIdleEvent &event); + + wxWindow *parent; std::vector points; fftw_complex *in, *out[2]; @@ -36,13 +41,6 @@ public: std::vector fft_result; std::vector fft_result_ma; std::vector fft_result_maa; - -private: - void OnPaint(wxPaintEvent& event); - void OnKeyDown(wxKeyEvent& event); - - void OnIdle(wxIdleEvent &event); - - wxDECLARE_EVENT_TABLE(); +wxDECLARE_EVENT_TABLE(); }; diff --git a/src/SDRThread.cpp b/src/SDRThread.cpp index 0b44b54..9be5591 100644 --- a/src/SDRThread.cpp +++ b/src/SDRThread.cpp @@ -95,7 +95,7 @@ wxThread::ExitCode SDRThread::Entry() { rtlsdr_open(&dev, use_my_dev); rtlsdr_set_sample_rate(dev, SRATE); - rtlsdr_set_center_freq(dev, 105700000); + rtlsdr_set_center_freq(dev, DEFAULT_FREQ); rtlsdr_set_agc_mode(dev, 1); rtlsdr_set_offset_tuning(dev, 1); rtlsdr_reset_buffer(dev); @@ -110,33 +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 + if (m_pQueue->stackSize()) { + bool freq_changed = false; + float new_freq; + + 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 + case SDRThreadTask::SDR_THREAD_TUNING: + std::cout << "Set frequency: " << task.getUInt() << std::endl; + freq_changed = true; + new_freq = task.getUInt(); + break; } } + + if (freq_changed) { + rtlsdr_set_center_freq(dev, new_freq); + } } rtlsdr_read_sync(dev, buf, BUF_SIZE, &n_read); - // move around - // long freq = 98000000+(20000000)*sin(seconds/50.0); - // rtlsdr_set_center_freq(dev, freq); - // std::cout << "Frequency: " << freq << std::endl; if (!TestDestroy()) { std::vector *new_buffer = new std::vector(); diff --git a/src/SDRThreadQueue.cpp b/src/SDRThreadQueue.cpp index e69de29..6f75c42 100644 --- a/src/SDRThreadQueue.cpp +++ b/src/SDRThreadQueue.cpp @@ -0,0 +1,43 @@ +#include "SDRThreadQueue.h" + +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +SDRThreadQueue::SDRThreadQueue(wxEvtHandler* pParent) : + m_pParent(pParent) { +} + +void SDRThreadQueue::addTask(const SDRThreadTask& task, const SDR_PRIORITY& priority) { + wxMutexLocker lock(m_MutexQueue); + m_Tasks.insert(std::make_pair(priority, task)); + m_QueueCount.Post(); +} + +SDRThreadTask SDRThreadQueue::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 SDRThreadQueue::report(const SDRThreadTask::SDR_COMMAND& cmd, const wxString& sArg, int iArg) { + wxCommandEvent evt(wxEVT_THREAD, cmd); + evt.SetString(sArg); + evt.SetInt(iArg); + m_pParent->AddPendingEvent(evt); +} + +size_t SDRThreadQueue::stackSize() { + wxMutexLocker lock(m_MutexQueue); + return m_Tasks.size(); +} + +wxEvtHandler* SDRThreadQueue::getHandler() { + return m_pParent; +} diff --git a/src/SDRThreadQueue.h b/src/SDRThreadQueue.h index 7f7e09a..dc9cc3e 100644 --- a/src/SDRThreadQueue.h +++ b/src/SDRThreadQueue.h @@ -1,59 +1,24 @@ #pragma once #include +#include "SDRThreadTask.h" -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, - }; - - 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; -}; +#include "wx/event.h" 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(); - } + SDRThreadQueue(wxEvtHandler* pParent); - wxEvtHandler* getHandler() { - return m_pParent; - } + void addTask(const SDRThreadTask& task, const SDR_PRIORITY& priority = SDR_PRIORITY_NORMAL); + void report(const SDRThreadTask::SDR_COMMAND& cmd, const wxString& sArg = wxEmptyString, int iArg = 0); + + SDRThreadTask pop(); + size_t stackSize(); + + wxEvtHandler* getHandler(); private: wxEvtHandler* m_pParent; diff --git a/src/SDRThreadTask.cpp b/src/SDRThreadTask.cpp new file mode 100644 index 0000000..f0de701 --- /dev/null +++ b/src/SDRThreadTask.cpp @@ -0,0 +1,9 @@ +#include "SDRThreadTask.h" + +void SDRThreadTask::setUInt(unsigned int i) { + arg_int = i; +} + +unsigned int SDRThreadTask::getUInt() { + return arg_int; +} diff --git a/src/SDRThreadTask.h b/src/SDRThreadTask.h new file mode 100644 index 0000000..93336c1 --- /dev/null +++ b/src/SDRThreadTask.h @@ -0,0 +1,24 @@ +#pragma once + +#include "wx/defs.h" +#include "wx/string.h" + +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, SDR_THREAD_TUNING + }; + + SDRThreadTask() : + m_cmd(SDR_THREAD_NULL) { + } + SDRThreadTask(SDR_COMMAND cmd) : + m_cmd(cmd) { + } + + void setUInt(unsigned int i); + unsigned int getUInt(); + + SDR_COMMAND m_cmd; + unsigned int arg_int; +}; From 7eae5517faad67856cb9fb54a80dc31eb174600b Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 4 Nov 2014 19:54:00 -0500 Subject: [PATCH 4/4] remove example code --- src/WorkerThread.cpp | 154 ------------------------------------------- 1 file changed, 154 deletions(-) delete mode 100644 src/WorkerThread.cpp diff --git a/src/WorkerThread.cpp b/src/WorkerThread.cpp deleted file mode 100644 index b2e7221..0000000 --- a/src/WorkerThread.cpp +++ /dev/null @@ -1,154 +0,0 @@ - - - - class WorkerThread : public wxThread - { - public: - WorkerThread(SDRThreadQueue* pQueue, int id=0) : m_pQueue(pQueue), m_ID(id) { assert(pQueue); wxThread::Create(); } - - private: - SDRThreadQueue* m_pQueue; - int m_ID; - - virtual wxThread::ExitCode Entry() - { - Sleep(1000); // sleep a while to simulate some time-consuming init procedure - SDRThreadTask::SDR_COMMAND iErr; - m_pQueue->Report(SDRThreadTask::SDR_THREAD_STARTED, wxEmptyString, m_ID); // tell main thread that worker thread has successfully started - try { while(true) OnTask(); } // this is the main loop: process tasks until a task handler throws - catch(SDRThreadTask::SDR_COMMAND& i) { m_pQueue->Report(iErr=i, wxEmptyString, m_ID); } // catch return value from error condition - return (wxThread::ExitCode)iErr; // and return exit code - } // virtual wxThread::ExitCode Entry() - - virtual void OnTask() - { - 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) - } // virtual void OnTask() - }; // class WorkerThread : public wxThread - - - // ---------------------------------------------------------------------------- - // main frame - // ---------------------------------------------------------------------------- - class MyFrame : public wxFrame - { - enum { eQUIT=wxID_CLOSE, eSTART_THREAD=wxID_HIGHEST+100 }; - DECLARE_DYNAMIC_CLASS(MyFrame) - public: - MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title), m_pQueue(NULL) - { - wxMenu *fileMenu=new wxMenu; - fileMenu->Append(eSTART_THREAD, _T("&Start a thread\tAlt-S"), _T("Starts one worker thread")); - fileMenu->Append(SDRThreadTask::SDR_THREAD_EXIT, _T("Sto&p a thread\tAlt-P"), _T("Stops one worker thread")); - fileMenu->Append(SDRThreadTask::SDR_THREAD_JOB, _T("&Add task to thread\tAlt-A"), _T("Adds a task to the worker thread")); - fileMenu->Append(SDRThreadTask::SDR_THREAD_JOBERR, _T("Add &errorneous task to thread\tAlt-E"), _T("Adds am errorneous task to the worker thread")); - fileMenu->Append(eQUIT, _T("E&xit\tAlt-X"), _T("Exit this program")); - wxMenuBar *menuBar=new wxMenuBar(); - menuBar->Append(fileMenu, _T("&Options")); - SetMenuBar(menuBar); - EnableThreadControls(false); // disable thread controls since worker thread isn't running yet - fileMenu->Enable(eSTART_THREAD, true); // starting threads should always be possible - CreateStatusBar(); - SetStatusText(_T("Worker thread sample")); - m_pQueue=new SDRThreadQueue(this); - } // MyFrame(const wxString& title) - ~MyFrame() { delete m_pQueue; } - void EnableThreadControls(bool bEnable) - { - wxMenu* pMenu=GetMenuBar()->GetMenu(0); - static const int MENUIDS[]={eSTART_THREAD, SDRThreadTask::SDR_THREAD_EXIT, SDRThreadTask::SDR_THREAD_JOB, SDRThreadTask::SDR_THREAD_JOBERR}; - for(int i=0; iEnable(MENUIDS[i++], bEnable)); - } - void OnStart(wxCommandEvent& WXUNUSED(event)) // start one worker thread - { - int id=m_Threads.empty()?1:m_Threads.back()+1; - m_Threads.push_back(id); - WorkerThread* pThread=new WorkerThread(m_pQueue, id); // create a new worker thread, increment thread counter (this implies, thread will start OK) - pThread->Run(); - SetStatusText(wxString::Format(wxT("[%i]: Thread started."), id)); - } - void OnStop(wxCommandEvent& WXUNUSED(event)) // stop one worker thread - { - if(m_Threads.empty()) { EnableThreadControls(false); Destroy(); return; } // no thread(s) running: frame can be destroyed right away - m_pQueue->AddTask(SDRThreadTask(SDRThreadTask::SDR_THREAD_EXIT, wxEmptyString), SDRThreadQueue::eHIGHEST); // add SDR_THREAD_EXIT notification with highest priority to bypass other running tasks - SetStatusText(_T("Stopping thread...")); - } - void OnTask(wxCommandEvent& event) // handler for launching a task for worker thread(s) - { - int iTask=rand(); - m_pQueue->AddTask(SDRThreadTask((SDRThreadTask::SDR_COMMAND)event.GetId(), wxString::Format(wxT("%u"), iTask))); - SetStatusText(wxString::Format(wxT("Task #%i started."), iTask)); // just set the status text - } - void OnThread(wxCommandEvent& event) // handler for thread notifications - { - switch(event.GetId()) - { - case SDRThreadTask::SDR_THREAD_JOB: - SetStatusText(wxString::Format(wxT("[%i]: %s"), event.GetInt(), event.GetString().c_str())); // progress display - break; - case SDRThreadTask::SDR_THREAD_EXIT: - SetStatusText(wxString::Format(wxT("[%i]: Stopped."), event.GetInt())); - m_Threads.remove(event.GetInt()); // thread has exited: remove thread ID from list - if(m_Threads.empty()) { EnableThreadControls(false); Destroy(); } // destroy main window if no more threads - break; - case SDRThreadTask::SDR_THREAD_STARTED: - SetStatusText(wxString::Format(wxT("[%i]: Ready."), event.GetInt())); - EnableThreadControls(true); // at least one thread successfully started: enable controls - break; - default: event.Skip(); - } - } - void OnQuit(wxCommandEvent& WXUNUSED(event)) - { - if(m_Threads.empty()) { Destroy(); return; } // no thread(s) running - exit right away - for(size_t t=0; tAddTask(SDRThreadTask(SDRThreadTask::SDR_THREAD_EXIT, wxEmptyString), SDRThreadQueue::eHIGHEST); } // send all running threads the "EXIT" signal - void OnClose(wxCloseEvent& WXUNUSED(event)) { wxCommandEvent e; OnQuit(e); } // just run OnQuit() which will terminate worker threads and destroy the main frame - private: - MyFrame() : wxFrame() {} - SDRThreadQueue* m_pQueue; - std::list m_Threads; - DECLARE_EVENT_TABLE() - }; // class MyFrame : public wxFrame - IMPLEMENT_DYNAMIC_CLASS(MyFrame, wxFrame) - BEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU(SDRThreadTask::SDR_THREAD_JOB, MyFrame::OnTask) - EVT_MENU(SDRThreadTask::SDR_THREAD_JOBERR, MyFrame::OnTask) - EVT_MENU(eSTART_THREAD, MyFrame::OnStart) - EVT_MENU(SDRThreadTask::SDR_THREAD_EXIT, MyFrame::OnStop) - EVT_COMMAND(wxID_ANY, wxEVT_THREAD, MyFrame::OnThread) - EVT_MENU(eQUIT, MyFrame::OnQuit) - EVT_CLOSE(MyFrame::OnClose) - END_EVENT_TABLE() - - // ---------------------------------------------------------------------------- - // the application - // ---------------------------------------------------------------------------- - class MyApp : public wxApp - { - public: - virtual bool OnInit() - { - if(!wxApp::OnInit()) return false; - MyFrame *frame=new MyFrame(_T("Minimal wxWidgets App")); - frame->Show(true); - return true; - } - }; // class MyApp : public wxApp - IMPLEMENT_APP(MyApp) \ No newline at end of file