mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	APT demod: moved processPixels process to a separate thread
This commit is contained in:
		
							parent
							
								
									de23efe635
								
							
						
					
					
						commit
						aac8f6fe2c
					
				| @ -5,6 +5,7 @@ set(demodapt_SOURCES | ||||
|     aptdemodsettings.cpp | ||||
|     aptdemodbaseband.cpp | ||||
|     aptdemodsink.cpp | ||||
|     aptdemodimageworker.cpp | ||||
|     aptdemodplugin.cpp | ||||
|     aptdemodwebapiadapter.cpp | ||||
| ) | ||||
| @ -14,6 +15,7 @@ set(demodapt_HEADERS | ||||
|     aptdemodsettings.h | ||||
|     aptdemodbaseband.h | ||||
|     aptdemodsink.h | ||||
|     aptdemodimageworker.h | ||||
|     aptdemodplugin.h | ||||
|     aptdemodwebapiadapter.h | ||||
| ) | ||||
|  | ||||
| @ -58,9 +58,12 @@ APTDemod::APTDemod(DeviceAPI *deviceAPI) : | ||||
|     setObjectName(m_channelId); | ||||
| 
 | ||||
|     m_basebandSink = new APTDemodBaseband(this); | ||||
|     m_basebandSink->setMessageQueueToChannel(getInputMessageQueue()); | ||||
|     m_basebandSink->moveToThread(&m_thread); | ||||
| 
 | ||||
|     m_imageWorker = new APTDemodImageWorker(); | ||||
|     m_basebandSink->setImagWorkerMessageQueue(m_imageWorker->getInputMessageQueue()); | ||||
|     m_imageWorker->moveToThread(&m_imageThread); | ||||
| 
 | ||||
|     applySettings(m_settings, true); | ||||
| 
 | ||||
|     m_deviceAPI->addChannelSink(this); | ||||
| @ -74,7 +77,8 @@ APTDemod::APTDemod(DeviceAPI *deviceAPI) : | ||||
|         m_image.prow[y] = new float[APT_PROW_WIDTH]; | ||||
|         m_tempImage.prow[y] = new float[APT_PROW_WIDTH]; | ||||
|     } | ||||
|     resetDecoder(); | ||||
| 
 | ||||
|     resetDecoder(); // FIXME: to be removed
 | ||||
| } | ||||
| 
 | ||||
| APTDemod::~APTDemod() | ||||
| @ -85,16 +89,22 @@ APTDemod::~APTDemod() | ||||
|     m_deviceAPI->removeChannelSinkAPI(this); | ||||
|     m_deviceAPI->removeChannelSink(this); | ||||
| 
 | ||||
|     if (m_imageWorker->isRunning()) { | ||||
|         stopImageWorker(); | ||||
|     } | ||||
| 
 | ||||
|     delete m_imageWorker; | ||||
| 
 | ||||
|     if (m_basebandSink->isRunning()) { | ||||
|         stop(); | ||||
|         stopBasebandSink(); | ||||
|     } | ||||
| 
 | ||||
|     delete m_basebandSink; | ||||
| 
 | ||||
|     for (int y = 0; y < APT_MAX_HEIGHT; y++) | ||||
|     { | ||||
|         delete m_image.prow[y]; | ||||
|         delete m_tempImage.prow[y]; | ||||
|         delete[] m_image.prow[y]; | ||||
|         delete[] m_tempImage.prow[y]; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -110,6 +120,12 @@ void APTDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto | ||||
| } | ||||
| 
 | ||||
| void APTDemod::start() | ||||
| { | ||||
|     startBasebandSink(); | ||||
|     startImageWorker(); | ||||
| } | ||||
| 
 | ||||
| void APTDemod::startBasebandSink() | ||||
| { | ||||
|     qDebug("APTDemod::start"); | ||||
| 
 | ||||
| @ -124,7 +140,25 @@ void APTDemod::start() | ||||
|     m_basebandSink->getInputMessageQueue()->push(msg); | ||||
| } | ||||
| 
 | ||||
