diff options
-rw-r--r-- | src/common/includes/Audio/audio.h (renamed from src/fsm/audio.h) | 36 | ||||
-rw-r--r-- | src/common/includes/Audio/cw.h (renamed from src/fsm/cw.h) | 0 | ||||
-rw-r--r-- | src/common/includes/GPIO/i2c.h (renamed from src/fsm/i2c.h) | 0 | ||||
-rw-r--r-- | src/common/src/Audio/audio.c | 32 | ||||
-rw-r--r-- | src/common/src/Audio/cw.c (renamed from src/fsm/cw.c) | 23 | ||||
-rw-r--r-- | src/common/src/Core/common.c | 9 | ||||
-rw-r--r-- | src/common/src/Core/main.c | 106 | ||||
-rw-r--r-- | src/fsm/common.c | 231 | ||||
-rw-r--r-- | src/simulator/Makefile | 2 | ||||
-rw-r--r-- | src/simulator/src/Audio/audio.c | 140 | ||||
-rw-r--r-- | src/simulator/src/Audio/cw.c | 32 | ||||
-rw-r--r-- | src/simulator/src/Core/main.c | 2 | ||||
-rw-r--r-- | src/simulator/src/Gui/gui.c | 69 | ||||
-rw-r--r-- | src/stm32f/src/Audio/audio.c (renamed from src/fsm/audio.c) | 132 | ||||
-rw-r--r-- | src/stm32f/src/Audio/cw.c | 4 | ||||
-rw-r--r-- | src/stm32f/src/GPIO/i2c.c (renamed from src/fsm/i2c.c) | 7 |
16 files changed, 430 insertions, 395 deletions
diff --git a/src/fsm/audio.h b/src/common/includes/Audio/audio.h index 35f3f65..006f82e 100644 --- a/src/fsm/audio.h +++ b/src/common/includes/Audio/audio.h @@ -6,37 +6,37 @@ typedef void AudioCallbackFunction(void *context,int buffer); -#define Audio8000HzSettings 256,5,12,1 -#define Audio16000HzSettings 213,2,13,0 -#define Audio32000HzSettings 213,2,6,1 -#define Audio48000HzSettings 258,3,3,1 -#define Audio96000HzSettings 344,2,3,1 -#define Audio22050HzSettings 429,4,9,1 -#define Audio44100HzSettings 271,2,6,0 -#define AudioVGAHSyncSettings 419,2,13,0 // 31475.3606. Actual VGA timer is 31472.4616. +#define Audio8000HzSettings 256,5,12,1,8000 +#define Audio16000HzSettings 213,2,13,0,16000 +#define Audio32000HzSettings 213,2,6,1,32000 +#define Audio48000HzSettings 258,3,3,1,48000 +#define Audio96000HzSettings 344,2,3,1,96000 +#define Audio22050HzSettings 429,4,9,1,22050 +#define Audio44100HzSettings 271,2,6,0,44100 +#define AudioVGAHSyncSettings 419,2,13,0,31475 // 31475.3606. Actual VGA timer is 31472.4616. #define AUDIO_BUF_LEN 4096 // Initialize and power up audio hardware. Use the above defines for the parameters. // Can probably only be called once. -void InitializeAudio(int plln,int pllr,int i2sdiv,int i2sodd); +void audio_initialize(int plln,int pllr,int i2sdiv,int i2sodd, int rate); // Power up and down the audio hardware. -void AudioOn(); -void AudioOff(); +void audio_on(); +void audio_off(); // Set audio volume in steps of 0.5 dB. 0xff is +12 dB. -void SetAudioVolume(int volume); +void audio_set_volume(int volume); // Output one audio sample directly to the hardware without using DMA. -void OutputAudioSample(int16_t sample); -void OutputAudioSampleWithoutBlocking(int16_t sample); +void audio_output_sample(int16_t sample); +void audio_output_sample_without_blocking(int16_t sample); // Start and stop audio playback using DMA. // Callback is optional, and called whenever a new buffer is needed. -void PlayAudioWithCallback(AudioCallbackFunction *callback,void *context); -void StopAudio(); +void audio_play_with_callback(AudioCallbackFunction *callback,void *context); +void audio_stop(); // Provide a new buffer to the audio DMA. Output is double buffered, so // at least two buffers must be maintained by the program. It is not allowed @@ -44,7 +44,7 @@ void StopAudio(); // invocation. // Buffers must reside in DMA1-accessible memory, that is, the 128k RAM bank, // or flash. -void ProvideAudioBuffer(void *samples,int numsamples); -bool ProvideAudioBufferWithoutBlocking(void *samples,int numsamples); +void audio_provide_buffer(void *samples,int numsamples); +bool audio_provide_buffer_without_blocking(void *samples,int numsamples); #endif diff --git a/src/fsm/cw.h b/src/common/includes/Audio/cw.h index 384918d..384918d 100644 --- a/src/fsm/cw.h +++ b/src/common/includes/Audio/cw.h diff --git a/src/fsm/i2c.h b/src/common/includes/GPIO/i2c.h index 109213b..109213b 100644 --- a/src/fsm/i2c.h +++ b/src/common/includes/GPIO/i2c.h diff --git a/src/common/src/Audio/audio.c b/src/common/src/Audio/audio.c new file mode 100644 index 0000000..3d3dbf4 --- /dev/null +++ b/src/common/src/Audio/audio.c @@ -0,0 +1,32 @@ +#include "Audio/audio.h" + +#include <stdlib.h> + +static void audio_write_register(uint8_t address, uint8_t value); +static void audio_start_dma_and_request_buffers(); +static void audio_stop_dma(); + +static AudioCallbackFunction *callback_function; +static void *callback_context; +static int16_t * volatile next_buffer_samples; +static volatile int next_buffer_length; +static volatile int buffer_number; +static volatile bool dma_running; + +void audio_initialize_platform(int plln, int pllr, int i2sdiv, int i2sodd, int rate); + +void audio_initialize(int plln, int pllr, int i2sdiv, int i2sodd, int rate) { + + // Intitialize state. + callback_function = NULL; + callback_context = NULL; + next_buffer_samples = NULL; + next_buffer_length = 0; + buffer_number = 0; + dma_running = false; + + audio_initialize_platform(plln, pllr, i2sdiv, i2sodd, rate); + + audio_set_volume(0xff); + +} diff --git a/src/fsm/cw.c b/src/common/src/Audio/cw.c index 6d54778..3f3b97d 100644 --- a/src/fsm/cw.c +++ b/src/common/src/Audio/cw.c @@ -34,11 +34,16 @@ * audio_queue */ -#include "cw.h" -#include "common.h" +#include "Audio/cw.h" +#include "Core/common.h" +#include "Audio/audio.h" + +#ifdef SIMULATOR +#define arm_cos_f32 cosf +#define arm_sin_f32 sinf +#else #include "arm_math.h" -#include "audio.h" -#include "debug.h" +#endif /* Kernel includes. */ #include "FreeRTOS.h" @@ -367,6 +372,8 @@ int cw_psk31_push_message(const char* text, int dit_duration, int frequency) xQueueSendToBack(cw_msg_queue, &msg, portMAX_DELAY); /* Send Message */ + cw_message_sent(msg.message); + return 1; } @@ -461,6 +468,10 @@ static int16_t cw_generate_audio(float omega, int i, int t) } else { cw_generate_audio_ampl -= cw_generate_audio_ampl / 64.0f; + + if (cw_generate_audio_ampl < 0) { + cw_generate_audio_ampl = 0; + } } cw_generate_audio_nco += omega; @@ -515,7 +526,7 @@ static void cw_psk31_task(void *pvParameters) cw_transmit_ongoing = 1; // Audio should be off, turn it on - AudioOn(); + audio_on(); if (cw_fill_msg_current.dit_duration) { cw_psk31_buffer_len = cw_text_to_on_buffer( @@ -582,7 +593,7 @@ static void cw_psk31_task(void *pvParameters) cw_transmit_ongoing = 0; // Turn off audio to save power - AudioOff(); + audio_off(); } } } diff --git a/src/common/src/Core/common.c b/src/common/src/Core/common.c index c31bbf8..476d1b4 100644 --- a/src/common/src/Core/common.c +++ b/src/common/src/Core/common.c @@ -38,8 +38,7 @@ static uint16_t lfsr; static void common_increase_timestamp(TimerHandle_t t); -int find_last_sunday(const struct tm* time) -{ +int find_last_sunday(const struct tm* time) { struct tm t = *time; // the last sunday can never be before the 20th @@ -68,8 +67,7 @@ int find_last_sunday(const struct tm* time) * 1 if true * -1 in case of error */ -static int is_dst(const struct tm *time) -{ +static int is_dst(const struct tm *time) { /* DST from 01:00 UTC on last Sunday in March * to 01:00 UTC on last Sunday in October */ @@ -114,8 +112,7 @@ static int is_dst(const struct tm *time) } } -int local_time(struct tm *time) -{ +int local_time(struct tm *time) { const int local_time_offset=1; // hours int valid = gps_utctime(time); diff --git a/src/common/src/Core/main.c b/src/common/src/Core/main.c index 1a72e32..7760d6c 100644 --- a/src/common/src/Core/main.c +++ b/src/common/src/Core/main.c @@ -34,8 +34,8 @@ #include "semphr.h" /* Includes */ -/* #include "audio.h" */ -/* #include "cw.h" */ +#include "Audio/audio.h" +#include "Audio/cw.h" /* #include "pio.h" */ /* #include "i2c.h" */ #include "GPS/gps.h" @@ -119,11 +119,11 @@ static void test_task(void *pvParameters) { if (i == 0) { i = 1; - leds_turn_on(LED_RED); + leds_turn_on(LED_GREEN); } else { i = 0; - leds_turn_off(LED_RED); + leds_turn_off(LED_GREEN); } } @@ -134,8 +134,8 @@ static void test_task(void *pvParameters) { // already running when calling the init functions. static void launcher_task(void *pvParameters) { - /* usart_debug_puts("CW init\r\n"); */ - /* cw_psk31_init(16000); */ + usart_debug_puts("CW init\r\n"); + cw_psk31_init(16000); /* */ /* usart_debug_puts("PIO init\r\n"); */ /* pio_init(); */ @@ -143,17 +143,17 @@ static void launcher_task(void *pvParameters) /* usart_debug_puts("I2C init\r\n"); */ /* i2c_init(); */ /* */ - /* usart_debug_puts("common init\r\n"); */ - /* common_init(); */ - /* */ + usart_debug_puts("common init\r\n"); + common_init(); + usart_debug_puts("GPS init\r\n"); gps_init(); - /* */ + /* usart_debug_puts("DS18B20 init\r\n"); */ /* temperature_init(); */ /* */ /* usart_debug_puts("TaskButton init\r\n"); */ - /* */ + TaskHandle_t task_handle; /* xTaskCreate( */ /* detect_button_press, */ @@ -195,24 +195,24 @@ static void launcher_task(void *pvParameters) trigger_fault(FAULT_SOURCE_MAIN); } - /* usart_debug_puts("Audio init\r\n"); */ - /* */ - /* InitializeAudio(Audio16000HzSettings); */ - /* */ - /* usart_debug_puts("Audio set volume\r\n"); */ - /* SetAudioVolume(210); */ - /* */ - /* usart_debug_puts("Audio set callback\r\n"); */ - /* PlayAudioWithCallback(audio_callback, NULL); */ - /* */ - /* // By default, let's the audio off to save power */ - /* AudioOff(); */ + usart_debug_puts("Audio init\r\n"); + + audio_initialize(Audio16000HzSettings); + + usart_debug_puts("Audio set volume\r\n"); + audio_set_volume(210); + + usart_debug_puts("Audio set callback\r\n"); + audio_play_with_callback(audio_callback, NULL); + + // By default, let's the audio off to save power + audio_off(); usart_debug_puts("Init done.\r\n"); xTaskCreate( test_task, - "TaskFSM", + "Test task", 4*configMINIMAL_STACK_SIZE, (void*) NULL, tskIDLE_PRIORITY + 2UL, @@ -224,6 +224,10 @@ static void launcher_task(void *pvParameters) * for more info. */ + cw_psk31_push_message("HB9G HI - TESTING", 50, 440); + cw_psk31_push_message("HB9G HI AGAIN", 50, 440); + cw_psk31_push_message("HB9G 73", 50, 440); + while (1) { vTaskSuspend(NULL); } @@ -273,33 +277,33 @@ static void detect_button_press(void *pvParameters) /* } */ } -static void audio_callback(void* context, int select_buffer) -{ - /* static int16_t audio_buffer0[AUDIO_BUF_LEN]; */ - /* static int16_t audio_buffer1[AUDIO_BUF_LEN]; */ - /* int16_t *samples; */ - /* */ - /* if (select_buffer == 0) { */ - /* samples = audio_buffer0; */ - /* GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_RED); */ - /* select_buffer = 1; */ - /* } else { */ - /* samples = audio_buffer1; */ - /* GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_RED); */ - /* select_buffer = 0; */ - /* } */ - /* */ - /* size_t samples_len = cw_psk31_fill_buffer(samples, AUDIO_BUF_LEN); */ - /* */ - /* if (samples_len == 0) { */ - /* for (int i = 0; i < AUDIO_BUF_LEN; i++) { */ - /* samples[i] = 0; */ - /* } */ - /* */ - /* samples_len = AUDIO_BUF_LEN; */ - /* } */ - /* */ - /* ProvideAudioBufferWithoutBlocking(samples, samples_len); */ +static void audio_callback(void* context, int select_buffer) { + static int16_t audio_buffer0[AUDIO_BUF_LEN]; + static int16_t audio_buffer1[AUDIO_BUF_LEN]; + int16_t *samples; + + if (select_buffer == 0) { + samples = audio_buffer0; + leds_turn_off(LED_RED); + select_buffer = 1; + } else { + samples = audio_buffer1; + leds_turn_on(LED_RED); + select_buffer = 0; + } + + size_t samples_len = cw_psk31_fill_buffer(samples, AUDIO_BUF_LEN); + + if (samples_len == 0) { + for (int i = 0; i < AUDIO_BUF_LEN; i++) { + samples[i] = 0; + } + + samples_len = AUDIO_BUF_LEN; + } + + audio_provide_buffer_without_blocking(samples, samples_len); + } static struct tm gps_time; diff --git a/src/fsm/common.c b/src/fsm/common.c deleted file mode 100644 index 27c792f..0000000 --- a/src/fsm/common.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2016 Matthias P. Braendli - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*/ - -#include "common.h" -#include "usart.h" -#include "FreeRTOS.h" -#include "timers.h" -#include "gps.h" -#include <stm32f4xx.h> -#include <time.h> - -static uint64_t common_timestamp = 0; // milliseconds since startup -static TimerHandle_t common_timer; - -// The LFSR is used as random number generator -static const uint16_t lfsr_start_state = 0x12ABu; -static uint16_t lfsr; - -static void common_increase_timestamp(TimerHandle_t t); - -int find_last_sunday(const struct tm* time) -{ - struct tm t = *time; - - // the last sunday can never be before the 20th - t.tm_mday = 20; - - int last_sunday = 1; - - while (t.tm_mon == time->tm_mon) { - t.tm_mday++; - if (mktime(&t) == (time_t)-1) { - // TODO error - return -1; - } - - const int sunday = 0; - if (t.tm_wday == sunday) { - last_sunday = t.tm_mday; - } - } - - return last_sunday; -} - -/* Calculate if we are in daylight saving time. - * return 0 if false - * 1 if true - * -1 in case of error - */ -static int is_dst(const struct tm *time) -{ - /* DST from 01:00 UTC on last Sunday in March - * to 01:00 UTC on last Sunday in October - */ - const int march = 2; - const int october = 9; - if (time->tm_mon < march) { - return 0; - } - else if (time->tm_mon == march) { - int last_sunday = find_last_sunday(time); - if (last_sunday == -1) return -1; - - if (time->tm_mday < last_sunday) { - return 0; - } - else if (time->tm_mday == last_sunday) { - return (time->tm_hour < 1) ? 0 : 1; - } - else { - return 1; - } - } - else if (time->tm_mon > march && time->tm_mon < october) { - return 1; - } - else if (time->tm_mon == october) { - int last_sunday = find_last_sunday(time); - if (last_sunday == -1) return -1; - - if (time->tm_mday < last_sunday) { - return 1; - } - else if (time->tm_mday == last_sunday) { - return (time->tm_hour < 1) ? 1 : 0; - } - else { - return 0; - } - } - else { - return 0; - } -} - -int local_time(struct tm *time) -{ - const int local_time_offset=1; // hours - - int valid = gps_utctime(time); - - if (valid) { - time->tm_hour += local_time_offset; - - if (is_dst(time)) { - time->tm_hour++; - time->tm_isdst = 1; - } - - // Let mktime fix the struct tm *time - if (mktime(time) == (time_t)-1) { - // TODO inform about failure - valid = 0; - } - } - - return valid; -} - - -void common_init(void) -{ - common_timer = xTimerCreate("Timer", - portTICK_PERIOD_MS, - pdTRUE, // Auto-reload - NULL, // No unique id - common_increase_timestamp - ); - - xTimerStart(common_timer, 0); - - lfsr = lfsr_start_state; -} - -static void common_increase_timestamp(TimerHandle_t t) -{ - common_timestamp++; -} - -uint64_t timestamp_now(void) -{ - return common_timestamp; -} - - -// Return either 0 or 1, somewhat randomly -int random_bool(void) -{ - uint16_t bit; - - /* taps: 16 14 13 11; feedback polynomial: x^16 + x^14 + x^13 + x^11 + 1 */ - bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1; - lfsr = (lfsr >> 1) | (bit << 15); - - return bit; -} - -// For the debugger -static int faultsource = 0; -void trigger_fault(int source) -{ - usart_debug("Fatal: %d", source); - - __disable_irq(); - - faultsource = source; - - while (1) {} -} - -void hard_fault_handler_c(uint32_t *hardfault_args) -{ - uint32_t stacked_r0; - uint32_t stacked_r1; - uint32_t stacked_r2; - uint32_t stacked_r3; - uint32_t stacked_r12; - uint32_t stacked_lr; - uint32_t stacked_pc; - uint32_t stacked_psr; - - stacked_r0 = hardfault_args[0]; - stacked_r1 = hardfault_args[1]; - stacked_r2 = hardfault_args[2]; - stacked_r3 = hardfault_args[3]; - - stacked_r12 = hardfault_args[4]; - stacked_lr = hardfault_args[5]; - stacked_pc = hardfault_args[6]; - stacked_psr = hardfault_args[7]; - - usart_debug_puts("\n\n[Hard fault handler - all numbers in hex]\n"); - usart_debug("R0 = %x\n", stacked_r0); - usart_debug("R1 = %x\n", stacked_r1); - usart_debug("R2 = %x\n", stacked_r2); - usart_debug("R3 = %x\n", stacked_r3); - usart_debug("R12 = %x\n", stacked_r12); - usart_debug("LR [R14] = %x subroutine call return address\n", stacked_lr); - usart_debug("PC [R15] = %x program counter\n", stacked_pc); - usart_debug("PSR = %x\n", stacked_psr); - usart_debug("BFAR = %x\n", (*((volatile unsigned long *)(0xE000ED38)))); - usart_debug("CFSR = %x\n", (*((volatile unsigned long *)(0xE000ED28)))); - usart_debug("HFSR = %x\n", (*((volatile unsigned long *)(0xE000ED2C)))); - usart_debug("DFSR = %x\n", (*((volatile unsigned long *)(0xE000ED30)))); - usart_debug("AFSR = %x\n", (*((volatile unsigned long *)(0xE000ED3C)))); - usart_debug("SCB_SHCSR = %x\n", SCB->SHCSR); - - while (1); -} diff --git a/src/simulator/Makefile b/src/simulator/Makefile index 511b6e6..663570e 100644 --- a/src/simulator/Makefile +++ b/src/simulator/Makefile @@ -70,7 +70,7 @@ CWARNS += -Wmissing-prototypes CFLAGS += -m32 CFLAGS += -DDEBUG=1 -CFLAGS += -g -DUSE_STDIO=1 -D__GCC_POSIX__=1 -lX11 -lm -lGL -lm -lGLU +CFLAGS += -g -DUSE_STDIO=1 -D__GCC_POSIX__=1 -lX11 -lm -lGL -lm -lGLU -lpulse-simple -lpulse ifneq ($(shell uname), Darwin) CFLAGS += -pthread endif diff --git a/src/simulator/src/Audio/audio.c b/src/simulator/src/Audio/audio.c new file mode 100644 index 0000000..0d21305 --- /dev/null +++ b/src/simulator/src/Audio/audio.c @@ -0,0 +1,140 @@ +#include "../../../common/src/Audio/audio.c" + +#include <pulse/simple.h> +#include "FreeRTOS.h" +#include "task.h" + + +pa_simple *s = NULL; + +int current_buffer_length = 0; +int16_t * current_buffer_samples; + +static void audio_buffer_sender(void *args); + +extern char gui_audio_on; + +void audio_initialize_platform(int plln, int pllr, int i2sdiv, int i2sodd, int rate) { + + int error; + + static pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 0, + .channels = 1 + }; + + ss.rate = rate; + + if (s = pa_simple_new(NULL, "Glutte", PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error)) { + + } else { + printf("Pulseaudio playback init error\n"); + while(1); + } + + + TaskHandle_t task_handle; + xTaskCreate( + audio_buffer_sender, + "Audio buffer sender", + configMINIMAL_STACK_SIZE, + (void*) NULL, + tskIDLE_PRIORITY + 2UL, + &task_handle); + +} + +static void audio_buffer_sender(void *args) { + + while(1) { + + if (current_buffer_length != 0) { + pa_simple_write(s, current_buffer_samples, current_buffer_length * 2, NULL); + current_buffer_length = 0; + audio_buffer_sent(); + } + + taskYIELD(); + } + +} + +void audio_buffer_sent() { + + if (next_buffer_samples) { + audio_start_dma_and_request_buffers(); + } else { + dma_running = false; + } + +} + +void audio_on() { + gui_audio_on = 1; +} + +void audio_off() { + gui_audio_on = 0; +} + +void audio_set_volume(int volume) { +} + + +void audio_output_sample_without_blocking(int16_t sample) { +} + +void audio_play_with_callback(AudioCallbackFunction *callback, void *context) { + audio_stop_dma(); + + callback_function = callback; + callback_context = context; + buffer_number = 0; + + if (callback_function) + callback_function(callback_context, buffer_number); +} + +void audio_stop() { + audio_stop_dma(); + callback_function = NULL; +} + +void audio_provide_buffer(void *samples, int numsamples) { + while (!audio_provide_buffer_without_blocking(samples, numsamples)) + __asm__ volatile ("nop"); +} + +bool audio_provide_buffer_without_blocking(void *samples, int numsamples) { + if (next_buffer_samples) + return false; + + next_buffer_samples = samples; + next_buffer_length = numsamples; + + if (!dma_running) + audio_start_dma_and_request_buffers(); + + return true; +} + +static void audio_start_dma_and_request_buffers() { + + current_buffer_length = next_buffer_length; + current_buffer_samples = next_buffer_samples; + + // Update state. + next_buffer_samples = NULL; + buffer_number ^= 1; + dma_running = true; + + // Invoke callback if it exists to queue up another buffer. + if (callback_function) + callback_function(callback_context, buffer_number); +} + +static void audio_stop_dma() { + dma_running = false; +} + diff --git a/src/simulator/src/Audio/cw.c b/src/simulator/src/Audio/cw.c new file mode 100644 index 0000000..0f37be4 --- /dev/null +++ b/src/simulator/src/Audio/cw.c @@ -0,0 +1,32 @@ +#include "../../../common/src/Audio/cw.c" + +extern char gui_cw_text[4096]; +int gui_cw_text_pointer = 0; + +void cw_move_buffer_up() { + + for (int i = 0; i <= 4010; i++) { + gui_cw_text[i] = gui_cw_text[i + 10]; + gui_cw_text[i + 1] = '\0'; + } + + gui_cw_text_pointer -= 10; + +} +void cw_message_sent(const char* str) { + + while(*str) { + gui_cw_text[gui_cw_text_pointer+1] = '\0'; + gui_cw_text[gui_cw_text_pointer] = *str; + gui_cw_text_pointer++; + + if (gui_cw_text_pointer >= 4000) { + cw_move_buffer_up(); + } + str++; + } + + gui_cw_text[gui_cw_text_pointer+1] = '\0'; + gui_cw_text[gui_cw_text_pointer] = '\n'; + gui_cw_text_pointer++; +} diff --git a/src/simulator/src/Core/main.c b/src/simulator/src/Core/main.c index 853ee83..088e344 100644 --- a/src/simulator/src/Core/main.c +++ b/src/simulator/src/Core/main.c @@ -58,7 +58,7 @@ char gui_gps_custom_day[4]; int gui_gps_custom_day_len; char gui_gps_custom_month[4]; int gui_gps_custom_month_len; -char gui_gps_custom_year[6]; +char gui_gps_custom_year[4]; int gui_gps_custom_year_len; static void thread_gui_gps(void *arg) { diff --git a/src/simulator/src/Gui/gui.c b/src/simulator/src/Gui/gui.c index 58bbb78..cd7e004 100644 --- a/src/simulator/src/Gui/gui.c +++ b/src/simulator/src/Gui/gui.c @@ -86,6 +86,14 @@ int gui_gps_custom_month_len = 2; char gui_gps_custom_year[4] = "16"; int gui_gps_custom_year_len = 2; + +/** + * Audio + **/ +char gui_audio_on = 0; +char gui_cw_text[4096]; + + struct XWindow { Display *dpy; Window win; @@ -314,12 +322,12 @@ int main_gui() { uart_send_txt_len = 0; } - nk_menubar_end(ctx); nk_layout_row_dynamic(ctx, 25, 1); - nk_label(ctx, "UART Output:", NK_TEXT_LEFT); + nk_menubar_end(ctx); + nk_layout_row_dynamic(ctx, 16, 1); char * current_pointer = uart_recv_txt; @@ -400,6 +408,63 @@ int main_gui() { } nk_end(ctx); + if (nk_begin(ctx, &layout, "Audio", nk_rect(160, 360, 100, 155), NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) { + + nk_layout_row_static(ctx, 20, 20, 3); + + struct nk_color color; + + nk_text(ctx, "", 0, NK_TEXT_LEFT); + nk_text(ctx, "", 0, NK_TEXT_LEFT); + nk_text(ctx, "", 0, NK_TEXT_LEFT); + + nk_text(ctx, "", 0, NK_TEXT_LEFT); + + color.r = 255; color.g = 255; color.b = 0; color.a = 255; + + if (gui_audio_on == 1) { + color.r = 0; + } else { + color.g = 0; + } + nk_button_color(ctx, color, NK_BUTTON_DEFAULT); + } + nk_end(ctx); + + + if (nk_begin(ctx, &layout, "CW", nk_rect(270, 360, 180, 155), NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) { + + nk_menubar_begin(ctx); + nk_layout_row_dynamic(ctx, 25, 1); + + nk_label(ctx, "CW Buffer:", NK_TEXT_LEFT); + + nk_menubar_end(ctx); + + nk_layout_row_dynamic(ctx, 16, 1); + + char * current_pointer = gui_cw_text; + int l = 0; + + while (*current_pointer != 0) { + + if (*current_pointer == '\n') { + if (l > 1) { + nk_text(ctx, current_pointer - l, l, NK_TEXT_LEFT); + } + current_pointer++; + l = 0; + } + current_pointer++; + l++; + } + + if (l > 1) { + nk_text(ctx, current_pointer - l, l, NK_TEXT_LEFT); + } + } + nk_end(ctx); + if (nk_begin(ctx, &layout, "GPS", nk_rect(460, 50, 200, 465), NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) { nk_layout_row_dynamic(ctx, 30, 1); diff --git a/src/fsm/audio.c b/src/stm32f/src/Audio/audio.c index 6ecea62..bdb2961 100644 --- a/src/fsm/audio.c +++ b/src/stm32f/src/Audio/audio.c @@ -1,32 +1,13 @@ -#include "audio.h" -#include "i2c.h" +#include "GPIO/i2c.h" #include "stm32f4xx_conf.h" #include "stm32f4xx.h" -#include <stdlib.h> +#include "../../../common/src/Audio/audio.c" -static void WriteRegister(uint8_t address, uint8_t value); -static void StartAudioDMAAndRequestBuffers(); -static void StopAudioDMA(); +void audio_initialize_platform(int plln, int pllr, int i2sdiv, int i2sodd, int rate) { -static AudioCallbackFunction *CallbackFunction; -static void *CallbackContext; -static int16_t * volatile NextBufferSamples; -static volatile int NextBufferLength; -static volatile int BufferNumber; -static volatile bool DMARunning; - -void InitializeAudio(int plln, int pllr, int i2sdiv, int i2sodd) { GPIO_InitTypeDef GPIO_InitStructure; - // Intitialize state. - CallbackFunction = NULL; - CallbackContext = NULL; - NextBufferSamples = NULL; - NextBufferLength = 0; - BufferNumber = 0; - DMARunning = false; - // Turn on peripherals. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); @@ -74,26 +55,24 @@ void InitializeAudio(int plln, int pllr, int i2sdiv, int i2sodd) { GPIO_SetBits(GPIOD, GPIO_Pin_4); // Configure codec. - WriteRegister(0x02, 0x01); // Keep codec powered off. - WriteRegister(0x04, 0xaf); // SPK always off and HP always on. + audio_write_register(0x02, 0x01); // Keep codec powered off. + audio_write_register(0x04, 0xaf); // SPK always off and HP always on. - WriteRegister(0x05, 0x81); // Clock configuration: Auto detection. - WriteRegister(0x06, 0x04); // Set slave mode and Philips audio standard. - - SetAudioVolume(0xff); + audio_write_register(0x05, 0x81); // Clock configuration: Auto detection. + audio_write_register(0x06, 0x04); // Set slave mode and Philips audio standard. // Power on the codec. - WriteRegister(0x02, 0x9e); + audio_write_register(0x02, 0x9e); // Configure codec for fast shutdown. - WriteRegister(0x0a, 0x00); // Disable the analog soft ramp. - WriteRegister(0x0e, 0x04); // Disable the digital soft ramp. + audio_write_register(0x0a, 0x00); // Disable the analog soft ramp. + audio_write_register(0x0e, 0x04); // Disable the digital soft ramp. - WriteRegister(0x27, 0x00); // Disable the limiter attack level. - WriteRegister(0x1f, 0x0f); // Adjust bass and treble levels. + audio_write_register(0x27, 0x00); // Disable the limiter attack level. + audio_write_register(0x1f, 0x0f); // Adjust bass and treble levels. - WriteRegister(0x1a, 0x0a); // Adjust PCM volume level. - WriteRegister(0x1b, 0x0a); + audio_write_register(0x1a, 0x0a); // Adjust PCM volume level. + audio_write_register(0x1b, 0x0a); // Disable I2S. SPI3 ->I2SCFGR = 0; @@ -114,78 +93,79 @@ void InitializeAudio(int plln, int pllr, int i2sdiv, int i2sodd) { } -void AudioOn() { - WriteRegister(0x02, 0x9e); +void audio_on() { + audio_write_register(0x02, 0x9e); SPI3 ->I2SCFGR = SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SCFG_1 | SPI_I2SCFGR_I2SE; // Master transmitter, Phillips mode, 16 bit values, clock polarity low, enable. } -void AudioOff() { - WriteRegister(0x02, 0x9f); +void audio_off() { + audio_write_register(0x02, 0x9f); SPI3 ->I2SCFGR = 0; } -void SetAudioVolume(int volume) { - WriteRegister(0x20, (volume + 0x19) & 0xff); - WriteRegister(0x21, (volume + 0x19) & 0xff); +void audio_set_volume(int volume) { + audio_write_register(0x20, (volume + 0x19) & 0xff); + audio_write_register(0x21, (volume + 0x19) & 0xff); } -void OutputAudioSample(int16_t sample) { +void audio_output_sample(int16_t sample) { while (!(SPI3 ->SR & SPI_SR_TXE )) ; SPI3 ->DR = sample; } -void OutputAudioSampleWithoutBlocking(int16_t sample) { + +void audio_output_sample_without_blocking(int16_t sample) { SPI3 ->DR = sample; } -void PlayAudioWithCallback(AudioCallbackFunction *callback, void *context) { - StopAudioDMA(); +void audio_play_with_callback(AudioCallbackFunction *callback, void *context) { + audio_stop_dma(); NVIC_EnableIRQ(DMA1_Stream7_IRQn); NVIC_SetPriority(DMA1_Stream7_IRQn, 5); SPI3 ->CR2 |= SPI_CR2_TXDMAEN; // Enable I2S TX DMA request. - CallbackFunction = callback; - CallbackContext = context; - BufferNumber = 0; + callback_function = callback; + callback_context = context; + buffer_number = 0; - if (CallbackFunction) - CallbackFunction(CallbackContext, BufferNumber); + if (callback_function) + callback_function(callback_context, buffer_number); } -void StopAudio() { - StopAudioDMA(); +void audio_stop() { + audio_stop_dma(); SPI3 ->CR2 &= ~SPI_CR2_TXDMAEN; // Disable I2S TX DMA request. NVIC_DisableIRQ(DMA1_Stream7_IRQn); - CallbackFunction = NULL; + callback_function = NULL; } -void ProvideAudioBuffer(void *samples, int numsamples) { - while (!ProvideAudioBufferWithoutBlocking(samples, numsamples)) +void audio_provide_buffer(void *samples, int numsamples) { + while (!audio_provide_buffer_without_blocking(samples, numsamples)) __asm__ volatile ("wfi"); } -bool ProvideAudioBufferWithoutBlocking(void *samples, int numsamples) { - if (NextBufferSamples) +bool audio_provide_buffer_without_blocking(void *samples, int numsamples) { + if (next_buffer_samples) return false; NVIC_DisableIRQ(DMA1_Stream7_IRQn); - NextBufferSamples = samples; - NextBufferLength = numsamples; + next_buffer_samples = samples; + next_buffer_length = numsamples; - if (!DMARunning) - StartAudioDMAAndRequestBuffers(); + if (!dma_running) + audio_start_dma_and_request_buffers(); NVIC_EnableIRQ(DMA1_Stream7_IRQn); return true; } -static void StartAudioDMAAndRequestBuffers() { +static void audio_start_dma_and_request_buffers() { // Configure DMA stream. DMA1_Stream7 ->CR = (0 * DMA_SxCR_CHSEL_0 ) | // Channel 0 (1 * DMA_SxCR_PL_0 ) | // Priority 1 @@ -194,42 +174,42 @@ static void StartAudioDMAAndRequestBuffers() { DMA_SxCR_MINC | // Increase memory address (1 * DMA_SxCR_DIR_0 ) | // Memory to peripheral DMA_SxCR_TCIE; // Transfer complete interrupt - DMA1_Stream7 ->NDTR = NextBufferLength; + DMA1_Stream7 ->NDTR = next_buffer_length; DMA1_Stream7 ->PAR = (uint32_t) &SPI3 ->DR; - DMA1_Stream7 ->M0AR = (uint32_t) NextBufferSamples; + DMA1_Stream7 ->M0AR = (uint32_t) next_buffer_samples; DMA1_Stream7 ->FCR = DMA_SxFCR_DMDIS; DMA1_Stream7 ->CR |= DMA_SxCR_EN; // Update state. - NextBufferSamples = NULL; - BufferNumber ^= 1; - DMARunning = true; + next_buffer_samples = NULL; + buffer_number ^= 1; + dma_running = true; // Invoke callback if it exists to queue up another buffer. - if (CallbackFunction) - CallbackFunction(CallbackContext, BufferNumber); + if (callback_function) + callback_function(callback_context, buffer_number); } -static void StopAudioDMA() { +static void audio_stop_dma() { DMA1_Stream7 ->CR &= ~DMA_SxCR_EN; // Disable DMA stream. while (DMA1_Stream7 ->CR & DMA_SxCR_EN ) ; // Wait for DMA stream to stop. - DMARunning = false; + dma_running = false; } void DMA1_Stream7_IRQHandler() { DMA1 ->HIFCR |= DMA_HIFCR_CTCIF7; // Clear interrupt flag. - if (NextBufferSamples) { - StartAudioDMAAndRequestBuffers(); + if (next_buffer_samples) { + audio_start_dma_and_request_buffers(); } else { - DMARunning = false; + dma_running = false; } } // Warning: don't i2c_write call from IRQ handler ! -static void WriteRegister(uint8_t address, uint8_t value) +static void audio_write_register(uint8_t address, uint8_t value) { const uint8_t device = 0x4a; const uint8_t data[2] = {address, value}; diff --git a/src/stm32f/src/Audio/cw.c b/src/stm32f/src/Audio/cw.c new file mode 100644 index 0000000..028ae82 --- /dev/null +++ b/src/stm32f/src/Audio/cw.c @@ -0,0 +1,4 @@ +#include "../../../common/src/Audio/cw.c" + +void cw_message_sent(const char* str) { +} diff --git a/src/fsm/i2c.c b/src/stm32f/src/GPIO/i2c.c index 6f7e193..750f5de 100644 --- a/src/fsm/i2c.c +++ b/src/stm32f/src/GPIO/i2c.c @@ -22,8 +22,9 @@ * SOFTWARE. */ -#include "i2c.h" -#include "common.h" +#include "GPIO/i2c.h" +#include "Core/common.h" + #include "stm32f4xx_conf.h" #include "stm32f4xx_i2c.h" #include "stm32f4xx.h" @@ -31,7 +32,7 @@ #include "FreeRTOSConfig.h" #include "task.h" #include "semphr.h" -#include "usart.h" +#include "GPIO/usart.h" /* I2C 1 on PB9 and PB6 * See pio.txt for PIO allocation details */ |