Sfoglia il codice sorgente

Refactor in progress. Many items not working.

Aria Burrell 3 anni fa
parent
commit
1f0730d2bb

+ 1 - 1
application.fam

@@ -8,6 +8,6 @@ App(
         "gui",
         "dialogs",
     ],
-    stack_size=4 * 1024,
+    stack_size=8 * 1024,
     order=20,
 )

+ 3 - 44
dtmf_dolphin.c

@@ -19,29 +19,12 @@ static void dtmf_dolphin_app_tick_event_callback(void* context) {
     furi_assert(context);
     DTMFDolphinApp* app = context;
 
-    // Needed to handle queueing to ISR and prioritization of audio
-    if (app->player.playing) {
-        dtmf_dolphin_player_handle_tick();
-    } else {
-        scene_manager_handle_tick_event(app->scene_manager);
-    }
+    // dtmf_dolphin_audio_handle_tick();
+    scene_manager_handle_tick_event(app->scene_manager);
 }
 
 static DTMFDolphinApp* app_alloc() {
     DTMFDolphinApp* app = malloc(sizeof(DTMFDolphinApp));
-    app->player.half_samples = 4 * 1024;
-    app->player.sample_count = 8 * 1024;
-    app->player.sample_buffer = malloc(sizeof(uint16_t) * app->player.sample_count);
-    app->player.buffer_buffer = malloc(sizeof(uint8_t) * app->player.sample_count);
-    app->player.wf1_period = 0;
-    app->player.wf2_period = 0;
-    app->player.wf1_freq = 0;
-    app->player.wf2_freq = 0;
-    app->player.wf1_pos = 0;
-    app->player.wf2_pos = 0;
-    app->player.queue = furi_message_queue_alloc(10, sizeof(DTMFDolphinEvent));
-    app->player.volume = 2.0f;
-    app->player.playing = false;
 
     app->gui = furi_record_open(RECORD_GUI);
     app->view_dispatcher = view_dispatcher_alloc();
@@ -70,22 +53,6 @@ static DTMFDolphinApp* app_alloc() {
         DTMFDolphinViewDialer,
         dtmf_dolphin_dialer_get_view(app->dtmf_dolphin_dialer));
 
-    app->dtmf_dolphin_bluebox = dtmf_dolphin_bluebox_alloc();
-    view_dispatcher_add_view(
-        app->view_dispatcher,
-        DTMFDolphinViewBluebox,
-        dtmf_dolphin_bluebox_get_view(app->dtmf_dolphin_bluebox));
-
-    app->dtmf_dolphin_play = widget_alloc();
-    view_dispatcher_add_view(
-        app->view_dispatcher,
-        DTMFDolphinViewPlay,
-        widget_get_view(app->dtmf_dolphin_play));
-
-    // app->dialer_button_panel = button_panel_alloc();
-    // app->bluebox_button_panel = button_panel_alloc();
-    // app->redbox_button_panel = button_panel_alloc();
-
     app->notification = furi_record_open(RECORD_NOTIFICATION);
     notification_message(app->notification, &sequence_display_backlight_enforce_on);
 
@@ -97,21 +64,15 @@ static DTMFDolphinApp* app_alloc() {
 static void app_free(DTMFDolphinApp* app) {
     furi_assert(app);
     view_dispatcher_remove_view(app->view_dispatcher, DTMFDolphinViewMainMenu);
-    view_dispatcher_remove_view(app->view_dispatcher, DTMFDolphinViewBluebox);
     view_dispatcher_remove_view(app->view_dispatcher, DTMFDolphinViewDialer);
-    view_dispatcher_remove_view(app->view_dispatcher, DTMFDolphinViewPlay);
     variable_item_list_free(app->main_menu_list);
 
-    dtmf_dolphin_bluebox_free(app->dtmf_dolphin_bluebox);
     dtmf_dolphin_dialer_free(app->dtmf_dolphin_dialer);
-    widget_free(app->dtmf_dolphin_play);
+    // widget_free(app->dtmf_dolphin_play);
 
     view_dispatcher_free(app->view_dispatcher);
     scene_manager_free(app->scene_manager);
 
-    furi_message_queue_free(app->player.queue);
-    free(app->player.sample_buffer);
-
     // button_panel_free(app->dialer_button_panel);
     // button_panel_free(app->bluebox_button_panel);
     // button_panel_free(app->redbox_button_panel);
@@ -126,8 +87,6 @@ static void app_free(DTMFDolphinApp* app) {
 int32_t dtmf_dolphin_app(void *p) {
     UNUSED(p);
     DTMFDolphinApp* app = app_alloc();
-
-    dtmf_dolphin_player_init(&(app->player));
     
     view_dispatcher_run(app->view_dispatcher);
 

+ 170 - 0
dtmf_dolphin_audio.c

@@ -0,0 +1,170 @@
+#include "dtmf_dolphin_audio.h"
+
+DTMFDolphinAudio *current_player;
+
+static void dtmf_dolphin_audio_dma_isr(void* ctx) {
+    FuriMessageQueue *event_queue = ctx;
+
+    if (LL_DMA_IsActiveFlag_HT1(DMA1)) {
+        LL_DMA_ClearFlag_HT1(DMA1);
+
+        DTMFDolphinCustomEvent event = {.type = DTMFDolphinEventDMAHalfTransfer};
+        furi_message_queue_put(event_queue, &event, 0);
+    }
+
+    if(LL_DMA_IsActiveFlag_TC1(DMA1)) {
+        LL_DMA_ClearFlag_TC1(DMA1);
+
+        DTMFDolphinCustomEvent event = {.type = DTMFDolphinEventDMAFullTransfer};
+        furi_message_queue_put(event_queue, &event, 0);
+    }
+}
+
+void dtmf_dolphin_audio_clear_samples(DTMFDolphinAudio* player) {
+    for (size_t i = 0; i < player->buffer_length; i++) {
+        player->sample_buffer[i] = 0;
+    }
+}
+
+DTMFDolphinOsc* dtmf_dolphin_osc_alloc() {
+    DTMFDolphinOsc *osc = { 0 };
+    osc->cached_freq = 0;
+    osc->offset = 0;
+    osc->period = 0;
+    return osc;
+}
+
+DTMFDolphinAudio* dtmf_dolphin_audio_alloc() {
+    DTMFDolphinAudio player;
+    player.buffer_length = SAMPLE_BUFFER_LENGTH;
+    player.half_buffer_length = SAMPLE_BUFFER_LENGTH / 2;
+    player.buffer_buffer = malloc(sizeof(uint8_t) * player.buffer_length);
+    player.sample_buffer = malloc(sizeof(uint16_t) * player.buffer_length);
+    player.osc1 = dtmf_dolphin_osc_alloc();
+    player.osc2 = dtmf_dolphin_osc_alloc();
+    player.playing = false;
+    player.volume = 2.0f;
+    player.queue = furi_message_queue_alloc(10, sizeof(DTMFDolphinCustomEvent));
+    dtmf_dolphin_audio_clear_samples(&player);
+
+    return false;
+}
+
+size_t calc_waveform_period(float freq) {
+    if (!freq) {
+        return 0;
+    }
+    // DMA Rate constant, thanks to Dr_Zlo
+    float dma_rate = CPU_CLOCK_FREQ \
+        / 2 \
+        / DTMF_DOLPHIN_HAL_DMA_PRESCALER \
+        / (DTMF_DOLPHIN_HAL_DMA_AUTORELOAD + 1);
+
+    return (uint16_t) (dma_rate / freq);
+}
+
+float sample_frame(DTMFDolphinOsc* osc, float freq) {
+    float frame = 0.0;
+
+    if (freq != osc->cached_freq || !osc->period) {
+        osc->cached_freq = freq;
+        osc->period = calc_waveform_period(freq);
+        osc->offset = 0;
+    }
+    if (osc->period) {
+        frame = tanhf(sin(osc->offset * PERIOD_2_PI / osc->period) + 1);
+        osc->offset = (osc->offset + 1) % osc->period;
+    }
+
+    return frame;
+}
+
+void dtmf_dolphin_audio_free(DTMFDolphinAudio* player) {
+    furi_message_queue_free(player->queue);
+    dtmf_dolphin_osc_free(player->osc1);
+    dtmf_dolphin_osc_free(player->osc2);
+    free(player->buffer_buffer);
+    free(player->sample_buffer);
+}
+
+void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc) {
+    UNUSED(osc);
+    // Nothing to free now, but keeping this here in case I reimplement caching
+}
+
+bool generate_waveform(DTMFDolphinAudio* player, float freq1, float freq2, uint16_t buffer_index) {
+    uint16_t* sample_buffer_start = &player->sample_buffer[buffer_index];
+
+    for (size_t i = 0; i < player->half_buffer_length; i++) {
+        float data = (sample_frame(player->osc1, freq1) / 2) + (sample_frame(player->osc2, freq2) / 2);
+        data *= player->volume;
+        data *= UINT8_MAX / 2;  // scale -128..127
+        data += UINT8_MAX / 2;  // to unsigned
+
+        if(data < 0) {
+            data = 0;
+        }
+
+        if(data > 255) {
+            data = 255;
+        }
+
+        player->buffer_buffer[i] = data;
+        sample_buffer_start[i] = data;
+    }
+
+    return true;
+}
+
+bool dtmf_dolphin_audio_play_tones(float freq1, float freq2) {
+    current_player = dtmf_dolphin_audio_alloc();
+
+    generate_waveform(current_player, freq1, freq2, 0);
+    generate_waveform(current_player, freq1, freq2, current_player->half_buffer_length);
+
+    dtmf_dolphin_speaker_init();
+    dtmf_dolphin_dma_init((uint32_t)current_player->sample_buffer, current_player->buffer_length);
+
+    furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, dtmf_dolphin_audio_dma_isr, current_player->queue);
+
+    dtmf_dolphin_dma_start();
+    dtmf_dolphin_speaker_start();
+
+    return true;
+}
+
+bool dtmf_dolphin_audio_stop_tones() {
+    current_player->playing = false;
+
+    dtmf_dolphin_speaker_stop();
+    dtmf_dolphin_dma_stop();
+
+    furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);
+
+    dtmf_dolphin_audio_free(current_player);
+   
+    return true;
+}
+
+bool dtmf_dolphin_audio_handle_tick() {
+    DTMFDolphinCustomEvent event;
+
+    if(furi_message_queue_get(current_player->queue, &event, FuriWaitForever) == FuriStatusOk) {
+        if(event.type == DTMFDolphinEventDMAHalfTransfer) {
+            generate_waveform(
+                current_player, 
+                (double) current_player->osc1->cached_freq, 
+                (double) current_player->osc2->cached_freq, 
+                0);
+            return true;
+        } else if (event.type == DTMFDolphinEventDMAFullTransfer) {
+            generate_waveform(
+                current_player, 
+                (double) current_player->osc1->cached_freq, 
+                (double) current_player->osc2->cached_freq, 
+                current_player->half_buffer_length);
+            return true;
+        }
+    }
+    return false;
+}

+ 42 - 0
dtmf_dolphin_audio.h

@@ -0,0 +1,42 @@
+#pragma once
+// #include "dtmf_dolphin_i.h"
+#include "dtmf_dolphin_event.h"
+#include "dtmf_dolphin_hal.h"
+
+#define SAMPLE_BUFFER_LENGTH 8192
+#define PERIOD_2_PI 6.2832
+#define CPU_CLOCK_FREQ 64000000
+
+typedef struct {
+    float cached_freq;
+    size_t period;
+    size_t buffer_length;
+    float* sample_buffer;
+    uint16_t offset;
+} DTMFDolphinOsc;
+
+typedef struct {
+    size_t buffer_length;
+    size_t half_buffer_length;
+    uint8_t *buffer_buffer;
+    uint16_t *sample_buffer;
+    float volume;
+    bool playing;
+    FuriMessageQueue *queue;
+    DTMFDolphinOsc *osc1;
+    DTMFDolphinOsc *osc2;
+} DTMFDolphinAudio;
+
+DTMFDolphinOsc* dtmf_dolphin_osc_alloc();
+
+DTMFDolphinAudio* dtmf_dolphin_audio_alloc();
+
+void dtmf_dolphin_audio_free(DTMFDolphinAudio* player);
+
+void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc);
+
+bool dtmf_dolphin_audio_play_tones(float freq1, float freq2);
+
+bool dtmf_dolphin_audio_stop_tones();
+
+bool dtmf_dolphin_audio_handle_tick();

+ 196 - 0
dtmf_dolphin_data.c

@@ -0,0 +1,196 @@
+#include "dtmf_dolphin_data.h"
+
+typedef struct {
+    const uint8_t row;
+    const uint8_t col;
+    const uint8_t span;
+} DTMFDolphinTonePos;
+
+typedef struct {
+    const char *name;
+    const float frequency_1;
+    const float frequency_2;
+    const DTMFDolphinTonePos pos;
+    const uint16_t pulses;         // for Redbox
+    const uint16_t pulse_ms;       // for Redbox
+    const uint16_t gap_duration;   // for Redbox
+} DTMFDolphinTones;
+
+typedef struct {
+    const char* name;
+    DTMFDolphinToneSection block;
+    uint8_t tone_count;
+    DTMFDolphinTones tones[DTMF_DOLPHIN_MAX_TONE_COUNT];
+} DTMFDolphinSceneData;
+
+DTMFDolphinSceneData DTMFDolphinSceneDataDialer = {
+    .name = "Dialer",
+    .block = DTMF_DOLPHIN_TONE_BLOCK_DIALER,
+    .tone_count = 16,
+    .tones = {
+        {"1", 697.0, 1209.0, {0, 0, 1}, 0, 0, 0},
+        {"2", 697.0, 1336.0, {0, 1, 1}, 0, 0, 0},
+        {"3", 697.0, 1477.0, {0, 2, 1}, 0, 0, 0},
+        {"A", 697.0, 1633.0, {0, 3, 1}, 0, 0, 0},
+        {"4", 770.0, 1209.0, {1, 0, 1}, 0, 0, 0},
+        {"5", 770.0, 1336.0, {1, 1, 1}, 0, 0, 0},
+        {"6", 770.0, 1477.0, {1, 2, 1}, 0, 0, 0},
+        {"B", 770.0, 1633.0, {1, 3, 1}, 0, 0, 0},
+        {"7", 852.0, 1209.0, {2, 0, 1}, 0, 0, 0},
+        {"8", 852.0, 1336.0, {2, 1, 1}, 0, 0, 0},
+        {"9", 852.0, 1477.0, {2, 2, 1}, 0, 0, 0},
+        {"C", 852.0, 1633.0, {2, 3, 1}, 0, 0, 0},
+        {"*", 941.0, 1209.0, {3, 0, 1}, 0, 0, 0},
+        {"0", 941.0, 1336.0, {3, 1, 1}, 0, 0, 0},
+        {"#", 941.0, 1477.0, {3, 2, 1}, 0, 0, 0},
+        {"D", 941.0, 1633.0, {3, 3, 1}, 0, 0, 0},
+    }
+};
+
+DTMFDolphinSceneData DTMFDolphinSceneDataBluebox = {
+    .name = "Bluebox",
+    .block = DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX,
+    .tone_count = 13,
+    .tones = {
+        {"1",      700.0,  900.0, {0, 0, 1}, 0, 0, 0},
+        {"2",      700.0, 1100.0, {0, 1, 1}, 0, 0, 0},
+        {"3",      900.0, 1100.0, {0, 2, 1}, 0, 0, 0},
+        {"4",      700.0, 1300.0, {1, 0, 1}, 0, 0, 0},
+        {"5",      900.0, 1300.0, {1, 1, 1}, 0, 0, 0},
+        {"6",     1100.0, 1300.0, {1, 2, 1}, 0, 0, 0},
+        {"7",      700.0, 1500.0, {2, 0, 1}, 0, 0, 0},
+        {"8",      900.0, 1500.0, {2, 1, 1}, 0, 0, 0},
+        {"9",     1100.0, 1500.0, {2, 2, 1}, 0, 0, 0},
+        {"0",     1300.0, 1500.0, {3, 1, 1}, 0, 0, 0},
+        {"KP",    1100.0, 1700.0, {0, 3, 2}, 0, 0, 0},
+        {"ST",    1500.0, 1700.0, {1, 3, 2}, 0, 0, 0},
+        {"2600",  2600.0,    0.0, {3, 3, 2}, 0, 0, 0},
+    }
+};
+
+DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUS = {
+    .name = "Redbox (US)",
+    .block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US,
+    .tone_count = 4,
+    .tones = {
+        {"Nickel",  1700.0, 2200.0, {0, 0, 4}, 1, 66, 0},
+        {"Dime",    1700.0, 2200.0, {1, 0, 4}, 2, 66, 66},
+        {"Quarter", 1700.0, 2200.0, {2, 0, 4}, 5, 33, 33},
+        {"Dollar",  1700.0, 2200.0, {3, 0, 4}, 1, 650, 0},
+    }
+};
+
+DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUK = {
+    .name = "Redbox (UK)",
+    .block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK,
+    .tone_count = 2,
+    .tones = {
+        {"10p", 1000.0, 0.0, {0, 0, 3}, 1, 200, 0},
+        {"50p", 1000.0, 0.0, {1, 0, 3}, 1, 350, 0},
+    }
+};
+
+DTMFDolphinSceneData DTMFDolphinSceneDataMisc = {
+    .name = "Misc",
+    .block = DTMF_DOLPHIN_TONE_BLOCK_MISC,
+    .tone_count = 3,
+    .tones = {
+        {"CCITT 11",   700.0, 1700.0, {0, 0, 4}, 0, 0, 0},
+        {"CCITT 12",   900.0, 1700.0, {1, 0, 4}, 0, 0, 0},
+        {"CCITT KP2", 1300.0, 1700.0, {2, 0, 4}, 0, 0, 0},
+    }
+};
+
+DTMFDolphinToneSection current_section;
+DTMFDolphinSceneData *current_scene_data;
+
+void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section) {
+    current_section = section;
+
+    switch (current_section)
+    {
+    case DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX:
+        current_scene_data = &DTMFDolphinSceneDataBluebox;
+        break;
+    case DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US:
+        current_scene_data = &DTMFDolphinSceneDataRedboxUS;
+        break;
+    case DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK:
+        current_scene_data = &DTMFDolphinSceneDataRedboxUK;
+        break;
+    case DTMF_DOLPHIN_TONE_BLOCK_MISC:
+        current_scene_data = &DTMFDolphinSceneDataMisc;
+        break;
+    default: // DTMF_DOLPHIN_TONE_BLOCK_DIALER:
+        current_scene_data = &DTMFDolphinSceneDataDialer;
+        break;
+    }
+}
+
+DTMFDolphinToneSection dtmf_dolphin_data_get_current_section() {
+    return current_section;
+}
+
+DTMFDolphinSceneData *dtmf_dolphin_data_get_current_scene_data() {
+    return current_scene_data;
+}
+
+bool dtmf_dolphin_data_get_tone_frequencies(float *freq1, float *freq2, uint8_t row, uint8_t col) {
+    for (size_t i = 0; i < current_scene_data->tone_count; i++) {
+        DTMFDolphinTones tones = current_scene_data->tones[i];
+        if (tones.pos.row == row && tones.pos.col == col) {
+            freq1[0] = tones.frequency_1;
+            freq2[0] = tones.frequency_2;
+            return true;
+        }
+    }
+    return false;
+}
+
+const char* dtmf_dolphin_data_get_tone_name(uint8_t row, uint8_t col) {
+    for (size_t i = 0; i < current_scene_data->tone_count; i++) {
+        DTMFDolphinTones tones = current_scene_data->tones[i];
+        if (tones.pos.row == row && tones.pos.col == col) {
+            return tones.name;
+        }
+    }
+    return NULL;
+}
+
+const char* dtmf_dolphin_data_get_current_section_name() {
+    if (current_scene_data) {
+        return current_scene_data->name;
+    }
+    return NULL;
+}
+
+void dtmf_dolphin_tone_get_max_pos(uint8_t* max_rows, uint8_t* max_cols, uint8_t* max_span) {
+    max_rows[0] = 0;
+    max_cols[0] = 0;
+    max_span[0] = 0;
+    uint8_t tmp_rowspan[5] = { 0, 0, 0, 0, 0 };
+    for (size_t i = 0; i < current_scene_data->tone_count; i++) {
+        DTMFDolphinTones tones = current_scene_data->tones[i];
+        if (tones.pos.row > max_rows[0]) {
+            max_rows[0] = tones.pos.row;
+        }
+        if (tones.pos.col > max_cols[0]) {
+            max_cols[0] = tones.pos.col;
+        }
+        tmp_rowspan[tones.pos.row] += tones.pos.span;
+        if (tmp_rowspan[tones.pos.row] > max_span[0])
+            max_span[0] = max_span[tones.pos.row];
+    }
+    max_rows[0]++;
+    max_cols[0]++;
+}
+
+uint8_t dtmf_dolphin_get_tone_span(uint8_t row, uint8_t col) {
+    for (size_t i = 0; i < current_scene_data->tone_count; i++) {
+        DTMFDolphinTones tones = current_scene_data->tones[i];
+        if (tones.pos.row == row && tones.pos.col == col) {
+            return tones.pos.span;
+        }
+    }
+    return 0;
+}

