2014-11-29 13:58:20 -05:00
|
|
|
#include "SDRPostThread.h"
|
|
|
|
#include "CubicSDRDefs.h"
|
|
|
|
#include "CubicSDR.h"
|
|
|
|
|
2014-12-23 23:37:18 -05:00
|
|
|
#include <vector>
|
|
|
|
#include <deque>
|
|
|
|
|
2014-11-29 13:58:20 -05:00
|
|
|
SDRPostThread::SDRPostThread() :
|
2015-02-21 23:25:40 -05:00
|
|
|
iqDataOutQueue(NULL), iqDataInQueue(NULL), iqVisualQueue(NULL), terminated(false), dcFilter(NULL), num_vis_samples(16384*2) {
|
2015-02-03 12:42:44 -05:00
|
|
|
|
|
|
|
// create a lookup table
|
|
|
|
for (unsigned int i = 0; i <= 0xffff; i++) {
|
|
|
|
liquid_float_complex tmp;
|
|
|
|
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
|
|
|
tmp.real = (float(i & 0xff) - 127.4f) * (1.0f/128.0f);
|
|
|
|
tmp.imag = (float(i >> 8) - 127.4f) * (1.0f/128.0f);
|
|
|
|
_lut.push_back(tmp);
|
|
|
|
#else // BIG_ENDIAN
|
|
|
|
tmp.real = (float(i >> 8) - 127.4f) * (1.0f/128.0f);
|
|
|
|
tmp.imag = (float(i & 0xff) - 127.4f) * (1.0f/128.0f);
|
|
|
|
_lut.push_back(tmp);
|
|
|
|
#endif
|
|
|
|
}
|
2014-11-29 13:58:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
SDRPostThread::~SDRPostThread() {
|
2014-12-11 19:07:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void SDRPostThread::bindDemodulator(DemodulatorInstance *demod) {
|
2014-12-22 21:12:13 -05:00
|
|
|
demodulators_add.push_back(demod);
|
2014-12-11 19:07:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void SDRPostThread::removeDemodulator(DemodulatorInstance *demod) {
|
|
|
|
if (!demod) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-22 21:12:13 -05:00
|
|
|
demodulators_remove.push_back(demod);
|
2014-12-11 19:07:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void SDRPostThread::setIQDataInQueue(SDRThreadIQDataQueue* iqDataQueue) {
|
|
|
|
iqDataInQueue = iqDataQueue;
|
|
|
|
}
|
2014-12-26 16:15:35 -05:00
|
|
|
void SDRPostThread::setIQDataOutQueue(DemodulatorThreadInputQueue* iqDataQueue) {
|
2014-12-11 19:07:21 -05:00
|
|
|
iqDataOutQueue = iqDataQueue;
|
|
|
|
}
|
2014-12-26 16:15:35 -05:00
|
|
|
void SDRPostThread::setIQVisualQueue(DemodulatorThreadInputQueue *iqVisQueue) {
|
2014-12-11 19:07:21 -05:00
|
|
|
iqVisualQueue = iqVisQueue;
|
2014-11-29 13:58:20 -05:00
|
|
|
}
|
|
|
|
|
2014-12-28 05:13:46 -05:00
|
|
|
void SDRPostThread::setNumVisSamples(int num_vis_samples_in) {
|
|
|
|
num_vis_samples = num_vis_samples_in;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SDRPostThread::getNumVisSamples() {
|
|
|
|
return num_vis_samples;
|
|
|
|
}
|
|
|
|
|
2014-11-29 13:58:20 -05:00
|
|
|
void SDRPostThread::threadMain() {
|
|
|
|
int n_read;
|
|
|
|
double seconds = 0.0;
|
|
|
|
|
2014-12-18 20:11:25 -05:00
|
|
|
#ifdef __APPLE__
|
|
|
|
pthread_t tID = pthread_self(); // ID of this thread
|
|
|
|
int priority = sched_get_priority_max( SCHED_FIFO) - 1;
|
2014-12-24 01:28:33 -05:00
|
|
|
sched_param prio = {priority}; // scheduling priority of thread
|
2014-12-18 20:11:25 -05:00
|
|
|
pthread_setschedparam(tID, SCHED_FIFO, &prio);
|
|
|
|
#endif
|
2014-12-16 20:33:44 -05:00
|
|
|
|
2014-11-29 13:58:20 -05:00
|
|
|
dcFilter = iirfilt_crcf_create_dc_blocker(0.0005);
|
|
|
|
|
2015-01-22 21:32:32 -05:00
|
|
|
DemodulatorThreadIQData *visualDataOut = new DemodulatorThreadIQData;
|
|
|
|
|
2014-11-30 17:11:29 -05:00
|
|
|
std::cout << "SDR post-processing thread started.." << std::endl;
|
|
|
|
|
2014-12-23 23:37:18 -05:00
|
|
|
std::deque<DemodulatorThreadIQData *> buffers;
|
|
|
|
std::deque<DemodulatorThreadIQData *>::iterator buffers_i;
|
2014-12-26 16:15:35 -05:00
|
|
|
std::vector<liquid_float_complex> fpData;
|
|
|
|
std::vector<liquid_float_complex> dataOut;
|
2014-12-23 23:37:18 -05:00
|
|
|
|
2014-11-29 13:58:20 -05:00
|
|
|
while (!terminated) {
|
2014-12-23 01:59:03 -05:00
|
|
|
SDRThreadIQData *data_in;
|
2014-11-29 13:58:20 -05:00
|
|
|
|
|
|
|
iqDataInQueue.load()->pop(data_in);
|
2014-12-24 00:11:41 -05:00
|
|
|
// std::lock_guard < std::mutex > lock(data_in->m_mutex);
|
2014-11-29 13:58:20 -05:00
|
|
|
|
2014-12-23 01:59:03 -05:00
|
|
|
if (data_in && data_in->data.size()) {
|
2014-12-26 16:15:35 -05:00
|
|
|
int dataSize = data_in->data.size()/2;
|
|
|
|
if (dataSize > fpData.capacity()) {
|
|
|
|
fpData.reserve(dataSize);
|
|
|
|
dataOut.reserve(dataSize);
|
|
|
|
}
|
|
|
|
if (dataSize != fpData.size()) {
|
|
|
|
fpData.resize(dataSize);
|
|
|
|
dataOut.resize(dataSize);
|
2014-12-24 03:03:34 -05:00
|
|
|
}
|
2014-11-29 13:58:20 -05:00
|
|
|
|
2014-12-26 16:15:35 -05:00
|
|
|
for (int i = 0, iMax = dataSize; i < iMax; i++) {
|
2015-02-03 12:42:44 -05:00
|
|
|
fpData[i] = _lut[*((uint16_t*)&data_in->data[2*i])];
|
2014-11-29 13:58:20 -05:00
|
|
|
}
|
|
|
|
|
2014-12-26 16:15:35 -05:00
|
|
|
iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]);
|
|
|
|
|
2015-01-24 22:01:47 -05:00
|
|
|
if (iqDataOutQueue.load() != NULL) {
|
2014-12-26 16:15:35 -05:00
|
|
|
DemodulatorThreadIQData *pipeDataOut = new DemodulatorThreadIQData;
|
2014-12-24 03:03:34 -05:00
|
|
|
|
2014-12-26 16:15:35 -05:00
|
|
|
pipeDataOut->frequency = data_in->frequency;
|
2015-01-11 17:08:16 -05:00
|
|
|
pipeDataOut->sampleRate = data_in->sampleRate;
|
2014-12-26 16:15:35 -05:00
|
|
|
pipeDataOut->data.assign(dataOut.begin(), dataOut.end());
|
|
|
|
iqDataOutQueue.load()->push(pipeDataOut);
|
2014-11-29 13:58:20 -05:00
|
|
|
}
|
|
|
|
|
2015-01-24 22:01:47 -05:00
|
|
|
if (iqVisualQueue.load() != NULL && iqVisualQueue.load()->empty()) {
|
2015-05-27 23:22:19 -04:00
|
|
|
|
|
|
|
visualDataOut->busy_rw.lock();
|
|
|
|
|
2015-01-22 21:32:32 -05:00
|
|
|
if (visualDataOut->data.size() < num_vis_samples) {
|
|
|
|
if (visualDataOut->data.capacity() < num_vis_samples) {
|
|
|
|
visualDataOut->data.reserve(num_vis_samples);
|
|
|
|
}
|
|
|
|
visualDataOut->data.resize(num_vis_samples);
|
|
|
|
}
|
|
|
|
|
2014-12-28 05:13:46 -05:00
|
|
|
visualDataOut->frequency = data_in->frequency;
|
2015-01-11 17:08:16 -05:00
|
|
|
visualDataOut->sampleRate = data_in->sampleRate;
|
2014-12-28 05:13:46 -05:00
|
|
|
visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples);
|
2015-05-27 23:22:19 -04:00
|
|
|
|
|
|
|
visualDataOut->busy_rw.unlock();
|
|
|
|
|
2014-12-22 19:43:56 -05:00
|
|
|
iqVisualQueue.load()->push(visualDataOut);
|
2014-11-29 13:58:20 -05:00
|
|
|
}
|
|
|
|
|
2014-12-22 21:12:13 -05:00
|
|
|
if (demodulators_add.size()) {
|
|
|
|
while (!demodulators_add.empty()) {
|
|
|
|
demodulators.push_back(demodulators_add.back());
|
|
|
|
demodulators_add.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (demodulators_remove.size()) {
|
|
|
|
while (!demodulators_remove.empty()) {
|
|
|
|
DemodulatorInstance *demod = demodulators_remove.back();
|
|
|
|
demodulators_remove.pop_back();
|
|
|
|
|
|
|
|
std::vector<DemodulatorInstance *>::iterator i = std::find(demodulators.begin(), demodulators.end(), demod);
|
|
|
|
|
|
|
|
if (i != demodulators.end()) {
|
|
|
|
demodulators.erase(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int activeDemods = 0;
|
|
|
|
bool pushedData = false;
|
2014-12-22 19:43:56 -05:00
|
|
|
|
2014-11-29 13:58:20 -05:00
|
|
|
if (demodulators.size()) {
|
|
|
|
|
2014-12-18 20:11:25 -05:00
|
|
|
std::vector<DemodulatorInstance *>::iterator i;
|
|
|
|
for (i = demodulators.begin(); i != demodulators.end(); i++) {
|
|
|
|
DemodulatorInstance *demod = *i;
|
2015-01-10 12:27:03 -05:00
|
|
|
if (demod->getFrequency() != data_in->frequency
|
2015-01-11 17:08:16 -05:00
|
|
|
&& abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
|
2014-12-22 21:12:13 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
activeDemods++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (demodulators.size()) {
|
2014-12-24 01:28:33 -05:00
|
|
|
|
2014-12-23 23:37:18 -05:00
|
|
|
DemodulatorThreadIQData *demodDataOut = NULL;
|
2014-12-24 01:28:33 -05:00
|
|
|
|
2014-12-23 23:37:18 -05:00
|
|
|
for (buffers_i = buffers.begin(); buffers_i != buffers.end(); buffers_i++) {
|
|
|
|
if ((*buffers_i)->getRefCount() <= 0) {
|
|
|
|
demodDataOut = (*buffers_i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-12-24 01:28:33 -05:00
|
|
|
|
2014-12-23 23:37:18 -05:00
|
|
|
if (demodDataOut == NULL) {
|
|
|
|
demodDataOut = new DemodulatorThreadIQData;
|
|
|
|
buffers.push_back(demodDataOut);
|
|
|
|
}
|
2014-12-24 01:28:33 -05:00
|
|
|
|
|
|
|
// std::lock_guard < std::mutex > lock(demodDataOut->m_mutex);
|
2014-12-23 01:59:03 -05:00
|
|
|
demodDataOut->frequency = data_in->frequency;
|
2015-01-11 17:08:16 -05:00
|
|
|
demodDataOut->sampleRate = data_in->sampleRate;
|
2014-12-22 23:27:52 -05:00
|
|
|
demodDataOut->setRefCount(activeDemods);
|
2014-12-26 16:15:35 -05:00
|
|
|
demodDataOut->data.assign(dataOut.begin(), dataOut.end());
|
2014-12-22 21:12:13 -05:00
|
|
|
|
|
|
|
std::vector<DemodulatorInstance *>::iterator i;
|
|
|
|
for (i = demodulators.begin(); i != demodulators.end(); i++) {
|
|
|
|
DemodulatorInstance *demod = *i;
|
|
|
|
DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod;
|
|
|
|
|
2015-03-26 22:45:52 -04:00
|
|
|
if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
|
2015-04-23 19:38:44 -04:00
|
|
|
if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
|
2014-12-22 21:12:13 -05:00
|
|
|
demod->setActive(false);
|
2014-12-22 23:27:52 -05:00
|
|
|
DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;
|
2014-12-23 01:59:03 -05:00
|
|
|
dummyDataOut->frequency = data_in->frequency;
|
2015-01-11 17:08:16 -05:00
|
|
|
dummyDataOut->sampleRate = data_in->sampleRate;
|
2014-12-22 21:12:13 -05:00
|
|
|
demodQueue->push(dummyDataOut);
|
|
|
|
}
|
2015-03-26 22:45:52 -04:00
|
|
|
|
|
|
|
if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) {
|
|
|
|
wxGetApp().setFrequency(demod->getFrequency());
|
|
|
|
}
|
2014-12-22 21:12:13 -05:00
|
|
|
} else if (!demod->isActive()) {
|
|
|
|
demod->setActive(true);
|
2015-02-05 20:54:04 -05:00
|
|
|
if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) {
|
|
|
|
wxGetApp().getDemodMgr().setActiveDemodulator(demod);
|
|
|
|
}
|
2014-12-22 21:12:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!demod->isActive()) {
|
2014-12-11 20:50:58 -05:00
|
|
|
continue;
|
|
|
|
}
|
2015-03-26 22:45:52 -04:00
|
|
|
if (demod->isFollow()) {
|
|
|
|
demod->setFollow(false);
|
|
|
|
}
|
2014-12-11 20:50:58 -05:00
|
|
|
|
2014-12-22 21:12:13 -05:00
|
|
|
demodQueue->push(demodDataOut);
|
|
|
|
pushedData = true;
|
|
|
|
}
|
2014-12-22 19:43:56 -05:00
|
|
|
|
2014-12-22 23:27:52 -05:00
|
|
|
if (!pushedData) {
|
2014-12-23 23:37:18 -05:00
|
|
|
demodDataOut->setRefCount(0);
|
2014-12-22 23:27:52 -05:00
|
|
|
}
|
|
|
|
}
|
2014-12-22 19:43:56 -05:00
|
|
|
}
|
2014-12-23 01:59:03 -05:00
|
|
|
}
|
2014-12-24 00:11:41 -05:00
|
|
|
data_in->decRefCount();
|
2014-11-29 13:58:20 -05:00
|
|
|
}
|
2014-12-23 23:37:18 -05:00
|
|
|
|
|
|
|
while (!buffers.empty()) {
|
|
|
|
DemodulatorThreadIQData *demodDataDel = buffers.front();
|
|
|
|
buffers.pop_front();
|
2014-12-24 01:28:33 -05:00
|
|
|
// std::lock_guard < std::mutex > lock(demodDataDel->m_mutex);
|
|
|
|
// delete demodDataDel;
|
2014-12-23 23:37:18 -05:00
|
|
|
}
|
2015-01-22 23:41:33 -05:00
|
|
|
if (iqVisualQueue.load() && !iqVisualQueue.load()->empty()) {
|
|
|
|
DemodulatorThreadIQData *visualDataDummy;
|
|
|
|
iqVisualQueue.load()->pop(visualDataDummy);
|
|
|
|
}
|
2014-12-23 23:37:18 -05:00
|
|
|
|
2015-01-22 21:32:32 -05:00
|
|
|
delete visualDataOut;
|
|
|
|
|
2014-11-30 17:11:29 -05:00
|
|
|
std::cout << "SDR post-processing thread done." << std::endl;
|
2014-11-29 13:58:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void SDRPostThread::terminate() {
|
|
|
|
terminated = true;
|
2014-12-23 01:59:03 -05:00
|
|
|
SDRThreadIQData *dummy = new SDRThreadIQData;
|
2014-11-30 17:11:29 -05:00
|
|
|
iqDataInQueue.load()->push(dummy);
|
2014-11-29 13:58:20 -05:00
|
|
|
}
|