| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // Copyright (C) 2016 Edouard Griffiths, F4EXB                                   //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // 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                  //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // 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 <string.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <QDebug>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "util/simpleserializer.h"
 | 
					
						
							|  |  |  | #include "dsp/dspcommands.h"
 | 
					
						
							|  |  |  | #include "dsp/dspengine.h"
 | 
					
						
							|  |  |  | #include "sdrplaygui.h"
 | 
					
						
							|  |  |  | #include "sdrplayinput.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <device/devicesourceapi.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "sdrplaythread.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MESSAGE_CLASS_DEFINITION(SDRPlayInput::MsgConfigureSDRPlay, Message) | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  | MESSAGE_CLASS_DEFINITION(SDRPlayInput::MsgReportSDRPlayGains, Message) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | SDRPlayInput::SDRPlayInput(DeviceSourceAPI *deviceAPI) : | 
					
						
							|  |  |  |     m_deviceAPI(deviceAPI), | 
					
						
							|  |  |  |     m_settings(), | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  | 	m_dev(0), | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |     m_sdrPlayThread(0), | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  |     m_deviceDescription("SDRPlay"), | 
					
						
							| 
									
										
										
										
											2017-04-14 02:49:41 +02:00
										 |  |  |     m_devNumber(0), | 
					
						
							|  |  |  |     m_running(false) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     openDevice(); | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SDRPlayInput::~SDRPlayInput() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     if (m_running) stop(); | 
					
						
							|  |  |  |     closeDevice(); | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  | bool SDRPlayInput::openDevice() | 
					
						
							| 
									
										
										
										
											2017-04-14 02:49:41 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     m_devNumber = m_deviceAPI->getSampleSourceSequence(); | 
					
						
							| 
									
										
										
										
											2017-04-14 02:49:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     if (m_dev != 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         closeDevice(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-04-14 02:49:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     int res; | 
					
						
							|  |  |  |     //int numberOfGains;
 | 
					
						
							| 
									
										
										
										
											2017-04-14 02:49:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     if (!m_sampleFifo.setSize(96000 * 4)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qCritical("SDRPlayInput::start: could not allocate SampleFifo"); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     if ((res = mirisdr_open(&m_dev, MIRISDR_HW_SDRPLAY, m_devNumber)) < 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qCritical("SDRPlayInput::start: could not open SDRPlay #%d: %s", m_devNumber, strerror(errno)); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     char vendor[256]; | 
					
						
							|  |  |  |     char product[256]; | 
					
						
							|  |  |  |     char serial[256]; | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     vendor[0] = '\0'; | 
					
						
							|  |  |  |     product[0] = '\0'; | 
					
						
							|  |  |  |     serial[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     if ((res = mirisdr_get_device_usb_strings(m_devNumber, vendor, product, serial)) < 0) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |         qCritical("SDRPlayInput::start: error accessing USB device"); | 
					
						
							|  |  |  |         stop(); | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     qWarning("SDRPlayInput::start: open: %s %s, SN: %s", vendor, product, serial); | 
					
						
							|  |  |  |     m_deviceDescription = QString("%1 (SN %2)").arg(product).arg(serial); | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:40:45 +02:00
										 |  |  | bool SDRPlayInput::start() | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  | { | 
					
						
							|  |  |  | //    QMutexLocker mutexLocker(&m_mutex);
 | 
					
						
							|  |  |  |     int res; | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     if (!m_dev) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_running) stop(); | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  | 	char s12FormatString[] = "336_S16"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((res = mirisdr_set_sample_format(m_dev, s12FormatString))) // sample format S12
 | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		qCritical("SDRPlayInput::start: could not set sample format: rc: %d", res); | 
					
						
							|  |  |  | 		stop(); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  | 	int sampleRate = SDRPlaySampleRates::getRate(m_settings.m_devSampleRateIndex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((res = mirisdr_set_sample_rate(m_dev, sampleRate))) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qCritical("SDRPlayInput::start: could not set sample rate to %d: rc: %d", sampleRate, res); | 
					
						
							|  |  |  |         stop(); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     char bulkFormatString[] = "BULK"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((res = mirisdr_set_transfer(m_dev, bulkFormatString)) < 0) | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		qCritical("SDRPlayInput::start: could not set USB Bulk mode: rc: %d", res); | 
					
						
							|  |  |  | 		stop(); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((res = mirisdr_reset_buffer(m_dev)) < 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		qCritical("SDRPlayInput::start: could not reset USB EP buffers: %s", strerror(errno)); | 
					
						
							|  |  |  | 		stop(); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     if((m_sdrPlayThread = new SDRPlayThread(m_dev, &m_sampleFifo)) == 0) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         qFatal("SDRPlayInput::start: failed to create thread"); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 02:46:52 +02:00
										 |  |  |     m_sdrPlayThread->setLog2Decimation(m_settings.m_log2Decim); | 
					
						
							|  |  |  |     m_sdrPlayThread->setFcPos((int) m_settings.m_fcPos); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-15 18:58:17 +01:00
										 |  |  |     m_sdrPlayThread->startWork(); | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  | //	mutexLocker.unlock();
 | 
					
						
							| 
									
										
										
										
											2016-11-14 03:23:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  | 	applySettings(m_settings, true, true); | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  | 	m_running = true; | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  | void SDRPlayInput::closeDevice() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_dev != 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         mirisdr_close(m_dev); | 
					
						
							|  |  |  |         m_dev = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_deviceDescription.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | void SDRPlayInput::stop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  | //    QMutexLocker mutexLocker(&m_mutex);
 | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if(m_sdrPlayThread != 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_sdrPlayThread->stopWork(); | 
					
						
							|  |  |  |         delete m_sdrPlayThread; | 
					
						
							|  |  |  |         m_sdrPlayThread = 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 03:17:04 +02:00
										 |  |  |     m_running = false; | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const QString& SDRPlayInput::getDeviceDescription() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_deviceDescription; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int SDRPlayInput::getSampleRate() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int rate = SDRPlaySampleRates::getRate(m_settings.m_devSampleRateIndex); | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     return rate / (1<<m_settings.m_log2Decim); | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | quint64 SDRPlayInput::getCenterFrequency() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_settings.m_centerFrequency; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool SDRPlayInput::handleMessage(const Message& message) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (MsgConfigureSDRPlay::match(message)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         MsgConfigureSDRPlay& conf = (MsgConfigureSDRPlay&) message; | 
					
						
							|  |  |  |         qDebug() << "SDRPlayInput::handleMessage: MsgConfigureSDRPlay"; | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  |         const SDRPlaySettings& settings = conf.getSettings(); | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  |         // change of sample rate needs full stop / start sequence that includes the standard apply settings
 | 
					
						
							| 
									
										
										
										
											2016-11-20 11:34:32 +01:00
										 |  |  |         // only if in started state (iff m_dev != 0)
 | 
					
						
							|  |  |  |         if ((m_dev != 0) && (m_settings.m_devSampleRateIndex != settings.m_devSampleRateIndex)) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2016-11-20 11:34:32 +01:00
										 |  |  |             m_settings = settings; | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  |             stop(); | 
					
						
							| 
									
										
										
										
											2017-04-14 03:40:45 +02:00
										 |  |  |             start(); | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         // standard changes
 | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (!applySettings(settings, false, false)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 qDebug("SDRPlayInput::handleMessage: config error"); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  | bool SDRPlayInput::applySettings(const SDRPlaySettings& settings, bool forwardChange, bool force) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |     bool forceGainSetting = false; | 
					
						
							| 
									
										
										
										
											2016-11-20 11:34:32 +01:00
										 |  |  |     //settings.debug("SDRPlayInput::applySettings");
 | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |     QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         m_settings.m_dcBlock = settings.m_dcBlock; | 
					
						
							|  |  |  |         m_deviceAPI->configureCorrections(m_settings.m_dcBlock, m_settings.m_iqCorrection); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         m_settings.m_iqCorrection = settings.m_iqCorrection; | 
					
						
							|  |  |  |         m_deviceAPI->configureCorrections(m_settings.m_dcBlock, m_settings.m_iqCorrection); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-18 04:36:12 +01:00
										 |  |  |     // gains processing
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |     if ((m_settings.m_tunerGainMode != settings.m_tunerGainMode) || force) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |         m_settings.m_tunerGainMode = settings.m_tunerGainMode; | 
					
						
							|  |  |  |         forceGainSetting = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  |     if (m_settings.m_tunerGainMode) // auto
 | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         if ((m_settings.m_tunerGain != settings.m_tunerGain) || forceGainSetting) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             m_settings.m_tunerGain = settings.m_tunerGain; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if(m_dev != 0) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 int r = mirisdr_set_tuner_gain(m_dev, m_settings.m_tunerGain); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (r < 0) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     qDebug("SDRPlayInput::applySettings: could not set tuner gain"); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  |                     int lnaGain; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (m_settings.m_frequencyBandIndex < 3) // bands using AM mode
 | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         lnaGain = mirisdr_get_mixbuffer_gain(m_dev); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     else | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         lnaGain = mirisdr_get_lna_gain(m_dev); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |                     MsgReportSDRPlayGains *message = MsgReportSDRPlayGains::create( | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  |                             lnaGain, | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |                             mirisdr_get_mixer_gain(m_dev), | 
					
						
							|  |  |  |                             mirisdr_get_baseband_gain(m_dev), | 
					
						
							|  |  |  |                             mirisdr_get_tuner_gain(m_dev) | 
					
						
							|  |  |  |                     ); | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |                     getOutputMessageQueueToGUI()->push(message); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  |     else // manual
 | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         bool anyChange = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((m_settings.m_lnaOn != settings.m_lnaOn) || forceGainSetting) | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |             if(m_dev != 0) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  |                 if (m_settings.m_frequencyBandIndex < 3) // bands using AM mode
 | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |                 { | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  |                     int r = mirisdr_set_mixbuffer_gain(m_dev, settings.m_lnaOn ? 0 : 1); // mirisdr_set_mixbuffer_gain takes gain reduction
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (r != 0) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         qDebug("SDRPlayInput::applySettings: could not set mixer buffer gain"); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     else | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         m_settings.m_lnaOn = settings.m_lnaOn; | 
					
						
							|  |  |  |                         anyChange = true; | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  |                     int r = mirisdr_set_lna_gain(m_dev, settings.m_lnaOn ? 0 : 1); // mirisdr_set_lna_gain takes gain reduction
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (r != 0) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         qDebug("SDRPlayInput::applySettings: could not set LNA gain"); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     else | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         m_settings.m_lnaOn = settings.m_lnaOn; | 
					
						
							|  |  |  |                         anyChange = true; | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |         if ((m_settings.m_mixerAmpOn != settings.m_mixerAmpOn) || forceGainSetting) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if(m_dev != 0) | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |                 int r = mirisdr_set_mixer_gain(m_dev, settings.m_mixerAmpOn ? 0 : 1); // mirisdr_set_lna_gain takes gain reduction
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (r != 0) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     qDebug("SDRPlayInput::applySettings: could not set mixer gain"); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     m_settings.m_mixerAmpOn = settings.m_mixerAmpOn; | 
					
						
							|  |  |  |                     anyChange = true; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if ((m_settings.m_basebandGain != settings.m_basebandGain) || forceGainSetting) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if(m_dev != 0) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 int r = mirisdr_set_baseband_gain(m_dev, settings.m_basebandGain); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (r != 0) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     qDebug("SDRPlayInput::applySettings: could not set mixer gain"); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     m_settings.m_basebandGain = settings.m_basebandGain; | 
					
						
							|  |  |  |                     anyChange = true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (anyChange) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  |             int lnaGain; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (m_settings.m_frequencyBandIndex < 3) // bands using AM mode
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 lnaGain = mirisdr_get_mixbuffer_gain(m_dev); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 mirisdr_get_lna_gain(m_dev); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |             MsgReportSDRPlayGains *message = MsgReportSDRPlayGains::create( | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:57 +01:00
										 |  |  |                     lnaGain, | 
					
						
							| 
									
										
										
										
											2016-11-18 02:46:35 +01:00
										 |  |  |                     mirisdr_get_mixer_gain(m_dev), | 
					
						
							|  |  |  |                     mirisdr_get_baseband_gain(m_dev), | 
					
						
							|  |  |  |                     mirisdr_get_tuner_gain(m_dev) | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |             getOutputMessageQueueToGUI()->push(message); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     if ((m_settings.m_log2Decim != settings.m_log2Decim) || force) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         m_settings.m_log2Decim = settings.m_log2Decim; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |         forwardChange = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         if (m_sdrPlayThread != 0) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |             m_sdrPlayThread->setLog2Decimation(m_settings.m_log2Decim); | 
					
						
							|  |  |  |             qDebug() << "SDRPlayInput::applySettings: set decimation to " << (1<<m_settings.m_log2Decim); | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     if (m_settings.m_centerFrequency != settings.m_centerFrequency) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         forwardChange = true; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     qint64 deviceCenterFrequency = m_settings.m_centerFrequency; | 
					
						
							|  |  |  |     qint64 f_img = deviceCenterFrequency; | 
					
						
							|  |  |  |     quint32 devSampleRate = SDRPlaySampleRates::getRate(m_settings.m_devSampleRateIndex); | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) | 
					
						
							|  |  |  |             || (m_settings.m_LOppmTenths != settings.m_LOppmTenths) | 
					
						
							|  |  |  |             || (m_settings.m_fcPos != settings.m_fcPos)) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         m_settings.m_centerFrequency = settings.m_centerFrequency; | 
					
						
							|  |  |  |         m_settings.m_LOppmTenths = settings.m_LOppmTenths; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         if ((m_settings.m_log2Decim == 0) || (settings.m_fcPos == SDRPlaySettings::FC_POS_CENTER)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             deviceCenterFrequency = m_settings.m_centerFrequency; | 
					
						
							|  |  |  |             f_img = deviceCenterFrequency; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |             if (settings.m_fcPos == SDRPlaySettings::FC_POS_INFRA) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |                 deviceCenterFrequency = m_settings.m_centerFrequency + (devSampleRate / 4); | 
					
						
							|  |  |  |                 f_img = deviceCenterFrequency + devSampleRate/2; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |             else if (settings.m_fcPos == SDRPlaySettings::FC_POS_SUPRA) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |                 deviceCenterFrequency = m_settings.m_centerFrequency - (devSampleRate / 4); | 
					
						
							|  |  |  |                 f_img = deviceCenterFrequency - devSampleRate/2; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         if(m_dev != 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (setCenterFrequency(deviceCenterFrequency)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 qDebug() << "SDRPlayInput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz" | 
					
						
							|  |  |  |                         << " device center freq: " << deviceCenterFrequency << " Hz" | 
					
						
							|  |  |  |                         << " device sample rate: " << devSampleRate << "Hz" | 
					
						
							|  |  |  |                         << " Actual sample rate: " << devSampleRate/(1<<m_settings.m_log2Decim) << "Hz" | 
					
						
							|  |  |  |                         << " img: " << f_img << "Hz"; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     if ((m_settings.m_fcPos != settings.m_fcPos) || force) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         m_settings.m_fcPos = settings.m_fcPos; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         if (m_sdrPlayThread != 0) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |             m_sdrPlayThread->setFcPos((int) m_settings.m_fcPos); | 
					
						
							|  |  |  |             qDebug() << "SDRPlayInput: set fc pos (enum) to " << (int) m_settings.m_fcPos; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     if ((m_settings.m_frequencyBandIndex != settings.m_frequencyBandIndex) || force) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         m_settings.m_frequencyBandIndex = settings.m_frequencyBandIndex; | 
					
						
							|  |  |  |         // change of frequency is done already
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     if ((m_settings.m_bandwidthIndex != settings.m_bandwidthIndex) || force) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int bandwidth = SDRPlayBandwidths::getBandwidth(settings.m_bandwidthIndex); | 
					
						
							|  |  |  |         int r = mirisdr_set_bandwidth(m_dev, bandwidth); | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         if (r < 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             qCritical("SDRPlayInput::applySettings: set bandwidth %d failed: rc: %d", bandwidth, r); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             qDebug("SDRPlayInput::applySettings: bandwidth set to %d", bandwidth); | 
					
						
							|  |  |  |             m_settings.m_bandwidthIndex = settings.m_bandwidthIndex; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:11:19 +01:00
										 |  |  |     if ((m_settings.m_ifFrequencyIndex != settings.m_ifFrequencyIndex) || force) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         int iFFrequency = SDRPlayIF::getIF(settings.m_ifFrequencyIndex); | 
					
						
							|  |  |  |         int r = mirisdr_set_if_freq(m_dev, iFFrequency); | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         if (r < 0) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |             qCritical("SDRPlayInput::applySettings: set IF frequency to %d failed: rc: %d", iFFrequency, r); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             qDebug("SDRPlayInput::applySettings: IF frequency set to %d", iFFrequency); | 
					
						
							|  |  |  |             m_settings.m_ifFrequencyIndex = settings.m_ifFrequencyIndex; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  |     if (forwardChange) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int sampleRate = getSampleRate(); | 
					
						
							|  |  |  |         DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency); | 
					
						
							|  |  |  |         m_deviceAPI->getDeviceInputMessageQueue()->push(notif); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  | bool SDRPlayInput::setCenterFrequency(quint64 freq_hz) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |     qint64 df = ((qint64)freq_hz * m_settings.m_LOppmTenths) / 10000000LL; | 
					
						
							|  |  |  |     freq_hz += df; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int r = mirisdr_set_center_freq(m_dev, static_cast<uint32_t>(freq_hz)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (r != 0) | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         qWarning("SDRPlayInput::setCenterFrequency: could not frequency to %llu Hz", freq_hz); | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  |         qWarning("SDRPlayInput::setCenterFrequency: frequency set to %llu Hz", freq_hz); | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2016-11-14 00:38:43 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-13 02:59:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 02:38:21 +01:00
										 |  |  | 
 |