| void APTDemod::startImageWorker() | ||||
| { | ||||
|     qDebug("APTDemod::startImageWorker"); | ||||
| 
 | ||||
|     m_imageWorker->reset(); | ||||
|     m_imageWorker->startWork(); | ||||
|     m_imageThread.start(); | ||||
| 
 | ||||
|     APTDemodImageWorker::MsgConfigureAPTDemodImageWorker *msg = APTDemodImageWorker::MsgConfigureAPTDemodImageWorker::create(m_settings, true); | ||||
|     m_imageWorker->getInputMessageQueue()->push(msg); | ||||
| } | ||||
| 
 | ||||
| void APTDemod::stop() | ||||
| { | ||||
|     stopImageWorker(); | ||||
|     stopBasebandSink(); | ||||
| } | ||||
| 
 | ||||
| void APTDemod::stopBasebandSink() | ||||
| { | ||||
|     qDebug("APTDemod::stop"); | ||||
|     m_basebandSink->stopWork(); | ||||
| @ -132,6 +166,14 @@ void APTDemod::stop() | ||||
|     m_thread.wait(); | ||||
| } | ||||
| 
 | ||||
| void APTDemod::stopImageWorker() | ||||
| { | ||||
|     qDebug("APTDemod::stopImageWorker"); | ||||
|     m_imageWorker->stopWork(); | ||||
|     m_imageThread.quit(); | ||||
|     m_imageThread.wait(); | ||||
| } | ||||
| 
 | ||||
