238 lines
7.3 KiB
C++
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();
|
|
}
|
|
*/
|