1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 01:18:38 -05:00

Try Threading.

This commit is contained in:
John Greb 2014-11-12 17:37:46 +00:00
parent 1a46bf391e
commit f78b2eebaf
5 changed files with 82 additions and 281 deletions

View File

@ -26,15 +26,13 @@ MESSAGE_CLASS_DEFINITION(V4LInput::MsgConfigureV4L, Message)
MESSAGE_CLASS_DEFINITION(V4LInput::MsgReportV4L, Message)
V4LInput::Settings::Settings() :
m_gain(0),
m_samplerate(2500000)
m_gain(0)
{
}
void V4LInput::Settings::resetToDefaults()
{
m_gain = 0;
m_samplerate = 2500000;
}
QByteArray V4LInput::Settings::serialize() const
@ -73,6 +71,16 @@ V4LInput::V4LInput(MessageQueue* msgQueueToGUI) :
{
}
bool V4LThread::Init()
{
OpenSource("/dev/swradio0");
if (fd < 0) {
qCritical("could not open SDR");
return false;
}
return true;
}
V4LInput::~V4LInput()
{
stopInput();
@ -96,62 +104,18 @@ bool V4LInput::startInput(int device)
serial[0] = '\0';
if(!m_sampleFifo.setSize(524288)) { // fraction of samplerate
if(!m_sampleFifo.setSize(4096*16)) {
qCritical("Could not allocate SampleFifo");
return false;
}
OpenSource("/dev/swradio0");
if (fd < 0) {
qCritical("could not open SDR");
return false;
}
m_dev = device;
/*
if((res = rtlsdr_get_usb_strings(m_dev, vendor, product, serial)) < 0) {
qCritical("error accessing USB device");
goto failed;
}
qWarning("RTLSDRInput open: %s %s, SN: %s", vendor, product, serial);
m_deviceDescription = QString("%1 (SN %2)").arg(product).arg(serial);
if((res = rtlsdr_set_sample_rate(m_dev, 1536000)) < 0) {
qCritical("could not set sample rate: %s", strerror(errno));
goto failed;
}
if((res = rtlsdr_set_tuner_gain_mode(m_dev, 1)) < 0) {
qCritical("error setting tuner gain mode");
goto failed;
}
if((res = rtlsdr_set_agc_mode(m_dev, 0)) < 0) {
qCritical("error setting agc mode");
goto failed;
}
numberOfGains = rtlsdr_get_tuner_gains(m_dev, NULL);
if(numberOfGains < 0) {
qCritical("error getting number of gain values supported");
goto failed;
}
m_gains.resize(numberOfGains);
if(rtlsdr_get_tuner_gains(m_dev, &m_gains[0]) < 0) {
qCritical("error getting gain values");
goto failed;
}
if((res = rtlsdr_reset_buffer(m_dev)) < 0) {
qCritical("could not reset USB EP buffers: %s", strerror(errno));
goto failed;
}
*/
if((m_V4LThread = new V4LThread(&m_sampleFifo)) == NULL) {
qFatal("out of memory");
goto failed;
}
m_V4LThread->startWork();
mutexLocker.unlock();
applySettings(m_generalSettings, m_settings, true);
//applySettings(m_generalSettings, m_settings, true);
qDebug("V4LInput: start");
MsgReportV4L::create(m_gains)->submit(m_guiMessageQueue);
@ -159,7 +123,6 @@ bool V4LInput::startInput(int device)
return true;
failed:
stopInput();
return false;
}
@ -172,10 +135,6 @@ void V4LInput::stopInput()
delete m_V4LThread;
m_V4LThread = NULL;
}
if(m_dev > 0) {
CloseSource();
m_dev = 0;
}
m_deviceDescription.clear();
}
@ -187,7 +146,6 @@ const QString& V4LInput::getDeviceDescription() const
int V4LInput::getSampleRate() const
{
int result = m_settings.m_samplerate / 4;
if (result > 200000) result /= 4;
return result;
}
@ -216,18 +174,13 @@ bool V4LInput::applySettings(const GeneralSettings& generalSettings, const Setti
if((m_generalSettings.m_centerFrequency != generalSettings.m_centerFrequency) || force) {
m_generalSettings.m_centerFrequency = generalSettings.m_centerFrequency;
if(m_dev > 0)
V4LInput::set_center_freq( (double)(generalSettings.m_centerFrequency
m_V4LThread->set_center_freq( (double)(generalSettings.m_centerFrequency
+ (settings.m_samplerate / 4) ));
}
if((m_settings.m_gain != settings.m_gain) || force) {
m_settings.m_gain = settings.m_gain;
if(m_dev > 0)
V4LInput::set_tuner_gain((double)m_settings.m_gain);
}
if((m_settings.m_samplerate != settings.m_samplerate) || force) {
m_settings.m_samplerate = settings.m_samplerate;
if(m_dev > 0)
m_V4LThread->setSamplerate((double)settings.m_samplerate);
m_V4LThread->set_tuner_gain((double)m_settings.m_gain);
}
return true;
}

View File

@ -94,22 +94,7 @@ public:
quint64 getCenterFrequency() const;
bool handleMessage(Message* message);
void OpenSource(const char *filename);
void CloseSource();
void set_sample_rate(double samp_rate);
void set_center_freq(double freq);
void set_bandwidth(double bandwidth);
void set_tuner_gain(double gain);
int work(int noutput_items, qint16* output_items);
private:
int fd;
quint32 pixelformat;
struct v4l_buffer *buffers;
unsigned int n_buffers;
void *recebuf_ptr;
unsigned int recebuf_len;
unsigned int recebuf_mmap_index;
QMutex m_mutex;
Settings m_settings;
int m_dev;

View File

@ -18,6 +18,7 @@
*/
#include "v4linput.h"
#include "v4lthread.h"
#include <string.h>
#include <errno.h>
#include <stdint.h>
@ -60,7 +61,7 @@ static void xioctl(int fh, unsigned long int request, void *arg)
}
void
V4LInput::OpenSource(const char *filename)
V4LThread::OpenSource(const char *filename)
{
struct v4l2_format fmt;
struct v4l2_buffer buf;
@ -124,7 +125,7 @@ V4LInput::OpenSource(const char *filename)
}
void
V4LInput::CloseSource()
V4LThread::CloseSource()
{
unsigned int i;
enum v4l2_buf_type type;
@ -140,7 +141,7 @@ V4LInput::CloseSource()
}
void
V4LInput::set_sample_rate(double samp_rate)
V4LThread::set_sample_rate(double samp_rate)
{
struct v4l2_frequency frequency;
@ -156,7 +157,7 @@ V4LInput::set_sample_rate(double samp_rate)
}
void
V4LInput::set_center_freq(double freq)
V4LThread::set_center_freq(double freq)
{
struct v4l2_frequency frequency;
@ -172,7 +173,7 @@ V4LInput::set_center_freq(double freq)
}
void
V4LInput::set_bandwidth(double bandwidth)
V4LThread::set_bandwidth(double bandwidth)
{
struct v4l2_ext_controls ext_ctrls;
struct v4l2_ext_control ext_ctrl;
@ -193,7 +194,7 @@ V4LInput::set_bandwidth(double bandwidth)
}
void
V4LInput::set_tuner_gain(double gain)
V4LThread::set_tuner_gain(double gain)
{
struct v4l2_ext_controls ext_ctrls;
struct v4l2_ext_control ext_ctrl;
@ -214,44 +215,41 @@ V4LInput::set_tuner_gain(double gain)
}
int
V4LInput::work(int noutput_items, int16_t* output_items)
{
//complex *out = (complex *) output_items;
int ret;
struct timeval tv;
struct v4l2_buffer buf;
fd_set fds;
unsigned int i, items = 0;
float *fptr = (float *) output_items;
V4LThread::work(int noutput_items)
{
int ret;
struct timeval tv;
struct v4l2_buffer buf;
fd_set fds;
unsigned int i, items = 0;
qint16 xreal, yimag;
uint8_t* b;
SampleVector::iterator it;
process_buf:
/* process received mmap buffer */
uint8_t *u8src = (uint8_t *) recebuf_ptr;
uint16_t *u16src = (uint16_t *) recebuf_ptr;
while (recebuf_len) {
if (pixelformat == V4L2_PIX_FMT_SDR_U8) {
*fptr++ = (*u8src++ - 127.5f) / 127.5f;
*fptr++ = (*u8src++ - 127.5f) / 127.5f;
recebuf_len -= 2;
items++;
recebuf_ptr = u8src;
} else if (pixelformat == V4L2_PIX_FMT_SDR_U16LE) {
*fptr++ = (*u16src++ - 32767.5f) / 32767.5f;
*fptr++ = (*u16src++ - 32767.5f) / 32767.5f;
recebuf_len -= 4;
items++;
recebuf_ptr = u16src;
} else {
recebuf_len = 0;
}
if (items == noutput_items)
break;
int pos = 0;
// in is 4*8bit*2(IQ), 8 bytes; out is 1*16bit*2(IQ) , 4bytes
it = m_convertBuffer.begin();
if (recebuf_len > 0) {
b = (uint8_t *) recebuf_ptr;
int len = noutput_items * 8;
if (len > recebuf_len)
len = recebuf_len;
for (pos = 0; pos < len - 7; pos += 8) {
xreal = b[pos+0] - b[pos+3] + b[pos+7] - b[pos+4];
yimag = b[pos+1] - b[pos+5] + b[pos+2] - b[pos+6];
Sample s( xreal << 3, yimag << 3 );
*it = s;
it++;
}
/* enqueue mmap buf after it is processed */
if (recebuf_len == 0 && items != 0) {
m_sampleFifo->write(m_convertBuffer.begin(), it);
recebuf_len -= pos;
recebuf_ptr = (void*)(b + pos);
}
// return now if there is still data in buffer, else free buffer and get another.
if (recebuf_len >= 8)
return pos / 8;
{ // frre buffer, if there was one.
if (pos > 0) {
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_SDR_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
@ -259,10 +257,6 @@ process_buf:
xioctl(fd, VIDIOC_QBUF, &buf);
}
/* signal DSP we have some samples to offer */
if (items)
return items;
/* Read data from device */
do {
FD_ZERO(&fds);
@ -289,10 +283,6 @@ process_buf:
recebuf_ptr = buffers[buf.index].start;
recebuf_len = buf.bytesused;
recebuf_mmap_index = buf.index;
/* FIXME: */
goto process_buf;
// Tell runtime system how many output items we produced.
return 0;
}
return pos / 8;
}

View File

@ -20,8 +20,6 @@
#include "v4lthread.h"
#include "dsp/samplefifo.h"
#define BLOCKSIZE 16384
V4LThread::V4LThread(SampleFifo* sampleFifo, QObject* parent) :
QThread(parent),
m_running(false),
@ -29,158 +27,25 @@ V4LThread::V4LThread(SampleFifo* sampleFifo, QObject* parent) :
m_convertBuffer(BLOCKSIZE),
m_sampleFifo(sampleFifo)
{
m_samplerate = 2500000;
}
V4LThread::~V4LThread()
{
stopWork();
}
void V4LThread::startWork()
{
m_startWaitMutex.lock();
start();
while(!m_running)
m_startWaiter.wait(&m_startWaitMutex, 100);
m_startWaitMutex.unlock();
}
void V4LThread::stopWork()
{
m_running = false;
wait();
}
void V4LThread::setSamplerate(int samplerate)
{
m_samplerate = samplerate;
}
void V4LThread::run()
{
int res;
if (! Init() )
return;
m_running = true;
m_startWaiter.wakeAll();
/*
while(m_running) {
if((res = rtlsdr_read_async(m_dev, &V4LThread::callbackHelper, this, 32, BLOCKSIZE)) < 0) {
qCritical("V4LThread: async error: %s", strerror(errno));
break;
}
work(BLOCKSIZE);
}
*/
m_running = false;
CloseSource();
}
void V4LThread::decimate2(SampleVector::iterator* it, const quint8* buf, qint32 len)
{
qint16 xreal, yimag;
for (int pos = 0; pos < len + 7; pos += 8) {
xreal = buf[pos+0] - buf[pos+3];
yimag = buf[pos+1] + buf[pos+2] - 255;
Sample s( xreal << 3, yimag << 3 );
**it = s;
(*it)++;
xreal = buf[pos+7] - buf[pos+4];
yimag = 255 - buf[pos+5] - buf[pos+6];
Sample t( xreal << 3, yimag << 3 );
**it = t;
(*it)++;
}
}
void V4LThread::decimate4(SampleVector::iterator* it, const quint8* buf, qint32 len)
{
qint16 xreal, yimag;
for (int pos = 0; pos < len + 7; pos += 8) {
xreal = buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4];
yimag = buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6];
Sample s( xreal << 3, yimag << 3 );
**it = s;
(*it)++;
}
}
void V4LThread::decimate8(SampleVector::iterator* it, const quint8* buf, qint32 len)
{
qint16 xreal, yimag;
for (int pos = 0; pos < len + 15; pos += 8) {
xreal = buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4];
yimag = buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6];
pos += 8;
xreal += buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4];
yimag += buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6];
Sample s( xreal << 3, yimag << 3 );
**it = s;
(*it)++;
}
}
void V4LThread::decimate16(SampleVector::iterator* it, const quint8* buf, qint32 len)
{
// Offset tuning: 4x downsample and rotate, then
// downsample 4x more. [ rotate: 0, 1, -3, 2, -4, -5, 7, -6]
qint16 xreal, yimag;
for (int step = 0; step < len - 31; step +=32) {
xreal = yimag = 0;
for (int pos = step; pos < step + 32; pos += 8) {
xreal += buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4];
yimag += buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6];
}
Sample s( xreal << 3, yimag << 3 );
**it = s;
(*it)++;
}
}
void V4LThread::callback(const quint8* buf, qint32 len)
{
qint16 xreal, yimag, phase;
SampleVector::iterator it = m_convertBuffer.begin();
switch(4) {
case 0: // 1:1 = no decimation
// just rotation
phase = -(1<<2);
for (int pos = 0; pos < len + 3; pos += 4) {
phase *= -1;
xreal = phase * (2 * buf[pos+0] - 255);
yimag = phase * (2 * buf[pos+1] - 255);
*it++ = Sample(xreal, yimag);
xreal = phase * (255 - 2 * buf[pos+3]);
yimag = phase * (2 * buf[pos+2] - 255);
*it++ = Sample(xreal, yimag);
}
break;
case 1: // 1:2
decimate2(&it, buf, len);
break;
case 2: // 1:4
decimate4(&it, buf, len);
break;
case 3: // 1:8
decimate8(&it, buf, len);
break;
default:
case 4: // 1:16
decimate16(&it, buf, len);
break;
}
m_sampleFifo->write(m_convertBuffer.begin(), it);
/*
if(!m_running)
rtlsdr_cancel_async(m_dev);
*/
}
void V4LThread::callbackHelper(unsigned char* buf, quint32 len, void* ctx)
{
V4LThread* thread = (V4LThread*)ctx;
thread->callback(buf, len);
}

