24 #include <QNetworkAccessManager> 25 #include <QNetworkReply> 51 static const double afSqTones[2] = {1000.0, 6000.0};
52 static const double afSqTones_lowrate[2] = {1000.0, 3500.0};
57 m_deviceAPI(devieAPI),
58 m_inputSampleRate(48000),
59 m_inputFrequencyOffset(0),
67 m_afSquelchOpen(false),
73 m_squelchDelayLine(24000),
75 m_settingsMutex(QMutex::Recursive)
77 qDebug(
"NFMDemod::NFMDemod");
121 Real coeff_2 = 3 * coeff_1;
122 Real abs_y = fabs(y) + 1e-10;
125 Real r = (x - abs_y) / (x + abs_y);
126 angle = coeff_1 - coeff_1 * r;
128 Real r = (x + abs_y) / (abs_y - x);
129 angle = coeff_2 - coeff_1 * r;
150 void NFMDemod::feed(
const SampleVector::const_iterator& begin,
const SampleVector::const_iterator& end,
bool firstOfBurst)
161 for (SampleVector::const_iterator it = begin; it != end; ++it)
163 Complex c(it->real(), it->imag());
365 qDebug() <<
"NFMDemod::start";
375 qDebug() <<
"NFMDemod::stop";
384 qDebug() <<
"NFMDemod::handleMessage: DownChannelizer::MsgChannelizerNotification";
394 qDebug() <<
"NFMDemod::handleMessage: MsgConfigureChannelizer:" 407 qDebug() <<
"NFMDemod::handleMessage: MsgConfigureNFMDemod";
417 qDebug(
"NFMDemod::handleMessage: BasebandSampleSink::MsgThreadedSink: %p", thread);
425 qDebug() <<
"NFMDemod::handleMessage: DSPConfigureAudio:" 426 <<
" sampleRate: " << sampleRate;
446 qDebug(
"NFMDemod::applyAudioSampleRate: %d", sampleRate);
464 if (sampleRate < 16000) {
485 qDebug() <<
"NFMDemod::applyChannelSettings:" 486 <<
" inputSampleRate: " << inputSampleRate
487 <<
" inputFrequencyOffset: " << inputFrequencyOffset;
510 qDebug() <<
"NFMDemod::applySettings:" 515 <<
" m_volume: " << settings.
m_volume 529 <<
" force: " << force;
531 QList<QString> reverseAPIKeys;
534 reverseAPIKeys.append(
"inputFrequencyOffset");
537 reverseAPIKeys.append(
"volume");
540 reverseAPIKeys.append(
"ctcssOn");
543 reverseAPIKeys.append(
"audioMute");
546 reverseAPIKeys.append(
"rgbColor");
549 reverseAPIKeys.append(
"title");
554 reverseAPIKeys.append(
"rfBandwidth");
564 reverseAPIKeys.append(
"fmDeviation");
570 reverseAPIKeys.append(
"afBandwidth");
579 reverseAPIKeys.append(
"squelchGate");
585 reverseAPIKeys.append(
"squelch");
588 reverseAPIKeys.append(
"deltaSquelch");
611 reverseAPIKeys.append(
"ctcssIndex");
616 reverseAPIKeys.append(
"highPass");
621 reverseAPIKeys.append(
"audioDeviceName");
673 QString& errorMessage)
684 const QStringList& channelSettingsKeys,
686 QString& errorMessage)
690 bool frequencyOffsetChanged =
false;
692 if (channelSettingsKeys.contains(
"afBandwidth")) {
695 if (channelSettingsKeys.contains(
"audioMute")) {
698 if (channelSettingsKeys.contains(
"highPass")) {
701 if (channelSettingsKeys.contains(
"ctcssIndex")) {
704 if (channelSettingsKeys.contains(
"ctcssOn")) {
707 if (channelSettingsKeys.contains(
"deltaSquelch")) {
710 if (channelSettingsKeys.contains(
"fmDeviation")) {
713 if (channelSettingsKeys.contains(
"inputFrequencyOffset"))
716 frequencyOffsetChanged =
true;
718 if (channelSettingsKeys.contains(
"rfBandwidth")) {
721 if (channelSettingsKeys.contains(
"rgbColor")) {
724 if (channelSettingsKeys.contains(
"squelch")) {
727 if (channelSettingsKeys.contains(
"squelchGate")) {
730 if (channelSettingsKeys.contains(
"title")) {
733 if (channelSettingsKeys.contains(
"volume")) {
736 if (channelSettingsKeys.contains(
"audioDeviceName")) {
739 if (channelSettingsKeys.contains(
"useReverseAPI")) {
742 if (channelSettingsKeys.contains(
"reverseAPIAddress")) {
745 if (channelSettingsKeys.contains(
"reverseAPIPort")) {
748 if (channelSettingsKeys.contains(
"reverseAPIDeviceIndex")) {
751 if (channelSettingsKeys.contains(
"reverseAPIChannelIndex")) {
755 if (frequencyOffsetChanged)
778 QString& errorMessage)
830 double magsqAvg, magsqPeak;
853 if (channelSettingsKeys.contains(
"afBandwidth") || force) {
856 if (channelSettingsKeys.contains(
"audioMute") || force) {
859 if (channelSettingsKeys.contains(
"highPass") || force) {
862 if (channelSettingsKeys.contains(
"ctcssIndex") || force) {
865 if (channelSettingsKeys.contains(
"ctcssOn") || force) {
868 if (channelSettingsKeys.contains(
"deltaSquelch") || force) {
871 if (channelSettingsKeys.contains(
"fmDeviation") || force) {
874 if (channelSettingsKeys.contains(
"inputFrequencyOffset") || force) {
877 if (channelSettingsKeys.contains(
"rfBandwidth") || force) {
880 if (channelSettingsKeys.contains(
"rgbColor") || force) {
883 if (channelSettingsKeys.contains(
"squelch") || force) {
886 if (channelSettingsKeys.contains(
"squelchGate") || force) {
889 if (channelSettingsKeys.contains(
"title") || force) {
892 if (channelSettingsKeys.contains(
"volume") || force) {
895 if (channelSettingsKeys.contains(
"audioDeviceName") || force) {
899 QString channelSettingsURL = QString(
"http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
905 m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader,
"application/json");
907 QBuffer *buffer=
new QBuffer();
908 buffer->open((QBuffer::ReadWrite));
909 buffer->write(swgChannelSettings->
asJson().toUtf8());
915 delete swgChannelSettings;
920 QNetworkReply::NetworkError replyError = reply->error();
924 qWarning() <<
"NFMDemod::networkManagerFinished:" 925 <<
" error(" << (int) replyError
926 <<
"): " << replyError
927 <<
": " << reply->errorString();
931 QString answer = reply->readAll();
933 qDebug(
"NFMDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
Real m_interpolatorDistanceRemain
void setOriginatorChannelIndex(qint32 originator_channel_index)
void addAudioSink(AudioFifo *audioFifo, MessageQueue *sampleSinkMessageQueue, int outputDeviceIndex=-1)
Add the audio sink.
const QThread * getThread() const
uint16_t m_reverseAPIPort
QNetworkRequest m_networkRequest
int getOutputSampleRate(int outputDeviceIndex=-1)
bool deserialize(const QByteArray &data)
void getMagSqLevels(double &avg, double &peak, int &nbSamples)
Complex nextIQ()
Return next complex sample.
void setCoefficients(int zN, int SampleRate)
bool decimate(Real *distance, const Complex &next, Complex *result)
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)
void setUseReverseApi(qint32 use_reverse_api)
float m_discriCompensation
compensation factor that depends on audio rate (1 for 48 kS/s)
PhaseDiscriminators m_phaseDiscri
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void setAfBandwidth(float af_bandwidth)
SWGNFMDemodSettings * getNfmDemodSettings()
const Real * getToneSet() const
void removeChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
void setChannelSampleRate(qint32 channel_sample_rate)
void create(int nTaps, double sampleRate, double lowCutoff, double highCutoff)
static double dbPower(double magsq, double floor=1e-12)
void addChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
void create(int phaseSteps, double sampleRate, double cutoff, double nbTapsPerPhase=4.5)
void processOneSample(Complex &ci)
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void setFMScaling(Real fmScaling)
bool interpolate(Real *distance, const Complex &next, Complex *result)
void create(int nTaps, double sampleRate, double cutoff)
int getDeviceSetIndex() const
qint32 getReverseApiPort()
int getOutputDeviceIndex(const QString &deviceName) const
MovingAverageUtil< Real, double, 32 > m_movingAverage
int getSampleRate() const
Real angleDist(Real a, Real b)
bool analyze(double sample)
qint32 getUseReverseApi()
void removeAudioSink(AudioFifo *audioFifo)
Remove the audio sink.
uint32_t m_audioSampleRate
ThreadedBasebandSampleSink * m_threadedChannelizer
virtual QByteArray serialize() const
qint64 getInputFrequencyOffset()
void setNfmDemodSettings(SWGNFMDemodSettings *nfm_demod_settings)
void setAudioMute(qint32 audio_mute)
void setAudioSampleRate(qint32 audio_sample_rate)
SWGNFMDemodReport * getNfmDemodReport()
void setSquelch(float squelch)
void setChannelType(QString *channel_type)
void setOriginatorDeviceSetIndex(qint32 originator_device_set_index)
void setSelectedCtcssIndex(int selectedCtcssIndex)
void setTitle(QString *title)
MessageQueue m_inputMessageQueue
Queue for asynchronous inbound communication.
virtual int webapiSettingsPutPatch(bool force, const QStringList &channelSettingsKeys, SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool po)
void write(const T &element)
void setHighPass(qint32 high_pass)
QString * getReverseApiAddress()
QString m_reverseAPIAddress
bool getDetectedTone(int &maxTone) const
Interpolator m_interpolator
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
static const QString m_channelIdURI
float arctan2(Real y, Real x)
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
QByteArray serialize() const
void setInputFrequencyOffset(qint64 input_frequency_offset)
static DSPEngine * instance()
void setVolume(float volume)
void setSquelchGate(qint32 squelch_gate)
uint16_t m_reverseAPIChannelIndex
QString m_audioDeviceName
static const int m_udpBlockSize
void setDeltaSquelch(qint32 delta_squelch)
Real m_interpolatorDistance
static bool match(const Message *message)
void setFreq(Real freq, Real sampleRate)
void removeChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Remove a channel sink (Rx)
void setReverseApiAddress(QString *reverse_api_address)
void setRfBandwidth(float rf_bandwidth)
Fixed< IntType, IntBits > sqrt(Fixed< IntType, IntBits > const &x)
Lowpass< Real > m_lowpass
void setDirection(qint32 direction)
MessageQueue * getMessageQueueToGUI()
virtual QString asJson() override
qint32 getReverseApiDeviceIndex()
uint16_t m_reverseAPIDeviceIndex
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport &response)
QNetworkAccessManager * m_networkManager
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings &response, const NFMDemodSettings &settings)
void setAudioDeviceName(QString *audio_device_name)
AudioDeviceManager * getAudioDeviceManager()
void addChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Add a channel sink (Rx)
Lowpass< Real > m_ctcssLowpass
void applyAudioSampleRate(int sampleRate)
bool setSize(uint32_t numSamples)
void applySettings(const NFMDemodSettings &settings, bool force=false)
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
void setRgbColor(qint32 rgb_color)
void networkManagerFinished(QNetworkReply *reply)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
void setSquelch(qint32 squelch)
NFMDemodSettings m_settings
void setNfmDemodReport(SWGNFMDemodReport *nfm_demod_report)
void setChannelPowerDb(float channel_power_db)
void setThreshold(double _threshold)
DownChannelizer * m_channelizer
void setCtcssTone(float ctcss_tone)
virtual int webapiReportGet(SWGSDRangel::SWGChannelReport &response, QString &errorMessage)
int32_t m_inputFrequencyOffset
AudioVector m_audioBuffer
int getIndexInDeviceSet() const
void webapiReverseSendSettings(QList< QString > &channelSettingsKeys, const NFMDemodSettings &settings, bool force)
virtual int webapiSettingsGet(SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
void setCtcssIndex(qint32 ctcss_index)
std::complex< Real > Complex
virtual bool deserialize(const QByteArray &data)
NFMDemod(DeviceAPI *deviceAPI)
qint32 getReverseApiChannelIndex()
CTCSSDetector m_ctcssDetector
qint64 getFrequencyOffset() const
Real phaseDiscriminatorDelta(const Complex &sample, double &magsq, Real &fmDev)
QString * getAudioDeviceName()
Bandpass< Real > m_bandpass
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force=false)
static const QString m_channelId
DoubleBufferFIFO< Real > m_squelchDelayLine
void setCtcssOn(qint32 ctcss_on)
int m_inputFrequencyOffset
uint32_t write(const quint8 *data, uint32_t numSamples)
void setReverseApiPort(qint32 reverse_api_port)
void setFmDeviation(qint32 fm_deviation)
bool analyze(Real *sample)
void setCoefficients(unsigned int N, unsigned int nbAvg, unsigned int sampleRate, unsigned int samplesAttack, unsigned int samplesDecay, const double *tones)
center frequency of tones tested
void setReverseApiChannelIndex(qint32 reverse_api_channel_index)
static MsgReportCTCSSFreq * create(Real freq)