+ 28 - 0
dtmf_dolphin_data.h

@@ -0,0 +1,28 @@
+#pragma once
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define DTMF_DOLPHIN_MAX_TONE_COUNT 16
+
+typedef enum {
+    DTMF_DOLPHIN_TONE_BLOCK_DIALER,
+    DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX,
+    DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US,
+    DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK,
+    DTMF_DOLPHIN_TONE_BLOCK_MISC,
+} DTMFDolphinToneSection;
+
+void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section);
+
+DTMFDolphinToneSection dtmf_dolphin_data_get_current_section();
+
+bool dtmf_dolphin_data_get_tone_frequencies(float *freq1, float *freq2, uint8_t row, uint8_t col);
+
+const char* dtmf_dolphin_data_get_tone_name(uint8_t row, uint8_t col);
+
+const char* dtmf_dolphin_data_get_current_section_name();
+
+void dtmf_dolphin_tone_get_max_pos(uint8_t* max_rows, uint8_t* max_cols, uint8_t* max_span);
+
+uint8_t dtmf_dolphin_get_tone_span(uint8_t row, uint8_t col);

+ 11 - 5
dtmf_dolphin_event.h

@@ -3,12 +3,18 @@
 typedef enum {
     DTMFDolphinEventVolumeUp = 0,
     DTMFDolphinEventVolumeDown,
-    DTMFDolphinBlueboxOkCB,
+    DTMFDolphinDialerOkCB,
     DTMFDolphinEventStartDialer,
     DTMFDolphinEventStartBluebox,
-    DTMFDolphinEventStartRedbox,
+    DTMFDolphinEventStartRedboxUS,
+    DTMFDolphinEventStartRedboxUK,
+    DTMFDolphinEventStartMisc,
     DTMFDolphinEventPlayTones,
     DTMFDolphinEventStopTones,
-    DTMFDolphinPlayerEventHalfTransfer,
-    DTMFDolphinPlayerEventFullTransfer,
-} DTMFDolphinEvent;
+    DTMFDolphinEventDMAHalfTransfer,
+    DTMFDolphinEventDMAFullTransfer,
+} DTMFDolphinEvent;
+
+typedef struct {
+    DTMFDolphinEvent type;
+} DTMFDolphinCustomEvent;

