2017-08-14 01:39:26 +02:00
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 <QDebug>
2018-04-15 18:25:22 +02:00
# include "SWGChannelSettings.h"
# include "SWGChannelReport.h"
# include "SWGUDPSinkReport.h"
2017-10-17 23:45:57 +02:00
# include "device/devicesinkapi.h"
2017-08-14 01:39:26 +02:00
# include "dsp/upchannelizer.h"
2017-10-17 23:45:57 +02:00
# include "dsp/threadedbasebandsamplesource.h"
2018-02-14 20:11:36 +01:00
# include "dsp/dspcommands.h"
2017-08-17 04:23:36 +02:00
# include "util/db.h"
2017-10-17 23:45:57 +02:00
2017-08-16 04:00:33 +02:00
# include "udpsinkmsg.h"
2017-08-14 01:39:26 +02:00
# include "udpsink.h"
2017-10-16 22:22:29 +02:00
MESSAGE_CLASS_DEFINITION ( UDPSink : : MsgConfigureUDPSink , Message )
MESSAGE_CLASS_DEFINITION ( UDPSink : : MsgConfigureChannelizer , Message )
2017-08-14 16:09:56 +02:00
MESSAGE_CLASS_DEFINITION ( UDPSink : : MsgUDPSinkSpectrum , Message )
2017-08-18 17:51:11 +02:00
MESSAGE_CLASS_DEFINITION ( UDPSink : : MsgResetReadIndex , Message )
2017-08-14 01:39:26 +02:00
2017-11-23 01:19:32 +01:00
const QString UDPSink : : m_channelIdURI = " sdrangel.channeltx.udpsink " ;
const QString UDPSink : : m_channelId = " UDPSink " ;
2017-11-08 17:09:25 +01:00
UDPSink : : UDPSink ( DeviceSinkAPI * deviceAPI ) :
2017-12-20 23:57:06 +01:00
ChannelSourceAPI ( m_channelIdURI ) ,
2017-10-17 21:08:54 +02:00
m_deviceAPI ( deviceAPI ) ,
2017-12-30 00:30:41 +01:00
m_basebandSampleRate ( 48000 ) ,
2017-12-30 10:17:30 +01:00
m_outputSampleRate ( 48000 ) ,
2017-12-30 00:30:41 +01:00
m_inputFrequencyOffset ( 0 ) ,
2017-10-17 00:14:06 +02:00
m_squelch ( 1e-6 ) ,
2017-11-08 17:09:25 +01:00
m_spectrum ( 0 ) ,
2017-08-16 22:49:19 +02:00
m_spectrumEnabled ( false ) ,
2017-08-16 23:37:01 +02:00
m_spectrumChunkSize ( 2160 ) ,
2017-08-16 22:49:19 +02:00
m_spectrumChunkCounter ( 0 ) ,
2017-08-14 22:50:28 +02:00
m_magsq ( 1e-10 ) ,
2017-08-17 04:23:36 +02:00
m_movingAverage ( 16 , 1e-10 ) ,
m_inMovingAverage ( 480 , 1e-10 ) ,
2017-08-16 16:09:35 +02:00
m_sampleRateSum ( 0 ) ,
m_sampleRateAvgCounter ( 0 ) ,
2017-08-16 23:37:01 +02:00
m_levelCalcCount ( 0 ) ,
m_peakLevel ( 0.0f ) ,
m_levelSum ( 0.0f ) ,
m_levelNbSamples ( 480 ) ,
2017-08-17 04:23:36 +02:00
m_squelchOpen ( false ) ,
m_squelchOpenCount ( 0 ) ,
m_squelchCloseCount ( 0 ) ,
m_squelchThreshold ( 4800 ) ,
2017-08-18 12:30:51 +02:00
m_modPhasor ( 0.0f ) ,
2017-08-19 03:42:56 +02:00
m_SSBFilterBufferIndex ( 0 ) ,
2017-08-14 01:39:26 +02:00
m_settingsMutex ( QMutex : : Recursive )
{
2017-11-23 01:19:32 +01:00
setObjectName ( m_channelId ) ;
2017-10-17 23:45:57 +02:00
2017-11-06 01:39:44 +01:00
m_udpHandler . setFeedbackMessageQueue ( & m_inputMessageQueue ) ;
m_SSBFilter = new fftfilt ( m_settings . m_lowCutoff / m_settings . m_inputSampleRate , m_settings . m_rfBandwidth / m_settings . m_inputSampleRate , m_ssbFftLen ) ;
m_SSBFilterBuffer = new Complex [ m_ssbFftLen > > 1 ] ; // filter returns data exactly half of its size
2018-03-16 10:26:49 +01:00
applyChannelSettings ( m_basebandSampleRate , m_outputSampleRate , m_inputFrequencyOffset , true ) ;
applySettings ( m_settings , true ) ;
2017-10-17 23:45:57 +02:00
m_channelizer = new UpChannelizer ( this ) ;
m_threadedChannelizer = new ThreadedBasebandSampleSource ( m_channelizer , this ) ;
m_deviceAPI - > addThreadedSource ( m_threadedChannelizer ) ;
2017-11-19 19:33:20 +01:00
m_deviceAPI - > addChannelAPI ( this ) ;
2017-08-14 01:39:26 +02:00
}
UDPSink : : ~ UDPSink ( )
{
2017-11-19 19:33:20 +01:00
m_deviceAPI - > removeChannelAPI ( this ) ;
2017-10-17 23:45:57 +02:00
m_deviceAPI - > removeThreadedSource ( m_threadedChannelizer ) ;
delete m_threadedChannelizer ;
delete m_channelizer ;
2018-04-18 22:20:47 +02:00
delete m_SSBFilter ;
delete [ ] m_SSBFilterBuffer ;
2017-08-14 01:39:26 +02:00
}
void UDPSink : : start ( )
{
2017-08-15 20:23:49 +02:00
m_udpHandler . start ( ) ;
2018-01-09 01:10:49 +01:00
applyChannelSettings ( m_basebandSampleRate , m_outputSampleRate , m_inputFrequencyOffset , true ) ;
2017-08-14 01:39:26 +02:00
}
void UDPSink : : stop ( )
{
2017-08-15 20:23:49 +02:00
m_udpHandler . stop ( ) ;
2017-08-14 01:39:26 +02:00
}
void UDPSink : : pull ( Sample & sample )
{
2017-10-17 00:14:06 +02:00
if ( m_settings . m_channelMute )
2017-08-14 10:59:05 +02:00
{
sample . m_real = 0.0f ;
sample . m_imag = 0.0f ;
2017-08-17 04:23:36 +02:00
initSquelch ( false ) ;
2017-08-14 10:59:05 +02:00
return ;
}
Complex ci ;
m_settingsMutex . lock ( ) ;
if ( m_interpolatorDistance > 1.0f ) // decimate
{
modulateSample ( ) ;
while ( ! m_interpolator . decimate ( & m_interpolatorDistanceRemain , m_modSample , & ci ) )
{
modulateSample ( ) ;
}
}
else
{
if ( m_interpolator . interpolate ( & m_interpolatorDistanceRemain , m_modSample , & ci ) )
{
modulateSample ( ) ;
}
}
m_interpolatorDistanceRemain + = m_interpolatorDistance ;
ci * = m_carrierNco . nextIQ ( ) ; // shift to carrier frequency
m_settingsMutex . unlock ( ) ;
2017-08-17 04:23:36 +02:00
double magsq = ci . real ( ) * ci . real ( ) + ci . imag ( ) * ci . imag ( ) ;
2018-01-22 08:46:05 +01:00
magsq / = ( SDR_TX_SCALED * SDR_TX_SCALED ) ;
2017-08-14 22:50:28 +02:00
m_movingAverage . feed ( magsq ) ;
m_magsq = m_movingAverage . average ( ) ;
2017-08-14 10:59:05 +02:00
sample . m_real = ( FixReal ) ci . real ( ) ;
sample . m_imag = ( FixReal ) ci . imag ( ) ;
}
void UDPSink : : modulateSample ( )
{
2018-04-19 00:52:01 +02:00
if ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatSnLE ) // Linear I/Q transponding
2017-08-15 20:23:49 +02:00
{
2017-08-18 12:30:51 +02:00
Sample s ;
2017-08-15 20:23:49 +02:00
m_udpHandler . readSample ( s ) ;
2017-08-17 04:23:36 +02:00
uint64_t magsq = s . m_real * s . m_real + s . m_imag * s . m_imag ;
2018-01-22 08:46:05 +01:00
m_inMovingAverage . feed ( magsq / ( SDR_TX_SCALED * SDR_TX_SCALED ) ) ;
2017-08-17 04:23:36 +02:00
m_inMagsq = m_inMovingAverage . average ( ) ;
calculateSquelch ( m_inMagsq ) ;
if ( m_squelchOpen )
{
2017-10-17 00:14:06 +02:00
m_modSample . real ( s . m_real * m_settings . m_gainOut ) ;
m_modSample . imag ( s . m_imag * m_settings . m_gainOut ) ;
2017-08-17 04:23:36 +02:00
calculateLevel ( m_modSample ) ;
}
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
}
2017-08-15 20:23:49 +02:00
}
2017-10-17 00:14:06 +02:00
else if ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatNFM )
2017-08-18 12:30:51 +02:00
{
2018-04-19 00:43:29 +02:00
qint16 t ;
2017-08-25 10:32:18 +02:00
readMonoSample ( t ) ;
2017-08-18 12:30:51 +02:00
m_inMovingAverage . feed ( ( t * t ) / 1073741824.0 ) ;
m_inMagsq = m_inMovingAverage . average ( ) ;
calculateSquelch ( m_inMagsq ) ;
if ( m_squelchOpen )
{
2018-01-22 08:46:05 +01:00
m_modPhasor + = ( m_settings . m_fmDeviation / m_settings . m_inputSampleRate ) * ( t / SDR_TX_SCALEF ) * M_PI * 2.0f ;
m_modSample . real ( cos ( m_modPhasor ) * 0.3162292f * SDR_TX_SCALEF * m_settings . m_gainOut ) ;
m_modSample . imag ( sin ( m_modPhasor ) * 0.3162292f * SDR_TX_SCALEF * m_settings . m_gainOut ) ;
2017-08-18 22:15:04 +02:00
calculateLevel ( m_modSample ) ;
2017-08-18 12:30:51 +02:00
}
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
}
}
2017-10-17 00:14:06 +02:00
else if ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatAM )
2017-08-19 01:46:52 +02:00
{
2018-04-19 00:43:29 +02:00
qint16 t ;
2017-08-25 10:32:18 +02:00
readMonoSample ( t ) ;
2018-01-22 08:46:05 +01:00
m_inMovingAverage . feed ( ( t * t ) / ( SDR_TX_SCALED * SDR_TX_SCALED ) ) ;
2017-08-19 01:46:52 +02:00
m_inMagsq = m_inMovingAverage . average ( ) ;
calculateSquelch ( m_inMagsq ) ;
if ( m_squelchOpen )
{
2018-01-22 08:46:05 +01:00
m_modSample . real ( ( ( t / SDR_TX_SCALEF ) * m_settings . m_amModFactor * m_settings . m_gainOut + 1.0f ) * ( SDR_TX_SCALEF / 2 ) ) ; // modulate and scale zero frequency carrier
2017-08-19 01:46:52 +02:00
m_modSample . imag ( 0.0f ) ;
calculateLevel ( m_modSample ) ;
}
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
}
}
2017-10-17 00:14:06 +02:00
else if ( ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatLSB ) | | ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatUSB ) )
2017-08-19 03:42:56 +02:00
{
2018-04-19 00:43:29 +02:00
qint16 t ;
2017-08-19 03:42:56 +02:00
Complex c , ci ;
fftfilt : : cmplx * filtered ;
int n_out = 0 ;
2017-08-25 10:32:18 +02:00
readMonoSample ( t ) ;
2018-01-22 08:46:05 +01:00
m_inMovingAverage . feed ( ( t * t ) / ( SDR_TX_SCALED * SDR_TX_SCALED ) ) ;
2017-08-19 03:42:56 +02:00
m_inMagsq = m_inMovingAverage . average ( ) ;
calculateSquelch ( m_inMagsq ) ;
if ( m_squelchOpen )
{
2018-01-22 08:46:05 +01:00
ci . real ( ( t / SDR_TX_SCALEF ) * m_settings . m_gainOut ) ;
2017-08-19 03:42:56 +02:00
ci . imag ( 0.0f ) ;
2017-10-17 00:14:06 +02:00
n_out = m_SSBFilter - > runSSB ( ci , & filtered , ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatUSB ) ) ;
2017-08-19 09:28:50 +02:00
if ( n_out > 0 )
2017-08-19 03:42:56 +02:00
{
memcpy ( ( void * ) m_SSBFilterBuffer , ( const void * ) filtered , n_out * sizeof ( Complex ) ) ;
m_SSBFilterBufferIndex = 0 ;
}
c = m_SSBFilterBuffer [ m_SSBFilterBufferIndex ] ;
2018-01-22 08:46:05 +01:00
m_modSample . real ( m_SSBFilterBuffer [ m_SSBFilterBufferIndex ] . real ( ) * SDR_TX_SCALEF ) ;
m_modSample . imag ( m_SSBFilterBuffer [ m_SSBFilterBufferIndex ] . imag ( ) * SDR_TX_SCALEF ) ;
2017-08-19 03:42:56 +02:00
m_SSBFilterBufferIndex + + ;
calculateLevel ( m_modSample ) ;
}
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
}
}
2017-08-15 20:23:49 +02:00
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
2017-08-17 04:23:36 +02:00
initSquelch ( false ) ;
2017-08-15 20:23:49 +02:00
}
2017-08-16 22:49:19 +02:00
if ( m_spectrum & & m_spectrumEnabled & & ( m_spectrumChunkCounter < m_spectrumChunkSize - 1 ) )
{
Sample s ;
s . m_real = ( FixReal ) m_modSample . real ( ) ;
s . m_imag = ( FixReal ) m_modSample . imag ( ) ;
m_sampleBuffer . push_back ( s ) ;
m_spectrumChunkCounter + + ;
}
2017-11-08 17:09:25 +01:00
else if ( m_spectrum )
2017-08-16 22:49:19 +02:00
{
m_spectrum - > feed ( m_sampleBuffer . begin ( ) , m_sampleBuffer . end ( ) , false ) ;
m_sampleBuffer . clear ( ) ;
m_spectrumChunkCounter = 0 ;
}
2017-08-14 01:39:26 +02:00
}
2017-08-16 23:37:01 +02:00
void UDPSink : : calculateLevel ( Real sample )
{
if ( m_levelCalcCount < m_levelNbSamples )
{
m_peakLevel = std : : max ( std : : fabs ( m_peakLevel ) , sample ) ;
m_levelSum + = sample * sample ;
m_levelCalcCount + + ;
}
else
{
2017-08-17 04:23:36 +02:00
qreal rmsLevel = m_levelSum > 0.0 ? sqrt ( m_levelSum / m_levelNbSamples ) : 0.0 ;
2017-08-16 23:37:01 +02:00
//qDebug("NFMMod::calculateLevel: %f %f", rmsLevel, m_peakLevel);
emit levelChanged ( rmsLevel , m_peakLevel , m_levelNbSamples ) ;
m_peakLevel = 0.0f ;
m_levelSum = 0.0f ;
m_levelCalcCount = 0 ;
}
}
void UDPSink : : calculateLevel ( Complex sample )
{
Real t = std : : abs ( sample ) ;
if ( m_levelCalcCount < m_levelNbSamples )
{
m_peakLevel = std : : max ( std : : fabs ( m_peakLevel ) , t ) ;
m_levelSum + = ( t * t ) ;
m_levelCalcCount + + ;
}
else
{
2018-01-22 08:46:05 +01:00
qreal rmsLevel = m_levelSum > 0.0 ? sqrt ( ( m_levelSum / ( SDR_TX_SCALED * SDR_TX_SCALED ) ) / m_levelNbSamples ) : 0.0 ;
emit levelChanged ( rmsLevel , m_peakLevel / SDR_TX_SCALEF , m_levelNbSamples ) ;
2017-08-16 23:37:01 +02:00
m_peakLevel = 0.0f ;
m_levelSum = 0.0f ;
m_levelCalcCount = 0 ;
}
}
2017-08-14 01:39:26 +02:00
bool UDPSink : : handleMessage ( const Message & cmd )
{
if ( UpChannelizer : : MsgChannelizerNotification : : match ( cmd ) )
{
UpChannelizer : : MsgChannelizerNotification & notif = ( UpChannelizer : : MsgChannelizerNotification & ) cmd ;
2017-12-30 00:30:41 +01:00
qDebug ( ) < < " UDPSink::handleMessage: MsgChannelizerNotification " ;
2017-08-14 01:39:26 +02:00
2017-12-30 00:30:41 +01:00
applyChannelSettings ( notif . getBasebandSampleRate ( ) , notif . getSampleRate ( ) , notif . getFrequencyOffset ( ) ) ;
2017-08-14 01:39:26 +02:00
return true ;
}
2017-10-16 23:04:53 +02:00
else if ( MsgConfigureChannelizer : : match ( cmd ) )
{
MsgConfigureChannelizer & cfg = ( MsgConfigureChannelizer & ) cmd ;
2017-12-30 00:30:41 +01:00
qDebug ( ) < < " UDPSink::handleMessage: MsgConfigureChannelizer: "
< < " sampleRate: " < < cfg . getSampleRate ( )
< < " centerFrequency: " < < cfg . getCenterFrequency ( ) ;
2017-10-16 23:04:53 +02:00
2017-10-17 23:45:57 +02:00
m_channelizer - > configure ( m_channelizer - > getInputMessageQueue ( ) ,
cfg . getSampleRate ( ) ,
cfg . getCenterFrequency ( ) ) ;
2017-10-16 23:04:53 +02:00
return true ;
}
else if ( MsgConfigureUDPSink : : match ( cmd ) )
{
MsgConfigureUDPSink & cfg = ( MsgConfigureUDPSink & ) cmd ;
2017-12-30 00:30:41 +01:00
qDebug ( ) < < " UDPSink::handleMessage: MsgConfigureUDPSink " ;
2017-10-16 23:04:53 +02:00
2017-12-30 00:30:41 +01:00
applySettings ( cfg . getSettings ( ) , cfg . getForce ( ) ) ;
2017-10-16 23:04:53 +02:00
return true ;
}
2017-08-16 04:00:33 +02:00
else if ( UDPSinkMessages : : MsgSampleRateCorrection : : match ( cmd ) )
{
2017-08-16 11:35:47 +02:00
UDPSinkMessages : : MsgSampleRateCorrection & cfg = ( UDPSinkMessages : : MsgSampleRateCorrection & ) cmd ;
2017-08-16 22:49:19 +02:00
Real newSampleRate = m_actualInputSampleRate + cfg . getCorrectionFactor ( ) * m_actualInputSampleRate ;
2017-08-16 16:09:35 +02:00
2017-08-16 22:49:19 +02:00
// exclude values too way out nominal sample rate (20%)
2017-10-17 00:14:06 +02:00
if ( ( newSampleRate < m_settings . m_inputSampleRate * 1.2 ) & & ( newSampleRate > m_settings . m_inputSampleRate * 0.8 ) )
2017-08-16 16:09:35 +02:00
{
2017-08-16 22:49:19 +02:00
m_actualInputSampleRate = newSampleRate ;
2017-12-29 03:22:04 +01:00
if ( ( cfg . getRawDeltaRatio ( ) > - 0.05 ) & & ( cfg . getRawDeltaRatio ( ) < 0.05 ) )
2017-08-16 16:09:35 +02:00
{
2017-08-16 22:49:19 +02:00
if ( m_sampleRateAvgCounter < m_sampleRateAverageItems )
{
m_sampleRateSum + = m_actualInputSampleRate ;
m_sampleRateAvgCounter + + ;
}
}
else
{
m_sampleRateSum = 0.0 ;
m_sampleRateAvgCounter = 0 ;
2017-08-16 16:09:35 +02:00
}
2017-08-16 22:49:19 +02:00
if ( m_sampleRateAvgCounter = = m_sampleRateAverageItems )
{
float avgRate = m_sampleRateSum / m_sampleRateAverageItems ;
qDebug ( " UDPSink::handleMessage: MsgSampleRateCorrection: corr: %+.6f new rate: %.0f: avg rate: %.0f " ,
cfg . getCorrectionFactor ( ) ,
m_actualInputSampleRate ,
avgRate ) ;
m_actualInputSampleRate = avgRate ;
m_sampleRateSum = 0.0 ;
m_sampleRateAvgCounter = 0 ;
}
2017-08-17 01:03:09 +02:00
// else
// {
// qDebug("UDPSink::handleMessage: MsgSampleRateCorrection: corr: %+.6f new rate: %.0f",
// cfg.getCorrectionFactor(),
// m_actualInputSampleRate);
// }
2017-08-16 22:49:19 +02:00
m_settingsMutex . lock ( ) ;
m_interpolatorDistanceRemain = 0 ;
m_interpolatorConsumed = false ;
2017-12-30 00:30:41 +01:00
m_interpolatorDistance = ( Real ) m_actualInputSampleRate / ( Real ) m_outputSampleRate ;
2017-10-17 00:14:06 +02:00
//m_interpolator.create(48, m_actualInputSampleRate, m_settings.m_rfBandwidth / 2.2, 3.0); // causes clicking: leaving at standard frequency
2017-08-16 22:49:19 +02:00
m_settingsMutex . unlock ( ) ;
2017-08-16 16:09:35 +02:00
}
2017-08-16 11:35:47 +02:00
2017-08-16 22:49:19 +02:00
return true ;
}
else if ( MsgUDPSinkSpectrum : : match ( cmd ) )
{
MsgUDPSinkSpectrum & spc = ( MsgUDPSinkSpectrum & ) cmd ;
m_spectrumEnabled = spc . getEnabled ( ) ;
qDebug ( ) < < " UDPSink::handleMessage: MsgUDPSinkSpectrum: m_spectrumEnabled: " < < m_spectrumEnabled ;
2017-08-16 11:35:47 +02:00
2017-08-16 04:00:33 +02:00
return true ;
}
2017-08-18 17:51:11 +02:00
else if ( MsgResetReadIndex : : match ( cmd ) )
{
m_settingsMutex . lock ( ) ;
m_udpHandler . resetReadIndex ( ) ;
m_settingsMutex . unlock ( ) ;
qDebug ( ) < < " UDPSink::handleMessage: MsgResetReadIndex " ;
return true ;
}
2018-02-14 20:11:36 +01:00
else if ( DSPSignalNotification : : match ( cmd ) )
{
return true ;
}
2017-08-14 01:39:26 +02:00
else
{
2017-08-16 22:49:19 +02:00
if ( m_spectrum ! = 0 )
{
return m_spectrum - > handleMessage ( cmd ) ;
}
else
{
return false ;
}
2017-08-14 01:39:26 +02:00
}
}
2017-10-17 09:02:33 +02:00
void UDPSink : : setSpectrum ( bool enabled )
2017-08-14 16:09:56 +02:00
{
Message * cmd = MsgUDPSinkSpectrum : : create ( enabled ) ;
2017-10-17 09:02:33 +02:00
getInputMessageQueue ( ) - > push ( cmd ) ;
2017-08-14 16:09:56 +02:00
}
2017-10-17 09:02:33 +02:00
void UDPSink : : resetReadIndex ( )
2017-08-18 17:51:11 +02:00
{
Message * cmd = MsgResetReadIndex : : create ( ) ;
2017-10-17 09:02:33 +02:00
getInputMessageQueue ( ) - > push ( cmd ) ;
2017-08-18 17:51:11 +02:00
}
2018-01-09 01:10:49 +01:00
void UDPSink : : applyChannelSettings ( int basebandSampleRate , int outputSampleRate , int inputFrequencyOffset , bool force )
2017-10-16 22:22:29 +02:00
{
2017-12-30 00:30:41 +01:00
qDebug ( ) < < " UDPSink::applyChannelSettings: "
< < " basebandSampleRate: " < < basebandSampleRate
< < " outputSampleRate: " < < outputSampleRate
< < " inputFrequencyOffset: " < < inputFrequencyOffset ;
if ( ( inputFrequencyOffset ! = m_inputFrequencyOffset ) | |
2018-01-09 01:10:49 +01:00
( outputSampleRate ! = m_outputSampleRate ) | | force )
2017-10-16 22:22:29 +02:00
{
m_settingsMutex . lock ( ) ;
2017-12-30 00:30:41 +01:00
m_carrierNco . setFreq ( inputFrequencyOffset , outputSampleRate ) ;
2017-10-16 22:22:29 +02:00
m_settingsMutex . unlock ( ) ;
}
2018-01-09 01:10:49 +01:00
if ( ( ( outputSampleRate ! = m_outputSampleRate ) & & ( ! m_settings . m_autoRWBalance ) ) | | force )
2017-12-30 00:30:41 +01:00
{
m_settingsMutex . lock ( ) ;
m_interpolatorDistanceRemain = 0 ;
m_interpolatorConsumed = false ;
m_interpolatorDistance = ( Real ) m_settings . m_inputSampleRate / ( Real ) outputSampleRate ;
m_interpolator . create ( 48 , m_settings . m_inputSampleRate , m_settings . m_rfBandwidth / 2.2 , 3.0 ) ;
m_settingsMutex . unlock ( ) ;
}
m_basebandSampleRate = basebandSampleRate ;
m_outputSampleRate = outputSampleRate ;
m_inputFrequencyOffset = inputFrequencyOffset ;
}
void UDPSink : : applySettings ( const UDPSinkSettings & settings , bool force )
{
qDebug ( ) < < " UDPSink::applySettings: "
< < " m_inputFrequencyOffset: " < < settings . m_inputFrequencyOffset
< < " m_sampleFormat: " < < settings . m_sampleFormat
< < " m_inputSampleRate: " < < settings . m_inputSampleRate
< < " m_rfBandwidth: " < < settings . m_rfBandwidth
< < " m_fmDeviation: " < < settings . m_fmDeviation
< < " m_udpAddressStr: " < < settings . m_udpAddress
< < " m_udpPort: " < < settings . m_udpPort
< < " m_channelMute: " < < settings . m_channelMute
< < " m_gainIn: " < < settings . m_gainIn
< < " m_gainOut: " < < settings . m_gainOut
< < " m_squelchGate: " < < settings . m_squelchGate
< < " m_squelch: " < < settings . m_squelch < < " dB "
< < " m_squelchEnabled: " < < settings . m_squelchEnabled
< < " m_autoRWBalance: " < < settings . m_autoRWBalance
< < " m_stereoInput: " < < settings . m_stereoInput
< < " force: " < < force ;
if ( ( settings . m_rfBandwidth ! = m_settings . m_rfBandwidth ) | |
2017-10-16 22:22:29 +02:00
( settings . m_inputSampleRate ! = m_settings . m_inputSampleRate ) | | force )
{
m_settingsMutex . lock ( ) ;
m_interpolatorDistanceRemain = 0 ;
m_interpolatorConsumed = false ;
2017-12-30 00:30:41 +01:00
m_interpolatorDistance = ( Real ) settings . m_inputSampleRate / ( Real ) m_outputSampleRate ;
2017-10-16 22:22:29 +02:00
m_interpolator . create ( 48 , settings . m_inputSampleRate , settings . m_rfBandwidth / 2.2 , 3.0 ) ;
m_actualInputSampleRate = settings . m_inputSampleRate ;
m_udpHandler . resetReadIndex ( ) ;
m_sampleRateSum = 0.0 ;
m_sampleRateAvgCounter = 0 ;
m_spectrumChunkSize = settings . m_inputSampleRate * 0.05 ; // 50 ms chunk
m_spectrumChunkCounter = 0 ;
m_levelNbSamples = settings . m_inputSampleRate * 0.01 ; // every 10 ms
m_levelCalcCount = 0 ;
m_peakLevel = 0.0f ;
m_levelSum = 0.0f ;
m_udpHandler . resizeBuffer ( settings . m_inputSampleRate ) ;
m_inMovingAverage . resize ( settings . m_inputSampleRate * 0.01 , 1e-10 ) ; // 10 ms
m_squelchThreshold = settings . m_inputSampleRate * settings . m_squelchGate ;
initSquelch ( m_squelchOpen ) ;
m_SSBFilter - > create_filter ( settings . m_lowCutoff / settings . m_inputSampleRate , settings . m_rfBandwidth / settings . m_inputSampleRate ) ;
m_settingsMutex . unlock ( ) ;
}
2017-10-17 00:14:06 +02:00
if ( ( settings . m_squelch ! = m_settings . m_squelch ) | | force )
{
m_squelch = CalcDb : : powerFromdB ( settings . m_squelch ) ;
}
2017-10-16 22:22:29 +02:00
if ( ( settings . m_squelchGate ! = m_settings . m_squelchGate ) | | force )
{
2017-12-30 00:30:41 +01:00
m_squelchThreshold = m_outputSampleRate * settings . m_squelchGate ;
2017-10-16 22:22:29 +02:00
initSquelch ( m_squelchOpen ) ;
}
if ( ( settings . m_udpAddress ! = m_settings . m_udpAddress ) | |
( settings . m_udpPort ! = m_settings . m_udpPort ) | | force )
{
m_settingsMutex . lock ( ) ;
m_udpHandler . configureUDPLink ( settings . m_udpAddress , settings . m_udpPort ) ;
m_settingsMutex . unlock ( ) ;
}
if ( ( settings . m_channelMute ! = m_settings . m_channelMute ) | | force )
{
if ( ! settings . m_channelMute ) {
m_udpHandler . resetReadIndex ( ) ;
}
}
if ( ( settings . m_autoRWBalance ! = m_settings . m_autoRWBalance ) | | force )
{
m_settingsMutex . lock ( ) ;
m_udpHandler . setAutoRWBalance ( settings . m_autoRWBalance ) ;
if ( ! settings . m_autoRWBalance )
{
m_interpolatorDistanceRemain = 0 ;
m_interpolatorConsumed = false ;
2017-12-30 00:30:41 +01:00
m_interpolatorDistance = ( Real ) settings . m_inputSampleRate / ( Real ) m_outputSampleRate ;
2017-10-16 22:22:29 +02:00
m_interpolator . create ( 48 , settings . m_inputSampleRate , settings . m_rfBandwidth / 2.2 , 3.0 ) ;
m_actualInputSampleRate = settings . m_inputSampleRate ;
m_udpHandler . resetReadIndex ( ) ;
}
m_settingsMutex . unlock ( ) ;
}
m_settings = settings ;
}
2017-12-17 23:15:42 +01:00
QByteArray UDPSink : : serialize ( ) const
{
return m_settings . serialize ( ) ;
}
bool UDPSink : : deserialize ( const QByteArray & data )
{
if ( m_settings . deserialize ( data ) )
{
MsgConfigureUDPSink * msg = MsgConfigureUDPSink : : create ( m_settings , true ) ;
m_inputMessageQueue . push ( msg ) ;
return true ;
}
else
{
m_settings . resetToDefaults ( ) ;
MsgConfigureUDPSink * msg = MsgConfigureUDPSink : : create ( m_settings , true ) ;
m_inputMessageQueue . push ( msg ) ;
return false ;
}
}
2018-04-15 18:25:22 +02:00
int UDPSink : : webapiSettingsGet (
SWGSDRangel : : SWGChannelSettings & response ,
QString & errorMessage __attribute__ ( ( unused ) ) )
{
response . setUdpSinkSettings ( new SWGSDRangel : : SWGUDPSinkSettings ( ) ) ;
response . getUdpSinkSettings ( ) - > init ( ) ;
webapiFormatChannelSettings ( response , m_settings ) ;
return 200 ;
}
int UDPSink : : webapiSettingsPutPatch (
bool force ,
const QStringList & channelSettingsKeys ,
SWGSDRangel : : SWGChannelSettings & response ,
QString & errorMessage __attribute__ ( ( unused ) ) )
{
UDPSinkSettings settings ;
bool frequencyOffsetChanged = false ;
if ( channelSettingsKeys . contains ( " sampleFormat " ) ) {
settings . m_sampleFormat = ( UDPSinkSettings : : SampleFormat ) response . getUdpSinkSettings ( ) - > getSampleFormat ( ) ;
}
if ( channelSettingsKeys . contains ( " inputSampleRate " ) ) {
settings . m_inputSampleRate = response . getUdpSinkSettings ( ) - > getInputSampleRate ( ) ;
}
if ( channelSettingsKeys . contains ( " inputFrequencyOffset " ) )
{
settings . m_inputFrequencyOffset = response . getUdpSinkSettings ( ) - > getInputFrequencyOffset ( ) ;
frequencyOffsetChanged = true ;
}
if ( channelSettingsKeys . contains ( " rfBandwidth " ) ) {
settings . m_rfBandwidth = response . getUdpSinkSettings ( ) - > getRfBandwidth ( ) ;
}
if ( channelSettingsKeys . contains ( " lowCutoff " ) ) {
settings . m_lowCutoff = response . getUdpSinkSettings ( ) - > getLowCutoff ( ) ;
}
if ( channelSettingsKeys . contains ( " fmDeviation " ) ) {
settings . m_fmDeviation = response . getUdpSinkSettings ( ) - > getFmDeviation ( ) ;
}
if ( channelSettingsKeys . contains ( " amModFactor " ) ) {
settings . m_amModFactor = response . getUdpSinkSettings ( ) - > getAmModFactor ( ) ;
}
if ( channelSettingsKeys . contains ( " channelMute " ) ) {
settings . m_channelMute = response . getUdpSinkSettings ( ) - > getChannelMute ( ) ! = 0 ;
}
if ( channelSettingsKeys . contains ( " gainIn " ) ) {
settings . m_gainIn = response . getUdpSinkSettings ( ) - > getGainIn ( ) ;
}
if ( channelSettingsKeys . contains ( " gainOut " ) ) {
settings . m_gainOut = response . getUdpSinkSettings ( ) - > getGainOut ( ) ;
}
if ( channelSettingsKeys . contains ( " squelch " ) ) {
settings . m_squelch = response . getUdpSinkSettings ( ) - > getSquelch ( ) ;
}
if ( channelSettingsKeys . contains ( " squelchGate " ) ) {
settings . m_squelchGate = response . getUdpSinkSettings ( ) - > getSquelchGate ( ) ;
}
if ( channelSettingsKeys . contains ( " squelchEnabled " ) ) {
settings . m_squelchEnabled = response . getUdpSinkSettings ( ) - > getSquelchEnabled ( ) ! = 0 ;
}
if ( channelSettingsKeys . contains ( " autoRWBalance " ) ) {
settings . m_autoRWBalance = response . getUdpSinkSettings ( ) - > getAutoRwBalance ( ) ! = 0 ;
}
if ( channelSettingsKeys . contains ( " stereoInput " ) ) {
settings . m_stereoInput = response . getUdpSinkSettings ( ) - > getStereoInput ( ) ! = 0 ;
}
if ( channelSettingsKeys . contains ( " rgbColor " ) ) {
settings . m_rgbColor = response . getUdpSinkSettings ( ) - > getRgbColor ( ) ;
}
if ( channelSettingsKeys . contains ( " udpAddress " ) ) {
settings . m_udpAddress = * response . getUdpSinkSettings ( ) - > getUdpAddress ( ) ;
}
if ( channelSettingsKeys . contains ( " udpPort " ) ) {
settings . m_udpPort = response . getUdpSinkSettings ( ) - > getUdpPort ( ) ;
}
if ( channelSettingsKeys . contains ( " title " ) ) {
settings . m_title = * response . getUdpSinkSettings ( ) - > getTitle ( ) ;
}
if ( frequencyOffsetChanged )
{
UDPSink : : MsgConfigureChannelizer * msgChan = UDPSink : : MsgConfigureChannelizer : : create (
settings . m_inputSampleRate ,
settings . m_inputFrequencyOffset ) ;
m_inputMessageQueue . push ( msgChan ) ;
}
MsgConfigureUDPSink * msg = MsgConfigureUDPSink : : create ( settings , force ) ;
m_inputMessageQueue . push ( msg ) ;
if ( m_guiMessageQueue ) // forward to GUI if any
{
MsgConfigureUDPSink * msgToGUI = MsgConfigureUDPSink : : create ( settings , force ) ;
m_guiMessageQueue - > push ( msgToGUI ) ;
}
webapiFormatChannelSettings ( response , settings ) ;
return 200 ;
}
int UDPSink : : webapiReportGet (
SWGSDRangel : : SWGChannelReport & response ,
QString & errorMessage __attribute__ ( ( unused ) ) )
{
response . setUdpSinkReport ( new SWGSDRangel : : SWGUDPSinkReport ( ) ) ;
response . getUdpSinkReport ( ) - > init ( ) ;
webapiFormatChannelReport ( response ) ;
return 200 ;
}
void UDPSink : : webapiFormatChannelSettings ( SWGSDRangel : : SWGChannelSettings & response , const UDPSinkSettings & settings )
{
response . getUdpSinkSettings ( ) - > setSampleFormat ( ( int ) settings . m_sampleFormat ) ;
response . getUdpSinkSettings ( ) - > setInputSampleRate ( settings . m_inputSampleRate ) ;
response . getUdpSinkSettings ( ) - > setInputFrequencyOffset ( settings . m_inputFrequencyOffset ) ;
response . getUdpSinkSettings ( ) - > setRfBandwidth ( settings . m_rfBandwidth ) ;
response . getUdpSinkSettings ( ) - > setLowCutoff ( settings . m_lowCutoff ) ;
response . getUdpSinkSettings ( ) - > setFmDeviation ( settings . m_fmDeviation ) ;
response . getUdpSinkSettings ( ) - > setAmModFactor ( settings . m_amModFactor ) ;
response . getUdpSinkSettings ( ) - > setChannelMute ( settings . m_channelMute ? 1 : 0 ) ;
response . getUdpSinkSettings ( ) - > setGainIn ( settings . m_gainIn ) ;
response . getUdpSinkSettings ( ) - > setGainOut ( settings . m_gainOut ) ;
response . getUdpSinkSettings ( ) - > setSquelch ( settings . m_squelch ) ;
response . getUdpSinkSettings ( ) - > setSquelchGate ( settings . m_squelchGate ) ;
response . getUdpSinkSettings ( ) - > setSquelchEnabled ( settings . m_squelchEnabled ? 1 : 0 ) ;
response . getUdpSinkSettings ( ) - > setAutoRwBalance ( settings . m_autoRWBalance ? 1 : 0 ) ;
response . getUdpSinkSettings ( ) - > setStereoInput ( settings . m_stereoInput ? 1 : 0 ) ;
response . getUdpSinkSettings ( ) - > setRgbColor ( settings . m_rgbColor ) ;
if ( response . getUdpSinkSettings ( ) - > getUdpAddress ( ) ) {
* response . getUdpSinkSettings ( ) - > getUdpAddress ( ) = settings . m_udpAddress ;
} else {
response . getUdpSinkSettings ( ) - > setUdpAddress ( new QString ( settings . m_udpAddress ) ) ;
}
response . getUdpSinkSettings ( ) - > setUdpPort ( settings . m_udpPort ) ;
if ( response . getUdpSinkSettings ( ) - > getTitle ( ) ) {
* response . getUdpSinkSettings ( ) - > getTitle ( ) = settings . m_title ;
} else {
response . getUdpSinkSettings ( ) - > setTitle ( new QString ( settings . m_title ) ) ;
}
}
void UDPSink : : webapiFormatChannelReport ( SWGSDRangel : : SWGChannelReport & response )
{
response . getUdpSinkReport ( ) - > setChannelPowerDb ( CalcDb : : dbPower ( getMagSq ( ) ) ) ;
response . getUdpSinkReport ( ) - > setChannelSampleRate ( m_outputSampleRate ) ;
}