Merge branch 'Next-Flip:dev' into dev

This commit is contained in:
Zachary Weiss
2024-04-09 22:07:10 -04:00
committed by GitHub
180 changed files with 1634 additions and 1441 deletions

View File

@@ -7,8 +7,6 @@ on:
- "Build"
- "Lint"
- "Release"
- "SonarCloud"
- "Submodules"
types:
- "completed"
issues:

3
.gitmodules vendored
View File

@@ -44,3 +44,6 @@
[submodule "documentation/doxygen/doxygen-awesome-css"]
path = documentation/doxygen/doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git
[submodule "lib/tlsf"]
path = lib/tlsf
url = https://github.com/espressif/tlsf

View File

@@ -1 +1 @@
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e lib/mjs -e */arm-none-eabi/*
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/tlsf -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e lib/mjs -e */arm-none-eabi/*

View File

@@ -230,6 +230,7 @@ firmware_debug = distenv.PhonyTarget(
source=firmware_env["FW_ELF"],
GDBOPTS="${GDBOPTS_BASE}",
GDBREMOTE="${OPENOCD_GDB_PIPE}",
FBT_FAP_DEBUG_ELF_ROOT=firmware_env["FBT_FAP_DEBUG_ELF_ROOT"],
)
distenv.Depends(firmware_debug, firmware_flash)
@@ -239,6 +240,7 @@ distenv.PhonyTarget(
source=firmware_env["FW_ELF"],
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
GDBREMOTE="${BLACKMAGIC_ADDR}",
FBT_FAP_DEBUG_ELF_ROOT=firmware_env["FBT_FAP_DEBUG_ELF_ROOT"],
)
# Debug alien elf

View File

@@ -19,7 +19,7 @@ bool file_browser_scene_start_on_event(void* context, SceneManagerEvent event) {
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
furi_string_set(app->file_path, ANY_PATH("badusb/demo_windows.txt"));
furi_string_set(app->file_path, ANY_PATH("badusb/Demos/demo_windows.txt"));
scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser);
consumed = true;
} else if(event.type == SceneManagerEventTypeTick) {

View File

@@ -4,11 +4,11 @@
#include "../minunit.h"
// v2 tests
void test_furi_create_open();
void test_furi_concurrent_access();
void test_furi_pubsub();
void test_furi_create_open(void);
void test_furi_concurrent_access(void);
void test_furi_pubsub(void);
void test_furi_memmgr();
void test_furi_memmgr(void);
static int foo = 0;

View File

@@ -8,31 +8,31 @@
#define TAG "UnitTests"
int run_minunit_test_furi();
int run_minunit_test_furi_hal();
int run_minunit_test_furi_hal_crypto();
int run_minunit_test_furi_string();
int run_minunit_test_infrared();
int run_minunit_test_rpc();
int run_minunit_test_manifest();
int run_minunit_test_flipper_format();
int run_minunit_test_flipper_format_string();
int run_minunit_test_stream();
int run_minunit_test_storage();
int run_minunit_test_subghz();
int run_minunit_test_dirwalk();
int run_minunit_test_power();
int run_minunit_test_protocol_dict();
int run_minunit_test_lfrfid_protocols();
int run_minunit_test_nfc();
int run_minunit_test_bit_lib();
int run_minunit_test_datetime();
int run_minunit_test_float_tools();
int run_minunit_test_bt();
int run_minunit_test_dialogs_file_browser_options();
int run_minunit_test_expansion();
int run_minunit_test_furi(void);
int run_minunit_test_furi_hal(void);
int run_minunit_test_furi_hal_crypto(void);
int run_minunit_test_furi_string(void);
int run_minunit_test_infrared(void);
int run_minunit_test_rpc(void);
int run_minunit_test_manifest(void);
int run_minunit_test_flipper_format(void);
int run_minunit_test_flipper_format_string(void);
int run_minunit_test_stream(void);
int run_minunit_test_storage(void);
int run_minunit_test_subghz(void);
int run_minunit_test_dirwalk(void);
int run_minunit_test_power(void);
int run_minunit_test_protocol_dict(void);
int run_minunit_test_lfrfid_protocols(void);
int run_minunit_test_nfc(void);
int run_minunit_test_bit_lib(void);
int run_minunit_test_datetime(void);
int run_minunit_test_float_tools(void);
int run_minunit_test_bt(void);
int run_minunit_test_dialogs_file_browser_options(void);
int run_minunit_test_expansion(void);
typedef int (*UnitTestEntry)();
typedef int (*UnitTestEntry)(void);
typedef struct {
const char* name;

View File

@@ -183,6 +183,14 @@ static bool subghz_device_cc1101_ext_check_init(void) {
furi_hal_gpio_init(
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
// Reset GDO2 (!TX/RX) to floating state
cc1101_status = cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
if(cc1101_status.CHIP_RDYn != 0) {
//timeout or error
break;
}
// Go to sleep
cc1101_status = cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle);
if(cc1101_status.CHIP_RDYn != 0) {
@@ -230,10 +238,7 @@ bool subghz_device_cc1101_ext_alloc(SubGhzDeviceConf* conf) {
&furi_hal_spi_bus_handle_external_extra);
// this is needed if multiple SPI devices are connected to the same bus but with different CS pins
if(momentum_settings.spi_cc1101_handle == SpiDefault && !furi_hal_subghz_get_ext_power_amp()) {
furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeOutputPushPull);
furi_hal_gpio_write(&gpio_ext_pc3, true);
} else if(momentum_settings.spi_cc1101_handle == SpiExtra) {
if(momentum_settings.spi_cc1101_handle == SpiExtra) {
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
furi_hal_gpio_write(&gpio_ext_pa4, true);
}
@@ -430,6 +435,9 @@ void subghz_device_cc1101_ext_reset(void) {
// Warning: push pull cc1101 clock output on GD0
cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
// Reset GDO2 (!TX/RX) to floating state
cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
@@ -439,6 +447,9 @@ void subghz_device_cc1101_ext_idle(void) {
//waiting for the chip to switch to IDLE mode
furi_check(cc1101_wait_status_state(
subghz_device_cc1101_ext->spi_bus_handle, CC1101StateIDLE, 10000));
// Reset GDO2 (!TX/RX) to floating state
cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(subghz_device_cc1101_ext->power_amp) {
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07M20S_AMP_GPIO, 0);
@@ -451,6 +462,10 @@ void subghz_device_cc1101_ext_rx(void) {
//waiting for the chip to switch to Rx mode
furi_check(
cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateRX, 10000));
// Go GDO2 (!TX/RX) to high (RX state)
cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(subghz_device_cc1101_ext->power_amp) {
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07M20S_AMP_GPIO, 0);
@@ -464,6 +479,8 @@ bool subghz_device_cc1101_ext_tx(void) {
//waiting for the chip to switch to Tx mode
furi_check(
cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateTX, 10000));
// Go GDO2 (!TX/RX) to low (TX state)
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(subghz_device_cc1101_ext->power_amp) {
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07M20S_AMP_GPIO, 1);

View File

@@ -46,7 +46,7 @@ static bool archive_favorites_read_line(File* file, FuriString* str_result) {
return result;
}
uint16_t archive_favorites_count() {
uint16_t archive_favorites_count(void) {
Storage* fs_api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(fs_api);

View File

@@ -5,7 +5,7 @@
#define ARCHIVE_FAV_PATH ANY_PATH("favorites.txt")
#define ARCHIVE_FAV_TEMP_PATH ANY_PATH("favorites.tmp")
uint16_t archive_favorites_count();
uint16_t archive_favorites_count(void);
bool archive_favorites_read(void* context);
bool archive_favorites_delete(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2)));
bool archive_is_favorite(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2)));

View File

@@ -36,7 +36,13 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder
txt_path = archive_get_default_path(ArchiveTabBadKb);
break;
}
if(txt_path != NULL && furi_string_start_with_str(file->path, txt_path)) {
if(txt_path != NULL) {
size_t len = strlen(txt_path);
if(furi_string_size(file->path) < len) continue;
// Compare but ignore /ext or /any, continue if different (memcmp() != 0)
if(memcmp(furi_string_get_cstr(file->path) + 4, txt_path + 4, len - 4)) {
continue;
}
file->type = i;
return;
}

View File

@@ -15,8 +15,10 @@ void lfrfid_scene_read_success_on_enter(void* context) {
} else {
furi_string_printf(display_text, "\e#%s\e#", protocol);
}
widget_add_text_box_element(
widget, 16, 2, 112, 14, AlignLeft, AlignTop, furi_string_get_cstr(display_text), true);
furi_string_cat(display_text, "\nHex: ");
furi_string_set(display_text, "Hex: ");
const size_t data_size = protocol_dict_get_data_size(app->dict, app->protocol_id);
uint8_t* data = malloc(data_size);
@@ -40,7 +42,7 @@ void lfrfid_scene_read_success_on_enter(void* context) {
furi_string_free(rendered_data);
widget_add_text_box_element(
widget, 0, 0, 128, 52, AlignLeft, AlignTop, furi_string_get_cstr(display_text), true);
widget, 0, 16, 128, 52, AlignLeft, AlignTop, furi_string_get_cstr(display_text), true);
widget_add_button_element(widget, GuiButtonTypeLeft, "Retry", lfrfid_widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "More", lfrfid_widget_callback, app);

View File

@@ -36,7 +36,7 @@ void lfrfid_scene_save_name_on_enter(void* context) {
LFRFID_TEXT_STORE_SIZE,
key_name_is_empty);
FURI_LOG_I("", "%s %s", furi_string_get_cstr(folder_path), app->text_store);
FURI_LOG_D("", "%s %s", furi_string_get_cstr(folder_path), app->text_store);
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
furi_string_get_cstr(folder_path),

View File

@@ -18,6 +18,7 @@ ADD_SCENE(momentum_app, misc, Misc)
ADD_SCENE(momentum_app, misc_screen, MiscScreen)
ADD_SCENE(momentum_app, misc_screen_color, MiscScreenColor)
ADD_SCENE(momentum_app, misc_dolphin, MiscDolphin)
ADD_SCENE(momentum_app, misc_spoof, MiscSpoof)
ADD_SCENE(momentum_app, misc_spoof_name, MiscSpoofName)
ADD_SCENE(momentum_app, misc_vgm, MiscVgm)
ADD_SCENE(momentum_app, misc_vgm_color, MiscVgmColor)
ADD_SCENE(momentum_app, misc_rename, MiscRename)

View File

@@ -3,8 +3,8 @@
enum VarItemListIndex {
VarItemListIndexScreen,
VarItemListIndexDolphin,
VarItemListIndexSpoof,
VarItemListIndexVgm,
VarItemListIndexChangeDeviceName,
VarItemListIndexChargeCap,
VarItemListIndexShowMomentumIntro,
};
@@ -37,10 +37,11 @@ void momentum_app_scene_misc_on_enter(void* context) {
item = variable_item_list_add(var_item_list, "Dolphin", 0, NULL, app);
variable_item_set_current_value_text(item, ">");
item = variable_item_list_add(var_item_list, "VGM Options", 0, NULL, app);
item = variable_item_list_add(var_item_list, "Spoofing Options", 0, NULL, app);
variable_item_set_current_value_text(item, ">");
variable_item_list_add(var_item_list, "Change Device Name", 0, NULL, app);
item = variable_item_list_add(var_item_list, "VGM Options", 0, NULL, app);
variable_item_set_current_value_text(item, ">");
char cap_str[6];
value_index = momentum_settings.charge_cap / CHARGE_CAP_INTV;
@@ -81,14 +82,14 @@ bool momentum_app_scene_misc_on_event(void* context, SceneManagerEvent event) {
scene_manager_set_scene_state(app->scene_manager, MomentumAppSceneMiscDolphin, 0);
scene_manager_next_scene(app->scene_manager, MomentumAppSceneMiscDolphin);
break;
case VarItemListIndexSpoof:
scene_manager_set_scene_state(app->scene_manager, MomentumAppSceneMiscSpoof, 0);
scene_manager_next_scene(app->scene_manager, MomentumAppSceneMiscSpoof);
break;
case VarItemListIndexVgm:
scene_manager_set_scene_state(app->scene_manager, MomentumAppSceneMiscVgm, 0);
scene_manager_next_scene(app->scene_manager, MomentumAppSceneMiscVgm);
break;
case VarItemListIndexChangeDeviceName:
scene_manager_set_scene_state(app->scene_manager, MomentumAppSceneMiscRename, 0);
scene_manager_next_scene(app->scene_manager, MomentumAppSceneMiscRename);
break;
case VarItemListIndexShowMomentumIntro: {
for(int i = 0; i < 10; i++) {
if(storage_common_copy(

View File

@@ -0,0 +1,77 @@
#include "../momentum_app.h"
enum VarItemListIndex {
VarItemListIndexFlipperName, // TODO: Split into name, mac, serial
VarItemListIndexShellColor,
};
const char* const shell_color_names[FuriHalVersionColorCount] = {
"Real",
"Black",
"White",
"Transparent",
};
static void momentum_app_scene_misc_spoof_shell_color_changed(VariableItem* item) {
MomentumApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, shell_color_names[index]);
momentum_settings.spoof_color = index;
app->save_settings = true;
app->require_reboot = true;
}
void momentum_app_scene_misc_spoof_var_item_list_callback(void* context, uint32_t index) {
MomentumApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void momentum_app_scene_misc_spoof_on_enter(void* context) {
MomentumApp* app = context;
VariableItemList* var_item_list = app->var_item_list;
VariableItem* item;
item = variable_item_list_add(var_item_list, "Flipper Name", 0, NULL, app);
variable_item_set_current_value_text(item, app->device_name);
item = variable_item_list_add(
var_item_list,
"Shell Color",
FuriHalVersionColorCount,
momentum_app_scene_misc_spoof_shell_color_changed,
app);
variable_item_set_current_value_index(item, momentum_settings.spoof_color);
variable_item_set_current_value_text(item, shell_color_names[momentum_settings.spoof_color]);
variable_item_list_set_enter_callback(
var_item_list, momentum_app_scene_misc_spoof_var_item_list_callback, app);
variable_item_list_set_selected_item(
var_item_list,
scene_manager_get_scene_state(app->scene_manager, MomentumAppSceneMiscSpoof));
view_dispatcher_switch_to_view(app->view_dispatcher, MomentumAppViewVarItemList);
}
bool momentum_app_scene_misc_spoof_on_event(void* context, SceneManagerEvent event) {
MomentumApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(app->scene_manager, MomentumAppSceneMiscSpoof, event.event);
consumed = true;
switch(event.event) {
case VarItemListIndexFlipperName:
scene_manager_next_scene(app->scene_manager, MomentumAppSceneMiscSpoofName);
break;
default:
break;
}
}
return consumed;
}
void momentum_app_scene_misc_spoof_on_exit(void* context) {
MomentumApp* app = context;
variable_item_list_reset(app->var_item_list);
}

View File

@@ -4,7 +4,7 @@ enum TextInputIndex {
TextInputResultOk,
};
static void momentum_app_scene_misc_rename_text_input_callback(void* context) {
static void momentum_app_scene_misc_spoof_name_text_input_callback(void* context) {
MomentumApp* app = context;
app->save_name = true;
@@ -12,8 +12,10 @@ static void momentum_app_scene_misc_rename_text_input_callback(void* context) {
view_dispatcher_send_custom_event(app->view_dispatcher, TextInputResultOk);
}
static bool
momentum_app_scene_misc_rename_validator(const char* text, FuriString* error, void* context) {
static bool momentum_app_scene_misc_spoof_name_validator(
const char* text,
FuriString* error,
void* context) {
UNUSED(context);
for(; *text; ++text) {
@@ -27,19 +29,19 @@ static bool
return true;
}
void momentum_app_scene_misc_rename_on_enter(void* context) {
void momentum_app_scene_misc_spoof_name_on_enter(void* context) {
MomentumApp* app = context;
TextInput* text_input = app->text_input;
text_input_set_header_text(text_input, "Leave empty for default");
text_input_set_header_text(text_input, "Leave empty for real name");
text_input_set_validator(text_input, momentum_app_scene_misc_rename_validator, NULL);
text_input_set_validator(text_input, momentum_app_scene_misc_spoof_name_validator, NULL);
text_input_set_minimum_length(text_input, 0);
text_input_set_result_callback(
text_input,
momentum_app_scene_misc_rename_text_input_callback,
momentum_app_scene_misc_spoof_name_text_input_callback,
app,
app->device_name,
FURI_HAL_VERSION_ARRAY_NAME_LENGTH,
@@ -48,7 +50,7 @@ void momentum_app_scene_misc_rename_on_enter(void* context) {
view_dispatcher_switch_to_view(app->view_dispatcher, MomentumAppViewTextInput);
}
bool momentum_app_scene_misc_rename_on_event(void* context, SceneManagerEvent event) {
bool momentum_app_scene_misc_spoof_name_on_event(void* context, SceneManagerEvent event) {
MomentumApp* app = context;
bool consumed = false;
@@ -66,7 +68,7 @@ bool momentum_app_scene_misc_rename_on_event(void* context, SceneManagerEvent ev
return consumed;
}
void momentum_app_scene_misc_rename_on_exit(void* context) {
void momentum_app_scene_misc_spoof_name_on_exit(void* context) {
MomentumApp* app = context;
text_input_reset(app->text_input);
}

View File

@@ -247,6 +247,8 @@ static void nfc_scene_read_success_on_enter_mf_ultralight(NfcApp* instance) {
furi_string_cat_printf(
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
furi_string_replace(temp_str, "Mifare", "MIFARE");
nfc_render_mf_ultralight_info(data, NfcProtocolFormatTypeShort, temp_str);
}

View File

@@ -574,7 +574,7 @@ static void nfc_protocol_support_scene_emulate_on_enter(NfcApp* instance) {
FuriString* temp_str = furi_string_alloc();
const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device);
widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_51x64);
widget_add_icon_element(widget, 0, 0, &I_NFC_dolphin_emulation_51x64);
if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateUid)) {
widget_add_string_element(

View File

@@ -20,8 +20,8 @@ static AllInOneLayoutType all_in_one_get_layout(const MfUltralightData* data) {
const uint8_t layout_byte = data->page[5].data[2];
const uint8_t layout_half_byte = data->page[5].data[2] & 0x0F;
FURI_LOG_I(TAG, "Layout byte: %02x", layout_byte);
FURI_LOG_I(TAG, "Layout half-byte: %02x", layout_half_byte);
FURI_LOG_D(TAG, "Layout byte: %02x", layout_byte);
FURI_LOG_D(TAG, "Layout half-byte: %02x", layout_half_byte);
switch(layout_half_byte) {
// If it is A, the layout type is a type A layout
@@ -32,7 +32,7 @@ static AllInOneLayoutType all_in_one_get_layout(const MfUltralightData* data) {
case 0x02:
return AllInOneLayoutType2;
default:
FURI_LOG_I(TAG, "Unknown layout type: %d", layout_half_byte);
FURI_LOG_E(TAG, "Unknown layout type: %d", layout_half_byte);
return AllInOneLayoutTypeUnknown;
}
}
@@ -47,7 +47,7 @@ static bool all_in_one_parse(const NfcDevice* device, FuriString* parsed_data) {
do {
if(data->page[4].data[0] != 0x45 || data->page[4].data[1] != 0xD9) {
FURI_LOG_I(TAG, "Pass not verified");
FURI_LOG_E(TAG, "Pass not verified");
break;
}
@@ -63,7 +63,7 @@ static bool all_in_one_parse(const NfcDevice* device, FuriString* parsed_data) {
// If the layout is D, the ride count is stored in the second byte of page 9
ride_count = data->page[9].data[1];
} else {
FURI_LOG_I(TAG, "Unknown layout: %d", layout_type);
FURI_LOG_E(TAG, "Unknown layout: %d", layout_type);
ride_count = 137;
}

View File

@@ -82,7 +82,7 @@ void from_minutes_to_datetime(uint32_t minutes, DateTime* datetime, uint16_t sta
bool parse_transport_block(const MfClassicBlock* block, FuriString* result) {
uint16_t transport_departament = bit_lib_get_bits_16(block->data, 0, 10);
FURI_LOG_I(TAG, "Transport departament: %x", transport_departament);
FURI_LOG_D(TAG, "Transport departament: %x", transport_departament);
uint16_t layout_type = bit_lib_get_bits_16(block->data, 52, 4);
if(layout_type == 0xE) {
@@ -91,7 +91,7 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) {
layout_type = bit_lib_get_bits_16(block->data, 52, 14);
}
FURI_LOG_I(TAG, "Layout type %x", layout_type);
FURI_LOG_D(TAG, "Layout type %x", layout_type);
uint16_t card_view = 0;
uint16_t card_type = 0;

View File

@@ -20,12 +20,17 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) {
uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
if(nfc_device_get_protocol(nfc->nfc_device) == NfcProtocolMfUltralight) {
submenu_add_item(
submenu,
"Unlock With Reader",
SubmenuIndexMfUlUnlockMenuReader,
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
nfc);
const MfUltralightData* mfu_data =
nfc_device_get_data(nfc->nfc_device, NfcProtocolMfUltralight);
// Hide for MFU-C since it uses 3DES
if(mfu_data->type != MfUltralightTypeMfulC) {
submenu_add_item(
submenu,
"Unlock With Reader",
SubmenuIndexMfUlUnlockMenuReader,
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
nfc);
}
}
submenu_add_item(
submenu,

View File

@@ -1,7 +1,6 @@
#include "subghz_gps.h"
#include "minmea.h"
#include <expansion/expansion.h>
#include <momentum/momentum.h>
#define UART_CH (momentum_settings.uart_nmea_channel)
@@ -128,15 +127,13 @@ static int32_t subghz_gps_uart_worker(void* context) {
static void subghz_gps_deinit(SubGhzGPS* subghz_gps) {
furi_assert(subghz_gps);
furi_thread_flags_set(furi_thread_get_id(subghz_gps->thread), WorkerEvtStop);
furi_thread_join(subghz_gps->thread);
furi_hal_serial_async_rx_stop(subghz_gps->serial_handle);
furi_hal_serial_deinit(subghz_gps->serial_handle);
furi_hal_serial_control_release(subghz_gps->serial_handle);
expansion_enable(furi_record_open(RECORD_EXPANSION));
furi_record_close(RECORD_EXPANSION);
furi_thread_flags_set(furi_thread_get_id(subghz_gps->thread), WorkerEvtStop);
furi_thread_join(subghz_gps->thread);
furi_thread_free(subghz_gps->thread);
furi_stream_buffer_free(subghz_gps->rx_stream);
@@ -162,7 +159,7 @@ static float subghz_gps_calc_angle(float lat1, float lon1, float lat2, float lon
return atan2(lat1 - lat2, lon1 - lon2) * 180 / (double)M_PI;
}
static void subghz_gps_get_descr(
static void subghz_gps_cat_realtime(
SubGhzGPS* subghz_gps,
FuriString* descr,
float latitude,
@@ -192,16 +189,11 @@ static void subghz_gps_get_descr(
angle_str = "W";
}
furi_string_printf(
furi_string_cat_printf(
descr,
"Captured at: %f,\r\n"
"%f\r\n"
"\r\n"
"Realtime: Sats: %d\r\n"
"Distance: %.2f%s Dir: %s\r\n"
"GPS time: %02d:%02d:%02d UTC",
(double)latitude,
(double)longitude,
subghz_gps->satellites,
(double)(subghz_gps->satellites > 0 ? distance > 1 ? distance : distance * 1000 : 0),
distance > 1 ? "km" : "m",
@@ -225,9 +217,6 @@ static void subghz_gps_init(SubGhzGPS* subghz_gps, uint32_t baudrate) {
furi_thread_alloc_ex("SubGhzGPSWorker", 1024, subghz_gps_uart_worker, subghz_gps);
furi_thread_start(subghz_gps->thread);
expansion_disable(furi_record_open(RECORD_EXPANSION));
furi_record_close(RECORD_EXPANSION);
subghz_gps->serial_handle = furi_hal_serial_control_acquire(UART_CH);
furi_check(subghz_gps->serial_handle);
furi_hal_serial_init(subghz_gps->serial_handle, baudrate);
@@ -236,7 +225,7 @@ static void subghz_gps_init(SubGhzGPS* subghz_gps, uint32_t baudrate) {
subghz_gps->serial_handle, subghz_gps_uart_on_irq_cb, subghz_gps, false);
subghz_gps->deinit = &subghz_gps_deinit;
subghz_gps->get_descr = &subghz_gps_get_descr;
subghz_gps->cat_realtime = &subghz_gps_cat_realtime;
}
#include <flipper_application/flipper_application.h>

View File

@@ -32,7 +32,7 @@ struct SubGhzGPS {
void (*deinit)(SubGhzGPS* subghz_gps);
/**
* Get description for signal info
* Concatenate realtime GPS info to string
*
* @param subghz_gps SubGhzGPS object
* @param descr Output string
@@ -40,7 +40,7 @@ struct SubGhzGPS {
* @param longitude Longitude
* @return void
*/
void (*get_descr)(SubGhzGPS* subghz_gps, FuriString* descr, float latitude, float longitude);
void (*cat_realtime)(SubGhzGPS* subghz_gps, FuriString* descr, float latitude, float longitude);
};
/**
@@ -49,7 +49,7 @@ struct SubGhzGPS {
*
* @return SubGhzGPS* SubGhzGPS object
*/
SubGhzGPS* subghz_gps_plugin_init();
SubGhzGPS* subghz_gps_plugin_init(uint32_t baudrate);
/**
* Deinitialize SubGhzGPS plugin

View File

@@ -11,6 +11,9 @@ SubGhzGPS* subghz_gps_plugin_init(uint32_t baudrate) {
furi_record_close(RECORD_EXPANSION);
if(connected) return NULL;
expansion_disable(furi_record_open(RECORD_EXPANSION));
furi_record_close(RECORD_EXPANSION);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperApplication* plugin_app = flipper_application_alloc(storage, firmware_api_interface);
do {
@@ -60,6 +63,9 @@ SubGhzGPS* subghz_gps_plugin_init(uint32_t baudrate) {
} while(false);
flipper_application_free(plugin_app);
furi_record_close(RECORD_STORAGE);
expansion_enable(furi_record_open(RECORD_EXPANSION));
furi_record_close(RECORD_EXPANSION);
return NULL;
}
@@ -68,4 +74,7 @@ void subghz_gps_plugin_deinit(SubGhzGPS* subghz_gps) {
flipper_application_free(subghz_gps->plugin_app);
free(subghz_gps);
furi_record_close(RECORD_STORAGE);
expansion_enable(furi_record_open(RECORD_EXPANSION));
furi_record_close(RECORD_EXPANSION);
}

View File

@@ -701,7 +701,7 @@ void subghz_txrx_set_default_preset(SubGhzTxRx* instance, uint32_t frequency) {
if(frequency == 0) {
frequency = subghz_setting_get_default_frequency(subghz_txrx_get_setting(instance));
}
subghz_txrx_set_preset(instance, default_modulation, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(instance, default_modulation, frequency, NAN, NAN, NULL, 0);
}
const char*
@@ -716,8 +716,8 @@ const char*
instance,
preset_name,
frequency,
0,
0,
NAN,
NAN,
subghz_setting_get_preset_data(setting, index),
subghz_setting_get_preset_data_size(setting, index));

View File

@@ -25,7 +25,7 @@ bool subghz_txrx_gen_data_protocol(
bool res = false;
subghz_txrx_set_preset(instance, preset_name, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(instance, preset_name, frequency, NAN, NAN, NULL, 0);
instance->decoder_result =
subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name);
@@ -98,7 +98,7 @@ bool subghz_txrx_gen_keeloq_protocol( //TODO lead to a general appearance
instance->transmitter =
subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
subghz_txrx_set_preset(instance, preset_name, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(instance, preset_name, frequency, NAN, NAN, NULL, 0);
if(instance->transmitter &&
subghz_protocol_keeloq_create_data(
@@ -131,7 +131,7 @@ bool subghz_txrx_gen_keeloq_bft_protocol(
txrx->transmitter =
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
subghz_txrx_set_preset(txrx, preset_name, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(txrx, preset_name, frequency, NAN, NAN, NULL, 0);
if(txrx->transmitter && subghz_protocol_keeloq_bft_create_data(
subghz_transmitter_get_protocol_instance(txrx->transmitter),
@@ -175,7 +175,7 @@ bool subghz_txrx_gen_nice_flor_s_protocol(
txrx->transmitter =
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME);
subghz_txrx_set_preset(txrx, preset_name, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(txrx, preset_name, frequency, NAN, NAN, NULL, 0);
if(txrx->transmitter && subghz_protocol_nice_flor_s_create_data(
subghz_transmitter_get_protocol_instance(txrx->transmitter),
@@ -208,7 +208,7 @@ bool subghz_txrx_gen_faac_slh_protocol(
txrx->transmitter =
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_FAAC_SLH_NAME);
subghz_txrx_set_preset(txrx, preset_name, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(txrx, preset_name, frequency, NAN, NAN, NULL, 0);
if(txrx->transmitter && subghz_protocol_faac_slh_create_data(
subghz_transmitter_get_protocol_instance(txrx->transmitter),
@@ -251,7 +251,7 @@ bool subghz_txrx_gen_alutech_at_4n_protocol(
txrx->transmitter =
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME);
subghz_txrx_set_preset(txrx, preset_name, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(txrx, preset_name, frequency, NAN, NAN, NULL, 0);
if(txrx->transmitter && subghz_protocol_alutech_at_4n_create_data(
subghz_transmitter_get_protocol_instance(txrx->transmitter),
@@ -280,7 +280,7 @@ bool subghz_txrx_gen_came_atomo_protocol(
txrx->transmitter =
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_CAME_ATOMO_NAME);
subghz_txrx_set_preset(txrx, preset_name, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(txrx, preset_name, frequency, NAN, NAN, NULL, 0);
if(txrx->transmitter && subghz_protocol_came_atomo_create_data(
subghz_transmitter_get_protocol_instance(txrx->transmitter),
@@ -309,7 +309,7 @@ bool subghz_txrx_gen_somfy_telis_protocol(
txrx->transmitter =
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME);
subghz_txrx_set_preset(txrx, preset_name, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(txrx, preset_name, frequency, NAN, NAN, NULL, 0);
if(txrx->transmitter && subghz_protocol_somfy_telis_create_data(
subghz_transmitter_get_protocol_instance(txrx->transmitter),
@@ -338,7 +338,7 @@ bool subghz_txrx_gen_secplus_v2_protocol(
bool ret = false;
instance->transmitter =
subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
subghz_txrx_set_preset(instance, name_preset, frequency, 0, 0, NULL, 0);
subghz_txrx_set_preset(instance, name_preset, frequency, NAN, NAN, NULL, 0);
if(instance->transmitter) {
subghz_protocol_secplus_v2_create_data(
subghz_transmitter_get_protocol_instance(instance->transmitter),

View File

@@ -60,9 +60,6 @@ bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent e
subghz_frequency_analyzer_get_frequency_to_save(subghz->subghz_frequency_analyzer);
if(frequency > 0) {
subghz->last_settings->frequency = frequency;
#ifdef FURI_DEBUG
subghz_last_settings_log(subghz->last_settings);
#endif
// Disable Hopping before opening the receiver scene!
if(subghz->last_settings->enable_hopping) {
subghz->last_settings->enable_hopping = false;
@@ -73,9 +70,6 @@ bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent e
return true;
} else if(event.event == SubGhzCustomEventViewFreqAnalOkLong) {
// Don't need to save, we already saved on short event
#ifdef FURI_DEBUG
FURI_LOG_W(TAG, "Goto next scene!");
#endif
//scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneStart, 10);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
return true;

View File

@@ -57,7 +57,7 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
}
subghz_txrx_set_preset(
subghz->txrx, "AM650", subghz->last_settings->frequency, 0, 0, NULL, 0);
subghz->txrx, "AM650", subghz->last_settings->frequency, NAN, NAN, NULL, 0);
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart);
} else if(state == SubGhzRxKeyStateTX) {

View File

@@ -20,12 +20,6 @@ const char* const timestamp_names_text[TIMESTAMP_NAMES_COUNT] = {
"ON",
};
#define EXT_MOD_POWER_AMP_COUNT 2
const char* const ext_mod_power_amp_text[EXT_MOD_POWER_AMP_COUNT] = {
"OFF",
"ON",
};
#define DEBUG_P_COUNT 2
const char* const debug_pin_text[DEBUG_P_COUNT] = {
"OFF",
@@ -104,27 +98,6 @@ static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) {
furi_hal_subghz_set_rolling_counter_mult(debug_counter_val[index]);
}
static void subghz_scene_reciever_config_set_ext_mod_power_amp_text(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, ext_mod_power_amp_text[index]);
subghz->last_settings->external_module_power_amp = index == 1;
// Set globally in furi hal
furi_hal_subghz_set_ext_power_amp(subghz->last_settings->external_module_power_amp);
subghz_last_settings_save(subghz->last_settings);
// reinit external device
const SubGhzRadioDeviceType current = subghz_txrx_radio_device_get(subghz->txrx);
if(current != SubGhzRadioDeviceTypeInternal) {
subghz_txrx_radio_device_set(subghz->txrx, SubGhzRadioDeviceTypeInternal);
subghz_txrx_radio_device_set(subghz->txrx, current);
}
}
static void subghz_scene_receiver_config_set_gps(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
@@ -153,18 +126,12 @@ static void subghz_scene_receiver_config_set_gps(VariableItem* item) {
}
subghz_last_settings_save(subghz->last_settings);
if(subghz->gps) {
subghz_gps_plugin_deinit(subghz->gps);
subghz->gps = NULL;
}
if(subghz->last_settings->gps_baudrate != 0) {
if(subghz->gps) {
furi_hal_serial_set_br(
subghz->gps->serial_handle, subghz->last_settings->gps_baudrate);
} else {
subghz->gps = subghz_gps_plugin_init(subghz->last_settings->gps_baudrate);
}
} else {
if(subghz->gps) {
subghz_gps_plugin_deinit(subghz->gps);
subghz->gps = NULL;
}
subghz->gps = subghz_gps_plugin_init(subghz->last_settings->gps_baudrate);
}
}
@@ -200,16 +167,6 @@ void subghz_scene_radio_settings_on_enter(void* context) {
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, radio_device_text[value_index]);
item = variable_item_list_add(
variable_item_list,
"Ext Power Amp",
EXT_MOD_POWER_AMP_COUNT,
subghz_scene_reciever_config_set_ext_mod_power_amp_text,
subghz);
value_index = subghz->last_settings->external_module_power_amp ? 1 : 0;
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, ext_mod_power_amp_text[value_index]);
item = variable_item_list_add(
variable_item_list,
"GPS Baudrate",

View File

@@ -104,14 +104,13 @@ void subghz_scene_read_raw_on_enter(void* context) {
if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateBack) {
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
#if SUBGHZ_LAST_SETTING_SAVE_PRESET
if(furi_string_empty(file_name)) {
subghz_txrx_set_preset_internal(
subghz->txrx,
subghz->last_settings->frequency,
subghz->last_settings->preset_index);
}
#endif
}
subghz_scene_read_raw_update_statusbar(subghz);

View File

@@ -250,12 +250,8 @@ void subghz_scene_receiver_on_enter(void* context) {
FuriString* item_time = furi_string_alloc();
if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) {
#if SUBGHZ_LAST_SETTING_SAVE_PRESET
subghz_txrx_set_preset_internal(
subghz->txrx, subghz->last_settings->frequency, subghz->last_settings->preset_index);
#else
subghz_txrx_set_default_preset(subghz->txrx, subghz->last_settings->frequency);
#endif
subghz->filter = subghz->last_settings->filter;
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);

View File

@@ -178,8 +178,8 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
subghz->txrx,
furi_string_get_cstr(preset.name),
frequency,
0,
0,
NAN,
NAN,
preset.data,
preset.data_size);
@@ -206,8 +206,8 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
subghz->txrx,
preset_name,
preset.frequency,
0,
0,
NAN,
NAN,
subghz_setting_get_preset_data(setting, index),
subghz_setting_get_preset_data_size(setting, index));
subghz->last_settings->preset_index = index;
@@ -240,8 +240,8 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item)
subghz->txrx,
furi_string_get_cstr(preset.name),
frequency,
0,
0,
NAN,
NAN,
preset.data,
preset.data_size);
variable_item_set_current_value_index(
@@ -410,14 +410,11 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context,
subghz->view_dispatcher, SubGhzCustomEventSceneSettingLock);
} else if(index == SubGhzSettingIndexResetToDefault) {
// Reset all values to default state!
#if SUBGHZ_LAST_SETTING_SAVE_PRESET
subghz_txrx_set_preset_internal(
subghz->txrx,
SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY,
SUBGHZ_LAST_SETTING_DEFAULT_PRESET);
#else
subghz_txrx_set_default_preset(subghz->txrx, SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY);
#endif
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
const char* preset_name = furi_string_get_cstr(preset.name);
@@ -449,9 +446,7 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context,
variable_item_list_set_selected_item(subghz->variable_item_list, default_index);
variable_item_list_reset(subghz->variable_item_list);
#ifdef FURI_DEBUG
subghz_last_settings_log(subghz->last_settings);
#endif
subghz_last_settings_save(subghz->last_settings);
view_dispatcher_send_custom_event(
@@ -745,9 +740,7 @@ void subghz_scene_receiver_config_on_exit(void* context) {
variable_item_list_set_selected_item(subghz->variable_item_list, 0);
variable_item_list_reset(subghz->variable_item_list);
#ifdef FURI_DEBUG
subghz_last_settings_log(subghz->last_settings);
#endif
subghz_last_settings_save(subghz->last_settings);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);

View File

@@ -40,8 +40,8 @@ static bool subghz_scene_receiver_info_update_parser(void* context) {
subghz->txrx,
furi_string_get_cstr(preset->name),
preset->frequency,
0,
0,
NAN,
NAN,
preset->data,
preset->data_size);

View File

@@ -35,8 +35,8 @@ void subghz_scene_saved_menu_on_enter(void* context) {
subghz_scene_saved_menu_submenu_callback,
subghz);
if(!isnanf(subghz_txrx_get_latitude(subghz->txrx)) &&
!isnanf(subghz_txrx_get_longitude(subghz->txrx))) {
if(!isnanf(subghz_txrx_get_latitude(subghz->txrx)) ||
!isnanf(subghz_txrx_get_longitude(subghz->txrx)) || subghz->gps) {
submenu_add_item(
subghz->submenu,
"Geographic info",

View File

@@ -18,7 +18,7 @@ void subghz_scene_set_cnt_on_enter(void* context) {
switch(state) {
case SetTypeBFTClone:
byte_input_set_header_text(byte_input, "Enter COUNTER in Hex");
byte_input_set_header_text(byte_input, "Enter COUNTER in hex");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_cnt_byte_input_callback,
@@ -29,7 +29,7 @@ void subghz_scene_set_cnt_on_enter(void* context) {
break;
case SetTypeFaacSLH_Manual_433:
case SetTypeFaacSLH_Manual_868:
byte_input_set_header_text(byte_input, "Enter COUNTER in Hex 20 bits");
byte_input_set_header_text(byte_input, "Enter COUNTER in hex 20 bits");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_cnt_byte_input_callback,

View File

@@ -13,7 +13,7 @@ void subghz_scene_set_fix_on_enter(void* context) {
// Setup view
ByteInput* byte_input = subghz->byte_input;
byte_input_set_header_text(byte_input, "Enter FIX in Hex");
byte_input_set_header_text(byte_input, "Enter FIX in hex");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_fix_byte_input_callback,

View File

@@ -14,7 +14,7 @@ void subghz_scene_set_seed_on_enter(void* context) {
// Setup view
ByteInput* byte_input = subghz->byte_input;
byte_input_set_header_text(byte_input, "Enter SEED in Hex");
byte_input_set_header_text(byte_input, "Enter SEED in hex");
byte_input_set_result_callback(
byte_input,
subghz_scene_set_seed_byte_input_callback,

View File

@@ -3,17 +3,7 @@
void subghz_scene_show_gps_draw_satellites(void* context) {
SubGhz* subghz = context;
DateTime datetime;
furi_hal_rtc_get_datetime(&datetime);
if((datetime.second - subghz->gps->fix_second) > 15) {
subghz->gps->latitude = NAN;
subghz->gps->longitude = NAN;
subghz->gps->satellites = 0;
subghz->gps->fix_hour = 0;
subghz->gps->fix_minute = 0;
subghz->gps->fix_second = 0;
}
widget_reset(subghz->widget);
float latitude, longitude;
// Get from saved file or from history
@@ -24,19 +14,32 @@ void subghz_scene_show_gps_draw_satellites(void* context) {
latitude = subghz_history_get_latitude(subghz->history, subghz->idx_menu_chosen);
longitude = subghz_history_get_longitude(subghz->history, subghz->idx_menu_chosen);
}
FuriString* text_str = furi_string_alloc_printf(
"Captured at: %f,\r\n"
"%f\r\n"
"\r\n",
(double)latitude,
(double)longitude);
if(subghz->gps) {
DateTime datetime;
furi_hal_rtc_get_datetime(&datetime);
if((datetime.second - subghz->gps->fix_second) > 15) {
subghz->gps->latitude = NAN;
subghz->gps->longitude = NAN;
subghz->gps->satellites = 0;
subghz->gps->fix_hour = 0;
subghz->gps->fix_minute = 0;
subghz->gps->fix_second = 0;
}
subghz->gps->cat_realtime(subghz->gps, text_str, latitude, longitude);
}
FuriString* text_str = furi_string_alloc();
subghz->gps->get_descr(subghz->gps, text_str, latitude, longitude);
widget_add_text_scroll_element(subghz->widget, 0, 0, 128, 64, furi_string_get_cstr(text_str));
furi_string_free(text_str);
}
void subghz_scene_show_gps_refresh_screen(void* context) {
SubGhz* subghz = context;
widget_reset(subghz->widget);
subghz_scene_show_gps_draw_satellites(subghz);
}
void subghz_scene_show_gps_on_enter(void* context) {
SubGhz* subghz = context;
@@ -44,7 +47,7 @@ void subghz_scene_show_gps_on_enter(void* context) {
if(subghz->gps) {
subghz->gps->timer =
furi_timer_alloc(subghz_scene_show_gps_refresh_screen, FuriTimerTypePeriodic, subghz);
furi_timer_alloc(subghz_scene_show_gps_draw_satellites, FuriTimerTypePeriodic, subghz);
furi_timer_start(subghz->gps->timer, 1000);
}

View File

@@ -207,16 +207,9 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
subghz->last_settings = subghz_last_settings_alloc();
size_t preset_count = subghz_setting_get_preset_count(setting);
subghz_last_settings_load(subghz->last_settings, preset_count);
#ifdef FURI_DEBUG
subghz_last_settings_log(subghz->last_settings);
#endif
if(!alloc_for_tx_only) {
#if SUBGHZ_LAST_SETTING_SAVE_PRESET
subghz_txrx_set_preset_internal(
subghz->txrx, subghz->last_settings->frequency, subghz->last_settings->preset_index);
#else
subghz_txrx_set_default_preset(subghz->txrx, subghz->last_settings->frequency);
#endif
subghz->history = subghz_history_alloc();
}

View File

@@ -26,8 +26,5 @@ void subghz_extended_freq() {
SubGhzLastSettings* last_settings = subghz_last_settings_alloc();
subghz_last_settings_load(last_settings, 0);
// Set globally in furi hal
furi_hal_subghz_set_ext_power_amp(last_settings->external_module_power_amp);
subghz_last_settings_free(last_settings);
}

View File

@@ -4,26 +4,24 @@
#define TAG "SubGhzLastSettings"
#define SUBGHZ_LAST_SETTING_FILE_TYPE "Flipper SubGhz Last Setting File"
#define SUBGHZ_LAST_SETTING_FILE_VERSION 1
#define SUBGHZ_LAST_SETTING_FILE_VERSION 3
#define SUBGHZ_LAST_SETTINGS_PATH EXT_PATH("subghz/assets/last_subghz.settings")
#define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY "Frequency"
#define SUBGHZ_LAST_SETTING_FIELD_PRESET "Preset" // AKA Modulation
#define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_FEEDBACK_LEVEL "FeedbackLevel"
#define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER "FATrigger"
#define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_ENABLED "External"
#define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER "ExtPower"
#define SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILE_NAMES "TimestampNames"
#define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER_AMP "ExtPowerAmp"
#define SUBGHZ_LAST_SETTING_FIELD_GPS "Gps"
#define SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILE_NAMES "ProtocolNames"
#define SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE "Hopping"
#define SUBGHZ_LAST_SETTING_FIELD_REMOVE_DUPLICATES "RemoveDuplicates"
#define SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER "IgnoreFilter"
#define SUBGHZ_LAST_SETTING_FIELD_FILTER "Filter"
#define SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD "RSSI"
#define SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD "DelOldSignals"
#define SUBGHZ_LAST_SETTING_FIELD_GPS_BAUDRATE "GpsBaudrate"
#define SUBGHZ_LAST_SETTING_FIELD_REMOVE_DUPLICATES "RemoveDuplicates"
#define SUBGHZ_LAST_SETTING_FIELD_REPEATER "Repeater"
#define SUBGHZ_LAST_SETTING_FIELD_ENABLE_SOUND "Sound"
#define SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD "DelOldSignals"
#define SUBGHZ_LAST_SETTING_FIELD_AUTOSAVE "Autosave"
SubGhzLastSettings* subghz_last_settings_alloc(void) {
@@ -39,202 +37,145 @@ void subghz_last_settings_free(SubGhzLastSettings* instance) {
void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count) {
furi_assert(instance);
// Default values (all others set to 0, if read from file fails these are used)
instance->frequency = SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY;
instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
instance->frequency_analyzer_feedback_level =
SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL;
instance->frequency_analyzer_trigger = SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER;
// See bin_raw_value in scenes/subghz_scene_receiver_config.c
instance->filter = SubGhzProtocolFlag_Decodable;
instance->rssi = SUBGHZ_RAW_THRESHOLD_MIN;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
uint32_t temp_frequency = 0;
uint32_t temp_frequency_analyzer_feedback_level = 0;
float temp_frequency_analyzer_trigger = 0;
bool temp_external_module_enabled = false;
bool temp_external_module_power_5v_disable = false;
bool temp_external_module_power_amp = false;
bool temp_protocol_file_names = false;
bool temp_enable_hopping = false;
bool temp_enable_sound = false;
uint32_t temp_repeater_state;
bool temp_remove_duplicates = false;
bool temp_delete_old_sig = false;
bool temp_autosave = false;
uint32_t temp_ignore_filter = 0;
uint32_t temp_filter = 0;
float temp_rssi = 0;
uint32_t temp_preset = 0;
FuriString* temp_str = furi_string_alloc();
uint32_t config_version = 0;
bool preset_was_read = false;
bool rssi_was_read = false;
bool filter_was_read = false;
bool ignore_filter_was_read = false;
bool remove_duplicates_was_read = false;
bool frequency_analyzer_feedback_level_was_read = false;
bool frequency_analyzer_trigger_was_read = false;
bool repeater_was_read = false;
bool enable_sound_was_read = false;
uint32_t temp_gps_baudrate = 0;
if(FSE_OK == storage_sd_status(storage) && SUBGHZ_LAST_SETTINGS_PATH &&
if(FSE_OK == storage_sd_status(storage) &&
flipper_format_file_open_existing(fff_data_file, SUBGHZ_LAST_SETTINGS_PATH)) {
preset_was_read = flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_PRESET, (uint32_t*)&temp_preset, 1);
flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_FREQUENCY, (uint32_t*)&temp_frequency, 1);
frequency_analyzer_feedback_level_was_read = flipper_format_read_uint32(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_FEEDBACK_LEVEL,
(uint32_t*)&temp_frequency_analyzer_feedback_level,
1);
frequency_analyzer_trigger_was_read = flipper_format_read_float(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER,
(float*)&temp_frequency_analyzer_trigger,
1);
flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_ENABLED,
(bool*)&temp_external_module_enabled,
1);
flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER,
(bool*)&temp_external_module_power_5v_disable,
1);
flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILE_NAMES,
(bool*)&temp_protocol_file_names,
1);
flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER_AMP,
(bool*)&temp_external_module_power_amp,
1);
flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_GPS, (uint32_t*)&temp_gps_baudrate, 1);
flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE,
(bool*)&temp_enable_hopping,
1);
rssi_was_read = flipper_format_read_float(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD, (float*)&temp_rssi, 1);
remove_duplicates_was_read = flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_REMOVE_DUPLICATES,
(bool*)&temp_remove_duplicates,
1);
ignore_filter_was_read = flipper_format_read_uint32(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER,
(uint32_t*)&temp_ignore_filter,
1);
filter_was_read = flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_FILTER, (uint32_t*)&temp_filter, 1);
repeater_was_read = flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_REPEATER, (uint32_t*)&temp_repeater_state, 1);
enable_sound_was_read = flipper_format_read_bool(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_ENABLE_SOUND, (bool*)&temp_enable_sound, 1);
flipper_format_read_bool(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD, (bool*)&temp_delete_old_sig, 1);
flipper_format_read_bool(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_AUTOSAVE, (bool*)&temp_autosave, 1);
do {
if(!flipper_format_read_header(fff_data_file, temp_str, &config_version)) break;
if((strcmp(furi_string_get_cstr(temp_str), SUBGHZ_LAST_SETTING_FILE_TYPE) != 0) ||
(config_version != SUBGHZ_LAST_SETTING_FILE_VERSION)) {
break;
}
if(!flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_FREQUENCY, &instance->frequency, 1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_PRESET, &instance->preset_index, 1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_uint32(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_FEEDBACK_LEVEL,
&instance->frequency_analyzer_feedback_level,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_float(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER,
&instance->frequency_analyzer_trigger,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILE_NAMES,
&instance->protocol_file_names,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE,
&instance->enable_hopping,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_uint32(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER,
&instance->ignore_filter,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_FILTER, &instance->filter, 1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_float(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD, &instance->rssi, 1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD,
&instance->delete_old_signals,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_uint32(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_GPS_BAUDRATE,
&instance->gps_baudrate,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_REMOVE_DUPLICATES,
&instance->remove_duplicates,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_uint32(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_REPEATER,
&instance->repeater_state,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_ENABLE_SOUND,
&instance->enable_sound,
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_bool(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_AUTOSAVE, &instance->autosave, 1)) {
flipper_format_rewind(fff_data_file);
}
} while(0);
} else {
FURI_LOG_E(TAG, "Error open file %s", SUBGHZ_LAST_SETTINGS_PATH);
}
if(temp_frequency == 0 || !furi_hal_subghz_is_tx_allowed(temp_frequency)) {
FURI_LOG_W(TAG, "Last used frequency not found or can't be used!");
instance->frequency = SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY;
instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
instance->frequency_analyzer_feedback_level =
SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL;
instance->frequency_analyzer_trigger = SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER;
instance->external_module_enabled = false;
instance->protocol_file_names = false;
instance->external_module_power_amp = false;
instance->gps_baudrate = 0;
instance->enable_hopping = false;
instance->remove_duplicates = false;
instance->repeater_state = 0;
instance->enable_sound = 0;
instance->delete_old_signals = false;
instance->autosave = false;
instance->ignore_filter = 0x00;
// See bin_raw_value in applications/main/subghz/scenes/subghz_scene_receiver_config.c
instance->filter = SubGhzProtocolFlag_Decodable;
instance->rssi = SUBGHZ_RAW_THRESHOLD_MIN;
} else {
instance->frequency = temp_frequency;
instance->frequency_analyzer_feedback_level =
frequency_analyzer_feedback_level_was_read ?
temp_frequency_analyzer_feedback_level :
SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL;
instance->frequency_analyzer_trigger = frequency_analyzer_trigger_was_read ?
temp_frequency_analyzer_trigger :
SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER;
if(!preset_was_read) {
FURI_LOG_W(TAG, "Preset was not read. Set default");
instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
} else if(temp_preset > (uint32_t)preset_count - 1) {
FURI_LOG_W(
TAG,
"Last used preset out of range. Preset to set: %ld, Max index: %ld. Set default",
temp_preset,
(uint32_t)preset_count - 1);
instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
} else {
instance->preset_index = temp_preset;
}
instance->external_module_enabled = temp_external_module_enabled;
instance->external_module_power_5v_disable = temp_external_module_power_5v_disable;
instance->protocol_file_names = temp_protocol_file_names;
instance->delete_old_signals = temp_delete_old_sig;
instance->autosave = temp_autosave;
// External power amp CC1101
instance->external_module_power_amp = temp_external_module_power_amp;
instance->rssi = rssi_was_read ? temp_rssi : SUBGHZ_RAW_THRESHOLD_MIN;
instance->enable_hopping = temp_enable_hopping;
instance->repeater_state = repeater_was_read ? temp_repeater_state : 0;
instance->enable_sound = enable_sound_was_read ? temp_enable_sound : false;
instance->remove_duplicates = remove_duplicates_was_read ? temp_remove_duplicates : false;
instance->ignore_filter = ignore_filter_was_read ? temp_ignore_filter : 0x00;
#if SUBGHZ_LAST_SETTING_SAVE_BIN_RAW
instance->filter = filter_was_read ? temp_filter : SubGhzProtocolFlag_Decodable;
#else
if(filter_was_read) {
instance->filter = temp_filter != SubGhzProtocolFlag_Decodable ?
SubGhzProtocolFlag_Decodable :
temp_filter;
} else {
instance->filter = SubGhzProtocolFlag_Decodable;
}
#endif
// Set globally in furi hal
furi_hal_subghz_set_ext_power_amp(instance->external_module_power_amp);
instance->gps_baudrate = temp_gps_baudrate;
}
furi_string_free(temp_str);
flipper_format_file_close(fff_data_file);
flipper_format_free(fff_data_file);
furi_record_close(RECORD_STORAGE);
if(instance->frequency == 0 || !furi_hal_subghz_is_tx_allowed(instance->frequency)) {
instance->frequency = SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY;
}
if(instance->preset_index > (uint32_t)preset_count - 1) {
instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
}
}
bool subghz_last_settings_save(SubGhzLastSettings* instance) {
furi_assert(instance);
#if SUBGHZ_LAST_SETTING_SAVE_BIN_RAW != true
instance->filter = SubGhzProtocolFlag_Decodable;
#endif
bool saved = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage);
@@ -251,96 +192,76 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
if(!flipper_format_write_header_cstr(
file, SUBGHZ_LAST_SETTING_FILE_TYPE, SUBGHZ_LAST_SETTING_FILE_VERSION))
break;
if(!flipper_format_insert_or_update_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_PRESET, &instance->preset_index, 1)) {
break;
}
if(!flipper_format_insert_or_update_uint32(
if(!flipper_format_write_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_FREQUENCY, &instance->frequency, 1)) {
break;
}
if(!flipper_format_insert_or_update_uint32(
if(!flipper_format_write_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_PRESET, &instance->preset_index, 1)) {
break;
}
if(!flipper_format_write_uint32(
file,
SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_FEEDBACK_LEVEL,
&instance->frequency_analyzer_feedback_level,
1)) {
break;
}
if(!flipper_format_insert_or_update_float(
if(!flipper_format_write_float(
file,
SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER,
&instance->frequency_analyzer_trigger,
1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
file,
SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_ENABLED,
&instance->external_module_enabled,
1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
file,
SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER,
&instance->external_module_power_5v_disable,
1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
if(!flipper_format_write_bool(
file,
SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILE_NAMES,
&instance->protocol_file_names,
1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
file,
SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER_AMP,
&instance->external_module_power_amp,
1)) {
break;
}
if(!flipper_format_insert_or_update_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_GPS, &instance->gps_baudrate, 1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
if(!flipper_format_write_bool(
file, SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE, &instance->enable_hopping, 1)) {
break;
}
if(!flipper_format_insert_or_update_float(
if(!flipper_format_write_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER, &instance->ignore_filter, 1)) {
break;
}
if(!flipper_format_write_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_FILTER, &instance->filter, 1)) {
break;
}
if(!flipper_format_write_float(
file, SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD, &instance->rssi, 1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
if(!flipper_format_write_bool(
file, SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD, &instance->delete_old_signals, 1)) {
break;
}
if(!flipper_format_write_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_GPS_BAUDRATE, &instance->gps_baudrate, 1)) {
break;
}
if(!flipper_format_write_bool(
file,
SUBGHZ_LAST_SETTING_FIELD_REMOVE_DUPLICATES,
&instance->remove_duplicates,
1)) {
break;
}
if(!flipper_format_insert_or_update_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER, &instance->ignore_filter, 1)) {
break;
}
if(!flipper_format_insert_or_update_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_FILTER, &instance->filter, 1)) {
break;
}
if(!flipper_format_insert_or_update_uint32(
if(!flipper_format_write_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_REPEATER, &instance->repeater_state, 1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
if(!flipper_format_write_bool(
file, SUBGHZ_LAST_SETTING_FIELD_ENABLE_SOUND, &instance->enable_sound, 1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
file, SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD, &instance->delete_old_signals, 1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
if(!flipper_format_write_bool(
file, SUBGHZ_LAST_SETTING_FIELD_AUTOSAVE, &instance->autosave, 1)) {
break;
}
@@ -357,54 +278,3 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
return saved;
}
const char* LOG_ON = "ON";
const char* LOG_OFF = "OFF";
static inline const char*
subghz_last_settings_log_filter_get_index(uint32_t filter, uint32_t flag) {
return READ_BIT(filter, flag) > 0 ? LOG_ON : LOG_OFF;
}
static inline const char* bool_to_char(bool value) {
return value ? LOG_ON : LOG_OFF;
}
void subghz_last_settings_log(SubGhzLastSettings* instance) {
furi_assert(instance);
FURI_LOG_I(
TAG,
"Frequency: %03ld.%02ld, FeedbackLevel: %ld, FATrigger: %.2f, External: %s, ExtPower: %s, TimestampNames: %s, ExtPowerAmp: %s,\n"
"GPSBaudrate: %ld, Hopping: %s,\nPreset: %ld, RSSI: %.2f, "
"BinRAW: %s, Repeater: %lu, Duplicates: %s, Autosave: %s, Starline: %s, Cars: %s, Magellan: %s, NiceFloR-S: %s, Weather: %s, TPMS: %s, Sound: %s",
instance->frequency / 1000000 % 1000,
instance->frequency / 10000 % 100,
instance->frequency_analyzer_feedback_level,
(double)instance->frequency_analyzer_trigger,
bool_to_char(instance->external_module_enabled),
bool_to_char(instance->external_module_power_5v_disable),
bool_to_char(instance->protocol_file_names),
bool_to_char(instance->external_module_power_amp),
instance->gps_baudrate,
bool_to_char(instance->enable_hopping),
instance->preset_index,
(double)instance->rssi,
subghz_last_settings_log_filter_get_index(instance->filter, SubGhzProtocolFlag_BinRAW),
instance->repeater_state,
bool_to_char(instance->remove_duplicates),
bool_to_char(instance->autosave),
subghz_last_settings_log_filter_get_index(
instance->ignore_filter, SubGhzProtocolFilter_StarLine),
subghz_last_settings_log_filter_get_index(
instance->ignore_filter, SubGhzProtocolFilter_AutoAlarms),
subghz_last_settings_log_filter_get_index(
instance->ignore_filter, SubGhzProtocolFilter_Magellan),
subghz_last_settings_log_filter_get_index(
instance->ignore_filter, SubGhzProtocolFilter_NiceFlorS),
subghz_last_settings_log_filter_get_index(
instance->ignore_filter, SubGhzProtocolFilter_Weather),
subghz_last_settings_log_filter_get_index(
instance->ignore_filter, SubGhzProtocolFilter_TPMS),
bool_to_char(instance->enable_sound));
}

View File

@@ -7,8 +7,6 @@
#include <lib/subghz/types.h>
#define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER (-93.0f)
#define SUBGHZ_LAST_SETTING_SAVE_BIN_RAW true
#define SUBGHZ_LAST_SETTING_SAVE_PRESET true
// 1 = "AM650"
// "AM270", "AM650", "FM238", "FM476",
#define SUBGHZ_LAST_SETTING_DEFAULT_PRESET 1
@@ -20,21 +18,17 @@ typedef struct {
uint32_t preset_index; // AKA Modulation
uint32_t frequency_analyzer_feedback_level;
float frequency_analyzer_trigger;
// TODO not using but saved so as not to change the version
bool external_module_enabled;
bool external_module_power_5v_disable;
bool external_module_power_amp;
// saved so as not to change the version
bool protocol_file_names;
uint32_t gps_baudrate;
bool enable_hopping;
uint32_t repeater_state;
bool enable_sound;
bool remove_duplicates;
uint32_t ignore_filter;
uint32_t filter;
float rssi;
bool delete_old_signals;
uint32_t gps_baudrate;
bool remove_duplicates;
uint32_t repeater_state;
bool enable_sound;
bool autosave;
} SubGhzLastSettings;
@@ -45,5 +39,3 @@ void subghz_last_settings_free(SubGhzLastSettings* instance);
void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count);
bool subghz_last_settings_save(SubGhzLastSettings* instance);
void subghz_last_settings_log(SubGhzLastSettings* instance);

View File

@@ -228,9 +228,7 @@ uint32_t subghz_frequency_find_correct(uint32_t input) {
uint32_t prev_freq = 0;
uint32_t current = 0;
uint32_t result = 0;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "input: %ld", input);
#endif
for(size_t i = 0; i < sizeof(subghz_frequency_list); i++) {
current = subghz_frequency_list[i];
if(current == input) {
@@ -281,7 +279,7 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
break;
}
subghz_frequency_analyzer_worker_set_trigger_level(instance->worker, trigger_level);
FURI_LOG_I(TAG, "trigger = %.1f", (double)trigger_level);
FURI_LOG_D(TAG, "trigger = %.1f", (double)trigger_level);
need_redraw = true;
} else if(event->type == InputTypePress && event->key == InputKeyUp) {
if(instance->feedback_level == 0) {
@@ -289,9 +287,7 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
} else {
instance->feedback_level--;
}
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "feedback_level = %d", instance->feedback_level);
#endif
need_redraw = true;
} else if(
((event->type == InputTypePress) || (event->type == InputTypeRepeat)) &&
@@ -324,13 +320,6 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
}
if(frequency_candidate > 0 &&
frequency_candidate != model->frequency_to_save) {
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"frequency_to_save: %ld, candidate: %ld",
model->frequency_to_save,
frequency_candidate);
#endif
model->frequency_to_save = frequency_candidate;
updated = true;
}
@@ -372,24 +361,12 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
},
true);
#ifdef FURI_DEBUG
FURI_LOG_I(
TAG,
"updated: %d, long: %d, type: %d",
updated,
(event->type == InputTypeLong),
event->type);
#endif
if(updated) {
instance->callback(SubGhzCustomEventViewFreqAnalOkShort, instance->context);
}
// First device receive short, then when user release button we get long
if(event->type == InputTypeLong && frequency_to_save > 0) {
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Long press!");
#endif
// Stop worker
if(subghz_frequency_analyzer_worker_is_running(instance->worker)) {
subghz_frequency_analyzer_worker_stop(instance->worker);

View File

@@ -435,8 +435,34 @@ void cli_command_free(Cli* cli, FuriString* args, void* context) {
printf("Minimum heap size: %zu\r\n", memmgr_get_minimum_free_heap());
printf("Maximum heap block: %zu\r\n", memmgr_heap_get_max_free_block());
printf("Pool free: %zu\r\n", memmgr_pool_get_free());
printf("Maximum pool block: %zu\r\n", memmgr_pool_get_max_block());
printf("Aux pool total free: %zu\r\n", memmgr_aux_pool_get_free());
printf("Aux pool max free block: %zu\r\n", memmgr_pool_get_max_block());
}
typedef struct {
void* addr;
size_t size;
} FreeBlockInfo;
#define FREE_BLOCK_INFO_MAX 128
typedef struct {
FreeBlockInfo free_blocks[FREE_BLOCK_INFO_MAX];
size_t free_blocks_count;
} FreeBlockContext;
static bool free_block_walker(void* pointer, size_t size, bool used, void* context) {
FreeBlockContext* free_blocks = (FreeBlockContext*)context;
if(!used) {
if(free_blocks->free_blocks_count < FREE_BLOCK_INFO_MAX) {
free_blocks->free_blocks[free_blocks->free_blocks_count].addr = pointer;
free_blocks->free_blocks[free_blocks->free_blocks_count].size = size;
free_blocks->free_blocks_count++;
} else {
return false;
}
}
return true;
}
void cli_command_free_blocks(Cli* cli, FuriString* args, void* context) {
@@ -444,7 +470,23 @@ void cli_command_free_blocks(Cli* cli, FuriString* args, void* context) {
UNUSED(args);
UNUSED(context);
memmgr_heap_printf_free_blocks();
FreeBlockContext* free_blocks = malloc(sizeof(FreeBlockContext));
free_blocks->free_blocks_count = 0;
memmgr_heap_walk_blocks(free_block_walker, free_blocks);
for(size_t i = 0; i < free_blocks->free_blocks_count; i++) {
printf(
"A %p S %zu\r\n",
(void*)free_blocks->free_blocks[i].addr,
free_blocks->free_blocks[i].size);
}
if(free_blocks->free_blocks_count == FREE_BLOCK_INFO_MAX) {
printf("... and more\r\n");
}
free(free_blocks);
}
void cli_command_i2c(Cli* cli, FuriString* args, void* context) {

View File

@@ -33,12 +33,16 @@ static void desktop_loader_callback(const void* message, void* context) {
Desktop* desktop = context;
const LoaderEvent* event = message;
if(event->type == LoaderEventTypeApplicationStarted) {
if(event->type == LoaderEventTypeApplicationBeforeLoad) {
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalBeforeAppStarted);
} else if(event->type == LoaderEventTypeApplicationStopped) {
furi_check(furi_semaphore_acquire(desktop->animation_semaphore, 3000) == FuriStatusOk);
} else if(
event->type == LoaderEventTypeApplicationLoadFailed ||
event->type == LoaderEventTypeApplicationStopped) {
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished);
}
}
static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) {
UNUSED(context);
furi_assert(canvas);
@@ -115,8 +119,11 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
switch(event) {
case DesktopGlobalBeforeAppStarted:
animation_manager_unload_and_stall_animation(desktop->animation_manager);
if(animation_manager_is_animation_loaded(desktop->animation_manager)) {
animation_manager_unload_and_stall_animation(desktop->animation_manager);
}
desktop_auto_lock_inhibit(desktop);
furi_semaphore_release(desktop->animation_semaphore);
return true;
case DesktopGlobalAfterAppFinished:
animation_manager_load_and_continue_animation(desktop->animation_manager);
@@ -273,6 +280,7 @@ void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) {
Desktop* desktop_alloc(void) {
Desktop* desktop = malloc(sizeof(Desktop));
desktop->animation_semaphore = furi_semaphore_alloc(1, 0);
desktop->animation_manager = animation_manager_alloc();
desktop->gui = furi_record_open(RECORD_GUI);
desktop->scene_thread = furi_thread_alloc();

View File

@@ -80,6 +80,8 @@ struct Desktop {
bool in_transition : 1;
FuriSemaphore* animation_semaphore;
Keybinds keybinds;
FuriPubSub* ascii_events_pubsub;

View File

@@ -91,13 +91,9 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
if(desktop_pin_is_valid(&desktop->settings.pin_code)) {
desktop_lock(desktop, true);
} else {
LoaderStatus status = loader_start(
desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG, NULL);
if(status == LoaderStatusOk) {
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1);
} else {
FURI_LOG_E(TAG, "Unable to start desktop settings");
}
loader_start_detached_with_gui_error(
desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG);
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1);
}
consumed = true;
break;
@@ -110,13 +106,9 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
power_off(power);
furi_record_close(RECORD_POWER);
} else {
LoaderStatus status = loader_start(
desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG, NULL);
if(status == LoaderStatusOk) {
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 2);
} else {
FURI_LOG_E(TAG, "Unable to start desktop settings");
}
loader_start_detached_with_gui_error(
desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG);
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 2);
}
consumed = true;
break;

View File

@@ -86,7 +86,7 @@ bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
switch(event.event) {
case DesktopLockedEventOpenPowerOff: {
if(momentum_settings.lockscreen_poweroff) {
loader_start(desktop->loader, "Power", "off", NULL);
loader_start_detached_with_gui_error(desktop->loader, "Power", "off");
}
consumed = true;
break;

View File

@@ -120,7 +120,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
break;
case DesktopMainEventOpenPowerOff: {
loader_start(desktop->loader, "Power", "off", NULL);
loader_start_detached_with_gui_error(desktop->loader, "Power", "off");
consumed = true;
break;
}

View File

@@ -3,7 +3,7 @@
#include <applications.h>
#include <storage/storage.h>
#include <furi_hal.h>
#include <momentum/momentum.h>
#include <assets_icons.h>
#include <dialogs/dialogs.h>
#include <toolbox/path.h>
@@ -13,6 +13,8 @@
#include <core/dangerous_defines.h>
#include <gui/icon_i.h>
#include <momentum/momentum.h>
#define TAG "Loader"
#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF
@@ -22,14 +24,14 @@ static const char*
loader_find_external_application_by_name(const char* app_name, FlipperApplicationFlag* flags) {
for(size_t i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT; i++) {
if(strcmp(FLIPPER_EXTERNAL_APPS[i].name, app_name) == 0) {
*flags = FLIPPER_EXTERNAL_APPS[i].flags;
if(flags) *flags = FLIPPER_EXTERNAL_APPS[i].flags;
return FLIPPER_EXTERNAL_APPS[i].path;
}
}
for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) {
if(strcmp(FLIPPER_SETTINGS_APPS[i].name, app_name) == 0) {
*flags = FLIPPER_SETTINGS_APPS[i].flags;
if(flags) *flags = FLIPPER_SETTINGS_APPS[i].flags;
return FLIPPER_SETTINGS_APPS[i].path;
}
}
@@ -59,10 +61,24 @@ LoaderStatus
return result.value;
}
static void loader_show_gui_error(LoaderStatus status, FuriString* error_message) {
// TODO FL-3522: we have many places where we can emit a double start, ex: desktop, menu
// so i prefer to not show LoaderStatusErrorAppStarted error message for now
if(status == LoaderStatusErrorUnknownApp || status == LoaderStatusErrorInternal) {
static void
loader_show_gui_error(LoaderStatus status, const char* name, FuriString* error_message) {
if(status == LoaderStatusErrorUnknownApp &&
loader_find_external_application_by_name(name, NULL) != NULL) {
// Special case for external apps
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
DialogMessage* message = dialog_message_alloc();
dialog_message_set_header(message, "Update needed", 64, 3, AlignCenter, AlignTop);
dialog_message_set_buttons(message, NULL, NULL, NULL);
dialog_message_set_icon(message, &I_WarningDolphinFlip_45x42, 83, 22);
dialog_message_set_text(
message, "Update firmware\nto run this app", 3, 26, AlignLeft, AlignTop);
dialog_message_show(dialogs, message);
dialog_message_free(message);
furi_record_close(RECORD_DIALOGS);
} else if(status == LoaderStatusErrorUnknownApp || status == LoaderStatusErrorInternal) {
// TODO FL-3522: we have many places where we can emit a double start, ex: desktop, menu
// so i prefer to not show LoaderStatusErrorAppStarted error message for now
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
DialogMessage* message = dialog_message_alloc();
dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop);
@@ -88,7 +104,7 @@ LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const
FuriString* error_message = furi_string_alloc();
LoaderStatus status = loader_start(loader, name, args, error_message);
loader_show_gui_error(status, error_message);
loader_show_gui_error(status, name, error_message);
furi_string_free(error_message);
return status;
}
@@ -97,11 +113,11 @@ void loader_start_detached_with_gui_error(Loader* loader, const char* name, cons
furi_check(loader);
furi_check(name);
LoaderMessage message;
message.type = LoaderMessageTypeStartByNameDetachedWithGuiError;
message.start.name = name ? strdup(name) : NULL;
message.start.args = args ? strdup(args) : NULL;
LoaderMessage message = {
.type = LoaderMessageTypeStartByNameDetachedWithGuiError,
.start.name = strdup(name),
.start.args = args ? strdup(args) : NULL,
};
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
}
@@ -194,11 +210,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
Loader* loader = context;
if(thread_state == FuriThreadStateRunning) {
LoaderEvent event;
event.type = LoaderEventTypeApplicationStarted;
furi_pubsub_publish(loader->pubsub, &event);
} else if(thread_state == FuriThreadStateStopped) {
if(thread_state == FuriThreadStateStopped) {
LoaderMessage message;
message.type = LoaderMessageTypeAppClosed;
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
@@ -407,6 +419,9 @@ static void loader_start_internal_app(
const FlipperInternalApplication* app,
const char* args) {
FURI_LOG_I(TAG, "Starting %s", app->name);
LoaderEvent event;
event.type = LoaderEventTypeApplicationBeforeLoad;
furi_pubsub_publish(loader->pubsub, &event);
// store args
furi_assert(loader->app.args == NULL);
@@ -462,6 +477,9 @@ static LoaderStatus loader_start_external_app(
FuriString* error_message,
FlipperApplicationFlag flags) {
LoaderStatus status = loader_make_success_status(error_message);
LoaderEvent event;
event.type = LoaderEventTypeApplicationBeforeLoad;
furi_pubsub_publish(loader->pubsub, &event);
do {
loader->app.fap = flipper_application_alloc(storage, firmware_api_interface);
@@ -489,7 +507,7 @@ static LoaderStatus loader_start_external_app(
if(load_status != FlipperApplicationLoadStatusSuccess) {
const char* err_msg = flipper_application_load_status_to_string(load_status);
status = loader_make_status_error(
LoaderStatusErrorInternal, error_message, "Load failed %s: %s", path, err_msg);
LoaderStatusErrorInternal, error_message, "Load failed, %s: %s", path, err_msg);
break;
} else if(api_mismatch) {
// Successful map, but found api mismatch -> warn user
@@ -544,12 +562,14 @@ static LoaderStatus loader_start_external_app(
}
loader_start_app_thread(loader, flags);
return status;
} while(0);
flipper_application_free(loader->app.fap);
loader->app.fap = NULL;
if(status != LoaderStatusOk) {
flipper_application_free(loader->app.fap);
loader->app.fap = NULL;
event.type = LoaderEventTypeApplicationLoadFailed;
furi_pubsub_publish(loader->pubsub, &event);
}
return status;
}
@@ -732,7 +752,7 @@ int32_t loader_srv(void* p) {
FuriString* error_message = furi_string_alloc();
LoaderStatus status = loader_do_start_by_name(
loader, message.start.name, message.start.args, error_message);
loader_show_gui_error(status, error_message);
loader_show_gui_error(status, message.start.name, error_message);
if(message.start.name) free((void*)message.start.name);
if(message.start.args) free((void*)message.start.args);
furi_string_free(error_message);

View File

@@ -18,7 +18,8 @@ typedef enum {
} LoaderStatus;
typedef enum {
LoaderEventTypeApplicationStarted,
LoaderEventTypeApplicationBeforeLoad,
LoaderEventTypeApplicationLoadFailed,
LoaderEventTypeApplicationStopped
} LoaderEventType;
@@ -32,7 +33,7 @@ typedef struct {
* @param[in] name application name or id
* @param[in] args application arguments
* @param[out] error_message detailed error message, can be NULL
* @return LoaderStatus
* @return LoaderStatus
*/
LoaderStatus
loader_start(Loader* instance, const char* name, const char* args, FuriString* error_message);
@@ -42,19 +43,19 @@ LoaderStatus
* @param[in] instance loader instance
* @param[in] name application name or id
* @param[in] args application arguments
* @return LoaderStatus
* @return LoaderStatus
*/
LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args);
/**
* @brief Start application detached with GUI error message
* @param[in] instance loader instance
* @param[in] name application name
* @param[in] name application name or id
* @param[in] args application arguments
*/
void loader_start_detached_with_gui_error(Loader* loader, const char* name, const char* args);
/**
/**
* @brief Lock application start
* @param[in] instance loader instance
* @return true on success

View File

@@ -33,8 +33,8 @@ typedef enum {
LoaderMessageTypeLock,
LoaderMessageTypeUnlock,
LoaderMessageTypeIsLocked,
LoaderMessageTypeStartByNameDetachedWithGuiError,
LoaderMessageTypeShowSettings,
} LoaderMessageType;

View File

@@ -25,9 +25,9 @@ static const uint8_t reset_display_mask = 1 << 5;
static const uint8_t reset_blink_mask = 1 << 6;
static void notification_vibro_on(bool force);
static void notification_vibro_off();
static void notification_vibro_off(void);
static void notification_sound_on(float freq, float volume, bool force);
static void notification_sound_off();
static void notification_sound_off(void);
static uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value);
static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value);

View File

@@ -300,9 +300,11 @@ static void power_loader_callback(const void* message, void* context) {
Power* power = context;
const LoaderEvent* event = message;
if(event->type == LoaderEventTypeApplicationStarted) {
if(event->type == LoaderEventTypeApplicationBeforeLoad) {
power_auto_shutdown_inhibit(power);
} else if(event->type == LoaderEventTypeApplicationStopped) {
} else if(
event->type == LoaderEventTypeApplicationLoadFailed ||
event->type == LoaderEventTypeApplicationStopped) {
power_auto_shutdown_arm(power);
}
}

View File

@@ -43,10 +43,12 @@ Storage* storage_app_alloc(void) {
}
#ifndef FURI_RAM_EXEC
storage_mnt_init(&app->storage[ST_MNT]);
storage_int_init(&app->storage[ST_INT]);
#endif
storage_ext_init(&app->storage[ST_EXT]);
#ifndef FURI_RAM_EXEC
storage_mnt_init(&app->storage[ST_MNT]);
#endif
// sd icon gui
app->sd_gui.enabled = false;

View File

@@ -156,3 +156,9 @@ size_t storage_open_files_count(StorageData* storage) {
size_t count = StorageFileList_size(storage->files);
return count;
}
const char* storage_file_get_path(File* file, StorageData* storage) {
StorageFile* storage_file_ref = storage_get_file(file, storage);
if(!storage_file_ref) return "";
return furi_string_get_cstr(storage_file_ref->path);
}

View File

@@ -35,6 +35,7 @@ void storage_file_init(StorageFile* obj);
void storage_file_init_set(StorageFile* obj, const StorageFile* src);
void storage_file_set(StorageFile* obj, const StorageFile* src);
void storage_file_clear(StorageFile* obj);
const char* storage_file_get_path(File* file, StorageData* storage);
void storage_data_init(StorageData* storage);
StorageStatus storage_data_status(StorageData* storage);

View File

@@ -4,6 +4,7 @@
#include <furi_hal.h>
#include "sd_notify.h"
#include <furi_hal_sd.h>
#include <toolbox/path.h>
typedef FIL SDFile;
typedef DIR SDDir;
@@ -741,6 +742,20 @@ FS_Error storage_process_virtual_format(StorageData* storage) {
SDError error = f_mkfs(sd_data->path, FM_ANY, 0, work, _MAX_SS);
free(work);
if(error != FR_OK) return FSE_INTERNAL;
if(storage_process_virtual_mount(storage) == FSE_OK) {
// Image file path
const char* img_path = storage_file_get_path(mnt_image, mnt_image_storage);
// Image file name
FuriString* img_name = furi_string_alloc();
path_extract_filename_no_ext(img_path, img_name);
// Label with drive id prefix
char* label = storage_ext_drive_path(storage, furi_string_get_cstr(img_name));
furi_string_free(img_name);
f_setlabel(label);
free(label);
storage_process_virtual_unmount(storage);
}
return FSE_OK;
#endif
}

View File

@@ -27,7 +27,7 @@ static void infrared_remote_clear_buttons(InfraredRemote* remote) {
InfraredButtonArray_reset(remote->buttons);
}
InfraredRemote* infrared_remote_alloc() {
InfraredRemote* infrared_remote_alloc(void) {
InfraredRemote* remote = malloc(sizeof(InfraredRemote));
InfraredButtonArray_init(remote->buttons);
remote->name = furi_string_alloc();

View File

@@ -8,7 +8,7 @@
typedef struct InfraredRemote InfraredRemote;
InfraredRemote* infrared_remote_alloc();
InfraredRemote* infrared_remote_alloc(void);
void infrared_remote_free(InfraredRemote* remote);
void infrared_remote_reset(InfraredRemote* remote);

View File

@@ -7,7 +7,7 @@ struct InfraredRemoteButton {
InfraredSignal* signal;
};
InfraredRemoteButton* infrared_remote_button_alloc() {
InfraredRemoteButton* infrared_remote_button_alloc(void) {
InfraredRemoteButton* button = malloc(sizeof(InfraredRemoteButton));
button->name = furi_string_alloc();
button->signal = infrared_signal_alloc();

View File

@@ -4,7 +4,7 @@
typedef struct InfraredRemoteButton InfraredRemoteButton;
InfraredRemoteButton* infrared_remote_button_alloc();
InfraredRemoteButton* infrared_remote_button_alloc(void);
void infrared_remote_button_free(InfraredRemoteButton* button);
void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name);

View File

@@ -166,7 +166,7 @@ static bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff)
return success;
}
InfraredSignal* infrared_signal_alloc() {
InfraredSignal* infrared_signal_alloc(void) {
InfraredSignal* signal = malloc(sizeof(InfraredSignal));
signal->is_raw = false;

View File

@@ -16,7 +16,7 @@ typedef struct {
float duty_cycle;
} InfraredRawSignal;
InfraredSignal* infrared_signal_alloc();
InfraredSignal* infrared_signal_alloc(void);
void infrared_signal_free(InfraredSignal* signal);
bool infrared_signal_is_raw(InfraredSignal* signal);

View File

@@ -3,7 +3,13 @@ let notify = require("notification");
let flipper = require("flipper");
let dialog = require("dialog");
badusb.setup({ vid: 0xAAAA, pid: 0xBBBB, mfr_name: "Flipper", prod_name: "Zero" });
badusb.setup({
vid: 0xAAAA,
pid: 0xBBBB,
mfr_name: "Flipper",
prod_name: "Zero",
layout_path: "/ext/badusb/assets/layouts/en-US.kl"
});
dialog.message("BadUSB demo", "Press OK to start");
if (badusb.isConnected()) {

View File

@@ -1,19 +1,36 @@
let storage = require("storage");
let path = "/ext/storage.test";
function arraybuf_to_string(arraybuf) {
let string = "";
let data_view = Uint8Array(arraybuf);
for (let i = 0; i < data_view.length; i++) {
string += chr(data_view[i]);
}
return string;
}
print("File exists:", storage.exists(path));
print("Writing...");
// write(path, data, offset)
// If offset is specified, the file is not cleared, content is kept and data is written at specified offset
// Takes both strings and array buffers
storage.write(path, "Hello ");
print("File exists:", storage.exists(path));
// Append will create the file even if it doesnt exist!
// Takes both strings and array buffers
storage.append(path, "World!");
print("Reading...");
// read(path, size, offset)
// If no size specified, total filesize is used
// If offset is specified, size is capped at (filesize - offset)
let data = storage.read(path);
print(data);
// read returns an array buffer, to allow proper usage of raw binary data
print(arraybuf_to_string(data));
print("Removing...")
storage.remove(path);
@@ -21,6 +38,9 @@ storage.remove(path);
print("Done")
// There's also:
// storage.copy(old_path, new_path);
// storage.move(old_path, new_path);
// storage.mkdir(path);
// storage.virtualInit(path);
// storage.virtualMount();
// storage.virtualQuit();

View File

@@ -2,8 +2,11 @@
#include "../js_modules.h"
#include <furi_hal.h>
#define ASCII_TO_KEY(layout, x) (((uint8_t)x < 128) ? (layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
typedef struct {
FuriHalUsbHidConfig* hid_cfg;
uint16_t layout[128];
FuriHalUsbInterface* usb_if_prev;
uint8_t key_hold_cnt;
} JsBadusbInst;
@@ -88,7 +91,11 @@ static void js_badusb_quit_free(JsBadusbInst* badusb) {
}
}
static bool setup_parse_params(struct mjs* mjs, mjs_val_t arg, FuriHalUsbHidConfig* hid_cfg) {
static bool setup_parse_params(
JsBadusbInst* badusb,
struct mjs* mjs,
mjs_val_t arg,
FuriHalUsbHidConfig* hid_cfg) {
if(!mjs_is_object(arg)) {
return false;
}
@@ -96,6 +103,7 @@ static bool setup_parse_params(struct mjs* mjs, mjs_val_t arg, FuriHalUsbHidConf
mjs_val_t pid_obj = mjs_get(mjs, arg, "pid", ~0);
mjs_val_t mfr_obj = mjs_get(mjs, arg, "mfr_name", ~0);
mjs_val_t prod_obj = mjs_get(mjs, arg, "prod_name", ~0);
mjs_val_t layout_obj = mjs_get(mjs, arg, "layout_path", ~0);
if(mjs_is_number(vid_obj) && mjs_is_number(pid_obj)) {
hid_cfg->vid = mjs_get_int32(mjs, vid_obj);
@@ -122,6 +130,25 @@ static bool setup_parse_params(struct mjs* mjs, mjs_val_t arg, FuriHalUsbHidConf
strlcpy(hid_cfg->product, str_temp, sizeof(hid_cfg->product));
}
if(mjs_is_string(layout_obj)) {
size_t str_len = 0;
const char* str_temp = mjs_get_string(mjs, &layout_obj, &str_len);
if((str_len == 0) || (str_temp == NULL)) {
return false;
}
File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
bool layout_loaded = storage_file_open(file, str_temp, FSAM_READ, FSOM_OPEN_EXISTING) &&
storage_file_read(file, badusb->layout, sizeof(badusb->layout)) ==
sizeof(badusb->layout);
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
if(!layout_loaded) {
return false;
}
} else {
memcpy(badusb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(badusb->layout)));
}
return true;
}
@@ -144,7 +171,7 @@ static void js_badusb_setup(struct mjs* mjs) {
} else if(num_args == 1) {
badusb->hid_cfg = malloc(sizeof(FuriHalUsbHidConfig));
// Parse argument object
args_correct = setup_parse_params(mjs, mjs_arg(mjs, 0), badusb->hid_cfg);
args_correct = setup_parse_params(badusb, mjs, mjs_arg(mjs, 0), badusb->hid_cfg);
}
if(!args_correct) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "");
@@ -191,9 +218,9 @@ static void js_badusb_is_connected(struct mjs* mjs) {
mjs_return(mjs, mjs_mk_boolean(mjs, is_connected));
}
uint16_t get_keycode_by_name(const char* key_name, size_t name_len) {
uint16_t get_keycode_by_name(JsBadusbInst* badusb, const char* key_name, size_t name_len) {
if(name_len == 1) { // Single char
return (HID_ASCII_TO_KEY(key_name[0]));
return (ASCII_TO_KEY(badusb->layout, key_name[0]));
}
for(size_t i = 0; i < COUNT_OF(key_codes); i++) {
@@ -210,7 +237,7 @@ uint16_t get_keycode_by_name(const char* key_name, size_t name_len) {
return HID_KEYBOARD_NONE;
}
static bool parse_keycode(struct mjs* mjs, size_t nargs, uint16_t* keycode) {
static bool parse_keycode(JsBadusbInst* badusb, struct mjs* mjs, size_t nargs, uint16_t* keycode) {
uint16_t key_tmp = 0;
for(size_t i = 0; i < nargs; i++) {
mjs_val_t arg = mjs_arg(mjs, i);
@@ -221,7 +248,7 @@ static bool parse_keycode(struct mjs* mjs, size_t nargs, uint16_t* keycode) {
// String error
return false;
}
uint16_t str_key = get_keycode_by_name(key_name, name_len);
uint16_t str_key = get_keycode_by_name(badusb, key_name, name_len);
if(str_key == HID_KEYBOARD_NONE) {
// Unknown key code
return false;
@@ -259,7 +286,7 @@ static void js_badusb_press(struct mjs* mjs) {
uint16_t keycode = HID_KEYBOARD_NONE;
size_t num_args = mjs_nargs(mjs);
if(num_args > 0) {
args_correct = parse_keycode(mjs, num_args, &keycode);
args_correct = parse_keycode(badusb, mjs, num_args, &keycode);
}
if(!args_correct) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "");
@@ -285,7 +312,7 @@ static void js_badusb_hold(struct mjs* mjs) {
uint16_t keycode = HID_KEYBOARD_NONE;
size_t num_args = mjs_nargs(mjs);
if(num_args > 0) {
args_correct = parse_keycode(mjs, num_args, &keycode);
args_correct = parse_keycode(badusb, mjs, num_args, &keycode);
}
if(!args_correct) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "");
@@ -324,7 +351,7 @@ static void js_badusb_release(struct mjs* mjs) {
mjs_return(mjs, MJS_UNDEFINED);
return;
} else {
args_correct = parse_keycode(mjs, num_args, &keycode);
args_correct = parse_keycode(badusb, mjs, num_args, &keycode);
}
if(!args_correct) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "");
@@ -347,14 +374,14 @@ static void ducky_numlock_on() {
}
// Simulate pressing a character using ALT+Numpad ASCII code
static void ducky_altchar(const char* ascii_code) {
static void ducky_altchar(JsBadusbInst* badusb, const char* ascii_code) {
// Hold the ALT key
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
// Press the corresponding numpad key for each digit of the ASCII code
for(size_t i = 0; ascii_code[i] != '\0'; i++) {
char digitChar[5] = {'N', 'U', 'M', ascii_code[i], '\0'}; // Construct the numpad key name
uint16_t numpad_keycode = get_keycode_by_name(digitChar, strlen(digitChar));
uint16_t numpad_keycode = get_keycode_by_name(badusb, digitChar, strlen(digitChar));
if(numpad_keycode == HID_KEYBOARD_NONE) {
continue; // Skip if keycode not found
}
@@ -420,9 +447,9 @@ static void badusb_print(struct mjs* mjs, bool ln, bool alt) {
// Convert character to ascii numeric value
char ascii_str[4];
snprintf(ascii_str, sizeof(ascii_str), "%u", (uint8_t)text_str[i]);
ducky_altchar(ascii_str);
ducky_altchar(badusb, ascii_str);
} else {
uint16_t keycode = HID_ASCII_TO_KEY(text_str[i]);
uint16_t keycode = ASCII_TO_KEY(badusb->layout, text_str[i]);
furi_hal_hid_kb_press(keycode);
furi_hal_hid_kb_release(keycode);
}

View File

@@ -211,7 +211,7 @@ void js_math_random(struct mjs* mjs) {
mjs_return(mjs, MJS_UNDEFINED);
}
const uint32_t random_val = furi_hal_random_get();
double rnd = (double)random_val / RAND_MAX;
double rnd = (double)random_val / FURI_HAL_RANDOM_MAX;
mjs_return(mjs, mjs_mk_number(mjs, rnd));
}

View File

@@ -32,8 +32,8 @@ static bool check_arg_count(struct mjs* mjs, size_t count) {
return true;
}
static bool get_path_arg(struct mjs* mjs, const char** path) {
mjs_val_t path_obj = mjs_arg(mjs, 0);
static bool get_path_arg(struct mjs* mjs, const char** path, size_t index) {
mjs_val_t path_obj = mjs_arg(mjs, index);
if(!mjs_is_string(path_obj)) {
ret_bad_args(mjs, "Path must be a string");
return false;
@@ -49,10 +49,9 @@ static bool get_path_arg(struct mjs* mjs, const char** path) {
static void js_storage_read(struct mjs* mjs) {
JsStorageInst* storage = get_this_ctx(mjs);
if(!check_arg_count(mjs, 1)) return;
const char* path;
if(!get_path_arg(mjs, &path)) return;
if(!get_path_arg(mjs, &path, 0)) return;
File* file = storage_file_alloc(storage->api);
do {
@@ -62,15 +61,26 @@ static void js_storage_read(struct mjs* mjs) {
}
uint64_t size = storage_file_size(file);
if(size > 128 * 1024) {
ret_int_err(mjs, "File too large");
mjs_val_t size_arg = mjs_arg(mjs, 1);
if(mjs_is_number(size_arg)) {
size = mjs_get_int32(mjs, size_arg);
}
mjs_val_t seek_arg = mjs_arg(mjs, 2);
if(mjs_is_number(seek_arg)) {
storage_file_seek(file, mjs_get_int32(mjs, seek_arg), true);
size = MIN(size, storage_file_size(file) - storage_file_tell(file));
}
if(size > memmgr_heap_get_max_free_block()) {
ret_int_err(mjs, "Read size too large");
break;
}
uint8_t* data = malloc(size);
size_t read = storage_file_read(file, data, size);
if(read == size) {
mjs_return(mjs, mjs_mk_string(mjs, (const char*)data, size, true));
mjs_return(mjs, mjs_mk_array_buf(mjs, (char*)data, size));
} else {
ret_int_err(mjs, "File read failed");
}
@@ -81,27 +91,41 @@ static void js_storage_read(struct mjs* mjs) {
static void js_storage_write(struct mjs* mjs) {
JsStorageInst* storage = get_this_ctx(mjs);
if(!check_arg_count(mjs, 2)) return;
const char* path;
if(!get_path_arg(mjs, &path)) return;
if(!get_path_arg(mjs, &path, 0)) return;
mjs_val_t data_obj = mjs_arg(mjs, 1);
if(!mjs_is_string(data_obj)) {
ret_bad_args(mjs, "Data must be a string");
mjs_val_t data_arg = mjs_arg(mjs, 1);
if(!mjs_is_typed_array(data_arg) && !mjs_is_string(data_arg)) {
ret_bad_args(mjs, "Data must be string, arraybuf or dataview");
return;
}
if(mjs_is_data_view(data_arg)) {
data_arg = mjs_dataview_get_buf(mjs, data_arg);
}
size_t data_len = 0;
const char* data = mjs_get_string(mjs, &data_obj, &data_len);
if((data_len == 0) || (data == NULL)) {
ret_bad_args(mjs, "Bad data argument");
return;
const char* data = NULL;
if(mjs_is_string(data_arg)) {
data = mjs_get_string(mjs, &data_arg, &data_len);
} else if(mjs_is_typed_array(data_arg)) {
data = mjs_array_buf_get_ptr(mjs, data_arg, &data_len);
}
mjs_val_t seek_arg = mjs_arg(mjs, 2);
File* file = storage_file_alloc(storage->api);
if(!storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
if(!storage_file_open(
file,
path,
FSAM_WRITE,
mjs_is_number(seek_arg) ? FSOM_OPEN_ALWAYS : FSOM_CREATE_ALWAYS)) {
ret_int_err(mjs, storage_file_get_error_desc(file));
} else {
if(mjs_is_number(seek_arg)) {
storage_file_seek(file, mjs_get_int32(mjs, seek_arg), true);
}
size_t write = storage_file_write(file, data, data_len);
mjs_return(mjs, mjs_mk_boolean(mjs, write == data_len));
}
@@ -113,18 +137,22 @@ static void js_storage_append(struct mjs* mjs) {
if(!check_arg_count(mjs, 2)) return;
const char* path;
if(!get_path_arg(mjs, &path)) return;
if(!get_path_arg(mjs, &path, 0)) return;
mjs_val_t data_obj = mjs_arg(mjs, 1);
if(!mjs_is_string(data_obj)) {
ret_bad_args(mjs, "Data must be a string");
mjs_val_t data_arg = mjs_arg(mjs, 1);
if(!mjs_is_typed_array(data_arg) && !mjs_is_string(data_arg)) {
ret_bad_args(mjs, "Data must be string, arraybuf or dataview");
return;
}
if(mjs_is_data_view(data_arg)) {
data_arg = mjs_dataview_get_buf(mjs, data_arg);
}
size_t data_len = 0;
const char* data = mjs_get_string(mjs, &data_obj, &data_len);
if((data_len == 0) || (data == NULL)) {
ret_bad_args(mjs, "Bad data argument");
return;
const char* data = NULL;
if(mjs_is_string(data_arg)) {
data = mjs_get_string(mjs, &data_arg, &data_len);
} else if(mjs_is_typed_array(data_arg)) {
data = mjs_array_buf_get_ptr(mjs, data_arg, &data_len);
}
File* file = storage_file_alloc(storage->api);
@@ -142,7 +170,7 @@ static void js_storage_exists(struct mjs* mjs) {
if(!check_arg_count(mjs, 1)) return;
const char* path;
if(!get_path_arg(mjs, &path)) return;
if(!get_path_arg(mjs, &path, 0)) return;
mjs_return(mjs, mjs_mk_boolean(mjs, storage_common_exists(storage->api, path)));
}
@@ -152,17 +180,63 @@ static void js_storage_remove(struct mjs* mjs) {
if(!check_arg_count(mjs, 1)) return;
const char* path;
if(!get_path_arg(mjs, &path)) return;
if(!get_path_arg(mjs, &path, 0)) return;
mjs_return(mjs, mjs_mk_boolean(mjs, storage_simply_remove(storage->api, path)));
}
static void js_storage_copy(struct mjs* mjs) {
JsStorageInst* storage = get_this_ctx(mjs);
if(!check_arg_count(mjs, 2)) return;
const char* old_path;
if(!get_path_arg(mjs, &old_path, 0)) return;
const char* new_path;
if(!get_path_arg(mjs, &new_path, 1)) return;
FS_Error error = storage_common_copy(storage->api, old_path, new_path);
if(error == FSE_OK) {
mjs_return(mjs, MJS_UNDEFINED);
} else {
ret_int_err(mjs, storage_error_get_desc(error));
}
}
static void js_storage_move(struct mjs* mjs) {
JsStorageInst* storage = get_this_ctx(mjs);
if(!check_arg_count(mjs, 2)) return;
const char* old_path;
if(!get_path_arg(mjs, &old_path, 0)) return;
const char* new_path;
if(!get_path_arg(mjs, &new_path, 1)) return;
FS_Error error = storage_common_rename(storage->api, old_path, new_path);
if(error == FSE_OK) {
mjs_return(mjs, MJS_UNDEFINED);
} else {
ret_int_err(mjs, storage_error_get_desc(error));
}
}
static void js_storage_mkdir(struct mjs* mjs) {
JsStorageInst* storage = get_this_ctx(mjs);
if(!check_arg_count(mjs, 1)) return;
const char* path;
if(!get_path_arg(mjs, &path, 0)) return;
mjs_return(mjs, mjs_mk_boolean(mjs, storage_simply_mkdir(storage->api, path)));
}
static void js_storage_virtual_init(struct mjs* mjs) {
JsStorageInst* storage = get_this_ctx(mjs);
if(!check_arg_count(mjs, 1)) return;
const char* path;
if(!get_path_arg(mjs, &path)) return;
if(!get_path_arg(mjs, &path, 0)) return;
if(storage->virtual) {
ret_int_err(mjs, "Virtual already setup");
@@ -214,6 +288,11 @@ static void js_storage_virtual_quit(struct mjs* mjs) {
return;
}
if(storage->virtual) {
storage_file_free(storage->virtual);
storage->virtual = NULL;
}
mjs_return(mjs, MJS_UNDEFINED);
}
@@ -226,6 +305,9 @@ static void* js_storage_create(struct mjs* mjs, mjs_val_t* object) {
mjs_set(mjs, storage_obj, "append", ~0, MJS_MK_FN(js_storage_append));
mjs_set(mjs, storage_obj, "exists", ~0, MJS_MK_FN(js_storage_exists));
mjs_set(mjs, storage_obj, "remove", ~0, MJS_MK_FN(js_storage_remove));
mjs_set(mjs, storage_obj, "copy", ~0, MJS_MK_FN(js_storage_copy));
mjs_set(mjs, storage_obj, "move", ~0, MJS_MK_FN(js_storage_move));
mjs_set(mjs, storage_obj, "mkdir", ~0, MJS_MK_FN(js_storage_mkdir));
mjs_set(mjs, storage_obj, "virtualInit", ~0, MJS_MK_FN(js_storage_virtual_init));
mjs_set(mjs, storage_obj, "virtualMount", ~0, MJS_MK_FN(js_storage_virtual_mount));
mjs_set(mjs, storage_obj, "virtualQuit", ~0, MJS_MK_FN(js_storage_virtual_quit));

View File

@@ -2,7 +2,7 @@
#define TAG "SubRemPresets"
SubRemSubFilePreset* subrem_sub_file_preset_alloc() {
SubRemSubFilePreset* subrem_sub_file_preset_alloc(void) {
SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset));
sub_preset->fff_data = flipper_format_string_alloc();

View File

@@ -27,7 +27,7 @@ typedef struct {
SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount];
} SubRemMapPreset;
SubRemSubFilePreset* subrem_sub_file_preset_alloc();
SubRemSubFilePreset* subrem_sub_file_preset_alloc(void);
void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset);

View File

@@ -25,7 +25,7 @@ static void subghz_txrx_radio_device_power_off(SubGhzTxRx* instance) {
if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
}
SubGhzTxRx* subghz_txrx_alloc() {
SubGhzTxRx* subghz_txrx_alloc(void) {
SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx));
instance->setting = subghz_setting_alloc();
subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user"));

View File

@@ -53,7 +53,7 @@ typedef enum {
*
* @return SubGhzTxRx* pointer to SubGhzTxRx
*/
SubGhzTxRx* subghz_txrx_alloc();
SubGhzTxRx* subghz_txrx_alloc(void);
/**
* Free SubGhzTxRx

View File

@@ -242,7 +242,7 @@ void subrem_view_edit_menu_exit(void* context) {
furi_assert(context);
}
SubRemViewEditMenu* subrem_view_edit_menu_alloc() {
SubRemViewEditMenu* subrem_view_edit_menu_alloc(void) {
SubRemViewEditMenu* subrem_view_edit_menu = malloc(sizeof(SubRemViewEditMenu));
// View allocation and configuration

View File

@@ -13,7 +13,7 @@ void subrem_view_edit_menu_set_callback(
SubRemViewEditMenuCallback callback,
void* context);
SubRemViewEditMenu* subrem_view_edit_menu_alloc();
SubRemViewEditMenu* subrem_view_edit_menu_alloc(void);
void subrem_view_edit_menu_free(SubRemViewEditMenu* subrem_view_edit_menu);

View File

@@ -277,7 +277,7 @@ void subrem_view_remote_exit(void* context) {
furi_assert(context);
}
SubRemViewRemote* subrem_view_remote_alloc() {
SubRemViewRemote* subrem_view_remote_alloc(void) {
SubRemViewRemote* subrem_view_remote = malloc(sizeof(SubRemViewRemote));
// View allocation and configuration

View File

@@ -20,7 +20,7 @@ void subrem_view_remote_set_callback(
SubRemViewRemoteCallback callback,
void* context);
SubRemViewRemote* subrem_view_remote_alloc();
SubRemViewRemote* subrem_view_remote_alloc(void);
void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Some files were not shown because too many files have changed in this diff Show More