Implementation of M17 frame encoder
This commit is contained in:
parent
82dd0a63f1
commit
35c1f062c6
|
|
@ -43,6 +43,7 @@ openrtx_src = ['openrtx/src/core/state.c',
|
||||||
'openrtx/src/protocols/M17/M17Callsign.cpp',
|
'openrtx/src/protocols/M17/M17Callsign.cpp',
|
||||||
'openrtx/src/protocols/M17/M17Modulator.cpp',
|
'openrtx/src/protocols/M17/M17Modulator.cpp',
|
||||||
'openrtx/src/protocols/M17/M17Demodulator.cpp',
|
'openrtx/src/protocols/M17/M17Demodulator.cpp',
|
||||||
|
'openrtx/src/protocols/M17/M17FrameEncoder.cpp',
|
||||||
'openrtx/src/protocols/M17/M17FrameDecoder.cpp',
|
'openrtx/src/protocols/M17/M17FrameDecoder.cpp',
|
||||||
'openrtx/src/protocols/M17/M17Transmitter.cpp',
|
'openrtx/src/protocols/M17/M17Transmitter.cpp',
|
||||||
'openrtx/src/protocols/M17/M17LinkSetupFrame.cpp']
|
'openrtx/src/protocols/M17/M17LinkSetupFrame.cpp']
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ 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
|
using meta_t = std::array< uint8_t, 14 >; // Data type for LSF metadata field
|
||||||
using payload_t = std::array< uint8_t, 16 >; // Data type for frame payload field
|
using payload_t = std::array< uint8_t, 16 >; // Data type for frame payload field
|
||||||
using lich_t = std::array< uint8_t, 12 >; // Data type for Golay(24,12) encoded LICH data
|
using lich_t = std::array< uint8_t, 12 >; // Data type for Golay(24,12) encoded LICH data
|
||||||
|
using frame_t = std::array< uint8_t, 48 >; // Data type for a full M17 data frame, including sync word
|
||||||
|
|
||||||
static constexpr std::array<uint8_t, 2> LSF_SYNC_WORD = {0x55, 0xF7}; // LSF sync word
|
static constexpr std::array<uint8_t, 2> LSF_SYNC_WORD = {0x55, 0xF7}; // LSF sync word
|
||||||
static constexpr std::array<uint8_t, 2> STREAM_SYNC_WORD = {0xFF, 0x5D}; // Stream data sync word
|
static constexpr std::array<uint8_t, 2> STREAM_SYNC_WORD = {0xFF, 0x5D}; // Stream data sync word
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ public:
|
||||||
* @param frame: byte array containg frame data.
|
* @param frame: byte array containg frame data.
|
||||||
* @return the type of frame recognized.
|
* @return the type of frame recognized.
|
||||||
*/
|
*/
|
||||||
M17FrameType decodeFrame(const std::array< uint8_t, 48 >& frame);
|
M17FrameType decodeFrame(const frame_t& frame);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the latest Link Setup Frame decoded. Check of the validity of the
|
* Get the latest Link Setup Frame decoded. Check of the validity of the
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 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 *
|
||||||
|
* the Free Software Foundation; either 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 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 M17FRAMEENCODER_H
|
||||||
|
#define M17FRAMEENCODER_H
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#error This header is C++ only!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <array>
|
||||||
|
#include "M17ConvolutionalEncoder.h"
|
||||||
|
#include "M17LinkSetupFrame.h"
|
||||||
|
#include "M17StreamFrame.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* M17 frame encoder.
|
||||||
|
*/
|
||||||
|
class M17FrameEncoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
M17FrameEncoder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
|
~M17FrameEncoder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the internal data structures, reset the counter for frame sequence
|
||||||
|
* number in stream data frames and reset the counter for LICH segment
|
||||||
|
* sequence.
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a Link Setup Frame into a frame ready for transmission, prepended
|
||||||
|
* with the corresponding sync word. Link Setup data is also copied to an
|
||||||
|
* internal data structure and used to generate the LICH segments to be
|
||||||
|
* placed in each stream frame.
|
||||||
|
*
|
||||||
|
* @param lsf: Link Setup Frame to be encoded.
|
||||||
|
* @param output: destination buffer for the encoded data.
|
||||||
|
*/
|
||||||
|
void encodeLsf(M17LinkSetupFrame& lsf, frame_t& output);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare and encode a stream data frame into a frame ready for
|
||||||
|
* transmission, prepended with the corresponding sync word. The frame
|
||||||
|
* sequence number is incremented by one on each function call and cleared
|
||||||
|
* when the reset() function is called. The LICH segment field is filled
|
||||||
|
* with data obtained from the latest Link Setup Frame encoded.
|
||||||
|
*
|
||||||
|
* @param payload: payload data.
|
||||||
|
* @param output: destination buffer for the encoded data.
|
||||||
|
* @param isLast: if true, current frame is marked as the last one to be
|
||||||
|
* transmitted.
|
||||||
|
* @return the frame sequence number.
|
||||||
|
*/
|
||||||
|
uint16_t encodeStreamFrame(const payload_t& payload, frame_t& output,
|
||||||
|
const bool isLast = false);
|
||||||
|
private:
|
||||||
|
|
||||||
|
M17ConvolutionalEncoder encoder; ///< Convolutional encoder.
|
||||||
|
std::array< lich_t, 6 > lichSegments; ///< Encoded LSF chunks for LICH generation.
|
||||||
|
uint8_t currentLich; ///< Index of current LSF chunk.
|
||||||
|
uint16_t streamFrameNumber; ///< Current frame number.
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* M17FRAMEENCODER_H */
|
||||||
|
|
@ -38,7 +38,7 @@ void M17FrameDecoder::reset()
|
||||||
streamFrame.clear();
|
streamFrame.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
M17FrameType M17FrameDecoder::decodeFrame(const std::array< uint8_t, 48 >& frame)
|
M17FrameType M17FrameDecoder::decodeFrame(const frame_t& frame)
|
||||||
{
|
{
|
||||||
std::array< uint8_t, 2 > syncWord;
|
std::array< uint8_t, 2 > syncWord;
|
||||||
std::array< uint8_t, 46 > data;
|
std::array< uint8_t, 46 > data;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 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 *
|
||||||
|
* the Free Software Foundation; either 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 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 <M17/M17CodePuncturing.h>
|
||||||
|
#include <M17/M17Decorrelator.h>
|
||||||
|
#include <M17/M17Interleaver.h>
|
||||||
|
#include <M17/M17FrameEncoder.h>
|
||||||
|
|
||||||
|
M17FrameEncoder::M17FrameEncoder() : currentLich(0), streamFrameNumber(0)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
M17FrameEncoder::~M17FrameEncoder()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void M17FrameEncoder::reset()
|
||||||
|
{
|
||||||
|
// Clear counters
|
||||||
|
currentLich = 0;
|
||||||
|
streamFrameNumber = 0;
|
||||||
|
|
||||||
|
// Clear all the LICH segments
|
||||||
|
for(auto& segment : lichSegments)
|
||||||
|
{
|
||||||
|
segment.fill(0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void M17FrameEncoder::encodeLsf(M17LinkSetupFrame& lsf, frame_t& output)
|
||||||
|
{
|
||||||
|
// Ensure the LSF to be encoded has a valid CRC field
|
||||||
|
lsf.updateCrc();
|
||||||
|
|
||||||
|
// Generate the Golay(24,12) LICH segments
|
||||||
|
for(size_t i = 0; i < lichSegments.size(); i++)
|
||||||
|
{
|
||||||
|
lichSegments[i] = lsf.generateLichSegment(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode the LSF, then puncture and decorrelate its data
|
||||||
|
std::array<uint8_t, 61> encoded;
|
||||||
|
encoder.reset();
|
||||||
|
encoder.encode(lsf.getData(), encoded.data(), sizeof(M17LinkSetupFrame));
|
||||||
|
encoded[60] = encoder.flush();
|
||||||
|
|
||||||
|
std::array<uint8_t, 46> punctured;
|
||||||
|
puncture(encoded, punctured, LSF_PUNCTURE);
|
||||||
|
interleave(punctured);
|
||||||
|
decorrelate(punctured);
|
||||||
|
|
||||||
|
// Copy data to output buffer, prepended with sync word.
|
||||||
|
auto it = std::copy(LSF_SYNC_WORD.begin(), LSF_SYNC_WORD.end(),
|
||||||
|
output.begin());
|
||||||
|
std::copy(punctured.begin(), punctured.end(), it);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t M17FrameEncoder::encodeStreamFrame(const payload_t& payload,
|
||||||
|
frame_t& output, const bool isLast)
|
||||||
|
{
|
||||||
|
M17StreamFrame streamFrame;
|
||||||
|
|
||||||
|
streamFrame.setFrameNumber(streamFrameNumber);
|
||||||
|
streamFrameNumber = (streamFrameNumber + 1) & 0x07FF;
|
||||||
|
if(isLast) streamFrame.lastFrame();
|
||||||
|
std::copy(payload.begin(), payload.end(), streamFrame.payload().begin());
|
||||||
|
|
||||||
|
// Encode frame
|
||||||
|
std::array<uint8_t, 37> encoded;
|
||||||
|
encoder.reset();
|
||||||
|
encoder.encode(streamFrame.getData(), encoded.data(), sizeof(M17StreamFrame));
|
||||||
|
encoded[36] = encoder.flush();
|
||||||
|
|
||||||
|
std::array<uint8_t, 34> punctured;
|
||||||
|
puncture(encoded, punctured, DATA_PUNCTURE);
|
||||||
|
|
||||||
|
// Add LICH segment to coded data
|
||||||
|
std::array<uint8_t, 46> frame;
|
||||||
|
auto it = std::copy(lichSegments[currentLich].begin(),
|
||||||
|
lichSegments[currentLich].end(),
|
||||||
|
frame.begin());
|
||||||
|
std::copy(punctured.begin(), punctured.end(), it);
|
||||||
|
|
||||||
|
// Increment LICH counter after copy
|
||||||
|
currentLich = (currentLich + 1) % lichSegments.size();
|
||||||
|
|
||||||
|
interleave(frame);
|
||||||
|
decorrelate(frame);
|
||||||
|
|
||||||
|
// Copy data to output buffer, prepended with sync word.
|
||||||
|
auto oIt = std::copy(STREAM_SYNC_WORD.begin(), STREAM_SYNC_WORD.end(),
|
||||||
|
output.begin());
|
||||||
|
std::copy(frame.begin(), frame.end(), oIt);
|
||||||
|
|
||||||
|
return streamFrame.getFrameNumber();
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue