diff --git a/meson.build b/meson.build
index 780daf06..6e8364b5 100644
--- a/meson.build
+++ b/meson.build
@@ -31,10 +31,13 @@ openrtx_src = ['openrtx/src/state.c',
'openrtx/src/queue.c',
'openrtx/src/rtx/rtx.cpp',
'openrtx/src/rtx/OpMode_FM.cpp',
+ 'openrtx/src/rtx/OpMode_M17.cpp',
'openrtx/src/gps.c',
'openrtx/src/dsp.cpp',
'openrtx/src/memory_profiling.cpp',
'openrtx/src/protocols/M17/M17Callsign.cpp',
+ 'openrtx/src/protocols/M17/M17Modulator.cpp',
+ 'openrtx/src/protocols/M17/M17Transmitter.cpp',
'openrtx/src/protocols/M17/M17LinkSetupFrame.cpp']
openrtx_inc = ['openrtx/include',
diff --git a/openrtx/include/rtx/OpMode_M17.h b/openrtx/include/rtx/OpMode_M17.h
new file mode 100644
index 00000000..cfb8f16f
--- /dev/null
+++ b/openrtx/include/rtx/OpMode_M17.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ * 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 *
+ ***************************************************************************/
+
+#ifndef OPMODE_M17_H
+#define OPMODE_M17_H
+
+#include
+#include
+#include
+#include "OpMode.h"
+
+
+/**
+ * Specialisation of the OpMode class for the management of M17 operating mode.
+ */
+class OpMode_M17 : public OpMode
+{
+public:
+
+ /**
+ * Constructor.
+ */
+ OpMode_M17();
+
+ /**
+ * Destructor.
+ */
+ ~OpMode_M17();
+
+ /**
+ * Enable the operating mode.
+ *
+ * Application must ensure this function is being called when entering the
+ * new operating mode and always before the first call of "update".
+ */
+ virtual void enable() override;
+
+ /**
+ * Disable the operating mode. This function stops the DMA transfers
+ * between the baseband, microphone and speakers. It also ensures that
+ * the radio, the audio amplifier and the microphone are in OFF state.
+ *
+ * Application must ensure this function is being called when exiting the
+ * current operating mode.
+ */
+ virtual void disable() override;
+
+ /**
+ * Update the internal FSM.
+ * Application code has to call this function periodically, to ensure proper
+ * functionality.
+ *
+ * @param status: pointer to the rtxStatus_t structure containing the current
+ * RTX status. Internal FSM may change the current value of the opStatus flag.
+ * @param newCfg: flag used inform the internal FSM that a new RTX configuration
+ * has been applied.
+ */
+ virtual void update(rtxStatus_t *const status, const bool newCfg) override;
+
+ /**
+ * Get the mode identifier corresponding to the OpMode class.
+ *
+ * @return the corresponding flag from the opmode enum.
+ */
+ virtual opmode getID() override
+ {
+ return M17;
+ }
+
+private:
+
+ /**
+ * Send an M17 frame over the air.
+ *
+ * @param lastFrame: set to true to indicate that current frame is the last
+ * frame of the currently active transmission.
+ */
+ void sendData(const bool lastFrame = false);
+
+ bool enterRx; ///< Flag for RX management.
+ M17Modulator modulator; ///< M17 modulator.
+ M17Transmitter m17Tx; ///< M17 transmission manager.
+};
+
+#endif /* OPMODE_M17_H */
diff --git a/openrtx/src/rtx/OpMode_M17.cpp b/openrtx/src/rtx/OpMode_M17.cpp
new file mode 100644
index 00000000..5ee64777
--- /dev/null
+++ b/openrtx/src/rtx/OpMode_M17.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+ * 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
+#include
+
+OpMode_M17::OpMode_M17() : enterRx(true), m17Tx(modulator)
+{
+
+}
+
+OpMode_M17::~OpMode_M17()
+{
+}
+
+void OpMode_M17::enable()
+{
+ modulator.init();
+ enterRx = true;
+}
+
+void OpMode_M17::disable()
+{
+ enterRx = false;
+ modulator.terminate();
+}
+
+void OpMode_M17::update(rtxStatus_t *const status, const bool newCfg)
+{
+ (void) newCfg;
+
+ // RX logic
+ if(status->opStatus == RX)
+ {
+ // TODO: Implement M17 Rx
+ }
+ else if((status->opStatus == OFF) && enterRx)
+ {
+ radio_disableRtx();
+
+ radio_enableRx();
+ status->opStatus = RX;
+ enterRx = false;
+ }
+
+ // TX logic
+ if(platform_getPttStatus() && (status->txDisable == 0))
+ {
+ // Enter Tx mode, setup transmission
+ if(status->opStatus != TX)
+ {
+ audio_disableAmp();
+ radio_disableRtx();
+
+ audio_enableMic();
+ radio_enableTx();
+
+ // TODO: Allow destinations different than broadcast
+ std::string source_address("OPNRTX");
+ m17Tx.start(source_address);
+
+ status->opStatus = TX;
+ }
+ else
+ {
+ // Transmission is ongoing, just modulate
+ sendData(false);
+ }
+ }
+
+ // PTT is off, transition to Rx state
+ if(!platform_getPttStatus() && (status->opStatus == TX))
+ {
+ // Send last audio frame
+ sendData(true);
+
+ audio_disableMic();
+ radio_disableRtx();
+
+ status->opStatus = OFF;
+ enterRx = true;
+ }
+
+ // Led control logic
+ switch(status->opStatus)
+ {
+ case RX:
+ // TODO: Implement Rx LEDs
+ break;
+
+ case TX:
+ platform_ledOff(GREEN);
+ platform_ledOn(RED);
+ break;
+
+ default:
+ platform_ledOff(GREEN);
+ platform_ledOff(RED);
+ break;
+ }
+}
+
+void OpMode_M17::sendData(bool lastFrame)
+{
+ payload_t dataFrame;
+
+ // TODO: temporarily data frame is filled with pseudorandom data
+ static unsigned int nSeed = 5323;
+ for(size_t i = 0; i < dataFrame.size(); i++)
+ {
+ nSeed = (8253729 * nSeed + 2396403);
+ dataFrame[i] = nSeed % 256;
+ }
+
+ m17Tx.send(dataFrame, lastFrame);
+}
diff --git a/openrtx/src/rtx/rtx.cpp b/openrtx/src/rtx/rtx.cpp
index e1551972..a7f74370 100644
--- a/openrtx/src/rtx/rtx.cpp
+++ b/openrtx/src/rtx/rtx.cpp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
pthread_mutex_t *cfgMutex; // Mutex for incoming config messages
@@ -31,9 +32,10 @@ rtxStatus_t rtxStatus; // RTX driver status
float rssi; // Current RSSI in dBm
bool reinitFilter; // Flag for RSSI filter re-initialisation
-OpMode *currMode; // Pointer to currently active opMode handler
-OpMode noMode; // Empty opMode handler for opmode::NONE
-OpMode_FM fmMode; // FM mode handler
+OpMode *currMode; // Pointer to currently active opMode handler
+OpMode noMode; // Empty opMode handler for opmode::NONE
+OpMode_FM fmMode; // FM mode handler
+OpMode_M17 m17Mode; // M17 mode handler
void rtx_init(pthread_mutex_t *m)
{
@@ -138,6 +140,7 @@ void rtx_taskFunc()
{
case NONE: currMode = &noMode; break;
case FM: currMode = &fmMode; break;
+ case M17: currMode = &m17Mode; break;
default: currMode = &noMode;
}