plugins
@ -21,6 +21,7 @@ extern int32_t accessor_app(void* p);
|
||||
extern int32_t archive_app(void* p);
|
||||
extern int32_t bad_usb_app(void* p);
|
||||
extern int32_t u2f_app(void* p);
|
||||
extern int32_t wav_player_app(void* p);
|
||||
extern int32_t uart_echo_app(void* p);
|
||||
extern int32_t blink_test_app(void* p);
|
||||
extern int32_t bt_debug_app(void* p);
|
||||
@ -38,6 +39,8 @@ extern int32_t passport_app(void* p);
|
||||
extern int32_t scened_app(void* p);
|
||||
extern int32_t storage_test_app(void* p);
|
||||
extern int32_t subghz_app(void* p);
|
||||
extern int32_t jukebox_app(void *p);
|
||||
extern int32_t universal_rf_remote_app(void *p);
|
||||
extern int32_t usb_mouse_app(void* p);
|
||||
extern int32_t usb_test_app(void* p);
|
||||
extern int32_t vibro_test_app(void* p);
|
||||
@ -49,7 +52,11 @@ extern int32_t text_box_test_app(void* p);
|
||||
extern int32_t music_player_app(void* p);
|
||||
extern int32_t snake_game_app(void* p);
|
||||
extern int32_t tetris_game_app(void *p);
|
||||
extern int32_t clock_app(void *p);
|
||||
// extern int32_t floopper_bloopper(void* p);
|
||||
// extern int32_t raycast_game_app(void* p);
|
||||
extern int32_t spectrum_analyzer_app(void* p);
|
||||
extern int32_t flappy_game_app(void* p);
|
||||
|
||||
// On system start hooks declaration
|
||||
extern void bt_on_system_start();
|
||||
@ -207,6 +214,14 @@ const size_t FLIPPER_SYSTEM_APPS_COUNT = COUNT_OF(FLIPPER_SYSTEM_APPS);
|
||||
// Main menu APP
|
||||
const FlipperApplication FLIPPER_APPS[] = {
|
||||
|
||||
#ifdef APP_CLOCK
|
||||
{.app = clock_app,
|
||||
.name = "Clock",
|
||||
.stack_size = 2048,
|
||||
.icon = &A_Clock_14,
|
||||
.flags = FlipperApplicationFlagDefault},
|
||||
#endif
|
||||
|
||||
#ifdef APP_SUBGHZ
|
||||
{.app = subghz_app,
|
||||
.name = "Sub-GHz",
|
||||
@ -270,7 +285,6 @@ const FlipperApplication FLIPPER_APPS[] = {
|
||||
.icon = &A_U2F_14,
|
||||
.flags = FlipperApplicationFlagDefault},
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
const size_t FLIPPER_APPS_COUNT = COUNT_OF(FLIPPER_APPS);
|
||||
@ -336,11 +350,27 @@ const FlipperApplication FLIPPER_PLUGINS[] = {
|
||||
.flags = FlipperApplicationFlagDefault},
|
||||
#endif
|
||||
|
||||
#ifdef APP_FLAPPY_GAME
|
||||
{.app = flappy_game_app,
|
||||
.name = "Flipper Flappy Bird",
|
||||
.stack_size = 1024,
|
||||
.icon = &A_Plugins_14
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef APP_JUKEBOX
|
||||
{.app = jukebox_app,
|
||||
.name = "Jukebox",
|
||||
.stack_size = 2048,
|
||||
.icon = &A_UniversalRemote_14,
|
||||
.flags = FlipperApplicationFlagDefault},
|
||||
#endif
|
||||
|
||||
#ifdef APP_MUSIC_PLAYER
|
||||
{.app = music_player_app,
|
||||
.name = "Music Player",
|
||||
.stack_size = 2048,
|
||||
.icon = &A_Plugins_14,
|
||||
.icon = &A_MusicPlayer_14,
|
||||
.flags = FlipperApplicationFlagDefault},
|
||||
#endif
|
||||
|
||||
@ -352,20 +382,44 @@ const FlipperApplication FLIPPER_PLUGINS[] = {
|
||||
.flags = FlipperApplicationFlagDefault},
|
||||
#endif
|
||||
|
||||
#ifdef APP_TETRIS_GAME
|
||||
{.app = tetris_game_app,
|
||||
.name = "Tetris Game",
|
||||
.stack_size = 1024,
|
||||
.icon = NULL},
|
||||
#ifdef APP_SPECTRUM_ANALYZER
|
||||
{.app = spectrum_analyzer_app,
|
||||
.name = "Spectrum Analyzer",
|
||||
.stack_size = 1024,
|
||||
.icon = &A_Plugins_14,
|
||||
.flags = FlipperApplicationFlagDefault},
|
||||
#endif
|
||||
|
||||
#ifdef APP_SPECTRUM_ANALYZER
|
||||
{.app = spectrum_analyzer_app,
|
||||
.name = "Spectrum Analyzer",
|
||||
.stack_size = 1024,
|
||||
.icon = &A_Plugins_14,
|
||||
#ifdef APP_TETRIS_GAME
|
||||
{.app = tetris_game_app, .name = "Tetris Game", .stack_size = 1024, .icon = NULL},
|
||||
#endif
|
||||
|
||||
#ifdef APP_UNIVERSALRF
|
||||
{.app = universal_rf_remote_app,
|
||||
.name = "Universal SubGHz",
|
||||
.stack_size = 2048,
|
||||
.icon = &A_UniversalRemote_14,
|
||||
.flags = FlipperApplicationFlagDefault},
|
||||
#endif
|
||||
|
||||
{.app = wav_player_app,
|
||||
.name = "Wav Player",
|
||||
.stack_size = 4096,
|
||||
.icon = &A_MusicPlayer_14,
|
||||
.flags = FlipperApplicationFlagDefault},
|
||||
|
||||
// #ifdef APP_RAYCAST_GAME
|
||||
// {.app = raycast_game_app, .name = "Raycast Game", .stack_size = 4096, .icon = NULL},
|
||||
// #endif
|
||||
|
||||
// #ifdef FLOOPPER_BLOOPPER
|
||||
// {.app = floopper_bloopper,
|
||||
// .name = "Floopper Bloopper",
|
||||
// .stack_size = 1024,
|
||||
// .icon = &A_Plugins_14,
|
||||
// .flags = FlipperApplicationFlagDefault},
|
||||
// #endif
|
||||
|
||||
};
|
||||
|
||||
const size_t FLIPPER_PLUGINS_COUNT = COUNT_OF(FLIPPER_PLUGINS);
|
||||
|
@ -40,6 +40,8 @@ APP_INFRARED = 1
|
||||
APP_LF_RFID = 1
|
||||
APP_NFC = 1
|
||||
APP_SUBGHZ = 1
|
||||
APP_UNIVERSALRF = 1
|
||||
APP_JUKEBOX = 1
|
||||
APP_ABOUT = 1
|
||||
APP_PASSPORT = 1
|
||||
APP_UPDATER = 1
|
||||
@ -48,7 +50,11 @@ APP_UPDATER = 1
|
||||
APP_MUSIC_PLAYER = 1
|
||||
APP_SNAKE_GAME = 1
|
||||
APP_TETRIS_GAME = 1
|
||||
# APP_RAYCAST_GAME = 1
|
||||
APP_CLOCK = 1
|
||||
APP_SPECTRUM_ANALYZER = 1
|
||||
APP_FLAPPY_GAME = 1
|
||||
|
||||
|
||||
# Debug
|
||||
APP_ACCESSOR = 1
|
||||
@ -106,6 +112,19 @@ SRV_GUI = 1
|
||||
SRV_CLI = 1
|
||||
endif
|
||||
|
||||
APP_UNIVERSALRF ?= 0
|
||||
ifeq ($(APP_UNIVERSALRF), 1)
|
||||
CFLAGS += -DAPP_UNIVERSALRF
|
||||
SRV_GUI = 1
|
||||
SRV_CLI = 1
|
||||
endif
|
||||
|
||||
APP_JUKEBOX ?= 0
|
||||
ifeq ($(APP_JUKEBOX), 1)
|
||||
CFLAGS += -DAPP_JUKEBOX
|
||||
SRV_GUI = 1
|
||||
SRV_CLI = 1
|
||||
endif
|
||||
|
||||
APP_ABOUT ?= 0
|
||||
ifeq ($(APP_ABOUT), 1)
|
||||
@ -230,21 +249,40 @@ CFLAGS += -DAPP_MUSIC_PLAYER
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
APP_FLAPPY_GAME ?= 0
|
||||
ifeq ($(APP_FLAPPY_GAME), 1)
|
||||
CFLAGS += -DAPP_FLAPPY_GAME
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
APP_SNAKE_GAME ?= 0
|
||||
ifeq ($(APP_SNAKE_GAME), 1)
|
||||
CFLAGS += -DAPP_SNAKE_GAME
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
APP_SPECTRUM_ANALYZER ?= 0
|
||||
ifeq ($(APP_SPECTRUM_ANALYZER), 1)
|
||||
CFLAGS += -DAPP_SPECTRUM_ANALYZER
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
APP_TETRIS_GAME ?= 0
|
||||
ifeq ($(APP_TETRIS_GAME), 1)
|
||||
CFLAGS += -DAPP_TETRIS_GAME
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
APP_SPECTRUM_ANALYZER ?= 0
|
||||
ifeq ($(APP_SPECTRUM_ANALYZER), 1)
|
||||
CFLAGS += -DAPP_SPECTRUM_ANALYZER
|
||||
# APP_RAYCAST_GAME ?= 0
|
||||
# ifeq ($(APP_RAYCAST_GAME), 1)
|
||||
# CFLAGS += -DAPP_RAYCAST_GAME
|
||||
# SRV_GUI = 1
|
||||
# endif
|
||||
|
||||
|
||||
APP_CLOCK ?= 0
|
||||
ifeq ($(APP_CLOCK), 1)
|
||||
CFLAGS += -DAPP_CLOCK
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
|
278
applications/clock_app/clock_app.c
Normal file
@ -0,0 +1,278 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#define TAG "Clock"
|
||||
|
||||
bool timerStarted=false;
|
||||
int timerSecs=0;
|
||||
int songSelect=0;
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
EventType type;
|
||||
InputEvent input;
|
||||
} PluginEvent;
|
||||
|
||||
typedef struct {
|
||||
FuriHalRtcDateTime datetime;
|
||||
} ClockState;
|
||||
|
||||
static void clock_input_callback(InputEvent* input_event, osMessageQueueId_t event_queue) {
|
||||
furi_assert(event_queue);
|
||||
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
|
||||
osMessageQueuePut(event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
static void clock_render_callback(Canvas* const canvas, void* ctx) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
ClockState* state = (ClockState*)acquire_mutex((ValueMutex*)ctx, 25);
|
||||
char strings[3][20];
|
||||
int curMin = (timerSecs/60);
|
||||
int curSec = timerSecs-(curMin *60);
|
||||
sprintf(strings[0], "%.4d-%.2d-%.2d", state->datetime.year, state->datetime.month, state->datetime.day);
|
||||
sprintf(strings[1], "%.2d:%.2d:%.2d", state->datetime.hour, state->datetime.minute, state->datetime.second);
|
||||
sprintf(strings[2], "%.2d:%.2d", curMin , curSec);
|
||||
release_mutex((ValueMutex*)ctx, state);
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, strings[1]);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignTop, strings[0]);
|
||||
// elements_button_left(canvas, "Alarms");
|
||||
// elements_button_right(canvas, "Settings");
|
||||
// elements_button_center(canvas, "Reset");
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignTop, strings[2]);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(timerStarted) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
} else {
|
||||
elements_button_center(canvas, "Start");
|
||||
}
|
||||
if(songSelect==0) {
|
||||
elements_button_right(canvas, "S:OFF");
|
||||
} else if(songSelect==1) {
|
||||
elements_button_right(canvas, "S:PoRa");
|
||||
} else if(songSelect==2) {
|
||||
elements_button_right(canvas, "S:Mario");
|
||||
}
|
||||
}
|
||||
|
||||
static void clock_state_init(ClockState* const state) {
|
||||
furi_hal_rtc_get_datetime(&state->datetime);
|
||||
}
|
||||
|
||||
const NotificationSequence clock_alert_silent = {
|
||||
&message_force_vibro_setting_on, &message_vibro_on, &message_red_255, &message_green_255, &message_blue_255, &message_display_backlight_on,
|
||||
&message_vibro_off, &message_display_backlight_off, &message_delay_50, &message_display_backlight_on, NULL,
|
||||
};
|
||||
const NotificationSequence clock_alert_pr1 = {
|
||||
&message_force_speaker_volume_setting_1f,
|
||||
&message_force_vibro_setting_on, &message_vibro_on, &message_red_255, &message_green_255, &message_blue_255, &message_display_backlight_on,
|
||||
&message_note_g5, &message_delay_100, &message_delay_100, &message_delay_50, &message_sound_off,
|
||||
&message_vibro_off, &message_display_backlight_off, &message_delay_50, &message_display_backlight_on,
|
||||
&message_note_g5, &message_delay_100, &message_delay_100, &message_delay_50, &message_sound_off, NULL,
|
||||
};
|
||||
const NotificationSequence clock_alert_pr2 = {
|
||||
&message_force_speaker_volume_setting_1f,
|
||||
&message_force_vibro_setting_on, &message_vibro_on,
|
||||
&message_note_fs5, &message_delay_100, &message_delay_100, &message_sound_off,
|
||||
&message_display_backlight_off, &message_vibro_off, &message_delay_50,
|
||||
&message_note_g5, &message_delay_100, &message_delay_100, &message_sound_off,
|
||||
&message_display_backlight_on, &message_delay_50,
|
||||
&message_note_a5, &message_delay_100, &message_delay_100, &message_sound_off, NULL,
|
||||
};
|
||||
const NotificationSequence clock_alert_pr3 = {
|
||||
&message_force_speaker_volume_setting_1f,
|
||||
&message_display_backlight_off,
|
||||
&message_note_g5, &message_delay_100, &message_delay_100, &message_sound_off,
|
||||
&message_delay_50, &message_red_255, &message_green_255, &message_blue_255, &message_display_backlight_on, &message_delay_100, NULL,
|
||||
};
|
||||
const NotificationSequence clock_alert_mario1 = {
|
||||
&message_force_speaker_volume_setting_1f,
|
||||
&message_force_vibro_setting_on, &message_vibro_on, &message_red_255, &message_green_255, &message_blue_255, &message_display_backlight_on,
|
||||
&message_note_e5, &message_delay_100, &message_delay_100, &message_delay_50, &message_sound_off,
|
||||
&message_note_e5, &message_delay_100, &message_delay_100, &message_delay_50, &message_sound_off,
|
||||
&message_vibro_off, &message_display_backlight_off, &message_delay_100, &message_display_backlight_on, &message_delay_100,
|
||||
&message_note_e5, &message_delay_100, &message_delay_100, &message_delay_50, &message_sound_off, NULL,
|
||||
};
|
||||
const NotificationSequence clock_alert_mario2 = {
|
||||
&message_force_speaker_volume_setting_1f,
|
||||
&message_force_vibro_setting_on, &message_vibro_on, &message_display_backlight_off, &message_delay_100, &message_display_backlight_on, &message_delay_100,
|
||||
&message_note_c5, &message_delay_100, &message_delay_100, &message_sound_off,
|
||||
&message_display_backlight_off, &message_vibro_off, &message_delay_50,
|
||||
&message_note_e5, &message_delay_100, &message_delay_100, &message_sound_off,
|
||||
&message_display_backlight_on, NULL,
|
||||
};
|
||||
const NotificationSequence clock_alert_mario3 = {
|
||||
&message_force_speaker_volume_setting_1f,
|
||||
&message_display_backlight_off,
|
||||
&message_note_g5, &message_delay_100, &message_delay_100, &message_delay_100, &message_delay_100, &message_sound_off,
|
||||
&message_delay_50, &message_red_255, &message_green_255, &message_blue_255, &message_display_backlight_on, &message_delay_100,
|
||||
&message_note_g4, &message_delay_100, &message_delay_100, &message_delay_100, &message_delay_100, &message_sound_off,
|
||||
NULL,
|
||||
};
|
||||
const NotificationSequence clock_alert_perMin = {
|
||||
&message_force_speaker_volume_setting_1f,
|
||||
&message_note_g5, &message_delay_100, &message_delay_50, &message_sound_off,
|
||||
&message_delay_10,
|
||||
&message_note_g4, &message_delay_50, &message_delay_10, &message_delay_10, &message_sound_off,
|
||||
NULL,
|
||||
};
|
||||
const NotificationSequence clock_alert_startStop = {
|
||||
&message_force_speaker_volume_setting_1f,
|
||||
&message_note_d6, &message_delay_100, &message_delay_10, &message_delay_10, &message_sound_off, NULL,
|
||||
};
|
||||
|
||||
// Runs every 1000ms by default
|
||||
static void clock_tick(void* ctx) {
|
||||
furi_assert(ctx);
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
PluginEvent event = {.type = EventTypeTick};
|
||||
if(timerStarted) {
|
||||
timerSecs=timerSecs+1;
|
||||
if(timerSecs%60==0) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &clock_alert_perMin);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
if(songSelect==1 ) {
|
||||
if(timerSecs==80) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &clock_alert_pr1);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
if(timerSecs==81) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &clock_alert_pr2);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
if(timerSecs==82) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &clock_alert_pr3);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
} else if(songSelect==2 ) {
|
||||
if(timerSecs==80) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &clock_alert_mario1);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
if(timerSecs==81) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &clock_alert_mario2);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
if(timerSecs==82) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &clock_alert_mario3);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
} else {
|
||||
if(timerSecs==80) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &clock_alert_silent);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
}
|
||||
}
|
||||
// It's OK to loose this event if system overloaded
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
}
|
||||
|
||||
int32_t clock_app(void* p) {
|
||||
UNUSED(p);
|
||||
timerStarted=false;
|
||||
timerSecs=0;
|
||||
songSelect=0;
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(PluginEvent), NULL);
|
||||
ClockState* plugin_state = malloc(sizeof(ClockState));
|
||||
clock_state_init(plugin_state);
|
||||
ValueMutex state_mutex;
|
||||
if (!init_mutex(&state_mutex, plugin_state, sizeof(ClockState))) {
|
||||
FURI_LOG_E(TAG, "cannot create mutex\r\n");
|
||||
free(plugin_state);
|
||||
return 255;
|
||||
}
|
||||
// Set system callbacks
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, clock_render_callback, &state_mutex);
|
||||
view_port_input_callback_set(view_port, clock_input_callback, event_queue);
|
||||
osTimerId_t timer = osTimerNew(clock_tick, osTimerPeriodic, event_queue, NULL);
|
||||
osTimerStart(timer, osKernelGetTickFreq());
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
// Main loop
|
||||
PluginEvent event;
|
||||
for (bool processing = true; processing;) {
|
||||
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100);
|
||||
ClockState* plugin_state = (ClockState*)acquire_mutex_block(&state_mutex);
|
||||
if (event_status == osOK) {
|
||||
// press events
|
||||
if (event.type == EventTypeKey) {
|
||||
if (event.input.type == InputTypeShort || event.input.type == InputTypeRepeat) {
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
if(timerStarted) timerSecs=timerSecs+5;
|
||||
break;
|
||||
case InputKeyDown:
|
||||
if(timerStarted) timerSecs=timerSecs-5;
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(songSelect==0) {
|
||||
songSelect=1;
|
||||
} else if(songSelect==1) {
|
||||
songSelect=2;
|
||||
} else {
|
||||
songSelect=0;
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
break;
|
||||
case InputKeyOk:
|
||||
if(songSelect==1 || songSelect==2) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &clock_alert_startStop);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
if(timerStarted) {
|
||||
timerStarted=false;
|
||||
timerSecs=0;
|
||||
} else {
|
||||
timerStarted=true;
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
// Exit the plugin
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if(event.type == EventTypeTick) {
|
||||
furi_hal_rtc_get_datetime(&plugin_state->datetime);
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "osMessageQueue: event timeout");
|
||||
// event timeout
|
||||
}
|
||||
view_port_update(view_port);
|
||||
release_mutex(&state_mutex, plugin_state);
|
||||
}
|
||||
osTimerDelete(timer);
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
furi_record_close("gui");
|
||||
view_port_free(view_port);
|
||||
osMessageQueueDelete(event_queue);
|
||||
return 0;
|
||||
}
|
54
applications/flappy_bird/bird.h
Normal file
@ -0,0 +1,54 @@
|
||||
#include <furi.h>
|
||||
|
||||
uint8_t bird_array[3][15][11] = {
|
||||
{
|
||||
{0,0,0,0,0,0,1,1,0,0,0},
|
||||
{0,0,0,0,0,1,0,0,1,0,0},
|
||||
{0,0,0,0,0,1,0,0,0,1,0},
|
||||
{0,0,1,1,1,1,0,0,0,1,0},
|
||||
{0,1,0,0,0,1,0,0,0,1,0},
|
||||
{0,1,0,0,0,0,1,0,1,0,1},
|
||||
{1,0,0,0,0,0,0,1,0,0,1},
|
||||
{1,0,1,1,1,0,0,1,0,0,1},
|
||||
{1,1,0,0,0,0,1,0,1,0,1},
|
||||
{1,0,0,0,0,1,0,1,0,1,0},
|
||||
{1,0,0,0,0,1,0,1,0,1,0},
|
||||
{0,1,0,1,1,1,0,1,0,1,0},
|
||||
{0,0,1,0,0,1,0,1,0,1,0},
|
||||
{0,0,0,1,1,1,0,1,0,1,0},
|
||||
{0,0,0,0,0,0,1,1,1,0,0},
|
||||
}, {
|
||||
{0,0,0,0,0,1,1,0,0,0,0},
|
||||
{0,0,0,0,1,0,0,1,0,0,0},
|
||||
{0,0,0,0,1,0,0,0,1,0,0},
|
||||
{0,0,1,1,1,0,0,0,1,0,0},
|
||||
{0,1,0,0,1,0,0,0,1,1,0},
|
||||
{0,1,0,0,0,1,0,1,0,0,1},
|
||||
{1,0,0,0,0,0,1,0,0,0,1},
|
||||
{1,0,1,1,1,0,0,1,0,0,1},
|
||||
{1,1,0,0,0,0,1,0,1,0,1},
|
||||
{1,0,0,0,0,1,0,1,0,1,0},
|
||||
{1,0,0,0,0,1,0,1,0,1,0},
|
||||
{0,1,0,1,1,1,0,1,0,1,0},
|
||||
{0,0,1,0,0,1,0,1,0,1,0},
|
||||
{0,0,0,1,1,1,0,1,0,1,0},
|
||||
{0,0,0,0,0,0,1,1,1,0,0},
|
||||
}, {
|
||||
{0,0,0,0,1,1,0,0,0,0,0},
|
||||
{0,0,0,1,0,0,1,0,0,0,0},
|
||||
{0,0,0,1,0,0,0,1,1,0,0},
|
||||
{0,0,1,1,0,0,0,1,0,1,0},
|
||||
{0,1,0,1,0,0,0,1,0,1,0},
|
||||
{0,1,0,0,1,0,1,0,0,0,1},
|
||||
{1,0,0,0,0,1,0,0,0,0,1},
|
||||
{1,0,1,1,1,0,0,1,0,0,1},
|
||||
{1,1,0,0,0,0,1,0,1,0,1},
|
||||
{1,0,0,0,0,1,0,1,0,1,0},
|
||||
{1,0,0,0,0,1,0,1,0,1,0},
|
||||
{0,1,0,1,1,1,0,1,0,1,0},
|
||||
{0,0,1,0,0,1,0,1,0,1,0},
|
||||
{0,0,0,1,1,1,0,1,0,1,0},
|
||||
{0,0,0,0,0,0,1,1,1,0,0},
|
||||
}
|
||||
};
|
||||
|
256
applications/flappy_bird/flappy_bird.c
Normal file
@ -0,0 +1,256 @@
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bird.h"
|
||||
|
||||
#define TAG "Flappy"
|
||||
|
||||
#define FLAPPY_BIRD_HEIGHT 15
|
||||
#define FLAPPY_BIRD_WIDTH 10
|
||||
|
||||
#define FLAPPY_PILAR_MAX 6
|
||||
#define FLAPPY_PILAR_DIST 45
|
||||
|
||||
#define FLAPPY_GAB_HEIGHT 25
|
||||
#define FLAPPY_GAB_WIDTH 5
|
||||
|
||||
#define FLAPPY_GRAVITY_JUMP -1.1
|
||||
#define FLAPPY_GRAVITY_TICK 0.10
|
||||
|
||||
#define FLIPPER_LCD_WIDTH 128
|
||||
#define FLIPPER_LCD_HEIGHT 64
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} POINT;
|
||||
|
||||
typedef struct {
|
||||
float gravity;
|
||||
POINT point;
|
||||
}BIRD;
|
||||
|
||||
typedef struct {
|
||||
POINT point;
|
||||
int height;
|
||||
int visible;
|
||||
int passed;
|
||||
} PILAR;
|
||||
|
||||
typedef struct {
|
||||
BIRD bird;
|
||||
|
||||
int points;
|
||||
int pilars_count;
|
||||
PILAR pilars[FLAPPY_PILAR_MAX];
|
||||
} GameState;
|
||||
|
||||
typedef struct {
|
||||
EventType type;
|
||||
InputEvent input;
|
||||
} GameEvent;
|
||||
|
||||
typedef enum {
|
||||
DirectionUp,
|
||||
DirectionRight,
|
||||
DirectionDown,
|
||||
DirectionLeft,
|
||||
} Direction;
|
||||
|
||||
static void flappy_game_random_pilar(GameState* const game_state) {
|
||||
PILAR pilar;
|
||||
|
||||
pilar.visible = 1;
|
||||
pilar.height = random() % (FLIPPER_LCD_HEIGHT - FLAPPY_GAB_HEIGHT) + 1;
|
||||
pilar.point.y = 0;
|
||||
pilar.point.x = FLIPPER_LCD_WIDTH + FLAPPY_GAB_WIDTH + 1;
|
||||
|
||||
game_state->pilars_count++;
|
||||
game_state->pilars[game_state->pilars_count % FLAPPY_PILAR_MAX] = pilar;
|
||||
}
|
||||
|
||||
static void flappy_game_tick(GameState* const game_state) {
|
||||
game_state->bird.gravity += FLAPPY_GRAVITY_TICK;
|
||||
game_state->bird.point.y += game_state->bird.gravity;
|
||||
|
||||
// Checking the location of the last respawned pilar.
|
||||
PILAR * pilar = &game_state->pilars[game_state->pilars_count % FLAPPY_PILAR_MAX];
|
||||
if (pilar->point.x == (FLIPPER_LCD_WIDTH - FLAPPY_PILAR_DIST))
|
||||
flappy_game_random_pilar(game_state);
|
||||
|
||||
// Updating the position/status of the pilars (visiblity, posotion, game points)
|
||||
for (int i = 0; i < FLAPPY_PILAR_MAX; i++) {
|
||||
PILAR * pilar = &game_state->pilars[i];
|
||||
pilar->point.x--;
|
||||
|
||||
if (pilar != NULL && pilar->visible && pilar->point.x > 0) {
|
||||
if (game_state->bird.point.x >= pilar->point.x + FLAPPY_GAB_WIDTH &&
|
||||
pilar->passed == 0) {
|
||||
pilar->passed = 1;
|
||||
game_state->points++;
|
||||
}
|
||||
if (pilar->point.x < -FLAPPY_PILAR_DIST)
|
||||
pilar->visible = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void flappy_game_flap(GameState* const game_state) {
|
||||
game_state->bird.gravity = FLAPPY_GRAVITY_JUMP;
|
||||
}
|
||||
|
||||
static void flappy_game_state_init(GameState* const game_state) {
|
||||
BIRD bird;
|
||||
bird.gravity = 0.0f;
|
||||
bird.point.x = 5;
|
||||
bird.point.y = 32;
|
||||
|
||||
game_state->bird = bird;
|
||||
game_state->pilars_count = 0;
|
||||
memset(game_state->pilars, 0, sizeof(game_state->pilars));
|
||||
|
||||
flappy_game_random_pilar(game_state);
|
||||
}
|
||||
|
||||
static void flappy_game_render_callback(Canvas* const canvas, void* ctx) {
|
||||
const GameState* game_state = acquire_mutex((ValueMutex*)ctx, 25);
|
||||
if(game_state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
// Pilars
|
||||
for (int i = 0; i < FLAPPY_PILAR_MAX; i++) {
|
||||
const PILAR * pilar = &game_state->pilars[i];
|
||||
if (pilar != NULL && pilar->visible) {
|
||||
canvas_draw_dot(canvas, pilar->point.x, pilar->point.y + 10);
|
||||
canvas_draw_frame(canvas, pilar->point.x, pilar->point.y,
|
||||
FLAPPY_GAB_WIDTH, pilar->height);
|
||||
|
||||
canvas_draw_frame(canvas, pilar->point.x, pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT,
|
||||
FLAPPY_GAB_WIDTH, FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
// Flappy
|
||||
for (int h = 0; h < FLAPPY_BIRD_HEIGHT; h++) {
|
||||
for (int w = 0; w < FLAPPY_BIRD_WIDTH; w++) {
|
||||
// Switch animation
|
||||
int bird = 0;
|
||||
if (game_state->bird.gravity < -0.5)
|
||||
bird = 1;
|
||||
else
|
||||
bird = 2;
|
||||
|
||||
// Draw bird pixels
|
||||
if (bird_array[bird][h][w] == 1) {
|
||||
int x = game_state->bird.point.x + h;
|
||||
int y = game_state->bird.point.y + w;
|
||||
|
||||
canvas_draw_dot(canvas, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
release_mutex((ValueMutex*)ctx, game_state);
|
||||
}
|
||||
|
||||
|
||||
static void flappy_game_input_callback(InputEvent* input_event, osMessageQueueId_t event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
GameEvent event = {.type = EventTypeKey, .input = *input_event};
|
||||
osMessageQueuePut(event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
static void flappy_game_update_timer_callback(osMessageQueueId_t event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
GameEvent event = {.type = EventTypeTick};
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
}
|
||||
|
||||
int32_t flappy_game_app(void* p) {
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(GameEvent), NULL);
|
||||
|
||||
GameState* game_state = malloc(sizeof(GameState));
|
||||
flappy_game_state_init(game_state);
|
||||
|
||||
ValueMutex state_mutex;
|
||||
if (!init_mutex(&state_mutex, game_state, sizeof(GameState))) {
|
||||
FURI_LOG_E(TAG, "cannot create mutex\r\n");
|
||||
free(game_state);
|
||||
return 255;
|
||||
}
|
||||
|
||||
// Set system callbacks
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, flappy_game_render_callback, &state_mutex);
|
||||
view_port_input_callback_set(view_port, flappy_game_input_callback, event_queue);
|
||||
|
||||
osTimerId_t timer =
|
||||
osTimerNew(flappy_game_update_timer_callback, osTimerPeriodic, event_queue, NULL);
|
||||
osTimerStart(timer, osKernelGetTickFreq() / 22);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
GameEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100);
|
||||
GameState* game_state = (GameState*)acquire_mutex_block(&state_mutex);
|
||||
|
||||
if(event_status == osOK) {
|
||||
// press events
|
||||
if(event.type == EventTypeKey) {
|
||||
if(event.input.type == InputTypePress) {
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
game_state->bird.point.y--;
|
||||
break;
|
||||
case InputKeyDown:
|
||||
game_state->bird.point.y++;
|
||||
break;
|
||||
case InputKeyRight:
|
||||
game_state->bird.point.x++;
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
game_state->bird.point.x--;
|
||||
break;
|
||||
case InputKeyOk:
|
||||
flappy_game_flap(game_state);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if(event.type == EventTypeTick) {
|
||||
flappy_game_tick(game_state);
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "osMessageQueue: event timeout");
|
||||
// event timeout
|
||||
}
|
||||
|
||||
view_port_update(view_port);
|
||||
release_mutex(&state_mutex, game_state);
|
||||
}
|
||||
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
furi_record_close("gui");
|
||||
view_port_free(view_port);
|
||||
osMessageQueueDelete(event_queue);
|
||||
|
||||
return 0;
|
||||
}
|
303
applications/jukebox/jukebox.c
Normal file
@ -0,0 +1,303 @@
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
#include <string.h>
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/transmitter.h>
|
||||
#include <lib/subghz/subghz_file_encoder_worker.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
#define TAG "JukeBox"
|
||||
|
||||
typedef struct {
|
||||
bool press[5];
|
||||
} RemoteAppState;
|
||||
|
||||
static void jukebox_reset_state(RemoteAppState* state) {
|
||||
state->press[0] = 0;
|
||||
state->press[1] = 0;
|
||||
state->press[2] = 0;
|
||||
state->press[3] = 0;
|
||||
state->press[4] = 0;
|
||||
}
|
||||
static string_t up_file;
|
||||
static string_t down_file;
|
||||
static string_t left_file;
|
||||
static string_t right_file;
|
||||
static string_t ok_file;
|
||||
|
||||
static char* subString(char* someString, int n) {
|
||||
char* new = malloc(sizeof(char) * n + 1);
|
||||
strncpy(new, someString, n);
|
||||
new[n] = '\0';
|
||||
return new;
|
||||
}
|
||||
|
||||
static char* file_stub(const char* file_name) {
|
||||
string_t filename;
|
||||
string_init(filename);
|
||||
// string_init(file_name);
|
||||
path_extract_filename_no_ext(file_name, filename);
|
||||
|
||||
return subString((char*)string_get_cstr(filename), 8);
|
||||
}
|
||||
|
||||
static void jukebox_send_signal(uint32_t frequency, string_t signal, string_t protocol) {
|
||||
uint32_t repeat = 1;
|
||||
frequency = frequency ? frequency : 433920000;
|
||||
FURI_LOG_D(TAG, "file to send: %s", string_get_cstr(signal));
|
||||
|
||||
if(strlen(string_get_cstr(signal)) < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
string_t flipper_format_string;
|
||||
if(strcmp(string_get_cstr(protocol), "RAW") == 0) {
|
||||
string_init_printf(flipper_format_string, "File_name: %s", string_get_cstr(signal));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
FlipperFormat* flipper_format = flipper_format_string_alloc();
|
||||
Stream* stream = flipper_format_get_raw_stream(flipper_format);
|
||||
stream_clean(stream);
|
||||
stream_write_cstring(stream, string_get_cstr(flipper_format_string));
|
||||
|
||||
SubGhzEnvironment* environment = subghz_environment_alloc();
|
||||
|
||||
SubGhzTransmitter* transmitter =
|
||||
subghz_transmitter_alloc_init(environment, string_get_cstr(protocol));
|
||||
subghz_transmitter_deserialize(transmitter, flipper_format);
|
||||
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok270Async);
|
||||
furi_hal_subghz_set_frequency_and_path(frequency);
|
||||
FURI_LOG_D(
|
||||
TAG, "Transmitting at %lu, repeat %lu. Press CTRL+C to stop\r\n", frequency, repeat);
|
||||
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter);
|
||||
|
||||
while(!(furi_hal_subghz_is_async_tx_complete())) {
|
||||
FURI_LOG_D(TAG, ".");
|
||||
fflush(stdout);
|
||||
osDelay(333);
|
||||
}
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
furi_hal_subghz_sleep();
|
||||
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
|
||||
flipper_format_free(flipper_format);
|
||||
subghz_transmitter_free(transmitter);
|
||||
subghz_environment_free(environment);
|
||||
}
|
||||
|
||||
static void jukebox_render_callback(Canvas* canvas, void* ctx) {
|
||||
RemoteAppState* state = (RemoteAppState*)acquire_mutex((ValueMutex*)ctx, 25);
|
||||
canvas_clear(canvas);
|
||||
char strings[5][20];
|
||||
string_t signal;
|
||||
string_init(signal);
|
||||
sprintf(strings[0], "Ok: %s", file_stub(string_get_cstr(ok_file)));
|
||||
sprintf(strings[1], "L: %s", file_stub(string_get_cstr(left_file)));
|
||||
sprintf(strings[2], "R: %s", file_stub(string_get_cstr(right_file)));
|
||||
sprintf(strings[3], "U: %s", file_stub(string_get_cstr(up_file)));
|
||||
sprintf(strings[4], "D: %s", file_stub(string_get_cstr(down_file)));
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 0, 10, "Univeral Remote");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 0, 24, strings[1]);
|
||||
canvas_draw_str(canvas, 85, 24, strings[2]);
|
||||
canvas_draw_str(canvas, 0, 36, strings[3]);
|
||||
canvas_draw_str(canvas, 85, 36, strings[4]);
|
||||
canvas_draw_str(canvas, 0, 48, strings[0]);
|
||||
// canvas_draw_circle(canvas, 100, 26, 25);
|
||||
|
||||
if(state->press[0]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(right_file));
|
||||
}
|
||||
|
||||
else if(state->press[1]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(left_file));
|
||||
|
||||
} else if(state->press[2]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(up_file));
|
||||
|
||||
} else if(state->press[3]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(down_file));
|
||||
|
||||
}
|
||||
|
||||
else if(state->press[4]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(ok_file));
|
||||
}
|
||||
FURI_LOG_D(TAG, "signal = %s", string_get_cstr(signal));
|
||||
|
||||
if(strlen(string_get_cstr(signal)) > 12) {
|
||||
string_t file_name;
|
||||
string_init(file_name);
|
||||
string_t protocol;
|
||||
string_init(protocol);
|
||||
string_set(file_name, string_get_cstr(signal));
|
||||
Storage* storage = furi_record_open("storage");
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
uint32_t frequency_str;
|
||||
flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name));
|
||||
flipper_format_read_uint32(fff_data_file, "Frequency", (uint32_t*)&frequency_str, 1);
|
||||
if(!flipper_format_read_string(fff_data_file, "Protocol", protocol)) {
|
||||
FURI_LOG_D(TAG, "Could not read Protocol");
|
||||
string_set(protocol, "RAW");
|
||||
}
|
||||
flipper_format_free(fff_data_file);
|
||||
furi_record_close("storage");
|
||||
FURI_LOG_D(TAG, "%lu", frequency_str);
|
||||
jukebox_send_signal(frequency_str, signal, protocol);
|
||||
}
|
||||
|
||||
canvas_draw_str(canvas, 10, 63, "[back] - skip, hold to exit");
|
||||
|
||||
release_mutex((ValueMutex*)ctx, state);
|
||||
}
|
||||
|
||||
static void jukebox_input_callback(InputEvent* input_event, void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
osMessageQueuePut(event_queue, input_event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
int32_t jukebox_app(void* p) {
|
||||
UNUSED(p);
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(InputEvent), NULL);
|
||||
furi_check(event_queue);
|
||||
string_init(up_file);
|
||||
string_init(down_file);
|
||||
string_init(left_file);
|
||||
string_init(right_file);
|
||||
string_init(ok_file);
|
||||
|
||||
string_t file_name;
|
||||
string_init(file_name);
|
||||
string_set(file_name, "/ext/subghz/assets/touchtunes_map");
|
||||
Storage* storage = furi_record_open("storage");
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) {
|
||||
FURI_LOG_D(TAG, "Could not open file %s", string_get_cstr(file_name));
|
||||
}
|
||||
|
||||
if(!flipper_format_read_string(fff_data_file, "UP", up_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read UP string");
|
||||
}
|
||||
if(!flipper_format_read_string(fff_data_file, "DOWN", down_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read DOWN string");
|
||||
}
|
||||
if(!flipper_format_read_string(fff_data_file, "LEFT", left_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read LEFT string");
|
||||
}
|
||||
if(!flipper_format_read_string(fff_data_file, "RIGHT", right_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read RIGHT string");
|
||||
}
|
||||
if(!flipper_format_read_string(fff_data_file, "OK", ok_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read OK string");
|
||||
}
|
||||
flipper_format_free(fff_data_file);
|
||||
furi_record_close("storage");
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"%s %s %s %s %s ",
|
||||
string_get_cstr(up_file),
|
||||
string_get_cstr(down_file),
|
||||
string_get_cstr(left_file),
|
||||
string_get_cstr(right_file),
|
||||
string_get_cstr(ok_file));
|
||||
|
||||
RemoteAppState _state = {{false, false, false, false, false}};
|
||||
|
||||
ValueMutex state_mutex;
|
||||
if(!init_mutex(&state_mutex, &_state, sizeof(RemoteAppState))) {
|
||||
FURI_LOG_D(TAG, "cannot create mutex");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
|
||||
view_port_draw_callback_set(view_port, jukebox_render_callback, &state_mutex);
|
||||
view_port_input_callback_set(view_port, jukebox_input_callback, event_queue);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
InputEvent event;
|
||||
while(osMessageQueueGet(event_queue, &event, NULL, osWaitForever) == osOK) {
|
||||
RemoteAppState* state = (RemoteAppState*)acquire_mutex_block(&state_mutex);
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"key: %s type: %s",
|
||||
input_get_key_name(event.key),
|
||||
input_get_type_name(event.type));
|
||||
|
||||
if(event.key == InputKeyRight) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[0] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[0] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[0] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyLeft) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[1] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[1] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[1] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyUp) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[2] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[2] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[2] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyDown) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[3] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[3] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[3] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyOk) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[4] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[4] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[4] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyBack) {
|
||||
if(event.type == InputTypeLong) {
|
||||
release_mutex(&state_mutex, state);
|
||||
break;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
jukebox_reset_state(state);
|
||||
}
|
||||
}
|
||||
release_mutex(&state_mutex, state);
|
||||
view_port_update(view_port);
|
||||
}
|
||||
|
||||
// remove & free all stuff created by app
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
osMessageQueueDelete(event_queue);
|
||||
delete_mutex(&state_mutex);
|
||||
|
||||
furi_record_close("gui");
|
||||
|
||||
return 0;
|
||||
}
|
@ -46,16 +46,17 @@ const char* const volume_text[VOLUME_COUNT] = {
|
||||
};
|
||||
const float volume_value[VOLUME_COUNT] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f};
|
||||
|
||||
#define DELAY_COUNT 6
|
||||
#define DELAY_COUNT 7
|
||||
const char* const delay_text[DELAY_COUNT] = {
|
||||
"1s",
|
||||
"5s",
|
||||
"15s",
|
||||
"30s",
|
||||
"60s",
|
||||
"90s",
|
||||
"120s",
|
||||
};
|
||||
const uint32_t delay_value[DELAY_COUNT] = {1000, 5000, 15000, 30000, 60000, 120000};
|
||||
const uint32_t delay_value[DELAY_COUNT] = {1000, 5000, 15000, 30000, 60000, 90000, 120000};
|
||||
|
||||
#define VIBRO_COUNT 2
|
||||
const char* const vibro_text[VIBRO_COUNT] = {
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
typedef struct {
|
||||
// +-----x
|
||||
@ -298,6 +300,11 @@ static void snake_game_process_game_step(SnakeState* const snake_state) {
|
||||
|
||||
bool eatFruit = (next_step.x == snake_state->fruit.x) && (next_step.y == snake_state->fruit.y);
|
||||
if(eatFruit) {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &sequence_single_vibro);
|
||||
notification_message(notification, &sequence_blink_white_100);
|
||||
furi_record_close("notification");
|
||||
|
||||
snake_state->len++;
|
||||
if(snake_state->len >= MAX_SNAKE_LEN) {
|
||||
snake_state->state = GameStateGameOver;
|
||||
|
@ -20,7 +20,7 @@ typedef struct {
|
||||
uint32_t channel0_frequency;
|
||||
uint32_t spacing;
|
||||
|
||||
double max_rssi;
|
||||
float max_rssi;
|
||||
uint8_t max_rssi_dec;
|
||||
uint8_t max_rssi_channel;
|
||||
uint8_t channel_ss[NUM_CHANNELS];
|
||||
@ -135,7 +135,7 @@ static void spectrum_analyzer_render_callback(Canvas* const canvas, void* ctx) {
|
||||
temp_str,
|
||||
36,
|
||||
"Peak: %3.2f Mhz %3.1f dbm",
|
||||
((double)(model->channel0_frequency + (model->max_rssi_channel * model->spacing)) /
|
||||
((float)(model->channel0_frequency + (model->max_rssi_channel * model->spacing)) /
|
||||
1000000),
|
||||
model->max_rssi);
|
||||
canvas_draw_str_aligned(canvas, 127, 0, AlignRight, AlignTop, temp_str);
|
||||
@ -156,7 +156,7 @@ static void spectrum_analyzer_input_callback(InputEvent* input_event, void* ctx)
|
||||
|
||||
static void spectrum_analyzer_worker_callback(
|
||||
void* channel_ss,
|
||||
double max_rssi,
|
||||
float max_rssi,
|
||||
uint8_t max_rssi_dec,
|
||||
uint8_t max_rssi_channel,
|
||||
void* context) {
|
||||
|
@ -16,7 +16,7 @@ struct SpectrumAnalyzerWorker {
|
||||
uint32_t channel0_frequency;
|
||||
uint32_t spacing;
|
||||
uint8_t width;
|
||||
double max_rssi;
|
||||
float max_rssi;
|
||||
uint8_t max_rssi_dec;
|
||||
uint8_t max_rssi_channel;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
typedef void (*SpectrumAnalyzerWorkerCallback)(
|
||||
void* chan_table,
|
||||
double max_rssi,
|
||||
float max_rssi,
|
||||
uint8_t max_rssi_dec,
|
||||
uint8_t max_rssi_channel,
|
||||
void* context);
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "../subghz_i.h"
|
||||
#include "../views/subghz_read_raw.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
#define RAW_FILE_NAME "Raw_signal_"
|
||||
#define RAW_FILE_NAME "R_"
|
||||
#define TAG "SubGhzSceneReadRAW"
|
||||
|
||||
bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
|
||||
@ -237,8 +239,17 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
string_t temp_str;
|
||||
string_init(temp_str);
|
||||
|
||||
FuriHalRtcDateTime datetime;
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
char strings[1][25];
|
||||
sprintf(strings[0], "%s%.4d%.2d%.2d%.2d%.2d", "R"
|
||||
, datetime.year, datetime.month, datetime.day
|
||||
, datetime.hour, datetime.minute
|
||||
);
|
||||
|
||||
string_printf(
|
||||
temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION);
|
||||
temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, strings[0], SUBGHZ_APP_EXTENSION);
|
||||
subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, string_get_cstr(temp_str));
|
||||
string_clear(temp_str);
|
||||
|
||||
@ -259,9 +270,17 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||
} else {
|
||||
//subghz_get_preset_name(subghz, subghz->error_str);
|
||||
FuriHalRtcDateTime datetime;
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
char strings[1][25];
|
||||
sprintf(strings[0], "%s%.4d%.2d%.2d%.2d%.2d", "R"
|
||||
, datetime.year, datetime.month, datetime.day
|
||||
, datetime.hour, datetime.minute
|
||||
);
|
||||
|
||||
if(subghz_protocol_raw_save_to_file_init(
|
||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result,
|
||||
RAW_FILE_NAME,
|
||||
strings[0],
|
||||
subghz->txrx->frequency,
|
||||
subghz->txrx->preset)) {
|
||||
DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
|
||||
|
@ -19,25 +19,36 @@ typedef enum {
|
||||
static const uint32_t subghz_frequencies[] = {
|
||||
/* 300 - 348 */
|
||||
300000000,
|
||||
302757000, /* FCC ID N6U303NTX */
|
||||
303875000,
|
||||
304250000,
|
||||
304250000, /* Ceiling Fan - Harbor Breeze*/
|
||||
310000000,
|
||||
313850000, /* 2007 Honda Key */
|
||||
315000000,
|
||||
318000000,
|
||||
348000000,
|
||||
387000000,
|
||||
|
||||
/* 387 - 464 */
|
||||
390000000,
|
||||
418000000,
|
||||
433075000, /* LPD433 first */
|
||||
433220000, /* 2016-2020 Honda */
|
||||
433420000,
|
||||
433889000, /* ROGUE? */
|
||||
|
||||
433920000, /* LPD433 mid */
|
||||
434420000,
|
||||
434775000, /* LPD433 last channels */
|
||||
438900000,
|
||||
464000000,
|
||||
|
||||
/* 779 - 928 */
|
||||
779000000,
|
||||
868350000,
|
||||
915000000,
|
||||
925000000,
|
||||
928000000,
|
||||
0,
|
||||
};
|
||||
static const uint32_t subghz_hopper_frequencies[] = {
|
||||
|
@ -269,7 +269,7 @@ static void tetris_game_update_timer_callback(osMessageQueueId_t event_queue) {
|
||||
|
||||
|
||||
int32_t tetris_game_app(void* p) {
|
||||
UNUSED(p);
|
||||
(void)p;
|
||||
srand(DWT->CYCCNT);
|
||||
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(TetrisEvent), NULL);
|
||||
@ -402,4 +402,4 @@ int32_t tetris_game_app(void* p) {
|
||||
free(tetris_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
303
applications/universal_rf/universal_rf.c
Normal file
@ -0,0 +1,303 @@
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
#include <string.h>
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/transmitter.h>
|
||||
#include <lib/subghz/subghz_file_encoder_worker.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
#define TAG "UniveralRFRemote"
|
||||
|
||||
typedef struct {
|
||||
bool press[5];
|
||||
} RemoteAppState;
|
||||
|
||||
static void remote_reset_state(RemoteAppState* state) {
|
||||
state->press[0] = 0;
|
||||
state->press[1] = 0;
|
||||
state->press[2] = 0;
|
||||
state->press[3] = 0;
|
||||
state->press[4] = 0;
|
||||
}
|
||||
static string_t up_file;
|
||||
static string_t down_file;
|
||||
static string_t left_file;
|
||||
static string_t right_file;
|
||||
static string_t ok_file;
|
||||
|
||||
static char* subString(char* someString, int n) {
|
||||
char* new = malloc(sizeof(char) * n + 1);
|
||||
strncpy(new, someString, n);
|
||||
new[n] = '\0';
|
||||
return new;
|
||||
}
|
||||
|
||||
static char* file_stub(const char* file_name) {
|
||||
string_t filename;
|
||||
string_init(filename);
|
||||
// string_init(file_name);
|
||||
path_extract_filename_no_ext(file_name, filename);
|
||||
|
||||
return subString((char*)string_get_cstr(filename), 8);
|
||||
}
|
||||
|
||||
static void remote_send_signal(uint32_t frequency, string_t signal, string_t protocol) {
|
||||
uint32_t repeat = 1;
|
||||
frequency = frequency ? frequency : 433920000;
|
||||
FURI_LOG_D(TAG, "file to send: %s", string_get_cstr(signal));
|
||||
|
||||
if(strlen(string_get_cstr(signal)) < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
string_t flipper_format_string;
|
||||
if(strcmp(string_get_cstr(protocol), "RAW") == 0) {
|
||||
string_init_printf(flipper_format_string, "File_name: %s", string_get_cstr(signal));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
FlipperFormat* flipper_format = flipper_format_string_alloc();
|
||||
Stream* stream = flipper_format_get_raw_stream(flipper_format);
|
||||
stream_clean(stream);
|
||||
stream_write_cstring(stream, string_get_cstr(flipper_format_string));
|
||||
|
||||
SubGhzEnvironment* environment = subghz_environment_alloc();
|
||||
|
||||
SubGhzTransmitter* transmitter =
|
||||
subghz_transmitter_alloc_init(environment, string_get_cstr(protocol));
|
||||
subghz_transmitter_deserialize(transmitter, flipper_format);
|
||||
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok270Async);
|
||||
furi_hal_subghz_set_frequency_and_path(frequency);
|
||||
FURI_LOG_D(
|
||||
TAG, "Transmitting at %lu, repeat %lu. Press CTRL+C to stop\r\n", frequency, repeat);
|
||||
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter);
|
||||
|
||||
while(!(furi_hal_subghz_is_async_tx_complete())) {
|
||||
FURI_LOG_D(TAG, ".");
|
||||
fflush(stdout);
|
||||
osDelay(333);
|
||||
}
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
furi_hal_subghz_sleep();
|
||||
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
|
||||
flipper_format_free(flipper_format);
|
||||
subghz_transmitter_free(transmitter);
|
||||
subghz_environment_free(environment);
|
||||
}
|
||||
|
||||
static void remote_render_callback(Canvas* canvas, void* ctx) {
|
||||
RemoteAppState* state = (RemoteAppState*)acquire_mutex((ValueMutex*)ctx, 25);
|
||||
canvas_clear(canvas);
|
||||
char strings[5][20];
|
||||
string_t signal;
|
||||
string_init(signal);
|
||||
sprintf(strings[0], "Ok: %s", file_stub(string_get_cstr(ok_file)));
|
||||
sprintf(strings[1], "L: %s", file_stub(string_get_cstr(left_file)));
|
||||
sprintf(strings[2], "R: %s", file_stub(string_get_cstr(right_file)));
|
||||
sprintf(strings[3], "U: %s", file_stub(string_get_cstr(up_file)));
|
||||
sprintf(strings[4], "D: %s", file_stub(string_get_cstr(down_file)));
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 0, 10, "Univeral Remote");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 0, 24, strings[1]);
|
||||
canvas_draw_str(canvas, 85, 24, strings[2]);
|
||||
canvas_draw_str(canvas, 0, 36, strings[3]);
|
||||
canvas_draw_str(canvas, 85, 36, strings[4]);
|
||||
canvas_draw_str(canvas, 0, 48, strings[0]);
|
||||
// canvas_draw_circle(canvas, 100, 26, 25);
|
||||
|
||||
if(state->press[0]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(right_file));
|
||||
}
|
||||
|
||||
else if(state->press[1]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(left_file));
|
||||
|
||||
} else if(state->press[2]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(up_file));
|
||||
|
||||
} else if(state->press[3]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(down_file));
|
||||
|
||||
}
|
||||
|
||||
else if(state->press[4]) {
|
||||
string_cat_printf(signal, "%s", string_get_cstr(ok_file));
|
||||
}
|
||||
FURI_LOG_D(TAG, "signal = %s", string_get_cstr(signal));
|
||||
|
||||
if(strlen(string_get_cstr(signal)) > 12) {
|
||||
string_t file_name;
|
||||
string_init(file_name);
|
||||
string_t protocol;
|
||||
string_init(protocol);
|
||||
string_set(file_name, string_get_cstr(signal));
|
||||
Storage* storage = furi_record_open("storage");
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
uint32_t frequency_str;
|
||||
flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name));
|
||||
flipper_format_read_uint32(fff_data_file, "Frequency", (uint32_t*)&frequency_str, 1);
|
||||
if(!flipper_format_read_string(fff_data_file, "Protocol", protocol)) {
|
||||
FURI_LOG_D(TAG, "Could not read Protocol");
|
||||
string_set(protocol, "RAW");
|
||||
}
|
||||
flipper_format_free(fff_data_file);
|
||||
furi_record_close("storage");
|
||||
FURI_LOG_D(TAG, "%lu", frequency_str);
|
||||
remote_send_signal(frequency_str, signal, protocol);
|
||||
}
|
||||
|
||||
canvas_draw_str(canvas, 10, 63, "[back] - skip, hold to exit");
|
||||
|
||||
release_mutex((ValueMutex*)ctx, state);
|
||||
}
|
||||
|
||||
static void remote_input_callback(InputEvent* input_event, void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
osMessageQueuePut(event_queue, input_event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
int32_t universal_rf_remote_app(void* p) {
|
||||
UNUSED(p);
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(InputEvent), NULL);
|
||||
furi_check(event_queue);
|
||||
string_init(up_file);
|
||||
string_init(down_file);
|
||||
string_init(left_file);
|
||||
string_init(right_file);
|
||||
string_init(ok_file);
|
||||
|
||||
string_t file_name;
|
||||
string_init(file_name);
|
||||
string_set(file_name, "/ext/subghz/assets/universal_rf_map");
|
||||
Storage* storage = furi_record_open("storage");
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) {
|
||||
FURI_LOG_D(TAG, "Could not open file %s", string_get_cstr(file_name));
|
||||
}
|
||||
|
||||
if(!flipper_format_read_string(fff_data_file, "UP", up_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read UP string");
|
||||
}
|
||||
if(!flipper_format_read_string(fff_data_file, "DOWN", down_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read DOWN string");
|
||||
}
|
||||
if(!flipper_format_read_string(fff_data_file, "LEFT", left_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read LEFT string");
|
||||
}
|
||||
if(!flipper_format_read_string(fff_data_file, "RIGHT", right_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read RIGHT string");
|
||||
}
|
||||
if(!flipper_format_read_string(fff_data_file, "OK", ok_file)) {
|
||||
FURI_LOG_D(TAG, "Could not read OK string");
|
||||
}
|
||||
flipper_format_free(fff_data_file);
|
||||
furi_record_close("storage");
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"%s %s %s %s %s ",
|
||||
string_get_cstr(up_file),
|
||||
string_get_cstr(down_file),
|
||||
string_get_cstr(left_file),
|
||||
string_get_cstr(right_file),
|
||||
string_get_cstr(ok_file));
|
||||
|
||||
RemoteAppState _state = {{false, false, false, false, false}};
|
||||
|
||||
ValueMutex state_mutex;
|
||||
if(!init_mutex(&state_mutex, &_state, sizeof(RemoteAppState))) {
|
||||
FURI_LOG_D(TAG, "cannot create mutex");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
|
||||
view_port_draw_callback_set(view_port, remote_render_callback, &state_mutex);
|
||||
view_port_input_callback_set(view_port, remote_input_callback, event_queue);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
InputEvent event;
|
||||
while(osMessageQueueGet(event_queue, &event, NULL, osWaitForever) == osOK) {
|
||||
RemoteAppState* state = (RemoteAppState*)acquire_mutex_block(&state_mutex);
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"key: %s type: %s",
|
||||
input_get_key_name(event.key),
|
||||
input_get_type_name(event.type));
|
||||
|
||||
if(event.key == InputKeyRight) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[0] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[0] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[0] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyLeft) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[1] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[1] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[1] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyUp) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[2] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[2] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[2] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyDown) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[3] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[3] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[3] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyOk) {
|
||||
if(event.type == InputTypePress) {
|
||||
state->press[4] = true;
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
state->press[4] = false;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
state->press[4] = false;
|
||||
}
|
||||
} else if(event.key == InputKeyBack) {
|
||||
if(event.type == InputTypeLong) {
|
||||
release_mutex(&state_mutex, state);
|
||||
break;
|
||||
} else if(event.type == InputTypeShort) {
|
||||
remote_reset_state(state);
|
||||
}
|
||||
}
|
||||
release_mutex(&state_mutex, state);
|
||||
view_port_update(view_port);
|
||||
}
|
||||
|
||||
// remove & free all stuff created by app
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
osMessageQueueDelete(event_queue);
|
||||
delete_mutex(&state_mutex);
|
||||
|
||||
furi_record_close("gui");
|
||||
|
||||
return 0;
|
||||
}
|
84
applications/wav_player/wav_parser.c
Normal file
@ -0,0 +1,84 @@
|
||||
#include "wav_parser.h"
|
||||
|
||||
#define TAG "WavParser"
|
||||
|
||||
const char* format_text(FormatTag tag) {
|
||||
switch(tag) {
|
||||
case FormatTagPCM:
|
||||
return "PCM";
|
||||
case FormatTagIEEE_FLOAT:
|
||||
return "IEEE FLOAT";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
struct WavParser {
|
||||
WavHeaderChunk header;
|
||||
WavFormatChunk format;
|
||||
WavDataChunk data;
|
||||
size_t wav_data_start;
|
||||
size_t wav_data_end;
|
||||
};
|
||||
|
||||
WavParser* wav_parser_alloc() {
|
||||
return malloc(sizeof(WavParser));
|
||||
}
|
||||
|
||||
void wav_parser_free(WavParser* parser) {
|
||||
free(parser);
|
||||
}
|
||||
|
||||
bool wav_parser_parse(WavParser* parser, Stream* stream) {
|
||||
stream_read(stream, (uint8_t*)&parser->header, sizeof(WavHeaderChunk));
|
||||
stream_read(stream, (uint8_t*)&parser->format, sizeof(WavFormatChunk));
|
||||
stream_read(stream, (uint8_t*)&parser->data, sizeof(WavDataChunk));
|
||||
|
||||
if(memcmp(parser->header.riff, "RIFF", 4) != 0 ||
|
||||
memcmp(parser->header.wave, "WAVE", 4) != 0) {
|
||||
FURI_LOG_E(TAG, "WAV: wrong header");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(memcmp(parser->format.fmt, "fmt ", 4) != 0) {
|
||||
FURI_LOG_E(TAG, "WAV: wrong format");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(parser->format.tag != FormatTagPCM || memcmp(parser->data.data, "data", 4) != 0) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"WAV: non-PCM format %u, next '%lu'",
|
||||
parser->format.tag,
|
||||
(uint32_t)parser->data.data);
|
||||
return false;
|
||||
}
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"Format tag: %s, ch: %u, smplrate: %lu, bps: %lu, bits: %u",
|
||||
format_text(parser->format.tag),
|
||||
parser->format.channels,
|
||||
parser->format.sample_rate,
|
||||
parser->format.byte_per_sec,
|
||||
parser->format.bits_per_sample);
|
||||
|
||||
parser->wav_data_start = stream_tell(stream);
|
||||
parser->wav_data_end = parser->wav_data_start + parser->data.size;
|
||||
|
||||
FURI_LOG_I(TAG, "data: %u - %u", parser->wav_data_start, parser->wav_data_end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t wav_parser_get_data_start(WavParser* parser) {
|
||||
return parser->wav_data_start;
|
||||
}
|
||||
|
||||
size_t wav_parser_get_data_end(WavParser* parser) {
|
||||
return parser->wav_data_end;
|
||||
}
|
||||
|
||||
size_t wav_parser_get_data_len(WavParser* parser) {
|
||||
return parser->wav_data_end - parser->wav_data_start;
|
||||
}
|
51
applications/wav_player/wav_parser.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include <toolbox/stream/stream.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
FormatTagPCM = 0x0001,
|
||||
FormatTagIEEE_FLOAT = 0x0003,
|
||||
} FormatTag;
|
||||
|
||||
typedef struct {
|
||||
uint8_t riff[4];
|
||||
uint32_t size;
|
||||
uint8_t wave[4];
|
||||
} WavHeaderChunk;
|
||||
|
||||
typedef struct {
|
||||
uint8_t fmt[4];
|
||||
uint32_t size;
|
||||
uint16_t tag;
|
||||
uint16_t channels;
|
||||
uint32_t sample_rate;
|
||||
uint32_t byte_per_sec;
|
||||
uint16_t block_align;
|
||||
uint16_t bits_per_sample;
|
||||
} WavFormatChunk;
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[4];
|
||||
uint32_t size;
|
||||
} WavDataChunk;
|
||||
|
||||
typedef struct WavParser WavParser;
|
||||
|
||||
WavParser* wav_parser_alloc();
|
||||
|
||||
void wav_parser_free(WavParser* parser);
|
||||
|
||||
bool wav_parser_parse(WavParser* parser, Stream* stream);
|
||||
|
||||
size_t wav_parser_get_data_start(WavParser* parser);
|
||||
|
||||
size_t wav_parser_get_data_end(WavParser* parser);
|
||||
|
||||
size_t wav_parser_get_data_len(WavParser* parser);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
303
applications/wav_player/wav_player.c
Normal file
@ -0,0 +1,303 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <cli/cli.h>
|
||||
#include <gui/gui.h>
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include "wav_player_hal.h"
|
||||
#include "wav_parser.h"
|
||||
#include "wav_player_view.h"
|
||||
|
||||
#define TAG "WavPlayer"
|
||||
|
||||
static bool open_wav_stream(Storage* storage, Stream* stream) {
|
||||
DialogsApp* dialogs = furi_record_open("dialogs");
|
||||
bool result = false;
|
||||
size_t name_size = 255;
|
||||
char* name_buffer = malloc(name_size);
|
||||
string_t path;
|
||||
string_init(path);
|
||||
|
||||
bool ret =
|
||||
dialog_file_select_show(dialogs, "/ext/wav_player", ".wav", name_buffer, name_size, NULL);
|
||||
furi_record_close("dialogs");
|
||||
|
||||
if(ret) {
|
||||
string_printf(path, "%s/%s.%s", "/ext/wav_player", name_buffer, "wav");
|
||||
if(!file_stream_open(stream, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
FURI_LOG_E(TAG, "Cannot open file \"%s\"", string_get_cstr(path));
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(path);
|
||||
free(name_buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
WavPlayerEventHalfTransfer,
|
||||
WavPlayerEventFullTransfer,
|
||||
WavPlayerEventCtrlVolUp,
|
||||
WavPlayerEventCtrlVolDn,
|
||||
WavPlayerEventCtrlMoveL,
|
||||
WavPlayerEventCtrlMoveR,
|
||||
WavPlayerEventCtrlOk,
|
||||
WavPlayerEventCtrlBack,
|
||||
} WavPlayerEventType;
|
||||
|
||||
typedef struct {
|
||||
WavPlayerEventType type;
|
||||
} WavPlayerEvent;
|
||||
|
||||
static void wav_player_dma_isr(void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
|
||||
// half of transfer
|
||||
if(LL_DMA_IsActiveFlag_HT1(DMA1)) {
|
||||
LL_DMA_ClearFlag_HT1(DMA1);
|
||||
// fill first half of buffer
|
||||
WavPlayerEvent event = {.type = WavPlayerEventHalfTransfer};
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
}
|
||||
|
||||
// transfer complete
|
||||
if(LL_DMA_IsActiveFlag_TC1(DMA1)) {
|
||||
LL_DMA_ClearFlag_TC1(DMA1);
|
||||
// fill second half of buffer
|
||||
WavPlayerEvent event = {.type = WavPlayerEventFullTransfer};
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Storage* storage;
|
||||
Stream* stream;
|
||||
WavParser* parser;
|
||||
uint16_t* sample_buffer;
|
||||
uint8_t* tmp_buffer;
|
||||
|
||||
size_t samples_count_half;
|
||||
size_t samples_count;
|
||||
|
||||
osMessageQueueId_t queue;
|
||||
|
||||
float volume;
|
||||
bool play;
|
||||
|
||||
WavPlayerView* view;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Gui* gui;
|
||||
NotificationApp* notification;
|
||||
} WavPlayerApp;
|
||||
|
||||
static WavPlayerApp* app_alloc() {
|
||||
WavPlayerApp* app = malloc(sizeof(WavPlayerApp));
|
||||
app->samples_count_half = 1024 * 4;
|
||||
app->samples_count = app->samples_count_half * 2;
|
||||
app->storage = furi_record_open("storage");
|
||||
app->stream = file_stream_alloc(app->storage);
|
||||
app->parser = wav_parser_alloc();
|
||||
app->sample_buffer = malloc(sizeof(uint16_t) * app->samples_count);
|
||||
app->tmp_buffer = malloc(sizeof(uint8_t) * app->samples_count);
|
||||
app->queue = osMessageQueueNew(10, sizeof(WavPlayerEvent), NULL);
|
||||
|
||||
app->volume = 10.0f;
|
||||
app->play = true;
|
||||
|
||||
app->gui = furi_record_open("gui");
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->view = wav_player_view_alloc();
|
||||
|
||||
view_dispatcher_add_view(app->view_dispatcher, 0, wav_player_view_get_view(app->view));
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
|
||||
|
||||
app->notification = furi_record_open("notification");
|
||||
notification_message(app->notification, &sequence_display_backlight_enforce_on);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void app_free(WavPlayerApp* app) {
|
||||
view_dispatcher_remove_view(app->view_dispatcher, 0);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
wav_player_view_free(app->view);
|
||||
furi_record_close("gui");
|
||||
|
||||
osMessageQueueDelete(app->queue);
|
||||
free(app->tmp_buffer);
|
||||
free(app->sample_buffer);
|
||||
wav_parser_free(app->parser);
|
||||
stream_free(app->stream);
|
||||
furi_record_close("storage");
|
||||
|
||||
notification_message(app->notification, &sequence_display_backlight_enforce_auto);
|
||||
furi_record_close("notification");
|
||||
free(app);
|
||||
}
|
||||
|
||||
// TODO: that works only with 8-bit 2ch audio
|
||||
static bool fill_data(WavPlayerApp* app, size_t index) {
|
||||
uint16_t* sample_buffer_start = &app->sample_buffer[index];
|
||||
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
|
||||
|
||||
for(size_t i = count; i < app->samples_count; i++) {
|
||||
app->tmp_buffer[i] = 0;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < app->samples_count; i += 2) {
|
||||
float data = app->tmp_buffer[i];
|
||||
data -= UINT8_MAX / 2; // to signed
|
||||
data /= UINT8_MAX / 2; // scale -1..1
|
||||
|
||||
data *= app->volume; // volume
|
||||
data = tanhf(data); // hyperbolic tangent limiter
|
||||
|
||||
data *= UINT8_MAX / 2; // scale -128..127
|
||||
data += UINT8_MAX / 2; // to unsigned
|
||||
|
||||
if(data < 0) {
|
||||
data = 0;
|
||||
}
|
||||
|
||||
if(data > 255) {
|
||||
data = 255;
|
||||
}
|
||||
|
||||
sample_buffer_start[i / 2] = data;
|
||||
}
|
||||
|
||||
wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);
|
||||
|
||||
return count != app->samples_count;
|
||||
}
|
||||
|
||||
static void ctrl_callback(WavPlayerCtrl ctrl, void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
WavPlayerEvent event;
|
||||
|
||||
switch(ctrl) {
|
||||
case WavPlayerCtrlVolUp:
|
||||
event.type = WavPlayerEventCtrlVolUp;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlVolDn:
|
||||
event.type = WavPlayerEventCtrlVolDn;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlMoveL:
|
||||
event.type = WavPlayerEventCtrlMoveL;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlMoveR:
|
||||
event.type = WavPlayerEventCtrlMoveR;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlOk:
|
||||
event.type = WavPlayerEventCtrlOk;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlBack:
|
||||
event.type = WavPlayerEventCtrlBack;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void app_run(WavPlayerApp* app) {
|
||||
if(!open_wav_stream(app->storage, app->stream)) return;
|
||||
if(!wav_parser_parse(app->parser, app->stream)) return;
|
||||
|
||||
wav_player_view_set_volume(app->view, app->volume);
|
||||
wav_player_view_set_start(app->view, wav_parser_get_data_start(app->parser));
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
wav_player_view_set_end(app->view, wav_parser_get_data_end(app->parser));
|
||||
wav_player_view_set_play(app->view, app->play);
|
||||
|
||||
wav_player_view_set_context(app->view, app->queue);
|
||||
wav_player_view_set_ctrl_callback(app->view, ctrl_callback);
|
||||
|
||||
bool eof = fill_data(app, 0);
|
||||
eof = fill_data(app, app->samples_count_half);
|
||||
|
||||
wav_player_speaker_init();
|
||||
wav_player_dma_init((uint32_t)app->sample_buffer, app->samples_count);
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, wav_player_dma_isr, app->queue);
|
||||
|
||||
wav_player_dma_start();
|
||||
wav_player_speaker_start();
|
||||
|
||||
WavPlayerEvent event;
|
||||
|
||||
while(1) {
|
||||
if(osMessageQueueGet(app->queue, &event, NULL, osWaitForever) == osOK) {
|
||||
if(event.type == WavPlayerEventHalfTransfer) {
|
||||
eof = fill_data(app, 0);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
if(eof) {
|
||||
stream_seek(
|
||||
app->stream,
|
||||
wav_parser_get_data_start(app->parser),
|
||||
StreamOffsetFromStart);
|
||||
}
|
||||
|
||||
} else if(event.type == WavPlayerEventFullTransfer) {
|
||||
eof = fill_data(app, app->samples_count_half);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
if(eof) {
|
||||
stream_seek(
|
||||
app->stream,
|
||||
wav_parser_get_data_start(app->parser),
|
||||
StreamOffsetFromStart);
|
||||
}
|
||||
} else if(event.type == WavPlayerEventCtrlVolUp) {
|
||||
if(app->volume < 9.9) app->volume += 0.2;
|
||||
wav_player_view_set_volume(app->view, app->volume);
|
||||
} else if(event.type == WavPlayerEventCtrlVolDn) {
|
||||
if(app->volume > 0.01) app->volume -= 0.2;
|
||||
wav_player_view_set_volume(app->view, app->volume);
|
||||
} else if(event.type == WavPlayerEventCtrlMoveL) {
|
||||
int32_t seek = stream_tell(app->stream) - wav_parser_get_data_start(app->parser);
|
||||
seek = MIN(seek, wav_parser_get_data_len(app->parser) / 100);
|
||||
stream_seek(app->stream, -seek, StreamOffsetFromCurrent);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
} else if(event.type == WavPlayerEventCtrlMoveR) {
|
||||
int32_t seek = wav_parser_get_data_end(app->parser) - stream_tell(app->stream);
|
||||
seek = MIN(seek, wav_parser_get_data_len(app->parser) / 100);
|
||||
stream_seek(app->stream, seek, StreamOffsetFromCurrent);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
} else if(event.type == WavPlayerEventCtrlOk) {
|
||||
app->play = !app->play;
|
||||
wav_player_view_set_play(app->view, app->play);
|
||||
|
||||
if(!app->play) {
|
||||
wav_player_speaker_stop();
|
||||
} else {
|
||||
wav_player_speaker_start();
|
||||
}
|
||||
} else if(event.type == WavPlayerEventCtrlBack) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wav_player_speaker_stop();
|
||||
wav_player_dma_stop();
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);
|
||||
}
|
||||
|
||||
int32_t wav_player_app(void* p) {
|
||||
WavPlayerApp* app = app_alloc();
|
||||
app_run(app);
|
||||
app_free(app);
|
||||
return 0;
|
||||
}
|
58
applications/wav_player/wav_player_hal.c
Normal file
@ -0,0 +1,58 @@
|
||||
#include "wav_player_hal.h"
|
||||
#include <stm32wbxx_ll_tim.h>
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
|
||||
#define FURI_HAL_SPEAKER_TIMER TIM16
|
||||
#define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1
|
||||
#define DMA_INSTANCE DMA1, LL_DMA_CHANNEL_1
|
||||
|
||||
void wav_player_speaker_init() {
|
||||
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
||||
TIM_InitStruct.Prescaler = 4;
|
||||
TIM_InitStruct.Autoreload = 255;
|
||||
LL_TIM_Init(FURI_HAL_SPEAKER_TIMER, &TIM_InitStruct);
|
||||
|
||||
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
|
||||
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
|
||||
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE;
|
||||
TIM_OC_InitStruct.CompareValue = 127;
|
||||
LL_TIM_OC_Init(FURI_HAL_SPEAKER_TIMER, FURI_HAL_SPEAKER_CHANNEL, &TIM_OC_InitStruct);
|
||||
}
|
||||
|
||||
void wav_player_speaker_start() {
|
||||
LL_TIM_EnableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_EnableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
}
|
||||
|
||||
void wav_player_speaker_stop() {
|
||||
LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
}
|
||||
|
||||
void wav_player_dma_init(uint32_t address, size_t size) {
|
||||
uint32_t dma_dst = (uint32_t) & (FURI_HAL_SPEAKER_TIMER->CCR1);
|
||||
|
||||
LL_DMA_ConfigAddresses(DMA_INSTANCE, address, dma_dst, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
||||
LL_DMA_SetDataLength(DMA_INSTANCE, size);
|
||||
|
||||
LL_DMA_SetPeriphRequest(DMA_INSTANCE, LL_DMAMUX_REQ_TIM16_UP);
|
||||
LL_DMA_SetDataTransferDirection(DMA_INSTANCE, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
||||
LL_DMA_SetChannelPriorityLevel(DMA_INSTANCE, LL_DMA_PRIORITY_VERYHIGH);
|
||||
LL_DMA_SetMode(DMA_INSTANCE, LL_DMA_MODE_CIRCULAR);
|
||||
LL_DMA_SetPeriphIncMode(DMA_INSTANCE, LL_DMA_PERIPH_NOINCREMENT);
|
||||
LL_DMA_SetMemoryIncMode(DMA_INSTANCE, LL_DMA_MEMORY_INCREMENT);
|
||||
LL_DMA_SetPeriphSize(DMA_INSTANCE, LL_DMA_PDATAALIGN_HALFWORD);
|
||||
LL_DMA_SetMemorySize(DMA_INSTANCE, LL_DMA_MDATAALIGN_HALFWORD);
|
||||
|
||||
LL_DMA_EnableIT_TC(DMA_INSTANCE);
|
||||
LL_DMA_EnableIT_HT(DMA_INSTANCE);
|
||||
}
|
||||
|
||||
void wav_player_dma_start() {
|
||||
LL_DMA_EnableChannel(DMA_INSTANCE);
|
||||
LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_SPEAKER_TIMER);
|
||||
}
|
||||
|
||||
void wav_player_dma_stop() {
|
||||
LL_DMA_DisableChannel(DMA_INSTANCE);
|
||||
}
|
23
applications/wav_player/wav_player_hal.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void wav_player_speaker_init();
|
||||
|
||||
void wav_player_speaker_start();
|
||||
|
||||
void wav_player_speaker_stop();
|
||||
|
||||
void wav_player_dma_init(uint32_t address, size_t size);
|
||||
|
||||
void wav_player_dma_start();
|
||||
|
||||
void wav_player_dma_stop();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
214
applications/wav_player/wav_player_view.c
Normal file
@ -0,0 +1,214 @@
|
||||
#include "wav_player_view.h"
|
||||
|
||||
#define DATA_COUNT 116
|
||||
|
||||
struct WavPlayerView {
|
||||
View* view;
|
||||
WavPlayerCtrlCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool play;
|
||||
float volume;
|
||||
size_t start;
|
||||
size_t end;
|
||||
size_t current;
|
||||
uint8_t data[DATA_COUNT];
|
||||
} WavPlayerViewModel;
|
||||
|
||||
float map(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||
return (x - in_min) * (out_max - out_min + 1) / (in_max - in_min + 1) + out_min;
|
||||
}
|
||||
|
||||
static void wav_player_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
WavPlayerViewModel* model = _model;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
uint8_t x_pos = 0;
|
||||
uint8_t y_pos = 0;
|
||||
|
||||
// volume
|
||||
x_pos = 124;
|
||||
y_pos = 0;
|
||||
const float volume = (64 / 10.0f) * model->volume;
|
||||
canvas_draw_frame(canvas, x_pos, y_pos, 4, 64);
|
||||
canvas_draw_box(canvas, x_pos, y_pos + (64 - volume), 4, volume);
|
||||
|
||||
// play / pause
|
||||
x_pos = 58;
|
||||
y_pos = 55;
|
||||
if(model->play) {
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos + 8, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 8, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
} else {
|
||||
canvas_draw_box(canvas, x_pos, y_pos, 3, 9);
|
||||
canvas_draw_box(canvas, x_pos + 4, y_pos, 3, 9);
|
||||
}
|
||||
|
||||
x_pos = 78;
|
||||
y_pos = 55;
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos + 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
|
||||
x_pos = 82;
|
||||
y_pos = 55;
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos + 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
|
||||
x_pos = 40;
|
||||
y_pos = 55;
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos - 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos - 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
|
||||
x_pos = 44;
|
||||
y_pos = 55;
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos - 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos - 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
|
||||
// len
|
||||
x_pos = 4;
|
||||
y_pos = 47;
|
||||
const uint8_t play_len = 116;
|
||||
uint8_t play_pos = map(model->current, model->start, model->end, 0, play_len - 4);
|
||||
|
||||
canvas_draw_frame(canvas, x_pos, y_pos, play_len, 4);
|
||||
canvas_draw_box(canvas, x_pos + play_pos, y_pos - 2, 4, 8);
|
||||
canvas_draw_box(canvas, x_pos, y_pos, play_pos, 4);
|
||||
|
||||
// osc
|
||||
x_pos = 4;
|
||||
y_pos = 0;
|
||||
for(size_t i = 1; i < DATA_COUNT; i++) {
|
||||
canvas_draw_line(canvas, x_pos + i - 1, model->data[i - 1], x_pos + i, model->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool wav_player_view_input_callback(InputEvent* event, void* context) {
|
||||
WavPlayerView* wav_player_view = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(wav_player_view->callback) {
|
||||
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
|
||||
if(event->key == InputKeyUp) {
|
||||
wav_player_view->callback(WavPlayerCtrlVolUp, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
wav_player_view->callback(WavPlayerCtrlVolDn, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
wav_player_view->callback(WavPlayerCtrlMoveL, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyRight) {
|
||||
wav_player_view->callback(WavPlayerCtrlMoveR, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyOk) {
|
||||
wav_player_view->callback(WavPlayerCtrlOk, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
wav_player_view->callback(WavPlayerCtrlBack, wav_player_view->context);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
WavPlayerView* wav_player_view_alloc() {
|
||||
WavPlayerView* wav_view = malloc(sizeof(WavPlayerView));
|
||||
wav_view->view = view_alloc();
|
||||
view_set_context(wav_view->view, wav_view);
|
||||
view_allocate_model(wav_view->view, ViewModelTypeLocking, sizeof(WavPlayerViewModel));
|
||||
view_set_draw_callback(wav_view->view, wav_player_view_draw_callback);
|
||||
view_set_input_callback(wav_view->view, wav_player_view_input_callback);
|
||||
|
||||
return wav_view;
|
||||
}
|
||||
|
||||
void wav_player_view_free(WavPlayerView* wav_view) {
|
||||
furi_assert(wav_view);
|
||||
view_free(wav_view->view);
|
||||
free(wav_view);
|
||||
}
|
||||
|
||||
View* wav_player_view_get_view(WavPlayerView* wav_view) {
|
||||
furi_assert(wav_view);
|
||||
return wav_view->view;
|
||||
}
|
||||
|
||||
void wav_player_view_set_volume(WavPlayerView* wav_view, float volume) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->volume = volume;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_start(WavPlayerView* wav_view, size_t start) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->start = start;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_end(WavPlayerView* wav_view, size_t end) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->end = end;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_current(WavPlayerView* wav_view, size_t current) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->current = current;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_play(WavPlayerView* wav_view, bool play) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->play = play;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
size_t inc = (data_count / DATA_COUNT) - 1;
|
||||
|
||||
for(size_t i = 0; i < DATA_COUNT; i++) {
|
||||
model->data[i] = *data / 6;
|
||||
if(model->data[i] > 42) model->data[i] = 42;
|
||||
data += inc;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback) {
|
||||
furi_assert(wav_view);
|
||||
wav_view->callback = callback;
|
||||
}
|
||||
|
||||
void wav_player_view_set_context(WavPlayerView* wav_view, void* context) {
|
||||
furi_assert(wav_view);
|
||||
wav_view->context = context;
|
||||
}
|
45
applications/wav_player/wav_player_view.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct WavPlayerView WavPlayerView;
|
||||
|
||||
typedef enum {
|
||||
WavPlayerCtrlVolUp,
|
||||
WavPlayerCtrlVolDn,
|
||||
WavPlayerCtrlMoveL,
|
||||
WavPlayerCtrlMoveR,
|
||||
WavPlayerCtrlOk,
|
||||
WavPlayerCtrlBack,
|
||||
} WavPlayerCtrl;
|
||||
|
||||
typedef void (*WavPlayerCtrlCallback)(WavPlayerCtrl ctrl, void* context);
|
||||
|
||||
WavPlayerView* wav_player_view_alloc();
|
||||
|
||||
void wav_player_view_free(WavPlayerView* wav_view);
|
||||
|
||||
View* wav_player_view_get_view(WavPlayerView* wav_view);
|
||||
|
||||
void wav_player_view_set_volume(WavPlayerView* wav_view, float volume);
|
||||
|
||||
void wav_player_view_set_start(WavPlayerView* wav_view, size_t start);
|
||||
|
||||
void wav_player_view_set_end(WavPlayerView* wav_view, size_t end);
|
||||
|
||||
void wav_player_view_set_current(WavPlayerView* wav_view, size_t current);
|
||||
|
||||
void wav_player_view_set_play(WavPlayerView* wav_view, bool play);
|
||||
|
||||
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count);
|
||||
|
||||
void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback);
|
||||
|
||||
void wav_player_view_set_context(WavPlayerView* wav_view, void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -328,6 +328,16 @@ const uint8_t _A_Bluetooth_14_4[] = {0x00,0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x0
|
||||
const uint8_t _A_Bluetooth_14_5[] = {0x00,0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x00,0x94,0x04,0x58,0x08,0x30,0x09,0x30,0x09,0x58,0x08,0x94,0x04,0x92,0x00,0x51,0x00,0x30,0x00,0x10,0x00,};
|
||||
const uint8_t* const _A_Bluetooth_14[] = {_A_Bluetooth_14_0,_A_Bluetooth_14_1,_A_Bluetooth_14_2,_A_Bluetooth_14_3,_A_Bluetooth_14_4,_A_Bluetooth_14_5};
|
||||
|
||||
const uint8_t _A_Clock_14_0[] = {0x00,0xF0,0x01,0x0E,0x0E,0x47,0x1C,0x03,0x18,0x49,0x12,0x41,0x10,0x41,0x10,0x01,0x10,0x09,0x12,0x02,0x08,0x46,0x0C,0x0E,0x0E,0xF6,0x0D,0x02,0x08,};
|
||||
const uint8_t _A_Clock_14_1[] = {0x00,0xF0,0x01,0x0E,0x0E,0x47,0x1C,0x03,0x18,0x09,0x13,0x81,0x10,0x41,0x10,0x01,0x10,0x09,0x12,0x02,0x08,0x46,0x0C,0x0E,0x0E,0xF6,0x0D,0x02,0x08,};
|
||||
const uint8_t _A_Clock_14_2[] = {0x00,0xF0,0x01,0x0E,0x0E,0x47,0x1C,0x03,0x18,0x09,0x12,0x01,0x10,0xC1,0x11,0x01,0x10,0x09,0x12,0x02,0x08,0x46,0x0C,0x0E,0x0E,0xF6,0x0D,0x02,0x08,};
|
||||
const uint8_t _A_Clock_14_3[] = {0x00,0xF0,0x01,0x0E,0x0E,0x47,0x1C,0x03,0x18,0x09,0x12,0x01,0x10,0x41,0x10,0x81,0x10,0x09,0x13,0x02,0x08,0x46,0x0C,0x0E,0x0E,0xF6,0x0D,0x02,0x08,};
|
||||
const uint8_t _A_Clock_14_4[] = {0x00,0xF0,0x01,0x0E,0x0E,0x47,0x1C,0x03,0x18,0x09,0x12,0x01,0x10,0x41,0x10,0x41,0x10,0x49,0x12,0x02,0x08,0x46,0x0C,0x0E,0x0E,0xF6,0x0D,0x02,0x08,};
|
||||
const uint8_t _A_Clock_14_5[] = {0x00,0xF0,0x01,0x0E,0x0E,0x47,0x1C,0x03,0x18,0x09,0x12,0x01,0x10,0x41,0x10,0x21,0x10,0x19,0x12,0x02,0x08,0x46,0x0C,0x0E,0x0E,0xF6,0x0D,0x02,0x08,};
|
||||
const uint8_t _A_Clock_14_6[] = {0x00,0xF0,0x01,0x0E,0x0E,0x47,0x1C,0x03,0x18,0x09,0x12,0x01,0x10,0x71,0x10,0x01,0x10,0x09,0x12,0x02,0x08,0x46,0x0C,0x0E,0x0E,0xF6,0x0D,0x02,0x08,};
|
||||
const uint8_t _A_Clock_14_7[] = {0x00,0xF0,0x01,0x0E,0x0E,0x47,0x1C,0x03,0x18,0x19,0x12,0x21,0x10,0x41,0x10,0x01,0x10,0x09,0x12,0x02,0x08,0x46,0x0C,0x0E,0x0E,0xF6,0x0D,0x02,0x08,};
|
||||
const uint8_t* const _A_Clock_14[] = {_A_Clock_14_0,_A_Clock_14_1,_A_Clock_14_2,_A_Clock_14_3,_A_Clock_14_4,_A_Clock_14_5,_A_Clock_14_6,_A_Clock_14_7};
|
||||
|
||||
const uint8_t _A_Debug_14_0[] = {0x00,0x20,0x01,0xC1,0x20,0x22,0x11,0x24,0x09,0xD9,0x26,0x16,0x1A,0xD8,0x06,0xD8,0x06,0xD6,0x1A,0x19,0x26,0xE4,0x09,0xC2,0x10,0x01,0x20,0x00,0x00,};
|
||||
const uint8_t _A_Debug_14_1[] = {0x00,0x20,0x01,0xC0,0x00,0x22,0x11,0x25,0x29,0xD8,0x06,0x16,0x1A,0xD9,0x26,0xD8,0x06,0xD4,0x0A,0x12,0x12,0xEA,0x15,0xC5,0x28,0x02,0x10,0x02,0x10,};
|
||||
const uint8_t _A_Debug_14_2[] = {0x00,0x20,0x01,0xC0,0x00,0x20,0x01,0x24,0x09,0xDA,0x16,0x11,0x22,0xDC,0x0E,0xDA,0x16,0xD9,0x26,0x14,0x0A,0xF2,0x13,0xD1,0x22,0x08,0x04,0x06,0x18,};
|
||||
@ -375,6 +385,13 @@ const uint8_t _A_Infrared_14_4[] = {0x01,0x00,0x0e,0x00,0x00,0x5f,0x82,0x02,0x05
|
||||
const uint8_t _A_Infrared_14_5[] = {0x01,0x00,0x15,0x00,0x00,0x2f,0xc2,0x07,0x08,0x82,0x01,0x47,0xc1,0x01,0x05,0x98,0x14,0x41,0xa3,0xf8,0x83,0x80,0x47,0xff,0x3f,};
|
||||
const uint8_t* const _A_Infrared_14[] = {_A_Infrared_14_0,_A_Infrared_14_1,_A_Infrared_14_2,_A_Infrared_14_3,_A_Infrared_14_4,_A_Infrared_14_5};
|
||||
|
||||
const uint8_t _A_MusicPlayer_14_0[] = {0x01,0x00,0x17,0x00,0x00,0x1e,0x02,0x01,0xc0,0x80,0xf0,0x20,0x74,0x08,0x15,0x02,0x00,0x01,0x3b,0x84,0x02,0xf0,0x01,0x29,0x80,0x5c,0x80,};
|
||||
const uint8_t _A_MusicPlayer_14_1[] = {0x01,0x00,0x16,0x00,0x80,0x41,0x20,0x10,0xe8,0x04,0x7a,0x01,0x12,0x80,0x40,0x80,0x27,0x80,0x81,0xf0,0x00,0x25,0x80,0x80,0x86,0x94,};
|
||||
const uint8_t _A_MusicPlayer_14_2[] = {0x01,0x00,0x13,0x00,0x00,0x34,0x82,0x03,0x30,0x81,0xcc,0x20,0x51,0x08,0x00,0x05,0x63,0x90,0x08,0xf0,0x04,0xa1,0x80,};
|
||||
const uint8_t _A_MusicPlayer_14_3[] = {0x01,0x00,0x16,0x00,0x82,0x40,0x21,0xd0,0x08,0xf4,0x02,0x25,0x00,0x81,0x00,0x52,0x07,0x20,0x81,0xcc,0x00,0x23,0x01,0x90,0x06,0xd4,};
|
||||
const uint8_t _A_MusicPlayer_14_4[] = {0x01,0x00,0x15,0x00,0x00,0x2c,0x82,0x01,0x70,0x80,0x7c,0x20,0x19,0x08,0x04,0x40,0x02,0x91,0xc8,0x04,0x78,0x02,0x50,0xc8,0x00,};
|
||||
const uint8_t* const _A_MusicPlayer_14[] = {_A_MusicPlayer_14_0,_A_MusicPlayer_14_1,_A_MusicPlayer_14_2,_A_MusicPlayer_14_3,_A_MusicPlayer_14_4};
|
||||
|
||||
const uint8_t _A_NFC_14_0[] = {0x00,0x00,0x08,0x00,0x10,0x00,0x12,0x00,0x22,0x42,0x24,0x87,0x24,0x8D,0x24,0x99,0x24,0xF1,0x24,0x62,0x24,0x00,0x22,0x00,0x12,0x00,0x10,0x00,0x08,};
|
||||
const uint8_t _A_NFC_14_1[] = {0x01,0x00,0x1a,0x00,0x80,0x42,0x20,0x11,0x00,0x09,0x48,0x28,0x52,0x0c,0x3c,0x83,0x1b,0x20,0xcc,0xc8,0x3e,0x32,0x0b,0x14,0x80,0x1a,0x21,0x34,0x84,0x00,};
|
||||
const uint8_t _A_NFC_14_2[] = {0x01,0x00,0x10,0x00,0x00,0x3d,0x0a,0x01,0x87,0x80,0x63,0x60,0x19,0x98,0x07,0xc6,0x01,0x62,0x09,0xc0,};
|
||||
@ -441,6 +458,38 @@ const uint8_t _A_U2F_14_2[] = {0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0x08
|
||||
const uint8_t _A_U2F_14_3[] = {0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,};
|
||||
const uint8_t* const _A_U2F_14[] = {_A_U2F_14_0,_A_U2F_14_1,_A_U2F_14_2,_A_U2F_14_3};
|
||||
|
||||
const uint8_t _A_UniversalRemote_14_0[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,};
|
||||
const uint8_t _A_UniversalRemote_14_1[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,};
|
||||
const uint8_t _A_UniversalRemote_14_2[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,};
|
||||
const uint8_t _A_UniversalRemote_14_3[] = {0x01,0x00,0x1a,0x00,0xd0,0x40,0x7f,0x10,0x70,0x08,0xc2,0x20,0x91,0x08,0x10,0x0c,0x60,0x90,0x88,0x64,0x32,0x30,0x09,0x2c,0xc4,0x18,0x26,0x78,0x08,0x08,};
|
||||
const uint8_t _A_UniversalRemote_14_4[] = {0x00,0x40,0x01,0xF8,0x07,0xF8,0x07,0x18,0x04,0x10,0x06,0x08,0x04,0x0C,0x0C,0x08,0x04,0x18,0x02,0x10,0x06,0xD8,0x06,0xF8,0x07,0xF8,0x07,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_5[] = {0x00,0x00,0x00,0xF0,0x07,0xF8,0x07,0x18,0x04,0x18,0x06,0x10,0x02,0x08,0x04,0x08,0x04,0x10,0x02,0x18,0x06,0xD8,0x06,0xF8,0x07,0xF0,0x03,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_6[] = {0x00,0x00,0x01,0xF0,0x03,0xF8,0x07,0x18,0x04,0x10,0x02,0x18,0x04,0x0C,0x0C,0x08,0x04,0x18,0x02,0x10,0x02,0xF8,0x06,0xF8,0x07,0xF0,0x07,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_7[] = {0x00,0x00,0x00,0xF8,0x07,0xF8,0x07,0x00,0x04,0x10,0x04,0x08,0x04,0x0C,0x0C,0x0C,0x0C,0x18,0x04,0x00,0x04,0xD8,0x06,0xF8,0x07,0xF0,0x03,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_8[] = {0x00,0x00,0x00,0xF0,0x07,0xF8,0x07,0x18,0x04,0x08,0x04,0x0C,0x0C,0x0A,0x1C,0x0E,0x18,0x08,0x0C,0x48,0x00,0xD8,0x06,0xF8,0x07,0xF0,0x03,0x40,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_9[] = {0x00,0x20,0x02,0xF8,0x07,0xF8,0x07,0x08,0x04,0x00,0x04,0x0C,0x0C,0x0B,0x34,0x0E,0x1C,0x0C,0x0C,0xE0,0x01,0xD8,0x06,0xF8,0x07,0xF8,0x07,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_10[] = {0x00,0xA0,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x08,0x00,0x0C,0x0C,0x0B,0x34,0x0A,0x14,0x0C,0x0C,0xF0,0x01,0x98,0x05,0xF8,0x07,0xF8,0x07,0x40,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_11[] = {0x00,0xA0,0x01,0xF8,0x07,0xF8,0x07,0x00,0x00,0x00,0x00,0x0E,0x0C,0x0A,0x34,0x0B,0x14,0x0C,0x0C,0xE0,0x01,0x98,0x05,0xF8,0x07,0xD8,0x07,0x60,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_12[] = {0x00,0xA0,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x00,0x0C,0x0C,0x0A,0x14,0x0A,0x1C,0x0C,0x0C,0xE0,0x01,0x98,0x05,0xF8,0x07,0xD8,0x07,0x60,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_13[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_14[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_15[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_16[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_17[] = {0x00,0xA0,0x01,0xF8,0x07,0xF8,0x07,0x00,0x00,0x04,0x08,0x0C,0x0C,0x0A,0x14,0x0A,0x1C,0x0C,0x0C,0xE0,0x01,0x98,0x06,0xF8,0x07,0xD8,0x07,0x60,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_18[] = {0x00,0x20,0x02,0xF8,0x07,0xF8,0x07,0x08,0x04,0x08,0x04,0x0E,0x0C,0x0A,0x34,0x0B,0x14,0x0C,0x0C,0xE4,0x03,0xD8,0x06,0xF8,0x07,0xF8,0x07,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_19[] = {0x00,0x00,0x00,0xF0,0x07,0xF8,0x07,0x18,0x04,0x04,0x08,0x0E,0x1C,0x0B,0x34,0x0A,0x14,0x0C,0x0C,0xE0,0x03,0xF8,0x06,0xF8,0x07,0xF0,0x07,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_20[] = {0x00,0x00,0x01,0xF0,0x03,0xF8,0x07,0x18,0x04,0x04,0x00,0x0C,0x0C,0x0B,0x34,0x0B,0x34,0x0C,0x0C,0xE0,0x05,0xF8,0x06,0xF8,0x07,0xF0,0x03,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_21[] = {0x00,0x00,0x00,0xF8,0x07,0xF8,0x07,0x10,0x00,0x08,0x04,0x0C,0x0C,0x0C,0x0C,0x0E,0x0C,0x08,0x04,0x88,0x04,0xF0,0x02,0xF8,0x07,0xF0,0x03,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_22[] = {0x00,0x00,0x00,0xF8,0x07,0xF8,0x07,0x00,0x00,0x18,0x04,0x08,0x04,0x0C,0x0C,0x08,0x04,0x08,0x04,0x00,0x04,0xD8,0x02,0xF8,0x07,0xF0,0x03,0x00,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_23[] = {0x01,0x00,0x14,0x00,0xa0,0x40,0x7f,0x10,0x70,0x08,0x81,0xc6,0x21,0x02,0x84,0x41,0x00,0x2a,0x09,0x1e,0xc4,0x18,0x26,0xa0,};
|
||||
const uint8_t _A_UniversalRemote_14_24[] = {0x01,0x00,0x17,0x00,0x90,0x40,0xbf,0x10,0x70,0x08,0xc2,0x20,0x91,0x08,0x14,0x62,0x0c,0x05,0x10,0x3a,0xe6,0x20,0xa1,0x33,0xa0,0x40,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_25[] = {0x01,0x00,0x1a,0x00,0xb0,0x40,0x7f,0x10,0x70,0x08,0xc2,0x20,0x91,0x88,0x34,0x62,0x04,0x05,0x10,0x39,0x40,0xa2,0x10,0x6c,0xc4,0x14,0x26,0x78,0x08,0x00,};
|
||||
const uint8_t _A_UniversalRemote_14_26[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x10,0x06,0x08,0x04,0x0C,0x0C,0x08,0x04,0x18,0x02,0x10,0x06,0x98,0x04,0xF8,0x07,0xF8,0x07,0x80,0x02,};
|
||||
const uint8_t _A_UniversalRemote_14_27[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,};
|
||||
const uint8_t _A_UniversalRemote_14_28[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,};
|
||||
const uint8_t _A_UniversalRemote_14_29[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,};
|
||||
const uint8_t* const _A_UniversalRemote_14[] = {_A_UniversalRemote_14_0,_A_UniversalRemote_14_1,_A_UniversalRemote_14_2,_A_UniversalRemote_14_3,_A_UniversalRemote_14_4,_A_UniversalRemote_14_5,_A_UniversalRemote_14_6,_A_UniversalRemote_14_7,_A_UniversalRemote_14_8,_A_UniversalRemote_14_9,_A_UniversalRemote_14_10,_A_UniversalRemote_14_11,_A_UniversalRemote_14_12,_A_UniversalRemote_14_13,_A_UniversalRemote_14_14,_A_UniversalRemote_14_15,_A_UniversalRemote_14_16,_A_UniversalRemote_14_17,_A_UniversalRemote_14_18,_A_UniversalRemote_14_19,_A_UniversalRemote_14_20,_A_UniversalRemote_14_21,_A_UniversalRemote_14_22,_A_UniversalRemote_14_23,_A_UniversalRemote_14_24,_A_UniversalRemote_14_25,_A_UniversalRemote_14_26,_A_UniversalRemote_14_27,_A_UniversalRemote_14_28,_A_UniversalRemote_14_29};
|
||||
|
||||
const uint8_t _A_iButton_14_0[] = {0x00,0x00,0x1C,0x00,0x3E,0x00,0x35,0x80,0x3A,0x78,0x15,0x84,0x0A,0x32,0x05,0x49,0x02,0x85,0x02,0x85,0x02,0x49,0x02,0x32,0x01,0x84,0x00,0x78,0x00,};
|
||||
const uint8_t _A_iButton_14_1[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x26,0x80,0x21,0xE0,0x10,0x38,0x0D,0x6C,0x03,0x56,0x01,0x2B,0x01,0x97,0x00,0x4D,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,};
|
||||
const uint8_t _A_iButton_14_2[] = {0x01,0x00,0x1a,0x00,0x00,0x24,0xc2,0x01,0x2c,0x80,0x48,0xfb,0x11,0x89,0x64,0x1b,0x2d,0x01,0xa5,0xc0,0x24,0xb0,0x08,0x94,0x02,0x13,0x00,0x83,0x85,0x88,};
|
||||
@ -760,11 +809,13 @@ const Icon I_KeySave_24x11 = {.width=24,.height=11,.frame_count=1,.frame_rate=0,
|
||||
const Icon A_125khz_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_125khz_14};
|
||||
const Icon A_BadUsb_14 = {.width=14,.height=14,.frame_count=11,.frame_rate=3,.frames=_A_BadUsb_14};
|
||||
const Icon A_Bluetooth_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Bluetooth_14};
|
||||
const Icon A_Clock_14 = {.width=14,.height=14,.frame_count=8,.frame_rate=3,.frames=_A_Clock_14};
|
||||
const Icon A_Debug_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_Debug_14};
|
||||
const Icon A_FileManager_14 = {.width=14,.height=14,.frame_count=10,.frame_rate=3,.frames=_A_FileManager_14};
|
||||
const Icon A_GPIO_14 = {.width=14,.height=14,.frame_count=8,.frame_rate=3,.frames=_A_GPIO_14};
|
||||
const Icon A_Games_14 = {.width=14,.height=14,.frame_count=9,.frame_rate=3,.frames=_A_Games_14};
|
||||
const Icon A_Infrared_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Infrared_14};
|
||||
const Icon A_MusicPlayer_14 = {.width=14,.height=14,.frame_count=5,.frame_rate=3,.frames=_A_MusicPlayer_14};
|
||||
const Icon A_NFC_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_NFC_14};
|
||||
const Icon A_Passport_14 = {.width=14,.height=14,.frame_count=10,.frame_rate=3,.frames=_A_Passport_14};
|
||||
const Icon A_Plugins_14 = {.width=14,.height=14,.frame_count=9,.frame_rate=3,.frames=_A_Plugins_14};
|
||||
@ -773,6 +824,7 @@ const Icon A_Settings_14 = {.width=14,.height=14,.frame_count=10,.frame_rate=3,.
|
||||
const Icon A_Sub1ghz_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Sub1ghz_14};
|
||||
const Icon A_Tamagotchi_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Tamagotchi_14};
|
||||
const Icon A_U2F_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_U2F_14};
|
||||
const Icon A_UniversalRemote_14 = {.width=14,.height=14,.frame_count=30,.frame_rate=3,.frames=_A_UniversalRemote_14};
|
||||
const Icon A_iButton_14 = {.width=14,.height=14,.frame_count=7,.frame_rate=3,.frames=_A_iButton_14};
|
||||
const Icon I_Detailed_chip_17x13 = {.width=17,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Detailed_chip_17x13};
|
||||
const Icon I_Medium_chip_22x21 = {.width=22,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_Medium_chip_22x21};
|
||||
|
@ -95,11 +95,13 @@ extern const Icon I_KeySave_24x11;
|
||||
extern const Icon A_125khz_14;
|
||||
extern const Icon A_BadUsb_14;
|
||||
extern const Icon A_Bluetooth_14;
|
||||
extern const Icon A_Clock_14;
|
||||
extern const Icon A_Debug_14;
|
||||
extern const Icon A_FileManager_14;
|
||||
extern const Icon A_GPIO_14;
|
||||
extern const Icon A_Games_14;
|
||||
extern const Icon A_Infrared_14;
|
||||
extern const Icon A_MusicPlayer_14;
|
||||
extern const Icon A_NFC_14;
|
||||
extern const Icon A_Passport_14;
|
||||
extern const Icon A_Plugins_14;
|
||||
@ -108,6 +110,7 @@ extern const Icon A_Settings_14;
|
||||
extern const Icon A_Sub1ghz_14;
|
||||
extern const Icon A_Tamagotchi_14;
|
||||
extern const Icon A_U2F_14;
|
||||
extern const Icon A_UniversalRemote_14;
|
||||
extern const Icon A_iButton_14;
|
||||
extern const Icon I_Detailed_chip_17x13;
|
||||
extern const Icon I_Medium_chip_22x21;
|
||||
|
BIN
assets/icons/MainMenu/Clock_14/frame_01.png
Normal file
After Width: | Height: | Size: 173 B |
BIN
assets/icons/MainMenu/Clock_14/frame_02.png
Normal file
After Width: | Height: | Size: 176 B |
BIN
assets/icons/MainMenu/Clock_14/frame_03.png
Normal file
After Width: | Height: | Size: 175 B |
BIN
assets/icons/MainMenu/Clock_14/frame_04.png
Normal file
After Width: | Height: | Size: 175 B |
BIN
assets/icons/MainMenu/Clock_14/frame_05.png
Normal file
After Width: | Height: | Size: 172 B |
BIN
assets/icons/MainMenu/Clock_14/frame_06.png
Normal file
After Width: | Height: | Size: 175 B |
BIN
assets/icons/MainMenu/Clock_14/frame_07.png
Normal file
After Width: | Height: | Size: 175 B |
BIN
assets/icons/MainMenu/Clock_14/frame_08.png
Normal file
After Width: | Height: | Size: 178 B |
1
assets/icons/MainMenu/Clock_14/frame_rate
Normal file
@ -0,0 +1 @@
|
||||
3
|
BIN
assets/icons/MainMenu/MusicPlayer_14/frame_0.png
Normal file
After Width: | Height: | Size: 149 B |
BIN
assets/icons/MainMenu/MusicPlayer_14/frame_1.png
Normal file
After Width: | Height: | Size: 148 B |
BIN
assets/icons/MainMenu/MusicPlayer_14/frame_2.png
Normal file
After Width: | Height: | Size: 141 B |
BIN
assets/icons/MainMenu/MusicPlayer_14/frame_3.png
Normal file
After Width: | Height: | Size: 147 B |
BIN
assets/icons/MainMenu/MusicPlayer_14/frame_4.png
Normal file
After Width: | Height: | Size: 144 B |
1
assets/icons/MainMenu/MusicPlayer_14/frame_rate
Normal file
@ -0,0 +1 @@
|
||||
3
|
After Width: | Height: | Size: 470 B |
After Width: | Height: | Size: 411 B |
After Width: | Height: | Size: 411 B |
After Width: | Height: | Size: 411 B |
After Width: | Height: | Size: 401 B |
After Width: | Height: | Size: 397 B |
After Width: | Height: | Size: 400 B |
After Width: | Height: | Size: 404 B |
After Width: | Height: | Size: 414 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 426 B |
After Width: | Height: | Size: 431 B |
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 426 B |
After Width: | Height: | Size: 418 B |
After Width: | Height: | Size: 419 B |
After Width: | Height: | Size: 425 B |
After Width: | Height: | Size: 415 B |
After Width: | Height: | Size: 405 B |
After Width: | Height: | Size: 394 B |
After Width: | Height: | Size: 401 B |
After Width: | Height: | Size: 401 B |
After Width: | Height: | Size: 404 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 411 B |
After Width: | Height: | Size: 411 B |
1
assets/icons/MainMenu/UniversalRemote_14/frame_rate
Normal file
@ -0,0 +1 @@
|
||||
3
|
@ -2,18 +2,30 @@ Filetype: Flipper SubGhz Setting File
|
||||
Version: 1
|
||||
Frequency_default: 433920000
|
||||
Frequency: 300000000
|
||||
Frequency: 302757000
|
||||
Frequency: 303875000
|
||||
Frequency: 304250000
|
||||
Frequency: 310000000
|
||||
Frequency: 312000000
|
||||
Frequency: 313850000
|
||||
Frequency: 314000000
|
||||
Frequency: 315000000
|
||||
Frequency: 318000000
|
||||
Frequency: 348000000
|
||||
Frequency: 387000000
|
||||
Frequency: 390000000
|
||||
Frequency: 418000000
|
||||
Frequency: 433075000
|
||||
Frequency: 433220000
|
||||
Frequency: 433420000
|
||||
Frequency: 433889000
|
||||
Frequency: 433920000
|
||||
Frequency: 434420000
|
||||
Frequency: 434775000
|
||||
Frequency: 438900000
|
||||
Frequency: 464000000
|
||||
Frequency: 779000000
|
||||
Frequency: 868350000
|
||||
Frequency: 915000000
|
||||
Frequency: 925000000
|
||||
Frequency: 928000000
|
||||
|
@ -2,23 +2,37 @@ Filetype: Flipper SubGhz Setting File
|
||||
Version: 1
|
||||
Frequency_default: 433920000
|
||||
Frequency: 300000000
|
||||
Frequency: 302757000
|
||||
Frequency: 303875000
|
||||
Frequency: 304250000
|
||||
Frequency: 310000000
|
||||
Frequency: 312000000
|
||||
Frequency: 313850000
|
||||
Frequency: 314000000
|
||||
Frequency: 315000000
|
||||
Frequency: 318000000
|
||||
Frequency: 348000000
|
||||
Frequency: 387000000
|
||||
Frequency: 390000000
|
||||
Frequency: 418000000
|
||||
Frequency: 433075000
|
||||
Frequency: 433220000
|
||||
Frequency: 433420000
|
||||
Frequency: 433889000
|
||||
Frequency: 433920000
|
||||
Frequency: 434420000
|
||||
Frequency: 434775000
|
||||
Frequency: 438900000
|
||||
Frequency: 464000000
|
||||
Frequency: 779000000
|
||||
Frequency: 868350000
|
||||
Frequency: 915000000
|
||||
Frequency: 925000000
|
||||
Frequency: 928000000
|
||||
Hopper_frequency: 312000000
|
||||
Hopper_frequency: 314000000
|
||||
Hopper_frequency: 315000000
|
||||
Hopper_frequency: 318000000
|
||||
Hopper_frequency: 390000000
|
||||
Hopper_frequency: 433920000
|
||||
Hopper_frequency: 868350000
|
||||
Hopper_frequency: 868350000
|
7
assets/resources/subghz/assets/touchtunes_map
Normal file
@ -0,0 +1,7 @@
|
||||
Filetype: Flipper SubGhz RAW File
|
||||
Version: 1
|
||||
UP: /any/subghz/touchtunes/brute/P2.sub
|
||||
DOWN: /any/subghz/touchtunes/brute/Pause.sub
|
||||
LEFT: /any/subghz/touchtunes/brute/Pwr.sub
|
||||
RIGHT: /any/subghz/touchtunes/brute/P1.sub
|
||||
OK: /any/subghz/touchtunes/brute/OK.sub
|
7
assets/resources/subghz/assets/universal_rf_map
Normal file
@ -0,0 +1,7 @@
|
||||
Filetype: Flipper SubGhz RAW File
|
||||
Version: 1
|
||||
UP: /any/subghz/Vehicles/Tesla/Tesla_charge_door_AM270.sub
|
||||
DOWN: /any/subghz/DoorbellFM.sub
|
||||
LEFT: /any/subghz/Vehicles/Tesla/Tesla_charge_door_AM650.sub
|
||||
RIGHT: /any/subghz/Doorbell1.sub
|
||||
OK: /any/subghz/handicap_push_door.sub
|
@ -19,9 +19,8 @@ endif
|
||||
MCU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
|
||||
|
||||
# Warnings configuration
|
||||
CFLAGS += -Wall -Wextra -Wredundant-decls -Wdouble-promotion
|
||||
CFLAGS += $(MCU_FLAGS) -DSTM32WB55xx -Wall -fdata-sections -ffunction-sections
|
||||
|
||||
CFLAGS += $(MCU_FLAGS) -DSTM32WB55xx -fdata-sections -ffunction-sections -fsingle-precision-constant
|
||||
LDFLAGS += $(MCU_FLAGS) -specs=nosys.specs -specs=nano.specs
|
||||
|
||||
CPPFLAGS += -fno-rtti -fno-use-cxa-atexit -fno-exceptions
|
||||
|
@ -3,40 +3,17 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
void set_random_name(char* name, uint8_t max_name_size) {
|
||||
static bool rand_generator_inited = false;
|
||||
|
||||
if(!rand_generator_inited) {
|
||||
srand(DWT->CYCCNT);
|
||||
rand_generator_inited = true;
|
||||
}
|
||||
const char* prefix[] = {
|
||||
"ancient",
|
||||
"hollow",
|
||||
"strange",
|
||||
"disappeared",
|
||||
"unknown",
|
||||
"unthinkable",
|
||||
"unnamable",
|
||||
"nameless",
|
||||
"my",
|
||||
};
|
||||
|
||||
const char* suffix[] = {
|
||||
"door",
|
||||
"entrance",
|
||||
"doorway",
|
||||
"entry",
|
||||
"portal",
|
||||
"entree",
|
||||
"opening",
|
||||
"crack",
|
||||
};
|
||||
uint8_t prefix_i = rand() % COUNT_OF(prefix);
|
||||
uint8_t suffix_i = rand() % COUNT_OF(suffix);
|
||||
|
||||
sniprintf(name, max_name_size, "%s_%s", prefix[prefix_i], suffix[suffix_i]);
|
||||
FuriHalRtcDateTime datetime;
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
char strings[1][25];
|
||||
sprintf(strings[0], "%s%.4d%.2d%.2d%.2d%.2d", "s"
|
||||
, datetime.year, datetime.month, datetime.day
|
||||
, datetime.hour, datetime.minute
|
||||
);
|
||||
sniprintf(name, max_name_size, "%s", strings[0]);
|
||||
// Set first symbol to upper case
|
||||
name[0] = name[0] - 0x20;
|
||||
}
|
||||
|