Merge branch 'dev' of https://github.com/ClaraCrazy/Flipper-Xtreme into fix-bad_kb_bt-flipper_app-conflict
@@ -196,9 +196,9 @@ $ ./fbt resources icons dolphin_ext
|
||||
|
||||
----
|
||||
<h2 align="center">Contributors</h2>
|
||||
<p align="center">
|
||||
<img src="https://user-images.githubusercontent.com/55334727/212134625-21383102-02f3-453f-b1d7-8a9c65b27612.svg">
|
||||
</p>
|
||||
|
||||
[](https://github.com/ClaraCrazy/Flipper-Xtreme/graphs/contributors)
|
||||
|
||||
|
||||
----
|
||||
## SAST Tools
|
||||
|
||||
@@ -3,36 +3,18 @@ App(
|
||||
name="Basic applications for main menu",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"fap_loader",
|
||||
"subghz",
|
||||
"unirfremix",
|
||||
"sub_playlist",
|
||||
"lfrfid",
|
||||
"nfc",
|
||||
"infrared",
|
||||
"gpio",
|
||||
"ibutton",
|
||||
"infrared",
|
||||
"lfrfid",
|
||||
"nfc",
|
||||
"subghz",
|
||||
"bad_kb",
|
||||
"u2f",
|
||||
"fap_loader",
|
||||
"sub_playlist",
|
||||
"archive",
|
||||
"clock",
|
||||
"unirfremix",
|
||||
],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="main_apps_default",
|
||||
name="Basic applications for main menu",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"gpio",
|
||||
# "ibutton",
|
||||
"infrared",
|
||||
"lfrfid",
|
||||
"nfc",
|
||||
"subghz",
|
||||
# "bad_kb",
|
||||
# "u2f",
|
||||
"fap_loader",
|
||||
"xtreme_app",
|
||||
"archive",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
App(
|
||||
appid="xtreme_app",
|
||||
name="Xtreme FW",
|
||||
apptype=FlipperAppType.SETTINGS,
|
||||
name="Xtreme Settings",
|
||||
apptype=FlipperAppType.APP,
|
||||
entry_point="xtreme_app",
|
||||
stack_size=2 * 1024,
|
||||
requires=[
|
||||
"gui",
|
||||
"xtreme",
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
icon="A_Xtreme_14",
|
||||
order=90,
|
||||
)
|
||||
@@ -4,3 +4,4 @@ ADD_SCENE(xtreme_app, statusbar, Statusbar)
|
||||
ADD_SCENE(xtreme_app, protocols, Protocols)
|
||||
ADD_SCENE(xtreme_app, dolphin, Dolphin)
|
||||
ADD_SCENE(xtreme_app, misc, Misc)
|
||||
ADD_SCENE(xtreme_app, misc_rename, MiscRename)
|
||||
@@ -1,5 +1,15 @@
|
||||
#include "../xtreme_app.h"
|
||||
|
||||
enum VarItemListIndex {
|
||||
VarItemListIndexSortDirsFirst,
|
||||
VarItemListIndexChangeDeviceName,
|
||||
};
|
||||
|
||||
void xtreme_app_scene_misc_var_item_list_callback(void* context, uint32_t index) {
|
||||
XtremeApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
static void xtreme_app_scene_misc_sort_folders_before_changed(VariableItem* item) {
|
||||
XtremeApp* app = variable_item_get_context(item);
|
||||
bool value = variable_item_get_current_value_index(item);
|
||||
@@ -23,15 +33,31 @@ void xtreme_app_scene_misc_on_enter(void* context) {
|
||||
variable_item_set_current_value_index(item, xtreme_settings->sort_dirs_first);
|
||||
variable_item_set_current_value_text(item, xtreme_settings->sort_dirs_first ? "ON" : "OFF");
|
||||
|
||||
variable_item_list_set_selected_item(var_item_list, 0);
|
||||
variable_item_list_add(var_item_list, "Change Device Name", 0, NULL, app);
|
||||
|
||||
variable_item_list_set_enter_callback(var_item_list, xtreme_app_scene_misc_var_item_list_callback, app);
|
||||
|
||||
variable_item_list_set_selected_item(var_item_list, scene_manager_get_scene_state(app->scene_manager, XtremeAppSceneMisc));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, XtremeAppViewVarItemList);
|
||||
}
|
||||
|
||||
bool xtreme_app_scene_misc_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
XtremeApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(app->scene_manager, XtremeAppSceneMisc, event.event);
|
||||
consumed = true;
|
||||
switch(event.event) {
|
||||
case VarItemListIndexChangeDeviceName:
|
||||
scene_manager_next_scene(app->scene_manager, XtremeAppSceneMiscRename);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "../xtreme_app.h"
|
||||
|
||||
enum TextInputIndex {
|
||||
TextInputIndexResult,
|
||||
};
|
||||
|
||||
static void xtreme_app_scene_misc_rename_text_input_callback(void* context) {
|
||||
XtremeApp* app = context;
|
||||
|
||||
app->save_name = true;
|
||||
app->require_reboot = true;
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, TextInputIndexResult);
|
||||
}
|
||||
|
||||
void xtreme_app_scene_misc_rename_on_enter(void* context) {
|
||||
XtremeApp* app = context;
|
||||
TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Leave empty for default");
|
||||
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
xtreme_app_scene_misc_rename_text_input_callback,
|
||||
app,
|
||||
app->device_name,
|
||||
NAMECHANGER_TEXT_STORE_SIZE,
|
||||
true);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, XtremeAppViewTextInput);
|
||||
}
|
||||
|
||||
bool xtreme_app_scene_misc_rename_on_event(void* context, SceneManagerEvent event) {
|
||||
XtremeApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
switch(event.event) {
|
||||
case TextInputIndexResult:
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void xtreme_app_scene_misc_rename_on_exit(void* context) {
|
||||
XtremeApp* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
}
|
||||
@@ -16,6 +16,18 @@ static bool xtreme_app_back_event_callback(void* context) {
|
||||
XtremeApp* app = context;
|
||||
|
||||
if(!scene_manager_has_previous_scene(app->scene_manager, XtremeAppSceneStart)) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
if(app->save_subghz) {
|
||||
FlipperFormat* subghz_range = flipper_format_file_alloc(storage);
|
||||
if(flipper_format_file_open_existing(subghz_range, "/ext/subghz/assets/extend_range.txt")) {
|
||||
flipper_format_insert_or_update_bool(
|
||||
subghz_range, "use_ext_range_at_own_risk", &app->subghz_extend, 1);
|
||||
flipper_format_insert_or_update_bool(
|
||||
subghz_range, "ignore_default_tx_region", &app->subghz_bypass, 1);
|
||||
}
|
||||
flipper_format_free(subghz_range);
|
||||
}
|
||||
|
||||
if(app->save_level) {
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
@@ -26,17 +38,27 @@ static bool xtreme_app_back_event_callback(void* context) {
|
||||
furi_record_close(RECORD_DOLPHIN);
|
||||
}
|
||||
|
||||
if(app->save_subghz) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* subghz_range = flipper_format_file_alloc(storage);
|
||||
if(flipper_format_file_open_existing(subghz_range, "/ext/subghz/assets/extend_range.txt")) {
|
||||
flipper_format_insert_or_update_bool(
|
||||
subghz_range, "use_ext_range_at_own_risk", &app->subghz_extend, 1);
|
||||
flipper_format_insert_or_update_bool(
|
||||
subghz_range, "ignore_default_tx_region", &app->subghz_bypass, 1);
|
||||
if(app->save_name) {
|
||||
if(strcmp(app->device_name, "") == 0) {
|
||||
storage_simply_remove(storage, NAMECHANGER_PATH);
|
||||
} else {
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
|
||||
do {
|
||||
if(!flipper_format_file_open_always(file, NAMECHANGER_PATH)) break;
|
||||
|
||||
if(!flipper_format_write_header_cstr(file, NAMECHANGER_HEADER, 1)) break;
|
||||
|
||||
if(!flipper_format_write_comment_cstr(file, "Changing the value below will change your FlipperZero device name.")) break;
|
||||
if(!flipper_format_write_comment_cstr(file, "Note: This is limited to 8 characters using the following: a-z, A-Z, 0-9, and _")) break;
|
||||
if(!flipper_format_write_comment_cstr(file, "It cannot contain any other characters.")) break;
|
||||
|
||||
if(!flipper_format_write_string_cstr(file, "Name", app->device_name)) break;
|
||||
|
||||
} while(0);
|
||||
|
||||
flipper_format_free(file);
|
||||
}
|
||||
flipper_format_free(subghz_range);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
if(app->save_settings) {
|
||||
@@ -54,6 +76,7 @@ static bool xtreme_app_back_event_callback(void* context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
@@ -83,6 +106,12 @@ XtremeApp* xtreme_app_alloc() {
|
||||
XtremeAppViewVarItemList,
|
||||
variable_item_list_get_view(app->var_item_list));
|
||||
|
||||
app->text_input = text_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
XtremeAppViewTextInput,
|
||||
text_input_get_view(app->text_input));
|
||||
|
||||
app->popup = popup_alloc();
|
||||
view_dispatcher_add_view(app->view_dispatcher, XtremeAppViewPopup, popup_get_view(app->popup));
|
||||
|
||||
@@ -90,11 +119,6 @@ XtremeApp* xtreme_app_alloc() {
|
||||
|
||||
XtremeSettings* xtreme_settings = XTREME_SETTINGS();
|
||||
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
DolphinStats stats = dolphin_stats(dolphin);
|
||||
app->dolphin_level = stats.level;
|
||||
furi_record_close(RECORD_DOLPHIN);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* subghz_range = flipper_format_file_alloc(storage);
|
||||
app->subghz_extend = false;
|
||||
@@ -105,6 +129,13 @@ XtremeApp* xtreme_app_alloc() {
|
||||
}
|
||||
flipper_format_free(subghz_range);
|
||||
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
DolphinStats stats = dolphin_stats(dolphin);
|
||||
app->dolphin_level = stats.level;
|
||||
furi_record_close(RECORD_DOLPHIN);
|
||||
|
||||
strlcpy(app->device_name, furi_hal_version_get_name_ptr(), NAMECHANGER_TEXT_STORE_SIZE);
|
||||
|
||||
app->asset_pack = 0;
|
||||
asset_packs_init(app->asset_packs);
|
||||
File* folder = storage_file_alloc(storage);
|
||||
@@ -148,6 +179,8 @@ void xtreme_app_free(XtremeApp* app) {
|
||||
// Gui modules
|
||||
view_dispatcher_remove_view(app->view_dispatcher, XtremeAppViewVarItemList);
|
||||
variable_item_list_free(app->var_item_list);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, XtremeAppViewTextInput);
|
||||
text_input_free(app->text_input);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, XtremeAppViewPopup);
|
||||
popup_free(app->popup);
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
#include <gui/scene_manager.h>
|
||||
#include <assets_icons.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <lib/toolbox/value_index.h>
|
||||
#include <namechangersrv/namechangersrv.h>
|
||||
#include "scenes/xtreme_app_scene.h"
|
||||
#include "dolphin/helpers/dolphin_state.h"
|
||||
#include "dolphin/dolphin.h"
|
||||
@@ -25,20 +27,24 @@ typedef struct {
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
VariableItemList* var_item_list;
|
||||
TextInput* text_input;
|
||||
Popup* popup;
|
||||
int dolphin_level;
|
||||
bool subghz_extend;
|
||||
bool subghz_bypass;
|
||||
bool save_settings;
|
||||
bool require_reboot;
|
||||
bool save_subghz;
|
||||
bool save_level;
|
||||
int dolphin_level;
|
||||
char device_name[NAMECHANGER_TEXT_STORE_SIZE];
|
||||
uint asset_pack;
|
||||
asset_packs_t asset_packs;
|
||||
FuriString* version_tag;
|
||||
bool save_subghz;
|
||||
bool save_level;
|
||||
bool save_name;
|
||||
bool save_settings;
|
||||
bool require_reboot;
|
||||
} XtremeApp;
|
||||
|
||||
typedef enum {
|
||||
XtremeAppViewVarItemList,
|
||||
XtremeAppViewTextInput,
|
||||
XtremeAppViewPopup,
|
||||
} XtremeAppView;
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <gui/view.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define TAG "Arkanoid"
|
||||
|
||||
@@ -398,9 +397,6 @@ int32_t arkanoid_game_app(void* p) {
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
GameEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <stdlib.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <gui/canvas_i.h>
|
||||
|
||||
@@ -278,7 +277,6 @@ void dealer_tick(GameState* game_state) {
|
||||
|
||||
if(dealer_score >= DEALER_MAX) {
|
||||
if(dealer_score > 21 || dealer_score < player_score) {
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameWin);
|
||||
enqueue(
|
||||
&(game_state->queue_state),
|
||||
game_state,
|
||||
@@ -572,9 +570,6 @@ int32_t blackjack_app(void* p) {
|
||||
|
||||
AppEvent event;
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
GameState* localstate = (GameState*)acquire_mutex_block(&state_mutex);
|
||||
@@ -635,4 +630,4 @@ free_and_exit:
|
||||
furi_message_queue_free(event_queue);
|
||||
|
||||
return return_code;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ App(
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
fap_icon="clock.png",
|
||||
fap_category="Tools",
|
||||
fap_category="Misc",
|
||||
)
|
||||
|
||||
@@ -10,5 +10,5 @@ App(
|
||||
stack_size=2 * 1024,
|
||||
order=20,
|
||||
fap_icon="cntdown_timer.png",
|
||||
fap_category="Tools",
|
||||
fap_category="Misc",
|
||||
)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "level.h"
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define SOUND
|
||||
|
||||
@@ -996,9 +995,6 @@ int32_t doom_app() {
|
||||
music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dsintro);
|
||||
music_player_worker_start(plugin_state->music_instance->worker);
|
||||
#endif
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
PluginState* plugin_state = (PluginState*)acquire_mutex_block(&state_mutex);
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include <FlappyBird_icons.h>
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/icon_animation_i.h>
|
||||
#include <input/input.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define TAG "Flappy"
|
||||
#define DEBUG false
|
||||
@@ -257,10 +255,6 @@ static void flappy_game_render_callback(Canvas* const canvas, void* ctx) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 37, 31, "Game Over");
|
||||
|
||||
if(game_state->points != 0 && game_state->points % 5 == 0) {
|
||||
DOLPHIN_DEED(getRandomDeed());
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
char buffer[12];
|
||||
snprintf(buffer, sizeof(buffer), "Score: %u", game_state->points);
|
||||
@@ -313,9 +307,6 @@ int32_t flappy_game_app(void* p) {
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
GameEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <storage/storage.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "sandbox.h"
|
||||
|
||||
@@ -463,9 +462,6 @@ int32_t game15_app() {
|
||||
sandbox_init(
|
||||
FPS, (SandboxRenderCallback)render_callback, (SandboxEventHandler)game_event_handler);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
sandbox_loop();
|
||||
sandbox_free();
|
||||
game_free();
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <storage/storage.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "digits.h"
|
||||
#include "array_utils.h"
|
||||
@@ -398,9 +397,6 @@ int32_t game_2048_app() {
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
bool is_finished = false;
|
||||
while(!is_finished) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &input, FuriWaitForever);
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/canvas_i.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define Y_FIELD_SIZE 6
|
||||
#define Y_LAST (Y_FIELD_SIZE - 1)
|
||||
@@ -531,9 +530,6 @@ int32_t heap_defence_app(void* p) {
|
||||
game->game_status = 0;
|
||||
game->animation = AnimationPause;
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
GameEvent event = {0};
|
||||
while(event.input.key != InputKeyBack) {
|
||||
if(furi_message_queue_get(event_queue, &event, 100) != FuriStatusOk) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
App(
|
||||
appid="hex_viewer",
|
||||
name="HEX Viewer",
|
||||
name="Hex Viewer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="hex_viewer_app",
|
||||
cdefines=["APP_HEX_VIEWER"],
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <m-string.h>
|
||||
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "assets.h"
|
||||
|
||||
@@ -253,9 +252,6 @@ static bool game_won(Minesweeper* minesweeper_state) {
|
||||
dialog_message_set_buttons(message, NULL, "Play again", NULL);
|
||||
dialog_message_set_icon(message, NULL, 72, 17);
|
||||
|
||||
// Call dolphin deed when we win the game
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameWin);
|
||||
|
||||
DialogMessageButton choice = dialog_message_show(dialogs, message);
|
||||
dialog_message_free(message);
|
||||
furi_string_free(tempStr);
|
||||
@@ -410,9 +406,6 @@ int32_t minesweeper_app(void* p) {
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
PluginEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
|
||||
@@ -10,5 +10,5 @@ App(
|
||||
stack_size=1 * 1024,
|
||||
order=20,
|
||||
fap_icon="morse_code_10px.png",
|
||||
fap_category="Music",
|
||||
fap_category="Misc",
|
||||
)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
App(
|
||||
appid="NameChanger",
|
||||
name="Name Changer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="namechanger_app",
|
||||
cdefines=["APP_NAMECHANGER"],
|
||||
requires=["gui", "storage"],
|
||||
stack_size=2 * 1024,
|
||||
order=90,
|
||||
fap_icon="namechanger_10px.png",
|
||||
fap_category="Tools",
|
||||
fap_icon_assets="icons",
|
||||
)
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1,162 +0,0 @@
|
||||
#include "namechanger.h"
|
||||
#include "scenes/namechanger_scene.h"
|
||||
|
||||
#include <toolbox/path.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
|
||||
bool namechanger_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
NameChanger* namechanger = context;
|
||||
return scene_manager_handle_custom_event(namechanger->scene_manager, event);
|
||||
}
|
||||
|
||||
bool namechanger_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
NameChanger* namechanger = context;
|
||||
return scene_manager_handle_back_event(namechanger->scene_manager);
|
||||
}
|
||||
|
||||
NameChanger* namechanger_alloc() {
|
||||
NameChanger* namechanger = malloc(sizeof(NameChanger));
|
||||
|
||||
namechanger->scene_manager = scene_manager_alloc(&namechanger_scene_handlers, namechanger);
|
||||
|
||||
namechanger->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(namechanger->view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(namechanger->view_dispatcher, namechanger);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
namechanger->view_dispatcher, namechanger_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
namechanger->view_dispatcher, namechanger_back_event_callback);
|
||||
|
||||
namechanger->gui = furi_record_open(RECORD_GUI);
|
||||
namechanger->storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
namechanger->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
namechanger->view_dispatcher,
|
||||
NameChangerViewSubmenu,
|
||||
submenu_get_view(namechanger->submenu));
|
||||
|
||||
namechanger->text_input = text_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
namechanger->view_dispatcher,
|
||||
NameChangerViewTextInput,
|
||||
text_input_get_view(namechanger->text_input));
|
||||
|
||||
namechanger->popup = popup_alloc();
|
||||
view_dispatcher_add_view(
|
||||
namechanger->view_dispatcher, NameChangerViewPopup, popup_get_view(namechanger->popup));
|
||||
|
||||
namechanger->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
namechanger->view_dispatcher, NameChangerViewWidget, widget_get_view(namechanger->widget));
|
||||
|
||||
return namechanger;
|
||||
}
|
||||
|
||||
void namechanger_free(NameChanger* namechanger) {
|
||||
furi_assert(namechanger);
|
||||
|
||||
view_dispatcher_remove_view(namechanger->view_dispatcher, NameChangerViewWidget);
|
||||
widget_free(namechanger->widget);
|
||||
view_dispatcher_remove_view(namechanger->view_dispatcher, NameChangerViewPopup);
|
||||
popup_free(namechanger->popup);
|
||||
|
||||
view_dispatcher_remove_view(namechanger->view_dispatcher, NameChangerViewTextInput);
|
||||
text_input_free(namechanger->text_input);
|
||||
|
||||
view_dispatcher_remove_view(namechanger->view_dispatcher, NameChangerViewSubmenu);
|
||||
submenu_free(namechanger->submenu);
|
||||
|
||||
view_dispatcher_free(namechanger->view_dispatcher);
|
||||
scene_manager_free(namechanger->scene_manager);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
free(namechanger);
|
||||
}
|
||||
|
||||
void namechanger_text_store_set(NameChanger* namechanger, const char* text, ...) {
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
|
||||
vsnprintf(namechanger->text_store, NAMECHANGER_TEXT_STORE_SIZE, text, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int32_t namechanger_app() {
|
||||
NameChanger* namechanger = namechanger_alloc();
|
||||
|
||||
view_dispatcher_attach_to_gui(
|
||||
namechanger->view_dispatcher, namechanger->gui, ViewDispatcherTypeFullscreen);
|
||||
scene_manager_next_scene(namechanger->scene_manager, NameChangerSceneStart);
|
||||
|
||||
view_dispatcher_run(namechanger->view_dispatcher);
|
||||
|
||||
namechanger_free(namechanger);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool namechanger_name_write(NameChanger* namechanger, char* name) {
|
||||
FuriString* file_path = furi_string_alloc();
|
||||
furi_string_set(file_path, "/ext/dolphin/name.txt");
|
||||
|
||||
bool result = false;
|
||||
|
||||
//If name is not "eraseerase" (set by Revert) then write name to file
|
||||
//otherwise, remove name.txt
|
||||
|
||||
if(strcmp(name, "eraseerase") != 0) {
|
||||
//save
|
||||
FlipperFormat* file = flipper_format_file_alloc(namechanger->storage);
|
||||
|
||||
do {
|
||||
// Open file for write
|
||||
if(!flipper_format_file_open_always(file, furi_string_get_cstr(file_path))) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Write header
|
||||
if(!flipper_format_write_header_cstr(file, NAMECHANGER_HEADER, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Write comments
|
||||
if(!flipper_format_write_comment_cstr(
|
||||
file, "Changing the value below will change your FlipperZero device name.")) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_comment_cstr(
|
||||
file,
|
||||
"Note: This is limited to 8 characters using the following: a-z, A-Z, 0-9, and _")) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_comment_cstr(
|
||||
file, "It cannot contain any other characters.")) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_write_string_cstr(file, "Name", name)) {
|
||||
break;
|
||||
}
|
||||
|
||||
result = true;
|
||||
} while(false);
|
||||
|
||||
flipper_format_free(file);
|
||||
|
||||
if(!result) {
|
||||
FURI_LOG_E(TAG, "Cannot save name file.");
|
||||
}
|
||||
} else {
|
||||
result = storage_simply_remove(namechanger->storage, furi_string_get_cstr(file_path));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#include <NameChanger_icons.h>
|
||||
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/widget.h>
|
||||
|
||||
#include "namechanger_custom_event.h"
|
||||
#include "scenes/namechanger_scene.h"
|
||||
|
||||
#define NAMECHANGER_TEXT_STORE_SIZE 9
|
||||
#define NAMECHANGER_HEADER "Flipper Name File"
|
||||
|
||||
#define TAG "NameChanger"
|
||||
|
||||
typedef struct {
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
|
||||
Gui* gui;
|
||||
Storage* storage;
|
||||
|
||||
char text_store[NAMECHANGER_TEXT_STORE_SIZE + 1];
|
||||
|
||||
Submenu* submenu;
|
||||
TextInput* text_input;
|
||||
Popup* popup;
|
||||
Widget* widget;
|
||||
} NameChanger;
|
||||
|
||||
typedef enum {
|
||||
NameChangerViewSubmenu,
|
||||
NameChangerViewTextInput,
|
||||
NameChangerViewPopup,
|
||||
NameChangerViewWidget,
|
||||
} NameChangerView;
|
||||
|
||||
bool namechanger_make_app_folder(NameChanger* namechanger);
|
||||
bool namechanger_name_write(NameChanger* namechanger, char* name);
|
||||
void namechanger_text_store_set(NameChanger* namechanger, const char* text, ...);
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
enum NameChangerCustomEvent {
|
||||
NameChangerCustomEventBack,
|
||||
NameChangerCustomEventTextEditResult,
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "namechanger_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const namechanger_on_enter_handlers[])(void*) = {
|
||||
#include "namechanger_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const namechanger_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "namechanger_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const namechanger_on_exit_handlers[])(void* context) = {
|
||||
#include "namechanger_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers namechanger_scene_handlers = {
|
||||
.on_enter_handlers = namechanger_on_enter_handlers,
|
||||
.on_event_handlers = namechanger_on_event_handlers,
|
||||
.on_exit_handlers = namechanger_on_exit_handlers,
|
||||
.scene_num = NameChangerSceneNum,
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) NameChangerScene##id,
|
||||
typedef enum {
|
||||
#include "namechanger_scene_config.h"
|
||||
NameChangerSceneNum,
|
||||
} NameChangerScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers namechanger_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "namechanger_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "namechanger_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "namechanger_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -1,56 +0,0 @@
|
||||
#include "../namechanger.h"
|
||||
|
||||
static void namechanger_scene_change_text_input_callback(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
|
||||
view_dispatcher_send_custom_event(
|
||||
namechanger->view_dispatcher, NameChangerCustomEventTextEditResult);
|
||||
}
|
||||
|
||||
void namechanger_scene_change_on_enter(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
TextInput* text_input = namechanger->text_input;
|
||||
|
||||
namechanger_text_store_set(namechanger, "%s", furi_hal_version_get_name_ptr());
|
||||
|
||||
text_input_set_header_text(text_input, "Set Flipper Name");
|
||||
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
namechanger_scene_change_text_input_callback,
|
||||
namechanger,
|
||||
namechanger->text_store,
|
||||
NAMECHANGER_TEXT_STORE_SIZE,
|
||||
true);
|
||||
|
||||
view_dispatcher_switch_to_view(namechanger->view_dispatcher, NameChangerViewTextInput);
|
||||
}
|
||||
|
||||
bool namechanger_scene_change_on_event(void* context, SceneManagerEvent event) {
|
||||
NameChanger* namechanger = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == NameChangerCustomEventTextEditResult) {
|
||||
if(namechanger_name_write(namechanger, namechanger->text_store)) {
|
||||
scene_manager_next_scene(
|
||||
namechanger->scene_manager, NameChangerSceneChangeSuccess);
|
||||
} else {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
namechanger->scene_manager, NameChangerSceneStart);
|
||||
}
|
||||
} else {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
namechanger->scene_manager, NameChangerSceneStart);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void namechanger_scene_change_on_exit(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
TextInput* text_input = namechanger->text_input;
|
||||
|
||||
text_input_reset(text_input);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#include "../namechanger.h"
|
||||
|
||||
static void namechanger_scene_change_success_popup_callback(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
view_dispatcher_send_custom_event(namechanger->view_dispatcher, NameChangerCustomEventBack);
|
||||
}
|
||||
|
||||
void namechanger_scene_change_success_on_enter(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
Popup* popup = namechanger->popup;
|
||||
|
||||
popup_set_header(popup, "Saved!", 5, 5, AlignLeft, AlignTop);
|
||||
popup_set_text(popup, "Rebooting...", 5, 17, AlignLeft, AlignTop);
|
||||
|
||||
popup_set_callback(popup, namechanger_scene_change_success_popup_callback);
|
||||
popup_set_context(popup, namechanger);
|
||||
popup_set_timeout(popup, 5000);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_dispatcher_switch_to_view(namechanger->view_dispatcher, NameChangerViewPopup);
|
||||
}
|
||||
|
||||
bool namechanger_scene_change_success_on_event(void* context, SceneManagerEvent event) {
|
||||
NameChanger* namechanger = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == NameChangerCustomEventBack) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
namechanger->scene_manager, NameChangerSceneChange);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void namechanger_scene_change_success_on_exit(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
Popup* popup = namechanger->popup;
|
||||
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 0, NULL);
|
||||
|
||||
popup_disable_timeout(popup);
|
||||
popup_set_context(popup, NULL);
|
||||
popup_set_callback(popup, NULL);
|
||||
|
||||
furi_hal_power_reset();
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
ADD_SCENE(namechanger, start, Start)
|
||||
ADD_SCENE(namechanger, change, Change)
|
||||
ADD_SCENE(namechanger, change_success, ChangeSuccess)
|
||||
ADD_SCENE(namechanger, revert, Revert)
|
||||
ADD_SCENE(namechanger, revert_success, RevertSuccess)
|
||||
@@ -1,53 +0,0 @@
|
||||
#include "../namechanger.h"
|
||||
|
||||
static void
|
||||
namechanger_scene_revert_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(namechanger->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void namechanger_scene_revert_on_enter(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
Widget* widget = namechanger->widget;
|
||||
widget_add_text_box_element(
|
||||
widget, 0, 0, 128, 25, AlignCenter, AlignCenter, "\e#Revert Name?\e#", false);
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeLeft, "Cancel", namechanger_scene_revert_widget_callback, namechanger);
|
||||
widget_add_button_element(
|
||||
widget,
|
||||
GuiButtonTypeRight,
|
||||
"Revert",
|
||||
namechanger_scene_revert_widget_callback,
|
||||
namechanger);
|
||||
view_dispatcher_switch_to_view(namechanger->view_dispatcher, NameChangerViewWidget);
|
||||
}
|
||||
|
||||
bool namechanger_scene_revert_on_event(void* context, SceneManagerEvent event) {
|
||||
NameChanger* namechanger = context;
|
||||
bool consumed = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == GuiButtonTypeRight) {
|
||||
if(namechanger_name_write(namechanger, "eraseerase")) {
|
||||
scene_manager_next_scene(
|
||||
namechanger->scene_manager, NameChangerSceneRevertSuccess);
|
||||
} else {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
namechanger->scene_manager, NameChangerSceneStart);
|
||||
}
|
||||
} else if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
namechanger->scene_manager, NameChangerSceneStart);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void namechanger_scene_revert_on_exit(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
widget_reset(namechanger->widget);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#include "../namechanger.h"
|
||||
|
||||
static void namechanger_scene_revert_success_popup_callback(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
view_dispatcher_send_custom_event(namechanger->view_dispatcher, NameChangerCustomEventBack);
|
||||
}
|
||||
|
||||
void namechanger_scene_revert_success_on_enter(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
Popup* popup = namechanger->popup;
|
||||
|
||||
popup_set_header(popup, "Reverted!", 70, 5, AlignLeft, AlignTop);
|
||||
popup_set_text(popup, "Rebooting...", 70, 16, AlignLeft, AlignTop);
|
||||
|
||||
popup_set_callback(popup, namechanger_scene_revert_success_popup_callback);
|
||||
popup_set_context(popup, namechanger);
|
||||
popup_set_timeout(popup, 5000);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_dispatcher_switch_to_view(namechanger->view_dispatcher, NameChangerViewPopup);
|
||||
}
|
||||
|
||||
bool namechanger_scene_revert_success_on_event(void* context, SceneManagerEvent event) {
|
||||
NameChanger* namechanger = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
namechanger->scene_manager, NameChangerSceneStart);
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == NameChangerCustomEventBack) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
namechanger->scene_manager, NameChangerSceneStart);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void namechanger_scene_revert_success_on_exit(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
Popup* popup = namechanger->popup;
|
||||
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 0, NULL);
|
||||
|
||||
popup_disable_timeout(popup);
|
||||
popup_set_context(popup, NULL);
|
||||
popup_set_callback(popup, NULL);
|
||||
|
||||
furi_hal_power_reset();
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
#include "../namechanger.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexChange,
|
||||
SubmenuIndexRevert,
|
||||
};
|
||||
|
||||
void namechanger_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
NameChanger* namechanger = context;
|
||||
view_dispatcher_send_custom_event(namechanger->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void namechanger_scene_start_on_enter(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
Submenu* submenu = namechanger->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Change",
|
||||
SubmenuIndexChange,
|
||||
namechanger_scene_start_submenu_callback,
|
||||
namechanger);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Revert",
|
||||
SubmenuIndexRevert,
|
||||
namechanger_scene_start_submenu_callback,
|
||||
namechanger);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(namechanger->scene_manager, NameChangerSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(namechanger->view_dispatcher, NameChangerViewSubmenu);
|
||||
}
|
||||
|
||||
bool namechanger_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
NameChanger* namechanger = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(
|
||||
namechanger->scene_manager, NameChangerSceneStart, event.event);
|
||||
consumed = true;
|
||||
if(event.event == SubmenuIndexChange) {
|
||||
scene_manager_next_scene(namechanger->scene_manager, NameChangerSceneChange);
|
||||
}
|
||||
if(event.event == SubmenuIndexRevert) {
|
||||
scene_manager_next_scene(namechanger->scene_manager, NameChangerSceneRevert);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void namechanger_scene_start_on_exit(void* context) {
|
||||
NameChanger* namechanger = context;
|
||||
submenu_reset(namechanger->submenu);
|
||||
}
|
||||
@@ -29,11 +29,6 @@ static bool flipp_pomodoro_app_custom_event_callback(void* ctx, uint32_t event)
|
||||
app->view_dispatcher, FlippPomodoroAppCustomEventStateUpdated);
|
||||
return CustomEventConsumed;
|
||||
case FlippPomodoroAppCustomEventStageComplete:
|
||||
if(flipp_pomodoro__get_stage(app->state) == FlippPomodoroStageFocus) {
|
||||
// REGISTER a deed on work stage complete to get an acheivement
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameWin);
|
||||
};
|
||||
|
||||
flipp_pomodoro__toggle_stage(app->state);
|
||||
notification_message(
|
||||
app->notification_app,
|
||||
@@ -98,4 +93,4 @@ int32_t flipp_pomodoro_app(void* p) {
|
||||
flipp_pomodoro_app_free(app);
|
||||
|
||||
return 0;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
@@ -346,8 +345,6 @@ int32_t snake_game_app(void* p) {
|
||||
|
||||
notification_message_block(notification, &sequence_display_backlight_enforce_on);
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
SnakeEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <stdlib.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <furi.h>
|
||||
#include <gui/canvas_i.h>
|
||||
#include "defines.h"
|
||||
@@ -277,7 +276,6 @@ void tick(GameState* game_state, NotificationApp* notification) {
|
||||
if(game_state->state == GameStatePlay) {
|
||||
if(game_state->top_cards[0].character == 11 && game_state->top_cards[1].character == 11 &&
|
||||
game_state->top_cards[2].character == 11 && game_state->top_cards[3].character == 11) {
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameWin);
|
||||
game_state->state = GameStateAnimate;
|
||||
return;
|
||||
}
|
||||
@@ -492,9 +490,6 @@ int32_t solitaire_app(void* p) {
|
||||
|
||||
AppEvent event;
|
||||
|
||||
// Call Dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 150);
|
||||
GameState* localstate = (GameState*)acquire_mutex_block(&state_mutex);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <string.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi_hal_gpio.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define BORDER_OFFSET 1
|
||||
#define MARGIN_OFFSET 3
|
||||
@@ -154,10 +153,6 @@ static void tetris_game_render_callback(Canvas* const canvas, void* ctx) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 4, 63, "Game Over");
|
||||
|
||||
if(tetris_state->numLines % 8 == 0 && tetris_state->numLines != 0) {
|
||||
DOLPHIN_DEED(getRandomDeed());
|
||||
}
|
||||
|
||||
char buffer[13];
|
||||
snprintf(buffer, sizeof(buffer), "Lines: %u", tetris_state->numLines);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
@@ -395,9 +390,6 @@ int32_t tetris_game_app() {
|
||||
Piece* newPiece = malloc(sizeof(Piece));
|
||||
uint8_t downRepeatCounter = 0;
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
for(bool processing = true; processing;) {
|
||||
// This 10U implicitly sets the game loop speed. downRepeatCounter relies on this value
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 10U);
|
||||
@@ -484,4 +476,4 @@ int32_t tetris_game_app() {
|
||||
free(tetris_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <gui/view.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define TAG "TicTacToe"
|
||||
|
||||
@@ -331,9 +330,6 @@ int32_t tictactoe_game_app(void* p) {
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
GameEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
@@ -383,4 +379,4 @@ int32_t tictactoe_game_app(void* p) {
|
||||
free(tictactoe_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
App(
|
||||
# --- App Info
|
||||
appid="wii_ec_anal",
|
||||
name="Wii EC Analyser",
|
||||
name="[GPIO] Wii EC Analyser",
|
||||
# --- Entry point
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="wii_ec_anal",
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
//ORIGINAL REPO: https://github.com/Dooskington/flipperzero-zombiez
|
||||
//AUTHORS: https://github.com/Dooskington | https://github.com/DevMilanIan
|
||||
@@ -314,9 +313,6 @@ int32_t zombiez_game_app(void* p) {
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Call dolphin deed on game start
|
||||
DOLPHIN_DEED(DolphinDeedPluginGameStart);
|
||||
|
||||
PluginEvent event;
|
||||
bool isRunning = true;
|
||||
while(isRunning) {
|
||||
@@ -401,4 +397,4 @@ free_and_exit:
|
||||
furi_message_queue_free(event_queue);
|
||||
|
||||
return return_code;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
|
||||
case DesktopLockMenuEventXtremeSettings:
|
||||
loader_start(desktop->loader, "Xtreme FW", NULL);
|
||||
loader_start(desktop->loader, "Xtreme Settings", NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -40,8 +40,6 @@ static const DolphinDeedWeight dolphin_deed_weights[] = {
|
||||
{1, DolphinAppPlugin}, // DolphinDeedGpioUartBridge
|
||||
|
||||
{1, DolphinAppPlugin}, // DolphinDeedPluginStart
|
||||
{1, DolphinAppPlugin}, // DolphinDeedPluginGameStart
|
||||
{10, DolphinAppPlugin}, // DolphinDeedPluginGameWin
|
||||
};
|
||||
|
||||
static uint8_t dolphin_deed_limits[] = {
|
||||
|
||||
@@ -56,8 +56,6 @@ typedef enum {
|
||||
DolphinDeedGpioUartBridge,
|
||||
|
||||
DolphinDeedPluginStart,
|
||||
DolphinDeedPluginGameStart,
|
||||
DolphinDeedPluginGameWin,
|
||||
|
||||
DolphinDeedMAX,
|
||||
|
||||
|
||||
@@ -13,8 +13,6 @@ void namechanger_on_system_start() {
|
||||
FuriString* NAMEHEADER;
|
||||
NAMEHEADER = furi_string_alloc_set("Flipper Name File");
|
||||
|
||||
FuriString* filepath;
|
||||
filepath = furi_string_alloc_set("/ext/dolphin/name.txt");
|
||||
|
||||
bool result = false;
|
||||
|
||||
@@ -22,7 +20,7 @@ void namechanger_on_system_start() {
|
||||
data = furi_string_alloc();
|
||||
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(file, furi_string_get_cstr(filepath))) {
|
||||
if(!flipper_format_file_open_existing(file, NAMECHANGER_PATH)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -59,7 +57,7 @@ void namechanger_on_system_start() {
|
||||
|
||||
do {
|
||||
// Open file for write
|
||||
if(!flipper_format_file_open_always(file, furi_string_get_cstr(filepath))) {
|
||||
if(!flipper_format_file_open_always(file, NAMECHANGER_PATH)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -109,7 +107,7 @@ void namechanger_on_system_start() {
|
||||
|
||||
do {
|
||||
// Open file for write
|
||||
if(!flipper_format_file_open_always(file, furi_string_get_cstr(filepath))) {
|
||||
if(!flipper_format_file_open_always(file, NAMECHANGER_PATH)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -161,7 +159,6 @@ void namechanger_on_system_start() {
|
||||
|
||||
furi_string_free(data);
|
||||
|
||||
furi_string_free(filepath);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
|
||||
#define NAMECHANGER_TEXT_STORE_SIZE 9
|
||||
#define NAMECHANGER_HEADER "Flipper Name File"
|
||||
#define NAMECHANGER_PATH EXT_PATH("dolphin/name.txt")
|
||||
|
||||
#define TAG "NameChangerSRV"
|
||||
|
||||
@@ -5,7 +5,6 @@ App(
|
||||
provides=[
|
||||
"passport",
|
||||
"system_settings",
|
||||
"xtreme_app",
|
||||
"about",
|
||||
],
|
||||
)
|
||||
|
||||
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1 @@
|
||||
3
|
||||
@@ -1,44 +0,0 @@
|
||||
## What a Firmware Target is
|
||||
|
||||
Flipper's firmware is modular and supports different hardware configurations in a common code base. It encapsulates hardware-specific differences in `furi_hal`, board initialization code, linker files, SDK data and other information in a _target definition_.
|
||||
|
||||
Target-specific files are placed in a single sub-folder in `firmware/targets`. It must contain a target definition file, `target.json`, and may contain other files if they are referenced by current target's definition. By default, `fbt` gathers all source files in target folder, unless they are explicitly excluded.
|
||||
|
||||
Targets can inherit most code parts from other targets, to reduce common code duplication.
|
||||
|
||||
|
||||
## Target Definition File
|
||||
|
||||
A target definition file, `target.json`, is a JSON file that can contain the following fields:
|
||||
|
||||
* `include_paths`: list of strings, folder paths relative to current target folder to add to global C/C++ header path lookup list.
|
||||
* `sdk_header_paths`: list of strings, folder paths relative to current target folder to gather headers from for including in SDK.
|
||||
* `startup_script`: filename of a startup script, performing initial hardware initialization.
|
||||
* `linker_script_flash`: filename of a linker script for creating the main firmware image.
|
||||
* `linker_script_ram`: filename of a linker script to use in "updater" build configuration.
|
||||
* `linker_script_app`: filename of a linker script to use for linking .fap files.
|
||||
* `sdk_symbols`: filename of a .csv file containing current SDK configuration for this target.
|
||||
* `linker_dependencies`: list of libraries to link the firmware with. Note that those not in the list won't be built by `fbt`. Also several link passes might be needed, in such case you may need to specify same library name twice.
|
||||
* `inherit`: string, specifies hardware target to borrow main configuration from. Current configuration may specify additional values for parameters that are lists of strings, or override values that are not lists.
|
||||
* `excluded_sources`: list of filenames from the inherited configuration(s) NOT to be built.
|
||||
* `excluded_headers`: list of headers from the inherited configuration(s) NOT to be included in generated SDK.
|
||||
* `excluded_modules`: list of strings specifying fbt library (module) names to exclude from being used to configure build environment.
|
||||
|
||||
|
||||
## Applications & Hardware
|
||||
|
||||
Not all applications are available on different hardware targets.
|
||||
|
||||
* For applications built into the firmware, you have to specify a compatible application set using `FIRMWARE_APP_SET=...` fbt option. See [fbt docs](./fbt.md#firmware-application-set) for details on build configurations.
|
||||
|
||||
* For applications built as external .faps, you have to explicitly specify compatible targets in application's manifest, `application.fam`. For example, to limit application to a single target, add `targets=["f7"],` to the manifest. It won't be built for other targets.
|
||||
|
||||
For details on application manifests, check out [their docs page](./AppManifests.md).
|
||||
|
||||
|
||||
## Building Firmware for a Specific Target
|
||||
|
||||
You have to specify TARGET_HW (and, optionally, FIRMWARE_APP_SET) for `fbt` to build firmware for non-default target. For example, building and flashing debug firmware for f18 can be done with
|
||||
|
||||
./fbt TARGET_HW=18 flash_usb_full
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
# Infrared Captures
|
||||
|
||||
**Credits go to @gsurkov, @skotopes, @knrn-ai, @DrZlo13 and @ahumeniy for making and contributing to the original `UniversalRemotes.md` Documentation located [Here](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/UniversalRemotes.md).**
|
||||
|
||||
**slightly adapted by @amec0e**
|
||||
|
||||
## Televisions, Fans, Audio and Projectors
|
||||
|
||||
Each signal is recorded using the following process:
|
||||
|
||||
1. Get the remote and point it to Flipper's IR receiver.
|
||||
2. Start learning a new remote if it's the first button or press `+` to add a new button otherwise.
|
||||
3. Do a Quick Press of a remote button and save it under a corresponding name. **(NOTE: Don't hold the remote button down, this will result in long captures and long playbacks ultimately slowing down the universal remotes performance)**
|
||||
4. Repeat steps 2-3 until all required signals are saved.
|
||||
|
||||
The signal names are self-explanatory. Remember to make sure that every recorded signal does what it's supposed to.
|
||||
|
||||
**NOTE:** It's possible some devices around you will cause interference and may force your capture into raw data instead of a parsed code.
|
||||
If you notice you get a parsed code when capturing it's best to click "Retry" a few times on the flipper when capturing to ensure the device is not suffering from any interference, and that the cleanest capture is possible.
|
||||
|
||||
## Types of data
|
||||
|
||||
**Parsed data**
|
||||
|
||||
This is the cleanest type of data because it means it is a recognised code.
|
||||
|
||||
```
|
||||
name: EXAMPLE
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 07 00 00 00
|
||||
command: 02 00 00 00
|
||||
```
|
||||
|
||||
**Raw Data**
|
||||
|
||||
With raw data its important not to hold the remotes button down when capturing on your flipper as this increases not only the size of the capture but the repeats and also how long it takes to send the signal back. Below is an ideal button capture.
|
||||
|
||||
```
|
||||
#
|
||||
name: EXAMPLE
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2410 597 1189 599 592 600 1186 602 589 603 1183 606 595 597 593 598 1208 605 596 596 594 597 593 599 592 25604 2403 604 1182 606 595 597 1189 599 591 601 1185 603 618 573 617 575 1211 602 588 603 588 605 596 596 594 25605 2402 604 1192 596 594 597 1189 599 592 601 1185 628 593 598 593 600 1186 602 589 603 588 604 597 595 596
|
||||
```
|
||||
|
||||
**Capturing Raw Data:**
|
||||
|
||||
If you are sure your remote is using raw data the best way to capture it will be to do a quick button press **(don't hold the remotes button down)** and look at how many samples you get, the general idea here is to get the lowest amount of raw data samples captured (around 100 samples is about right) while making sure that the playback on the device is still working. This is usually accomplished by doing a quick button press on the remote when capturing.
|
||||
|
||||
## Air Conditioners
|
||||
|
||||
Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote.
|
||||
The majority of A/C remotes have a small display that shows the current mode, temperature, and other settings.
|
||||
When the user presses a button, a whole set of parameters is transmitted to the device, which must be recorded and used as a whole.
|
||||
|
||||
In order to capture a particular air conditioner, there is a particular process require to capturing and this is done using the following process:
|
||||
|
||||
1. Get the remote and press the **Power Button** so that the display shows that A/C is ON.
|
||||
2. Set the A/C to the corresponding mode (see table below), leaving other parameters such as fan speed or vane on **AUTO** (if applicable).
|
||||
3. Press the **POWER** button to switch the A/C off.
|
||||
4. Start learning a new remote on Flipper if it's the first button or press `+` to add a new button otherwise.
|
||||
5. Point the remote to Flipper's IR receiver as directed and press **POWER** button once again.
|
||||
6. Save the resulting signal under the specified name.
|
||||
7. Repeat steps 2-6 for each signal from the table below.
|
||||
|
||||
| Signal | Mode | Temperature | Note |
|
||||
| :-----: | :--------: | :---------: | ----------------------------------- |
|
||||
| Dh | Dehumidify | N/A | |
|
||||
| Cool_hi | Cooling | See note | Lowest temperature in cooling mode |
|
||||
| Cool_lo | Cooling | 23°C | |
|
||||
| Heat_hi | Heating | See note | Highest temperature in heating mode |
|
||||
| Heat_lo | Heating | 23°C | |
|
||||
|
||||
Finally, record the `Off` signal:
|
||||
|
||||
1. Make sure the display shows that the A/C is ON.
|
||||
2. Start learning a new signal on Flipper and point the remote towards the IR receiver.
|
||||
3. Press the **POWER** button so that the remote shows the OFF state.
|
||||
4. Save the resulting signal under the name `Off`.
|
||||
|
||||
Test the file against the actual device. Make sure that every signal does what it's supposed to.
|
||||
@@ -0,0 +1,7 @@
|
||||
# Flipper Zero / Xtreme Firmware documentation
|
||||
|
||||
For some general information on Flipper Zero, check out [our wiki](https://github.com/ClaraCrazy/Flipper-Xtreme/wiki)!
|
||||
It includes some useful [Generic Guides](https://github.com/ClaraCrazy/Flipper-Xtreme/wiki/Generic-Guides) for Flipper's main functions.
|
||||
It also features an in-depth look at one of our most exclusive features: [Asset Packs](https://github.com/ClaraCrazy/Flipper-Xtreme/wiki/Asset-Packs).
|
||||
|
||||
If you instead are looking for some very detailed description of Flipper's ecosystem, OS, tools and file formats, please have a look at [Unleashed's documentation](https://github.com/DarkFlippers/unleashed-firmware/tree/dev/documentation)!
|
||||
@@ -1,76 +0,0 @@
|
||||
# Universal Remotes
|
||||
|
||||
## Televisions
|
||||
|
||||
Adding your TV set to the universal remote is quite straightforward. Up to 6 signals can be recorded: `Power`, `Mute`, `Vol_up`, `Vol_dn`, `Ch_next`, and `Ch_prev`. Any of them can be omitted if not supported by your TV.
|
||||
|
||||
Each signal is recorded using the following algorithm:
|
||||
|
||||
1. Get the remote and point it to Flipper's IR receiver.
|
||||
2. Start learning a new remote if it's the first button or press `+` to add a new button otherwise.
|
||||
3. Press a remote button and save it under a corresponding name.
|
||||
4. Repeat steps 2-3 until all required signals are saved.
|
||||
|
||||
The signal names are self-explanatory. Remember to make sure that every recorded signal does what it's supposed to.
|
||||
|
||||
If everything checks out, append these signals **to the end** of the [TV universal remote file](/assets/resources/infrared/assets/tv.ir).
|
||||
|
||||
## Audio players
|
||||
|
||||
Adding your audio player to the universal remote is done in the same manner as described above. Up to 8 signals can be recorded: `Power`, `Play`, `Pause`, `Vol_up`, `Vol_dn`, `Next`, `Prev`, and `Mute`. Any of them can be omitted if not supported by the player.
|
||||
|
||||
The signal names are self-explanatory.
|
||||
On many remotes, the `Play` button doubles as `Pause`. In this case, record it as `Play` omitting the `Pause`.
|
||||
Make sure that every signal does what it's supposed to.
|
||||
|
||||
If everything checks out, append these signals **to the end** of the [audio player universal remote file](/assets/resources/infrared/assets/audio.ir).
|
||||
|
||||
## Projectors
|
||||
|
||||
Adding your projector to the universal remote is really simple. Up to 4 signals can be recorded: `Power`, `Mute`, `Vol_up`, `Vol_dn`. Any of them can be omitted if not supported by your projector.
|
||||
To save time, please make sure every recording has been named accordingly.
|
||||
In case of omitting, on most projectors with the 4 following buttons, you should not have a problem.
|
||||
|
||||
|
||||
## Air conditioners
|
||||
|
||||
Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote.
|
||||
The majority of A/C remotes have a small display that shows the current mode, temperature, and other settings.
|
||||
When the user presses a button, a whole set of parameters is transmitted to the device, which must be recorded and used as a whole.
|
||||
|
||||
In order to add a particular air conditioner to the universal remote, 6 signals must be recorded: `Off`, `Dh`, `Cool_hi`, `Cool_lo`, `Heat_hi`, and `Heat_lo`.
|
||||
Each signal (except `Off`) is recorded using the following algorithm:
|
||||
|
||||
1. Get the remote and press the **Power Button** so that the display shows that A/C is ON.
|
||||
2. Set the A/C to the corresponding mode (see table below), leaving other parameters such as fan speed or vane on **AUTO** (if applicable).
|
||||
3. Press the **POWER** button to switch the A/C off.
|
||||
4. Start learning a new remote on Flipper if it's the first button or press `+` to add a new button otherwise.
|
||||
5. Point the remote to Flipper's IR receiver as directed and press **POWER** button once again.
|
||||
6. Save the resulting signal under the specified name.
|
||||
7. Repeat steps 2-6 for each signal from the table below.
|
||||
|
||||
| Signal | Mode | Temperature | Note |
|
||||
| :-----: | :--------: | :---------: | ----------------------------------- |
|
||||
| Dh | Dehumidify | N/A | |
|
||||
| Cool_hi | Cooling | See note | Lowest temperature in cooling mode |
|
||||
| Cool_lo | Cooling | 23°C | |
|
||||
| Heat_hi | Heating | See note | Highest temperature in heating mode |
|
||||
| Heat_lo | Heating | 23°C | |
|
||||
|
||||
Finally, record the `Off` signal:
|
||||
|
||||
1. Make sure the display shows that the A/C is ON.
|
||||
2. Start learning a new signal on Flipper and point the remote towards the IR receiver.
|
||||
3. Press the **POWER** button so that the remote shows the OFF state.
|
||||
4. Save the resulting signal under the name `Off`.
|
||||
|
||||
The resulting remote file should now contain 6 signals. You can omit any of them, but you then won't be able to use their functionality.
|
||||
Test the file against the actual device. Make sure that every signal does what it's supposed to.
|
||||
|
||||
If everything checks out, append these signals **to the end** of the [A/C universal remote file](/assets/resources/infrared/assets/ac.ir).
|
||||
|
||||
## Final steps
|
||||
|
||||
The order of signals is not important, but they should be preceded by the following comment: `# Model: <Your model name>` in order to keep the library organized.
|
||||
|
||||
When done, open a pull request containing the changed file.
|
||||