CubicSDR/src/SDRThread.cpp

238 lines
7.3 KiB
C++

#include "SDRThread.h"
static void rtl_callback(unsigned char *buf, uint32_t len, void *ctx) {
std::cout << "Got buffer! length: " << len << std::endl;
}
SDRThread::SDRThread(wxApp *app) :
wxThread(wxTHREAD_DETACHED) {
dev = NULL;
this->handler = handler;
}
SDRThread::~SDRThread() {
}
void SDRThread::enumerate_rtl() {
unsigned int rtl_count = rtlsdr_get_device_count();
std::cout << "RTL Devices: " << rtl_count << std::endl;
char manufact[256];
char product[256];
char serial[256];
for (int i = 0; i < rtl_count; i++) {
std::cout << "Device #" << i << ": " << rtlsdr_get_device_name(i) << std::endl;
if (rtlsdr_get_device_usb_strings(i, manufact, product, serial) == 0) {
std::cout << "\tManufacturer: " << manufact << ", Product Name: " << product << ", Serial: " << serial << std::endl;
rtlsdr_open(&dev, i);
std::cout << "\t Tuner type: ";
switch (rtlsdr_get_tuner_type(dev)) {
case RTLSDR_TUNER_UNKNOWN:
std::cout << "Unknown";
break;
case RTLSDR_TUNER_E4000:
std::cout << "Elonics E4000";
break;
case RTLSDR_TUNER_FC0012:
std::cout << "Fitipower FC0012";
break;
case RTLSDR_TUNER_FC0013:
std::cout << "Fitipower FC0013";
break;
case RTLSDR_TUNER_FC2580:
std::cout << "Fitipower FC2580";
break;
case RTLSDR_TUNER_R820T:
std::cout << "Rafael Micro R820T";
break;
case RTLSDR_TUNER_R828D:
break;
}
std::cout << std::endl;
/*
int num_gains = rtlsdr_get_tuner_gains(dev, NULL);
int *gains = (int *)malloc(sizeof(int) * num_gains);
rtlsdr_get_tuner_gains(dev, gains);
std::cout << "\t Valid gains: ";
for (int g = 0; g < num_gains; g++) {
if (g > 0) {
std::cout << ", ";
}
std::cout << ((float)gains[g]/10.0f);
}
std::cout << std::endl;
free(gains);
*/
rtlsdr_close(dev);
} else {
std::cout << "\tUnable to access device #" << i << " (in use?)" << std::endl;
}
}
}
#define BUF_SIZE 16 * 32 * 512
wxThread::ExitCode SDRThread::Entry() {
__int8 *buf = (__int8 *) malloc(BUF_SIZE);
enumerate_rtl();
rtlsdr_open(&dev, 4);
rtlsdr_set_sample_rate(dev, 2500000);
rtlsdr_set_center_freq(dev, 105700000);
rtlsdr_reset_buffer(dev);
int n_read;
int i = 0;
// rtlsdr_read_async(dev, rtl_callback, NULL, 0, 0);
std::cout << "Sampling..";
while (!TestDestroy()) {
rtlsdr_read_sync(dev, buf, BUF_SIZE, &n_read);
// std::cout << "Got buffer! length: " << n_read << std::endl;
std::cout << ".";
if (i%50==0) {
std::cout << std::endl;
}
i++;
//wxQueueEvent(app,new wxThreadEvent(wxEVT_COMMAND_SDRThread_UPDATE));
}
std::cout << std::endl << "Done." << std::endl << std::endl;
// wxQueueEvent(m_pHandler,new wxThreadEvent(wxEVT_COMMAND_SDRThread_COMPLETED));
free(buf);
rtlsdr_close(dev);
return (wxThread::ExitCode) 0; // success
}
/*
class MyFrame: public wxFrame {
public:
~MyFrame() {
// it's better to do any thread cleanup in the OnClose()
// event handler, rather than in the destructor.
// This is because the event loop for a top-level window is not
// active anymore when its destructor is called and if the thread
// sends events when ending, they won't be processed unless
// you ended the thread from OnClose.
// See @ref overview_windowdeletion for more info.
}
void DoStartThread();
void DoPauseThread();
// a resume routine would be nearly identic to DoPauseThread()
void DoResumeThread() {
}
void OnThreadUpdate(wxThreadEvent&);
void OnThreadCompletion(wxThreadEvent&);
void OnClose(wxCloseEvent&);
protected:
SDRThread *m_pThread;
wxCriticalSection m_pThreadCS; // protects the m_pThread pointer
wxDECLARE_EVENT_TABLE();
};
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_CLOSE(MyFrame::OnClose)
EVT_MENU(Minimal_Start, MyFrame::DoStartThread)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_SDRThread_UPDATE, MyFrame::OnThreadUpdate)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_SDRThread_COMPLETED, MyFrame::OnThreadCompletion)
wxEND_EVENT_TABLE()
wxDEFINE_EVENT(wxEVT_COMMAND_SDRThread_COMPLETED, wxThreadEvent)wxDEFINE_EVENT
(wxEVT_COMMAND_SDRThread_UPDATE, wxThreadEvent)void
MyFrame::DoStartThread() {
m_pThread = new SDRThread(this);
if (m_pThread->Run() != wxTHREAD_NO_ERROR) {
wxLogError
("Can't create the thread!");
delete m_pThread;
m_pThread = NULL;
}
// after the call to wxThread::Run(), the m_pThread pointer is "unsafe":
// at any moment the thread may cease to exist (because it completes its work).
// To avoid dangling pointers OnThreadExit() will set m_pThread
// to NULL when the thread dies.
}
wxThread::ExitCode SDRThread::Entry() {
while (!TestDestroy()) {
// ... do a bit of work...
wxQueueEvent(m_pHandler,
new wxThreadEvent(wxEVT_COMMAND_SDRThread_UPDATE));
}
// signal the event handler that this thread is going to be destroyed
// NOTE: here we assume that using the m_pHandler pointer is safe,
// (in this case this is assured by the MyFrame destructor)
wxQueueEvent(m_pHandler,
new wxThreadEvent(wxEVT_COMMAND_SDRThread_COMPLETED));
return (wxThread::ExitCode) 0; // success
}
SDRThread::~SDRThread() {
wxCriticalSectionLocker enter(m_pHandler->m_pThreadCS);
// the thread is being destroyed; make sure not to leave dangling pointers around
m_pHandler->m_pThread = NULL;
}
void MyFrame::OnThreadCompletion(wxThreadEvent&) {
wxMessageOutputDebug().Printf("MYFRAME: SDRThread exited!\n");
}
void MyFrame::OnThreadUpdate(wxThreadEvent&) {
wxMessageOutputDebug().Printf("MYFRAME: SDRThread update...\n");
}
void MyFrame::DoPauseThread() {
// anytime we access the m_pThread pointer we must ensure that it won't
// be modified in the meanwhile; since only a single thread may be
// inside a given critical section at a given time, the following code
// is safe:
wxCriticalSectionLocker enter(m_pThreadCS);
if (m_pThread) // does the thread still exist?
{
// without a critical section, once reached this point it may happen
// that the OS scheduler gives control to the SDRThread::Entry() function,
// which in turn may return (because it completes its work) making
// invalid the m_pThread pointer
if (m_pThread->Pause() != wxTHREAD_NO_ERROR)
wxLogError
("Can't pause the thread!");
}
}
void MyFrame::OnClose(wxCloseEvent&) {
{
wxCriticalSectionLocker enter(m_pThreadCS);
if (m_pThread) // does the thread still exist?
{
wxMessageOutputDebug().Printf("MYFRAME: deleting thread");
if (m_pThread->Delete() != wxTHREAD_NO_ERROR)
wxLogError
("Can't delete the thread!");
}
} // exit from the critical section to give the thread
// the possibility to enter its destructor
// (which is guarded with m_pThreadCS critical section!)
while (1) {
{ // was the ~SDRThread() function executed?
wxCriticalSectionLocker enter(m_pThreadCS);
if (!m_pThread)
break;
}
// wait for thread completion
wxThread::This()->Sleep(1);
}
Destroy();
}
*/