./fbt format

This commit is contained in:
RogueMaster
2022-09-21 14:28:03 -04:00
parent 3f3258d9f3
commit 32e18d5500
37 changed files with 2764 additions and 2572 deletions
+133 -137
View File
@@ -16,70 +16,69 @@ typedef struct {
InputEvent input; InputEvent input;
} PluginEvent; } PluginEvent;
//QUEUE //QUEUE
struct node { struct node {
int interval; int interval;
struct node *next; struct node* next;
}; };
typedef struct node node; typedef struct node node;
typedef struct { typedef struct {
int size; int size;
int max_size; int max_size;
node *front; node* front;
node *rear; node* rear;
} queue; } queue;
static void init_queue(queue *q) { static void init_queue(queue* q) {
q->size = 0; q->size = 0;
q->max_size = 8; q->max_size = 8;
q->front = NULL; q->front = NULL;
q->rear = NULL; q->rear = NULL;
} }
static void queue_remove(queue *q) { static void queue_remove(queue* q) {
node *tmp; node* tmp;
tmp = q->front; tmp = q->front;
q->front = q->front->next; q->front = q->front->next;
q->size--; q->size--;
free(tmp); free(tmp);
} }
static void queue_add(queue *q, int value) { static void queue_add(queue* q, int value) {
node *tmp = malloc(sizeof(node)); node* tmp = malloc(sizeof(node));
tmp->interval = value; tmp->interval = value;
tmp->next = NULL; tmp->next = NULL;
if (q->size == q->max_size) { if(q->size == q->max_size) {
queue_remove(q); queue_remove(q);
} }
// check if empty // check if empty
if (q->rear == NULL) { if(q->rear == NULL) {
q->front = tmp; q->front = tmp;
q->rear = tmp; q->rear = tmp;
} else { } else {
q->rear->next = tmp; q->rear->next = tmp;
q->rear = tmp; q->rear = tmp;
} }
q->size++; q->size++;
} }
static float queue_avg(queue *q) { static float queue_avg(queue* q) {
float avg = 0.0; float avg = 0.0;
if (q->size == 0){ if(q->size == 0) {
return avg; return avg;
} else { } else {
node *tmp; node* tmp;
float sum = 0.0; float sum = 0.0;
tmp = q->front; tmp = q->front;
while (tmp != NULL) { while(tmp != NULL) {
sum = sum + tmp->interval; sum = sum + tmp->interval;
tmp = tmp->next; tmp = tmp->next;
} }
avg = sum / q->size; avg = sum / q->size;
FURI_LOG_D("BPM-Tapper", "Sum: %.2f Avg: %.2f", (double)sum, (double)avg); FURI_LOG_D("BPM-Tapper", "Sum: %.2f Avg: %.2f", (double)sum, (double)avg);
return avg; return avg;
} }
} }
@@ -95,33 +94,32 @@ typedef struct {
double bpm; double bpm;
uint32_t last_stamp; uint32_t last_stamp;
uint32_t interval; uint32_t interval;
queue *tap_queue; queue* tap_queue;
} BPMTapper; } BPMTapper;
static void show_hello() { static void show_hello() {
// BEGIN HELLO DIALOG
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
DialogMessage* message = dialog_message_alloc();
// BEGIN HELLO DIALOG const char* header_text = "BPM Tapper";
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); const char* message_text = "Tap center to start";
DialogMessage* message = dialog_message_alloc();
const char* header_text = "BPM Tapper"; dialog_message_set_header(message, header_text, 63, 3, AlignCenter, AlignTop);
const char* message_text = "Tap center to start"; dialog_message_set_text(message, message_text, 0, 17, AlignLeft, AlignTop);
dialog_message_set_buttons(message, NULL, "Tap", NULL);
dialog_message_set_header(message, header_text, 63, 3, AlignCenter, AlignTop); dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
dialog_message_set_text(message, message_text, 0, 17, AlignLeft, AlignTop);
dialog_message_set_buttons(message, NULL, "Tap", NULL);
dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17); dialog_message_show(dialogs, message);
dialog_message_show(dialogs, message); dialog_message_free(message);
furi_record_close(RECORD_DIALOGS);
dialog_message_free(message); // END HELLO DIALOG
furi_record_close(RECORD_DIALOGS);
// END HELLO DIALOG
} }
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue); furi_assert(event_queue);
PluginEvent event = {.type = EventTypeKey, .input = *input_event}; PluginEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever); furi_message_queue_put(event_queue, &event, FuriWaitForever);
@@ -131,8 +129,8 @@ static void render_callback(Canvas* const canvas, void* ctx) {
string_t tempStr; string_t tempStr;
const BPMTapper* bpm_state = acquire_mutex((ValueMutex*)ctx, 25); const BPMTapper* bpm_state = acquire_mutex((ValueMutex*)ctx, 25);
if (bpm_state == NULL) { if(bpm_state == NULL) {
return; return;
} }
// border // border
//canvas_draw_frame(canvas, 0, 0, 128, 64); //canvas_draw_frame(canvas, 0, 0, 128, 64);
@@ -152,7 +150,7 @@ static void render_callback(Canvas* const canvas, void* ctx) {
canvas_draw_str_aligned(canvas, 5, 20, AlignLeft, AlignBottom, string_get_cstr(tempStr)); canvas_draw_str_aligned(canvas, 5, 20, AlignLeft, AlignBottom, string_get_cstr(tempStr));
string_reset(tempStr); string_reset(tempStr);
string_printf(tempStr, "x2 %.2f /2 %.2f", bpm_state->bpm*2, bpm_state->bpm/2); string_printf(tempStr, "x2 %.2f /2 %.2f", bpm_state->bpm * 2, bpm_state->bpm / 2);
canvas_draw_str_aligned(canvas, 64, 60, AlignCenter, AlignCenter, string_get_cstr(tempStr)); canvas_draw_str_aligned(canvas, 64, 60, AlignCenter, AlignCenter, string_get_cstr(tempStr));
string_reset(tempStr); string_reset(tempStr);
@@ -166,97 +164,95 @@ static void render_callback(Canvas* const canvas, void* ctx) {
release_mutex((ValueMutex*)ctx, bpm_state); release_mutex((ValueMutex*)ctx, bpm_state);
} }
static void bpm_state_init(BPMTapper* const plugin_state) { static void bpm_state_init(BPMTapper* const plugin_state) {
plugin_state->taps = 0; plugin_state->taps = 0;
plugin_state->bpm = 120.0; plugin_state->bpm = 120.0;
plugin_state->last_stamp = 0;// furi_get_tick(); plugin_state->last_stamp = 0; // furi_get_tick();
plugin_state->interval = 0; plugin_state->interval = 0;
queue *q; queue* q;
q = malloc(sizeof(queue)); q = malloc(sizeof(queue));
init_queue(q); init_queue(q);
plugin_state->tap_queue = q; plugin_state->tap_queue = q;
} }
int32_t bpm_tapper_app(void* p) { int32_t bpm_tapper_app(void* p) {
UNUSED(p); UNUSED(p);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
BPMTapper* bpm_state = malloc(sizeof(BPMTapper));
// setup
bpm_state_init(bpm_state);
ValueMutex state_mutex;
if (!init_mutex(&state_mutex, bpm_state, sizeof(bpm_state))) {
FURI_LOG_E("BPM-Tapper", "cannot create mutex\r\n");
free(bpm_state);
return 255;
}
show_hello();
// BEGIN IMPLEMENTATION BPMTapper* bpm_state = malloc(sizeof(BPMTapper));
// setup
bpm_state_init(bpm_state);
// Set system callbacks ValueMutex state_mutex;
ViewPort* view_port = view_port_alloc(); if(!init_mutex(&state_mutex, bpm_state, sizeof(bpm_state))) {
view_port_draw_callback_set(view_port, render_callback, &state_mutex); FURI_LOG_E("BPM-Tapper", "cannot create mutex\r\n");
view_port_input_callback_set(view_port, input_callback, event_queue); free(bpm_state);
return 255;
// Open GUI and register view_port
Gui* gui = furi_record_open("gui");
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
PluginEvent event;
for (bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
BPMTapper* bpm_state = (BPMTapper*)acquire_mutex_block(&state_mutex);
if(event_status == FuriStatusOk) {
// press events
if(event.type == EventTypeKey) {
if(event.input.type == InputTypePress) {
switch(event.input.key) {
case InputKeyUp:
case InputKeyDown:
case InputKeyRight:
case InputKeyLeft:
case InputKeyOk:
bpm_state->taps++;
uint32_t new_stamp = furi_get_tick();
if (bpm_state->last_stamp == 0) {
bpm_state->last_stamp = new_stamp;
break;
}
bpm_state->interval = new_stamp - bpm_state->last_stamp;
bpm_state->last_stamp = new_stamp;
queue_add(bpm_state->tap_queue, bpm_state->interval);
float avg = queue_avg(bpm_state->tap_queue);
float bps = 1.0 / (avg / 1000.0);
bpm_state->bpm = bps * 60.0;
break;
case InputKeyBack:
// Exit the plugin
processing = false;
break;
}
}
}
} else {
FURI_LOG_D("BPM-Tapper", "FuriMessageQueue: event timeout");
// event timeout
} }
view_port_update(view_port); show_hello();
release_mutex(&state_mutex, bpm_state);
}
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close("gui");
view_port_free(view_port);
furi_message_queue_free(event_queue);
delete_mutex(&state_mutex);
queue *q = bpm_state->tap_queue;
free(q);
free(bpm_state);
return 0; // BEGIN IMPLEMENTATION
// Set system callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, render_callback, &state_mutex);
view_port_input_callback_set(view_port, input_callback, event_queue);
// Open GUI and register view_port
Gui* gui = furi_record_open("gui");
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
PluginEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
BPMTapper* bpm_state = (BPMTapper*)acquire_mutex_block(&state_mutex);
if(event_status == FuriStatusOk) {
// press events
if(event.type == EventTypeKey) {
if(event.input.type == InputTypePress) {
switch(event.input.key) {
case InputKeyUp:
case InputKeyDown:
case InputKeyRight:
case InputKeyLeft:
case InputKeyOk:
bpm_state->taps++;
uint32_t new_stamp = furi_get_tick();
if(bpm_state->last_stamp == 0) {
bpm_state->last_stamp = new_stamp;
break;
}
bpm_state->interval = new_stamp - bpm_state->last_stamp;
bpm_state->last_stamp = new_stamp;
queue_add(bpm_state->tap_queue, bpm_state->interval);
float avg = queue_avg(bpm_state->tap_queue);
float bps = 1.0 / (avg / 1000.0);
bpm_state->bpm = bps * 60.0;
break;
case InputKeyBack:
// Exit the plugin
processing = false;
break;
}
}
}
} else {
FURI_LOG_D("BPM-Tapper", "FuriMessageQueue: event timeout");
// event timeout
}
view_port_update(view_port);
release_mutex(&state_mutex, bpm_state);
}
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close("gui");
view_port_free(view_port);
furi_message_queue_free(event_queue);
delete_mutex(&state_mutex);
queue* q = bpm_state->tap_queue;
free(q);
free(bpm_state);
return 0;
} }
+2 -2
View File
@@ -425,11 +425,11 @@ int32_t calculator_app(void* p) {
view_port_update(view_port); view_port_update(view_port);
} }
if(event.type == InputTypeLong) { if(event.type == InputTypeLong) {
switch(event.key) { switch(event.key) {
case InputKeyOk: case InputKeyOk:
if (calculator_state->position.x == 0 && calculator_state->position.y == 4) { if(calculator_state->position.x == 0 && calculator_state->position.y == 4) {
if(calculator_state->textLength < MAX_TEXT_LENGTH) { if(calculator_state->textLength < MAX_TEXT_LENGTH) {
calculator_state->text[calculator_state->textLength++] = ')'; calculator_state->text[calculator_state->textLength++] = ')';
calculator_state->text[calculator_state->textLength] = '\0'; calculator_state->text[calculator_state->textLength] = '\0';
+31 -21
View File
@@ -26,59 +26,69 @@
#ifndef TINYEXPR_H #ifndef TINYEXPR_H
#define TINYEXPR_H #define TINYEXPR_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct te_expr { typedef struct te_expr {
int type; int type;
union {double value; const double *bound; const void *function;}; union {
void *parameters[1]; double value;
const double* bound;
const void* function;
};
void* parameters[1];
} te_expr; } te_expr;
enum { enum {
TE_VARIABLE = 0, TE_VARIABLE = 0,
TE_FUNCTION0 = 8, TE_FUNCTION1, TE_FUNCTION2, TE_FUNCTION3, TE_FUNCTION0 = 8,
TE_FUNCTION4, TE_FUNCTION5, TE_FUNCTION6, TE_FUNCTION7, TE_FUNCTION1,
TE_FUNCTION2,
TE_FUNCTION3,
TE_FUNCTION4,
TE_FUNCTION5,
TE_FUNCTION6,
TE_FUNCTION7,
TE_CLOSURE0 = 16, TE_CLOSURE1, TE_CLOSURE2, TE_CLOSURE3, TE_CLOSURE0 = 16,
TE_CLOSURE4, TE_CLOSURE5, TE_CLOSURE6, TE_CLOSURE7, TE_CLOSURE1,
TE_CLOSURE2,
TE_CLOSURE3,
TE_CLOSURE4,
TE_CLOSURE5,
TE_CLOSURE6,
TE_CLOSURE7,
TE_FLAG_PURE = 32 TE_FLAG_PURE = 32
}; };
typedef struct te_variable { typedef struct te_variable {
const char *name; const char* name;
const void *address; const void* address;
int type; int type;
void *context; void* context;
} te_variable; } te_variable;
/* Parses the input expression, evaluates it, and frees it. */ /* Parses the input expression, evaluates it, and frees it. */
/* Returns NaN on error. */ /* Returns NaN on error. */
double te_interp(const char *expression, int *error); double te_interp(const char* expression, int* error);
/* Parses the input expression and binds variables. */ /* Parses the input expression and binds variables. */
/* Returns NULL on error. */ /* Returns NULL on error. */
te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error); te_expr*
te_compile(const char* expression, const te_variable* variables, int var_count, int* error);
/* Evaluates the expression. */ /* Evaluates the expression. */
double te_eval(const te_expr *n); double te_eval(const te_expr* n);
/* Prints debugging information on the syntax tree. */ /* Prints debugging information on the syntax tree. */
void te_print(const te_expr *n); void te_print(const te_expr* n);
/* Frees the expression. */ /* Frees the expression. */
/* This is safe to call on NULL pointers. */ /* This is safe to call on NULL pointers. */
void te_free(te_expr *n); void te_free(te_expr* n);
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -11,7 +11,8 @@ static void storage_DolphinBackup_scene_confirm_widget_callback(
furi_assert(app); furi_assert(app);
if(type == InputTypeShort) { if(type == InputTypeShort) {
if(result == GuiButtonTypeRight) { if(result == GuiButtonTypeRight) {
view_dispatcher_send_custom_event(app->view_dispatcher, DolphinBackupCustomEventConfirm); view_dispatcher_send_custom_event(
app->view_dispatcher, DolphinBackupCustomEventConfirm);
} else if(result == GuiButtonTypeLeft) { } else if(result == GuiButtonTypeLeft) {
view_dispatcher_send_custom_event(app->view_dispatcher, DolphinBackupCustomEventExit); view_dispatcher_send_custom_event(app->view_dispatcher, DolphinBackupCustomEventExit);
} }
@@ -83,10 +83,10 @@ static void app_free(DTMFDolphinApp* app) {
free(app); free(app);
} }
int32_t dtmf_dolphin_app(void *p) { int32_t dtmf_dolphin_app(void* p) {
UNUSED(p); UNUSED(p);
DTMFDolphinApp* app = app_alloc(); DTMFDolphinApp* app = app_alloc();
view_dispatcher_run(app->view_dispatcher); view_dispatcher_run(app->view_dispatcher);
app_free(app); app_free(app);
@@ -1,11 +1,11 @@
#include "dtmf_dolphin_audio.h" #include "dtmf_dolphin_audio.h"
DTMFDolphinAudio *current_player; DTMFDolphinAudio* current_player;
static void dtmf_dolphin_audio_dma_isr(void* ctx) { static void dtmf_dolphin_audio_dma_isr(void* ctx) {
FuriMessageQueue *event_queue = ctx; FuriMessageQueue* event_queue = ctx;
if (LL_DMA_IsActiveFlag_HT1(DMA1)) { if(LL_DMA_IsActiveFlag_HT1(DMA1)) {
LL_DMA_ClearFlag_HT1(DMA1); LL_DMA_ClearFlag_HT1(DMA1);
DTMFDolphinCustomEvent event = {.type = DTMFDolphinEventDMAHalfTransfer}; DTMFDolphinCustomEvent event = {.type = DTMFDolphinEventDMAHalfTransfer};
@@ -21,13 +21,13 @@ static void dtmf_dolphin_audio_dma_isr(void* ctx) {
} }
void dtmf_dolphin_audio_clear_samples(DTMFDolphinAudio* player) { void dtmf_dolphin_audio_clear_samples(DTMFDolphinAudio* player) {
for (size_t i = 0; i < player->buffer_length; i++) { for(size_t i = 0; i < player->buffer_length; i++) {
player->sample_buffer[i] = 0; player->sample_buffer[i] = 0;
} }
} }
DTMFDolphinOsc* dtmf_dolphin_osc_alloc() { DTMFDolphinOsc* dtmf_dolphin_osc_alloc() {
DTMFDolphinOsc *osc = malloc(sizeof(DTMFDolphinOsc)); DTMFDolphinOsc* osc = malloc(sizeof(DTMFDolphinOsc));
osc->cached_freq = 0; osc->cached_freq = 0;
osc->offset = 0; osc->offset = 0;
osc->period = 0; osc->period = 0;
@@ -36,7 +36,7 @@ DTMFDolphinOsc* dtmf_dolphin_osc_alloc() {
} }
DTMFDolphinAudio* dtmf_dolphin_audio_alloc() { DTMFDolphinAudio* dtmf_dolphin_audio_alloc() {
DTMFDolphinAudio *player = malloc(sizeof(DTMFDolphinAudio)); DTMFDolphinAudio* player = malloc(sizeof(DTMFDolphinAudio));
player->buffer_length = SAMPLE_BUFFER_LENGTH; player->buffer_length = SAMPLE_BUFFER_LENGTH;
player->half_buffer_length = SAMPLE_BUFFER_LENGTH / 2; player->half_buffer_length = SAMPLE_BUFFER_LENGTH / 2;
player->sample_buffer = malloc(sizeof(uint16_t) * player->buffer_length); player->sample_buffer = malloc(sizeof(uint16_t) * player->buffer_length);
@@ -50,34 +50,32 @@ DTMFDolphinAudio* dtmf_dolphin_audio_alloc() {
} }
size_t calc_waveform_period(float freq) { size_t calc_waveform_period(float freq) {
if (!freq) { if(!freq) {
return 0; return 0;
} }
// DMA Rate calculation, thanks to Dr_Zlo // DMA Rate calculation, thanks to Dr_Zlo
float dma_rate = CPU_CLOCK_FREQ \ float dma_rate = CPU_CLOCK_FREQ / 2 / DTMF_DOLPHIN_HAL_DMA_PRESCALER /
/ 2 \ (DTMF_DOLPHIN_HAL_DMA_AUTORELOAD + 1);
/ DTMF_DOLPHIN_HAL_DMA_PRESCALER \
/ (DTMF_DOLPHIN_HAL_DMA_AUTORELOAD + 1);
// Using a constant scaling modifier, which likely represents // Using a constant scaling modifier, which likely represents
// the combined system overhead and isr latency. // the combined system overhead and isr latency.
return (uint16_t) dma_rate * 2 / freq * 0.801923; return (uint16_t)dma_rate * 2 / freq * 0.801923;
} }
void osc_generate_lookup_table(DTMFDolphinOsc* osc, float freq) { void osc_generate_lookup_table(DTMFDolphinOsc* osc, float freq) {
if (osc->lookup_table != NULL) { if(osc->lookup_table != NULL) {
free(osc->lookup_table); free(osc->lookup_table);
} }
osc->offset = 0; osc->offset = 0;
osc->cached_freq = freq; osc->cached_freq = freq;
osc->period = calc_waveform_period(freq); osc->period = calc_waveform_period(freq);
if (!osc->period) { if(!osc->period) {
osc->lookup_table = NULL; osc->lookup_table = NULL;
return; return;
} }
osc->lookup_table = malloc(sizeof(float) * osc->period); osc->lookup_table = malloc(sizeof(float) * osc->period);
for (size_t i = 0; i < osc->period; i++) { for(size_t i = 0; i < osc->period; i++) {
osc->lookup_table[i] = sin(i * PERIOD_2_PI / osc->period) + 1; osc->lookup_table[i] = sin(i * PERIOD_2_PI / osc->period) + 1;
} }
} }
@@ -85,7 +83,7 @@ void osc_generate_lookup_table(DTMFDolphinOsc* osc, float freq) {
float sample_frame(DTMFDolphinOsc* osc) { float sample_frame(DTMFDolphinOsc* osc) {
float frame = 0.0; float frame = 0.0;
if (osc->period) { if(osc->period) {
frame = osc->lookup_table[osc->offset]; frame = osc->lookup_table[osc->offset];
osc->offset = (osc->offset + 1) % osc->period; osc->offset = (osc->offset + 1) % osc->period;
} }
@@ -103,7 +101,7 @@ void dtmf_dolphin_audio_free(DTMFDolphinAudio* player) {
} }
void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc) { void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc) {
if (osc->lookup_table != NULL) { if(osc->lookup_table != NULL) {
free(osc->lookup_table); free(osc->lookup_table);
} }
free(osc); free(osc);
@@ -112,18 +110,16 @@ void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc) {
bool generate_waveform(DTMFDolphinAudio* player, uint16_t buffer_index) { bool generate_waveform(DTMFDolphinAudio* player, uint16_t buffer_index) {
uint16_t* sample_buffer_start = &player->sample_buffer[buffer_index]; uint16_t* sample_buffer_start = &player->sample_buffer[buffer_index];
for (size_t i = 0; i < player->half_buffer_length; i++) { for(size_t i = 0; i < player->half_buffer_length; i++) {
float data = 0; float data = 0;
if (player->osc2->period) { if(player->osc2->period) {
data = \ data = (sample_frame(player->osc1) / 2) + (sample_frame(player->osc2) / 2);
(sample_frame(player->osc1) / 2) + \
(sample_frame(player->osc2) / 2);
} else { } else {
data = (sample_frame(player->osc1)); data = (sample_frame(player->osc1));
} }
data *= player->volume; data *= player->volume;
data *= UINT8_MAX / 2; // scale -128..127 data *= UINT8_MAX / 2; // scale -128..127
data += UINT8_MAX / 2; // to unsigned data += UINT8_MAX / 2; // to unsigned
if(data < 0) { if(data < 0) {
data = 0; data = 0;
@@ -151,7 +147,8 @@ bool dtmf_dolphin_audio_play_tones(float freq1, float freq2) {
dtmf_dolphin_speaker_init(); dtmf_dolphin_speaker_init();
dtmf_dolphin_dma_init((uint32_t)current_player->sample_buffer, current_player->buffer_length); 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); furi_hal_interrupt_set_isr(
FuriHalInterruptIdDma1Ch1, dtmf_dolphin_audio_dma_isr, current_player->queue);
dtmf_dolphin_dma_start(); dtmf_dolphin_dma_start();
dtmf_dolphin_speaker_start(); dtmf_dolphin_speaker_start();
@@ -165,20 +162,20 @@ bool dtmf_dolphin_audio_stop_tones() {
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL); furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);
dtmf_dolphin_audio_free(current_player); dtmf_dolphin_audio_free(current_player);
return true; return true;
} }
bool dtmf_dolphin_audio_handle_tick() { bool dtmf_dolphin_audio_handle_tick() {
bool handled = false; bool handled = false;
if (current_player) { if(current_player) {
DTMFDolphinCustomEvent event; DTMFDolphinCustomEvent event;
if(furi_message_queue_get(current_player->queue, &event, 250) == FuriStatusOk) { if(furi_message_queue_get(current_player->queue, &event, 250) == FuriStatusOk) {
if(event.type == DTMFDolphinEventDMAHalfTransfer) { if(event.type == DTMFDolphinEventDMAHalfTransfer) {
generate_waveform(current_player, 0); generate_waveform(current_player, 0);
handled = true; handled = true;
} else if (event.type == DTMFDolphinEventDMAFullTransfer) { } else if(event.type == DTMFDolphinEventDMAFullTransfer) {
generate_waveform(current_player, current_player->half_buffer_length); generate_waveform(current_player, current_player->half_buffer_length);
handled = true; handled = true;
} }
@@ -17,12 +17,12 @@ typedef struct {
typedef struct { typedef struct {
size_t buffer_length; size_t buffer_length;
size_t half_buffer_length; size_t half_buffer_length;
uint8_t *buffer_buffer; uint8_t* buffer_buffer;
uint16_t *sample_buffer; uint16_t* sample_buffer;
float volume; float volume;
FuriMessageQueue *queue; FuriMessageQueue* queue;
DTMFDolphinOsc *osc1; DTMFDolphinOsc* osc1;
DTMFDolphinOsc *osc2; DTMFDolphinOsc* osc2;
} DTMFDolphinAudio; } DTMFDolphinAudio;
DTMFDolphinOsc* dtmf_dolphin_osc_alloc(); DTMFDolphinOsc* dtmf_dolphin_osc_alloc();
@@ -7,13 +7,13 @@ typedef struct {
} DTMFDolphinTonePos; } DTMFDolphinTonePos;
typedef struct { typedef struct {
const char *name; const char* name;
const float frequency_1; const float frequency_1;
const float frequency_2; const float frequency_2;
const DTMFDolphinTonePos pos; const DTMFDolphinTonePos pos;
const uint16_t pulses; // for Redbox const uint16_t pulses; // for Redbox
const uint16_t pulse_ms; // for Redbox const uint16_t pulse_ms; // for Redbox
const uint16_t gap_duration; // for Redbox const uint16_t gap_duration; // for Redbox
} DTMFDolphinTones; } DTMFDolphinTones;
typedef struct { typedef struct {
@@ -44,41 +44,38 @@ DTMFDolphinSceneData DTMFDolphinSceneDataDialer = {
{"0", 941.0, 1336.0, {3, 1, 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}, {"#", 941.0, 1477.0, {3, 2, 1}, 0, 0, 0},
{"D", 941.0, 1633.0, {3, 3, 1}, 0, 0, 0}, {"D", 941.0, 1633.0, {3, 3, 1}, 0, 0, 0},
} }};
};
DTMFDolphinSceneData DTMFDolphinSceneDataBluebox = { DTMFDolphinSceneData DTMFDolphinSceneDataBluebox = {
.name = "Bluebox", .name = "Bluebox",
.block = DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX, .block = DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX,
.tone_count = 13, .tone_count = 13,
.tones = { .tones = {
{"1", 700.0, 900.0, {0, 0, 1}, 0, 0, 0}, {"1", 700.0, 900.0, {0, 0, 1}, 0, 0, 0},
{"2", 700.0, 1100.0, {0, 1, 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}, {"3", 900.0, 1100.0, {0, 2, 1}, 0, 0, 0},
{"4", 700.0, 1300.0, {1, 0, 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}, {"5", 900.0, 1300.0, {1, 1, 1}, 0, 0, 0},
{"6", 1100.0, 1300.0, {1, 2, 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}, {"7", 700.0, 1500.0, {2, 0, 1}, 0, 0, 0},
{"8", 900.0, 1500.0, {2, 1, 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}, {"9", 1100.0, 1500.0, {2, 2, 1}, 0, 0, 0},
{"0", 1300.0, 1500.0, {3, 1, 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}, {"KP", 1100.0, 1700.0, {0, 3, 2}, 0, 0, 0},
{"ST", 1500.0, 1700.0, {1, 3, 2}, 0, 0, 0}, {"ST", 1500.0, 1700.0, {1, 3, 2}, 0, 0, 0},
{"2600", 2600.0, 0.0, {3, 2, 3}, 0, 0, 0}, {"2600", 2600.0, 0.0, {3, 2, 3}, 0, 0, 0},
} }};
};
DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUS = { DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUS = {
.name = "Redbox (US)", .name = "Redbox (US)",
.block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US, .block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US,
.tone_count = 4, .tone_count = 4,
.tones = { .tones = {
{"Nickel", 1700.0, 2200.0, {0, 0, 5}, 1, 66, 0}, {"Nickel", 1700.0, 2200.0, {0, 0, 5}, 1, 66, 0},
{"Dime", 1700.0, 2200.0, {1, 0, 5}, 2, 66, 66}, {"Dime", 1700.0, 2200.0, {1, 0, 5}, 2, 66, 66},
{"Quarter", 1700.0, 2200.0, {2, 0, 5}, 5, 33, 33}, {"Quarter", 1700.0, 2200.0, {2, 0, 5}, 5, 33, 33},
{"Dollar", 1700.0, 2200.0, {3, 0, 5}, 1, 650, 0}, {"Dollar", 1700.0, 2200.0, {3, 0, 5}, 1, 650, 0},
} }};
};
DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUK = { DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUK = {
.name = "Redbox (UK)", .name = "Redbox (UK)",
@@ -87,28 +84,25 @@ DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUK = {
.tones = { .tones = {
{"10p", 1000.0, 0.0, {0, 0, 3}, 1, 200, 0}, {"10p", 1000.0, 0.0, {0, 0, 3}, 1, 200, 0},
{"50p", 1000.0, 0.0, {1, 0, 3}, 1, 350, 0}, {"50p", 1000.0, 0.0, {1, 0, 3}, 1, 350, 0},
} }};
};
DTMFDolphinSceneData DTMFDolphinSceneDataMisc = { DTMFDolphinSceneData DTMFDolphinSceneDataMisc = {
.name = "Misc", .name = "Misc",
.block = DTMF_DOLPHIN_TONE_BLOCK_MISC, .block = DTMF_DOLPHIN_TONE_BLOCK_MISC,
.tone_count = 3, .tone_count = 3,
.tones = { .tones = {
{"CCITT 11", 700.0, 1700.0, {0, 0, 5}, 0, 0, 0}, {"CCITT 11", 700.0, 1700.0, {0, 0, 5}, 0, 0, 0},
{"CCITT 12", 900.0, 1700.0, {1, 0, 5}, 0, 0, 0}, {"CCITT 12", 900.0, 1700.0, {1, 0, 5}, 0, 0, 0},
{"CCITT KP2", 1300.0, 1700.0, {2, 0, 5}, 0, 0, 0}, {"CCITT KP2", 1300.0, 1700.0, {2, 0, 5}, 0, 0, 0},
} }};
};
DTMFDolphinToneSection current_section; DTMFDolphinToneSection current_section;
DTMFDolphinSceneData *current_scene_data; DTMFDolphinSceneData* current_scene_data;
void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section) { void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section) {
current_section = section; current_section = section;
switch (current_section) switch(current_section) {
{
case DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX: case DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX:
current_scene_data = &DTMFDolphinSceneDataBluebox; current_scene_data = &DTMFDolphinSceneDataBluebox;
break; break;
@@ -131,14 +125,14 @@ DTMFDolphinToneSection dtmf_dolphin_data_get_current_section() {
return current_section; return current_section;
} }
DTMFDolphinSceneData *dtmf_dolphin_data_get_current_scene_data() { DTMFDolphinSceneData* dtmf_dolphin_data_get_current_scene_data() {
return current_scene_data; return current_scene_data;
} }
bool dtmf_dolphin_data_get_tone_frequencies(float *freq1, float *freq2, uint8_t row, uint8_t col) { 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++) { for(size_t i = 0; i < current_scene_data->tone_count; i++) {
DTMFDolphinTones tones = current_scene_data->tones[i]; DTMFDolphinTones tones = current_scene_data->tones[i];
if (tones.pos.row == row && tones.pos.col == col) { if(tones.pos.row == row && tones.pos.col == col) {
freq1[0] = tones.frequency_1; freq1[0] = tones.frequency_1;
freq2[0] = tones.frequency_2; freq2[0] = tones.frequency_2;
return true; return true;
@@ -148,9 +142,9 @@ bool dtmf_dolphin_data_get_tone_frequencies(float *freq1, float *freq2, uint8_t
} }
const char* dtmf_dolphin_data_get_tone_name(uint8_t row, uint8_t col) { 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++) { for(size_t i = 0; i < current_scene_data->tone_count; i++) {
DTMFDolphinTones tones = current_scene_data->tones[i]; DTMFDolphinTones tones = current_scene_data->tones[i];
if (tones.pos.row == row && tones.pos.col == col) { if(tones.pos.row == row && tones.pos.col == col) {
return tones.name; return tones.name;
} }
} }
@@ -158,7 +152,7 @@ const char* dtmf_dolphin_data_get_tone_name(uint8_t row, uint8_t col) {
} }
const char* dtmf_dolphin_data_get_current_section_name() { const char* dtmf_dolphin_data_get_current_section_name() {
if (current_scene_data) { if(current_scene_data) {
return current_scene_data->name; return current_scene_data->name;
} }
return NULL; return NULL;
@@ -168,27 +162,26 @@ void dtmf_dolphin_tone_get_max_pos(uint8_t* max_rows, uint8_t* max_cols, uint8_t
max_rows[0] = 0; max_rows[0] = 0;
max_cols[0] = 0; max_cols[0] = 0;
max_span[0] = 0; max_span[0] = 0;
uint8_t tmp_rowspan[5] = { 0, 0, 0, 0, 0 }; uint8_t tmp_rowspan[5] = {0, 0, 0, 0, 0};
for (size_t i = 0; i < current_scene_data->tone_count; i++) { for(size_t i = 0; i < current_scene_data->tone_count; i++) {
DTMFDolphinTones tones = current_scene_data->tones[i]; DTMFDolphinTones tones = current_scene_data->tones[i];
if (tones.pos.row > max_rows[0]) { if(tones.pos.row > max_rows[0]) {
max_rows[0] = tones.pos.row; max_rows[0] = tones.pos.row;
} }
if (tones.pos.col > max_cols[0]) { if(tones.pos.col > max_cols[0]) {
max_cols[0] = tones.pos.col; max_cols[0] = tones.pos.col;
} }
tmp_rowspan[tones.pos.row] += tones.pos.span; tmp_rowspan[tones.pos.row] += tones.pos.span;
if (tmp_rowspan[tones.pos.row] > max_span[0]) if(tmp_rowspan[tones.pos.row] > max_span[0]) max_span[0] = tmp_rowspan[tones.pos.row];
max_span[0] = tmp_rowspan[tones.pos.row];
} }
max_rows[0]++; max_rows[0]++;
max_cols[0]++; max_cols[0]++;
} }
uint8_t dtmf_dolphin_get_tone_span(uint8_t row, uint8_t col) { 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++) { for(size_t i = 0; i < current_scene_data->tone_count; i++) {
DTMFDolphinTones tones = current_scene_data->tones[i]; DTMFDolphinTones tones = current_scene_data->tones[i];
if (tones.pos.row == row && tones.pos.col == col) { if(tones.pos.row == row && tones.pos.col == col) {
return tones.pos.span; return tones.pos.span;
} }
} }
@@ -17,7 +17,7 @@ void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section);
DTMFDolphinToneSection dtmf_dolphin_data_get_current_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); 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_tone_name(uint8_t row, uint8_t col);
@@ -17,7 +17,6 @@
#define TAG "DTMFDolphin" #define TAG "DTMFDolphin"
enum DTMFDolphinSceneState { enum DTMFDolphinSceneState {
DTMFDolphinSceneStateDialer, DTMFDolphinSceneStateDialer,
DTMFDolphinSceneStateBluebox, DTMFDolphinSceneStateBluebox,
@@ -39,7 +38,4 @@ typedef struct {
NotificationApp* notification; NotificationApp* notification;
} DTMFDolphinApp; } DTMFDolphinApp;
typedef enum { typedef enum { DTMFDolphinViewMainMenu, DTMFDolphinViewDialer } DTMFDolphinView;
DTMFDolphinViewMainMenu,
DTMFDolphinViewDialer
} DTMFDolphinView;
@@ -2,17 +2,15 @@
// #include "../dtmf_dolphin_data.h" // #include "../dtmf_dolphin_data.h"
// #include "../dtmf_dolphin_audio.h" // #include "../dtmf_dolphin_audio.h"
void dtmf_dolphin_scene_dialer_on_enter(void* context) {
void dtmf_dolphin_scene_dialer_on_enter(void *context) {
DTMFDolphinApp* app = context; DTMFDolphinApp* app = context;
DTMFDolphinScene scene_id = DTMFDolphinSceneDialer; DTMFDolphinScene scene_id = DTMFDolphinSceneDialer;
enum DTMFDolphinSceneState state = scene_manager_get_scene_state(app->scene_manager, scene_id); enum DTMFDolphinSceneState state = scene_manager_get_scene_state(app->scene_manager, scene_id);
switch (state) switch(state) {
{
case DTMFDolphinSceneStateBluebox: case DTMFDolphinSceneStateBluebox:
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX); dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX);
break; break;
case DTMFDolphinSceneStateRedboxUS: case DTMFDolphinSceneStateRedboxUS:
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US); dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US);
break; break;
@@ -2,16 +2,10 @@
static void dtmf_dolphin_scene_start_main_menu_enter_callback(void* context, uint32_t index) { static void dtmf_dolphin_scene_start_main_menu_enter_callback(void* context, uint32_t index) {
DTMFDolphinApp* app = context; DTMFDolphinApp* app = context;
if (index == DTMFDolphinSceneStateDialer) { if(index == DTMFDolphinSceneStateDialer) {
view_dispatcher_send_custom_event( view_dispatcher_send_custom_event(app->view_dispatcher, DTMFDolphinEventStartDialer);
app->view_dispatcher, } else if(index == DTMFDolphinSceneStateBluebox) {
DTMFDolphinEventStartDialer view_dispatcher_send_custom_event(app->view_dispatcher, DTMFDolphinEventStartBluebox);
);
} else if (index == DTMFDolphinSceneStateBluebox) {
view_dispatcher_send_custom_event(
app->view_dispatcher,
DTMFDolphinEventStartBluebox
);
} }
} }
@@ -21,21 +15,16 @@ void dtmf_dolphin_scene_start_on_enter(void* context) {
// VariableItem* item; // VariableItem* item;
variable_item_list_set_enter_callback( variable_item_list_set_enter_callback(
var_item_list, var_item_list, dtmf_dolphin_scene_start_main_menu_enter_callback, app);
dtmf_dolphin_scene_start_main_menu_enter_callback,
app);
variable_item_list_add(var_item_list, "Dialer", 0, NULL, NULL); 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_add(var_item_list, "Misc", 0, NULL, NULL); variable_item_list_add(var_item_list, "Misc", 0, NULL, NULL);
variable_item_list_set_selected_item( variable_item_list_set_selected_item(
var_item_list, var_item_list, scene_manager_get_scene_state(app->scene_manager, DTMFDolphinSceneStart));
scene_manager_get_scene_state(app->scene_manager, DTMFDolphinSceneStart));
view_dispatcher_switch_to_view( view_dispatcher_switch_to_view(app->view_dispatcher, DTMFDolphinViewMainMenu);
app->view_dispatcher,
DTMFDolphinViewMainMenu);
} }
bool dtmf_dolphin_scene_start_on_event(void* context, SceneManagerEvent event) { bool dtmf_dolphin_scene_start_on_event(void* context, SceneManagerEvent event) {
@@ -44,14 +33,17 @@ bool dtmf_dolphin_scene_start_on_event(void* context, SceneManagerEvent event) {
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if (event.event == DTMFDolphinEventStartDialer) { if(event.event == DTMFDolphinEventStartDialer) {
scene_manager_set_scene_state(app->scene_manager, DTMFDolphinSceneDialer, DTMFDolphinSceneStateDialer); scene_manager_set_scene_state(
app->scene_manager, DTMFDolphinSceneDialer, DTMFDolphinSceneStateDialer);
scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneDialer); scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneDialer);
} else if (event.event == DTMFDolphinEventStartBluebox) { } else if(event.event == DTMFDolphinEventStartBluebox) {
scene_manager_set_scene_state(app->scene_manager, DTMFDolphinSceneDialer, DTMFDolphinSceneStateBluebox); scene_manager_set_scene_state(
app->scene_manager, DTMFDolphinSceneDialer, DTMFDolphinSceneStateBluebox);
scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneDialer); scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneDialer);
} else if (event.event == DTMFDolphinEventStartMisc) { } else if(event.event == DTMFDolphinEventStartMisc) {
scene_manager_set_scene_state(app->scene_manager, DTMFDolphinSceneDialer, DTMFDolphinSceneStateMisc); scene_manager_set_scene_state(
app->scene_manager, DTMFDolphinSceneDialer, DTMFDolphinSceneStateMisc);
scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneDialer); scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneDialer);
} }
consumed = true; consumed = true;
@@ -7,4 +7,4 @@
#define DTMF_DOLPHIN_NUMPAD_Y 14 #define DTMF_DOLPHIN_NUMPAD_Y 14
#define DTMF_DOLPHIN_BUTTON_WIDTH 13 #define DTMF_DOLPHIN_BUTTON_WIDTH 13
#define DTMF_DOLPHIN_BUTTON_HEIGHT 13 #define DTMF_DOLPHIN_BUTTON_HEIGHT 13
#define DTMF_DOLPHIN_BUTTON_PADDING 1 // all sides #define DTMF_DOLPHIN_BUTTON_PADDING 1 // all sides
@@ -21,53 +21,55 @@ static bool dtmf_dolphin_dialer_process_up(DTMFDolphinDialer* dtmf_dolphin_diale
static bool dtmf_dolphin_dialer_process_down(DTMFDolphinDialer* dtmf_dolphin_dialer); static bool dtmf_dolphin_dialer_process_down(DTMFDolphinDialer* dtmf_dolphin_dialer);
static bool dtmf_dolphin_dialer_process_left(DTMFDolphinDialer* dtmf_dolphin_dialer); static bool dtmf_dolphin_dialer_process_left(DTMFDolphinDialer* dtmf_dolphin_dialer);
static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_dialer); static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_dialer);
static bool dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event); static bool
dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event);
void draw_button(Canvas* canvas, uint8_t row, uint8_t col, bool invert) { void draw_button(Canvas* canvas, uint8_t row, uint8_t col, bool invert) {
uint8_t left = DTMF_DOLPHIN_NUMPAD_X + // ((col + 1) * DTMF_DOLPHIN_BUTTON_PADDING) +
uint8_t left = DTMF_DOLPHIN_NUMPAD_X + \ (col * DTMF_DOLPHIN_BUTTON_WIDTH);
// ((col + 1) * DTMF_DOLPHIN_BUTTON_PADDING) + // (col * DTMF_DOLPHIN_BUTTON_PADDING);
(col * DTMF_DOLPHIN_BUTTON_WIDTH); uint8_t top = DTMF_DOLPHIN_NUMPAD_Y + // ((row + 1) * DTMF_DOLPHIN_BUTTON_PADDING) +
// (col * DTMF_DOLPHIN_BUTTON_PADDING); (row * DTMF_DOLPHIN_BUTTON_HEIGHT);
uint8_t top = DTMF_DOLPHIN_NUMPAD_Y + \ // (row * DTMF_DOLPHIN_BUTTON_PADDING);
// ((row + 1) * DTMF_DOLPHIN_BUTTON_PADDING) +
(row * DTMF_DOLPHIN_BUTTON_HEIGHT);
// (row * DTMF_DOLPHIN_BUTTON_PADDING);
uint8_t span = dtmf_dolphin_get_tone_span(row, col); uint8_t span = dtmf_dolphin_get_tone_span(row, col);
if (span == 0) { if(span == 0) {
return; return;
} }
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
if (invert) if(invert)
canvas_draw_rbox(canvas, left, top, canvas_draw_rbox(
canvas,
left,
top,
(DTMF_DOLPHIN_BUTTON_WIDTH * span) - (DTMF_DOLPHIN_BUTTON_PADDING * 2), (DTMF_DOLPHIN_BUTTON_WIDTH * span) - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
DTMF_DOLPHIN_BUTTON_HEIGHT - (DTMF_DOLPHIN_BUTTON_PADDING * 2), DTMF_DOLPHIN_BUTTON_HEIGHT - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
2); 2);
else else
canvas_draw_rframe(canvas, left, top, canvas_draw_rframe(
canvas,
left,
top,
(DTMF_DOLPHIN_BUTTON_WIDTH * span) - (DTMF_DOLPHIN_BUTTON_PADDING * 2), (DTMF_DOLPHIN_BUTTON_WIDTH * span) - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
DTMF_DOLPHIN_BUTTON_HEIGHT- (DTMF_DOLPHIN_BUTTON_PADDING * 2), DTMF_DOLPHIN_BUTTON_HEIGHT - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
2); 2);
if (invert) if(invert) canvas_invert_color(canvas);
canvas_invert_color(canvas);
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
// canvas_set_color(canvas, invert ? ColorWhite : ColorBlack); // canvas_set_color(canvas, invert ? ColorWhite : ColorBlack);
canvas_draw_str_aligned(canvas, canvas_draw_str_aligned(
left - 1 + (int) ((DTMF_DOLPHIN_BUTTON_WIDTH * span) / 2), canvas,
top + (int) (DTMF_DOLPHIN_BUTTON_HEIGHT / 2), left - 1 + (int)((DTMF_DOLPHIN_BUTTON_WIDTH * span) / 2),
top + (int)(DTMF_DOLPHIN_BUTTON_HEIGHT / 2),
AlignCenter, AlignCenter,
AlignCenter, AlignCenter,
dtmf_dolphin_data_get_tone_name(row, col)); dtmf_dolphin_data_get_tone_name(row, col));
if (invert) if(invert) canvas_invert_color(canvas);
canvas_invert_color(canvas);
} }
void draw_dialer(Canvas* canvas, void* _model) { void draw_dialer(Canvas* canvas, void* _model) {
@@ -79,9 +81,9 @@ void draw_dialer(Canvas* canvas, void* _model) {
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
for (int r = 0; r < max_rows; r++) { for(int r = 0; r < max_rows; r++) {
for (int c = 0; c < max_cols; c++) { for(int c = 0; c < max_cols; c++) {
if (model->row == r && model->col == c) if(model->row == r && model->col == c)
draw_button(canvas, r, c, true); draw_button(canvas, r, c, true);
else else
draw_button(canvas, r, c, false); draw_button(canvas, r, c, false);
@@ -89,20 +91,20 @@ void draw_dialer(Canvas* canvas, void* _model) {
} }
} }
void update_frequencies(DTMFDolphinDialerModel *model) { void update_frequencies(DTMFDolphinDialerModel* model) {
dtmf_dolphin_data_get_tone_frequencies(&model->freq1, &model->freq2, model->row, model->col); 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) { static void dtmf_dolphin_dialer_draw_callback(Canvas* canvas, void* _model) {
DTMFDolphinDialerModel* model = _model; DTMFDolphinDialerModel* model = _model;
if (model->playing) { if(model->playing) {
// Leverage the prioritized draw callback to handle // Leverage the prioritized draw callback to handle
// the DMA so that it doesn't skip. // the DMA so that it doesn't skip.
dtmf_dolphin_audio_handle_tick(); dtmf_dolphin_audio_handle_tick();
// Don't do any drawing if audio is playing. // Don't do any drawing if audio is playing.
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned( elements_multiline_text_aligned(
canvas, canvas,
canvas_width(canvas) / 2, canvas_width(canvas) / 2,
canvas_height(canvas) / 2, canvas_height(canvas) / 2,
AlignCenter, AlignCenter,
@@ -118,11 +120,15 @@ static void dtmf_dolphin_dialer_draw_callback(Canvas* canvas, void* _model) {
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text(canvas, 2, 10, dtmf_dolphin_data_get_current_section_name()); elements_multiline_text(canvas, 2, 10, dtmf_dolphin_data_get_current_section_name());
canvas_draw_line(canvas, canvas_draw_line(
(max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1, 0, canvas,
(max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1, canvas_height(canvas)); (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1,
0,
(max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1,
canvas_height(canvas));
elements_multiline_text(canvas, (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 4, 10, "Detail"); elements_multiline_text(canvas, (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 4, 10, "Detail");
canvas_draw_line(canvas, 0, DTMF_DOLPHIN_NUMPAD_Y - 3, canvas_width(canvas), DTMF_DOLPHIN_NUMPAD_Y - 3); canvas_draw_line(
canvas, 0, DTMF_DOLPHIN_NUMPAD_Y - 3, canvas_width(canvas), DTMF_DOLPHIN_NUMPAD_Y - 3);
// elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Dialer Mode"); // elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Dialer Mode");
draw_dialer(canvas, model); draw_dialer(canvas, model);
@@ -130,22 +136,20 @@ static void dtmf_dolphin_dialer_draw_callback(Canvas* canvas, void* _model) {
string_t output; string_t output;
string_init(output); string_init(output);
if (model->freq1 && model->freq2) { if(model->freq1 && model->freq2) {
string_cat_printf( string_cat_printf(
output, output,
"Dual Tone\nF1: %u Hz\nF2: %u Hz\n", "Dual Tone\nF1: %u Hz\nF2: %u Hz\n",
(unsigned int) model->freq1, (unsigned int)model->freq1,
(unsigned int) model->freq2); (unsigned int)model->freq2);
} else if (model->freq1) { } else if(model->freq1) {
string_cat_printf( string_cat_printf(output, "Single Tone\nF: %u Hz\n", (unsigned int)model->freq1);
output,
"Single Tone\nF: %u Hz\n",
(unsigned int) model->freq1);
} }
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
elements_multiline_text(canvas, (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 4, 21, string_get_cstr(output)); elements_multiline_text(
canvas, (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 4, 21, string_get_cstr(output));
string_clear(output); string_clear(output);
} }
@@ -178,11 +182,11 @@ static bool dtmf_dolphin_dialer_process_up(DTMFDolphinDialer* dtmf_dolphin_diale
dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) { dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
uint8_t span = 0; uint8_t span = 0;
uint8_t cursor = model->row; uint8_t cursor = model->row;
while (span == 0 && cursor > 0) { while(span == 0 && cursor > 0) {
cursor--; cursor--;
span = dtmf_dolphin_get_tone_span(cursor, model->col); span = dtmf_dolphin_get_tone_span(cursor, model->col);
} }
if (span != 0) { if(span != 0) {
model->row = cursor; model->row = cursor;
} }
return true; return true;
@@ -204,7 +208,7 @@ static bool dtmf_dolphin_dialer_process_down(DTMFDolphinDialer* dtmf_dolphin_dia
cursor++; cursor++;
span = dtmf_dolphin_get_tone_span(cursor, model->col); span = dtmf_dolphin_get_tone_span(cursor, model->col);
} }
if (span != 0) { if(span != 0) {
model->row = cursor; model->row = cursor;
} }
return true; return true;
@@ -217,11 +221,11 @@ static bool dtmf_dolphin_dialer_process_left(DTMFDolphinDialer* dtmf_dolphin_dia
dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) { dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
uint8_t span = 0; uint8_t span = 0;
uint8_t cursor = model->col; uint8_t cursor = model->col;
while (span == 0 && cursor > 0) { while(span == 0 && cursor > 0) {
cursor--; cursor--;
span = dtmf_dolphin_get_tone_span(model->row, cursor); span = dtmf_dolphin_get_tone_span(model->row, cursor);
} }
if (span != 0) { if(span != 0) {
model->col = cursor; model->col = cursor;
} }
return true; return true;
@@ -243,7 +247,7 @@ static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_di
cursor++; cursor++;
span = dtmf_dolphin_get_tone_span(model->row, cursor); span = dtmf_dolphin_get_tone_span(model->row, cursor);
} }
if (span != 0) { if(span != 0) {
model->col = cursor; model->col = cursor;
} }
return true; return true;
@@ -251,14 +255,15 @@ static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_di
return true; return true;
} }
static bool dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event) { static bool
dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event) {
bool consumed = false; bool consumed = false;
with_view_model( with_view_model(
dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) { dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
if (event->type == InputTypePress) { if(event->type == InputTypePress) {
model->playing = dtmf_dolphin_audio_play_tones(model->freq1, model->freq2); model->playing = dtmf_dolphin_audio_play_tones(model->freq1, model->freq2);
} else if (event->type == InputTypeRelease) { } else if(event->type == InputTypeRelease) {
model->playing = !dtmf_dolphin_audio_stop_tones(); model->playing = !dtmf_dolphin_audio_stop_tones();
} }
@@ -281,15 +286,15 @@ static void dtmf_dolphin_dialer_enter_callback(void* context) {
model->freq2 = 0.0; model->freq2 = 0.0;
model->playing = false; model->playing = false;
return true; return true;
} });
);
} }
DTMFDolphinDialer* dtmf_dolphin_dialer_alloc() { DTMFDolphinDialer* dtmf_dolphin_dialer_alloc() {
DTMFDolphinDialer* dtmf_dolphin_dialer = malloc(sizeof(DTMFDolphinDialer)); DTMFDolphinDialer* dtmf_dolphin_dialer = malloc(sizeof(DTMFDolphinDialer));
dtmf_dolphin_dialer->view = view_alloc(); dtmf_dolphin_dialer->view = view_alloc();
view_allocate_model(dtmf_dolphin_dialer->view, ViewModelTypeLocking, sizeof(DTMFDolphinDialerModel)); view_allocate_model(
dtmf_dolphin_dialer->view, ViewModelTypeLocking, sizeof(DTMFDolphinDialerModel));
with_view_model( with_view_model(
dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) { dtmf_dolphin_dialer->view, (DTMFDolphinDialerModel * model) {
@@ -300,8 +305,7 @@ DTMFDolphinDialer* dtmf_dolphin_dialer_alloc() {
model->freq2 = 0.0; model->freq2 = 0.0;
model->playing = false; model->playing = false;
return true; return true;
} });
);
view_set_context(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer); view_set_context(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer);
view_set_draw_callback(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer_draw_callback); view_set_draw_callback(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer_draw_callback);
@@ -320,4 +324,3 @@ View* dtmf_dolphin_dialer_get_view(DTMFDolphinDialer* dtmf_dolphin_dialer) {
furi_assert(dtmf_dolphin_dialer); furi_assert(dtmf_dolphin_dialer);
return dtmf_dolphin_dialer->view; return dtmf_dolphin_dialer->view;
} }
@@ -12,4 +12,7 @@ void dtmf_dolphin_dialer_free(DTMFDolphinDialer* dtmf_dolphin_dialer);
View* dtmf_dolphin_dialer_get_view(DTMFDolphinDialer* dtmf_dolphin_dialer); View* dtmf_dolphin_dialer_get_view(DTMFDolphinDialer* dtmf_dolphin_dialer);
void dtmf_dolphin_dialer_set_ok_callback(DTMFDolphinDialer* dtmf_dolphin_dialer, DTMFDolphinDialerOkCallback callback, void* context); void dtmf_dolphin_dialer_set_ok_callback(
DTMFDolphinDialer* dtmf_dolphin_dialer,
DTMFDolphinDialerOkCallback callback,
void* context);
@@ -14,7 +14,7 @@ void elements_button_top_left(Canvas* canvas, const char* str) {
const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const uint8_t x = 0; const uint8_t x = 0;
const uint8_t y = 0 + button_height; const uint8_t y = 0 + button_height;
canvas_draw_box(canvas, x, y - button_height, button_width, button_height); canvas_draw_box(canvas, x, y - button_height, button_width, button_height);
canvas_draw_line(canvas, x + button_width + 0, y - button_height, x + button_width + 0, y - 1); canvas_draw_line(canvas, x + button_width + 0, y - button_height, x + button_width + 0, y - 1);
@@ -44,8 +44,8 @@ void elements_button_top_right(Canvas* canvas, const char* str) {
canvas_draw_box(canvas, x - button_width, y - button_height, button_width, button_height); canvas_draw_box(canvas, x - button_width, y - button_height, button_width, button_height);
canvas_draw_line(canvas, x - button_width - 1, y - button_height, x - button_width - 1, y - 1); canvas_draw_line(canvas, x - button_width - 1, y - button_height, x - button_width - 1, y - 1);
canvas_draw_line(canvas, x - button_width - 2, y - button_height, x - button_width - 2, y - 2); canvas_draw_line(canvas, x - button_width - 2, y - button_height, x - button_width - 2, y - 2);
canvas_draw_line(canvas, x - button_width - 3, y - button_height, x - button_width - 3, y - 3); canvas_draw_line(canvas, x - button_width - 3, y - button_height, x - button_width - 3, y - 3);
canvas_invert_color(canvas); canvas_invert_color(canvas);
canvas_draw_str(canvas, x - button_width + horizontal_offset, y - vertical_offset, str); canvas_draw_str(canvas, x - button_width + horizontal_offset, y - vertical_offset, str);
+289 -277
View File
@@ -21,351 +21,363 @@
#define wave_bitmap_left_width 4 #define wave_bitmap_left_width 4
#define wave_bitmap_left_height 14 #define wave_bitmap_left_height 14
static uint8_t wave_bitmap_left_bits[] = { static uint8_t wave_bitmap_left_bits[] =
0x08, 0x0C, 0x06, 0x06, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x06, {0x08, 0x0C, 0x06, 0x06, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x06, 0x0C, 0x08};
0x0C, 0x08
};
#define wave_bitmap_right_width 4 #define wave_bitmap_right_width 4
#define wave_bitmap_right_height 14 #define wave_bitmap_right_height 14
static uint8_t wave_bitmap_right_bits[] = { static uint8_t wave_bitmap_right_bits[] =
0x01, 0x03, 0x06, 0x06, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x06, 0x06, {0x01, 0x03, 0x06, 0x06, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x06, 0x06, 0x03, 0x01};
0x03, 0x01
};
typedef enum { typedef enum {
EventTypeTick, EventTypeTick,
EventTypeKey, EventTypeKey,
} EventType; } EventType;
typedef struct { typedef struct {
EventType type; EventType type;
InputEvent input; InputEvent input;
} PluginEvent; } PluginEvent;
enum OutputMode { enum OutputMode { Loud, Vibro, Silent };
Loud,
Vibro,
Silent
};
typedef struct { typedef struct {
double bpm; double bpm;
bool playing; bool playing;
int beats_per_bar; int beats_per_bar;
int note_length; int note_length;
int current_beat; int current_beat;
enum OutputMode output_mode; enum OutputMode output_mode;
FuriTimer* timer; FuriTimer* timer;
NotificationApp* notifications; NotificationApp* notifications;
} MetronomeState; } MetronomeState;
static void render_callback(Canvas* const canvas, void* ctx) { static void render_callback(Canvas* const canvas, void* ctx) {
const MetronomeState* metronome_state = acquire_mutex((ValueMutex*)ctx, 25); const MetronomeState* metronome_state = acquire_mutex((ValueMutex*)ctx, 25);
if(metronome_state == NULL) { if(metronome_state == NULL) {
return; return;
} }
string_t tempStr; string_t tempStr;
string_init(tempStr); string_init(tempStr);
canvas_draw_frame(canvas, 0, 0, 128, 64); canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
// draw bars/beat
string_printf(tempStr, "%d/%d", metronome_state->beats_per_bar, metronome_state->note_length);
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, string_get_cstr(tempStr));
string_reset(tempStr);
// draw BPM value // draw bars/beat
string_printf(tempStr, "%.2f", metronome_state->bpm); string_printf(tempStr, "%d/%d", metronome_state->beats_per_bar, metronome_state->note_length);
canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, string_get_cstr(tempStr));
canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignCenter, string_get_cstr(tempStr)); string_reset(tempStr);
string_reset(tempStr);
// draw volume indicator // draw BPM value
// always draw first waves string_printf(tempStr, "%.2f", metronome_state->bpm);
canvas_draw_xbm(canvas, 20, 17, wave_bitmap_left_width, wave_bitmap_left_height, wave_bitmap_left_bits); canvas_set_font(canvas, FontBigNumbers);
canvas_draw_xbm(canvas, canvas_width(canvas)-20-wave_bitmap_right_width, 17, wave_bitmap_right_width, wave_bitmap_right_height, wave_bitmap_right_bits); canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignCenter, string_get_cstr(tempStr));
if (metronome_state->output_mode < Silent) { string_reset(tempStr);
canvas_draw_xbm(canvas, 16, 17, wave_bitmap_left_width, wave_bitmap_left_height, wave_bitmap_left_bits);
canvas_draw_xbm(canvas, canvas_width(canvas)-16-wave_bitmap_right_width, 17, wave_bitmap_right_width, wave_bitmap_right_height, wave_bitmap_right_bits);
}
if (metronome_state->output_mode < Vibro) {
canvas_draw_xbm(canvas, 12, 17, wave_bitmap_left_width, wave_bitmap_left_height, wave_bitmap_left_bits);
canvas_draw_xbm(canvas, canvas_width(canvas)-12-wave_bitmap_right_width, 17, wave_bitmap_right_width, wave_bitmap_right_height, wave_bitmap_right_bits);
}
// draw button prompts
canvas_set_font(canvas, FontSecondary);
elements_button_left(canvas, "Slow");
elements_button_right(canvas, "Fast");
if (metronome_state->playing) {
elements_button_center(canvas, "Stop ");
} else {
elements_button_center(canvas, "Start");
}
elements_button_top_left(canvas, "Push");
elements_button_top_right(canvas, "Hold");
// draw progress bar // draw volume indicator
elements_progress_bar(canvas, 8, 36, 112, (float)metronome_state->current_beat/metronome_state->beats_per_bar); // always draw first waves
canvas_draw_xbm(
canvas, 20, 17, wave_bitmap_left_width, wave_bitmap_left_height, wave_bitmap_left_bits);
canvas_draw_xbm(
canvas,
canvas_width(canvas) - 20 - wave_bitmap_right_width,
17,
wave_bitmap_right_width,
wave_bitmap_right_height,
wave_bitmap_right_bits);
if(metronome_state->output_mode < Silent) {
canvas_draw_xbm(
canvas, 16, 17, wave_bitmap_left_width, wave_bitmap_left_height, wave_bitmap_left_bits);
canvas_draw_xbm(
canvas,
canvas_width(canvas) - 16 - wave_bitmap_right_width,
17,
wave_bitmap_right_width,
wave_bitmap_right_height,
wave_bitmap_right_bits);
}
if(metronome_state->output_mode < Vibro) {
canvas_draw_xbm(
canvas, 12, 17, wave_bitmap_left_width, wave_bitmap_left_height, wave_bitmap_left_bits);
canvas_draw_xbm(
canvas,
canvas_width(canvas) - 12 - wave_bitmap_right_width,
17,
wave_bitmap_right_width,
wave_bitmap_right_height,
wave_bitmap_right_bits);
}
// draw button prompts
canvas_set_font(canvas, FontSecondary);
elements_button_left(canvas, "Slow");
elements_button_right(canvas, "Fast");
if(metronome_state->playing) {
elements_button_center(canvas, "Stop ");
} else {
elements_button_center(canvas, "Start");
}
elements_button_top_left(canvas, "Push");
elements_button_top_right(canvas, "Hold");
// cleanup // draw progress bar
string_clear(tempStr); elements_progress_bar(
release_mutex((ValueMutex*)ctx, metronome_state); canvas, 8, 36, 112, (float)metronome_state->current_beat / metronome_state->beats_per_bar);
// cleanup
string_clear(tempStr);
release_mutex((ValueMutex*)ctx, metronome_state);
} }
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue); furi_assert(event_queue);
PluginEvent event = {.type = EventTypeKey, .input = *input_event}; PluginEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever); furi_message_queue_put(event_queue, &event, FuriWaitForever);
} }
static void timer_callback(void* ctx) { static void timer_callback(void* ctx) {
// this is where we go BEEP! // this is where we go BEEP!
MetronomeState* metronome_state = acquire_mutex((ValueMutex*)ctx, 25); MetronomeState* metronome_state = acquire_mutex((ValueMutex*)ctx, 25);
metronome_state->current_beat++; metronome_state->current_beat++;
if (metronome_state->current_beat > metronome_state->beats_per_bar) { if(metronome_state->current_beat > metronome_state->beats_per_bar) {
metronome_state->current_beat = 1; metronome_state->current_beat = 1;
}
if (metronome_state->current_beat == 1) {
// pronounced beat
notification_message(metronome_state->notifications, &sequence_set_only_red_255);
switch(metronome_state->output_mode) {
case Loud:
furi_hal_speaker_start(440.0f, 1.0f);
break;
case Vibro:
notification_message(metronome_state->notifications, &sequence_set_vibro_on);
break;
case Silent:
break;
} }
} else { if(metronome_state->current_beat == 1) {
// unpronounced beat // pronounced beat
notification_message(metronome_state->notifications, &sequence_set_only_green_255); notification_message(metronome_state->notifications, &sequence_set_only_red_255);
switch(metronome_state->output_mode) { switch(metronome_state->output_mode) {
case Loud: case Loud:
furi_hal_speaker_start(220.0f, 1.0f); furi_hal_speaker_start(440.0f, 1.0f);
break; break;
case Vibro: case Vibro:
notification_message(metronome_state->notifications, &sequence_set_vibro_on); notification_message(metronome_state->notifications, &sequence_set_vibro_on);
break; break;
case Silent: case Silent:
break; break;
} }
}; } else {
// unpronounced beat
notification_message(metronome_state->notifications, &sequence_set_only_green_255);
switch(metronome_state->output_mode) {
case Loud:
furi_hal_speaker_start(220.0f, 1.0f);
break;
case Vibro:
notification_message(metronome_state->notifications, &sequence_set_vibro_on);
break;
case Silent:
break;
}
};
// this is a bit of a kludge... if we are on vibro and unpronounced, stop vibro after half the usual duration // this is a bit of a kludge... if we are on vibro and unpronounced, stop vibro after half the usual duration
switch(metronome_state->output_mode) { switch(metronome_state->output_mode) {
case Loud: case Loud:
furi_delay_ms(BEEP_DELAY_MS);
furi_hal_speaker_stop();
break;
case Vibro:
if (metronome_state->current_beat == 1) {
furi_delay_ms(BEEP_DELAY_MS); furi_delay_ms(BEEP_DELAY_MS);
notification_message(metronome_state->notifications, &sequence_reset_vibro); furi_hal_speaker_stop();
} else { break;
furi_delay_ms((int)BEEP_DELAY_MS/2); case Vibro:
notification_message(metronome_state->notifications, &sequence_reset_vibro); if(metronome_state->current_beat == 1) {
furi_delay_ms((int)BEEP_DELAY_MS/2); furi_delay_ms(BEEP_DELAY_MS);
} notification_message(metronome_state->notifications, &sequence_reset_vibro);
break; } else {
furi_delay_ms((int)BEEP_DELAY_MS / 2);
notification_message(metronome_state->notifications, &sequence_reset_vibro);
furi_delay_ms((int)BEEP_DELAY_MS / 2);
}
break;
case Silent: case Silent:
break; break;
} }
notification_message(metronome_state->notifications, &sequence_reset_rgb); notification_message(metronome_state->notifications, &sequence_reset_rgb);
release_mutex((ValueMutex*)ctx, metronome_state); release_mutex((ValueMutex*)ctx, metronome_state);
} }
static uint32_t state_to_sleep_ticks(MetronomeState* metronome_state) { static uint32_t state_to_sleep_ticks(MetronomeState* metronome_state) {
// calculate time between beeps // calculate time between beeps
uint32_t tps = furi_kernel_get_tick_frequency(); uint32_t tps = furi_kernel_get_tick_frequency();
double multiplier = 4.0d/metronome_state->note_length; double multiplier = 4.0d / metronome_state->note_length;
double bps = (double)metronome_state->bpm / 60; double bps = (double)metronome_state->bpm / 60;
return (uint32_t)(round(tps / bps) - ((BEEP_DELAY_MS/1000)*tps)) * multiplier; return (uint32_t)(round(tps / bps) - ((BEEP_DELAY_MS / 1000) * tps)) * multiplier;
} }
static void update_timer(MetronomeState* metronome_state) { static void update_timer(MetronomeState* metronome_state) {
if (furi_timer_is_running(metronome_state->timer)) { if(furi_timer_is_running(metronome_state->timer)) {
furi_timer_stop(metronome_state->timer); furi_timer_stop(metronome_state->timer);
furi_timer_start( furi_timer_start(metronome_state->timer, state_to_sleep_ticks(metronome_state));
metronome_state->timer, }
state_to_sleep_ticks(metronome_state)
);
}
} }
static void increase_bpm(MetronomeState* metronome_state, double amount) { static void increase_bpm(MetronomeState* metronome_state, double amount) {
metronome_state->bpm += amount; metronome_state->bpm += amount;
if(metronome_state->bpm > (double)BPM_BOUNDARY_HIGH) { if(metronome_state->bpm > (double)BPM_BOUNDARY_HIGH) {
metronome_state->bpm = BPM_BOUNDARY_HIGH; metronome_state->bpm = BPM_BOUNDARY_HIGH;
} }
update_timer(metronome_state); update_timer(metronome_state);
} }
static void decrease_bpm(MetronomeState* metronome_state, double amount) { static void decrease_bpm(MetronomeState* metronome_state, double amount) {
metronome_state->bpm -= amount; metronome_state->bpm -= amount;
if(metronome_state->bpm < (double)BPM_BOUNDARY_LOW) { if(metronome_state->bpm < (double)BPM_BOUNDARY_LOW) {
metronome_state->bpm = BPM_BOUNDARY_LOW; metronome_state->bpm = BPM_BOUNDARY_LOW;
} }
update_timer(metronome_state); update_timer(metronome_state);
} }
static void cycle_beats_per_bar(MetronomeState* metronome_state) { static void cycle_beats_per_bar(MetronomeState* metronome_state) {
metronome_state->beats_per_bar++; metronome_state->beats_per_bar++;
if (metronome_state->beats_per_bar > metronome_state->note_length) { if(metronome_state->beats_per_bar > metronome_state->note_length) {
metronome_state->beats_per_bar = 1; metronome_state->beats_per_bar = 1;
} }
} }
static void cycle_note_length(MetronomeState* metronome_state) { static void cycle_note_length(MetronomeState* metronome_state) {
metronome_state->note_length *= 2; metronome_state->note_length *= 2;
if (metronome_state->note_length > 16) { if(metronome_state->note_length > 16) {
metronome_state->note_length = 2; metronome_state->note_length = 2;
metronome_state->beats_per_bar = 1; metronome_state->beats_per_bar = 1;
} }
update_timer(metronome_state); update_timer(metronome_state);
} }
static void cycle_output_mode(MetronomeState* metronome_state) { static void cycle_output_mode(MetronomeState* metronome_state) {
metronome_state->output_mode++; metronome_state->output_mode++;
if (metronome_state->output_mode > Silent) { if(metronome_state->output_mode > Silent) {
metronome_state->output_mode = Loud; metronome_state->output_mode = Loud;
} }
} }
static void metronome_state_init(MetronomeState* const metronome_state) { static void metronome_state_init(MetronomeState* const metronome_state) {
metronome_state->bpm = 120.0; metronome_state->bpm = 120.0;
metronome_state->playing = false; metronome_state->playing = false;
metronome_state->beats_per_bar = 4; metronome_state->beats_per_bar = 4;
metronome_state->note_length = 4; metronome_state->note_length = 4;
metronome_state->current_beat = 0; metronome_state->current_beat = 0;
metronome_state->output_mode = Loud; metronome_state->output_mode = Loud;
metronome_state->notifications = furi_record_open(RECORD_NOTIFICATION); metronome_state->notifications = furi_record_open(RECORD_NOTIFICATION);
} }
int32_t metronome_app() { int32_t metronome_app() {
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
MetronomeState* metronome_state = malloc(sizeof(MetronomeState)); MetronomeState* metronome_state = malloc(sizeof(MetronomeState));
metronome_state_init(metronome_state); metronome_state_init(metronome_state);
ValueMutex state_mutex; ValueMutex state_mutex;
if(!init_mutex(&state_mutex, metronome_state, sizeof(MetronomeState))) { if(!init_mutex(&state_mutex, metronome_state, sizeof(MetronomeState))) {
FURI_LOG_E("Metronome", "cannot create mutex\r\n"); FURI_LOG_E("Metronome", "cannot create mutex\r\n");
free(metronome_state); free(metronome_state);
return 255; return 255;
}
// Set system callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, render_callback, &state_mutex);
view_port_input_callback_set(view_port, input_callback, event_queue);
metronome_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, &state_mutex);
// Open GUI and register view_port
Gui* gui = furi_record_open("gui");
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
PluginEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
MetronomeState* metronome_state = (MetronomeState*)acquire_mutex_block(&state_mutex);
if(event_status == FuriStatusOk) {
if(event.type == EventTypeKey) {
if(event.input.type == InputTypeShort) {
// push events
switch(event.input.key) {
case InputKeyUp:
cycle_beats_per_bar(metronome_state);
break;
case InputKeyDown:
cycle_output_mode(metronome_state);
break;
case InputKeyRight:
increase_bpm(metronome_state, BPM_STEP_SIZE_FINE);
break;
case InputKeyLeft:
decrease_bpm(metronome_state, BPM_STEP_SIZE_FINE);
break;
case InputKeyOk:
metronome_state->playing = !metronome_state->playing;
if (metronome_state->playing) {
furi_timer_start(metronome_state->timer, state_to_sleep_ticks(metronome_state));
} else {
furi_timer_stop(metronome_state->timer);
}
break;
case InputKeyBack:
processing = false;
break;
}
} else if (event.input.type == InputTypeLong) {
// hold events
switch(event.input.key) {
case InputKeyUp:
cycle_note_length(metronome_state);
break;
case InputKeyDown:
break;
case InputKeyRight:
increase_bpm(metronome_state, BPM_STEP_SIZE_COARSE);
break;
case InputKeyLeft:
decrease_bpm(metronome_state, BPM_STEP_SIZE_COARSE);
break;
case InputKeyOk:
break;
case InputKeyBack:
processing = false;
break;
}
} else if (event.input.type == InputTypeRepeat) {
// repeat events
switch(event.input.key) {
case InputKeyUp:
break;
case InputKeyDown:
break;
case InputKeyRight:
increase_bpm(metronome_state, BPM_STEP_SIZE_COARSE);
break;
case InputKeyLeft:
decrease_bpm(metronome_state, BPM_STEP_SIZE_COARSE);
break;
case InputKeyOk:
break;
case InputKeyBack:
processing = false;
break;
}
}
}
} else {
FURI_LOG_D("Metronome", "FuriMessageQueue: event timeout");
// event timeout
} }
view_port_update(view_port); // Set system callbacks
release_mutex(&state_mutex, metronome_state); ViewPort* view_port = view_port_alloc();
} view_port_draw_callback_set(view_port, render_callback, &state_mutex);
view_port_input_callback_set(view_port, input_callback, event_queue);
metronome_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, &state_mutex);
view_port_enabled_set(view_port, false); // Open GUI and register view_port
gui_remove_view_port(gui, view_port); Gui* gui = furi_record_open("gui");
furi_record_close("gui"); gui_add_view_port(gui, view_port, GuiLayerFullscreen);
view_port_free(view_port);
furi_message_queue_free(event_queue);
delete_mutex(&state_mutex);
furi_timer_free(metronome_state->timer);
furi_record_close(RECORD_NOTIFICATION);
free(metronome_state);
return 0; PluginEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
MetronomeState* metronome_state = (MetronomeState*)acquire_mutex_block(&state_mutex);
if(event_status == FuriStatusOk) {
if(event.type == EventTypeKey) {
if(event.input.type == InputTypeShort) {
// push events
switch(event.input.key) {
case InputKeyUp:
cycle_beats_per_bar(metronome_state);
break;
case InputKeyDown:
cycle_output_mode(metronome_state);
break;
case InputKeyRight:
increase_bpm(metronome_state, BPM_STEP_SIZE_FINE);
break;
case InputKeyLeft:
decrease_bpm(metronome_state, BPM_STEP_SIZE_FINE);
break;
case InputKeyOk:
metronome_state->playing = !metronome_state->playing;
if(metronome_state->playing) {
furi_timer_start(
metronome_state->timer, state_to_sleep_ticks(metronome_state));
} else {
furi_timer_stop(metronome_state->timer);
}
break;
case InputKeyBack:
processing = false;
break;
}
} else if(event.input.type == InputTypeLong) {
// hold events
switch(event.input.key) {
case InputKeyUp:
cycle_note_length(metronome_state);
break;
case InputKeyDown:
break;
case InputKeyRight:
increase_bpm(metronome_state, BPM_STEP_SIZE_COARSE);
break;
case InputKeyLeft:
decrease_bpm(metronome_state, BPM_STEP_SIZE_COARSE);
break;
case InputKeyOk:
break;
case InputKeyBack:
processing = false;
break;
}
} else if(event.input.type == InputTypeRepeat) {
// repeat events
switch(event.input.key) {
case InputKeyUp:
break;
case InputKeyDown:
break;
case InputKeyRight:
increase_bpm(metronome_state, BPM_STEP_SIZE_COARSE);
break;
case InputKeyLeft:
decrease_bpm(metronome_state, BPM_STEP_SIZE_COARSE);
break;
case InputKeyOk:
break;
case InputKeyBack:
processing = false;
break;
}
}
}
} else {
FURI_LOG_D("Metronome", "FuriMessageQueue: event timeout");
// event timeout
}
view_port_update(view_port);
release_mutex(&state_mutex, metronome_state);
}
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close("gui");
view_port_free(view_port);
furi_message_queue_free(event_queue);
delete_mutex(&state_mutex);
furi_timer_free(metronome_state->timer);
furi_record_close(RECORD_NOTIFICATION);
free(metronome_state);
return 0;
} }
File diff suppressed because it is too large Load Diff
+129 -106
View File
@@ -22,16 +22,16 @@
#include "hal.h" #include "hal.h"
#define MEMORY_SIZE 4096 // 4096 x 4 bits (640 x 4 bits of RAM) #define MEMORY_SIZE 4096 // 4096 x 4 bits (640 x 4 bits of RAM)
#define MEM_RAM_ADDR 0x000 #define MEM_RAM_ADDR 0x000
#define MEM_RAM_SIZE 0x280 #define MEM_RAM_SIZE 0x280
#define MEM_DISPLAY1_ADDR 0xE00 #define MEM_DISPLAY1_ADDR 0xE00
#define MEM_DISPLAY1_SIZE 0x050 #define MEM_DISPLAY1_SIZE 0x050
#define MEM_DISPLAY2_ADDR 0xE80 #define MEM_DISPLAY2_ADDR 0xE80
#define MEM_DISPLAY2_SIZE 0x050 #define MEM_DISPLAY2_SIZE 0x050
#define MEM_IO_ADDR 0xF00 #define MEM_IO_ADDR 0xF00
#define MEM_IO_SIZE 0x080 #define MEM_IO_SIZE 0x080
/* Define this if you want to reduce the footprint of the memory buffer from 4096 u4_t (most likely bytes) /* Define this if you want to reduce the footprint of the memory buffer from 4096 u4_t (most likely bytes)
* to 464 u8_t (bytes for sure), while increasing slightly the number of operations needed to read/write from/to it. * to 464 u8_t (bytes for sure), while increasing slightly the number of operations needed to read/write from/to it.
@@ -40,139 +40,162 @@
#ifdef LOW_FOOTPRINT #ifdef LOW_FOOTPRINT
/* Invalid memory areas are not buffered to reduce the footprint of the library in memory */ /* Invalid memory areas are not buffered to reduce the footprint of the library in memory */
#define MEM_BUFFER_SIZE (MEM_RAM_SIZE + MEM_DISPLAY1_SIZE + MEM_DISPLAY2_SIZE + MEM_IO_SIZE)/2 #define MEM_BUFFER_SIZE (MEM_RAM_SIZE + MEM_DISPLAY1_SIZE + MEM_DISPLAY2_SIZE + MEM_IO_SIZE) / 2
/* Maps the CPU memory to the memory buffer */ /* Maps the CPU memory to the memory buffer */
#define RAM_TO_MEMORY(n) ((n - MEM_RAM_ADDR)/2) #define RAM_TO_MEMORY(n) ((n - MEM_RAM_ADDR) / 2)
#define DISP1_TO_MEMORY(n) ((n - MEM_DISPLAY1_ADDR + MEM_RAM_SIZE)/2) #define DISP1_TO_MEMORY(n) ((n - MEM_DISPLAY1_ADDR + MEM_RAM_SIZE) / 2)
#define DISP2_TO_MEMORY(n) ((n - MEM_DISPLAY2_ADDR + MEM_RAM_SIZE + MEM_DISPLAY1_SIZE)/2) #define DISP2_TO_MEMORY(n) ((n - MEM_DISPLAY2_ADDR + MEM_RAM_SIZE + MEM_DISPLAY1_SIZE) / 2)
#define IO_TO_MEMORY(n) ((n - MEM_IO_ADDR + MEM_RAM_SIZE + MEM_DISPLAY1_SIZE + MEM_DISPLAY2_SIZE)/2) #define IO_TO_MEMORY(n) \
((n - MEM_IO_ADDR + MEM_RAM_SIZE + MEM_DISPLAY1_SIZE + MEM_DISPLAY2_SIZE) / 2)
#define SET_RAM_MEMORY(buffer, n, v) {buffer[RAM_TO_MEMORY(n)] = (buffer[RAM_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | ((v) & 0xF) << (((n) % 2) << 2);} #define SET_RAM_MEMORY(buffer, n, v) \
#define SET_DISP1_MEMORY(buffer, n, v) {buffer[DISP1_TO_MEMORY(n)] = (buffer[DISP1_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | ((v) & 0xF) << (((n) % 2) << 2);} { \
#define SET_DISP2_MEMORY(buffer, n, v) {buffer[DISP2_TO_MEMORY(n)] = (buffer[DISP2_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | ((v) & 0xF) << (((n) % 2) << 2);} buffer[RAM_TO_MEMORY(n)] = (buffer[RAM_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | \
#define SET_IO_MEMORY(buffer, n, v) {buffer[IO_TO_MEMORY(n)] = (buffer[IO_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | ((v) & 0xF) << (((n) % 2) << 2);} ((v)&0xF) << (((n) % 2) << 2); \
#define SET_MEMORY(buffer, n, v) {if ((n) < (MEM_RAM_ADDR + MEM_RAM_SIZE)) { \ }
SET_RAM_MEMORY(buffer, n, v); \ #define SET_DISP1_MEMORY(buffer, n, v) \
} else if ((n) < MEM_DISPLAY1_ADDR) { \ { \
/* INVALID_MEMORY */ \ buffer[DISP1_TO_MEMORY(n)] = (buffer[DISP1_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | \
} else if ((n) < (MEM_DISPLAY1_ADDR + MEM_DISPLAY1_SIZE)) { \ ((v)&0xF) << (((n) % 2) << 2); \
SET_DISP1_MEMORY(buffer, n, v); \ }
} else if ((n) < MEM_DISPLAY2_ADDR) { \ #define SET_DISP2_MEMORY(buffer, n, v) \
/* INVALID_MEMORY */ \ { \
} else if ((n) < (MEM_DISPLAY2_ADDR + MEM_DISPLAY2_SIZE)) { \ buffer[DISP2_TO_MEMORY(n)] = (buffer[DISP2_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | \
SET_DISP2_MEMORY(buffer, n, v); \ ((v)&0xF) << (((n) % 2) << 2); \
} else if ((n) < MEM_IO_ADDR) { \ }
/* INVALID_MEMORY */ \ #define SET_IO_MEMORY(buffer, n, v) \
} else if ((n) < (MEM_IO_ADDR + MEM_IO_SIZE)) { \ { \
SET_IO_MEMORY(buffer, n, v); \ buffer[IO_TO_MEMORY(n)] = (buffer[IO_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | \
} else { \ ((v)&0xF) << (((n) % 2) << 2); \
/* INVALID_MEMORY */ \ }
}} #define SET_MEMORY(buffer, n, v) \
{ \
if((n) < (MEM_RAM_ADDR + MEM_RAM_SIZE)) { \
SET_RAM_MEMORY(buffer, n, v); \
} else if((n) < MEM_DISPLAY1_ADDR) { \
/* INVALID_MEMORY */ \
} else if((n) < (MEM_DISPLAY1_ADDR + MEM_DISPLAY1_SIZE)) { \
SET_DISP1_MEMORY(buffer, n, v); \
} else if((n) < MEM_DISPLAY2_ADDR) { \
/* INVALID_MEMORY */ \
} else if((n) < (MEM_DISPLAY2_ADDR + MEM_DISPLAY2_SIZE)) { \
SET_DISP2_MEMORY(buffer, n, v); \
} else if((n) < MEM_IO_ADDR) { \
/* INVALID_MEMORY */ \
} else if((n) < (MEM_IO_ADDR + MEM_IO_SIZE)) { \
SET_IO_MEMORY(buffer, n, v); \
} else { \
/* INVALID_MEMORY */ \
} \
}
#define GET_RAM_MEMORY(buffer, n) ((buffer[RAM_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF) #define GET_RAM_MEMORY(buffer, n) ((buffer[RAM_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF)
#define GET_DISP1_MEMORY(buffer, n) ((buffer[DISP1_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF) #define GET_DISP1_MEMORY(buffer, n) ((buffer[DISP1_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF)
#define GET_DISP2_MEMORY(buffer, n) ((buffer[DISP2_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF) #define GET_DISP2_MEMORY(buffer, n) ((buffer[DISP2_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF)
#define GET_IO_MEMORY(buffer, n) ((buffer[IO_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF) #define GET_IO_MEMORY(buffer, n) ((buffer[IO_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF)
#define GET_MEMORY(buffer, n) ((buffer[ \ #define GET_MEMORY(buffer, n) \
((n) < (MEM_RAM_ADDR + MEM_RAM_SIZE)) ? RAM_TO_MEMORY(n) : \ ((buffer \
((n) < MEM_DISPLAY1_ADDR) ? 0 : \ [((n) < (MEM_RAM_ADDR + MEM_RAM_SIZE)) ? RAM_TO_MEMORY(n) : \
((n) < (MEM_DISPLAY1_ADDR + MEM_DISPLAY1_SIZE)) ? DISP1_TO_MEMORY(n) : \ ((n) < MEM_DISPLAY1_ADDR) ? 0 : \
((n) < MEM_DISPLAY2_ADDR) ? 0 : \ ((n) < (MEM_DISPLAY1_ADDR + MEM_DISPLAY1_SIZE)) ? DISP1_TO_MEMORY(n) : \
((n) < (MEM_DISPLAY2_ADDR + MEM_DISPLAY2_SIZE)) ? DISP2_TO_MEMORY(n) : \ ((n) < MEM_DISPLAY2_ADDR) ? 0 : \
((n) < MEM_IO_ADDR) ? 0 : \ ((n) < (MEM_DISPLAY2_ADDR + MEM_DISPLAY2_SIZE)) ? DISP2_TO_MEMORY(n) : \
((n) < (MEM_IO_ADDR + MEM_IO_SIZE)) ? IO_TO_MEMORY(n) : 0 \ ((n) < MEM_IO_ADDR) ? 0 : \
] >> (((n) % 2) << 2)) & 0xF) ((n) < (MEM_IO_ADDR + MEM_IO_SIZE)) ? IO_TO_MEMORY(n) : \
0] >> \
(((n) % 2) << 2)) & \
0xF)
#define MEM_BUFFER_TYPE u8_t #define MEM_BUFFER_TYPE u8_t
#else #else
#define MEM_BUFFER_SIZE MEMORY_SIZE #define MEM_BUFFER_SIZE MEMORY_SIZE
#define SET_MEMORY(buffer, n, v) {buffer[n] = v;} #define SET_MEMORY(buffer, n, v) \
#define SET_RAM_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v) { buffer[n] = v; }
#define SET_DISP1_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v) #define SET_RAM_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v)
#define SET_DISP2_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v) #define SET_DISP1_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v)
#define SET_IO_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v) #define SET_DISP2_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v)
#define SET_IO_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v)
#define GET_MEMORY(buffer, n) (buffer[n]) #define GET_MEMORY(buffer, n) (buffer[n])
#define GET_RAM_MEMORY(buffer, n) GET_MEMORY(buffer, n) #define GET_RAM_MEMORY(buffer, n) GET_MEMORY(buffer, n)
#define GET_DISP1_MEMORY(buffer, n) GET_MEMORY(buffer, n) #define GET_DISP1_MEMORY(buffer, n) GET_MEMORY(buffer, n)
#define GET_DISP2_MEMORY(buffer, n) GET_MEMORY(buffer, n) #define GET_DISP2_MEMORY(buffer, n) GET_MEMORY(buffer, n)
#define GET_IO_MEMORY(buffer, n) GET_MEMORY(buffer, n) #define GET_IO_MEMORY(buffer, n) GET_MEMORY(buffer, n)
#define MEM_BUFFER_TYPE u4_t #define MEM_BUFFER_TYPE u4_t
#endif #endif
typedef struct breakpoint { typedef struct breakpoint {
u13_t addr; u13_t addr;
struct breakpoint *next; struct breakpoint* next;
} breakpoint_t; } breakpoint_t;
/* Pins (TODO: add other pins) */ /* Pins (TODO: add other pins) */
typedef enum { typedef enum {
PIN_K00 = 0x0, PIN_K00 = 0x0,
PIN_K01 = 0x1, PIN_K01 = 0x1,
PIN_K02 = 0x2, PIN_K02 = 0x2,
PIN_K03 = 0x3, PIN_K03 = 0x3,
PIN_K10 = 0X4, PIN_K10 = 0X4,
PIN_K11 = 0X5, PIN_K11 = 0X5,
PIN_K12 = 0X6, PIN_K12 = 0X6,
PIN_K13 = 0X7, PIN_K13 = 0X7,
} pin_t; } pin_t;
typedef enum { typedef enum {
PIN_STATE_LOW = 0, PIN_STATE_LOW = 0,
PIN_STATE_HIGH = 1, PIN_STATE_HIGH = 1,
} pin_state_t; } pin_state_t;
typedef enum { typedef enum {
INT_PROG_TIMER_SLOT = 0, INT_PROG_TIMER_SLOT = 0,
INT_SERIAL_SLOT = 1, INT_SERIAL_SLOT = 1,
INT_K10_K13_SLOT = 2, INT_K10_K13_SLOT = 2,
INT_K00_K03_SLOT = 3, INT_K00_K03_SLOT = 3,
INT_STOPWATCH_SLOT = 4, INT_STOPWATCH_SLOT = 4,
INT_CLOCK_TIMER_SLOT = 5, INT_CLOCK_TIMER_SLOT = 5,
INT_SLOT_NUM, INT_SLOT_NUM,
} int_slot_t; } int_slot_t;
typedef struct { typedef struct {
u4_t factor_flag_reg; u4_t factor_flag_reg;
u4_t mask_reg; u4_t mask_reg;
bool_t triggered; /* 1 if triggered, 0 otherwise */ bool_t triggered; /* 1 if triggered, 0 otherwise */
u8_t vector; u8_t vector;
} interrupt_t; } interrupt_t;
typedef struct { typedef struct {
u13_t *pc; u13_t* pc;
u12_t *x; u12_t* x;
u12_t *y; u12_t* y;
u4_t *a; u4_t* a;
u4_t *b; u4_t* b;
u5_t *np; u5_t* np;
u8_t *sp; u8_t* sp;
u4_t *flags; u4_t* flags;
u32_t *tick_counter; u32_t* tick_counter;
u32_t *clk_timer_timestamp; u32_t* clk_timer_timestamp;
u32_t *prog_timer_timestamp; u32_t* prog_timer_timestamp;
bool_t *prog_timer_enabled; bool_t* prog_timer_enabled;
u8_t *prog_timer_data; u8_t* prog_timer_data;
u8_t *prog_timer_rld; u8_t* prog_timer_rld;
u32_t *call_depth; u32_t* call_depth;
interrupt_t *interrupts; interrupt_t* interrupts;
MEM_BUFFER_TYPE *memory; MEM_BUFFER_TYPE* memory;
} state_t; } state_t;
void cpu_add_bp(breakpoint_t** list, u13_t addr);
void cpu_add_bp(breakpoint_t **list, u13_t addr); void cpu_free_bp(breakpoint_t** list);
void cpu_free_bp(breakpoint_t **list);
void cpu_set_speed(u8_t speed); void cpu_set_speed(u8_t speed);
state_t * cpu_get_state(void); state_t* cpu_get_state(void);
u32_t cpu_get_depth(void); u32_t cpu_get_depth(void);
@@ -184,7 +207,7 @@ void cpu_refresh_hw(void);
void cpu_reset(void); void cpu_reset(void);
bool_t cpu_init(const u12_t *program, breakpoint_t *breakpoints, u32_t freq); bool_t cpu_init(const u12_t* program, breakpoint_t* breakpoints, u32_t freq);
void cpu_release(void); void cpu_release(void);
int cpu_step(void); int cpu_step(void);
+26 -26
View File
@@ -23,14 +23,14 @@
#include "../hal_types.h" #include "../hal_types.h"
#ifndef NULL #ifndef NULL
#define NULL 0 #define NULL 0
#endif #endif
typedef enum { typedef enum {
LOG_ERROR = 0x1, LOG_ERROR = 0x1,
LOG_INFO = (0x1 << 1), LOG_INFO = (0x1 << 1),
LOG_MEMORY = (0x1 << 2), LOG_MEMORY = (0x1 << 2),
LOG_CPU = (0x1 << 3), LOG_CPU = (0x1 << 3),
} log_level_t; } log_level_t;
/* The Hardware Abstraction Layer /* The Hardware Abstraction Layer
@@ -38,52 +38,52 @@ typedef enum {
* All pointers MUST be implemented, but some implementations can be left empty. * All pointers MUST be implemented, but some implementations can be left empty.
*/ */
typedef struct { typedef struct {
/* Memory allocation functions /* Memory allocation functions
* NOTE: Needed only if breakpoints support is required. * NOTE: Needed only if breakpoints support is required.
*/ */
void * (*malloc)(u32_t size); void* (*malloc)(u32_t size);
void (*free)(void *ptr); void (*free)(void* ptr);
/* What to do if the CPU has halted /* What to do if the CPU has halted
*/ */
void (*halt)(void); void (*halt)(void);
/* Log related function /* Log related function
* NOTE: Needed only if log messages are required. * NOTE: Needed only if log messages are required.
*/ */
bool_t (*is_log_enabled)(log_level_t level); bool_t (*is_log_enabled)(log_level_t level);
void (*log)(log_level_t level, char *buff, ...); void (*log)(log_level_t level, char* buff, ...);
/* Clock related functions /* Clock related functions
* NOTE: Timestamps granularity is configured with tamalib_init(), an accuracy * NOTE: Timestamps granularity is configured with tamalib_init(), an accuracy
* of ~30 us (1/32768) is required for a cycle accurate emulation. * of ~30 us (1/32768) is required for a cycle accurate emulation.
*/ */
void (*sleep_until)(timestamp_t ts); void (*sleep_until)(timestamp_t ts);
timestamp_t (*get_timestamp)(void); timestamp_t (*get_timestamp)(void);
/* Screen related functions /* Screen related functions
* NOTE: In case of direct hardware access to pixels, the set_XXXX() functions * NOTE: In case of direct hardware access to pixels, the set_XXXX() functions
* (called for each pixel/icon update) can directly drive them, otherwise they * (called for each pixel/icon update) can directly drive them, otherwise they
* should just store the data in a buffer and let update_screen() do the actual * should just store the data in a buffer and let update_screen() do the actual
* rendering (at 30 fps). * rendering (at 30 fps).
*/ */
void (*update_screen)(void); void (*update_screen)(void);
void (*set_lcd_matrix)(u8_t x, u8_t y, bool_t val); void (*set_lcd_matrix)(u8_t x, u8_t y, bool_t val);
void (*set_lcd_icon)(u8_t icon, bool_t val); void (*set_lcd_icon)(u8_t icon, bool_t val);
/* Sound related functions /* Sound related functions
* NOTE: set_frequency() changes the output frequency of the sound, while * NOTE: set_frequency() changes the output frequency of the sound, while
* play_frequency() decides whether the sound should be heard or not. * play_frequency() decides whether the sound should be heard or not.
*/ */
void (*set_frequency)(u32_t freq); void (*set_frequency)(u32_t freq);
void (*play_frequency)(bool_t en); void (*play_frequency)(bool_t en);
/* Event handler from the main app (if any) /* Event handler from the main app (if any)
* NOTE: This function usually handles button related events, states loading/saving ... * NOTE: This function usually handles button related events, states loading/saving ...
*/ */
int (*handler)(void); int (*handler)(void);
} hal_t; } hal_t;
extern hal_t *g_hal; extern hal_t* g_hal;
#endif /* _HAL_H_ */ #endif /* _HAL_H_ */
+75 -80
View File
@@ -22,29 +22,27 @@
#include "hal.h" #include "hal.h"
/* SEG -> LCD mapping */ /* SEG -> LCD mapping */
static u8_t seg_pos[40] = {0, 1, 2, 3, 4, 5, 6, 7, 32, 8, 9, 10, 11, 12 ,13 ,14, 15, 33, 34, 35, 31, 30, 29, 28, 27, 26, 25, 24, 36, 23, 22, 21, 20, 19, 18, 17, 16, 37, 38, 39}; static u8_t seg_pos[40] = {0, 1, 2, 3, 4, 5, 6, 7, 32, 8, 9, 10, 11, 12,
13, 14, 15, 33, 34, 35, 31, 30, 29, 28, 27, 26, 25, 24,
36, 23, 22, 21, 20, 19, 18, 17, 16, 37, 38, 39};
bool_t hw_init(void) {
/* Buttons are active LOW */
cpu_set_input_pin(PIN_K00, PIN_STATE_HIGH);
cpu_set_input_pin(PIN_K01, PIN_STATE_HIGH);
cpu_set_input_pin(PIN_K02, PIN_STATE_HIGH);
bool_t hw_init(void) return 0;
{
/* Buttons are active LOW */
cpu_set_input_pin(PIN_K00, PIN_STATE_HIGH);
cpu_set_input_pin(PIN_K01, PIN_STATE_HIGH);
cpu_set_input_pin(PIN_K02, PIN_STATE_HIGH);
return 0;
} }
void hw_release(void) void hw_release(void) {
{
} }
void hw_set_lcd_pin(u8_t seg, u8_t com, u8_t val) void hw_set_lcd_pin(u8_t seg, u8_t com, u8_t val) {
{ if(seg_pos[seg] < LCD_WIDTH) {
if (seg_pos[seg] < LCD_WIDTH) { g_hal->set_lcd_matrix(seg_pos[seg], com, val);
g_hal->set_lcd_matrix(seg_pos[seg], com, val); } else {
} else { /*
/*
* IC n -> seg-com|... * IC n -> seg-com|...
* IC 0 -> 8-0 |18-3 |19-2 * IC 0 -> 8-0 |18-3 |19-2
* IC 1 -> 8-1 |17-0 |19-3 * IC 1 -> 8-1 |17-0 |19-3
@@ -55,85 +53,82 @@ void hw_set_lcd_pin(u8_t seg, u8_t com, u8_t val)
* IC 6 -> 28-14|37-15|39-12 * IC 6 -> 28-14|37-15|39-12
* IC 7 -> 28-15|38-12|39-13 * IC 7 -> 28-15|38-12|39-13
*/ */
if (seg == 8 && com < 4) { if(seg == 8 && com < 4) {
g_hal->set_lcd_icon(com, val); g_hal->set_lcd_icon(com, val);
} else if (seg == 28 && com >= 12) { } else if(seg == 28 && com >= 12) {
g_hal->set_lcd_icon(com - 8, val); g_hal->set_lcd_icon(com - 8, val);
} }
} }
} }
void hw_set_button(button_t btn, btn_state_t state) void hw_set_button(button_t btn, btn_state_t state) {
{ pin_state_t pin_state = (state == BTN_STATE_PRESSED) ? PIN_STATE_LOW : PIN_STATE_HIGH;
pin_state_t pin_state = (state == BTN_STATE_PRESSED) ? PIN_STATE_LOW : PIN_STATE_HIGH;
switch (btn) { switch(btn) {
case BTN_LEFT: case BTN_LEFT:
cpu_set_input_pin(PIN_K02, pin_state); cpu_set_input_pin(PIN_K02, pin_state);
break; break;
case BTN_MIDDLE: case BTN_MIDDLE:
cpu_set_input_pin(PIN_K01, pin_state); cpu_set_input_pin(PIN_K01, pin_state);
break; break;
case BTN_RIGHT: case BTN_RIGHT:
cpu_set_input_pin(PIN_K00, pin_state); cpu_set_input_pin(PIN_K00, pin_state);
break; break;
} }
} }
void hw_set_buzzer_freq(u4_t freq) void hw_set_buzzer_freq(u4_t freq) {
{ u32_t snd_freq = 0;
u32_t snd_freq = 0;
switch (freq) { switch(freq) {
case 0: case 0:
/* 4096.0 Hz */ /* 4096.0 Hz */
snd_freq = 40960; snd_freq = 40960;
break; break;
case 1: case 1:
/* 3276.8 Hz */ /* 3276.8 Hz */
snd_freq = 32768; snd_freq = 32768;
break; break;
case 2: case 2:
/* 2730.7 Hz */ /* 2730.7 Hz */
snd_freq = 27307; snd_freq = 27307;
break; break;
case 3: case 3:
/* 2340.6 Hz */ /* 2340.6 Hz */
snd_freq = 23406; snd_freq = 23406;
break; break;
case 4: case 4:
/* 2048.0 Hz */ /* 2048.0 Hz */
snd_freq = 20480; snd_freq = 20480;
break; break;
case 5: case 5:
/* 1638.4 Hz */ /* 1638.4 Hz */
snd_freq = 16384; snd_freq = 16384;
break; break;
case 6: case 6:
/* 1365.3 Hz */ /* 1365.3 Hz */
snd_freq = 13653; snd_freq = 13653;
break; break;
case 7: case 7:
/* 1170.3 Hz */ /* 1170.3 Hz */
snd_freq = 11703; snd_freq = 11703;
break; break;
} }
if (snd_freq != 0) { if(snd_freq != 0) {
g_hal->set_frequency(snd_freq); g_hal->set_frequency(snd_freq);
} }
} }
void hw_enable_buzzer(bool_t en) void hw_enable_buzzer(bool_t en) {
{ g_hal->play_frequency(en);
g_hal->play_frequency(en);
} }
+8 -9
View File
@@ -22,23 +22,22 @@
#include "hal.h" #include "hal.h"
#define LCD_WIDTH 32 #define LCD_WIDTH 32
#define LCD_HEIGHT 16 #define LCD_HEIGHT 16
#define ICON_NUM 8 #define ICON_NUM 8
typedef enum { typedef enum {
BTN_STATE_RELEASED = 0, BTN_STATE_RELEASED = 0,
BTN_STATE_PRESSED, BTN_STATE_PRESSED,
} btn_state_t; } btn_state_t;
typedef enum { typedef enum {
BTN_LEFT = 0, BTN_LEFT = 0,
BTN_MIDDLE, BTN_MIDDLE,
BTN_RIGHT, BTN_RIGHT,
} button_t; } button_t;
bool_t hw_init(void); bool_t hw_init(void);
void hw_release(void); void hw_release(void);
+67 -76
View File
@@ -22,7 +22,7 @@
#include "cpu.h" #include "cpu.h"
#include "hal.h" #include "hal.h"
#define DEFAULT_FRAMERATE 30 // fps #define DEFAULT_FRAMERATE 30 // fps
static exec_mode_t exec_mode = EXEC_MODE_RUN; static exec_mode_t exec_mode = EXEC_MODE_RUN;
@@ -34,104 +34,95 @@ static u32_t ts_freq;
static u8_t g_framerate = DEFAULT_FRAMERATE; static u8_t g_framerate = DEFAULT_FRAMERATE;
hal_t *g_hal; hal_t* g_hal;
bool_t tamalib_init(const u12_t* program, breakpoint_t* breakpoints, u32_t freq) {
bool_t res = 0;
bool_t tamalib_init(const u12_t *program, breakpoint_t *breakpoints, u32_t freq) res |= cpu_init(program, breakpoints, freq);
{ res |= hw_init();
bool_t res = 0;
res |= cpu_init(program, breakpoints, freq); ts_freq = freq;
res |= hw_init();
ts_freq = freq; return res;
return res;
} }
void tamalib_release(void) void tamalib_release(void) {
{ hw_release();
hw_release(); cpu_release();
cpu_release();
} }
void tamalib_set_framerate(u8_t framerate) void tamalib_set_framerate(u8_t framerate) {
{ g_framerate = framerate;
g_framerate = framerate;
} }
u8_t tamalib_get_framerate(void) u8_t tamalib_get_framerate(void) {
{ return g_framerate;
return g_framerate;
} }
void tamalib_register_hal(hal_t *hal) void tamalib_register_hal(hal_t* hal) {
{ g_hal = hal;
g_hal = hal;
} }
void tamalib_set_exec_mode(exec_mode_t mode) void tamalib_set_exec_mode(exec_mode_t mode) {
{ exec_mode = mode;
exec_mode = mode; step_depth = cpu_get_depth();
step_depth = cpu_get_depth(); cpu_sync_ref_timestamp();
cpu_sync_ref_timestamp();
} }
void tamalib_step(void) void tamalib_step(void) {
{ if(exec_mode == EXEC_MODE_PAUSE) {
if (exec_mode == EXEC_MODE_PAUSE) { return;
return; }
}
if (cpu_step()) { if(cpu_step()) {
exec_mode = EXEC_MODE_PAUSE; exec_mode = EXEC_MODE_PAUSE;
step_depth = cpu_get_depth(); step_depth = cpu_get_depth();
} else { } else {
switch (exec_mode) { switch(exec_mode) {
case EXEC_MODE_PAUSE: case EXEC_MODE_PAUSE:
case EXEC_MODE_RUN: case EXEC_MODE_RUN:
break; break;
case EXEC_MODE_STEP: case EXEC_MODE_STEP:
exec_mode = EXEC_MODE_PAUSE; exec_mode = EXEC_MODE_PAUSE;
break; break;
case EXEC_MODE_NEXT: case EXEC_MODE_NEXT:
if (cpu_get_depth() <= step_depth) { if(cpu_get_depth() <= step_depth) {
exec_mode = EXEC_MODE_PAUSE; exec_mode = EXEC_MODE_PAUSE;
step_depth = cpu_get_depth(); step_depth = cpu_get_depth();
} }
break; break;
case EXEC_MODE_TO_CALL: case EXEC_MODE_TO_CALL:
if (cpu_get_depth() > step_depth) { if(cpu_get_depth() > step_depth) {
exec_mode = EXEC_MODE_PAUSE; exec_mode = EXEC_MODE_PAUSE;
step_depth = cpu_get_depth(); step_depth = cpu_get_depth();
} }
break; break;
case EXEC_MODE_TO_RET: case EXEC_MODE_TO_RET:
if (cpu_get_depth() < step_depth) { if(cpu_get_depth() < step_depth) {
exec_mode = EXEC_MODE_PAUSE; exec_mode = EXEC_MODE_PAUSE;
step_depth = cpu_get_depth(); step_depth = cpu_get_depth();
} }
break; break;
} }
} }
} }
void tamalib_mainloop(void) void tamalib_mainloop(void) {
{ timestamp_t ts;
timestamp_t ts;
while (!g_hal->handler()) { while(!g_hal->handler()) {
tamalib_step(); tamalib_step();
/* Update the screen @ g_framerate fps */ /* Update the screen @ g_framerate fps */
ts = g_hal->get_timestamp(); ts = g_hal->get_timestamp();
if (ts - screen_ts >= ts_freq/g_framerate) { if(ts - screen_ts >= ts_freq / g_framerate) {
screen_ts = ts; screen_ts = ts;
g_hal->update_screen(); g_hal->update_screen();
} }
} }
} }
+15 -16
View File
@@ -24,35 +24,34 @@
#include "hw.h" #include "hw.h"
#include "hal.h" #include "hal.h"
#define tamalib_set_button(btn, state) hw_set_button(btn, state) #define tamalib_set_button(btn, state) hw_set_button(btn, state)
#define tamalib_set_speed(speed) cpu_set_speed(speed) #define tamalib_set_speed(speed) cpu_set_speed(speed)
#define tamalib_get_state() cpu_get_state() #define tamalib_get_state() cpu_get_state()
#define tamalib_refresh_hw() cpu_refresh_hw() #define tamalib_refresh_hw() cpu_refresh_hw()
#define tamalib_reset() cpu_reset() #define tamalib_reset() cpu_reset()
#define tamalib_add_bp(list, addr) cpu_add_bp(list, addr) #define tamalib_add_bp(list, addr) cpu_add_bp(list, addr)
#define tamalib_free_bp(list) cpu_free_bp(list) #define tamalib_free_bp(list) cpu_free_bp(list)
typedef enum { typedef enum {
EXEC_MODE_PAUSE, EXEC_MODE_PAUSE,
EXEC_MODE_RUN, EXEC_MODE_RUN,
EXEC_MODE_STEP, EXEC_MODE_STEP,
EXEC_MODE_NEXT, EXEC_MODE_NEXT,
EXEC_MODE_TO_CALL, EXEC_MODE_TO_CALL,
EXEC_MODE_TO_RET, EXEC_MODE_TO_RET,
} exec_mode_t; } exec_mode_t;
void tamalib_release(void); void tamalib_release(void);
bool_t tamalib_init(const u12_t *program, breakpoint_t *breakpoints, u32_t freq); bool_t tamalib_init(const u12_t* program, breakpoint_t* breakpoints, u32_t freq);
void tamalib_set_framerate(u8_t framerate); void tamalib_set_framerate(u8_t framerate);
u8_t tamalib_get_framerate(void); u8_t tamalib_get_framerate(void);
void tamalib_register_hal(hal_t *hal); void tamalib_register_hal(hal_t* hal);
void tamalib_set_exec_mode(exec_mode_t mode); void tamalib_set_exec_mode(exec_mode_t mode);
+2 -2
View File
@@ -1181,7 +1181,7 @@ static void tanks_game_init_game(TanksState* const tanks_state, GameState type)
static bool static bool
tanks_game_collision(Point const next_step, bool shoot, TanksState const* const tanks_state) { tanks_game_collision(Point const next_step, bool shoot, TanksState const* const tanks_state) {
if((int8_t) next_step.x < 0 || (int8_t) next_step.y < 0) { if((int8_t)next_step.x < 0 || (int8_t)next_step.y < 0) {
return true; return true;
} }
@@ -1533,7 +1533,7 @@ static void tanks_game_process_game_step(TanksState* const tanks_state) {
} }
int32_t tanks_game_app(void* p) { int32_t tanks_game_app(void* p) {
UNUSED(p); UNUSED(p);
srand(DWT->CYCCNT); srand(DWT->CYCCNT);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TanksEvent)); FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TanksEvent));
@@ -1,12 +1,12 @@
#include "../wifi_deauther_app_i.h" #include "../wifi_deauther_app_i.h"
void wifi_deauther_console_output_handle_rx_data_cb(uint8_t *buf, size_t len, void* context) { void wifi_deauther_console_output_handle_rx_data_cb(uint8_t* buf, size_t len, void* context) {
furi_assert(context); furi_assert(context);
WifideautherApp* app = context; WifideautherApp* app = context;
// If text box store gets too big, then truncate it // If text box store gets too big, then truncate it
app->text_box_store_strlen += len; app->text_box_store_strlen += len;
if (app->text_box_store_strlen >= WIFI_deauther_TEXT_BOX_STORE_SIZE - 1) { if(app->text_box_store_strlen >= WIFI_deauther_TEXT_BOX_STORE_SIZE - 1) {
string_right(app->text_box_store, app->text_box_store_strlen / 2); string_right(app->text_box_store, app->text_box_store_strlen / 2);
app->text_box_store_strlen = string_size(app->text_box_store); app->text_box_store_strlen = string_size(app->text_box_store);
} }
@@ -24,21 +24,22 @@ void wifi_deauther_scene_console_output_on_enter(void* context) {
TextBox* text_box = app->text_box; TextBox* text_box = app->text_box;
text_box_reset(app->text_box); text_box_reset(app->text_box);
text_box_set_font(text_box, TextBoxFontText); text_box_set_font(text_box, TextBoxFontText);
if (app->focus_console_start) { if(app->focus_console_start) {
text_box_set_focus(text_box, TextBoxFocusStart); text_box_set_focus(text_box, TextBoxFocusStart);
} else { } else {
text_box_set_focus(text_box, TextBoxFocusEnd); text_box_set_focus(text_box, TextBoxFocusEnd);
} }
if (app->is_command) { if(app->is_command) {
string_reset(app->text_box_store); string_reset(app->text_box_store);
app->text_box_store_strlen = 0; app->text_box_store_strlen = 0;
if (0 == strncmp("help", app->selected_tx_string, strlen("help"))) { if(0 == strncmp("help", app->selected_tx_string, strlen("help"))) {
const char* help_msg = "For app support/feedback,\nreach out to me:\n@cococode#6011 (discord)\n0xchocolate (github)\n"; const char* help_msg =
"For app support/feedback,\nreach out to me:\n@cococode#6011 (discord)\n0xchocolate (github)\n";
string_cat_str(app->text_box_store, help_msg); string_cat_str(app->text_box_store, help_msg);
app->text_box_store_strlen += strlen(help_msg); app->text_box_store_strlen += strlen(help_msg);
} }
if (app->show_stopscan_tip) { if(app->show_stopscan_tip) {
const char* help_msg = "Press BACK to send stopscan\n"; const char* help_msg = "Press BACK to send stopscan\n";
string_cat_str(app->text_box_store, help_msg); string_cat_str(app->text_box_store, help_msg);
app->text_box_store_strlen += strlen(help_msg); app->text_box_store_strlen += strlen(help_msg);
@@ -51,11 +52,13 @@ void wifi_deauther_scene_console_output_on_enter(void* context) {
view_dispatcher_switch_to_view(app->view_dispatcher, WifideautherAppViewConsoleOutput); view_dispatcher_switch_to_view(app->view_dispatcher, WifideautherAppViewConsoleOutput);
// Register callback to receive data // Register callback to receive data
wifi_deauther_uart_set_handle_rx_data_cb(app->uart, wifi_deauther_console_output_handle_rx_data_cb); // setup callback for rx thread wifi_deauther_uart_set_handle_rx_data_cb(
app->uart, wifi_deauther_console_output_handle_rx_data_cb); // setup callback for rx thread
// Send command with newline '\n' // Send command with newline '\n'
if (app->is_command && app->selected_tx_string) { if(app->is_command && app->selected_tx_string) {
wifi_deauther_uart_tx((uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string)); wifi_deauther_uart_tx(
(uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
wifi_deauther_uart_tx((uint8_t*)("\n"), 1); wifi_deauther_uart_tx((uint8_t*)("\n"), 1);
} }
} }
@@ -82,7 +85,7 @@ void wifi_deauther_scene_console_output_on_exit(void* context) {
wifi_deauther_uart_set_handle_rx_data_cb(app->uart, NULL); wifi_deauther_uart_set_handle_rx_data_cb(app->uart, NULL);
// Automatically stop the scan when exiting view // Automatically stop the scan when exiting view
if (app->is_command) { if(app->is_command) {
wifi_deauther_uart_tx((uint8_t*)("stopscan\n"), strlen("stopscan\n")); wifi_deauther_uart_tx((uint8_t*)("stopscan\n"), strlen("stopscan\n"));
} }
} }
@@ -3,17 +3,9 @@
// For each command, define whether additional arguments are needed // For each command, define whether additional arguments are needed
// (enabling text input to fill them out), and whether the console // (enabling text input to fill them out), and whether the console
// text box should focus at the start of the output or the end // text box should focus at the start of the output or the end
typedef enum { typedef enum { NO_ARGS = 0, INPUT_ARGS, TOGGLE_ARGS } InputArgs;
NO_ARGS = 0,
INPUT_ARGS,
TOGGLE_ARGS
} InputArgs;
typedef enum { typedef enum { FOCUS_CONSOLE_END = 0, FOCUS_CONSOLE_START, FOCUS_CONSOLE_TOGGLE } FocusConsole;
FOCUS_CONSOLE_END = 0,
FOCUS_CONSOLE_START,
FOCUS_CONSOLE_TOGGLE
} FocusConsole;
#define SHOW_STOPSCAN_TIP (true) #define SHOW_STOPSCAN_TIP (true)
#define NO_TIP (false) #define NO_TIP (false)
@@ -31,34 +23,78 @@ typedef struct {
// NUM_MENU_ITEMS defined in wifi_deauther_app_i.h - if you add an entry here, increment it! // NUM_MENU_ITEMS defined in wifi_deauther_app_i.h - if you add an entry here, increment it!
const WifideautherItem MenuItems[NUM_MENU_ITEMS] = { const WifideautherItem MenuItems[NUM_MENU_ITEMS] = {
{ "View Log from", {"start", "end"}, 2, {}, NO_ARGS, FOCUS_CONSOLE_TOGGLE, NO_TIP }, {"View Log from", {"start", "end"}, 2, {}, NO_ARGS, FOCUS_CONSOLE_TOGGLE, NO_TIP},
{ "Help", {""}, 1, {"help"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, {"Help", {""}, 1, {"help"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
{ "Stop", {""}, 1, {"stop all"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, {"Stop", {""}, 1, {"stop all"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
{ "Scan", {"All", "SSIDs", "Stations"}, 3, {"scan", "scan aps", "scan stations"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, {"Scan",
{ "Select", {"All", "SSIDs", "Stations"}, 3, {"select all", "select aps", "select stations"}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP }, {"All", "SSIDs", "Stations"},
{ "Deselect", {"All", "SSIDs", "Stations"}, 3, {"deselect all", "deselect aps", "deselect stations"}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP }, 3,
{ "Show", {"SSIDs", "Stations", "All", "Selected"}, 4, {"show ap", "show station", "show all", "show selected"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, {"scan", "scan aps", "scan stations"},
{ "Attack", {"deauth", "deauthall", "beacon", "probe"}, 4, {"attack deauth", "attack deauthall", "attack beacon", "attack probe"}, NO_ARGS, FOCUS_CONSOLE_END, SHOW_STOPSCAN_TIP }, NO_ARGS,
{ "Settings", {"Get", "Remove AP", "Set SSID", "Set Pass", "Save"}, 5, {"get settings", "set webinterface false", "set ssid: pwned", "set password: deauther", "save settings"}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP }, FOCUS_CONSOLE_END,
{ "Sysinfo", {""}, 1, {"sysinfo"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, NO_TIP},
{ "Reboot", {""}, 1, {"reboot"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, {"Select",
{"All", "SSIDs", "Stations"},
3,
{"select all", "select aps", "select stations"},
INPUT_ARGS,
FOCUS_CONSOLE_END,
NO_TIP},
{"Deselect",
{"All", "SSIDs", "Stations"},
3,
{"deselect all", "deselect aps", "deselect stations"},
INPUT_ARGS,
FOCUS_CONSOLE_END,
NO_TIP},
{"Show",
{"SSIDs", "Stations", "All", "Selected"},
4,
{"show ap", "show station", "show all", "show selected"},
NO_ARGS,
FOCUS_CONSOLE_END,
NO_TIP},
{"Attack",
{"deauth", "deauthall", "beacon", "probe"},
4,
{"attack deauth", "attack deauthall", "attack beacon", "attack probe"},
NO_ARGS,
FOCUS_CONSOLE_END,
SHOW_STOPSCAN_TIP},
{"Settings",
{"Get", "Remove AP", "Set SSID", "Set Pass", "Save"},
5,
{"get settings",
"set webinterface false",
"set ssid: pwned",
"set password: deauther",
"save settings"},
INPUT_ARGS,
FOCUS_CONSOLE_END,
NO_TIP},
{"Sysinfo", {""}, 1, {"sysinfo"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
{"Reboot", {""}, 1, {"reboot"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
}; };
static void wifi_deauther_scene_start_var_list_enter_callback(void* context, uint32_t index) { static void wifi_deauther_scene_start_var_list_enter_callback(void* context, uint32_t index) {
furi_assert(context); furi_assert(context);
WifideautherApp* app = context; WifideautherApp* app = context;
if (app->selected_option_index[index] < MenuItems[index].num_options_menu) { if(app->selected_option_index[index] < MenuItems[index].num_options_menu) {
app->selected_tx_string = MenuItems[index].actual_commands[app->selected_option_index[index]]; app->selected_tx_string =
MenuItems[index].actual_commands[app->selected_option_index[index]];
} }
app->is_command = (1 <= index); app->is_command = (1 <= index);
app->is_custom_tx_string = false; app->is_custom_tx_string = false;
app->selected_menu_index = index; app->selected_menu_index = index;
app->focus_console_start = (MenuItems[index].focus_console == FOCUS_CONSOLE_TOGGLE) ? (app->selected_option_index[index] == 0) : MenuItems[index].focus_console; app->focus_console_start = (MenuItems[index].focus_console == FOCUS_CONSOLE_TOGGLE) ?
(app->selected_option_index[index] == 0) :
MenuItems[index].focus_console;
app->show_stopscan_tip = MenuItems[index].show_stopscan_tip; app->show_stopscan_tip = MenuItems[index].show_stopscan_tip;
bool needs_keyboard = (MenuItems[index].needs_keyboard == TOGGLE_ARGS) ? (app->selected_option_index[index] != 0) : MenuItems[index].needs_keyboard; bool needs_keyboard = (MenuItems[index].needs_keyboard == TOGGLE_ARGS) ?
if (needs_keyboard) { (app->selected_option_index[index] != 0) :
MenuItems[index].needs_keyboard;
if(needs_keyboard) {
view_dispatcher_send_custom_event(app->view_dispatcher, WifideautherEventStartKeyboard); view_dispatcher_send_custom_event(app->view_dispatcher, WifideautherEventStartKeyboard);
} else { } else {
view_dispatcher_send_custom_event(app->view_dispatcher, WifideautherEventStartConsole); view_dispatcher_send_custom_event(app->view_dispatcher, WifideautherEventStartConsole);
@@ -86,11 +122,17 @@ void wifi_deauther_scene_start_on_enter(void* context) {
var_item_list, wifi_deauther_scene_start_var_list_enter_callback, app); var_item_list, wifi_deauther_scene_start_var_list_enter_callback, app);
VariableItem* item; VariableItem* item;
for (int i = 0; i < NUM_MENU_ITEMS; ++i) { for(int i = 0; i < NUM_MENU_ITEMS; ++i) {
item = variable_item_list_add(var_item_list, MenuItems[i].item_string, MenuItems[i].num_options_menu, wifi_deauther_scene_start_var_list_change_callback, app); item = variable_item_list_add(
if (MenuItems[i].num_options_menu) { var_item_list,
MenuItems[i].item_string,
MenuItems[i].num_options_menu,
wifi_deauther_scene_start_var_list_change_callback,
app);
if(MenuItems[i].num_options_menu) {
variable_item_set_current_value_index(item, app->selected_option_index[i]); variable_item_set_current_value_index(item, app->selected_option_index[i]);
variable_item_set_current_value_text(item, MenuItems[i].options_menu[app->selected_option_index[i]]); variable_item_set_current_value_text(
item, MenuItems[i].options_menu[app->selected_option_index[i]]);
} }
} }
@@ -106,15 +148,17 @@ bool wifi_deauther_scene_start_on_event(void* context, SceneManagerEvent event)
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if (event.event == WifideautherEventStartKeyboard) { if(event.event == WifideautherEventStartKeyboard) {
scene_manager_set_scene_state(app->scene_manager, WifideautherSceneStart, app->selected_menu_index); scene_manager_set_scene_state(
app->scene_manager, WifideautherSceneStart, app->selected_menu_index);
scene_manager_next_scene(app->scene_manager, WifideautherAppViewTextInput); scene_manager_next_scene(app->scene_manager, WifideautherAppViewTextInput);
} else if (event.event == WifideautherEventStartConsole) { } else if(event.event == WifideautherEventStartConsole) {
scene_manager_set_scene_state(app->scene_manager, WifideautherSceneStart, app->selected_menu_index); scene_manager_set_scene_state(
app->scene_manager, WifideautherSceneStart, app->selected_menu_index);
scene_manager_next_scene(app->scene_manager, WifideautherAppViewConsoleOutput); scene_manager_next_scene(app->scene_manager, WifideautherAppViewConsoleOutput);
} }
consumed = true; consumed = true;
} else if (event.type == SceneManagerEventTypeTick) { } else if(event.type == SceneManagerEventTypeTick) {
app->selected_menu_index = variable_item_list_get_selected_item_index(app->var_item_list); app->selected_menu_index = variable_item_list_get_selected_item_index(app->var_item_list);
consumed = true; consumed = true;
} }
@@ -1,6 +1,5 @@
#include "../wifi_deauther_app_i.h" #include "../wifi_deauther_app_i.h"
void wifi_deauther_scene_text_input_callback(void* context) { void wifi_deauther_scene_text_input_callback(void* context) {
WifideautherApp* app = context; WifideautherApp* app = context;
@@ -10,7 +9,7 @@ void wifi_deauther_scene_text_input_callback(void* context) {
void wifi_deauther_scene_text_input_on_enter(void* context) { void wifi_deauther_scene_text_input_on_enter(void* context) {
WifideautherApp* app = context; WifideautherApp* app = context;
if (false == app->is_custom_tx_string) { if(false == app->is_custom_tx_string) {
// Fill text input with selected string so that user can add to it // Fill text input with selected string so that user can add to it
size_t length = strlen(app->selected_tx_string); size_t length = strlen(app->selected_tx_string);
furi_assert(length < WIFI_deauther_TEXT_INPUT_STORE_SIZE); furi_assert(length < WIFI_deauther_TEXT_INPUT_STORE_SIZE);
@@ -19,27 +18,33 @@ void wifi_deauther_scene_text_input_on_enter(void* context) {
// Add space - because flipper keyboard currently doesn't have a space // Add space - because flipper keyboard currently doesn't have a space
app->text_input_store[length] = ' '; app->text_input_store[length] = ' ';
app->text_input_store[length+1] = '\0'; app->text_input_store[length + 1] = '\0';
app->is_custom_tx_string = true; app->is_custom_tx_string = true;
} }
// Setup view // Setup view
TextInput* text_input = app->text_input; TextInput* text_input = app->text_input;
// Add help message to header // Add help message to header
if (0 == strncmp("ssid -a -g", app->selected_tx_string, strlen("ssid -a -g"))) { if(0 == strncmp("ssid -a -g", app->selected_tx_string, strlen("ssid -a -g"))) {
text_input_set_header_text(text_input, "Enter # SSIDs to generate"); text_input_set_header_text(text_input, "Enter # SSIDs to generate");
} else if (0 == strncmp("ssid -a -n", app->selected_tx_string, strlen("ssid -a -n"))) { } else if(0 == strncmp("ssid -a -n", app->selected_tx_string, strlen("ssid -a -n"))) {
text_input_set_header_text(text_input, "Enter SSID name to add"); text_input_set_header_text(text_input, "Enter SSID name to add");
} else if (0 == strncmp("ssid -r", app->selected_tx_string, strlen("ssid -r"))) { } else if(0 == strncmp("ssid -r", app->selected_tx_string, strlen("ssid -r"))) {
text_input_set_header_text(text_input, "Remove target from SSID list"); text_input_set_header_text(text_input, "Remove target from SSID list");
} else if (0 == strncmp("select -a", app->selected_tx_string, strlen("select -a"))) { } else if(0 == strncmp("select -a", app->selected_tx_string, strlen("select -a"))) {
text_input_set_header_text(text_input, "Add target from AP list"); text_input_set_header_text(text_input, "Add target from AP list");
} else if (0 == strncmp("select -s", app->selected_tx_string, strlen("select -s"))) { } else if(0 == strncmp("select -s", app->selected_tx_string, strlen("select -s"))) {
text_input_set_header_text(text_input, "Add target from SSID list"); text_input_set_header_text(text_input, "Add target from SSID list");
} else { } else {
text_input_set_header_text(text_input, "Add command arguments"); text_input_set_header_text(text_input, "Add command arguments");
} }
text_input_set_result_callback(text_input, wifi_deauther_scene_text_input_callback, app, app->text_input_store, WIFI_deauther_TEXT_INPUT_STORE_SIZE, false); text_input_set_result_callback(
text_input,
wifi_deauther_scene_text_input_callback,
app,
app->text_input_store,
WIFI_deauther_TEXT_INPUT_STORE_SIZE,
false);
view_dispatcher_switch_to_view(app->view_dispatcher, WifideautherAppViewTextInput); view_dispatcher_switch_to_view(app->view_dispatcher, WifideautherAppViewTextInput);
} }
@@ -48,8 +53,8 @@ bool wifi_deauther_scene_text_input_on_event(void* context, SceneManagerEvent ev
WifideautherApp* app = context; WifideautherApp* app = context;
bool consumed = false; bool consumed = false;
if (event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if (event.event == WifideautherEventStartConsole) { if(event.event == WifideautherEventStartConsole) {
// Point to custom string to send // Point to custom string to send
app->selected_tx_string = app->text_input_store; app->selected_tx_string = app->text_input_store;
scene_manager_next_scene(app->scene_manager, WifideautherAppViewConsoleOutput); scene_manager_next_scene(app->scene_manager, WifideautherAppViewConsoleOutput);
@@ -47,17 +47,19 @@ WifideautherApp* wifi_deauther_app_alloc() {
WifideautherAppViewVarItemList, WifideautherAppViewVarItemList,
variable_item_list_get_view(app->var_item_list)); variable_item_list_get_view(app->var_item_list));
for (int i = 0; i < NUM_MENU_ITEMS; ++i) { for(int i = 0; i < NUM_MENU_ITEMS; ++i) {
app->selected_option_index[i] = 0; app->selected_option_index[i] = 0;
} }
app->text_box = text_box_alloc(); app->text_box = text_box_alloc();
view_dispatcher_add_view(app->view_dispatcher, WifideautherAppViewConsoleOutput, text_box_get_view(app->text_box)); view_dispatcher_add_view(
app->view_dispatcher, WifideautherAppViewConsoleOutput, text_box_get_view(app->text_box));
string_init(app->text_box_store); string_init(app->text_box_store);
string_reserve(app->text_box_store, WIFI_deauther_TEXT_BOX_STORE_SIZE); string_reserve(app->text_box_store, WIFI_deauther_TEXT_BOX_STORE_SIZE);
app->text_input = text_input_alloc(); app->text_input = text_input_alloc();
view_dispatcher_add_view(app->view_dispatcher, WifideautherAppViewTextInput, text_input_get_view(app->text_input)); view_dispatcher_add_view(
app->view_dispatcher, WifideautherAppViewTextInput, text_input_get_view(app->text_input));
scene_manager_next_scene(app->scene_manager, WifideautherSceneStart); scene_manager_next_scene(app->scene_manager, WifideautherSceneStart);
@@ -10,8 +10,8 @@ struct WifideautherUart {
WifideautherApp* app; WifideautherApp* app;
FuriThread* rx_thread; FuriThread* rx_thread;
StreamBufferHandle_t rx_stream; StreamBufferHandle_t rx_stream;
uint8_t rx_buf[RX_BUF_SIZE+1]; uint8_t rx_buf[RX_BUF_SIZE + 1];
void (*handle_rx_data_cb)(uint8_t *buf, size_t len, void* context); void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context);
}; };
typedef enum { typedef enum {
@@ -19,7 +19,9 @@ typedef enum {
WorkerEvtRxDone = (1 << 1), WorkerEvtRxDone = (1 << 1),
} WorkerEvtFlags; } WorkerEvtFlags;
void wifi_deauther_uart_set_handle_rx_data_cb(WifideautherUart* uart, void (*handle_rx_data_cb)(uint8_t *buf, size_t len, void* context)) { void wifi_deauther_uart_set_handle_rx_data_cb(
WifideautherUart* uart,
void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context)) {
furi_assert(uart); furi_assert(uart);
uart->handle_rx_data_cb = handle_rx_data_cb; uart->handle_rx_data_cb = handle_rx_data_cb;
} }
@@ -48,10 +50,9 @@ static int32_t uart_worker(void* context) {
furi_check((events & FuriFlagError) == 0); furi_check((events & FuriFlagError) == 0);
if(events & WorkerEvtStop) break; if(events & WorkerEvtStop) break;
if(events & WorkerEvtRxDone) { if(events & WorkerEvtRxDone) {
size_t len = size_t len = xStreamBufferReceive(uart->rx_stream, uart->rx_buf, RX_BUF_SIZE, 0);
xStreamBufferReceive(uart->rx_stream, uart->rx_buf, RX_BUF_SIZE, 0);
if(len > 0) { if(len > 0) {
if (uart->handle_rx_data_cb) uart->handle_rx_data_cb(uart->rx_buf, len, uart->app); if(uart->handle_rx_data_cb) uart->handle_rx_data_cb(uart->rx_buf, len, uart->app);
} }
} }
} }
@@ -61,12 +62,12 @@ static int32_t uart_worker(void* context) {
return 0; return 0;
} }
void wifi_deauther_uart_tx(uint8_t *data, size_t len) { void wifi_deauther_uart_tx(uint8_t* data, size_t len) {
furi_hal_uart_tx(UART_CH, data, len); furi_hal_uart_tx(UART_CH, data, len);
} }
WifideautherUart* wifi_deauther_uart_init(WifideautherApp* app) { WifideautherUart* wifi_deauther_uart_init(WifideautherApp* app) {
WifideautherUart *uart = malloc(sizeof(WifideautherUart)); WifideautherUart* uart = malloc(sizeof(WifideautherUart));
furi_hal_console_disable(); furi_hal_console_disable();
furi_hal_uart_set_br(UART_CH, BAUDRATE); furi_hal_uart_set_br(UART_CH, BAUDRATE);
@@ -6,7 +6,9 @@
typedef struct WifideautherUart WifideautherUart; typedef struct WifideautherUart WifideautherUart;
void wifi_deauther_uart_set_handle_rx_data_cb(WifideautherUart* uart, void (*handle_rx_data_cb)(uint8_t *buf, size_t len, void* context)); void wifi_deauther_uart_set_handle_rx_data_cb(
void wifi_deauther_uart_tx(uint8_t *data, size_t len); WifideautherUart* uart,
void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context));
void wifi_deauther_uart_tx(uint8_t* data, size_t len);
WifideautherUart* wifi_deauther_uart_init(WifideautherApp* app); WifideautherUart* wifi_deauther_uart_init(WifideautherApp* app);
void wifi_deauther_uart_free(WifideautherUart* uart); void wifi_deauther_uart_free(WifideautherUart* uart);
@@ -112,7 +112,8 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
break; break;
} }
case DesktopMainEventOpenClock: { case DesktopMainEventOpenClock: {
LoaderStatus status = loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Main/Clock.fap")); LoaderStatus status =
loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Main/Clock.fap"));
consumed = true; consumed = true;
break; break;
} }
@@ -169,38 +170,38 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
break; break;
} }
case DesktopMainEventOpenSnake: { case DesktopMainEventOpenSnake: {
LoaderStatus status = loader_start( LoaderStatus status =
desktop->loader, "Applications", EXT_PATH("/apps/Games/Snake.fap")); loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Games/Snake.fap"));
consumed = true; consumed = true;
break; break;
} }
case DesktopMainEventOpen2048: { case DesktopMainEventOpen2048: {
LoaderStatus status = loader_start( LoaderStatus status =
desktop->loader, "Applications", EXT_PATH("/apps/Games/2048.fap")); loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Games/2048.fap"));
consumed = true; consumed = true;
break; break;
} }
case DesktopMainEventOpenZombiez: { case DesktopMainEventOpenZombiez: {
LoaderStatus status = loader_start( LoaderStatus status =
desktop->loader, "Applications", EXT_PATH("/apps/Games/Zombiez.fap")); loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Games/Zombiez.fap"));
consumed = true; consumed = true;
break; break;
} }
case DesktopMainEventOpenTetris: { case DesktopMainEventOpenTetris: {
LoaderStatus status = loader_start( LoaderStatus status =
desktop->loader, "Applications", EXT_PATH("/apps/Games/Tetris.fap")); loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Games/Tetris.fap"));
consumed = true; consumed = true;
break; break;
} }
case DesktopMainEventOpenDOOM: { case DesktopMainEventOpenDOOM: {
LoaderStatus status = loader_start( LoaderStatus status =
desktop->loader, "Applications", EXT_PATH("/apps/Games/DOOM.fap")); loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Games/DOOM.fap"));
consumed = true; consumed = true;
break; break;
} }
case DesktopMainEventOpenDice: { case DesktopMainEventOpenDice: {
LoaderStatus status = loader_start( LoaderStatus status =
desktop->loader, "Applications", EXT_PATH("/apps/Games/Dice.fap")); loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Games/Dice.fap"));
consumed = true; consumed = true;
break; break;
} }
@@ -85,7 +85,7 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) {
} else { } else {
str = "Set PIN + Off"; str = "Set PIN + Off";
} }
// } else if(i == DesktopLockMenuIndexGameMode) { // } else if(i == DesktopLockMenuIndexGameMode) {
// str = "Games Mode"; // str = "Games Mode";
} else if(i == DesktopLockMenuIndexDummy) { } else if(i == DesktopLockMenuIndexDummy) {
if(m->dummy_mode) { if(m->dummy_mode) {
@@ -151,7 +151,7 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) {
lock_menu->callback(DesktopLockMenuEventPinLock, lock_menu->context); lock_menu->callback(DesktopLockMenuEventPinLock, lock_menu->context);
} else if((idx == DesktopLockMenuIndexPinLockShutdown) && (event->type == InputTypeShort)) { } else if((idx == DesktopLockMenuIndexPinLockShutdown) && (event->type == InputTypeShort)) {
lock_menu->callback(DesktopLockMenuEventPinLockShutdown, lock_menu->context); lock_menu->callback(DesktopLockMenuEventPinLockShutdown, lock_menu->context);
// } else if((idx == DesktopLockMenuIndexGameMode) && (event->type == InputTypeShort)) { // } else if((idx == DesktopLockMenuIndexGameMode) && (event->type == InputTypeShort)) {
// desktop_view_lock_menu_dumbmode_changed(1); // desktop_view_lock_menu_dumbmode_changed(1);
// DOLPHIN_DEED(getRandomDeed()); // DOLPHIN_DEED(getRandomDeed());
// lock_menu->callback(DesktopLockMenuEventExit, lock_menu->context); // lock_menu->callback(DesktopLockMenuEventExit, lock_menu->context);
@@ -84,7 +84,8 @@ bool desktop_main_input_callback(InputEvent* event, void* context) {
} else if(event->key == InputKeyDown) { } else if(event->key == InputKeyDown) {
main_view->callback(DesktopMainEventOpenFavoriteSecondary, main_view->context); main_view->callback(DesktopMainEventOpenFavoriteSecondary, main_view->context);
} else if(event->key == InputKeyLeft) { } else if(event->key == InputKeyLeft) {
main_view->callback(DesktopMainEventOpenSubRemote, main_view->context); // OPENS SUBGHZ REMOTE main_view->callback(
DesktopMainEventOpenSubRemote, main_view->context); // OPENS SUBGHZ REMOTE
} }
} }
} else if(main_view->is_gamemode == true) { } else if(main_view->is_gamemode == true) {
@@ -105,9 +106,11 @@ bool desktop_main_input_callback(InputEvent* event, void* context) {
} else if(event->key == InputKeyUp) { } else if(event->key == InputKeyUp) {
main_view->callback(DesktopMainEventOpenDOOM, main_view->context); // OPENS DOOM main_view->callback(DesktopMainEventOpenDOOM, main_view->context); // OPENS DOOM
} else if(event->key == InputKeyDown) { } else if(event->key == InputKeyDown) {
main_view->callback(DesktopMainEventOpenZombiez, main_view->context); // OPENS Zombiez main_view->callback(
DesktopMainEventOpenZombiez, main_view->context); // OPENS Zombiez
} else if(event->key == InputKeyLeft) { } else if(event->key == InputKeyLeft) {
main_view->callback(DesktopMainEventOpenTetris, main_view->context); // OPENS TETRIS main_view->callback(
DesktopMainEventOpenTetris, main_view->context); // OPENS TETRIS
} }
} }
} else { } else {
@@ -127,10 +130,12 @@ bool desktop_main_input_callback(InputEvent* event, void* context) {
} else if(event->key == InputKeyUp) { } else if(event->key == InputKeyUp) {
main_view->callback(DesktopMainEventOpenSnake, main_view->context); // OPENS SNAKE main_view->callback(DesktopMainEventOpenSnake, main_view->context); // OPENS SNAKE
} else if(event->key == InputKeyDown) { } else if(event->key == InputKeyDown) {
main_view->callback(DesktopMainEventOpenZombiez, main_view->context); // OPENS Zombiez main_view->callback(
DesktopMainEventOpenZombiez, main_view->context); // OPENS Zombiez
} else if(event->key == InputKeyLeft) { } else if(event->key == InputKeyLeft) {
main_view->callback(DesktopMainEventOpenTetris, main_view->context); // OPENS TETRIS main_view->callback(
} DesktopMainEventOpenTetris, main_view->context); // OPENS TETRIS
}
} }
} }
@@ -151,10 +151,10 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent sme)
consumed = true; consumed = true;
break; break;
// case SCENE_EVENT_SELECT_FAVORITE_GAME: // case SCENE_EVENT_SELECT_FAVORITE_GAME:
// scene_manager_set_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite, 2); // scene_manager_set_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite, 2);
// scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); // scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite);
// consumed = true; // consumed = true;
// break; // break;
case SCENE_EVENT_SELECT_PIN_SETUP: case SCENE_EVENT_SELECT_PIN_SETUP:
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu);
consumed = true; consumed = true;
@@ -19,16 +19,15 @@ static const Icon* const portrait_happy[7] = {
&I_G0ku, &I_G0ku,
&I_g0ku_1, &I_g0ku_1,
&I_g0ku_2, &I_g0ku_2,
&I_g0ku_3 &I_g0ku_3};
};
// static const Icon* const portrait_ok[MOODS_TOTAL] = { // static const Icon* const portrait_ok[MOODS_TOTAL] = {
// &I_passport_okay1_46x49, // &I_passport_okay1_46x49,
// &I_passport_okay2_46x49, // &I_passport_okay2_46x49,
// &I_passport_okay3_46x49}; // &I_passport_okay3_46x49};
// static const Icon* const portrait_bad[MOODS_TOTAL] = { // static const Icon* const portrait_bad[MOODS_TOTAL] = {
// &I_passport_bad1_46x49, // &I_passport_bad1_46x49,
// &I_passport_bad2_46x49, // &I_passport_bad2_46x49,
// &I_passport_bad3_46x49}; // &I_passport_bad3_46x49};
// static const Icon* const* portraits[MOODS_TOTAL] = {portrait_happy, portrait_ok, portrait_bad}; // static const Icon* const* portraits[MOODS_TOTAL] = {portrait_happy, portrait_ok, portrait_bad};
static const Icon* const* portraits[MOODS_TOTAL] = {portrait_happy}; static const Icon* const* portraits[MOODS_TOTAL] = {portrait_happy};
@@ -49,8 +48,7 @@ static const char* const moods[16] = {
"Annoyed", "Annoyed",
"Upset", "Upset",
"Angry", "Angry",
"Furious" "Furious"};
};
static void input_callback(InputEvent* input, void* ctx) { static void input_callback(InputEvent* input, void* ctx) {
FuriSemaphore* semaphore = ctx; FuriSemaphore* semaphore = ctx;
@@ -87,7 +85,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
// multipass // multipass
canvas_draw_icon(canvas, 0, 0, &I_passport_DB); canvas_draw_icon(canvas, 0, 0, &I_passport_DB);
// portrait // portrait
furi_assert((stats->level > 0) && (stats->level <= 30)); furi_assert((stats->level > 0) && (stats->level <= 30));
uint16_t tmpLvl = 0; uint16_t tmpLvl = 0;
@@ -98,7 +96,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
if(stats->level > 24) tmpLvl = 5; if(stats->level > 24) tmpLvl = 5;
if(stats->level > 27) tmpLvl = 6; if(stats->level > 27) tmpLvl = 6;
canvas_draw_icon(canvas, 11, 2, portraits[mood][tmpLvl]); canvas_draw_icon(canvas, 11, 2, portraits[mood][tmpLvl]);
const char* my_name = furi_hal_version_get_name_ptr(); const char* my_name = furi_hal_version_get_name_ptr();
snprintf(level_str, 12, "Level: %hu", stats->level); snprintf(level_str, 12, "Level: %hu", stats->level);
snprintf(xp_str, 12, "%lu/%lu", xp_above_last_levelup, xp_for_current_level); snprintf(xp_str, 12, "%lu/%lu", xp_above_last_levelup, xp_for_current_level);
@@ -114,7 +112,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
canvas_set_color(canvas, ColorWhite); canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 123 - xp_progress, 45, xp_progress + 1, 5); canvas_draw_box(canvas, 123 - xp_progress, 45, xp_progress + 1, 5);
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
} }
int32_t passport_app(void* p) { int32_t passport_app(void* p) {
UNUSED(p); UNUSED(p);
+1 -2
View File
@@ -142,8 +142,7 @@ void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t durati
case KIADecoderStepSaveDuration: case KIADecoderStepSaveDuration:
if(level) { if(level) {
if(duration >= if(duration >=
(uint32_t)( (uint32_t)(subghz_protocol_kia_const.te_long + subghz_protocol_kia_const.te_delta * 2)) {
subghz_protocol_kia_const.te_long + subghz_protocol_kia_const.te_delta * 2)) {
//Found stop bit //Found stop bit
instance->decoder.parser_step = KIADecoderStepReset; instance->decoder.parser_step = KIADecoderStepReset;
if(instance->decoder.decode_count_bit == if(instance->decoder.decode_count_bit ==