Implementation of M17 frame encoder

pull/68/head
Silvano Seva 2022-01-06 12:17:27 +01:00
rodzic 82dd0a63f1
commit 35c1f062c6
6 zmienionych plików z 211 dodań i 2 usunięć

Wyświetl plik

@ -43,6 +43,7 @@ openrtx_src = ['openrtx/src/core/state.c',
'openrtx/src/protocols/M17/M17Callsign.cpp',
'openrtx/src/protocols/M17/M17Modulator.cpp',
'openrtx/src/protocols/M17/M17Demodulator.cpp',
'openrtx/src/protocols/M17/M17FrameEncoder.cpp',
'openrtx/src/protocols/M17/M17FrameDecoder.cpp',
'openrtx/src/protocols/M17/M17Transmitter.cpp',
'openrtx/src/protocols/M17/M17LinkSetupFrame.cpp']

Wyświetl plik

@ -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 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 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> STREAM_SYNC_WORD = {0xFF, 0x5D}; // Stream data sync word

Wyświetl plik

@ -69,7 +69,7 @@ public:
* @param frame: byte array containg frame data.
* @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

Wyświetl plik

@ -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 */

Wyświetl plik

@ -38,7 +38,7 @@ void M17FrameDecoder::reset()
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, 46 > data;

Wyświetl plik

@ -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();
}