From 2ef8010438528e78efc109fcb5ada79ea47189f1 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 28 Oct 2014 22:59:17 -0400 Subject: [PATCH] Rendering rtl-sdr I/Q data to the GL canvas --- src/AppFrame.cpp | 8 +++-- src/AppFrame.h | 2 ++ src/IQBufferThread.cpp | 7 ++--- src/IQBufferThread.h | 8 ++--- src/PrimaryGLContext.cpp | 68 +++++++++++++++++++++++++++++++++------- src/PrimaryGLContext.h | 11 ++++++- src/SDRThread.cpp | 9 ++++-- 7 files changed, 85 insertions(+), 28 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 28f0e7e..91d31d0 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -23,7 +23,7 @@ wxEND_EVENT_TABLE() AppFrame::AppFrame() : wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) { - new TestGLCanvas(this, NULL); + canvas = new TestGLCanvas(this, NULL); // SetIcon(wxICON(sample)); @@ -57,9 +57,11 @@ void AppFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event)) { } void AppFrame::OnEventInput(wxThreadEvent& event) { - std::vector *new_buffer = event.GetPayload *>(); + std::vector *new_buffer = event.GetPayload *>(); - std::cout << "Got IQ buffer, length: " << new_buffer->size() << std::endl; +// std::cout << "Got IQ buffer, length: " << new_buffer->size() << std::endl; + + canvas->setData(new_buffer); delete new_buffer; } diff --git a/src/AppFrame.h b/src/AppFrame.h index db1ca26..b960df0 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -14,5 +14,7 @@ private: void OnNewWindow(wxCommandEvent& event); void OnIdle(wxIdleEvent& event); + TestGLCanvas *canvas; + wxDECLARE_EVENT_TABLE(); }; diff --git a/src/IQBufferThread.cpp b/src/IQBufferThread.cpp index e97e04f..11304b4 100644 --- a/src/IQBufferThread.cpp +++ b/src/IQBufferThread.cpp @@ -1,7 +1,6 @@ #include "IQBufferThread.h" #include - #include "wx/wxprec.h" #ifndef WX_PRECOMP @@ -12,8 +11,6 @@ #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" #endif - - #define BUF_SIZE (16 * 32 * 512) IQBufferThread::IQBufferThread(wxApp *app) : @@ -24,7 +21,7 @@ IQBufferThread::~IQBufferThread() { } wxThread::ExitCode IQBufferThread::Entry() { - unsigned char *buf = (unsigned char*) malloc(BUF_SIZE); + signed char *buf = (signed char*) malloc(BUF_SIZE); int n_read; int i = 0; @@ -40,7 +37,7 @@ wxThread::ExitCode IQBufferThread::Entry() { // iq_buffer.pop(); // delete old_buffer; // } - std::cout << "#"; +// std::cout << "#"; // } this->Sleep(100); } diff --git a/src/IQBufferThread.h b/src/IQBufferThread.h index 01e7af6..432ef95 100644 --- a/src/IQBufferThread.h +++ b/src/IQBufferThread.h @@ -10,19 +10,17 @@ #include "SDRThread.h" #include - class IQBufferThread: public wxThread { public: IQBufferThread(wxApp *app); ~IQBufferThread(); - void OnEventInput(wxEvent& event) - { - std::cout << "event !" << std::endl; + void OnEventInput(wxEvent& event) { + std::cout << "event !" << std::endl; } protected: virtual ExitCode Entry(); wxApp *handler; - std::queue *> iq_buffer; + std::queue *> iq_buffer; }; diff --git a/src/PrimaryGLContext.cpp b/src/PrimaryGLContext.cpp index a99603b..3c8bb97 100644 --- a/src/PrimaryGLContext.cpp +++ b/src/PrimaryGLContext.cpp @@ -59,23 +59,45 @@ PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas) : CheckGLError(); } -void PrimaryGLContext::PlotIQ() { +void PrimaryGLContext::PlotIQ(std::vector &i_points, std::vector &q_points) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glBegin(GL_LINE_STRIP); - glColor3f(1.0f, 1.0f, 1.0f); - glVertex3f(-1.0f, -0.5f, 0.0f); - glVertex3f(1.0f, -0.5f, 0.0f); - glEnd(); + glPushMatrix(); + glTranslatef(0.0f, 0.5f, 0.0f); + if (q_points.size()) { + glScalef(10.0f, 1.0f, 1.0f); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, &q_points[0]); + glDrawArrays(GL_LINE_STRIP, 0, q_points.size() / 2); + glDisableClientState(GL_VERTEX_ARRAY); + } else { + glBegin(GL_LINE_STRIP); + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(-1.0f, 0.0f, 0.0f); + glVertex3f(1.0f, 0.0f, 0.0f); + glEnd(); + } + glPopMatrix(); - glBegin(GL_LINE_STRIP); - glColor3f(1.0f, 1.0f, 1.0f); - glVertex3f(-1.0f, 0.5f, 0.0f); - glVertex3f(1.0f, 0.5f, 0.0f); - glEnd(); + glPushMatrix(); + glTranslatef(0.0f, -0.5f, 0.0f); + if (i_points.size()) { + glScalef(10.0f, 1.0f, 1.0f); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, &i_points[0]); + glDrawArrays(GL_LINE_STRIP, 0, i_points.size() / 2); + glDisableClientState(GL_VERTEX_ARRAY); + } else { + glBegin(GL_LINE_STRIP); + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(-1.0f, 0.0f, 0.0f); + glVertex3f(1.0f, 0.0f, 0.0f); + glEnd(); + } + glPopMatrix(); glFlush(); @@ -84,6 +106,7 @@ void PrimaryGLContext::PlotIQ() { wxBEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) EVT_PAINT(TestGLCanvas::OnPaint) EVT_KEY_DOWN(TestGLCanvas::OnKeyDown) +EVT_IDLE(TestGLCanvas::OnIdle) wxEND_EVENT_TABLE() TestGLCanvas::TestGLCanvas(wxWindow *parent, int *attribList) : @@ -99,7 +122,7 @@ void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { PrimaryGLContext& canvas = wxGetApp().GetContext(this); glViewport(0, 0, ClientSize.x, ClientSize.y); - canvas.PlotIQ(); + canvas.PlotIQ(i_points, q_points); SwapBuffers(); } @@ -124,3 +147,24 @@ void TestGLCanvas::OnKeyDown(wxKeyEvent& event) { } } +void TestGLCanvas::setData(std::vector *data) { + if (data && data->size()) { + if (i_points.size() < data->size()) { + i_points.resize(data->size()); + } + if (q_points.size() < data->size()) { + q_points.resize(data->size()); + } + + for (int i = 0, iMax = data->size() / 2; i < iMax; i++) { + i_points[i * 2 + 1] = (float) (*data)[i * 2] / 127.0f; + q_points[i * 2 + 1] = (float) (*data)[i * 2 + 1] / 127.0f; + i_points[i * 2] = q_points[i * 2] = 2.0f * ((float) i / (float) iMax) - 1.0f; + } + } +} + +void TestGLCanvas::OnIdle(wxIdleEvent &event) { + Refresh(false); +} +; diff --git a/src/PrimaryGLContext.h b/src/PrimaryGLContext.h index 0a5d49c..fc5be10 100644 --- a/src/PrimaryGLContext.h +++ b/src/PrimaryGLContext.h @@ -3,12 +3,14 @@ #include "wx/glcanvas.h" #include "wx/timer.h" +#include + class PrimaryGLContext : public wxGLContext { public: PrimaryGLContext(wxGLCanvas *canvas); - void PlotIQ(); + void PlotIQ(std::vector &i_points, std::vector &q_points); private: // textures for the cube faces @@ -20,9 +22,16 @@ class TestGLCanvas : public wxGLCanvas public: TestGLCanvas(wxWindow *parent, int *attribList = NULL); + void setData(std::vector *data); + + std::vector i_points; + std::vector q_points; + private: void OnPaint(wxPaintEvent& event); void OnKeyDown(wxKeyEvent& event); + void OnIdle(wxIdleEvent &event); + wxDECLARE_EVENT_TABLE(); }; diff --git a/src/SDRThread.cpp b/src/SDRThread.cpp index 43c5eec..145103f 100644 --- a/src/SDRThread.cpp +++ b/src/SDRThread.cpp @@ -3,7 +3,6 @@ #define BUF_SIZE (16 * 32 * 512) - //wxDEFINE_EVENT(wxEVT_COMMAND_SDRThread_INPUT, wxThreadEvent); SDRThread::SDRThread(AppFrame *frame) : @@ -91,6 +90,8 @@ wxThread::ExitCode SDRThread::Entry() { rtlsdr_open(&dev, 0); rtlsdr_set_sample_rate(dev, 2500000); rtlsdr_set_center_freq(dev, 105700000); + rtlsdr_set_agc_mode(dev, 1); + rtlsdr_set_offset_tuning(dev, 1); rtlsdr_reset_buffer(dev); int n_read; @@ -100,7 +101,11 @@ wxThread::ExitCode SDRThread::Entry() { rtlsdr_read_sync(dev, buf, BUF_SIZE, &n_read); if (!TestDestroy()) { - std::vector *new_buffer = new std::vector(buf, buf + n_read); + std::vector *new_buffer = new std::vector(); + + for (int i = 0; i < n_read; i++) { + new_buffer->push_back(buf[i] - 127); + } wxThreadEvent event(wxEVT_THREAD, EVENT_SDR_INPUT); event.SetPayload(new_buffer);