diff --git a/platform/drivers/audio/audio_ttwrplus.c b/platform/drivers/audio/audio_ttwrplus.c
new file mode 100644
index 00000000..7d024912
--- /dev/null
+++ b/platform/drivers/audio/audio_ttwrplus.c
@@ -0,0 +1,91 @@
+/***************************************************************************
+ * Copyright (C) 2023 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
+
+const struct audioDevice outputDevices[] =
+{
+ {NULL, 0, 0, SINK_MCU},
+ {NULL, 0, 0, SINK_RTX},
+ {NULL, 0, 0, SINK_SPK},
+};
+
+const struct audioDevice inputDevices[] =
+{
+ {NULL, 0, 0, SINK_MCU},
+ {NULL, 0, 0, SINK_RTX},
+ {NULL, 0, 0, SINK_SPK},
+};
+
+void audio_init()
+{
+
+}
+
+void audio_terminate()
+{
+
+}
+
+void audio_connect(const enum AudioSource source, const enum AudioSink sink)
+{
+ /*
+ * Squelch implementation:
+ * when an audio path is created between SOURCE_RTX and SINK_SPK, unmute
+ * speaker power amplifier to hear analog fm audio.
+ */
+ if (source == SOURCE_RTX && sink == SINK_SPK)
+ sa8x8_setAudio(true);
+}
+
+void audio_disconnect(const enum AudioSource source, const enum AudioSink sink)
+{
+ /*
+ * Squelch implementation:
+ * when an audio path is released between SOURCE_RTX and SINK_SPK, mute
+ * speaker power amplifier to squelch noise.
+ */
+ if (source == SOURCE_RTX && sink == SINK_SPK)
+ sa8x8_setAudio(false);
+}
+
+bool audio_checkPathCompatibility(const enum AudioSource p1Source,
+ const enum AudioSink p1Sink,
+ const enum AudioSource p2Source,
+ const enum AudioSink p2Sink)
+
+{
+ static const uint8_t RTX_SPK = (SOURCE_RTX * 3) + SINK_SPK;
+ static const uint8_t MIC_RTX = (SOURCE_MIC * 3) + SINK_RTX;
+
+ uint8_t p1 = (p1Source * 3) + p1Sink;
+ uint8_t p2 = (p2Source * 3) + p2Sink;
+
+ // RTX-SPK and MIC-RTX are compatible
+ if((p1 == RTX_SPK) && (p2 == MIC_RTX))
+ return true;
+
+ // Same as above but with the paths swapped
+ if((p1 == MIC_RTX) && (p2 == RTX_SPK))
+ return true;
+
+ // Disallow all the other path combinations
+ return false;
+}
diff --git a/platform/drivers/baseband/AT1846S_SA8x8.cpp b/platform/drivers/baseband/AT1846S_SA8x8.cpp
index ad317381..259fe7b2 100644
--- a/platform/drivers/baseband/AT1846S_SA8x8.cpp
+++ b/platform/drivers/baseband/AT1846S_SA8x8.cpp
@@ -87,7 +87,7 @@ void AT1846S::setBandwidth(const AT1846S_BW band)
// 25kHz bandwidth
i2c_writeReg16(0x15, 0x1F00); // Tuning bit
i2c_writeReg16(0x32, 0x7564); // AGC target power
- i2c_writeReg16(0x3A, 0x44C3); // Modulation detect sel
+ i2c_writeReg16(0x3A, 0x4003); // Modulation detect sel
i2c_writeReg16(0x3F, 0x29D2); // RSSI 3 threshold
i2c_writeReg16(0x3C, 0x0E1C); // Peak detect threshold
i2c_writeReg16(0x48, 0x1E38); // Noise 1 threshold
@@ -113,7 +113,7 @@ void AT1846S::setBandwidth(const AT1846S_BW band)
// 12.5kHz bandwidth
i2c_writeReg16(0x15, 0x1100); // Tuning bit
i2c_writeReg16(0x32, 0x4495); // AGC target power
- i2c_writeReg16(0x3A, 0x40C3); // Modulation detect sel
+ i2c_writeReg16(0x3A, 0x4003); // Modulation detect sel
i2c_writeReg16(0x3F, 0x28D0); // RSSI 3 threshold
i2c_writeReg16(0x3C, 0x0F1E); // Peak detect threshold
i2c_writeReg16(0x48, 0x1DB6); // Noise 1 threshold
diff --git a/platform/drivers/baseband/SA8x8.c b/platform/drivers/baseband/SA8x8.c
index e53fa814..4050788d 100644
--- a/platform/drivers/baseband/SA8x8.c
+++ b/platform/drivers/baseband/SA8x8.c
@@ -28,9 +28,9 @@
* Minimum required version of sa868-fw
*/
#define SA868FW_MAJOR 1
-#define SA868FW_MINOR 1
+#define SA868FW_MINOR 3
#define SA868FW_PATCH 0
-#define SA868FW_RELEASE 20
+#define SA868FW_RELEASE 1
#if DT_NODE_HAS_STATUS(DT_ALIAS(radio), okay)
@@ -122,8 +122,10 @@ static inline bool checkFwVersion()
sscanf(fwVersionStr, "sa8x8-fw/v%hhu.%hhu.%hhu.r%hhu", &major, &minor,
&patch, &release);
- if((major >= SA868FW_MAJOR) && (minor >= SA868FW_MINOR) &&
- (patch >= SA868FW_PATCH) && (release >= SA868FW_RELEASE))
+ if((major > SA868FW_MAJOR) ||
+ (major == SA868FW_MAJOR) && (minor > SA868FW_MINOR) ||
+ (major == SA868FW_MAJOR) && (minor == SA868FW_MINOR) && (patch > SA868FW_PATCH) ||
+ (major == SA868FW_MAJOR) && (minor == SA868FW_MINOR) && (patch == SA868FW_PATCH) && (release >= SA868FW_RELEASE))
{
return true;
}
@@ -279,7 +281,19 @@ void sa8x8_setTxPower(const float power)
uint8_t amp_enable = (power > 1.0f) ? 1 : 0;
int ret = gpio_pin_set_dt(&radio_pwr, amp_enable);
if(ret != 0)
- printk("SA8x8: failed to enable high power mode");
+ printk("SA8x8: failed to change power mode");
+}
+
+void sa8x8_setAudio(bool value)
+{
+ char buf[SA8X8_MSG_SIZE];
+
+ uartPrint("AT+AUDIO=%d\r\n", value);
+ k_msgq_get(&uart_msgq, buf, K_MSEC(100));
+
+ // Check that response is "OK\r"
+ if(strncmp(buf, "OK\r", 3U) != 0)
+ printk("SA8x8: failed to enable control speaker power amplifier");
}
void sa8x8_writeAT1846Sreg(uint8_t reg, uint16_t value)
diff --git a/platform/drivers/baseband/SA8x8.h b/platform/drivers/baseband/SA8x8.h
index b36bd12a..d9a30eb0 100644
--- a/platform/drivers/baseband/SA8x8.h
+++ b/platform/drivers/baseband/SA8x8.h
@@ -62,6 +62,13 @@ int sa8x8_enableHSMode();
*/
void sa8x8_setTxPower(const float power);
+/**
+ * Enable or disable the speaker power amplifier.
+ *
+ * @param value: boolean state of the speaker power amplifier.
+ */
+void sa8x8_setAudio(bool value);
+
/**
* Write a register of the AT1846S radio IC contained in the SA8x8 module.
*
diff --git a/platform/drivers/baseband/radio_ttwrplus.cpp b/platform/drivers/baseband/radio_ttwrplus.cpp
index 153aee7d..1bef6aab 100644
--- a/platform/drivers/baseband/radio_ttwrplus.cpp
+++ b/platform/drivers/baseband/radio_ttwrplus.cpp
@@ -43,6 +43,9 @@ void radio_init(const rtxStatus_t *rtxState)
// platform_init()
sa8x8_enableHSMode();
+ // Mute speaker power amplifier by default
+ sa8x8_setAudio(false);
+
/*
* Configure AT1846S, keep AF output disabled at power on.
*/
diff --git a/platform/targets/ttwrplus/CMakeLists.txt b/platform/targets/ttwrplus/CMakeLists.txt
index 4c4913c1..e1b58c6f 100644
--- a/platform/targets/ttwrplus/CMakeLists.txt
+++ b/platform/targets/ttwrplus/CMakeLists.txt
@@ -18,8 +18,8 @@ target_sources(app
${OPENRTX_ROOT}/platform/drivers/baseband/AT1846S_SA8x8.cpp
${OPENRTX_ROOT}/platform/drivers/baseband/SA8x8.c
${OPENRTX_ROOT}/platform/drivers/GPS/GPS_ttwrplus.c
+ ${OPENRTX_ROOT}/platform/drivers/audio/audio_ttwrplus.c
- ${OPENRTX_ROOT}/platform/drivers/stubs/audio_stub.c
${OPENRTX_ROOT}/platform/drivers/stubs/cps_io_stub.c
${OPENRTX_ROOT}/platform/drivers/stubs/nvmem_stub.c