mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-11 19:33:30 -07:00
+144
-542
@@ -1,247 +1,10 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include "applications/settings/desktop_settings/desktop_settings_app.h"
|
||||
#include "Clock_icons.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
#define TAG "Clock"
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
EventType type;
|
||||
InputEvent input;
|
||||
} PluginEvent;
|
||||
|
||||
typedef struct {
|
||||
FuriMutex* mutex;
|
||||
FuriMessageQueue* event_queue;
|
||||
DesktopSettings* desktop_settings;
|
||||
uint32_t timer_start_timestamp;
|
||||
uint32_t lastexp_timestamp;
|
||||
uint32_t timer_stopped_seconds;
|
||||
uint32_t songSelect;
|
||||
uint32_t codeSequence;
|
||||
uint32_t timerSecs;
|
||||
uint32_t alert_time;
|
||||
bool timer_running;
|
||||
bool militaryTime; // 24 hour
|
||||
bool w_test;
|
||||
} ClockState;
|
||||
|
||||
const NotificationSequence clock_alert_silent = {
|
||||
&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_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_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_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_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_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_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_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_red_255,
|
||||
&message_green_255,
|
||||
&message_blue_255,
|
||||
&message_note_d6,
|
||||
&message_delay_100,
|
||||
&message_delay_10,
|
||||
&message_delay_10,
|
||||
&message_sound_off,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationMessage message_red_127 = {
|
||||
.type = NotificationMessageTypeLedRed,
|
||||
.data.led.value = 0x7F,
|
||||
};
|
||||
|
||||
const NotificationMessage message_green_127 = {
|
||||
.type = NotificationMessageTypeLedGreen,
|
||||
.data.led.value = 0x7F,
|
||||
};
|
||||
|
||||
const NotificationMessage message_blue_127 = {
|
||||
.type = NotificationMessageTypeLedBlue,
|
||||
.data.led.value = 0x7F,
|
||||
};
|
||||
|
||||
const NotificationSequence sequence_rainbow = {
|
||||
&message_red_255, &message_green_0, &message_blue_0,
|
||||
&message_delay_250, &message_red_255, &message_green_127,
|
||||
&message_blue_0, &message_delay_250, &message_red_255,
|
||||
&message_green_255, &message_blue_0, &message_delay_250,
|
||||
&message_red_127, &message_green_255, &message_blue_0,
|
||||
&message_delay_250, &message_red_0, &message_green_255,
|
||||
&message_blue_0, &message_delay_250, &message_red_0,
|
||||
&message_green_255, &message_blue_127, &message_delay_250,
|
||||
&message_red_0, &message_green_255, &message_blue_255,
|
||||
&message_delay_250, &message_red_0, &message_green_127,
|
||||
&message_blue_255, &message_delay_250, &message_red_0,
|
||||
&message_green_0, &message_blue_255, &message_delay_250,
|
||||
&message_red_127, &message_green_0, &message_blue_255,
|
||||
&message_delay_250, &message_red_255, &message_green_0,
|
||||
&message_blue_255, &message_delay_250, &message_red_255,
|
||||
&message_green_0, &message_blue_127, &message_delay_250,
|
||||
&message_red_127, &message_green_127, &message_blue_127,
|
||||
&message_delay_250, &message_red_255, &message_green_255,
|
||||
&message_blue_255, &message_delay_250, NULL,
|
||||
};
|
||||
|
||||
static void desktop_view_main_dumbmode_changed(DesktopSettings* settings) {
|
||||
settings->is_dumbmode = !settings->is_dumbmode;
|
||||
DESKTOP_SETTINGS_SAVE(settings);
|
||||
}
|
||||
#include "clock_app.h"
|
||||
|
||||
static void clock_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
@@ -250,117 +13,98 @@ static void clock_input_callback(InputEvent* input_event, FuriMessageQueue* even
|
||||
}
|
||||
|
||||
static void clock_render_callback(Canvas* const canvas, void* ctx) {
|
||||
//canvas_clear(canvas);
|
||||
//canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
ClockState* state = ctx;
|
||||
if(furi_mutex_acquire(state->mutex, 200) != FuriStatusOk) {
|
||||
// Can't obtain mutex, requeue render
|
||||
//FURI_LOG_D(TAG, "Can't obtain mutex, requeue render");
|
||||
PluginEvent event = {.type = EventTypeTick};
|
||||
furi_message_queue_put(state->event_queue, &event, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
char strings[3][20];
|
||||
snprintf(strings[0], 20, "%.4d-%.2d-%.2d", curr_dt.year, curr_dt.month, curr_dt.day);
|
||||
uint8_t hour = curr_dt.hour;
|
||||
char strAMPM[3];
|
||||
snprintf(strAMPM, sizeof(strAMPM), "%s", "AM");
|
||||
if(!state->militaryTime && hour >= 12) {
|
||||
if(hour > 12) hour -= 12;
|
||||
snprintf(strAMPM, sizeof(strAMPM), "%s", "PM");
|
||||
|
||||
char time_string[TIME_LEN];
|
||||
char date_string[DATE_LEN];
|
||||
char meridian_string[MERIDIAN_LEN];
|
||||
char timer_string[20];
|
||||
|
||||
if(state->time_format == LocaleTimeFormat24h) {
|
||||
snprintf(
|
||||
time_string, TIME_LEN, CLOCK_TIME_FORMAT, curr_dt.hour, curr_dt.minute, curr_dt.second);
|
||||
} else {
|
||||
bool pm = curr_dt.hour > 12;
|
||||
bool pm12 = curr_dt.hour >= 12;
|
||||
snprintf(
|
||||
time_string,
|
||||
TIME_LEN,
|
||||
CLOCK_TIME_FORMAT,
|
||||
pm ? curr_dt.hour - 12 : curr_dt.hour,
|
||||
curr_dt.minute,
|
||||
curr_dt.second);
|
||||
|
||||
snprintf(
|
||||
meridian_string,
|
||||
MERIDIAN_LEN,
|
||||
MERIDIAN_FORMAT,
|
||||
pm12 ? MERIDIAN_STRING_PM : MERIDIAN_STRING_AM);
|
||||
}
|
||||
snprintf(strings[1], 20, "%.2d:%.2d:%.2d", hour, curr_dt.minute, curr_dt.second);
|
||||
|
||||
if(state->date_format == LocaleDateFormatYMD) {
|
||||
snprintf(
|
||||
date_string, DATE_LEN, CLOCK_ISO_DATE_FORMAT, curr_dt.year, curr_dt.month, curr_dt.day);
|
||||
} else if(state->date_format == LocaleDateFormatMDY) {
|
||||
snprintf(
|
||||
date_string, DATE_LEN, CLOCK_RFC_DATE_FORMAT, curr_dt.month, curr_dt.day, curr_dt.year);
|
||||
} else {
|
||||
snprintf(
|
||||
date_string, DATE_LEN, CLOCK_RFC_DATE_FORMAT, curr_dt.day, curr_dt.month, curr_dt.year);
|
||||
}
|
||||
|
||||
bool timer_running = state->timer_running;
|
||||
uint32_t songSelect = state->songSelect;
|
||||
int alert_time = (int)state->alert_time;
|
||||
uint32_t timer_start_timestamp = state->timer_start_timestamp;
|
||||
uint32_t timer_stopped_seconds = state->timer_stopped_seconds;
|
||||
char alertTime[4];
|
||||
snprintf(alertTime, sizeof(alertTime), "%d", alert_time);
|
||||
|
||||
furi_mutex_release(state->mutex);
|
||||
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
if(timer_start_timestamp != 0 && !state->w_test) {
|
||||
|
||||
if(timer_start_timestamp != 0) {
|
||||
int32_t elapsed_secs = timer_running ? (curr_ts - timer_start_timestamp) :
|
||||
timer_stopped_seconds;
|
||||
snprintf(strings[2], 20, "%.2ld:%.2ld", elapsed_secs / 60, elapsed_secs % 60);
|
||||
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, strings[1]); // DRAW TIME
|
||||
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignTop, strings[2]); // DRAW TIMER
|
||||
canvas_set_font(canvas, FontBatteryPercent);
|
||||
if(!state->militaryTime)
|
||||
canvas_draw_str_aligned(canvas, 117, 4, AlignCenter, AlignCenter, strAMPM);
|
||||
canvas_draw_str_aligned(canvas, 117, 11, AlignCenter, AlignCenter, alertTime);
|
||||
canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignTop, strings[0]); // DRAW DATE
|
||||
snprintf(timer_string, 20, "%.2ld:%.2ld", elapsed_secs / 60, elapsed_secs % 60);
|
||||
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, time_string); // DRAW TIME
|
||||
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignTop, timer_string); // DRAW TIMER
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignTop, date_string); // DRAW DATE
|
||||
elements_button_left(canvas, "Reset");
|
||||
} else {
|
||||
if(state->w_test) canvas_set_font(canvas, FontBatteryPercent);
|
||||
if(state->w_test && timer_start_timestamp != 0) {
|
||||
int32_t elapsed_secs = timer_running ? (curr_ts - timer_start_timestamp) :
|
||||
timer_stopped_seconds;
|
||||
snprintf(strings[2], 20, "%.2ld:%.2ld", elapsed_secs / 60, elapsed_secs % 60);
|
||||
int32_t elapsed_secs_img = (elapsed_secs % 60) % 5;
|
||||
int32_t elapsed_secs_img2 = (elapsed_secs % 60) % 4;
|
||||
// int32_t elapsed_secs_img3 = (elapsed_secs % 60) % 4;
|
||||
static const Icon* const count_anim[5] = {
|
||||
&I_HappyFlipper_128x64, &I_G0ku, &I_g0ku_1, &I_g0ku_2, &I_g0ku_3};
|
||||
static const Icon* const count_anim2[4] = {
|
||||
&I_EviWaiting1_18x21, &I_EviWaiting2_18x21, &I_EviSmile1_18x21, &I_EviSmile2_18x21};
|
||||
static const Icon* const count_anim3[4] = {
|
||||
&I_frame_01, &I_frame_02, &I_frame_03, &I_frame_02};
|
||||
canvas_draw_icon(canvas, -5, 15, count_anim[elapsed_secs_img]);
|
||||
canvas_draw_icon(canvas, 90, 0, count_anim2[elapsed_secs_img2]);
|
||||
canvas_draw_icon(canvas, 110, 5, count_anim3[elapsed_secs_img2]);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 32, AlignCenter, AlignTop, strings[2]); // DRAW TIMER
|
||||
}
|
||||
canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignCenter, strings[1]); // DRAW TIME
|
||||
canvas_set_font(canvas, FontBatteryPercent);
|
||||
if(!state->militaryTime) {
|
||||
canvas_draw_str_aligned(canvas, 69, 15, AlignCenter, AlignCenter, strAMPM);
|
||||
}
|
||||
if(!state->w_test)
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 38, AlignCenter, AlignTop, strings[0]); // DRAW DATE
|
||||
canvas_draw_str_aligned(canvas, 64, 28, AlignCenter, AlignCenter, time_string);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 64, 42, AlignCenter, AlignTop, date_string);
|
||||
|
||||
if(!state->desktop_settings->is_dumbmode && !state->w_test)
|
||||
elements_button_left(canvas, state->militaryTime ? "12h" : "24h");
|
||||
if(state->time_format == LocaleTimeFormat12h)
|
||||
canvas_draw_str_aligned(canvas, 65, 12, AlignCenter, AlignCenter, meridian_string);
|
||||
}
|
||||
if(!state->desktop_settings->is_dumbmode && !state->w_test) {
|
||||
if(timer_running) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
} else {
|
||||
elements_button_center(canvas, "Start");
|
||||
}
|
||||
}
|
||||
if(timer_running && !state->w_test) {
|
||||
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");
|
||||
} else if(songSelect == 3) {
|
||||
elements_button_right(canvas, "S:ByMin");
|
||||
}
|
||||
}
|
||||
if(state->w_test && state->desktop_settings->is_dumbmode) {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8);
|
||||
if(timer_running) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
} else if(timer_start_timestamp != 0 && !timer_running) {
|
||||
elements_button_center(canvas, "Start");
|
||||
}
|
||||
}
|
||||
|
||||
static void clock_state_init(ClockState* const state) {
|
||||
memset(state, 0, sizeof(ClockState));
|
||||
state->militaryTime = false;
|
||||
state->songSelect = 2;
|
||||
state->codeSequence = 0;
|
||||
state->lastexp_timestamp = 0;
|
||||
state->timer_start_timestamp = 0;
|
||||
state->timer_stopped_seconds = 0;
|
||||
state->timerSecs = 0;
|
||||
state->alert_time = 80;
|
||||
state->desktop_settings = malloc(sizeof(DesktopSettings));
|
||||
state->w_test = false;
|
||||
state->time_format = locale_get_time_format();
|
||||
|
||||
state->date_format = locale_get_date_format();
|
||||
|
||||
//FURI_LOG_D(TAG, "Time format: %s", state->settings.time_format == H12 ? "12h" : "24h");
|
||||
//FURI_LOG_D(TAG, "Date format: %s", state->settings.date_format == Iso ? "ISO 8601" : "RFC 5322");
|
||||
//furi_hal_rtc_get_datetime(&state->datetime);
|
||||
}
|
||||
|
||||
// Runs every 1000ms by default
|
||||
@@ -368,271 +112,129 @@ static void clock_tick(void* ctx) {
|
||||
furi_assert(ctx);
|
||||
FuriMessageQueue* event_queue = ctx;
|
||||
PluginEvent event = {.type = EventTypeTick};
|
||||
// It's OK to lose this event if system overloaded
|
||||
// It's OK to loose this event if system overloaded
|
||||
furi_message_queue_put(event_queue, &event, 0);
|
||||
}
|
||||
|
||||
int32_t clock_app(void* p) {
|
||||
UNUSED(p);
|
||||
ClockState* plugin_state = malloc(sizeof(ClockState));
|
||||
clock_state_init(plugin_state);
|
||||
|
||||
plugin_state->event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
|
||||
if(plugin_state->event_queue == NULL) {
|
||||
FURI_LOG_E(TAG, "cannot create event queue\n");
|
||||
FURI_LOG_E(TAG, "Cannot create event queue");
|
||||
free(plugin_state);
|
||||
return 255;
|
||||
}
|
||||
//FURI_LOG_D(TAG, "Event queue created");
|
||||
|
||||
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(plugin_state->mutex == NULL) {
|
||||
FURI_LOG_E(TAG, "cannot create mutex\n");
|
||||
FURI_LOG_E(TAG, "Cannot create mutex");
|
||||
furi_message_queue_free(plugin_state->event_queue);
|
||||
free(plugin_state);
|
||||
return 255;
|
||||
}
|
||||
//FURI_LOG_D(TAG, "Mutex created");
|
||||
|
||||
clock_state_init(plugin_state);
|
||||
|
||||
// Set system callbacks
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, clock_render_callback, plugin_state);
|
||||
view_port_input_callback_set(view_port, clock_input_callback, plugin_state->event_queue);
|
||||
|
||||
FuriTimer* timer =
|
||||
furi_timer_alloc(clock_tick, FuriTimerTypePeriodic, plugin_state->event_queue);
|
||||
|
||||
if(timer == NULL) {
|
||||
FURI_LOG_E(TAG, "cannot create timer\n");
|
||||
FURI_LOG_E(TAG, "Cannot create timer");
|
||||
furi_mutex_free(plugin_state->mutex);
|
||||
furi_message_queue_free(plugin_state->event_queue);
|
||||
free(plugin_state);
|
||||
return 255;
|
||||
}
|
||||
DESKTOP_SETTINGS_LOAD(plugin_state->desktop_settings);
|
||||
// Set system callbacks
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, clock_render_callback, plugin_state);
|
||||
view_port_input_callback_set(view_port, clock_input_callback, plugin_state->event_queue);
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
//FURI_LOG_D(TAG, "Timer created");
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
furi_timer_start(timer, furi_kernel_get_tick_frequency());
|
||||
//FURI_LOG_D(TAG, "Timer started");
|
||||
|
||||
// Main loop
|
||||
PluginEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(plugin_state->event_queue, &event, 100);
|
||||
if(event_status == FuriStatusOk) {
|
||||
if(furi_mutex_acquire(plugin_state->mutex, FuriWaitForever) != FuriStatusOk) continue;
|
||||
// press events
|
||||
if(event.type == EventTypeKey) {
|
||||
if(event.input.type == InputTypeShort || event.input.type == InputTypeRepeat) {
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
if(plugin_state->codeSequence == 0 || plugin_state->codeSequence == 1) {
|
||||
plugin_state->codeSequence++;
|
||||
if(plugin_state->timer_running)
|
||||
plugin_state->alert_time = plugin_state->alert_time + 5;
|
||||
} else {
|
||||
plugin_state->codeSequence = 0;
|
||||
if(plugin_state->timer_running)
|
||||
plugin_state->alert_time = plugin_state->alert_time + 5;
|
||||
}
|
||||
break;
|
||||
case InputKeyDown:
|
||||
if(plugin_state->codeSequence == 2 || plugin_state->codeSequence == 3) {
|
||||
plugin_state->codeSequence++;
|
||||
if(plugin_state->timer_running)
|
||||
plugin_state->alert_time = plugin_state->alert_time - 5;
|
||||
} else {
|
||||
plugin_state->codeSequence = 0;
|
||||
if(plugin_state->timer_running)
|
||||
plugin_state->alert_time = plugin_state->alert_time - 5;
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(plugin_state->codeSequence == 5 || plugin_state->codeSequence == 7) {
|
||||
plugin_state->codeSequence++;
|
||||
if(plugin_state->codeSequence == 8) {
|
||||
desktop_view_main_dumbmode_changed(plugin_state->desktop_settings);
|
||||
plugin_state->w_test = true; // OH HEY NOW LETS GAIN EXP & MORE FUN
|
||||
}
|
||||
} else {
|
||||
plugin_state->codeSequence = 0;
|
||||
if(plugin_state->songSelect == 0) {
|
||||
plugin_state->songSelect = 1;
|
||||
} else if(plugin_state->songSelect == 1) {
|
||||
plugin_state->songSelect = 2;
|
||||
} else if(plugin_state->songSelect == 2) {
|
||||
plugin_state->songSelect = 3;
|
||||
} else {
|
||||
plugin_state->songSelect = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(plugin_state->codeSequence == 4 || plugin_state->codeSequence == 6) {
|
||||
plugin_state->codeSequence++;
|
||||
} else {
|
||||
plugin_state->codeSequence = 0;
|
||||
if(plugin_state->timer_start_timestamp != 0) {
|
||||
// START? TIMER
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
// Reset seconds
|
||||
plugin_state->timer_start_timestamp = curr_ts;
|
||||
plugin_state->timer_stopped_seconds = 0;
|
||||
plugin_state->timerSecs = 0;
|
||||
} else {
|
||||
// Toggle 12/24 hours
|
||||
if(!plugin_state->desktop_settings->is_dumbmode)
|
||||
plugin_state->militaryTime = !plugin_state->militaryTime;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
if(plugin_state->codeSequence == 9) {
|
||||
plugin_state->codeSequence++;
|
||||
} else {
|
||||
plugin_state->codeSequence = 0;
|
||||
if(!plugin_state->desktop_settings->is_dumbmode) {
|
||||
if(plugin_state->songSelect == 1 ||
|
||||
plugin_state->songSelect == 2 ||
|
||||
plugin_state->songSelect == 3) {
|
||||
notification_message(notification, &clock_alert_startStop);
|
||||
}
|
||||
// START/STOP TIMER
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
if(plugin_state->timer_running) {
|
||||
// Update stopped seconds
|
||||
plugin_state->timer_stopped_seconds =
|
||||
curr_ts - plugin_state->timer_start_timestamp;
|
||||
} else {
|
||||
if(plugin_state->timer_start_timestamp == 0) {
|
||||
// Set starting timestamp if this is first time
|
||||
plugin_state->timer_start_timestamp = curr_ts;
|
||||
} else {
|
||||
// Timer was already running, need to slightly readjust so we don't
|
||||
// count the intervening time
|
||||
plugin_state->timer_start_timestamp =
|
||||
curr_ts - plugin_state->timer_stopped_seconds;
|
||||
}
|
||||
}
|
||||
plugin_state->timer_running = !plugin_state->timer_running;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if(plugin_state->codeSequence == 8) {
|
||||
plugin_state->codeSequence++;
|
||||
} else {
|
||||
plugin_state->w_test = false;
|
||||
// Don't Exit the plugin
|
||||
plugin_state->codeSequence--;
|
||||
if(plugin_state->codeSequence < (uint32_t)-1) processing = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
if(event_status != FuriStatusOk) continue;
|
||||
|
||||
if(furi_mutex_acquire(plugin_state->mutex, FuriWaitForever) != FuriStatusOk) continue;
|
||||
// press events
|
||||
if(event.type == EventTypeKey) {
|
||||
if(event.input.type == InputTypeShort || event.input.type == InputTypeRepeat) {
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
case InputKeyDown:
|
||||
case InputKeyRight:
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(plugin_state->timer_start_timestamp != 0) {
|
||||
// Reset seconds
|
||||
plugin_state->timer_running = false;
|
||||
plugin_state->timer_start_timestamp = 0;
|
||||
plugin_state->timer_stopped_seconds = 0;
|
||||
}
|
||||
if(plugin_state->codeSequence == 10) {
|
||||
plugin_state->codeSequence = 0;
|
||||
plugin_state->desktop_settings->is_dumbmode =
|
||||
true; // MAKE SURE IT'S ON SO IT GETS TURNED OFF
|
||||
desktop_view_main_dumbmode_changed(plugin_state->desktop_settings);
|
||||
if(plugin_state->songSelect == 1 || plugin_state->songSelect == 2 ||
|
||||
plugin_state->songSelect == 3) {
|
||||
notification_message(notification, &sequence_success);
|
||||
notification_message(notification, &sequence_rainbow);
|
||||
notification_message(notification, &sequence_rainbow);
|
||||
}
|
||||
plugin_state->militaryTime = true; // 24 HR TIME FOR THIS
|
||||
DOLPHIN_DEED(getRandomDeed());
|
||||
}
|
||||
} else if(event.input.type == InputTypeLong) {
|
||||
if(event.input.key == InputKeyLeft) {
|
||||
plugin_state->codeSequence = 0;
|
||||
if(plugin_state->timer_start_timestamp != 0) {
|
||||
// Reset seconds
|
||||
plugin_state->timer_running = false;
|
||||
plugin_state->timer_start_timestamp = 0;
|
||||
plugin_state->timer_stopped_seconds = 0;
|
||||
plugin_state->timerSecs = 0;
|
||||
}
|
||||
} else if(event.input.key == InputKeyBack) {
|
||||
// Exit the plugin
|
||||
processing = false;
|
||||
}
|
||||
}
|
||||
} else if(event.type == EventTypeTick) {
|
||||
// Do nothing, just need to update viewport
|
||||
if(plugin_state->timer_running) {
|
||||
plugin_state->timerSecs = plugin_state->timerSecs + 1;
|
||||
if(plugin_state->timerSecs % 60 == 0 && plugin_state->timerSecs != 0) {
|
||||
notification_message(notification, &clock_alert_perMin);
|
||||
}
|
||||
if(plugin_state->songSelect == 1) {
|
||||
if(plugin_state->timerSecs == plugin_state->alert_time) {
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
if(plugin_state->lastexp_timestamp + 10 <= curr_ts &&
|
||||
plugin_state->w_test) {
|
||||
plugin_state->lastexp_timestamp = curr_ts;
|
||||
DOLPHIN_DEED(getRandomDeed());
|
||||
}
|
||||
notification_message(notification, &clock_alert_pr1);
|
||||
}
|
||||
if(plugin_state->timerSecs == plugin_state->alert_time + 1) {
|
||||
notification_message(notification, &clock_alert_pr2);
|
||||
}
|
||||
if(plugin_state->timerSecs == plugin_state->alert_time + 2) {
|
||||
notification_message(notification, &clock_alert_pr3);
|
||||
notification_message(notification, &sequence_rainbow);
|
||||
notification_message(notification, &sequence_rainbow);
|
||||
}
|
||||
} else if(plugin_state->songSelect == 2) {
|
||||
if(plugin_state->timerSecs == plugin_state->alert_time) {
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
if(plugin_state->lastexp_timestamp + 10 <= curr_ts &&
|
||||
plugin_state->w_test) {
|
||||
plugin_state->lastexp_timestamp = curr_ts;
|
||||
DOLPHIN_DEED(getRandomDeed());
|
||||
}
|
||||
notification_message(notification, &clock_alert_mario1);
|
||||
}
|
||||
if(plugin_state->timerSecs == plugin_state->alert_time + 1) {
|
||||
notification_message(notification, &clock_alert_mario2);
|
||||
}
|
||||
if(plugin_state->timerSecs == plugin_state->alert_time + 2) {
|
||||
notification_message(notification, &clock_alert_mario3);
|
||||
notification_message(notification, &sequence_rainbow);
|
||||
notification_message(notification, &sequence_rainbow);
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:;
|
||||
// START/STOP TIMER
|
||||
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
|
||||
if(plugin_state->timer_running) {
|
||||
// Update stopped seconds
|
||||
plugin_state->timer_stopped_seconds =
|
||||
curr_ts - plugin_state->timer_start_timestamp;
|
||||
} else {
|
||||
if(plugin_state->timerSecs == plugin_state->alert_time) {
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
if(plugin_state->lastexp_timestamp + 10 <= curr_ts &&
|
||||
plugin_state->w_test) {
|
||||
plugin_state->lastexp_timestamp = curr_ts;
|
||||
DOLPHIN_DEED(getRandomDeed());
|
||||
}
|
||||
notification_message(notification, &clock_alert_silent);
|
||||
if(plugin_state->timer_start_timestamp == 0) {
|
||||
// Set starting timestamp if this is first time
|
||||
plugin_state->timer_start_timestamp = curr_ts;
|
||||
} else {
|
||||
// Timer was already running, need to slightly readjust so we don't
|
||||
// count the intervening time
|
||||
plugin_state->timer_start_timestamp =
|
||||
curr_ts - plugin_state->timer_stopped_seconds;
|
||||
}
|
||||
}
|
||||
plugin_state->timer_running = !plugin_state->timer_running;
|
||||
break;
|
||||
case InputKeyBack:
|
||||
// Exit the plugin
|
||||
processing = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
view_port_update(view_port);
|
||||
furi_mutex_release(plugin_state->mutex);
|
||||
}
|
||||
} /*else if(event.type == EventTypeTick) {
|
||||
furi_hal_rtc_get_datetime(&plugin_state->datetime);
|
||||
}*/
|
||||
|
||||
view_port_update(view_port);
|
||||
furi_mutex_release(plugin_state->mutex);
|
||||
}
|
||||
// Cleanup
|
||||
|
||||
furi_timer_free(timer);
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_GUI);
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(plugin_state->event_queue);
|
||||
furi_mutex_free(plugin_state->mutex);
|
||||
free(plugin_state->desktop_settings);
|
||||
free(plugin_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <input/input.h>
|
||||
#include <locale/locale.h>
|
||||
|
||||
#define TAG "Clock"
|
||||
|
||||
#define CLOCK_ISO_DATE_FORMAT "%.4d-%.2d-%.2d"
|
||||
#define CLOCK_RFC_DATE_FORMAT "%.2d-%.2d-%.4d"
|
||||
#define CLOCK_TIME_FORMAT "%.2d:%.2d:%.2d"
|
||||
|
||||
#define MERIDIAN_FORMAT "%s"
|
||||
#define MERIDIAN_STRING_AM "AM"
|
||||
#define MERIDIAN_STRING_PM "PM"
|
||||
|
||||
#define TIME_LEN 12
|
||||
#define DATE_LEN 14
|
||||
#define MERIDIAN_LEN 3
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
EventType type;
|
||||
InputEvent input;
|
||||
} PluginEvent;
|
||||
|
||||
typedef struct {
|
||||
LocaleDateFormat date_format;
|
||||
LocaleTimeFormat time_format;
|
||||
FuriHalRtcDateTime datetime;
|
||||
FuriMutex* mutex;
|
||||
FuriMessageQueue* event_queue;
|
||||
uint32_t timer_start_timestamp;
|
||||
uint32_t timer_stopped_seconds;
|
||||
bool timer_running;
|
||||
} ClockState;
|
||||
@@ -23,7 +23,6 @@ void infrared_scene_universal_on_enter(void* context) {
|
||||
SubmenuIndexUniversalTV,
|
||||
infrared_scene_universal_submenu_callback,
|
||||
context);
|
||||
submenu_set_selected_item(submenu, 0);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
@@ -53,6 +52,8 @@ void infrared_scene_universal_on_enter(void* context) {
|
||||
infrared_scene_universal_submenu_callback,
|
||||
context);
|
||||
|
||||
submenu_set_selected_item(submenu, 0);
|
||||
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu);
|
||||
}
|
||||
|
||||
|
||||
@@ -360,16 +360,6 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
variable_item_set_current_value_text(
|
||||
item, subghz_setting_get_preset_name(subghz->setting, value_index));
|
||||
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Sound:",
|
||||
SPEAKER_COUNT,
|
||||
subghz_scene_receiver_config_set_speaker,
|
||||
subghz);
|
||||
value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, speaker_text[value_index]);
|
||||
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
SubGhzCustomEventManagerSet) {
|
||||
// Hopping
|
||||
@@ -418,6 +408,16 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
variable_item_set_current_value_text(item, rssi_threshold_text[value_index]);
|
||||
|
||||
// Lock keyboard
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Sound:",
|
||||
SPEAKER_COUNT,
|
||||
subghz_scene_receiver_config_set_speaker,
|
||||
subghz);
|
||||
value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, speaker_text[value_index]);
|
||||
|
||||
variable_item_list_add(subghz->variable_item_list, "Lock Keyboard", 1, NULL, NULL);
|
||||
variable_item_list_set_enter_callback(
|
||||
subghz->variable_item_list,
|
||||
|
||||
@@ -162,9 +162,10 @@ bool subghz_path_is_file(FuriString* path);
|
||||
uint32_t subghz_random_serial(void);
|
||||
void subghz_hopper_update(SubGhz* subghz);
|
||||
|
||||
extern const NotificationSequence subghz_sequence_rx;
|
||||
extern const NotificationSequence subghz_sequence_rx_locked;
|
||||
void subghz_speaker_on(SubGhz* subghz);
|
||||
void subghz_speaker_off(SubGhz* subghz);
|
||||
void subghz_speaker_mute(SubGhz* subghz);
|
||||
void subghz_speaker_unmute(SubGhz* subghz);
|
||||
|
||||
extern const NotificationSequence subghz_sequence_rx;
|
||||
extern const NotificationSequence subghz_sequence_rx_locked;
|
||||
|
||||
@@ -47,47 +47,51 @@ static int32_t music_player_worker_thread_callback(void* context) {
|
||||
|
||||
NoteBlockArray_it_t it;
|
||||
NoteBlockArray_it(it, instance->notes);
|
||||
if(furi_hal_speaker_acquire(1000)) {
|
||||
while(instance->should_work) {
|
||||
if(NoteBlockArray_end_p(it)) {
|
||||
NoteBlockArray_it(it, instance->notes);
|
||||
furi_delay_ms(10);
|
||||
} else {
|
||||
NoteBlock* note_block = NoteBlockArray_ref(it);
|
||||
|
||||
while(instance->should_work) {
|
||||
if(NoteBlockArray_end_p(it)) {
|
||||
NoteBlockArray_it(it, instance->notes);
|
||||
furi_delay_ms(10);
|
||||
} else {
|
||||
NoteBlock* note_block = NoteBlockArray_ref(it);
|
||||
float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE;
|
||||
float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4);
|
||||
float duration = 60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm /
|
||||
note_block->duration;
|
||||
uint32_t dots = note_block->dots;
|
||||
while(dots > 0) {
|
||||
duration += duration / 2;
|
||||
dots--;
|
||||
}
|
||||
uint32_t next_tick = furi_get_tick() + duration;
|
||||
float volume = instance->volume;
|
||||
|
||||
float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE;
|
||||
float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4);
|
||||
float duration =
|
||||
60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm / note_block->duration;
|
||||
uint32_t dots = note_block->dots;
|
||||
while(dots > 0) {
|
||||
duration += duration / 2;
|
||||
dots--;
|
||||
if(instance->callback) {
|
||||
instance->callback(
|
||||
note_block->semitone,
|
||||
note_block->dots,
|
||||
note_block->duration,
|
||||
0.0,
|
||||
instance->callback_context);
|
||||
}
|
||||
|
||||
furi_hal_speaker_stop();
|
||||
furi_hal_speaker_start(frequency, volume);
|
||||
while(instance->should_work && furi_get_tick() < next_tick) {
|
||||
volume *= 0.9945679;
|
||||
furi_hal_speaker_set_volume(volume);
|
||||
furi_delay_ms(2);
|
||||
}
|
||||
NoteBlockArray_next(it);
|
||||
}
|
||||
uint32_t next_tick = furi_get_tick() + duration;
|
||||
float volume = instance->volume;
|
||||
|
||||
if(instance->callback) {
|
||||
instance->callback(
|
||||
note_block->semitone,
|
||||
note_block->dots,
|
||||
note_block->duration,
|
||||
0.0,
|
||||
instance->callback_context);
|
||||
}
|
||||
|
||||
furi_hal_speaker_stop();
|
||||
furi_hal_speaker_start(frequency, volume);
|
||||
while(instance->should_work && furi_get_tick() < next_tick) {
|
||||
volume *= 0.9945679;
|
||||
furi_hal_speaker_set_volume(volume);
|
||||
furi_delay_ms(2);
|
||||
}
|
||||
NoteBlockArray_next(it);
|
||||
}
|
||||
}
|
||||
|
||||
furi_hal_speaker_stop();
|
||||
furi_hal_speaker_stop();
|
||||
furi_hal_speaker_release();
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Speaker system is busy with another process.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ enum UsbDebugSubmenuIndex {
|
||||
UsbHidSubmenuIndexKeyboard,
|
||||
UsbHidSubmenuIndexMedia,
|
||||
UsbHidSubmenuIndexMouse,
|
||||
UsbHidSubmenuIndexMouseJiggler,
|
||||
};
|
||||
|
||||
void usb_hid_submenu_callback(void* context, uint32_t index) {
|
||||
@@ -27,6 +28,9 @@ void usb_hid_submenu_callback(void* context, uint32_t index) {
|
||||
} else if(index == UsbHidSubmenuIndexMouse) {
|
||||
app->view_id = UsbHidViewMouse;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMouse);
|
||||
} else if(index == UsbHidSubmenuIndexMouseJiggler) {
|
||||
app->view_id = UsbHidViewMouseJiggler;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMouseJiggler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +80,12 @@ UsbHid* usb_hid_app_alloc() {
|
||||
app->submenu, "Media", UsbHidSubmenuIndexMedia, usb_hid_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->submenu, "Mouse", UsbHidSubmenuIndexMouse, usb_hid_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"Mouse Jiggler",
|
||||
UsbHidSubmenuIndexMouseJiggler,
|
||||
usb_hid_submenu_callback,
|
||||
app);
|
||||
view_set_previous_callback(submenu_get_view(app->submenu), usb_hid_exit);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, UsbHidViewSubmenu, submenu_get_view(app->submenu));
|
||||
@@ -121,6 +131,15 @@ UsbHid* usb_hid_app_alloc() {
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, UsbHidViewMouse, usb_hid_mouse_get_view(app->usb_hid_mouse));
|
||||
|
||||
// Mouse jiggler view
|
||||
app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app);
|
||||
view_set_previous_callback(
|
||||
hid_mouse_jiggler_get_view(app->hid_mouse_jiggler), usb_hid_exit_confirm_view);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
UsbHidViewMouseJiggler,
|
||||
hid_mouse_jiggler_get_view(app->hid_mouse_jiggler));
|
||||
|
||||
// TODO switch to menu after Media is done
|
||||
app->view_id = UsbHidViewSubmenu;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id);
|
||||
@@ -147,6 +166,8 @@ void usb_hid_app_free(UsbHid* app) {
|
||||
usb_hid_media_free(app->usb_hid_media);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMouse);
|
||||
usb_hid_mouse_free(app->usb_hid_mouse);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMouseJiggler);
|
||||
hid_mouse_jiggler_free(app->hid_mouse_jiggler);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
// Close records
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "views/usb_hid_keyboard.h"
|
||||
#include "views/usb_hid_media.h"
|
||||
#include "views/usb_hid_mouse.h"
|
||||
#include "views/usb_hid_mouse_jiggler.h"
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
@@ -23,6 +24,7 @@ typedef struct {
|
||||
UsbHidKeyboard* usb_hid_keyboard;
|
||||
UsbHidMedia* usb_hid_media;
|
||||
UsbHidMouse* usb_hid_mouse;
|
||||
HidMouseJiggler* hid_mouse_jiggler;
|
||||
uint32_t view_id;
|
||||
} UsbHid;
|
||||
|
||||
@@ -32,5 +34,6 @@ typedef enum {
|
||||
UsbHidViewKeyboard,
|
||||
UsbHidViewMedia,
|
||||
UsbHidViewMouse,
|
||||
UsbHidViewMouseJiggler,
|
||||
UsbHidViewExitConfirm,
|
||||
} UsbHidView;
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "usb_hid_mouse_jiggler.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include <USB_Keyboard_icons.h>
|
||||
|
||||
#define TAG "HidMouseJiggler"
|
||||
|
||||
struct HidMouseJiggler {
|
||||
View* view;
|
||||
FuriTimer* timer;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool running;
|
||||
uint8_t counter;
|
||||
} HidMouseJigglerModel;
|
||||
|
||||
static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
HidMouseJigglerModel* model = context;
|
||||
|
||||
// Header
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Jiggler");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto jiggle");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
// Ok
|
||||
canvas_draw_icon(canvas, 63, 25, &I_Space_65x18);
|
||||
if(model->running) {
|
||||
elements_slightly_rounded_box(canvas, 66, 27, 60, 13);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9);
|
||||
if(model->running) {
|
||||
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop");
|
||||
} else {
|
||||
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start");
|
||||
}
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Back
|
||||
canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8);
|
||||
elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit");
|
||||
}
|
||||
|
||||
static void hid_mouse_jiggler_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
HidMouseJiggler* hid_mouse_jiggler = context;
|
||||
with_view_model(
|
||||
hid_mouse_jiggler->view,
|
||||
HidMouseJigglerModel * model,
|
||||
{
|
||||
if(model->running) {
|
||||
model->counter++;
|
||||
furi_hal_hid_mouse_move(
|
||||
(model->counter % 2 == 0) ? MOUSE_MOVE_SHORT : -MOUSE_MOVE_SHORT, 0);
|
||||
}
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
||||
static void hid_mouse_jiggler_enter_callback(void* context) {
|
||||
furi_assert(context);
|
||||
HidMouseJiggler* hid_mouse_jiggler = context;
|
||||
|
||||
furi_timer_start(hid_mouse_jiggler->timer, 500);
|
||||
}
|
||||
|
||||
static void hid_mouse_jiggler_exit_callback(void* context) {
|
||||
furi_assert(context);
|
||||
HidMouseJiggler* hid_mouse_jiggler = context;
|
||||
furi_timer_stop(hid_mouse_jiggler->timer);
|
||||
}
|
||||
|
||||
static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
HidMouseJiggler* hid_mouse_jiggler = context;
|
||||
|
||||
bool consumed = false;
|
||||
|
||||
if(event->key == InputKeyOk) {
|
||||
with_view_model(
|
||||
hid_mouse_jiggler->view,
|
||||
HidMouseJigglerModel * model,
|
||||
{ model->running = !model->running; },
|
||||
true);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
HidMouseJiggler* hid_mouse_jiggler_alloc() {
|
||||
HidMouseJiggler* hid_mouse_jiggler = malloc(sizeof(HidMouseJiggler));
|
||||
|
||||
hid_mouse_jiggler->view = view_alloc();
|
||||
view_set_context(hid_mouse_jiggler->view, hid_mouse_jiggler);
|
||||
view_allocate_model(
|
||||
hid_mouse_jiggler->view, ViewModelTypeLocking, sizeof(HidMouseJigglerModel));
|
||||
view_set_draw_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_draw_callback);
|
||||
view_set_input_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_input_callback);
|
||||
view_set_enter_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_enter_callback);
|
||||
view_set_exit_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_exit_callback);
|
||||
|
||||
hid_mouse_jiggler->timer = furi_timer_alloc(
|
||||
hid_mouse_jiggler_timer_callback, FuriTimerTypePeriodic, hid_mouse_jiggler);
|
||||
|
||||
return hid_mouse_jiggler;
|
||||
}
|
||||
|
||||
void hid_mouse_jiggler_free(HidMouseJiggler* hid_mouse_jiggler) {
|
||||
furi_assert(hid_mouse_jiggler);
|
||||
|
||||
furi_timer_stop(hid_mouse_jiggler->timer);
|
||||
furi_timer_free(hid_mouse_jiggler->timer);
|
||||
|
||||
view_free(hid_mouse_jiggler->view);
|
||||
|
||||
free(hid_mouse_jiggler);
|
||||
}
|
||||
|
||||
View* hid_mouse_jiggler_get_view(HidMouseJiggler* hid_mouse_jiggler) {
|
||||
furi_assert(hid_mouse_jiggler);
|
||||
return hid_mouse_jiggler->view;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#define MOUSE_MOVE_SHORT 5
|
||||
#define MOUSE_MOVE_LONG 20
|
||||
|
||||
typedef struct HidMouseJiggler HidMouseJiggler;
|
||||
|
||||
HidMouseJiggler* hid_mouse_jiggler_alloc();
|
||||
|
||||
void hid_mouse_jiggler_free(HidMouseJiggler* hid_mouse_jiggler);
|
||||
|
||||
View* hid_mouse_jiggler_get_view(HidMouseJiggler* hid_mouse_jiggler);
|
||||
@@ -1,6 +1,31 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 6th Dec, 2022
|
||||
# Last Updated 19th Dec, 2022
|
||||
#
|
||||
# ON/Speed
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1280 423 1285 445 414 1287 1259 418 1279 450 409 1266 442 1260 437 1265 443 1259 438 1264 1282 421 438 8680 1284 419 1289 442 406 1268 1288 415 1282 447 412 1263 434 1267 440 1262 435 1266 441 1261 1285 444 415 8677 1287 415 1282 447 412 1263 1283 447 1261 442 406 1268 439 1262 435 1267 440 1262 435 1267 1289 413 435 8683 1281 421 1286 443 416 1259 1287 416 1281 448 411 1263 444 1258 439 1262 435 1267 440 1263 1283 419 440 8679 1285 417 1280 449 410 1292 1254 448 1260 443 416 1259 438 1264 444 1258 439 1263 444 1258 1288 415 444 8675 1289 413 1284 445 414 1262 1284 419 1288 440 408 1293 415 1261 436 1265 442 1260 437 1265 1281 422 437 8680 1284 418 1289 440 408 1267 1289 414 1283 445 414 1262 435 1266 442 1260 437 1265 442 1261 1285 418 441 8678 1286 417 1290 439 409 1267 1289 414 1283 445 414 1262 435 1267 440 1262 435 1267 440 1263 1283 420 439
|
||||
#
|
||||
name: MODE
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1284 419 1288 442 417 1258 1288 415 1282 448 411 1264 443 1258 439 1263 444 1258 1288 415 444 1258 439 8679 1284 419 1288 441 407 1267 1289 441 1256 447 412 1262 435 1267 440 1262 435 1293 1263 413 435 1267 440 8679 1284 418 1289 441 407 1267 1289 414 1283 447 412 1262 435 1267 440 1261 436 1267 1289 413 435 1267 440 8678 1285 418 1289 440 408 1267 1289 440 1257 447 412 1262 435 1267 440 1262 435 1268 1288 414 434 1268 439 8679 1284 418 1289 440 408 1267 1289 413 1284 445 414 1261 436 1266 441 1260 437 1266 1290 412 436 1266 441 8676 1287 415 1282 448 411 1264 1282 421 1286 443 416 1258 439 1263 434 1267 440 1262 1284 419 440 1262 435 8683 1280 422 1285 444 415 1287 1259 444 1253 449 410 1292 415 1285 412 1264 443 1259 1287 416 443 1259 438 8680 1284 420 1287 414 434 1268 1288 415 1282 447 412 1289 408 1267 440 1262 435 1267 1289 414 434 1268 439
|
||||
#
|
||||
name: SWING
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1281 422 1285 444 415 1260 1286 444 1263 439 409 1266 441 1261 1285 445 414 1261 436 1266 441 1261 436 8682 1281 421 1286 444 415 1260 1286 445 1262 439 409 1266 441 1261 1285 445 414 1261 436 1266 441 1260 437 8683 1280 422 1286 444 415 1261 1285 445 1262 440 408 1267 440 1262 1284 446 413 1262 435 1268 439 1262 435 8684 1279 423 1284 445 414 1261 1285 445 1263 439 409 1265 442 1260 1286 444 415 1260 437 1265 442 1259 438 8682 1281 421 1286 443 416 1259 1287 443 1254 448 411 1264 443 1259 1287 443 416 1259 438 1265 442 1260 437 8682 1281 421 1286 444 415 1260 1286 444 1253 450 409 1266 441 1261 1285 445 414 1261 436 1266 441 1261 436 8683 1290 413 1284 445 414 1262 1283 446 1261 441 407 1294 413 1262 1284 420 439 1263 434 1267 440 1262 435
|
||||
#
|
||||
name: TIMER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1283 420 1287 443 416 1259 1287 443 1254 449 410 1292 415 1260 437 1266 1290 439 409 1266 442 1261 436 8684 1290 413 1284 446 413 1263 1283 447 1261 442 417 1258 439 1263 444 1259 1287 442 417 1259 438 1264 443 8677 1287 416 1281 449 410 1265 1281 449 1259 444 415 1260 437 1265 442 1260 1286 443 416 1260 437 1265 442 8676 1288 415 1282 447 412 1263 1283 447 1261 442 417 1257 440 1263 434 1268 1288 441 418 1257 440 1263 434 8685 1289 414 1283 447 412 1263 1283 447 1261 442 417 1258 439 1263 445 1258 1288 442 417 1258 439 1264 444 8676 1288 415 1282 448 411 1264 1282 448 1260 444 415 1259 438 1264 443 1260 1286 417 442 1260 437 1265 442 8677 1286 416 1281 449 410 1265 1281 422 1285 444 415 1260 437 1265 442 1260 1286 417 442 1260 437 1265 442
|
||||
#
|
||||
name: POWER
|
||||
type: parsed
|
||||
|
||||
Reference in New Issue
Block a user