+ 2 - 2
dtmf_dolphin_hal.c

@@ -2,8 +2,8 @@
 
 void dtmf_dolphin_speaker_init() {
     LL_TIM_InitTypeDef TIM_InitStruct = {0};
-    TIM_InitStruct.Prescaler = 4;
-    TIM_InitStruct.Autoreload = 255;
+    TIM_InitStruct.Prescaler = DTMF_DOLPHIN_HAL_DMA_PRESCALER;
+    TIM_InitStruct.Autoreload = DTMF_DOLPHIN_HAL_DMA_AUTORELOAD;
     LL_TIM_Init(FURI_HAL_SPEAKER_TIMER, &TIM_InitStruct);
 
     LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};

+ 3 - 2
dtmf_dolphin_hal.h

@@ -1,8 +1,6 @@
 #pragma once
 #include <furi.h>
 #include <furi_hal.h>
-#include <stdint.h>
-#include <stddef.h>
 #include <stm32wb55xx.h>
 #include <stm32wbxx_ll_tim.h>
 #include <stm32wbxx_ll_dma.h>
@@ -11,6 +9,9 @@
 #define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1
 #define DMA_INSTANCE DMA1, LL_DMA_CHANNEL_1
 
+#define DTMF_DOLPHIN_HAL_DMA_PRESCALER 4
+#define DTMF_DOLPHIN_HAL_DMA_AUTORELOAD 255
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 9 - 16
dtmf_dolphin_i.h

