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 */