| bool APTDemod::matchSatellite(const QString satelliteName) | ||||
| { | ||||
|    return    m_settings.m_satelliteTrackerControl | ||||
| @ -176,7 +218,8 @@ bool APTDemod::handleMessage(const Message& cmd) | ||||
|     } | ||||
|     else if (APTDemod::MsgResetDecoder::match(cmd)) | ||||
|     { | ||||
|         resetDecoder(); | ||||
|         resetDecoder(); // FIXME: to be removed
 | ||||
|         m_imageWorker->getInputMessageQueue()->push(APTDemod::MsgResetDecoder::create()); | ||||
|         // Forward to sink
 | ||||
|         m_basebandSink->getInputMessageQueue()->push(APTDemod::MsgResetDecoder::create()); | ||||
|         return true; | ||||
| @ -579,7 +622,8 @@ int APTDemod::webapiActionsPost( | ||||
|                 if (matchSatellite(*satelliteName)) | ||||
|                 { | ||||
|                     // Reset for new pass
 | ||||
|                     resetDecoder(); | ||||
|                     resetDecoder(); // FIXME: to be removed
 | ||||
|                     m_imageWorker->getInputMessageQueue()->push(APTDemod::MsgResetDecoder::create()); | ||||
|                     m_basebandSink->getInputMessageQueue()->push(APTDemod::MsgResetDecoder::create()); | ||||
| 
 | ||||
|                     // Save satellite name
 | ||||
|  | ||||
| @ -32,12 +32,14 @@ | ||||
| #include "util/message.h" | ||||
| 
 | ||||
| #include "aptdemodbaseband.h" | ||||
| #include "aptdemodimageworker.h" | ||||
| #include "aptdemodsettings.h" | ||||
| 
 | ||||
| class QNetworkAccessManager; | ||||
| class QNetworkReply; | ||||
| class QThread; | ||||
| class DeviceAPI; | ||||
| class APTDemodImageWorker; | ||||
| 
 | ||||
| class APTDemod : public BasebandSampleSink, public ChannelAPI { | ||||
|     Q_OBJECT | ||||
| @ -144,8 +146,18 @@ public: | ||||
|     virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); | ||||
|     virtual void start(); | ||||
|     virtual void stop(); | ||||
|     virtual void startBasebandSink(); | ||||
|     virtual void stopBasebandSink(); | ||||
|     virtual void startImageWorker(); | ||||
|     virtual void stopImageWorker(); | ||||
|     virtual bool handleMessage(const Message& cmd); | ||||
| 
 | ||||
|     void setMessageQueueToGUI(MessageQueue* queue) override | ||||
|     { | ||||
|         ChannelAPI::setMessageQueueToGUI(queue); | ||||
|         m_imageWorker->setMessageQueueToGUI(queue); | ||||
|     } | ||||
| 
 | ||||
|     virtual void getIdentifier(QString& id) { id = objectName(); } | ||||
|     virtual const QString& getURI() const { return getName(); } | ||||
|     virtual void getTitle(QString& title) { title = m_settings.m_title; } | ||||
| @ -202,7 +214,9 @@ public: | ||||
| private: | ||||
|     DeviceAPI *m_deviceAPI; | ||||
|     QThread m_thread; | ||||
|     QThread m_imageThread; | ||||
|     APTDemodBaseband* m_basebandSink; | ||||
|     APTDemodImageWorker *m_imageWorker; | ||||
|     APTDemodSettings m_settings; | ||||
|     int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
 | ||||
|     qint64 m_centerFrequency; | ||||
|  | ||||
| @ -68,7 +68,7 @@ public: | ||||
|     void getMagSqLevels(double& avg, double& peak, int& nbSamples) { | ||||
|         m_sink.getMagSqLevels(avg, peak, nbSamples); | ||||
|     } | ||||
|     void setMessageQueueToChannel(MessageQueue *messageQueue) { m_sink.setMessageQueueToChannel(messageQueue); } | ||||
|     void setImagWorkerMessageQueue(MessageQueue *messageQueue) { m_sink.setImageWorkerMessageQueue(messageQueue); } | ||||
|     void setBasebandSampleRate(int sampleRate); | ||||
|     double getMagSq() const { return m_sink.getMagSq(); } | ||||
|     bool isRunning() const { return m_running; } | ||||
|  | ||||
							
								
								
									
										279
									
								
								plugins/channelrx/demodapt/aptdemodimageworker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								plugins/channelrx/demodapt/aptdemodimageworker.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,279 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Copyright (C) 2015-2018 Edouard Griffiths, F4EXB.                             //
 | ||||
| // Copyright (C) 2021 Jon Beniston, M7RCE                                        //
 | ||||
| //                                                                               //
 | ||||
| // This program is free software; you can redistribute it and/or modify          //
 | ||||
| // it under the terms of the GNU General Public License as published by          //
 | ||||
| // the Free Software Foundation as version 3 of the License, or                  //
 | ||||
| // (at your option) any later version.                                           //
 | ||||
| //                                                                               //
 | ||||
| // This program is distributed in the hope that it will be useful,               //
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||
| // GNU General Public License V3 for more details.                               //
 | ||||
| //                                                                               //
 | ||||
| // You should have received a copy of the GNU General Public License             //
 | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
| #include "aptdemod.h" | ||||
| #include "aptdemodimageworker.h" | ||||
| 
 | ||||
| MESSAGE_CLASS_DEFINITION(APTDemodImageWorker::MsgConfigureAPTDemodImageWorker, Message) | ||||
| 
 | ||||
| APTDemodImageWorker::APTDemodImageWorker() : | ||||
|     m_messageQueueToGUI(nullptr), | ||||
|     m_running(false), | ||||
|     m_mutex(QMutex::Recursive) | ||||
| { | ||||
|     for (int y = 0; y < APT_MAX_HEIGHT; y++) | ||||
|     { | ||||
|         m_image.prow[y] = new float[APT_PROW_WIDTH]; | ||||
|         m_tempImage.prow[y] = new float[APT_PROW_WIDTH]; | ||||
|     } | ||||
| 
 | ||||
|     resetDecoder(); | ||||
| } | ||||
| 
 | ||||
| APTDemodImageWorker::~APTDemodImageWorker() | ||||
| { | ||||
|     m_inputMessageQueue.clear(); | ||||
| 
 | ||||
|     for (int y = 0; y < APT_MAX_HEIGHT; y++) | ||||
|     { | ||||
|         delete[] m_image.prow[y]; | ||||
|         delete[] m_tempImage.prow[y]; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void APTDemodImageWorker::reset() | ||||
| { | ||||
|     QMutexLocker mutexLocker(&m_mutex); | ||||
|     m_inputMessageQueue.clear(); | ||||
| } | ||||
| 
 | ||||
| void APTDemodImageWorker::startWork() | ||||
| { | ||||
|     QMutexLocker mutexLocker(&m_mutex); | ||||
|     connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); | ||||
|     m_running = true; | ||||
| } | ||||
| 
 | ||||
| void APTDemodImageWorker::stopWork() | ||||
| { | ||||
|     QMutexLocker mutexLocker(&m_mutex); | ||||
|     disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); | ||||
|     m_running = false; | ||||
| } | ||||
| 
 | ||||
| void APTDemodImageWorker::handleInputMessages() | ||||
| { | ||||
|     Message* message; | ||||
| 
 | ||||
|     while ((message = m_inputMessageQueue.pop()) != nullptr) | ||||
|     { | ||||
|         if (handleMessage(*message)) { | ||||
|             delete message; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool APTDemodImageWorker::handleMessage(const Message& cmd) | ||||
| { | ||||
|     if (MsgConfigureAPTDemodImageWorker::match(cmd)) | ||||
|     { | ||||
|         QMutexLocker mutexLocker(&m_mutex); | ||||
|         MsgConfigureAPTDemodImageWorker& cfg = (MsgConfigureAPTDemodImageWorker&) cmd; | ||||
|         qDebug("APTDemodImageWorker::handleMessage: MsgConfigureAPTDemodImageWorker"); | ||||
|         applySettings(cfg.getSettings(), cfg.getForce()); | ||||
|         return true; | ||||
|     } | ||||
|     else if (APTDemod::MsgPixels::match(cmd)) | ||||
|     { | ||||
|         QMutexLocker mutexLocker(&m_mutex); | ||||
|         const APTDemod::MsgPixels& pixelsMsg = (APTDemod::MsgPixels&) cmd; | ||||
|         const float *pixels = pixelsMsg.getPixels(); | ||||
|         processPixels(pixels); | ||||
|         return true; | ||||
|     } | ||||
|     else if (APTDemod::MsgResetDecoder::match(cmd)) | ||||
|     { | ||||
|         resetDecoder(); | ||||
|         return true; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void APTDemodImageWorker::applySettings(const APTDemodSettings& settings, bool force) | ||||
| { | ||||
|     (void) force; | ||||
|     m_settings = settings; | ||||
| } | ||||
| 
 | ||||
| void APTDemodImageWorker::resetDecoder() | ||||
| { | ||||
|     m_image.nrow = 0; | ||||
|     m_tempImage.nrow = 0; | ||||
|     m_greyImage = QImage(APT_IMG_WIDTH, APT_MAX_HEIGHT, QImage::Format_Grayscale8); | ||||
|     m_greyImage.fill(0); | ||||
|     m_colourImage = QImage(APT_IMG_WIDTH, APT_MAX_HEIGHT, QImage::Format_RGB888); | ||||
|     m_colourImage.fill(0); | ||||
|     m_satelliteName = ""; | ||||
| } | ||||
| 
 | ||||
| void APTDemodImageWorker::processPixels(const float *pixels) | ||||
| { | ||||
|     std::copy(pixels, pixels + APT_PROW_WIDTH, m_image.prow[m_image.nrow]); | ||||
|     m_image.nrow++; | ||||
|     sendImageToGUI(); | ||||
| } | ||||
| 
 | ||||
| void APTDemodImageWorker::sendImageToGUI() | ||||
| { | ||||
|     // Send image to GUI
 | ||||
|     if (m_messageQueueToGUI) | ||||
|     { | ||||
|         QStringList imageTypes; | ||||
|         QImage image = processImage(imageTypes); | ||||
|         m_messageQueueToGUI->push(APTDemod::MsgImage::create(image, imageTypes, m_satelliteName)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| QImage APTDemodImageWorker::processImage(QStringList& imageTypes) | ||||
| { | ||||
|     copyImage(&m_tempImage, &m_image); | ||||
| 
 | ||||
|     // Calibrate channels according to wavelength
 | ||||
|     if (m_tempImage.nrow >= APT_CALIBRATION_ROWS) | ||||
|     { | ||||
|         m_tempImage.chA = apt_calibrate(m_tempImage.prow, m_tempImage.nrow, APT_CHA_OFFSET, APT_CH_WIDTH); | ||||
|         m_tempImage.chB = apt_calibrate(m_tempImage.prow, m_tempImage.nrow, APT_CHB_OFFSET, APT_CH_WIDTH); | ||||
|         QStringList channelTypes({ | ||||
|             "",  // Unknown
 | ||||
|             "Visible (0.58-0.68 um)", | ||||
|             "Near-IR (0.725-1.0 um)", | ||||
|             "Near-IR (1.58-1.64 um)", | ||||
|             "Mid-infrared (3.55-3.93 um)", | ||||
|             "Thermal-infrared (10.3-11.3 um)", | ||||
|             "Thermal-infrared (11.5-12.5 um)" | ||||
|             }); | ||||
| 
 | ||||
|         imageTypes.append(channelTypes[m_tempImage.chA]); | ||||
|         imageTypes.append(channelTypes[m_tempImage.chB]); | ||||
|     } | ||||
| 
 | ||||
|     // Crop noise due to low elevation at top and bottom of image
 | ||||
|     if (m_settings.m_cropNoise) | ||||
|         m_tempImage.zenith -= apt_cropNoise(&m_tempImage); | ||||
| 
 | ||||
|     // Denoise filter
 | ||||
|     if (m_settings.m_denoise) | ||||
|     { | ||||
|         apt_denoise(m_tempImage.prow, m_tempImage.nrow, APT_CHA_OFFSET, APT_CH_WIDTH); | ||||
|         apt_denoise(m_tempImage.prow, m_tempImage.nrow, APT_CHB_OFFSET, APT_CH_WIDTH); | ||||
|     } | ||||
| 
 | ||||
|     // Flip image if satellite pass is North to South
 | ||||
|     if (m_settings.m_flip) | ||||
|     { | ||||
|         apt_flipImage(&m_tempImage, APT_CH_WIDTH, APT_CHA_OFFSET); | ||||
|         apt_flipImage(&m_tempImage, APT_CH_WIDTH, APT_CHB_OFFSET); | ||||
|     } | ||||
| 
 | ||||
|     // Linear equalise to improve contrast
 | ||||
|     if (m_settings.m_linearEqualise) | ||||
|     { | ||||
|         apt_linearEnhance(m_tempImage.prow, m_tempImage.nrow, APT_CHA_OFFSET, APT_CH_WIDTH); | ||||
|         apt_linearEnhance(m_tempImage.prow, m_tempImage.nrow, APT_CHB_OFFSET, APT_CH_WIDTH); | ||||
|     } | ||||
| 
 | ||||
|     // Histogram equalise to improve contrast
 | ||||
|     if (m_settings.m_histogramEqualise) | ||||
|     { | ||||
|         apt_histogramEqualise(m_tempImage.prow, m_tempImage.nrow, APT_CHA_OFFSET, APT_CH_WIDTH); | ||||
|         apt_histogramEqualise(m_tempImage.prow, m_tempImage.nrow, APT_CHB_OFFSET, APT_CH_WIDTH); | ||||
|     } | ||||
| 
 | ||||
|     if (m_settings.m_precipitationOverlay) | ||||
|     { | ||||
|         // Overlay precipitation
 | ||||
|         for (int r = 0; r < m_tempImage.nrow; r++) | ||||
|         { | ||||
|             uchar *l = m_colourImage.scanLine(r); | ||||
|             for (int i = 0; i < APT_IMG_WIDTH; i++) | ||||
|             { | ||||
|                 float p = m_tempImage.prow[r][i]; | ||||
| 
 | ||||
|                 if ((i >= APT_CHB_OFFSET) && (i < APT_CHB_OFFSET + APT_CH_WIDTH) && (p >= 198)) | ||||
|                 { | ||||
|                     apt_rgb_t rgb = apt_applyPalette(apt_PrecipPalette, p - 198); | ||||
|                     // Negative float values get converted to positive uchars here
 | ||||
|                     l[i*3] = (uchar)rgb.r; | ||||
|                     l[i*3+1] = (uchar)rgb.g; | ||||
|                     l[i*3+2] = (uchar)rgb.b; | ||||
|                     int a = i - APT_CHB_OFFSET + APT_CHA_OFFSET; | ||||
|                     l[a*3] = (uchar)rgb.r; | ||||
|                     l[a*3+1] = (uchar)rgb.g; | ||||
|                     l[a*3+2] = (uchar)rgb.b; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     uchar q = roundAndClip(p); | ||||
|                     l[i*3] = q; | ||||
|                     l[i*3+1] = q; | ||||
|                     l[i*3+2] = q; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return extractImage(m_colourImage); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         for (int r = 0; r < m_tempImage.nrow; r++) | ||||
|         { | ||||
|             uchar *l = m_greyImage.scanLine(r); | ||||
| 
 | ||||
|             for (int i = 0; i < APT_IMG_WIDTH; i++) | ||||
|             { | ||||
|                 float p = m_tempImage.prow[r][i]; | ||||
|                 l[i] = roundAndClip(p); | ||||
|             } | ||||
|         } | ||||
|         return extractImage(m_greyImage); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| QImage APTDemodImageWorker::extractImage(QImage image) | ||||
| { | ||||
|     if (m_settings.m_channels == APTDemodSettings::BOTH_CHANNELS) { | ||||
|         return image.copy(0, 0, APT_IMG_WIDTH, m_tempImage.nrow); | ||||
|     } else if (m_settings.m_channels == APTDemodSettings::CHANNEL_A) { | ||||
|         return image.copy(APT_CHA_OFFSET, 0, APT_CH_WIDTH, m_tempImage.nrow); | ||||
|     } else { | ||||
|         return image.copy(APT_CHB_OFFSET, 0, APT_CH_WIDTH, m_tempImage.nrow); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void APTDemodImageWorker::copyImage(apt_image_t *dst, apt_image_t *src) | ||||
| { | ||||
|     dst->nrow = src->nrow; | ||||
|     dst->zenith = src->zenith; | ||||
|     dst->chA = src->chA; | ||||
|     dst->chB = src->chB; | ||||
| 
 | ||||
|     for (int i = 0; i < src->nrow; i++) { | ||||
|         std::copy(src->prow[i], src->prow[i] + APT_PROW_WIDTH, dst->prow[i]); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uchar APTDemodImageWorker::roundAndClip(float p) | ||||
| { | ||||
|     int q = (int) round(p); | ||||
|     q = q > 255 ? 255 : q < 0 ? 0 : q; | ||||
|     return q; | ||||
| } | ||||
							
								
								
									
										100
									
								
								plugins/channelrx/demodapt/aptdemodimageworker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								plugins/channelrx/demodapt/aptdemodimageworker.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Copyright (C) 2015-2018 Edouard Griffiths, F4EXB.                             //
 | ||||
| // Copyright (C) 2021 Jon Beniston, M7RCE                                        //
 | ||||
| //                                                                               //
 | ||||
| // This program is free software; you can redistribute it and/or modify          //
 | ||||
| // it under the terms of the GNU General Public License as published by          //
 | ||||
| // the Free Software Foundation as version 3 of the License, or                  //
 | ||||
| // (at your option) any later version.                                           //
 | ||||
| //                                                                               //
 | ||||
| // This program is distributed in the hope that it will be useful,               //
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||
| // GNU General Public License V3 for more details.                               //
 | ||||
| //                                                                               //
 | ||||
| // You should have received a copy of the GNU General Public License             //
 | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #ifndef INCLUDE_APTDEMODIMAGEWORKER_H | ||||
| #define INCLUDE_APTDEMODIMAGEWORKER_H | ||||
| 
 | ||||
| #include <QObject> | ||||
| #include <QMutex> | ||||
| #include <QImage> | ||||
| 
 | ||||
| #include <apt.h> | ||||
| 
 | ||||
| #include "util/messagequeue.h" | ||||
| #include "util/message.h" | ||||
| 
 | ||||
| #include "aptdemodsettings.h" | ||||
| 
 | ||||
| class APTDemodImageWorker : public QObject | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     class MsgConfigureAPTDemodImageWorker : public Message { | ||||
|         MESSAGE_CLASS_DECLARATION | ||||
| 
 | ||||
|     public: | ||||
|         const APTDemodSettings& getSettings() const { return m_settings; } | ||||
|         bool getForce() const { return m_force; } | ||||
| 
 | ||||
|         static MsgConfigureAPTDemodImageWorker* create(const APTDemodSettings& settings, bool force) | ||||
|         { | ||||
|             return new MsgConfigureAPTDemodImageWorker(settings, force); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         APTDemodSettings m_settings; | ||||
|         bool m_force; | ||||
| 
 | ||||
|         MsgConfigureAPTDemodImageWorker(const APTDemodSettings& settings, bool force) : | ||||
|             Message(), | ||||
|             m_settings(settings), | ||||
|             m_force(force) | ||||
|         { } | ||||
|     }; | ||||
| 
 | ||||
|     APTDemodImageWorker(); | ||||
|     ~APTDemodImageWorker(); | ||||
|     void reset(); | ||||
|     void startWork(); | ||||
|     void stopWork(); | ||||
|     bool isRunning() const { return m_running; } | ||||
| 
 | ||||
|     MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
 | ||||
|     void setMessageQueueToGUI(MessageQueue *messageQueue) { m_messageQueueToGUI = messageQueue; } | ||||
| 
 | ||||
| private: | ||||
|     MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
 | ||||
|     MessageQueue *m_messageQueueToGUI; | ||||
|     APTDemodSettings m_settings; | ||||
| 
 | ||||
|     // Image buffers
 | ||||
|     apt_image_t m_image;                // Received image
 | ||||
|     apt_image_t m_tempImage;            // Processed image
 | ||||
|     QImage m_greyImage; | ||||
|     QImage m_colourImage; | ||||
|     QString m_satelliteName; | ||||
| 
 | ||||
|     bool m_running; | ||||
|     QMutex m_mutex; | ||||
| 
 | ||||
|     bool handleMessage(const Message& cmd); | ||||
|     void applySettings(const APTDemodSettings& settings, bool force = false); | ||||
|     void resetDecoder(); | ||||
|     void processPixels(const float *pixels); | ||||
|     void sendImageToGUI(); | ||||
|     QImage processImage(QStringList& imageTypes); | ||||
|     QImage extractImage(QImage image); | ||||
| 
 | ||||
|     static void copyImage(apt_image_t *dst, apt_image_t *src); | ||||
|     static uchar roundAndClip(float p); | ||||
| 
 | ||||
| private slots: | ||||
|     void handleInputMessages(); | ||||
| }; | ||||
| 
 | ||||
| #endif // INCLUDE_APTDEMODIMAGEWORKER_H
 | ||||
| @ -37,7 +37,7 @@ APTDemodSink::APTDemodSink(APTDemod *packetDemod) : | ||||
|         m_magsqSum(0.0f), | ||||
|         m_magsqPeak(0.0f), | ||||
|         m_magsqCount(0), | ||||
|         m_messageQueueToChannel(nullptr), | ||||
|         m_imageWorkerMessageQueue(nullptr), | ||||
|         m_samples(nullptr) | ||||
| { | ||||
|     m_magsq = 0.0; | ||||
| @ -124,7 +124,11 @@ void APTDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV | ||||
|     { | ||||
|         float pixels[APT_PROW_WIDTH]; | ||||
|         apt_getpixelrow(pixels, m_row, &m_zenith, m_row == 0, getsamples, this); | ||||
|         getMessageQueueToChannel()->push(APTDemod::MsgPixels::create(pixels, m_zenith)); | ||||
| 
 | ||||
|         if (getImageWorkerMessageQueue()) { | ||||
|             getImageWorkerMessageQueue()->push(APTDemod::MsgPixels::create(pixels, m_zenith)); | ||||
|         } | ||||
| 
 | ||||
|         m_row++; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -51,7 +51,7 @@ public: | ||||
| 
 | ||||
|     void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false); | ||||
|     void applySettings(const APTDemodSettings& settings, bool force = false); | ||||
|     void setMessageQueueToChannel(MessageQueue *messageQueue) { m_messageQueueToChannel = messageQueue; } | ||||
|     void setImageWorkerMessageQueue(MessageQueue *messageQueue) { m_imageWorkerMessageQueue = messageQueue; } | ||||
| 
 | ||||
|     double getMagSq() const { return m_magsq; } | ||||
| 
 | ||||
| @ -103,7 +103,7 @@ private: | ||||
|     int  m_magsqCount; | ||||
|     MagSqLevelsStore m_magSqLevelStore; | ||||
| 
 | ||||
|     MessageQueue *m_messageQueueToChannel; | ||||
|     MessageQueue *m_imageWorkerMessageQueue; | ||||
| 
 | ||||
|     MovingAverageUtil<Real, double, 16> m_movingAverage; | ||||
| 
 | ||||
| @ -120,7 +120,7 @@ private: | ||||
|     int m_zenith;       // Row number of Zenith
 | ||||
| 
 | ||||
|     void processOneSample(Complex &ci); | ||||
|     MessageQueue *getMessageQueueToChannel() { return m_messageQueueToChannel; } | ||||
|     MessageQueue *getImageWorkerMessageQueue() { return m_imageWorkerMessageQueue; } | ||||
| }; | ||||
| 
 | ||||
| #endif // INCLUDE_APTDEMODSINK_H
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user