@@ -5,26 +5,25 @@
 #include <gui/gui.h>
 #include <gui/view_dispatcher.h>
 #include <gui/scene_manager.h>
-#include <gui/modules/submenu.h>
-#include <gui/modules/widget.h>
+// #include <gui/modules/submenu.h>
+// #include <gui/modules/widget.h>
 #include <gui/modules/variable_item_list.h>
 #include <notification/notification_messages.h>
 #include <input/input.h>
 
 #include "dtmf_dolphin_event.h"
-#include "dtmf_dolphin_player.h"
 
 #include "views/dtmf_dolphin_dialer.h"
-#include "views/dtmf_dolphin_bluebox.h"
 
 #define TAG "DTMFDolphin"
 
 
-enum DTMFDolphinItem {
-    DTMFDolphinItemDialer,
-    DTMFDolphinItemBluebox,
-    DTMFDolphinItemRedbox,
-    DTMFDolphinItemPlay
+enum DTMFDolphinSceneState {
+    DTMFDolphinSceneStateDialer,
+    DTMFDolphinSceneStateBluebox,
+    DTMFDolphinSceneStateRedboxUS,
+    DTMFDolphinSceneStateRedboxUK,
+    DTMFDolphinSceneStateMisc,
 };
 
 typedef struct {
@@ -32,9 +31,6 @@ typedef struct {
     SceneManager* scene_manager;
     VariableItemList* main_menu_list;
     DTMFDolphinDialer* dtmf_dolphin_dialer;
-    DTMFDolphinBluebox* dtmf_dolphin_bluebox;
-    DTMFDolphinPlayer player;
-    Widget* dtmf_dolphin_play;
 
     Gui* gui;
     // ButtonPanel* dialer_button_panel;
@@ -45,8 +41,5 @@ typedef struct {
 
 typedef enum {
     DTMFDolphinViewMainMenu,
-    DTMFDolphinViewDialer,
-    DTMFDolphinViewBluebox,
-    DTMFDolphinViewRedbox,
-    DTMFDolphinViewPlay,
+    DTMFDolphinViewDialer
 } DTMFDolphinView;

+ 0 - 156
dtmf_dolphin_player.c

@@ -1,156 +0,0 @@
-#include "dtmf_dolphin_player.h"
-
-#define DTMF_DOLPHIN_SAMPLE_RATE (8000)
-
-typedef struct {
-    DTMFDolphinEvent type;
-} DTMFDolphinPlayerEvent;
-
-// Keep this here for accessibility in local scope event without context
-DTMFDolphinPlayer* player;
-
-void dtmf_dolphin_dma_isr(void* ctx) {
-    FuriMessageQueue *event_queue = ctx;
-
-    if (LL_DMA_IsActiveFlag_HT1(DMA1)) {
-        LL_DMA_ClearFlag_HT1(DMA1);
-
-        DTMFDolphinPlayerEvent event = {.type = DTMFDolphinPlayerEventHalfTransfer};
-        furi_message_queue_put(event_queue, &event, 0);
-    }
-
-    if(LL_DMA_IsActiveFlag_TC1(DMA1)) {
-        LL_DMA_ClearFlag_TC1(DMA1);
-
-        DTMFDolphinPlayerEvent event = {.type = DTMFDolphinPlayerEventFullTransfer};
-        furi_message_queue_put(event_queue, &event, 0);
-    }
-}
-
-bool dtmf_dolphin_player_init(void* context) {
-    player = context;
-
-    return false;
-}
-
-void dtmf_dolphin_player_clear_samples() {
-    for (size_t i = 0; i < player->sample_count; i++) {
-        player->sample_buffer[i] = 0;
-    }
-}
-
-bool dtmf_dolphin_player_generate_waveform(size_t index) {
-    uint16_t* sample_buffer_start = &player->sample_buffer[index];
-    if (!player->wf1_freq)
-        return false;
-
-    // Generate basic sine wave sample to fill sample_count
-    for (size_t i = 0; i < player->half_samples; i++) {
-        // float data = sin(i * PERIOD_2_PI / player->wf1_period) + 1;
-        float data = sin(player->wf1_pos * PERIOD_2_PI / player->wf1_period) + 1;
-        player->wf1_pos = (player->wf1_pos + 1) % player->wf1_period;
-
-        data *= player->volume;
-
-        // Downmix second tone with the first
-        if (player->wf2_freq) {
-            data /= 2;
-
-            float data_2 = sin(player->wf2_pos * PERIOD_2_PI / player->wf2_period) + 1;
-            player->wf2_pos = (player->wf2_pos + 1) % player->wf2_period;
-
-            data_2 *= player->volume / 2;
-
-            data += data_2;
-        }
-
-        data = tanhf(data);
-
-        data *= UINT8_MAX / 2; // scale -128..127
-        data += UINT8_MAX / 2; // to unsigned
-
-        if(data < 0) {
-            data = 0;
-        }
-
-        if(data > 255) {
-            data = 255;
-        }
-
-        player->buffer_buffer[i] = data;
-        sample_buffer_start[i] = data;
-    }
-
-    return true;
-}
-
-bool dtmf_dolphin_player_play_tones(float *freq) {
-    player->wf1_pos = 0;
-    player->wf2_pos = 0;
-    player->wf1_freq = 0;
-    player->wf2_freq = 0;
-    player->wf1_period = 0;
-    player->wf2_period = 0;
-    if (freq[0]) {
-        player->wf1_freq = freq[0];
-        player->wf1_period = player->sample_count / freq[0] * 4;
-    }
-    if (freq[1]) {
-        player->wf2_freq = freq[1];
-        player->wf2_period = player->sample_count / freq[1] * 4;
-    }
-    dtmf_dolphin_player_clear_samples();
-
-    dtmf_dolphin_player_generate_waveform(0);
-    dtmf_dolphin_player_generate_waveform(player->half_samples);
-
-    dtmf_dolphin_speaker_init();
-    dtmf_dolphin_dma_init((uint32_t)player->sample_buffer, player->sample_count);
-
-    furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, dtmf_dolphin_dma_isr, player->queue);
-
-    dtmf_dolphin_dma_start();
-    dtmf_dolphin_speaker_start();
-
-    player->playing = true;
-
-    return true;
-}
-
-bool dtmf_dolphin_player_stop_tones() {
-    player->playing = false;
-
-    dtmf_dolphin_speaker_stop();
-    dtmf_dolphin_dma_stop();
-
-    furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);
-   
-    return true;
-}
-
-bool dtmf_dolphin_player_handle_tick() {
-    DTMFDolphinPlayerEvent event;
-
-    if(furi_message_queue_get(player->queue, &event, FuriWaitForever) == FuriStatusOk) {
-        if (player->playing) {
-            if(event.type == DTMFDolphinPlayerEventHalfTransfer) {
-                dtmf_dolphin_player_generate_waveform(0);
-                // uint16_t* sample_buffer_start = &player->sample_buffer[0];
-                // for (size_t i = 0; i < player->half_samples; i++) {
-                //     sample_buffer_start[i] = player->buffer_buffer[i];
-                // }
-                return true;
-            } else if (event.type == DTMFDolphinPlayerEventFullTransfer) {
-                dtmf_dolphin_player_generate_waveform(player->half_samples);
-                // uint16_t* sample_buffer_start = &player->sample_buffer[player->half_samples];
-                // for (size_t i = 0; i < player->half_samples; i++) {
-                //     sample_buffer_start[i] = player->buffer_buffer[i];
-                // }
-                return true;
-            }
-        } else {
-            return true;
-        }
-    }
-    return false;
-}

+ 0 - 47
dtmf_dolphin_player.h

@@ -1,47 +0,0 @@
-#pragma once
-#include "dtmf_dolphin_event.h"
-#include "dtmf_dolphin_hal.h"
-#include "dtmf_dolphin_tone.h"
-
-#define PERIOD_2_PI 6.2832
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
-    size_t half_samples;
-    size_t sample_count;
-    float wf1_freq;
-    float wf2_freq;
-    uint16_t wf1_period;
-    uint16_t wf2_period;
-    uint16_t wf1_pos;
-    uint16_t wf2_pos;
-    uint8_t *buffer_buffer;
-    uint16_t *sample_buffer;
-    float volume;
-    bool playing;
-
-    FuriMessageQueue* queue;
-} DTMFDolphinPlayer;
-
-void dtmf_dolphin_dma_isr(void* ctx);
-
-bool dtmf_dolphin_player_init(void* context);
-
-void dtmf_dolphin_player_clear_samples();
-
-bool dtmf_dolphin_player_generate_waveform(size_t index);
-
-bool dtmf_dolphin_player_play_tones(float *freq);
-
-bool dtmf_dolphin_player_stop_tones();
-
-bool dtmf_dolphin_player_handle_tick();
-
-#ifdef __cplusplus
-}
-#endif
-
-