View File

@ -24,6 +24,9 @@
#include "dsp/samplefifo.h"
#include "dsp/inthalfbandfilter.h"
#define SAMPLERATE 1024000
#define BLOCKSIZE 4096
class V4LThread : public QThread {
Q_OBJECT
@ -31,12 +34,25 @@ public:
V4LThread(SampleFifo* sampleFifo, QObject* parent = NULL);
~V4LThread();
void startWork();
bool Init();
void stopWork();
void setSamplerate(int samplerate);
void OpenSource(const char *filename);
void CloseSource();
void set_sample_rate(double samp_rate);
void set_center_freq(double freq);
void set_bandwidth(double bandwidth);
void set_tuner_gain(double gain);
int work(int n_items);
private:
int fd;
quint32 pixelformat;
struct v4l_buffer *buffers;
unsigned int n_buffers;
void *recebuf_ptr;
unsigned int recebuf_len;
unsigned int recebuf_mmap_index;
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
@ -48,13 +64,5 @@ private:
void run();
void decimate2(SampleVector::iterator* it, const quint8* buf, qint32 len);
void decimate4(SampleVector::iterator* it, const quint8* buf, qint32 len);
void decimate8(SampleVector::iterator* it, const quint8* buf, qint32 len);
void decimate16(SampleVector::iterator* it, const quint8* buf, qint32 len);
void callback(const quint8* buf, qint32 len);
static void callbackHelper(unsigned char* buf, quint32 len, void* ctx);
};
#endif // INCLUDE_V4LTHREAD_H