From a22aceb57691267036655fdd2dd7521b54e16447 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Thu, 11 Aug 2022 19:50:38 +0200 Subject: [PATCH] Reorganized code for M17 transmission: removed M17Transmitter class, use M17FrameEncoder to assemble LSF and data frames, modified API of M17Modulator class. --- meson.build | 1 - .../include/protocols/M17/M17Modulator.hpp | 21 +-- .../include/protocols/M17/M17Transmitter.hpp | 95 -------------- openrtx/include/rtx/OpMode_M17.hpp | 4 +- openrtx/src/protocols/M17/M17Modulator.cpp | 83 +++++++----- openrtx/src/protocols/M17/M17Transmitter.cpp | 124 ------------------ openrtx/src/rtx/OpMode_M17.cpp | 37 ++++-- 7 files changed, 88 insertions(+), 277 deletions(-) delete mode 100644 openrtx/include/protocols/M17/M17Transmitter.hpp delete mode 100644 openrtx/src/protocols/M17/M17Transmitter.cpp diff --git a/meson.build b/meson.build index 9219b7a9..a98c3e08 100644 --- a/meson.build +++ b/meson.build @@ -57,7 +57,6 @@ openrtx_src = ['openrtx/src/core/state.c', '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'] openrtx_inc = ['openrtx/include', diff --git a/openrtx/include/protocols/M17/M17Modulator.hpp b/openrtx/include/protocols/M17/M17Modulator.hpp index 86d77eb9..209d217e 100644 --- a/openrtx/include/protocols/M17/M17Modulator.hpp +++ b/openrtx/include/protocols/M17/M17Modulator.hpp @@ -62,31 +62,32 @@ public: */ void terminate(); + /** + * Start baseband transmission and send an 80ms preamble. + */ + void start(); + /** * Generate and transmit the baseband signal obtained by 4FSK modulation of - * a given block of data. When called for the first time, this function - * starts baseband transmission. + * a given block of data. * - * @param sync: synchronisation word to be prepended to data block. - * @param data: data block to be transmitted. + * @param frame: M17 frame to be sent. * @param isLast: flag signalling that current block is the last one being * transmitted. */ - void send(const std::array< uint8_t, 2 >& sync, - const std::array< uint8_t, 46 >& data, - const bool isLast = false); + void send(const frame_t& frame, const bool isLast); private: /** * Generate baseband stream from symbol stream. */ - void generateBaseband(); + void symbolsToBaseband(); /** * Emit the baseband stream towards the output stage, platform dependent. */ - void emitBaseband(); + void sendBaseband(); static constexpr size_t M17_TX_SAMPLE_RATE = 48000; static constexpr size_t M17_SAMPLES_PER_SYMBOL = M17_TX_SAMPLE_RATE / M17_SYMBOL_RATE; @@ -100,7 +101,7 @@ private: static constexpr float M17_RRC_OFFSET = 0.0f; #endif - std::array< int16_t, M17_FRAME_SYMBOLS > symbols; + std::array< int8_t, M17_FRAME_SYMBOLS > symbols; std::unique_ptr< int16_t[] > baseband_buffer; ///< Buffer for baseband audio handling. stream_sample_t *idleBuffer; ///< Half baseband buffer, free for processing. streamId outStream; ///< Baseband output stream ID. diff --git a/openrtx/include/protocols/M17/M17Transmitter.hpp b/openrtx/include/protocols/M17/M17Transmitter.hpp deleted file mode 100644 index 4d4d0ee0..00000000 --- a/openrtx/include/protocols/M17/M17Transmitter.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/*************************************************************************** - * 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 * - * 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 * - ***************************************************************************/ - -#ifndef M17TRANSMITTER_H -#define M17TRANSMITTER_H - -#ifndef __cplusplus -#error This header is C++ only! -#endif - -#include -#include -#include "M17ConvolutionalEncoder.hpp" -#include "M17LinkSetupFrame.hpp" -#include "M17StreamFrame.hpp" -#include "M17Modulator.hpp" - -namespace M17 -{ - -/** - * M17 transmitter. - */ -class M17Transmitter -{ -public: - - /** - * Constructor. - * - * @param modulator: reference to M17 4FSK modulator driver. - */ - M17Transmitter(M17Modulator& modulator); - - /** - * Destructor. - */ - ~M17Transmitter(); - - /** - * Start a new data stream with broadcast destination callsign. - * - * @param src: source callsign. - */ - void start(const std::string& src); - - /** - * Start a new data stream with given destination callsign. If destination - * callsing is empty, the stream falls back to broadcast transmission. - * - * @param src: source callsign. - * @param dst: destination callsign. - */ - void start(const std::string& src, const std::string& dst); - - /** - * Send a block of data. - * - * @param payload: payload data. - * @param isLast: if true, current frame is marked as the last one to be - * transmitted. - */ - void send(const payload_t& payload, const bool isLast = false); - -private: - - M17ConvolutionalEncoder encoder; ///< Convolutional encoder. - M17LinkSetupFrame lsf; ///< Link Setup Frame handler. - M17StreamFrame dataFrame; ///< Data frame Handler. - M17Modulator& modulator; ///< 4FSK modulator. - std::array< lich_t, 6 > lichSegments; ///< Encoded LSF chunks for LICH generation. - uint8_t currentLich; ///< Index of current LSF chunk. - uint16_t frameNumber; ///< Current frame number. -}; - -} /* M17 */ - -#endif /* M17TRANSMITTER_H */ diff --git a/openrtx/include/rtx/OpMode_M17.hpp b/openrtx/include/rtx/OpMode_M17.hpp index 17dbdf29..17c224c0 100644 --- a/openrtx/include/rtx/OpMode_M17.hpp +++ b/openrtx/include/rtx/OpMode_M17.hpp @@ -22,7 +22,7 @@ #define OPMODE_M17_H #include -#include +#include #include #include #include "OpMode.hpp" @@ -126,8 +126,8 @@ private: 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 + M17::M17FrameEncoder encoder; ///< M17 frame encoder }; #endif /* OPMODE_M17_H */ diff --git a/openrtx/src/protocols/M17/M17Modulator.cpp b/openrtx/src/protocols/M17/M17Modulator.cpp index 94de4329..80190965 100644 --- a/openrtx/src/protocols/M17/M17Modulator.cpp +++ b/openrtx/src/protocols/M17/M17Modulator.cpp @@ -47,8 +47,7 @@ void M17Modulator::init() { /* * Allocate a chunk of memory to contain two complete buffers for baseband - * audio. Split this chunk in two separate blocks for double buffering using - * placement new. + * audio. */ baseband_buffer = std::make_unique< int16_t[] >(2 * M17_FRAME_SAMPLES); @@ -72,30 +71,55 @@ void M17Modulator::terminate() baseband_buffer.reset(); } -void M17Modulator::send(const std::array< uint8_t, 2 >& sync, - const std::array< uint8_t, 46 >& data, - const bool isLast) +void M17::M17Modulator::start() { - auto sync1 = byteToSymbols(sync[0]); - auto sync2 = byteToSymbols(sync[1]); + if(txRunning) return; - auto it = std::copy(sync1.begin(), sync1.end(), symbols.begin()); - it = std::copy(sync2.begin(), sync2.end(), it); + txRunning = true; + stopTx = false; - for(size_t i = 0; i < data.size(); i++) + // Fill symbol buffer with preamble, made of alternated +3 and -3 symbols + for(size_t i = 0; i < symbols.size(); i += 2) { - auto sym = byteToSymbols(data[i]); + symbols[i] = +3; + symbols[i + 1] = -3; + } + + // Generate baseband signal and then start transmission + symbolsToBaseband(); + #ifndef PLATFORM_LINUX + outStream = outputStream_start(SINK_RTX, PRIO_TX, baseband_buffer.get(), + 2*M17_FRAME_SAMPLES, BUF_CIRC_DOUBLE, + M17_TX_SAMPLE_RATE); + idleBuffer = outputStream_getIdleBuffer(outStream); + #else + sendBaseband(); + #endif + + // Repeat baseband generation and transmission, this makes the preamble to + // be long 80ms (two frames) + symbolsToBaseband(); + sendBaseband(); +} + + +void M17Modulator::send(const frame_t& frame, const bool isLast) +{ + auto it = symbols.begin(); + for(size_t i = 0; i < frame.size(); i++) + { + auto sym = byteToSymbols(frame[i]); it = std::copy(sym.begin(), sym.end(), it); } // If last frame, signal stop of transmission if(isLast) stopTx = true; - generateBaseband(); - emitBaseband(); + symbolsToBaseband(); + sendBaseband(); } -void M17Modulator::generateBaseband() +void M17Modulator::symbolsToBaseband() { memset(idleBuffer, 0x00, M17_FRAME_SAMPLES * sizeof(stream_sample_t)); @@ -110,33 +134,20 @@ void M17Modulator::generateBaseband() elem = M17::rrc_48k(elem * M17_RRC_GAIN) - M17_RRC_OFFSET; idleBuffer[i] = static_cast< int16_t >(elem); } -} -#ifndef PLATFORM_LINUX -void M17Modulator::emitBaseband() -{ #if defined(PLATFORM_MD3x0) || defined(PLATFORM_MDUV3x0) dsp_pwmCompensate(&pwmFilterState, idleBuffer, M17_FRAME_SAMPLES); dsp_invertPhase(idleBuffer, M17_FRAME_SAMPLES); #endif +} - if(txRunning == false) - { - // First run, start transmission - outStream = outputStream_start(SINK_RTX, - PRIO_TX, - baseband_buffer.get(), - 2*M17_FRAME_SAMPLES, - BUF_CIRC_DOUBLE, - M17_TX_SAMPLE_RATE); - txRunning = true; - stopTx = false; - } - else - { - // Transmission is ongoing, syncronise with stream end before proceeding - outputStream_sync(outStream, true); - } +#ifndef PLATFORM_LINUX +void M17Modulator::sendBaseband() +{ + if(txRunning == false) return; + + // Transmission is ongoing, syncronise with stream end before proceeding + outputStream_sync(outStream, true); // Check if transmission stop is requested, if so stop the output stream // and wait until its effective termination. @@ -157,7 +168,7 @@ void M17Modulator::emitBaseband() } } #else -void M17Modulator::emitBaseband() +void M17Modulator::sendBaseband() { FILE *outfile = fopen("/tmp/m17_output.raw", "ab"); diff --git a/openrtx/src/protocols/M17/M17Transmitter.cpp b/openrtx/src/protocols/M17/M17Transmitter.cpp deleted file mode 100644 index 34a7eb04..00000000 --- a/openrtx/src/protocols/M17/M17Transmitter.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2021 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 * - ***************************************************************************/ - -#include -#include -#include -#include - -using namespace M17; - -M17Transmitter::M17Transmitter(M17Modulator& modulator) : modulator(modulator), - currentLich(0), frameNumber(0) -{ - -} - -M17Transmitter::~M17Transmitter() -{ - -} - -void M17Transmitter::start(const std::string& src) -{ - // Just call start() with an empty string for destination callsign. - std::string empty; - start(src, empty); -} - -void M17Transmitter::start(const std::string& src, const std::string& dst) -{ - // Reset LICH and frame counters - currentLich = 0; - frameNumber = 0; - - // Fill the Link Setup Frame - lsf.clear(); - lsf.setSource(src); - if(!dst.empty()) lsf.setDestination(dst); - - streamType_t type; - type.fields.stream = 1; // Stream - type.fields.dataType = 2; // Voice data - type.fields.CAN = 0; // Channel access number - - lsf.setType(type); - 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 encoded; - encoder.reset(); - encoder.encode(lsf.getData(), encoded.data(), sizeof(M17LinkSetupFrame)); - encoded[60] = encoder.flush(); - - std::array punctured; - puncture(encoded, punctured, LSF_PUNCTURE); - interleave(punctured); - decorrelate(punctured); - - // Send preamble - std::array preamble_sync; - std::array preamble_bytes; - preamble_sync.fill(0x77); - preamble_bytes.fill(0x77); - modulator.send(preamble_sync, preamble_bytes); - - // Send LSF - modulator.send(LSF_SYNC_WORD, punctured); -} - -void M17Transmitter::send(const payload_t& payload, const bool isLast) -{ - dataFrame.clear(); - dataFrame.setFrameNumber(frameNumber); - frameNumber = (frameNumber + 1) & 0x07FF; - if(isLast) dataFrame.lastFrame(); - std::copy(payload.begin(), payload.end(), dataFrame.payload().begin()); - - // Encode frame - std::array encoded; - encoder.reset(); - encoder.encode(dataFrame.getData(), encoded.data(), sizeof(M17StreamFrame)); - encoded[36] = encoder.flush(); - - std::array punctured; - puncture(encoded, punctured, DATA_PUNCTURE); - - // Add LICH segment to coded data and send - std::array 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); - - modulator.send(STREAM_SYNC_WORD, frame, isLast); -} diff --git a/openrtx/src/rtx/OpMode_M17.cpp b/openrtx/src/rtx/OpMode_M17.cpp index 91bec540..94b90663 100644 --- a/openrtx/src/rtx/OpMode_M17.cpp +++ b/openrtx/src/rtx/OpMode_M17.cpp @@ -29,8 +29,7 @@ using namespace std; using namespace M17; -OpMode_M17::OpMode_M17() : startRx(false), startTx(false), locked(false), - m17Tx(modulator) +OpMode_M17::OpMode_M17() : startRx(false), startTx(false), locked(false) { } @@ -190,18 +189,37 @@ void OpMode_M17::rxState(rtxStatus_t *const status) void OpMode_M17::txState(rtxStatus_t *const status) { + frame_t m17Frame; + if(startTx) { + startTx = false; + + std::string src(status->source_address); + std::string dst(status->destination_address); + M17LinkSetupFrame lsf; + + lsf.clear(); + lsf.setSource(src); + if(!dst.empty()) lsf.setDestination(dst); + + streamType_t type; + type.fields.stream = 1; // Stream + type.fields.dataType = 2; // Voice data + type.fields.CAN = 0; // Channel access number + + lsf.setType(type); + lsf.updateCrc(); + + encoder.reset(); + encoder.encodeLsf(lsf, m17Frame); + audio_enableMic(); 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); - - startTx = false; + modulator.start(); + modulator.send(m17Frame, false); } payload_t dataFrame; @@ -218,5 +236,6 @@ void OpMode_M17::txState(rtxStatus_t *const status) status->opStatus = OFF; } - m17Tx.send(dataFrame, lastFrame); + encoder.encodeStreamFrame(dataFrame, m17Frame, lastFrame); + modulator.send(m17Frame, lastFrame); }