+ 0 - 84
dtmf_dolphin_tone.c

@@ -1,84 +0,0 @@
-#include "dtmf_dolphin_tone.h"
-
-const char* dtmf_dolphin_get_tone_name(uint8_t row, uint8_t col, DTMFDolphinToneSection block) {
-    if (block == DTMF_DOLPHIN_TONE_BLOCK_DIALER) {
-        for (int i = 0; i < DTMF_DOLPHIN_DIALER_TONE_COUNT; i++) {
-            if (dtmf_dolphin_dialer_tone[i].pos.row == row && dtmf_dolphin_dialer_tone[i].pos.col == col) {
-                return dtmf_dolphin_dialer_tone[i].name;
-            }
-        }
-    } else if (block == DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX) {
-        // if (index < DTMF_DOLPHIN_BLUEBOX_TONE_COUNT) {
-        //     return dtmf_dolphin_bluebox_tone[index].name;
-        // }
-    }
-    return "N";
-}
-
-uint8_t dtmf_dolphin_get_tone_span(uint8_t row, uint8_t col, DTMFDolphinToneSection block) {
-    if (block == DTMF_DOLPHIN_TONE_BLOCK_DIALER) {
-        for (int i = 0; i < DTMF_DOLPHIN_DIALER_TONE_COUNT; i++) {
-            if (dtmf_dolphin_dialer_tone[i].pos.row == row && dtmf_dolphin_dialer_tone[i].pos.col == col) {
-                return dtmf_dolphin_dialer_tone[i].pos.span;
-            }
-        }
-    } else if (block == DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX) {
-        // if (index < DTMF_DOLPHIN_BLUEBOX_TONE_COUNT) {
-        //     return dtmf_dolphin_bluebox_tone[index].name;
-        // }
-    }
-    return 1; // Default to 1
-}
-
-void dtmf_dolphin_get_tone_frequencies(float *freq, uint8_t row, uint8_t col, DTMFDolphinToneSection block) {
-    freq[0] = 0;
-    freq[1] = 0;
-
-    if (block == DTMF_DOLPHIN_TONE_BLOCK_DIALER) {
-        for (int i = 0; i < DTMF_DOLPHIN_DIALER_TONE_COUNT; i++) {
-            if (dtmf_dolphin_dialer_tone[i].pos.row == row && dtmf_dolphin_dialer_tone[i].pos.col == col) {
-                freq[0] = dtmf_dolphin_dialer_tone[i].frequency_1;
-                freq[1] = dtmf_dolphin_dialer_tone[i].frequency_2;
-            }
-        }
-    } else if (block == DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX) {
-        // if (index < DTMF_DOLPHIN_BLUEBOX_TONE_COUNT) {
-        //     return dtmf_dolphin_bluebox_tone[index].name;
-        // }
-    }
-}
-
-void dtmf_dolphin_tone_get_max_pos(uint8_t *max_rows, uint8_t *max_cols, uint8_t *max_span, DTMFDolphinToneSection block) {
-    max_rows[0] = 0;
-    max_cols[0] = 0;
-    max_span[0] = 0;
-    uint8_t span[8] = { 0 };
-    if (block == DTMF_DOLPHIN_TONE_BLOCK_DIALER) {
-        for (int i = 0; i < DTMF_DOLPHIN_DIALER_TONE_COUNT; i++) {
-            if (dtmf_dolphin_dialer_tone[i].pos.row > max_rows[0])
-                max_rows[0] = dtmf_dolphin_dialer_tone[i].pos.row;
-            if (dtmf_dolphin_dialer_tone[i].pos.col > max_cols[0])
-                max_cols[0] = dtmf_dolphin_dialer_tone[i].pos.col;
-            span[dtmf_dolphin_dialer_tone[i].pos.row] += dtmf_dolphin_dialer_tone[i].pos.span;
-        }
-        max_rows[0]++;
-        max_cols[0]++;
-        for (int i = 0; i < max_rows[0]; i++) {
-            if (span[i] > max_span[0])
-                max_span[0] = span[i];
-        }
-    } else if (block == DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX) {
-        // if (index < DTMF_DOLPHIN_BLUEBOX_TONE_COUNT) {
-        // for (int i; i < DTMF_DOLPHIN_BLUEBOX_TONE_COUNT; i++) {
-        //     if (dtmf_dolphin_bluebox_tone[i].pos.row > max_rows)
-        //         max_rows = dtmf_dolphin_bluebox_tone[i].pos.row;
-        //     if (dtmf_dolphin_bluebox_tone[i].pos.col > max_cols)
-        //         max_cols = dtmf_dolphin_bluebox_tone[i].pos.col;
-        // }
-    }
-}
-
-// void dtmf_dolphin_bluebox_generate(uint8_t index, uint8_t *buffer) {
-
-//     // TODO: Generate the waveform
-// }

+ 0 - 25
dtmf_dolphin_tone.h

