Implemented unpacking and decoding of M17 audio stream frames

This commit is contained in:
Silvano Seva 2022-04-10 09:47:00 +02:00
parent a37e24c953
commit da5c453852
22 changed files with 221 additions and 130 deletions

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* 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 *
@ -28,6 +28,9 @@
#include <string>
#include "M17Datatypes.h"
namespace M17
{
/**
* Encode a callsign in base-40 format, starting with the right-most character.
* The final value is written out in "big-endian" form, with the most-significant
@ -52,4 +55,6 @@ bool encode_callsign(const std::string& callsign, call_t& encodedCall,
*/
std::string decode_callsign(const call_t& encodedCall);
#endif /* M17_CALLSIGN_H */
} // namespace M17
#endif // M17_CALLSIGN_H

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* Adapted from original code written by Rob Riggs, Mobilinkd LLC *
* *
@ -30,6 +30,8 @@
#include <experimental/array>
#include "M17Utils.h"
namespace M17
{
/**
* Puncture matrix for linx setup frame.
@ -117,5 +119,6 @@ size_t depuncture(const std::array< uint8_t, IN >& input,
return bit_count;
}
} // namespace M17
#endif /* M17_CODE_PUNCTURING_H */
#endif // M17_CODE_PUNCTURING_H

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* Adapted from original code written by Rob Riggs, Mobilinkd LLC *
* *
@ -30,6 +30,9 @@
#include <cstdint>
#include <cstddef>
namespace M17
{
/**
* Convolutional encoder tailored on M17 protocol specifications, requiring a
* coder rate R = 1/2, a constraint length K = 5 and polynomials G1 = 0x19 and
@ -111,4 +114,6 @@ private:
uint8_t memory = 0; ///< Convolutional encoder memory.
};
#endif /* M17_CONVOLUTIONAL_ENCODER_H */
} // namespace M17
#endif // M17_CONVOLUTIONAL_ENCODER_H

View File

@ -1,9 +1,9 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Wojciech Kaczmarski SP5WWP *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Wojciech Kaczmarski SP5WWP *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* *
* This program is free software; you can redistribute it and/or modify *
@ -36,7 +36,36 @@ namespace M17
/*
* Coefficients for M17 RRC filter
*/
extern const std::array<float, 81> rrc_taps;
static constexpr std::array<float, 81> rrc_taps =
{
-0.003195702904062073, -0.002930279157647190, -0.001940667871554463,
-0.000356087678023658, 0.001547011339077758, 0.003389554791179751,
0.004761898604225673, 0.005310860846138910, 0.004824746306020221,
0.003297923526848786, 0.000958710871218619, -0.001749908029791816,
-0.004238694106631223, -0.005881783042101693, -0.006150256456781309,
-0.004745376707651645, -0.001704189656473565, 0.002547854551539951,
0.007215575568844704, 0.011231038205363532, 0.013421952197060707,
0.012730475385624438, 0.008449554307303753, 0.000436744366018287,
-0.010735380379191660, -0.023726883538258272, -0.036498030780605324,
-0.046500883189991064, -0.050979050575999614, -0.047340680079891187,
-0.033554880492651755, -0.008513823955725943, 0.027696543159614194,
0.073664520037517042, 0.126689053778116234, 0.182990955139333916,
0.238080025892859704, 0.287235637987091563, 0.326040247765297220,
0.350895727088112619, 0.359452932027607974, 0.350895727088112619,
0.326040247765297220, 0.287235637987091563, 0.238080025892859704,
0.182990955139333916, 0.126689053778116234, 0.073664520037517042,
0.027696543159614194, -0.008513823955725943, -0.033554880492651755,
-0.047340680079891187, -0.050979050575999614, -0.046500883189991064,
-0.036498030780605324, -0.023726883538258272, -0.010735380379191660,
0.000436744366018287, 0.008449554307303753, 0.012730475385624438,
0.013421952197060707, 0.011231038205363532, 0.007215575568844704,
0.002547854551539951, -0.001704189656473565, -0.004745376707651645,
-0.006150256456781309, -0.005881783042101693, -0.004238694106631223,
-0.001749908029791816, 0.000958710871218619, 0.003297923526848786,
0.004824746306020221, 0.005310860846138910, 0.004761898604225673,
0.003389554791179751, 0.001547011339077758, -0.000356087678023658,
-0.001940667871554463, -0.002930279157647190, -0.003195702904062073,
};
/*
* FIR implementation of the RRC filter for baseband audio generation.

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* 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 *
@ -28,6 +28,8 @@
#error This header is C++ only!
#endif
namespace M17
{
using call_t = std::array< uint8_t, 6 >; // Data type for encoded callsign
using meta_t = std::array< uint8_t, 14 >; // Data type for LSF metadata field
@ -60,4 +62,6 @@ typedef union
}
streamType_t;
#endif /* M17_DATATYPES_H */
} // namespace M17
#endif // M17_DATATYPES_H

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* Adapted from original code written by Rob Riggs, Mobilinkd LLC *
* *
@ -31,6 +31,8 @@
#include <string>
#include <array>
namespace M17
{
/**
* Decorrelator sequence for data randomisation.
@ -60,4 +62,6 @@ inline void decorrelate(std::array< uint8_t, N >& data)
}
}
#endif /* M17_DECORRELATOR_H */
} // namespace M17
#endif // M17_DECORRELATOR_H

