2017-08-13 19:39:26 -04: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 12:25:22 -04:00
# include "SWGChannelSettings.h"
# include "SWGChannelReport.h"
# include "SWGUDPSinkReport.h"
2017-10-17 17:45:57 -04:00
# include "device/devicesinkapi.h"
2017-08-13 19:39:26 -04:00
# include "dsp/upchannelizer.h"
2017-10-17 17:45:57 -04:00
# include "dsp/threadedbasebandsamplesource.h"
2018-02-14 14:11:36 -05:00
# include "dsp/dspcommands.h"
2017-08-16 22:23:36 -04:00
# include "util/db.h"
2017-10-17 17:45:57 -04:00
2017-08-15 22:00:33 -04:00
# include "udpsinkmsg.h"
2017-08-13 19:39:26 -04:00
# include "udpsink.h"
2017-10-16 16:22:29 -04:00
MESSAGE_CLASS_DEFINITION ( UDPSink : : MsgConfigureUDPSink , Message )
MESSAGE_CLASS_DEFINITION ( UDPSink : : MsgConfigureChannelizer , Message )
2017-08-14 10:09:56 -04:00
MESSAGE_CLASS_DEFINITION ( UDPSink : : MsgUDPSinkSpectrum , Message )
2017-08-18 11:51:11 -04:00
MESSAGE_CLASS_DEFINITION ( UDPSink : : MsgResetReadIndex , Message )
2017-08-13 19:39:26 -04:00
2017-11-22 19:19:32 -05:00
const QString UDPSink : : m_channelIdURI = " sdrangel.channeltx.udpsink " ;
const QString UDPSink : : m_channelId = " UDPSink " ;
2017-11-08 11:09:25 -05:00
UDPSink : : UDPSink ( DeviceSinkAPI * deviceAPI ) :
2017-12-20 17:57:06 -05:00
ChannelSourceAPI ( m_channelIdURI ) ,
2017-10-17 15:08:54 -04:00
m_deviceAPI ( deviceAPI ) ,
2017-12-29 18:30:41 -05:00
m_basebandSampleRate ( 48000 ) ,
2017-12-30 04:17:30 -05:00
m_outputSampleRate ( 48000 ) ,
2017-12-29 18:30:41 -05:00
m_inputFrequencyOffset ( 0 ) ,
2017-10-16 18:14:06 -04:00
m_squelch ( 1e-6 ) ,
2017-11-08 11:09:25 -05:00
m_spectrum ( 0 ) ,
2017-08-16 16:49:19 -04:00
m_spectrumEnabled ( false ) ,
2017-08-16 17:37:01 -04:00
m_spectrumChunkSize ( 2160 ) ,
2017-08-16 16:49:19 -04:00
m_spectrumChunkCounter ( 0 ) ,
2017-08-14 16:50:28 -04:00
m_magsq ( 1e-10 ) ,
2017-08-16 22:23:36 -04:00
m_movingAverage ( 16 , 1e-10 ) ,
m_inMovingAverage ( 480 , 1e-10 ) ,
2017-08-16 10:09:35 -04:00
m_sampleRateSum ( 0 ) ,
m_sampleRateAvgCounter ( 0 ) ,
2017-08-16 17:37:01 -04:00
m_levelCalcCount ( 0 ) ,
m_peakLevel ( 0.0f ) ,
m_levelSum ( 0.0f ) ,
m_levelNbSamples ( 480 ) ,
2017-08-16 22:23:36 -04:00
m_squelchOpen ( false ) ,
m_squelchOpenCount ( 0 ) ,
m_squelchCloseCount ( 0 ) ,
m_squelchThreshold ( 4800 ) ,
2017-08-18 06:30:51 -04:00
m_modPhasor ( 0.0f ) ,
2017-08-18 21:42:56 -04:00
m_SSBFilterBufferIndex ( 0 ) ,
2017-08-13 19:39:26 -04:00
m_settingsMutex ( QMutex : : Recursive )
{
2017-11-22 19:19:32 -05:00
setObjectName ( m_channelId ) ;
2017-10-17 17:45:57 -04:00
2017-11-05 19:39:44 -05: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 05:26:49 -04:00
applyChannelSettings ( m_basebandSampleRate , m_outputSampleRate , m_inputFrequencyOffset , true ) ;
applySettings ( m_settings , true ) ;
2017-10-17 17:45:57 -04:00
m_channelizer = new UpChannelizer ( this ) ;
m_threadedChannelizer = new ThreadedBasebandSampleSource ( m_channelizer , this ) ;
m_deviceAPI - > addThreadedSource ( m_threadedChannelizer ) ;
2017-11-19 13:33:20 -05:00
m_deviceAPI - > addChannelAPI ( this ) ;
2017-08-13 19:39:26 -04:00
}
UDPSink : : ~ UDPSink ( )
{
2017-11-19 13:33:20 -05:00
m_deviceAPI - > removeChannelAPI ( this ) ;
2017-10-17 17:45:57 -04:00
m_deviceAPI - > removeThreadedSource ( m_threadedChannelizer ) ;
delete m_threadedChannelizer ;
delete m_channelizer ;
2018-04-18 16:20:47 -04:00
delete m_SSBFilter ;
delete [ ] m_SSBFilterBuffer ;
2017-08-13 19:39:26 -04:00
}
void UDPSink : : start ( )
{
2017-08-15 14:23:49 -04:00
m_udpHandler . start ( ) ;
2018-01-08 19:10:49 -05:00
applyChannelSettings ( m_basebandSampleRate , m_outputSampleRate , m_inputFrequencyOffset , true ) ;
2017-08-13 19:39:26 -04:00
}
void UDPSink : : stop ( )
{
2017-08-15 14:23:49 -04:00
m_udpHandler . stop ( ) ;
2017-08-13 19:39:26 -04:00
}
void UDPSink : : pull ( Sample & sample )
{
2017-10-16 18:14:06 -04:00
if ( m_settings . m_channelMute )
2017-08-14 04:59:05 -04:00
{
sample . m_real = 0.0f ;
sample . m_imag = 0.0f ;
2017-08-16 22:23:36 -04:00
initSquelch ( false ) ;
2017-08-14 04:59:05 -04: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-16 22:23:36 -04:00
double magsq = ci . real ( ) * ci . real ( ) + ci . imag ( ) * ci . imag ( ) ;
2018-01-22 02:46:05 -05:00
magsq / = ( SDR_TX_SCALED * SDR_TX_SCALED ) ;
2017-08-14 16:50:28 -04:00
m_movingAverage . feed ( magsq ) ;
m_magsq = m_movingAverage . average ( ) ;
2017-08-14 04:59:05 -04:00
sample . m_real = ( FixReal ) ci . real ( ) ;
sample . m_imag = ( FixReal ) ci . imag ( ) ;
}
void UDPSink : : modulateSample ( )
{
2018-04-18 18:52:01 -04:00
if ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatSnLE ) // Linear I/Q transponding
2017-08-15 14:23:49 -04:00
{
2017-08-18 06:30:51 -04:00
Sample s ;
2017-08-15 14:23:49 -04:00
m_udpHandler . readSample ( s ) ;
2017-08-16 22:23:36 -04:00
uint64_t magsq = s . m_real * s . m_real + s . m_imag * s . m_imag ;
2018-01-22 02:46:05 -05:00
m_inMovingAverage . feed ( magsq / ( SDR_TX_SCALED * SDR_TX_SCALED ) ) ;
2017-08-16 22:23:36 -04:00
m_inMagsq = m_inMovingAverage . average ( ) ;
calculateSquelch ( m_inMagsq ) ;
if ( m_squelchOpen )
{
2017-10-16 18:14:06 -04:00
m_modSample . real ( s . m_real * m_settings . m_gainOut ) ;
m_modSample . imag ( s . m_imag * m_settings . m_gainOut ) ;
2017-08-16 22:23:36 -04:00
calculateLevel ( m_modSample ) ;
}
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
}
2017-08-15 14:23:49 -04:00
}
2017-10-16 18:14:06 -04:00
else if ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatNFM )
2017-08-18 06:30:51 -04:00
{
2018-04-18 18:43:29 -04:00
qint16 t ;
2017-08-25 04:32:18 -04:00
readMonoSample ( t ) ;
2017-08-18 06:30:51 -04:00
m_inMovingAverage . feed ( ( t * t ) / 1073741824.0 ) ;
m_inMagsq = m_inMovingAverage . average ( ) ;
calculateSquelch ( m_inMagsq ) ;
if ( m_squelchOpen )
{
2018-01-22 02:46:05 -05: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 16:15:04 -04:00
calculateLevel ( m_modSample ) ;
2017-08-18 06:30:51 -04:00
}
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
}
}
2017-10-16 18:14:06 -04:00
else if ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatAM )
2017-08-18 19:46:52 -04:00
{
2018-04-18 18:43:29 -04:00
qint16 t ;
2017-08-25 04:32:18 -04:00
readMonoSample ( t ) ;
2018-01-22 02:46:05 -05:00
m_inMovingAverage . feed ( ( t * t ) / ( SDR_TX_SCALED * SDR_TX_SCALED ) ) ;
2017-08-18 19:46:52 -04:00
m_inMagsq = m_inMovingAverage . average ( ) ;
calculateSquelch ( m_inMagsq ) ;
if ( m_squelchOpen )
{
2018-01-22 02:46:05 -05: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-18 19:46:52 -04:00
m_modSample . imag ( 0.0f ) ;
calculateLevel ( m_modSample ) ;
}
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
}
}
2017-10-16 18:14:06 -04:00
else if ( ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatLSB ) | | ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatUSB ) )
2017-08-18 21:42:56 -04:00
{
2018-04-18 18:43:29 -04:00
qint16 t ;
2017-08-18 21:42:56 -04:00
Complex c , ci ;
fftfilt : : cmplx * filtered ;
int n_out = 0 ;
2017-08-25 04:32:18 -04:00
readMonoSample ( t ) ;
2018-01-22 02:46:05 -05:00
m_inMovingAverage . feed ( ( t * t ) / ( SDR_TX_SCALED * SDR_TX_SCALED ) ) ;
2017-08-18 21:42:56 -04:00
m_inMagsq = m_inMovingAverage . average ( ) ;
calculateSquelch ( m_inMagsq ) ;
if ( m_squelchOpen )
{
2018-01-22 02:46:05 -05:00
ci . real ( ( t / SDR_TX_SCALEF ) * m_settings . m_gainOut ) ;
2017-08-18 21:42:56 -04:00
ci . imag ( 0.0f ) ;
2017-10-16 18:14:06 -04:00
n_out = m_SSBFilter - > runSSB ( ci , & filtered , ( m_settings . m_sampleFormat = = UDPSinkSettings : : FormatUSB ) ) ;
2017-08-19 03:28:50 -04:00
if ( n_out > 0 )
2017-08-18 21:42:56 -04:00
{
memcpy ( ( void * ) m_SSBFilterBuffer , ( const void * ) filtered , n_out * sizeof ( Complex ) ) ;
m_SSBFilterBufferIndex = 0 ;
}
c = m_SSBFilterBuffer [ m_SSBFilterBufferIndex ] ;
2018-01-22 02:46:05 -05: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-18 21:42:56 -04:00
m_SSBFilterBufferIndex + + ;
calculateLevel ( m_modSample ) ;
}
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
}
}
2017-08-15 14:23:49 -04:00
else
{
m_modSample . real ( 0.0f ) ;
m_modSample . imag ( 0.0f ) ;
2017-08-16 22:23:36 -04:00
initSquelch ( false ) ;
2017-08-15 14:23:49 -04:00
}
2017-08-16 16:49:19 -04: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 11:09:25 -05:00
else if ( m_spectrum )
2017-08-16 16:49:19 -04:00
{
m_spectrum - > feed ( m_sampleBuffer . begin ( ) , m_sampleBuffer . end ( ) , false ) ;
m_sampleBuffer . clear ( ) ;
m_spectrumChunkCounter = 0 ;
}
2017-08-13 19:39:26 -04:00
}
2017-08-16 17:37:01 -04: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-16 22:23:36 -04:00
qreal rmsLevel = m_levelSum > 0.0 ? sqrt ( m_levelSum / m_levelNbSamples ) : 0.0 ;
2017-08-16 17:37:01 -04: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 02:46:05 -05: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 17:37:01 -04:00
m_peakLevel = 0.0f ;
m_levelSum = 0.0f ;
m_levelCalcCount = 0 ;
}
}
2017-08-13 19:39:26 -04:00
bool UDPSink : : handleMessage ( const Message & cmd )
{
if ( UpChannelizer : : MsgChannelizerNotification : : match ( cmd ) )
{
UpChannelizer : : MsgChannelizerNotification & notif = ( UpChannelizer : : MsgChannelizerNotification & ) cmd ;
2017-12-29 18:30:41 -05:00
qDebug ( ) < < " UDPSink::handleMessage: MsgChannelizerNotification " ;
2017-08-13 19:39:26 -04:00
2017-12-29 18:30:41 -05:00
applyChannelSettings ( notif . getBasebandSampleRate ( ) , notif . getSampleRate ( ) , notif . getFrequencyOffset ( ) ) ;
2017-08-13 19:39:26 -04:00
return true ;
}
2017-10-16 17:04:53 -04:00
else if ( MsgConfigureChannelizer : : match ( cmd ) )
{
MsgConfigureChannelizer & cfg = ( MsgConfigureChannelizer & ) cmd ;
2017-12-29 18:30:41 -05:00
qDebug ( ) < < " UDPSink::handleMessage: MsgConfigureChannelizer: "
< < " sampleRate: " < < cfg . getSampleRate ( )
< < " centerFrequency: " < < cfg . getCenterFrequency ( ) ;
2017-10-16 17:04:53 -04:00
2017-10-17 17:45:57 -04:00
m_channelizer - > configure ( m_channelizer - > getInputMessageQueue ( ) ,
cfg . getSampleRate ( ) ,
cfg . getCenterFrequency ( ) ) ;
2017-10-16 17:04:53 -04:00
return true ;
}
else if ( MsgConfigureUDPSink : : match ( cmd ) )
{
MsgConfigureUDPSink & cfg = ( MsgConfigureUDPSink & ) cmd ;
2017-12-29 18:30:41 -05:00
qDebug ( ) < < " UDPSink::handleMessage: MsgConfigureUDPSink " ;
2017-10-16 17:04:53 -04:00
2017-12-29 18:30:41 -05:00
applySettings ( cfg . getSettings ( ) , cfg . getForce ( ) ) ;
2017-10-16 17:04:53 -04:00
return true ;
}
2017-08-15 22:00:33 -04:00
else if ( UDPSinkMessages : : MsgSampleRateCorrection : : match ( cmd ) )
{
2017-08-16 05:35:47 -04:00
UDPSinkMessages : : MsgSampleRateCorrection & cfg = ( UDPSinkMessages : : MsgSampleRateCorrection & ) cmd ;
2017-08-16 16:49:19 -04:00
Real newSampleRate = m_actualInputSampleRate + cfg . getCorrectionFactor ( ) * m_actualInputSampleRate ;
2017-08-16 10:09:35 -04:00
2017-08-16 16:49:19 -04:00
// exclude values too way out nominal sample rate (20%)
2017-10-16 18:14:06 -04:00
if ( ( newSampleRate < m_settings . m_inputSampleRate * 1.2 ) & & ( newSampleRate > m_settings . m_inputSampleRate * 0.8 ) )
2017-08-16 10:09:35 -04:00
{
2017-08-16 16:49:19 -04:00
m_actualInputSampleRate = newSampleRate ;
2017-12-28 21:22:04 -05:00
if ( ( cfg . getRawDeltaRatio ( ) > - 0.05 ) & & ( cfg . getRawDeltaRatio ( ) < 0.05 ) )
2017-08-16 10:09:35 -04:00
{
2017-08-16 16:49:19 -04:00
if ( m_sampleRateAvgCounter < m_sampleRateAverageItems )
{
m_sampleRateSum + = m_actualInputSampleRate ;
m_sampleRateAvgCounter + + ;
}
}
else
{
m_sampleRateSum = 0.0 ;
m_sampleRateAvgCounter = 0 ;
2017-08-16 10:09:35 -04:00
}
2017-08-16 16:49:19 -04: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-16 19:03:09 -04:00
// else
// {
// qDebug("UDPSink::handleMessage: MsgSampleRateCorrection: corr: %+.6f new rate: %.0f",
// cfg.getCorrectionFactor(),
// m_actualInputSampleRate);
// }
2017-08-16 16:49:19 -04:00
m_settingsMutex . lock ( ) ;
m_interpolatorDistanceRemain = 0 ;
m_interpolatorConsumed = false ;
2017-12-29 18:30:41 -05:00
m_interpolatorDistance = ( Real ) m_actualInputSampleRate / ( Real ) m_outputSampleRate ;
2017-10-16 18:14:06 -04:00
//m_interpolator.create(48, m_actualInputSampleRate, m_settings.m_rfBandwidth / 2.2, 3.0); // causes clicking: leaving at standard frequency
2017-08-16 16:49:19 -04:00
m_settingsMutex . unlock ( ) ;
2017-08-16 10:09:35 -04:00
}
2017-08-16 05:35:47 -04:00
2017-08-16 16:49:19 -04: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 05:35:47 -04:00
2017-08-15 22:00:33 -04:00
return true ;
}
2017-08-18 11:51:11 -04:00
else if ( MsgResetReadIndex : : match ( cmd ) )
{
m_settingsMutex . lock ( ) ;
m_udpHandler . resetReadIndex ( ) ;
m_settingsMutex . unlock ( ) ;
qDebug ( ) < < " UDPSink::handleMessage: MsgResetReadIndex " ;
return true ;
}
2018-02-14 14:11:36 -05:00
else if ( DSPSignalNotification : : match ( cmd ) )
{
return true ;
}
2017-08-13 19:39:26 -04:00
else
{
2017-08-16 16:49:19 -04:00
if ( m_spectrum ! = 0 )
{
return m_spectrum - > handleMessage ( cmd ) ;
}
else
{
return false ;
}
2017-08-13 19:39:26 -04:00
}
}
2017-10-17 03:02:33 -04:00
void UDPSink : : setSpectrum ( bool enabled )
2017-08-14 10:09:56 -04:00
{
Message * cmd = MsgUDPSinkSpectrum : : create ( enabled ) ;
2017-10-17 03:02:33 -04:00
getInputMessageQueue ( ) - > push ( cmd ) ;
2017-08-14 10:09:56 -04:00
}
2017-10-17 03:02:33 -04:00
void UDPSink : : resetReadIndex ( )
2017-08-18 11:51:11 -04:00
{
Message * cmd = MsgResetReadIndex : : create ( ) ;
2017-10-17 03:02:33 -04:00
getInputMessageQueue ( ) - > push ( cmd ) ;
2017-08-18 11:51:11 -04:00
}
2018-01-08 19:10:49 -05:00
void UDPSink : : applyChannelSettings ( int basebandSampleRate , int outputSampleRate , int inputFrequencyOffset , bool force )
2017-10-16 16:22:29 -04:00
{
2017-12-29 18:30:41 -05:00
qDebug ( ) < < " UDPSink::applyChannelSettings: "
< < " basebandSampleRate: " < < basebandSampleRate
< < " outputSampleRate: " < < outputSampleRate
< < " inputFrequencyOffset: " < < inputFrequencyOffset ;
if ( ( inputFrequencyOffset ! = m_inputFrequencyOffset ) | |
2018-01-08 19:10:49 -05:00
( outputSampleRate ! = m_outputSampleRate ) | | force )
2017-10-16 16:22:29 -04:00
{
m_settingsMutex . lock ( ) ;
2017-12-29 18:30:41 -05:00
m_carrierNco . setFreq ( inputFrequencyOffset , outputSampleRate ) ;
2017-10-16 16:22:29 -04:00
m_settingsMutex . unlock ( ) ;
}
2018-01-08 19:10:49 -05:00
if ( ( ( outputSampleRate ! = m_outputSampleRate ) & & ( ! m_settings . m_autoRWBalance ) ) | | force )
2017-12-29 18:30:41 -05: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 16:22:29 -04:00
( settings . m_inputSampleRate ! = m_settings . m_inputSampleRate ) | | force )
{
m_settingsMutex . lock ( ) ;
m_interpolatorDistanceRemain = 0 ;
m_interpolatorConsumed = false ;
2017-12-29 18:30:41 -05:00
m_interpolatorDistance = ( Real ) settings . m_inputSampleRate / ( Real ) m_outputSampleRate ;
2017-10-16 16:22:29 -04: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-16 18:14:06 -04:00
if ( ( settings . m_squelch ! = m_settings . m_squelch ) | | force )
{
m_squelch = CalcDb : : powerFromdB ( settings . m_squelch ) ;
}
2017-10-16 16:22:29 -04:00
if ( ( settings . m_squelchGate ! = m_settings . m_squelchGate ) | | force )
{
2017-12-29 18:30:41 -05:00
m_squelchThreshold = m_outputSampleRate * settings . m_squelchGate ;
2017-10-16 16:22:29 -04: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-29 18:30:41 -05:00
m_interpolatorDistance = ( Real ) settings . m_inputSampleRate / ( Real ) m_outputSampleRate ;
2017-10-16 16:22:29 -04: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 17:15:42 -05: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 12:25:22 -04: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 ( " 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 ) ;
}