@@ -1,25 +0,0 @@
-#pragma once
-#include "tones/dtmf_dolphin_dialer_tones.h"
-#include "tones/dtmf_dolphin_bluebox_tones.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
-    DTMF_DOLPHIN_TONE_BLOCK_DIALER,
-    DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX,
-    DTMF_DOLPHIN_TONE_BLOCK_REDBOX,
-} DTMFDolphinToneSection;
-
-const char* dtmf_dolphin_get_tone_name(uint8_t row, uint8_t col, DTMFDolphinToneSection block);
-
-uint8_t dtmf_dolphin_get_tone_span(uint8_t row, uint8_t col, DTMFDolphinToneSection block);
-
-void dtmf_dolphin_get_tone_frequencies(float *freq, uint8_t row, uint8_t col, DTMFDolphinToneSection block);
-
-void dtmf_dolphin_tone_get_max_pos(uint8_t *max_rows, uint8_t *max_cols, uint8_t *max_span, DTMFDolphinToneSection block);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 16
scenes/dtmf_dolphin_scene_bluebox.c

@@ -1,16 +0,0 @@
-#include "../dtmf_dolphin_i.h"
-
-void dtmf_dolphin_scene_bluebox_on_enter(void *context) {
-    DTMFDolphinApp* app = context;
-    view_dispatcher_switch_to_view(app->view_dispatcher, DTMFDolphinViewBluebox);
-}
-
-bool dtmf_dolphin_scene_bluebox_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
-}
-
-void dtmf_dolphin_scene_bluebox_on_exit(void* context) {
-    UNUSED(context);
-}

+ 1 - 2
scenes/dtmf_dolphin_scene_config.h

@@ -1,3 +1,2 @@
 ADD_SCENE(dtmf_dolphin, start, Start)
-ADD_SCENE(dtmf_dolphin, dialer, Dialer)
-ADD_SCENE(dtmf_dolphin, bluebox, Bluebox)
+ADD_SCENE(dtmf_dolphin, dialer, Dialer)

+ 28 - 4
scenes/dtmf_dolphin_scene_dialer.c

@@ -1,7 +1,31 @@
 #include "../dtmf_dolphin_i.h"
+// #include "../dtmf_dolphin_data.h"
+// #include "../dtmf_dolphin_audio.h"
+
 
 void dtmf_dolphin_scene_dialer_on_enter(void *context) {
     DTMFDolphinApp* app = context;
+    DTMFDolphinScene scene_id = DTMFDolphinSceneDialer;
+    enum DTMFDolphinSceneState state = scene_manager_get_scene_state(app->scene_manager, scene_id);
+
+    switch (state)
+    {
+    case DTMFDolphinSceneStateBluebox:
+        dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX);
+        break;    
+    case DTMFDolphinSceneStateRedboxUS:
+        dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US);
+        break;
+    case DTMFDolphinSceneStateRedboxUK:
+        dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK);
+        break;
+    case DTMFDolphinSceneStateMisc:
+        dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_MISC);
+        break;
+    default:
+        dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_DIALER);
+        break;
+    }
 
     view_dispatcher_switch_to_view(app->view_dispatcher, DTMFDolphinViewDialer);
 }