View File

@ -31,6 +31,9 @@
#include "M17Viterbi.h"
#include "M17StreamFrame.h"
namespace M17
{
enum class M17FrameType : uint8_t
{
PREAMBLE = 0, ///< Frame contains a preamble.
@ -128,4 +131,6 @@ private:
M17Viterbi viterbi; ///< Viterbi decoder.
};
#endif /* M17FRAMEDECODER_H */
} // namespace M17
#endif // M17FRAMEDECODER_H

View File

@ -31,6 +31,9 @@
#include "M17LinkSetupFrame.h"
#include "M17StreamFrame.h"
namespace M17
{
/**
* M17 frame encoder.
*/
@ -89,4 +92,6 @@ private:
uint16_t streamFrameNumber; ///< Current frame number.
};
#endif /* M17FRAMEENCODER_H */
} // namespace M17
#endif // M17FRAMEENCODER_H

View File

@ -1,9 +1,9 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Wojciech Kaczmarski SP5WWP *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Wojciech Kaczmarski SP5WWP *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* *
* This program is free software; you can redistribute it and/or modify *
@ -29,6 +29,9 @@
#include <cstdint>
namespace M17
{
namespace Golay24
{
@ -170,4 +173,6 @@ static inline uint16_t golay24_decode(const uint32_t& codeword)
return ((codeword ^ errors) >> 12) & 0x0FFF;
}
#endif /* M17_GOLAY_H */
} // namespace M17
#endif // M17_GOLAY_H

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* Adapted from original code written by Rob Riggs, Mobilinkd LLC *
* *
@ -29,6 +29,9 @@
#include "M17Utils.h"
namespace M17
{
/**
* Interleave a block of data using the quadratic permutation polynomial from
* M17 protocol specification. Polynomial used is P(x) = 45*x + 92*x^2.
@ -78,4 +81,6 @@ void deinterleave(std::array< uint8_t, N >& data)
std::copy(deinterleaved.begin(), deinterleaved.end(), data.begin());
}
#endif /* M17_INTERLEAVER_H */
} // namespace M17
#endif // M17_INTERLEAVER_H

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* 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 *
@ -29,6 +29,9 @@
#include <array>
#include "M17Datatypes.h"
namespace M17
{
class M17FrameDecoder;
/**
@ -164,4 +167,6 @@ private:
friend class M17FrameDecoder;
};
#endif /* M17_LINKSETUPFRAME_H */
} // namespace M17
#endif // M17_LINKSETUPFRAME_H

View File

@ -18,8 +18,8 @@
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#ifndef M17_FRAME_H
#define M17_FRAME_H
#ifndef M17_STREAM_FRAME_H
#define M17_STREAM_FRAME_H
#ifndef __cplusplus
#error This header is C++ only!
@ -29,6 +29,9 @@
#include <string>
#include "M17Datatypes.h"
namespace M17
{
class M17FrameDecoder;
/**
@ -138,4 +141,6 @@ private:
friend class M17FrameDecoder;
};
#endif /* M17_FRAME_H */
} // namespace M17
#endif // M17_STREAM_FRAME_H

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* 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 *

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* *
* This program is free software; you can redistribute it and/or modify *
@ -31,6 +31,8 @@
#include <array>
#include <assert.h>
namespace M17
{
/**
* Utility function allowing to retrieve the value of a single bit from an array
@ -106,4 +108,6 @@ inline void setSymbol(std::array< uint8_t, N >& array, const size_t pos,
}
}
#endif /* M17_UTILS_H */
} // namespace M17
#endif // M17_UTILS_H

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* Adapted from original code written by Phil Karn KA9Q *
* *
@ -33,6 +33,9 @@
#include <bitset>
#include "M17Utils.h"
namespace M17
{
/**
* Hard decision Viterbi decoder tailored on M17 protocol specifications,
* that is for decoding of data encoded with a convolutional encoder with a
@ -216,4 +219,6 @@ private:
std::array< std::bitset< NumStates >, 244 > history;
};
#endif /* M17_VITERBI_H */
} // namespace M17
#endif // M17_VITERBI_H

