0
mirror of https://github.com/skuep/AIOC.git synced 2026-01-30 17:48:22 +00:00
2025-09-26 15:59:15 +02:00

163 lines
5.8 KiB
C

#include "io.h"
#include "fox_hunt.h"
#include "morse.h"
#define FOXHUNT_SAMPLERATE 48000
#define FOXHUNT_CARRIERLUT_SIZE (sizeof(carrierLUT)/sizeof(*carrierLUT))
static uint8_t isIdentifying = 0;
static uint8_t secondsPassed = 0;
static uint8_t isKeying = 0;
static uint16_t remainingCycles;
static uint8_t timingsLength;
static uint8_t timingsIndex = 0;
static uint8_t timingsLUT[FOXHUNT_MAX_TIMINGS];
static uint8_t sampleIndex = 0;
/* 750 Hz sine wave at 48000 Hz sample rate and 16 bits/sample */
static int16_t carrierLUT[] = {
0, 3252, 6482, 9658, 12728, 15671, 18458, 21062, 23457, 25618,
27525, 29158, 30502, 31542, 32269, 32675, 32757, 32513, 31945, 31061,
29867, 28377, 26605, 24568, 22287, 19785, 17086, 14217, 11207, 8085,
4883, 2173, -434, -3884, -6886, -10108, -13118, -15987, -18686, -21188,
-24569, -26606, -28378, -29868, -31062, -31946, -32514, -32758, -32676, -32270,
-31543, -30503, -29159, -27526, -25619, -23458, -21063, -18459, -15672, -12729,
-9659, -6483, -3253, -1
};
static void Timer_DAC_Init(void)
{
/* Calculate clock rate divider for requested sample rate with rounding */
uint32_t timerFreq = (HAL_RCC_GetHCLKFreq() == HAL_RCC_GetPCLK2Freq()) ? HAL_RCC_GetPCLK2Freq() : 2 * HAL_RCC_GetPCLK2Freq();
uint32_t rateDivider = (timerFreq + FOXHUNT_SAMPLERATE / 2) / FOXHUNT_SAMPLERATE;
/* Enable clock and (re-) initialize timer */
__HAL_RCC_TIM15_CLK_ENABLE();
/* TIM15_TRGO triggers DAC */
TIM15->CR1 &= ~TIM_CR1_CEN;
TIM15->CR1 = TIM_CLOCKDIVISION_DIV1 | TIM_COUNTERMODE_UP | TIM_AUTORELOAD_PRELOAD_ENABLE;
TIM15->CR2 = TIM_TRGO_UPDATE;
TIM15->PSC = 0;
TIM15->ARR = rateDivider - 1;
TIM15->EGR = TIM_EGR_UG;
TIM15->DIER = TIM_DIER_UIE;
TIM15->CR1 |= TIM_CR1_CEN;
NVIC_SetPriority(TIM15_IRQn, AIOC_IRQ_PRIO_AUDIO);
}
static void DAC_Init(void)
{
__HAL_RCC_DAC1_CLK_ENABLE();
/* Make sure DAC is disabled */
DAC->CR = 0x00;
/* Select TIM15 TRGO as trigger and enable DAC */
DAC->CR = (0x3 << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1;
/* Output VDD/2 */
DAC1->DHR12L1 = 32768;
}
void FoxHunt_Init(void) {
char messageBuffer[FOXHUNT_MAX_CHARS] = {
/* Read the ID from the settings registers */
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG0, CHAR00),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG0, CHAR01),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG0, CHAR02),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG0, CHAR03),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG1, CHAR04),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG1, CHAR05),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG1, CHAR06),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG1, CHAR07),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG2, CHAR08),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG2, CHAR09),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG2, CHAR10),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG2, CHAR11),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG3, CHAR12),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG3, CHAR13),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG3, CHAR14),
SETTINGS_GET(SETTINGS_REG_FOXHUNT_MSG3, CHAR15),
};
timingsLength = Morse_GenerateTimings(messageBuffer, FOXHUNT_MAX_CHARS, timingsLUT, FOXHUNT_MAX_TIMINGS);
if (SETTINGS_GET(SETTINGS_REG_FOXHUNT_CTRL, INTERVAL) != 0) {
/* Set up the DAC and timer. Note, this needs to happen after the "regular" USB Audio Subsystem Init,
* to overwrite their DAC configuration for our purpose here. */
Timer_DAC_Init();
DAC_Init();
/* Make sure the TIM15 IRQ is enabled */
NVIC_EnableIRQ(TIM15_IRQn);
}
}
void FoxHunt_Tick(void) {
secondsPassed++;
if ((SETTINGS_GET(SETTINGS_REG_FOXHUNT_CTRL, INTERVAL) != 0) &&
(secondsPassed >= SETTINGS_GET(SETTINGS_REG_FOXHUNT_CTRL, INTERVAL)) &&
(isIdentifying == 0)) {
secondsPassed = 0;
IO_PTTAssert(IO_PTT_MASK_PTT1);
isIdentifying = 1;
timingsIndex = 0;
remainingCycles = timingsLUT[timingsIndex] * ((uint32_t) (MORSE_UNIT_LENGTH * FOXHUNT_SAMPLERATE) / SETTINGS_GET(SETTINGS_REG_FOXHUNT_CTRL, WPM));
isKeying = 0;
}
}
void TIM15_IRQHandler(void)
{
if (TIM15->SR & TIM_SR_UIF) {
TIM15->SR = (uint32_t) ~TIM_SR_UIF;
int16_t sample = 0x0000;
if (isIdentifying) {
/* If the key is down, pull samples from our sine waveform */
if (isKeying) {
sample = carrierLUT[sampleIndex++];
if (sampleIndex == FOXHUNT_CARRIERLUT_SIZE) {
sampleIndex = 0;
}
}
/* state machine for morse output
* we ssume that we alternate between a sine wave and silence
* timings[] has the amount of time we spend for each element
*/
remainingCycles--;
if (remainingCycles == 0) {
timingsIndex++;
if (timingsIndex == timingsLength) {
/* All done IDing */
isIdentifying = 0;
IO_PTTDeassert(IO_PTT_MASK_PTT1);
} else {
/* Move on to the next timing */
remainingCycles = timingsLUT[timingsIndex] * ((uint32_t) (MORSE_UNIT_LENGTH * FOXHUNT_SAMPLERATE) / SETTINGS_GET(SETTINGS_REG_FOXHUNT_CTRL, WPM));
/* if we were silent start making noise, if we were making noise be silent */
isKeying = isKeying == 0 ? 1 : 0;
}
}
}
/* Get volume */
uint16_t volume = SETTINGS_GET(SETTINGS_REG_FOXHUNT_CTRL, VOLUME);
/* Scale with 16-bit unsigned volume and round */
sample = (int16_t) (((int32_t) sample * volume + (sample > 0 ? 32768 : -32768)) / 65536);
/* Load DAC holding register with sample */
DAC1->DHR12L1 = ((int32_t) sample + 32768) & 0xFFFFU;
}
}