@@ -9,14 +33,14 @@ void dtmf_dolphin_scene_dialer_on_enter(void *context) {
 bool dtmf_dolphin_scene_dialer_on_event(void* context, SceneManagerEvent event) {
     DTMFDolphinApp* app = context;
     UNUSED(app);
+    UNUSED(event);
     bool consumed = false;
 
-    if(event.type == SceneManagerEventTypeCustom) {
-        consumed = true;
-    }
+    // if(event.type == SceneManagerEventTypeTick) {
+    //     consumed = true;
+    // }
 
     return consumed;
-    return false;
 }
 
 void dtmf_dolphin_scene_dialer_on_exit(void* context) {

+ 6 - 6
scenes/dtmf_dolphin_scene_start.c

@@ -2,12 +2,12 @@
 
 static void dtmf_dolphin_scene_start_main_menu_enter_callback(void* context, uint32_t index) {
     DTMFDolphinApp* app = context;
-    if (index == DTMFDolphinItemDialer) {
+    if (index == DTMFDolphinSceneStateDialer) {
         view_dispatcher_send_custom_event(
             app->view_dispatcher,
             DTMFDolphinEventStartDialer
         );
-    } else if (index == DTMFDolphinItemBluebox) {
+    } else if (index == DTMFDolphinSceneStateBluebox) {
         view_dispatcher_send_custom_event(
             app->view_dispatcher,
             DTMFDolphinEventStartBluebox
@@ -26,7 +26,7 @@ void dtmf_dolphin_scene_start_on_enter(void* context) {
         app);
 
     variable_item_list_add(var_item_list, "Dialer", 0, NULL, NULL);
-    // variable_item_list_add(var_item_list, "Bluebox", 0, NULL, NULL);
+    variable_item_list_add(var_item_list, "Bluebox", 0, NULL, NULL);
 
     variable_item_list_set_selected_item(
         var_item_list,
@@ -44,11 +44,11 @@ bool dtmf_dolphin_scene_start_on_event(void* context, SceneManagerEvent event) {
 
     if(event.type == SceneManagerEventTypeCustom) {
         if (event.event == DTMFDolphinEventStartDialer) {
-            scene_manager_set_scene_state(app->scene_manager, DTMFDolphinSceneDialer, DTMFDolphinItemDialer);
+            scene_manager_set_scene_state(app->scene_manager, DTMFDolphinSceneDialer, DTMFDolphinSceneStateDialer);
             scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneDialer);
         } else if (event.event == DTMFDolphinEventStartBluebox) {
-            scene_manager_set_scene_state(app->scene_manager, DTMFDolphinSceneBluebox, DTMFDolphinItemBluebox);
-            scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneBluebox);
+            scene_manager_set_scene_state(app->scene_manager, DTMFDolphinSceneDialer, DTMFDolphinSceneStateBluebox);
+            scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneDialer);
         }
         consumed = true;
     }

+ 0 - 29
tones/dtmf_dolphin_bluebox_tones.h

@@ -1,29 +0,0 @@
-#pragma once
-#include <stdint.h>
-
-#define DTMF_DOLPHIN_BLUEBOX_TONE_COUNT 16
-
-typedef struct {
-    const char *name;
-    const float frequency_1;
-    const float frequency_2;
-} DTMFDolphinBlueboxTones;
-
-static const DTMFDolphinBlueboxTones dtmf_dolphin_bluebox_tone[DTMF_DOLPHIN_BLUEBOX_TONE_COUNT] = {
-    {"2600 Hz", 2600.0, 0.0},
-    {"1", 700.0, 900.0},
-    {"2", 700.0, 1100.0},
-    {"3", 900.0, 1100.0},
-    {"4", 700.0, 1300.0},
-    {"5", 900.0, 1300.0},
-    {"6", 1100.0, 1300.0},
-    {"7", 700.0, 1500.0},
-    {"8", 900.0, 1500.0},
-    {"9", 1100.0, 1500.0},
-    {"0", 1300.0, 1500.0},
-    {"Key Pulse (KP)", 1100.0, 1700.0},
-    {"Start (ST)", 1500.0, 1700.0},
-    {"CCITT 11", 700.0, 1700.0},
-    {"CCITT 12", 900.0, 1700.0},
-    {"CCITT KP2", 1300.0, 1700.0},
-};

+ 0 - 43
tones/dtmf_dolphin_dialer_tones.h

@@ -1,43 +0,0 @@
-#pragma once
-#include <stdint.h>
-
-#define DTMF_DOLPHIN_DIALER_TONE_COUNT 16
-
-typedef struct DTMFDolphinDialerTonePos {
-    const uint8_t row;
-    const uint8_t col;
-    const uint8_t span;
-} DTMFDolphinDialerTonePos;
-
-typedef struct {
-    const char *name;
-    const float frequency_1;
-    const float frequency_2;
-    const struct DTMFDolphinDialerTonePos pos;
-} DTMFDolphinDialerTones;
-
-/*  Via https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling
-        1209 Hz 	1336 Hz 	1477 Hz 	1633 Hz
-697 Hz 	1 	        2 	        3 	        A
-770 Hz 	4 	        5 	        6 	        B
-852 Hz 	7 	        8 	        9 	        C
-941 Hz 	* 	        0 	        # 	        D */
-
-static const DTMFDolphinDialerTones dtmf_dolphin_dialer_tone[DTMF_DOLPHIN_DIALER_TONE_COUNT] = {
-    {"1", 697.0, 1209.0, {0, 0, 1}},
-    {"2", 697.0, 1336.0, {0, 1, 1}},
-    {"3", 697.0, 1477.0, {0, 2, 1}},
-    {"A", 697.0, 1633.0, {0, 3, 1}},
-    {"4", 770.0, 1209.0, {1, 0, 1}},
-    {"5", 770.0, 1336.0, {1, 1, 1}},
-    {"6", 770.0, 1477.0, {1, 2, 1}},
-    {"B", 770.0, 1633.0, {1, 3, 1}},
-    {"7", 852.0, 1209.0, {2, 0, 1}},
-    {"8", 852.0, 1336.0, {2, 1, 1}},
-    {"9", 852.0, 1477.0, {2, 2, 1}},
-    {"C", 852.0, 1633.0, {2, 3, 1}},
-    {"*", 941.0, 1209.0, {3, 0, 1}},
-    {"0", 941.0, 1336.0, {3, 1, 1}},
-    {"#", 941.0, 1477.0, {3, 2, 1}},
-    {"D", 941.0, 1633.0, {3, 3, 1}},
-};

+ 0 - 131
views/dtmf_dolphin_bluebox.c

@@ -1,131 +0,0 @@
-#include "dtmf_dolphin_bluebox.h"
-
-#include <gui/elements.h>
-
-typedef struct DTMFDolphinBluebox {
-    View* view;
-    DTMFDolphinBlueboxOkCallback callback;
-    void* context;
-} DTMFDolphinBluebox;
-
-typedef struct {
-    uint8_t index;
-} DTMFDolphinBlueboxModel;
-
-static bool dtmf_dolphin_bluebox_process_left(DTMFDolphinBluebox* dtmf_dolphin_bluebox);
-static bool dtmf_dolphin_bluebox_process_right(DTMFDolphinBluebox* dtmf_dolphin_bluebox);
-static bool dtmf_dolphin_bluebox_process_ok(DTMFDolphinBluebox* dtmf_dolphin_bluebox, InputEvent* event);
-
-static void dtmf_dolphin_bluebox_draw_callback(Canvas* canvas, void* _model) {
-    DTMFDolphinBlueboxModel* model = _model;
-    UNUSED(model);
-    canvas_set_font(canvas, FontPrimary);
-    elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Bluebox Mode");
-    canvas_set_font(canvas, FontSecondary);
-    elements_multiline_text_aligned(
-        canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to select");
-    // elements_multiline_text_aligned(
-    //     canvas, 64, 32, AlignCenter, AlignTop, dtmf_dolphin_get_tone_name(model->index, DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX));
-}
-
-static bool dtmf_dolphin_bluebox_input_callback(InputEvent* event, void* context) {
-    furi_assert(context);
-    DTMFDolphinBluebox* dtmf_dolphin_bluebox = context;
-    bool consumed = false;
-
-    if(event->type == InputTypeShort) {
-        if(event->key == InputKeyRight) {
-            consumed = dtmf_dolphin_bluebox_process_right(dtmf_dolphin_bluebox);
-        } else if(event->key == InputKeyLeft) {
-            consumed = dtmf_dolphin_bluebox_process_left(dtmf_dolphin_bluebox);
-        }
-    } else if(event->key == InputKeyOk) {
-        consumed = dtmf_dolphin_bluebox_process_ok(dtmf_dolphin_bluebox, event);
-    }
-
-    return consumed;
-}
-
-static bool dtmf_dolphin_bluebox_process_left(DTMFDolphinBluebox* dtmf_dolphin_bluebox) {
-    with_view_model(
-        dtmf_dolphin_bluebox->view, (DTMFDolphinBlueboxModel * model) {
-            if(model->index) {
-                model->index--;
-            }
-            return true;
-        });
-    return true;
-}
-
-static bool dtmf_dolphin_bluebox_process_right(DTMFDolphinBluebox* dtmf_dolphin_bluebox) {
-    with_view_model(
-        dtmf_dolphin_bluebox->view, (DTMFDolphinBlueboxModel * model) {
-            if(model->index < DTMF_DOLPHIN_BLUEBOX_TONE_COUNT) {
-                model->index++;
-            }
-            return true;
-        });
-    return true;
-}
-
-static bool dtmf_dolphin_bluebox_process_ok(DTMFDolphinBluebox* dtmf_dolphin_bluebox, InputEvent* event) {
-    bool consumed = false;
-
-    with_view_model(
-        dtmf_dolphin_bluebox->view, (DTMFDolphinBlueboxModel* model) {
-            if(event->type == InputTypePress) {
-                if(model->index < DTMF_DOLPHIN_BLUEBOX_TONE_COUNT) {
-                    // TODO: Do the thing
-                } else {
-                    // TODO: Do the thing
-                }
-                consumed = true;
-            } else if(event->type == InputTypeRelease) {
-                if(model->index < DTMF_DOLPHIN_BLUEBOX_TONE_COUNT) {
-                    // gpio_item_set_pin(Model->pin_idx, false);
-                } else {
-                    // gpio_item_set_all_pins(false);
-                }
-                consumed = true;
-            }
-            dtmf_dolphin_bluebox->callback(event->type, dtmf_dolphin_bluebox->context);
-            return true;
-        });
-
-    return consumed;
-}
-
-DTMFDolphinBluebox* dtmf_dolphin_bluebox_alloc() {
-    DTMFDolphinBluebox* dtmf_dolphin_bluebox = malloc(sizeof(DTMFDolphinBluebox));
-
-    dtmf_dolphin_bluebox->view = view_alloc();
-    view_allocate_model(dtmf_dolphin_bluebox->view, ViewModelTypeLocking, sizeof(DTMFDolphinBlueboxModel));
-    view_set_context(dtmf_dolphin_bluebox->view, dtmf_dolphin_bluebox);
-    view_set_draw_callback(dtmf_dolphin_bluebox->view, dtmf_dolphin_bluebox_draw_callback);
-    view_set_input_callback(dtmf_dolphin_bluebox->view, dtmf_dolphin_bluebox_input_callback);
-
-    return dtmf_dolphin_bluebox;
-}
-
-void dtmf_dolphin_bluebox_free(DTMFDolphinBluebox* dtmf_dolphin_bluebox) {
-    furi_assert(dtmf_dolphin_bluebox);
-    view_free(dtmf_dolphin_bluebox->view);
-    free(dtmf_dolphin_bluebox);
-}
-
-View* dtmf_dolphin_bluebox_get_view(DTMFDolphinBluebox* dtmf_dolphin_bluebox) {
-    furi_assert(dtmf_dolphin_bluebox);
-    return dtmf_dolphin_bluebox->view;
-}
-
-void dtmf_dolphin_bluebox_set_ok_callback(DTMFDolphinBluebox* dtmf_dolphin_bluebox, DTMFDolphinBlueboxOkCallback callback, void* context) {
-    furi_assert(dtmf_dolphin_bluebox);
-    furi_assert(callback);
-    with_view_model(
-        dtmf_dolphin_bluebox->view, (DTMFDolphinBlueboxModel * model) {
-            UNUSED(model);
-            dtmf_dolphin_bluebox->callback = callback;
-            dtmf_dolphin_bluebox->context = context;
-            return false;
-        });
-}

+ 0 - 15
views/dtmf_dolphin_bluebox.h

@@ -1,15 +0,0 @@
-#pragma once
-
-#include <gui/view.h>
-#include "../dtmf_dolphin_tone.h"
-
-typedef struct DTMFDolphinBluebox DTMFDolphinBluebox;
-typedef void (*DTMFDolphinBlueboxOkCallback)(InputType type, void* context);
-
-DTMFDolphinBluebox* dtmf_dolphin_bluebox_alloc();
-
-void dtmf_dolphin_bluebox_free(DTMFDolphinBluebox* dtmf_dolphin_bluebox);
-
-View* dtmf_dolphin_bluebox_get_view(DTMFDolphinBluebox* dtmf_dolphin_bluebox);
-
-void dtmf_dolphin_bluebox_set_ok_callback(DTMFDolphinBluebox* dtmf_dolphin_bluebox, DTMFDolphinBlueboxOkCallback callback, void* context);

+ 3 - 1
views/dtmf_dolphin_common.h

@@ -1,5 +1,7 @@
 #pragma once
-#include "../dtmf_dolphin_player.h"
+#include "../dtmf_dolphin_event.h"
+#include "../dtmf_dolphin_data.h"
+#include "../dtmf_dolphin_audio.h"
 
 #define DTMF_DOLPHIN_NUMPAD_X 1
 #define DTMF_DOLPHIN_NUMPAD_Y 14

+ 20 - 25
views/dtmf_dolphin_dialer.c

@@ -9,9 +9,12 @@ typedef struct DTMFDolphinDialer {
 } DTMFDolphinDialer;
 
 typedef struct {
+    DTMFDolphinToneSection section;
     uint8_t row;
     uint8_t col;
-    float *freq;
+    float freq1;
+    float freq2;
+    DTMFDolphinAudio player;
 } DTMFDolphinDialerModel;
 
 static bool dtmf_dolphin_dialer_process_up(DTMFDolphinDialer* dtmf_dolphin_dialer);
@@ -31,7 +34,7 @@ void draw_button(Canvas* canvas, uint8_t row, uint8_t col, bool invert) {
         (row * DTMF_DOLPHIN_BUTTON_HEIGHT);
         // (row * DTMF_DOLPHIN_BUTTON_PADDING);
 
-    uint8_t span = dtmf_dolphin_get_tone_span(row, col, DTMF_DOLPHIN_TONE_BLOCK_DIALER);
+    uint8_t span = dtmf_dolphin_get_tone_span(row, col);
 
     canvas_set_color(canvas, ColorBlack);
     
@@ -57,7 +60,7 @@ void draw_button(Canvas* canvas, uint8_t row, uint8_t col, bool invert) {
         top + (int) (DTMF_DOLPHIN_BUTTON_HEIGHT / 2),
         AlignCenter,
         AlignCenter,
-        dtmf_dolphin_get_tone_name(row, col, DTMF_DOLPHIN_TONE_BLOCK_DIALER));
+        dtmf_dolphin_data_get_tone_name(row, col));
 
     if (invert)
         canvas_invert_color(canvas);
@@ -68,7 +71,7 @@ void draw_dialer(Canvas* canvas, void* _model) {
     uint8_t max_rows;
     uint8_t max_cols;
     uint8_t max_span;
-    dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span, DTMF_DOLPHIN_TONE_BLOCK_DIALER);
+    dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span);
 
     canvas_set_font(canvas, FontSecondary);
 
@@ -83,18 +86,19 @@ void draw_dialer(Canvas* canvas, void* _model) {
 }
 
 void update_frequencies(DTMFDolphinDialerModel *model) {
-    dtmf_dolphin_get_tone_frequencies(model->freq, model->row, model->col, DTMF_DOLPHIN_TONE_BLOCK_DIALER);
+    dtmf_dolphin_data_get_tone_frequencies(&model->freq1, &model->freq2, model->row, model->col);
 }
 
 static void dtmf_dolphin_dialer_draw_callback(Canvas* canvas, void* _model) {
     DTMFDolphinDialerModel* model = _model;
+    update_frequencies(model);
     uint8_t max_rows;
     uint8_t max_cols;
     uint8_t max_span;
-    dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span, DTMF_DOLPHIN_TONE_BLOCK_DIALER);
+    dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span);
 
     canvas_set_font(canvas, FontPrimary);
-    elements_multiline_text(canvas, 2, 10, "Dialer");
+    elements_multiline_text(canvas, 2, 10, dtmf_dolphin_data_get_current_section_name());
     canvas_draw_line(canvas,
         (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1, 0,
         (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1, canvas_height(canvas));
@@ -110,8 +114,8 @@ static void dtmf_dolphin_dialer_draw_callback(Canvas* canvas, void* _model) {
     string_cat_printf(
         output,
         "F1: %u Hz\nF2: %u Hz",
-        model->freq[0] ? (unsigned int) model->freq[0] : 0,
-        model->freq[1] ? (unsigned int) model->freq[1] : 0);
+        model->freq1 ? (unsigned int) model->freq1 : 0,
+        model->freq2 ? (unsigned int) model->freq2 : 0);
 
     canvas_set_font(canvas, FontSecondary);
     canvas_set_color(canvas, ColorBlack);
@@ -148,7 +152,6 @@ static bool dtmf_dolphin_dialer_process_up(DTMFDolphinDialer* dtmf_dolphin_diale
         dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
             if(model->row > 0) {
                 model->row--;
-                update_frequencies(model);
             }
             return true;
         });
@@ -159,13 +162,12 @@ static bool dtmf_dolphin_dialer_process_down(DTMFDolphinDialer* dtmf_dolphin_dia
     uint8_t max_rows = 0;
     uint8_t max_cols = 0;
     uint8_t max_span = 0;
-    dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span, DTMF_DOLPHIN_TONE_BLOCK_DIALER);
+    dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span);
 
     with_view_model(
         dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
             if(model->row < max_rows - 1) {
                 model->row++;
-                update_frequencies(model);
             }
             return true;
         });
@@ -177,7 +179,6 @@ static bool dtmf_dolphin_dialer_process_left(DTMFDolphinDialer* dtmf_dolphin_dia
         dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
             if(model->col > 0) {
                 model->col--;
-                update_frequencies(model);
             }
             return true;
         });
@@ -188,13 +189,12 @@ static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_di
     uint8_t max_rows = 0;
     uint8_t max_cols = 0;
     uint8_t max_span = 0;
-    dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span, DTMF_DOLPHIN_TONE_BLOCK_DIALER);
+    dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span);
 
     with_view_model(
         dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
             if(model->col < max_cols - 1) {
                 model->col++;
-                update_frequencies(model);
             }
             return true;
         });