View File

@ -21,6 +21,7 @@
#ifndef OPMODE_M17_H
#define OPMODE_M17_H
#include <M17/M17FrameDecoder.h>
#include <M17/M17Transmitter.h>
#include <M17/M17Demodulator.h>
#include <M17/M17Modulator.h>
@ -103,10 +104,12 @@ private:
*/
void sendData(const bool lastFrame = false);
bool enterRx; ///< Flag for RX management.
M17::M17Modulator modulator; ///< M17 modulator.
M17::M17Demodulator demodulator; ///< M17 demodulator.
M17::M17Transmitter m17Tx; ///< M17 transmission manager.
bool enterRx; ///< Flag for RX management.
bool locked; ///< Demodulator locked on data stream.
M17::M17Modulator modulator; ///< M17 modulator.
M17::M17Demodulator demodulator; ///< M17 demodulator.
M17::M17Transmitter m17Tx; ///< M17 transmission manager.
M17::M17FrameDecoder decoder; ///< M17 frame decoder
};
#endif /* OPMODE_M17_H */

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* Adapted from original code written by Rob Riggs, Mobilinkd LLC *
* *
@ -23,8 +23,8 @@
#include <string>
#include <M17/M17Callsign.h>
bool encode_callsign(const std::string& callsign, call_t& encodedCall,
bool strict)
bool M17::encode_callsign(const std::string& callsign, call_t& encodedCall,
bool strict)
{
encodedCall.fill(0x00);
if(callsign.size() > 9) return false;
@ -67,7 +67,7 @@ bool encode_callsign(const std::string& callsign, call_t& encodedCall,
return true;
}
std::string decode_callsign(const call_t& encodedCall)
std::string M17::decode_callsign(const call_t& encodedCall)
{
// First of all, check if encoded address is a broadcast one
bool isBroadcast = true;

View File

@ -1,8 +1,8 @@
/***************************************************************************
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
* *
* 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 *
@ -20,42 +20,4 @@
#include <M17/M17DSP.h>
namespace M17
{
/*
* Coefficients for M17 RRC filter for 48KHz sample rate
*/
const std::array<float, 81> rrc_taps = {
-0.003195702904062073, -0.002930279157647190, -0.001940667871554463,
-0.000356087678023658, 0.001547011339077758, 0.003389554791179751,
0.004761898604225673, 0.005310860846138910, 0.004824746306020221,
0.003297923526848786, 0.000958710871218619, -0.001749908029791816,
-0.004238694106631223, -0.005881783042101693, -0.006150256456781309,
-0.004745376707651645, -0.001704189656473565, 0.002547854551539951,
0.007215575568844704, 0.011231038205363532, 0.013421952197060707,
0.012730475385624438, 0.008449554307303753, 0.000436744366018287,
-0.010735380379191660, -0.023726883538258272, -0.036498030780605324,
-0.046500883189991064, -0.050979050575999614, -0.047340680079891187,
-0.033554880492651755, -0.008513823955725943, 0.027696543159614194,
0.073664520037517042, 0.126689053778116234, 0.182990955139333916,
0.238080025892859704, 0.287235637987091563, 0.326040247765297220,
0.350895727088112619, 0.359452932027607974, 0.350895727088112619,
0.326040247765297220, 0.287235637987091563, 0.238080025892859704,
0.182990955139333916, 0.126689053778116234, 0.073664520037517042,
0.027696543159614194, -0.008513823955725943, -0.033554880492651755,
-0.047340680079891187, -0.050979050575999614, -0.046500883189991064,
-0.036498030780605324, -0.023726883538258272, -0.010735380379191660,
0.000436744366018287, 0.008449554307303753, 0.012730475385624438,
0.013421952197060707, 0.011231038205363532, 0.007215575568844704,
0.002547854551539951, -0.001704189656473565, -0.004745376707651645,
-0.006150256456781309, -0.005881783042101693, -0.004238694106631223,
-0.001749908029791816, 0.000958710871218619, 0.003297923526848786,
0.004824746306020221, 0.005310860846138910, 0.004761898604225673,
0.003389554791179751, 0.001547011339077758, -0.000356087678023658,
-0.001940667871554463, -0.002930279157647190, -0.003195702904062073,
};
Fir< std::tuple_size< decltype(rrc_taps) >::value > rrc(rrc_taps);
} /* M17 */
Fir< std::tuple_size< decltype(M17::rrc_taps) >::value > M17::rrc(M17::rrc_taps);

View File

@ -25,6 +25,7 @@
#include <M17/M17CodePuncturing.h>
#include <algorithm>
using namespace M17;
M17FrameDecoder::M17FrameDecoder() { }

View File

@ -23,6 +23,8 @@
#include <M17/M17Interleaver.h>
#include <M17/M17FrameEncoder.h>
using namespace M17;
M17FrameEncoder::M17FrameEncoder() : currentLich(0), streamFrameNumber(0)
{
reset();

View File

@ -23,6 +23,7 @@
#include <M17/M17Callsign.h>
#include <M17/M17LinkSetupFrame.h>
using namespace M17;
M17LinkSetupFrame::M17LinkSetupFrame()
{

View File

@ -27,15 +27,16 @@
#include <rtx.h>
using namespace std;
using namespace M17;
OpMode_M17::OpMode_M17() : enterRx(true), m17Tx(modulator)
OpMode_M17::OpMode_M17() : enterRx(false), locked(false), m17Tx(modulator)
{
}
OpMode_M17::~OpMode_M17()
{
disable();
}
void OpMode_M17::enable()
@ -43,6 +44,7 @@ void OpMode_M17::enable()
codec_init();
modulator.init();
demodulator.init();
locked = false;
enterRx = true;
}
@ -50,6 +52,9 @@ void OpMode_M17::disable()
{
enterRx = false;
codec_terminate();
audio_disableAmp();
audio_disableMic();
radio_disableRtx();
modulator.terminate();
demodulator.terminate();
}
@ -61,16 +66,36 @@ void OpMode_M17::update(rtxStatus_t *const status, const bool newCfg)
// RX logic
if(status->opStatus == RX)
{
demodulator.update();
sleepFor(0u, 30u);
bool newData = demodulator.update();
locked = demodulator.isLocked();
if(locked && newData)
{
auto& frame = demodulator.getFrame();
auto type = decoder.decodeFrame(frame);
if(type == M17FrameType::STREAM)
{
M17StreamFrame sf = decoder.getStreamFrame();
codec_pushFrame(sf.payload().data(), false);
codec_pushFrame(sf.payload().data() + 8, false);
}
}
}
else if((status->opStatus == OFF) && enterRx)
{
radio_disableRtx();
radio_enableRx();
status->opStatus = RX;
audio_disableMic();
audio_enableAmp();
codec_stop();
codec_startDecode(SINK_SPK);
decoder.reset();
demodulator.startBasebandSampling();
radio_enableRx();
status->opStatus = RX;
enterRx = false;
}
@ -81,17 +106,20 @@ void OpMode_M17::update(rtxStatus_t *const status, const bool newCfg)
if(status->opStatus != TX)
{
demodulator.stopBasebandSampling();
audio_disableAmp();
radio_disableRtx();
audio_disableAmp();
codec_stop();
audio_enableMic();
radio_enableTx();
codec_startEncode(SOURCE_MIC);
radio_enableTx();
std::string source_address(status->source_address);
std::string destination_address(status->destination_address);
m17Tx.start(source_address, destination_address);
locked = false;
status->opStatus = TX;
}
else
@ -107,8 +135,8 @@ void OpMode_M17::update(rtxStatus_t *const status, const bool newCfg)
// Send last audio frame
sendData(true);
audio_disableMic();
radio_disableRtx();
audio_disableMic();
codec_stop();
status->opStatus = OFF;
@ -119,7 +147,12 @@ void OpMode_M17::update(rtxStatus_t *const status, const bool newCfg)
switch(status->opStatus)
{
case RX:
// TODO: Implement Rx LEDs
if(locked)
platform_ledOn(GREEN);
else
platform_ledOff(GREEN);
break;
case TX: