2022-06-06 21:22:18 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Copyright (C) 2022 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 //
|
|
|
|
// (at your option) any later version. //
|
|
|
|
// //
|
|
|
|
// This program is distributed in the hope that it will be useful, //
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
|
|
// GNU General Public License V3 for more details. //
|
|
|
|
// //
|
|
|
|
// You should have received a copy of the GNU General Public License //
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#ifndef INCLUDE_M17DEMODPROCESSOR_H
|
|
|
|
#define INCLUDE_M17DEMODPROCESSOR_H
|
|
|
|
|
|
|
|
#include <QObject>
|
|
|
|
|
|
|
|
#include "audio/audiocompressor.h"
|
2022-07-19 23:47:48 -04:00
|
|
|
#include "M17Demodulator.h"
|
2022-06-06 21:22:18 -04:00
|
|
|
#include "m17demodfilters.h"
|
|
|
|
|
|
|
|
class AudioFifo;
|
2022-06-19 00:39:05 -04:00
|
|
|
class MessageQueue;
|
2022-06-06 21:22:18 -04:00
|
|
|
|
|
|
|
class M17DemodProcessor : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
2022-06-08 22:49:41 -04:00
|
|
|
enum StdPacketProtocol
|
|
|
|
{
|
|
|
|
StdPacketRaw,
|
|
|
|
StdPacketAX25,
|
|
|
|
StdPacketAPRS,
|
|
|
|
StdPacket6LoWPAN,
|
|
|
|
StdPacketIPv4,
|
|
|
|
StdPacketSMS,
|
|
|
|
StdPacketWinlink,
|
|
|
|
StdPacketUnknown
|
|
|
|
};
|
|
|
|
|
2022-06-06 21:22:18 -04:00
|
|
|
M17DemodProcessor();
|
|
|
|
~M17DemodProcessor();
|
|
|
|
|
2022-06-19 00:39:05 -04:00
|
|
|
void setDemodInputMessageQueue(MessageQueue *messageQueue) { m_demodInputMessageQueue = messageQueue; }
|
2022-06-06 21:22:18 -04:00
|
|
|
void pushSample(qint16 sample);
|
|
|
|
void setDisplayLSF(bool displayLSF) { m_displayLSF = displayLSF; }
|
|
|
|
void setNoiseBlanker(bool noiseBlanker) { m_noiseBlanker = noiseBlanker; }
|
|
|
|
void setAudioFifo(AudioFifo *fifo) { m_audioFifo = fifo; }
|
|
|
|
void setAudioMute(bool mute) { m_audioMute = mute; }
|
|
|
|
void setUpsampling(int upsampling);
|
|
|
|
void setVolume(float volume);
|
|
|
|
void setHP(bool useHP) { m_upsamplingFilter.useHP(useHP); }
|
|
|
|
void resetInfo();
|
|
|
|
void setDCDOff();
|
|
|
|
uint32_t getLSFCount() const { return m_lsfCount; }
|
|
|
|
const QString& getSrcCall() const { return m_srcCall; }
|
|
|
|
const QString& getDestcCall() const { return m_destCall; }
|
|
|
|
const QString& getTypeInfo() const { return m_typeInfo; }
|
2022-07-15 21:48:33 -04:00
|
|
|
const std::array<uint8_t, 14>& getMeta() const { return m_metadata; }
|
|
|
|
bool getHasGNSS() const { return m_hasGNSS; }
|
2022-06-08 22:49:41 -04:00
|
|
|
bool getStreamElsePacket() const { return m_streamElsePacket; }
|
2022-06-06 21:22:18 -04:00
|
|
|
uint16_t getCRC() const { return m_crc; }
|
2022-06-08 22:49:41 -04:00
|
|
|
StdPacketProtocol getStdPacketProtocol() const;
|
2022-06-06 21:22:18 -04:00
|
|
|
|
|
|
|
void getDiagnostics(
|
|
|
|
bool& dcd,
|
|
|
|
float& evm,
|
|
|
|
float& deviation,
|
|
|
|
float& offset,
|
|
|
|
int& status,
|
2022-07-06 01:01:42 -04:00
|
|
|
int& sync_word_type,
|
2022-06-06 21:22:18 -04:00
|
|
|
float& clock,
|
|
|
|
int& sampleIndex,
|
|
|
|
int& syncIndex,
|
|
|
|
int& clockIndex,
|
|
|
|
int& viterbiCost
|
|
|
|
) const
|
|
|
|
{
|
|
|
|
dcd = m_dcd;
|
|
|
|
evm = m_evm;
|
|
|
|
deviation = m_deviation;
|
|
|
|
offset = m_offset;
|
|
|
|
status = m_status;
|
2022-07-06 01:01:42 -04:00
|
|
|
sync_word_type = m_syncWordType;
|
2022-06-06 21:22:18 -04:00
|
|
|
clock = m_clock;
|
|
|
|
sampleIndex = m_sampleIndex;
|
|
|
|
syncIndex = m_syncIndex;
|
|
|
|
clockIndex = m_clockIndex;
|
|
|
|
viterbiCost = m_viterbiCost;
|
|
|
|
}
|
|
|
|
|
2022-07-06 21:19:01 -04:00
|
|
|
void getBERT(uint32_t& bertErrors, uint32_t& bertBits)
|
|
|
|
{
|
|
|
|
bertErrors = m_prbs.errors();
|
|
|
|
bertBits = m_prbs.bits();
|
|
|
|
}
|
|
|
|
|
2022-07-09 04:56:16 -04:00
|
|
|
void resetPRBS() {
|
|
|
|
m_prbs.reset();
|
|
|
|
}
|
|
|
|
|
2022-06-06 21:22:18 -04:00
|
|
|
private:
|
|
|
|
std::vector<uint8_t> m_currentPacket;
|
|
|
|
size_t m_packetFrameCounter;
|
2022-07-04 17:03:07 -04:00
|
|
|
modemm17::PRBS9 m_prbs;
|
2022-06-06 21:22:18 -04:00
|
|
|
bool m_displayLSF;
|
|
|
|
bool m_noiseBlanker;
|
|
|
|
struct CODEC2 *m_codec2;
|
|
|
|
static M17DemodProcessor *m_this;
|
2022-07-04 17:03:07 -04:00
|
|
|
modemm17::M17Demodulator m_demod;
|
2022-06-06 21:22:18 -04:00
|
|
|
AudioFifo *m_audioFifo;
|
|
|
|
bool m_audioMute;
|
|
|
|
AudioVector m_audioBuffer;
|
|
|
|
uint m_audioBufferFill;
|
|
|
|
float m_volume;
|
|
|
|
int m_upsampling; //!< upsampling factor
|
|
|
|
float m_upsamplingFactors[7];
|
|
|
|
AudioCompressor m_compressor;
|
|
|
|
float m_upsamplerLastValue;
|
|
|
|
|
|
|
|
M17DemodAudioInterpolatorFilter m_upsamplingFilter;
|
|
|
|
|
|
|
|
// Diagnostics
|
2022-07-06 01:01:42 -04:00
|
|
|
bool m_dcd; //!< Data Carrier Detect
|
|
|
|
float m_evm; //!< Error Vector Magnitude in percent
|
|
|
|
float m_deviation; //!< Estimated deviation. Ideal = 1.0
|
|
|
|
float m_offset; //!< Estimated frequency offset. Ideal = 0.0 practically limited to ~[-0.18, 0.18]
|
|
|
|
int m_status; //!< Status
|
|
|
|
int m_syncWordType; //!< Sync word type
|
2022-06-06 21:22:18 -04:00
|
|
|
float m_clock;
|
|
|
|
int m_sampleIndex;
|
|
|
|
int m_syncIndex;
|
|
|
|
int m_clockIndex;
|
2022-07-06 01:01:42 -04:00
|
|
|
int m_viterbiCost; //!< [-1:128] ideally 0
|
2022-06-06 21:22:18 -04:00
|
|
|
|
|
|
|
QString m_srcCall;
|
|
|
|
QString m_destCall;
|
|
|
|
QString m_typeInfo;
|
2022-06-08 22:49:41 -04:00
|
|
|
bool m_streamElsePacket;
|
2022-06-06 21:22:18 -04:00
|
|
|
std::array<uint8_t, 14> m_metadata;
|
2022-07-15 21:48:33 -04:00
|
|
|
bool m_hasGNSS;
|
2022-06-06 21:22:18 -04:00
|
|
|
uint16_t m_crc;
|
|
|
|
uint32_t m_lsfCount; // Incremented each time a new LSF is decoded. Reset when lock is lost.
|
2022-06-08 22:49:41 -04:00
|
|
|
StdPacketProtocol m_stdPacketProtocol;
|
2022-06-06 21:22:18 -04:00
|
|
|
|
2022-06-19 00:39:05 -04:00
|
|
|
MessageQueue *m_demodInputMessageQueue;
|
|
|
|
|
2022-07-04 17:03:07 -04:00
|
|
|
static bool handle_frame(modemm17::M17FrameDecoder::output_buffer_t const& frame, int viterbi_cost);
|
2022-06-06 21:22:18 -04:00
|
|
|
static void diagnostic_callback(
|
|
|
|
bool dcd,
|
|
|
|
float evm,
|
|
|
|
float deviation,
|
|
|
|
float offset,
|
|
|
|
int status,
|
2022-07-06 01:01:42 -04:00
|
|
|
int sync_word_type,
|
2022-06-06 21:22:18 -04:00
|
|
|
float clock,
|
|
|
|
int sample_index,
|
|
|
|
int sync_index,
|
|
|
|
int clock_index,
|
|
|
|
int viterbi_cost
|
|
|
|
);
|
2022-07-04 17:03:07 -04:00
|
|
|
bool decode_lsf(modemm17::M17FrameDecoder::lsf_buffer_t const& lsf);
|
|
|
|
bool decode_lich(modemm17::M17FrameDecoder::lich_buffer_t const& lich);
|
|
|
|
bool decode_packet(modemm17::M17FrameDecoder::packet_buffer_t const& packet_segment);
|
|
|
|
bool decode_bert(modemm17::M17FrameDecoder::bert_buffer_t const& bert);
|
|
|
|
bool demodulate_audio(modemm17::M17FrameDecoder::audio_buffer_t const& audio, int viterbi_cost);
|
2022-06-06 21:22:18 -04:00
|
|
|
void decode_type(uint16_t type);
|
2022-07-04 17:03:07 -04:00
|
|
|
void append_packet(std::vector<uint8_t>& result, modemm17::M17FrameDecoder::lsf_buffer_t in);
|
2022-06-06 21:22:18 -04:00
|
|
|
|
|
|
|
void processAudio(const std::array<int16_t, 160>& in);
|
|
|
|
void upsample(int upsampling, const int16_t *in, int nbSamplesIn);
|
|
|
|
void noUpsample(const int16_t *in, int nbSamplesIn);
|
|
|
|
|
|
|
|
void setVolumeFactors();
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // INCLUDE_M17PROCESSOR_H
|