diff --git a/meson.build b/meson.build
index 4d81a80d..674a4cfc 100644
--- a/meson.build
+++ b/meson.build
@@ -163,7 +163,7 @@ md3x0_src = src + stm32f405_src + ['platform/drivers/display/HX8353_MDx.cpp',
'platform/drivers/NVM/spiFlash_MDx.c',
'platform/drivers/NVM/nvmem_MD3x0.c',
'platform/drivers/ADC/ADC1_MDx.c',
- 'platform/drivers/tones/toneGenerator_MDx.c',
+ 'platform/drivers/tones/toneGenerator_MDx.cpp',
'platform/drivers/baseband/SKY72310.c',
'platform/drivers/baseband/radio_MD3x0.c',
'platform/drivers/baseband/HR_C5000.c',
@@ -181,7 +181,7 @@ mduv3x0_src = src + stm32f405_src + ['platform/drivers/display/HX8353_MDx.cpp',
'platform/drivers/NVM/spiFlash_MDx.c',
'platform/drivers/NVM/nvmem_MDUV3x0.c',
'platform/drivers/ADC/ADC1_MDx.c',
- 'platform/drivers/tones/toneGenerator_MDx.c',
+ 'platform/drivers/tones/toneGenerator_MDx.cpp',
'platform/drivers/baseband/radio_UV3x0.c',
'platform/drivers/GPS/GPS_MDx.cpp',
'platform/targets/MD-UV3x0/platform.c',
@@ -195,7 +195,7 @@ mduv3x0_def = def + stm32f405_def + {'PLATFORM_MDUV3x0': ''}
## TYT MD-9600
md9600_src = src + stm32f405_src + ['platform/targets/MD-9600/platform.c',
- 'platform/drivers/tones/toneGenerator_MDx.c']
+ 'platform/drivers/tones/toneGenerator_MDx.cpp']
md9600_inc = inc + stm32f405_inc + ['platform/targets/MD-9600']
md9600_def = def + stm32f405_def + {'PLATFORM_MD9600': ''}
diff --git a/platform/drivers/tones/toneGenerator_MDx.c b/platform/drivers/tones/toneGenerator_MDx.c
deleted file mode 100644
index 43eda67b..00000000
--- a/platform/drivers/tones/toneGenerator_MDx.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2020 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 "toneGenerator_MDx.h"
-#include
-#include
-
-/*
- * Sine table for PWM-based sinewave generation, containing 256 samples over one
- * period of a 64Hz sinewave. This gives a PWM base frequency of 16.384kHz.
- */
-static const uint8_t sineTable[] =
-{
- 128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,
- 185,188,190,193,196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,
- 230,232,234,235,237,238,240,241,243,244,245,246,248,249,250,250,251,252,253,
- 253,254,254,254,255,255,255,255,255,255,255,254,254,254,253,253,252,251,250,
- 250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,
- 220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,
- 170,167,165,162,158,155,152,149,146,143,140,137,134,131,128,124,121,118,115,
- 112,109,106,103,100,97,93,90,88,85,82,79,76,73,70,67,65,62,59,57,54,52,49,47,
- 44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10,9,7,6,5,5,4,3,2,
- 2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,
- 25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88,
- 90,93,97,100,103,106,109,112,115,118,121,124
-};
-
-/*
- * Correction factor to compensate for the (slight) difference between the exact
- * sampling frequency of the sine table and the PWM frequency generated by the
- * timer. This difference causes a frequency error in the resulting output of
- * both CTCSS and "beep" signals.
- * To compensate for this, simply multiply the target frequency by this
- * correction factor.
- */
-const float freqCorrFactor = 16384.0f/16406.25;
-const uint32_t baseSineFreq = 64;
-
-uint32_t toneTableIndex = 0; /* Current sine table index for CTCSS generator */
-uint32_t toneTableIncr = 0; /* CTCSS sine table index increment per tick */
-
-uint32_t beepTableIndex = 0; /* Current sine table index for "beep" generator */
-uint32_t beepTableIncr = 0; /* "beep" sine table index increment per tick */
-uint32_t beepTimerCount = 0; /* Downcounter for timed "beep" */
-
-/* Name-mangled function name, for C++ compatibility */
-void __attribute__((used)) _Z15TIM3_IRQHandlerv()
-{
- toneTableIndex += toneTableIncr;
- beepTableIndex += beepTableIncr;
-
- TIM3->CCR2 = sineTable[(toneTableIndex >> 16) & 0xFF];
- TIM3->CCR3 = sineTable[(beepTableIndex >> 16) & 0xFF];
- TIM3->SR = 0;
-
- if(beepTimerCount > 0)
- {
- beepTimerCount--;
- if(beepTimerCount == 0)
- {
- TIM3->CCER &= ~TIM_CCER_CC3E;
- }
- }
-
- /* Shutdown timer if both compare channels are inactive */
- if((TIM3->CCER & (TIM_CCER_CC2E | TIM_CCER_CC3E)) == 0)
- {
- TIM3->CR1 &= ~TIM_CR1_CEN;
- }
-}
-
-void toneGen_init()
-{
- /*
- * Configure GPIOs:
- * - CTCSS output is on PC7 (on MD380), that is TIM3-CH2, AF2
- * - "beep" output is on PC8 (on MD380), that is TIM3-CH3, AF2
- */
- gpio_setMode(CTCSS_OUT, ALTERNATE);
- gpio_setMode(BEEP_OUT, ALTERNATE);
- gpio_setAlternateFunction(CTCSS_OUT, 2);
- gpio_setAlternateFunction(BEEP_OUT, 2);
-
- /*
- * Timer configuration:
- * - APB1 frequency = 42MHz but timer run at twice of this frequency: with
- * 1:20 prescaler we have Ftick = 4.2MHz
- * - ARR = 255 (8-bit PWM), gives an update rate of 16.406kHz
- * - Nominal update rate is 16.384kHz -> error = +22.25Hz
- */
- RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
- __DSB();
-
- TIM3->ARR = 0xFF;
- TIM3->PSC = 19;
- TIM3->CCMR1 = TIM_CCMR1_OC2M_2 /* CH2 in PWM mode 1, preload enabled */
- | TIM_CCMR1_OC2M_1
- | TIM_CCMR1_OC2PE;
- TIM3->CCMR2 = TIM_CCMR2_OC3M_2 /* The same for CH3 */
- | TIM_CCMR2_OC3M_1
- | TIM_CCMR2_OC3PE;
- TIM3->DIER |= TIM_DIER_UIE; /* Interrupt on counter update */
- TIM3->CR1 |= TIM_CR1_ARPE; /* Enable auto preload on reload */
-
- NVIC_SetPriority(TIM3_IRQn, 10);
- NVIC_EnableIRQ(TIM3_IRQn);
-}
-
-void toneGen_terminate()
-{
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM3EN;
- __DSB();
-
- gpio_setMode(CTCSS_OUT, INPUT);
- gpio_setMode(BEEP_OUT, INPUT);
-}
-
-void toneGen_setToneFreq(float toneFreq)
-{
- /*
- * Convert to 16.16 fixed point number, then divide by the frequency of
- * sinewave stored in the PWM table
- */
- float dividend = toneFreq * freqCorrFactor * 65536.0f;
- toneTableIncr = ((uint32_t) dividend)/baseSineFreq;
-}
-
-void toneGen_toneOn()
-{
- TIM3->CCER |= TIM_CCER_CC2E;
- TIM3->CR1 |= TIM_CR1_CEN;
-}
-
-void toneGen_toneOff()
-{
- TIM3->CCER &= ~TIM_CCER_CC2E;
-}
-
-void toneGen_setBeepFreq(float beepFreq)
-{
- float dividend = beepFreq * freqCorrFactor * 65536.0f;
- beepTableIncr = ((uint32_t) dividend)/baseSineFreq;
-}
-
-void toneGen_beepOn()
-{
- TIM3->CCER |= TIM_CCER_CC3E;
- TIM3->CR1 |= TIM_CR1_CEN;
-}
-
-void toneGen_beepOff()
-{
- TIM3->CCER &= ~TIM_CCER_CC3E;
-}
-
-void toneGen_timedBeep(uint16_t duration)
-{
- /*
- * Duration is in milliseconds, while counter update rate is 16.406kHz.
- * Thus, the value for downcounter is (duration * 16.406)/1000.
- */
- beepTimerCount = (duration * 16406)/1000;
- TIM3->CCER |= TIM_CCER_CC3E;
- TIM3->CR1 |= TIM_CR1_CEN;
-}
diff --git a/platform/drivers/tones/toneGenerator_MDx.cpp b/platform/drivers/tones/toneGenerator_MDx.cpp
new file mode 100644
index 00000000..f8eea958
--- /dev/null
+++ b/platform/drivers/tones/toneGenerator_MDx.cpp
@@ -0,0 +1,339 @@
+/***************************************************************************
+ * Copyright (C) 2020 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 "toneGenerator_MDx.h"
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+/*
+ * Sine table for PWM-based sinewave generation, containing 256 samples over one
+ * period of a 35Hz sinewave. This gives a PWM base frequency of 8.96kHz.
+ */
+static const uint8_t sineTable[] =
+{
+ 128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,
+ 185,188,190,193,196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,
+ 230,232,234,235,237,238,240,241,243,244,245,246,248,249,250,250,251,252,253,
+ 253,254,254,254,255,255,255,255,255,255,255,254,254,254,253,253,252,251,250,
+ 250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,
+ 220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,
+ 170,167,165,162,158,155,152,149,146,143,140,137,134,131,128,124,121,118,115,
+ 112,109,106,103,100,97,93,90,88,85,82,79,76,73,70,67,65,62,59,57,54,52,49,47,
+ 44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10,9,7,6,5,5,4,3,2,
+ 2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,
+ 25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,
+ 88,90,93,97,100,103,106,109,112,115,118,121,124
+};
+
+static const uint32_t baseSineFreq = 35;
+
+uint32_t toneTableIndex = 0; /* Current sine table index for CTCSS generator */
+uint32_t toneTableIncr = 0; /* CTCSS sine table index increment per tick */
+
+uint32_t beepTableIndex = 0; /* Current sine table index for "beep" generator */
+uint32_t beepTableIncr = 0; /* "beep" sine table index increment per tick */
+uint32_t beepTimerCount = 0; /* Downcounter for timed "beep" */
+uint8_t beepVolume = 0; /* "beep" volume level */
+
+bool tonesLocked = false; /* If true tone channel is in use by FSK/playback */
+
+using namespace miosix;
+Thread *dmaWaiting = 0;
+
+/*
+ * TIM14 interrupt handler, used to manage generation of CTCSS and "beep" tones.
+ */
+void __attribute__((used)) TIM8_TRG_COM_TIM14_IRQHandler()
+{
+ TIM14->SR = 0;
+
+ toneTableIndex += toneTableIncr;
+ beepTableIndex += beepTableIncr;
+
+ TIM3->CCR2 = sineTable[(toneTableIndex >> 16) & 0xFF];
+
+ if(!tonesLocked)
+ {
+ TIM3->CCR3 = (sineTable[(beepTableIndex >> 16) & 0xFF] * beepVolume) >> 8;
+ }
+
+ if(beepTimerCount > 0)
+ {
+ beepTimerCount--;
+ if(beepTimerCount == 0)
+ {
+ TIM3->CCER &= ~TIM_CCER_CC3E;
+ }
+ }
+
+ /* Shutdown timers if both compare channels are inactive */
+ if((TIM3->CCER & (TIM_CCER_CC2E | TIM_CCER_CC3E)) == 0)
+ {
+ TIM3->CR1 &= ~TIM_CR1_CEN;
+ TIM14->CR1 &= ~TIM_CR1_CEN;
+ }
+}
+
+/*
+ * DMA1 Stream2 interrupt handler, for audio playback and FSK modulation.
+ */
+void __attribute__((used)) DMA_Handler()
+{
+ DMA1->LIFCR |= DMA_LIFCR_CTCIF2 | DMA_LIFCR_CTEIF2;
+
+ if(dmaWaiting == 0) return;
+ dmaWaiting->IRQwakeup();
+ if(dmaWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority())
+ Scheduler::IRQfindNextThread();
+ dmaWaiting = 0;
+}
+
+void __attribute__((naked)) DMA1_Stream2_IRQHandler()
+{
+ saveContext();
+ asm volatile("bl _Z11DMA_Handlerv");
+ restoreContext();
+}
+
+void toneGen_init()
+{
+ /*
+ * Configure GPIOs:
+ * - CTCSS output is on PC7 (on MD380), that is TIM3-CH2, AF2
+ * - "beep" output is on PC8 (on MD380), that is TIM3-CH3, AF2
+ */
+ gpio_setMode(CTCSS_OUT, ALTERNATE);
+ gpio_setMode(BEEP_OUT, ALTERNATE);
+ gpio_setAlternateFunction(CTCSS_OUT, 2);
+ gpio_setAlternateFunction(BEEP_OUT, 2);
+
+ /*
+ * TIM3 configuration:
+ * - APB1 frequency = 42MHz but timer run at twice of this frequency: with
+ * 1:3 prescaler we have Ftick = 28MHz
+ * - ARR = 255 (8-bit PWM), gives a PWM frequency of 109.375kHz
+ */
+ RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
+ __DSB();
+
+ TIM3->ARR = 0xFF;
+ TIM3->PSC = 2;
+ TIM3->CCMR1 = TIM_CCMR1_OC2M_2 /* CH2 in PWM mode 1, preload enabled */
+ | TIM_CCMR1_OC2M_1
+ | TIM_CCMR1_OC2PE;
+ TIM3->CCMR2 = TIM_CCMR2_OC3M_2 /* The same for CH3 */
+ | TIM_CCMR2_OC3M_1
+ | TIM_CCMR2_OC3PE;
+ TIM3->CR1 |= TIM_CR1_ARPE; /* Enable auto preload on reload */
+
+ /*
+ * TIM14 configuration:
+ * - APB1 frequency = 42MHz but timer run at twice of this frequency.
+ * - ARR = 9375 gives an update rate of 8.96kHz
+ */
+ RCC->APB1ENR |= RCC_APB1ENR_TIM14EN;
+ __DSB();
+
+ TIM14->PSC = 0; /* 1:1 prescaler */
+ TIM14->ARR = 9375;
+ TIM14->CNT = 0;
+ TIM14->EGR = TIM_EGR_UG; /* Update registers */
+ TIM14->DIER = TIM_DIER_UIE; /* Interrupt on counter update */
+
+ NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 10);
+ NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
+}
+
+void toneGen_terminate()
+{
+ RCC->APB1ENR &= ~(RCC_APB1ENR_TIM3EN |
+ RCC_APB1ENR_TIM14EN |
+ RCC_APB1ENR_TIM7EN);
+ RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA1EN;
+ __DSB();
+
+ dmaWaiting->wakeup();
+
+ gpio_setMode(CTCSS_OUT, INPUT);
+ gpio_setMode(BEEP_OUT, INPUT);
+}
+
+void toneGen_setToneFreq(float toneFreq)
+{
+ /*
+ * Convert to 16.16 fixed point number, then divide by the frequency of
+ * sinewave stored in the PWM table
+ */
+ float dividend = toneFreq * 65536.0f;
+ toneTableIncr = ((uint32_t) dividend)/baseSineFreq;
+}
+
+void toneGen_toneOn()
+{
+ TIM3->CCER |= TIM_CCER_CC2E;
+ TIM3->CR1 |= TIM_CR1_CEN;
+ TIM14->CR1 |= TIM_CR1_CEN;
+}
+
+void toneGen_toneOff()
+{
+ TIM3->CCER &= ~TIM_CCER_CC2E;
+}
+
+void toneGen_beepOn(const float beepFreq, const uint8_t volume,
+ const uint32_t duration)
+{
+ {
+ /* Do not generate "beep" if the PWM channel is busy, critical section */
+ FastInterruptDisableLock dLock;
+ if(tonesLocked) return;
+ }
+
+ float dividend = beepFreq * 65536.0f;
+ beepTableIncr = ((uint32_t) dividend)/baseSineFreq;
+ beepVolume = volume;
+
+ /*
+ * Duration is in milliseconds, while counter update rate is 8.96kHz.
+ * Thus, the value for downcounter is (duration * 8960)/1000.
+ */
+ beepTimerCount = (duration * 8960)/1000;
+
+ TIM3->CCER |= TIM_CCER_CC3E;
+ TIM3->CR1 |= TIM_CR1_CEN;
+ TIM14->CR1 |= TIM_CR1_CEN;
+}
+
+void toneGen_beepOff()
+{
+ /*
+ * Prevent disabling of tones if PWM channel is occupied by FSK/playback.
+ * Locking interrupts to avoid race conditions.
+ */
+ FastInterruptDisableLock dLock;
+ if(tonesLocked) return;
+ TIM3->CCER &= ~TIM_CCER_CC3E;
+}
+
+void toneGen_encodeAFSK1200(const uint8_t* buf, const size_t len)
+{
+ (void) buf;
+ (void) len;
+}
+
+void toneGen_playAudioStream(const uint16_t* buf, const size_t len,
+ const uint32_t sampleRate)
+{
+ if((buf == NULL) || (len == 0) || (sampleRate == 0)) return;
+
+ {
+ /* Critical section to avoid race conditions on "tonesLocked" */
+ FastInterruptDisableLock dLock;
+ tonesLocked = true;
+ beepTimerCount = 0;
+ }
+
+ RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
+ RCC->APB1ENR |= RCC_APB1ENR_TIM7EN;
+ __DSB();
+
+ /*
+ * Timebase for triggering of DMA transfers.
+ * Bus frequency is 84MHz.
+ */
+ uint32_t ratio = (84000000/sampleRate) - 1;
+
+ TIM7->CNT = 0;
+ TIM7->PSC = 0;
+ TIM7->ARR = ratio;
+ TIM7->EGR = TIM_EGR_UG;
+ TIM7->DIER = TIM_DIER_UDE;
+
+ /*
+ * DMA stream for sample transfer
+ */
+ DMA1_Stream2->NDTR = len;
+ DMA1_Stream2->PAR = ((uint32_t) &(TIM3->CCR3));
+ DMA1_Stream2->M0AR = ((uint32_t) buf);
+ DMA1_Stream2->CR = DMA_SxCR_CHSEL_0 /* Channel 1 */
+ | DMA_SxCR_PL /* Very high priority */
+ | DMA_SxCR_MSIZE_0 /* 16 bit source size */
+ | DMA_SxCR_PSIZE_0 /* 16 bit destination size */
+ | DMA_SxCR_MINC /* Increment source pointer */
+ | DMA_SxCR_DIR_0 /* Memory to peripheral */
+ | DMA_SxCR_TCIE /* Transfer complete interrupt */
+ | DMA_SxCR_TEIE /* Transfer error interrupt */
+ | DMA_SxCR_EN; /* Enable transfer */
+
+ NVIC_ClearPendingIRQ(DMA1_Stream2_IRQn);
+ NVIC_SetPriority(DMA1_Stream2_IRQn, 10);
+ NVIC_EnableIRQ(DMA1_Stream2_IRQn);
+
+ /* Enable compare channel */
+ TIM3->CCR3 = 0;
+ TIM3->CCER |= TIM_CCER_CC3E;
+ TIM3->CR1 |= TIM_CR1_CEN;
+
+ /* Start timer */
+ TIM7->CR1 = TIM_CR1_CEN;
+
+ /*
+ * Put the calling thread in waiting status until transfer completes
+ */
+ {
+ FastInterruptDisableLock dLock;
+ dmaWaiting = Thread::IRQgetCurrentThread();
+ do
+ {
+ Thread::IRQwait();
+ {
+ FastInterruptEnableLock eLock(dLock);
+ Thread::yield();
+ }
+ } while(dmaWaiting);
+ }
+
+ /* End of transfer, turn off TIM7 and DMA */
+ TIM7->CR1 = 0;
+ TIM3->CCER &= ~TIM_CCER_CC3E;
+
+ RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA1EN;
+ RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN;
+ __DSB();
+
+ /* Finally, unlock tones */
+ FastInterruptDisableLock dLock;
+ tonesLocked = false;
+}
+
+bool toneGen_toneStatus()
+{
+ /*
+ * Tone section is busy whenever CC3E bit in TIM3 CCER register is set.
+ * Lock interrupts before reading the register to avoid race conditions.
+ */
+ FastInterruptDisableLock dLock;
+ return (TIM3->CCER & TIM_CCER_CC3E) ? true : false;
+}
diff --git a/platform/drivers/tones/toneGenerator_MDx.h b/platform/drivers/tones/toneGenerator_MDx.h
index abfb321a..c2f727a8 100644
--- a/platform/drivers/tones/toneGenerator_MDx.h
+++ b/platform/drivers/tones/toneGenerator_MDx.h
@@ -22,12 +22,27 @@
#define TONE_GENERATOR_H
#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
/**
- * Tone generator for MDxx380 family, used for both CTCSS tones and user
- * interface "beeps".
- * This driver uses TIM3 of STM32F405 mcu in PWM mode to generate sinewaves
- * using a precomputed sine table.
+ * Tone generator for MDx family, used primarily for CTCSS tones and user
+ * interface "beeps". It also provides a means to encode AFSK/4FSK data and to
+ * reproduce arbitrary audio samples.
+ *
+ * WARNING: this driver implements a priority mechanism between "beeps", FSK
+ * modulation and audio playback. A request for FSK modulation or audio playback
+ * always interrupts the generation of a "beep" tone and generation of "beep"
+ * tones is disabled when FSK modulation or audio playback is active.
+ *
+ * This driver uses the following peripherals of the STM32F405 MCU:
+ * - TIM3 as high-frequency PWM timebase.
+ * - TIM14 as timebase for CTCSS and "beeps" through a sine table.
+ * - TIM7 and DMA1_Stream2 for AFSK, 4FSK and playback of audio streams.
*/
/**
@@ -42,9 +57,10 @@ void toneGen_terminate();
/**
* Set frequency for CTCSS tone generation.
+ *
* @param toneFreq: CTCSS tone frequency.
*/
-void toneGen_setToneFreq(float toneFreq);
+void toneGen_setToneFreq(const float toneFreq);
/**
* Activate generation of CTCSS tone.
@@ -57,26 +73,58 @@ void toneGen_toneOn();
void toneGen_toneOff();
/**
- * Set frequency for user interface "beep".
- * @param beepFreq: frequency of "beep" tone.
+ * Activate generation of a "beep" tone, with a given duration.
+ * Audio is sent both to the speaker and to the rtx baseband IC.
+ *
+ * @param beepFreq: frequency of "beep" tone in Hz.
+ * @param volume: "beep" output volume, range 0 - 255.
+ * @param duration: tone duration in milliseconds, zero for infinite duration.
*/
-void toneGen_setBeepFreq(float beepFreq);
+void toneGen_beepOn(const float beepFreq, const uint8_t volume,
+ const uint32_t duration);
/**
- * Activate generation of "beep" tone.
- */
-void toneGen_beepOn();
-
-/**
- * Terminate generation of "beep" tone.
+ * Terminate generation of "beep" tone, irrespectively of its duration.
*/
void toneGen_beepOff();
/**
- * Activate generation of "beep" tone with automatic termination after a given
- * amount of time.
- * @param duration: duration of "beep" tone, in milliseconds.
+ * Encode a given data stream using Bell 202 scheme at 1200 baud, sending the
+ * audio stream to both the speaker and the rtx baseband IC.
+ * This function blocks the execution flow until all data has been sent.
+ *
+ * @param buf: pointer to a buffer containing data to be encoded.
+ * @param len: length of the data buffer.
*/
-void toneGen_timedBeep(uint16_t duration);
+void toneGen_encodeAFSK1200(const uint8_t *buf, const size_t len);
+
+/**
+ * Reproduce an audio stream, sending audio stream to both the speaker and the
+ * rtx baseband IC.
+ * This function blocks the execution flow until all data has been sent.
+ *
+ * WARNING: the underlying peripheral accepts ONLY 16 bit transfers, while the
+ * PWM resolution is 8 bit. Thus, the sample buffer MUST be of uint16_t elements
+ * and, when filling it with data, one must remember that the upper 8 bit are
+ * DISCARDED.
+ *
+ * @param buf: pointer to a buffer containing the audio samples.
+ * @param len: length of the data buffer.
+ * @param sampleRate: sample rate of the audio stream in samples per second.
+ */
+void toneGen_playAudioStream(const uint16_t *buf, const size_t len,
+ const uint32_t sampleRate);
+
+/**
+ * Get the current status of the "beep"/AFSK/audio generator stage.
+ *
+ * @return true if the tone generator is busy.
+ */
+bool toneGen_toneStatus();
+
+
+#ifdef __cplusplus
+}
+#endif
#endif /* TONE_GENERATOR_H */