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