@@ -207,9 +207,9 @@ static bool dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_diale
     with_view_model(
         dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
             if (event->type == InputTypePress) {
-                dtmf_dolphin_player_play_tones(model->freq);
+                dtmf_dolphin_audio_play_tones(model->freq1, model->freq2);
             } else if (event->type == InputTypeRelease) {
-                dtmf_dolphin_player_stop_tones();
+                dtmf_dolphin_audio_stop_tones();
             }
 
             return true;
@@ -228,8 +228,9 @@ DTMFDolphinDialer* dtmf_dolphin_dialer_alloc() {
         dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
             model->col = 0;
             model->row = 0;
-            model->freq = malloc(sizeof(float) * 2);
-            update_frequencies(model);
+            model->section = 0;
+            model->freq1 = 0.0;
+            model->freq2 = 0.0;
             return true;
         }
     );
@@ -243,12 +244,6 @@ DTMFDolphinDialer* dtmf_dolphin_dialer_alloc() {
 
 void dtmf_dolphin_dialer_free(DTMFDolphinDialer* dtmf_dolphin_dialer) {
     furi_assert(dtmf_dolphin_dialer);
-    with_view_model(
-        dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
-            free(model->freq);
-            return true;
-        }
-    );
     view_free(dtmf_dolphin_dialer->view);
     free(dtmf_dolphin_dialer);
 }

+ 0 - 2
views/dtmf_dolphin_dialer.h

@@ -1,8 +1,6 @@
 #pragma once
 
 #include <gui/view.h>
-#include "../dtmf_dolphin_event.h"
-#include "../dtmf_dolphin_tone.h"
 #include "dtmf_dolphin_common.h"
 
 typedef struct DTMFDolphinDialer DTMFDolphinDialer;