This commit is contained in:
Willy-JL
2024-06-17 20:21:08 +02:00
26 changed files with 382 additions and 150 deletions

View File

@@ -1,5 +1,4 @@
### Breaking Changes:
- OFW: NFC: Reading Apple/Google Pay can crash due to new Mifare Plus poller
- VGM: Reworked color customization functionality over RPC (by @HaxSam & @Willy-JL)
- Better rainbow support, more responsive config, custom fore/back-ground
- If you used this, need to reflash your VGM and reconfigure the colors
@@ -9,11 +8,11 @@
### Added:
- Sub-GHz:
- New Legrand doorbell protocol (by @user890104)
- OFW: Princeton protocol add custom guard time (by @Skorpionm)
- OFW: Princeton protocol add custom guard time (by @Skorpionm & @xMasterX)
- NFC:
- OFW: Mifare Plus detection support (by @Astrrra)
- OFW: Felica emulation (by @RebornedBrain)
- OFW: Write to ultralight cards is now possible (by @RebornedBrain)
- OFW: Write to Ultralight cards is now possible (by @RebornedBrain & @gornekich)
- OFW: RFID: Added Support for Securakey Protocol (by @zinongli)
- MNTM Settings: Click Ok on Asset Pack setting to choose from a full-screen list (by @Willy-JL)
- JS: Added ADC (analog voltage) support to gpio library (by @jamisonderek)
@@ -46,11 +45,12 @@
- Archive: Fix favorite's parent folders thinking they are favorited too (by @Willy-JL)
- FBT: Consistent version/branch info, fix gitorigin (by @Willy-JL)
- AssetPacker: Pack pre-compiled icons and fonts too (by @Willy-JL)
- OFW: ELF/Flipper application: Do not crash on "out of memory" (by @DrZlo13)
- OFW: JS: Disable logging in mjs +2k free flash (by @hedger)
- OFW: NFC: Fixed infinite loop in dictionary attack scene (by @RebornedBrain)
- OFW: Desktop: Lockup fix, GUI improvements (by @skotopes)
- OFW: Sub-GHz: Fixed transition to Saved menu after Delete RAW (by @Skorpionm)
- OFW: Loader: fix crash on locked via cli loader (by @DrZlo13)
- OFW: Loader: Fix crash on locked via cli loader (by @DrZlo13)
- OFW: Archive: Fix memory leak in favorites add/remove (by @skotopes)
- OFW: Accessor: Disable expansion service on start (by @skotopes)
- OFW: Cleanup of various warnings from clangd (by @hedger)

View File

@@ -41,8 +41,7 @@ static NfcCommand nfc_scene_read_poller_callback_mf_plus(NfcGenericEvent event,
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
command = NfcCommandStop;
} else if(mf_plus_event->type == MfPlusPollerEventTypeReadFailed) {
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerFailure);
command = NfcCommandStop;
command = NfcCommandReset;
}
return command;

View File

@@ -192,7 +192,7 @@ static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instanc
} else if(
data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 ||
data->type == MfUltralightTypeNTAG216 || data->type == MfUltralightTypeUL11 ||
data->type == MfUltralightTypeUL21) {
data->type == MfUltralightTypeUL21 || data->type == MfUltralightTypeOrigin) {
submenu_add_item(
submenu,
"Write",

View File

@@ -465,13 +465,10 @@ static bool nfc_is_hal_ready(void) {
// No connection to the chip, show an error screen
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
DialogMessage* message = dialog_message_alloc();
dialog_message_set_header(message, "Error: NFC Chip Failed", 64, 0, AlignCenter, AlignTop);
dialog_message_set_text(
message,
"Error!\nNFC chip failed to start\n\n\nSend a photo of this to:\nsupport@flipperzero.one",
0,
0,
AlignLeft,
AlignTop);
message, "Send error photo via\nsupport.flipper.net", 0, 63, AlignLeft, AlignBottom);
dialog_message_set_icon(message, &I_err_09, 128 - 25, 64 - 25);
dialog_message_show(dialogs, message);
dialog_message_free(message);
furi_record_close(RECORD_DIALOGS);

View File

@@ -41,11 +41,11 @@ static const char*
// API
LoaderStatus
loader_start(Loader* loader, const char* name, const char* args, FuriString* error_message) {
furi_check(loader);
furi_check(name);
static LoaderMessageLoaderStatusResult loader_start_internal(
Loader* loader,
const char* name,
const char* args,
FuriString* error_message) {
LoaderMessage message;
LoaderMessageLoaderStatusResult result;
@@ -58,44 +58,127 @@ LoaderStatus
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
api_lock_wait_unlock_and_free(message.api_lock);
return result.value;
return result;
}
static void
loader_show_gui_error(LoaderStatus status, const char* name, FuriString* error_message) {
if(status == LoaderStatusErrorUnknownApp &&
typedef struct {
const char* error;
const char* description;
const char* url;
const Icon* icon;
} LoaderError;
static const LoaderError err_app_not_found =
{"App Not Found", "Update firmware or app", "err_01", &I_err_01};
static const LoaderError err_invalid_flie = {"Invalid File", "Update the app", "err_02", &I_err_02};
static const LoaderError err_invalid_manifest =
{"Invalid Manifest", "Update firmware or app", "err_03", &I_err_03};
static const LoaderError err_missing_imports =
{"Missing Imports", "Update firmware", "err_04", &I_err_04};
static const LoaderError err_hw_target_mismatch =
{"HW Target\nMismatch", "App not supported", "err_05", &I_err_05};
static const LoaderError err_outdated_app = {"Outdated App", "Update the app", "err_06", &I_err_06};
static const LoaderError err_outdated_firmware =
{"Outdated\nFirmware", "Update firmware", "err_07", &I_err_07};
static void loader_dialog_prepare_and_show(DialogsApp* dialogs, const LoaderError* err) {
FuriString* header = furi_string_alloc_printf("Error: %s", err->error);
FuriString* text =
furi_string_alloc_printf("%s\nLearn more:\nr.flipper.net/%s", err->description, err->url);
DialogMessage* message = dialog_message_alloc();
dialog_message_set_header(message, furi_string_get_cstr(header), 64, 0, AlignCenter, AlignTop);
dialog_message_set_text(message, furi_string_get_cstr(text), 0, 63, AlignLeft, AlignBottom);
dialog_message_set_icon(message, err->icon, 128 - 25, 64 - 25);
dialog_message_show(dialogs, message);
dialog_message_free(message);
furi_string_free(header);
furi_string_free(text);
}
static void loader_show_gui_error(
LoaderMessageLoaderStatusResult status,
const char* name,
FuriString* error_message) {
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
DialogMessage* message = dialog_message_alloc();
if(status.value == 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) {
} else if(status.value == LoaderStatusErrorUnknownApp) {
loader_dialog_prepare_and_show(dialogs, &err_app_not_found);
} else if(status.value == 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);
dialog_message_set_buttons(message, NULL, NULL, NULL);
switch(status.error) {
case LoaderStatusErrorInvalidFile:
loader_dialog_prepare_and_show(dialogs, &err_invalid_flie);
break;
case LoaderStatusErrorInvalidManifest:
loader_dialog_prepare_and_show(dialogs, &err_invalid_manifest);
break;
case LoaderStatusErrorMissingImports:
loader_dialog_prepare_and_show(dialogs, &err_missing_imports);
break;
case LoaderStatusErrorHWMismatch:
loader_dialog_prepare_and_show(dialogs, &err_hw_target_mismatch);
break;
case LoaderStatusErrorOutdatedApp:
loader_dialog_prepare_and_show(dialogs, &err_outdated_app);
break;
case LoaderStatusErrorOutdatedFirmware:
loader_dialog_prepare_and_show(dialogs, &err_outdated_firmware);
break;
case LoaderStatusErrorOutOfMemory:
dialog_message_set_header(
message, "Error: Out of Memory", 64, 0, AlignCenter, AlignTop);
dialog_message_set_text(
message,
"Not enough RAM to run the\napp. Please reboot the device",
64,
13,
AlignCenter,
AlignTop);
dialog_message_set_buttons(message, NULL, NULL, "Reboot");
if(dialog_message_show(dialogs, message) == DialogMessageButtonRight) {
furi_hal_power_reset();
}
break;
default:
// Generic error
dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop);
furi_string_replace(error_message, ":", "\n");
furi_string_replace(error_message, "/ext/apps/", "");
furi_string_replace(error_message, ", ", "\n");
furi_string_replace(error_message, ": ", "\n");
furi_string_replace(error_message, ":", "\n");
furi_string_replace(error_message, "/ext/apps/", "");
furi_string_replace(error_message, ", ", "\n");
furi_string_replace(error_message, ": ", "\n");
dialog_message_set_text(
message, furi_string_get_cstr(error_message), 64, 35, AlignCenter, AlignCenter);
dialog_message_show(dialogs, message);
dialog_message_free(message);
furi_record_close(RECORD_DIALOGS);
dialog_message_set_text(
message, furi_string_get_cstr(error_message), 64, 35, AlignCenter, AlignCenter);
dialog_message_show(dialogs, message);
break;
}
}
dialog_message_free(message);
furi_record_close(RECORD_DIALOGS);
}
LoaderStatus
loader_start(Loader* loader, const char* name, const char* args, FuriString* error_message) {
furi_check(loader);
furi_check(name);
LoaderMessageLoaderStatusResult result =
loader_start_internal(loader, name, args, error_message);
return result.value;
}
LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args) {
@@ -103,10 +186,11 @@ LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const
furi_check(name);
FuriString* error_message = furi_string_alloc();
LoaderStatus status = loader_start(loader, name, args, error_message);
loader_show_gui_error(status, name, error_message);
LoaderMessageLoaderStatusResult result =
loader_start_internal(loader, name, args, error_message);
loader_show_gui_error(result, name, error_message);
furi_string_free(error_message);
return status;
return result.value;
}
void loader_start_detached_with_gui_error(Loader* loader, const char* name, const char* args) {
@@ -469,14 +553,47 @@ static LoaderStatus loader_make_success_status(FuriString* error_message) {
return LoaderStatusOk;
}
static LoaderStatus loader_start_external_app(
static LoaderStatusError
loader_status_error_from_preload_status(FlipperApplicationPreloadStatus status) {
switch(status) {
case FlipperApplicationPreloadStatusInvalidFile:
return LoaderStatusErrorInvalidFile;
case FlipperApplicationPreloadStatusNotEnoughMemory:
return LoaderStatusErrorOutOfMemory;
case FlipperApplicationPreloadStatusInvalidManifest:
return LoaderStatusErrorInvalidManifest;
case FlipperApplicationPreloadStatusApiTooOld:
return LoaderStatusErrorOutdatedApp;
case FlipperApplicationPreloadStatusApiTooNew:
return LoaderStatusErrorOutdatedFirmware;
case FlipperApplicationPreloadStatusTargetMismatch:
return LoaderStatusErrorHWMismatch;
default:
return LoaderStatusErrorUnknown;
}
}
static LoaderStatusError
loader_status_error_from_load_status(FlipperApplicationLoadStatus status) {
switch(status) {
case FlipperApplicationLoadStatusMissingImports:
return LoaderStatusErrorMissingImports;
default:
return LoaderStatusErrorUnknown;
}
}
static LoaderMessageLoaderStatusResult loader_start_external_app(
Loader* loader,
Storage* storage,
const char* path,
const char* args,
FuriString* error_message,
FlipperApplicationFlag flags) {
LoaderStatus status = loader_make_success_status(error_message);
LoaderMessageLoaderStatusResult result;
result.value = loader_make_success_status(error_message);
result.error = LoaderStatusErrorUnknown;
LoaderEvent event;
event.type = LoaderEventTypeApplicationBeforeLoad;
furi_pubsub_publish(loader->pubsub, &event);
@@ -495,8 +612,9 @@ static LoaderStatus loader_start_external_app(
api_mismatch = true;
} else if(preload_res != FlipperApplicationPreloadStatusSuccess) {
const char* err_msg = flipper_application_preload_status_to_string(preload_res);
status = loader_make_status_error(
result.value = loader_make_status_error(
LoaderStatusErrorInternal, error_message, "Preload failed, %s: %s", path, err_msg);
result.error = loader_status_error_from_preload_status(preload_res);
break;
}
@@ -506,8 +624,9 @@ static LoaderStatus loader_start_external_app(
FURI_LOG_I(TAG, "Loaded in %zums", (size_t)(furi_get_tick() - start));
if(load_status != FlipperApplicationLoadStatusSuccess) {
const char* err_msg = flipper_application_load_status_to_string(load_status);
status = loader_make_status_error(
result.value = loader_make_status_error(
LoaderStatusErrorInternal, error_message, "Load failed, %s: %s", path, err_msg);
result.error = loader_status_error_from_load_status(load_status);
break;
} else if(api_mismatch) {
// Successful map, but found api mismatch -> warn user
@@ -548,7 +667,7 @@ static LoaderStatus loader_start_external_app(
FURI_LOG_I(TAG, "Starting app");
if(flipper_application_is_plugin(loader->app.fap)) {
status = loader_make_status_error(
result.value = loader_make_status_error(
LoaderStatusErrorInternal, error_message, "Plugin %s is not runnable", path);
break;
}
@@ -570,14 +689,14 @@ static LoaderStatus loader_start_external_app(
loader_start_app_thread(loader, flags);
} while(0);
if(status != LoaderStatusOk) {
if(result.value != LoaderStatusOk) {
flipper_application_free(loader->app.fap);
loader->app.fap = NULL;
event.type = LoaderEventTypeApplicationLoadFailed;
furi_pubsub_publish(loader->pubsub, &event);
}
return status;
return result;
}
// process messages
@@ -613,23 +732,26 @@ static bool loader_do_is_locked(Loader* loader) {
return loader->app.thread != NULL;
}
static LoaderStatus loader_do_start_by_name(
static LoaderMessageLoaderStatusResult loader_do_start_by_name(
Loader* loader,
const char* name,
const char* args,
FuriString* error_message) {
LoaderStatus status;
LoaderMessageLoaderStatusResult status;
status.value = loader_make_success_status(error_message);
status.error = LoaderStatusErrorUnknown;
do {
// check lock
if(loader_do_is_locked(loader)) {
if(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE) {
status = loader_make_status_error(
status.value = loader_make_status_error(
LoaderStatusErrorAppStarted, error_message, "Loader is locked");
} else {
const char* current_thread_name =
furi_thread_get_name(furi_thread_get_id(loader->app.thread));
status = loader_make_status_error(
status.value = loader_make_status_error(
LoaderStatusErrorAppStarted,
error_message,
"Loader is locked, please close the \"%s\" first",
@@ -648,7 +770,7 @@ static LoaderStatus loader_do_start_by_name(
const FlipperInternalApplication* app = loader_find_application_by_name(name);
if(app) {
loader_start_internal_app(loader, app, args);
status = loader_make_success_status(error_message);
status.value = loader_make_success_status(error_message);
break;
}
}
@@ -656,7 +778,7 @@ static LoaderStatus loader_do_start_by_name(
// check Applications
if(strcmp(name, LOADER_APPLICATIONS_NAME) == 0) {
loader_do_applications_show(loader);
status = loader_make_success_status(error_message);
status.value = loader_make_success_status(error_message);
break;
}
@@ -681,7 +803,7 @@ static LoaderStatus loader_do_start_by_name(
furi_record_close(RECORD_STORAGE);
}
status = loader_make_status_error(
status.value = loader_make_status_error(
LoaderStatusErrorUnknownApp, error_message, "Application \"%s\" not found", name);
} while(false);
@@ -756,13 +878,13 @@ int32_t loader_srv(void* p) {
if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) {
switch(message.type) {
case LoaderMessageTypeStartByName:
message.status_value->value = loader_do_start_by_name(
*(message.status_value) = loader_do_start_by_name(
loader, message.start.name, message.start.args, message.start.error_message);
api_lock_unlock(message.api_lock);
break;
case LoaderMessageTypeStartByNameDetachedWithGuiError: {
FuriString* error_message = furi_string_alloc();
LoaderStatus status = loader_do_start_by_name(
LoaderMessageLoaderStatusResult status = loader_do_start_by_name(
loader, message.start.name, message.start.args, error_message);
loader_show_gui_error(status, message.start.name, error_message);
if(message.start.name) free((void*)message.start.name);

View File

@@ -44,8 +44,20 @@ typedef struct {
FuriString* error_message;
} LoaderMessageStartByName;
typedef enum {
LoaderStatusErrorUnknown,
LoaderStatusErrorInvalidFile,
LoaderStatusErrorInvalidManifest,
LoaderStatusErrorMissingImports,
LoaderStatusErrorHWMismatch,
LoaderStatusErrorOutdatedApp,
LoaderStatusErrorOutOfMemory,
LoaderStatusErrorOutdatedFirmware,
} LoaderStatusError;
typedef struct {
LoaderStatus value;
LoaderStatusError error;
} LoaderMessageLoaderStatusResult;
typedef struct {

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

View File

@@ -435,7 +435,6 @@ static bool elf_relocate(ELFFile* elf, ELFSection* s) {
/************************************ Internal FAP interfaces *************************************/
/**************************************************************************************************/
typedef enum {
SectionTypeERROR = 0,
SectionTypeUnused = 1 << 0,
SectionTypeData = 1 << 1,
SectionTypeRelData = 1 << 2,
@@ -443,8 +442,6 @@ typedef enum {
SectionTypeStrTab = 1 << 4,
SectionTypeDebugLink = 1 << 5,
SectionTypeFastRelData = 1 << 6,
SectionTypeValid = SectionTypeSymTab | SectionTypeStrTab,
} SectionType;
static bool elf_load_debug_link(ELFFile* elf, Elf32_Shdr* section_header) {
@@ -460,37 +457,62 @@ static bool str_prefix(const char* str, const char* prefix) {
return strncmp(prefix, str, strlen(prefix)) == 0;
}
static bool elf_load_section_data(ELFFile* elf, ELFSection* section, Elf32_Shdr* section_header) {
typedef enum {
ELFLoadSectionResultSuccess,
ELFLoadSectionResultNoMemory,
ELFLoadSectionResultError,
} ELFLoadSectionResult;
typedef struct {
SectionType type;
ELFLoadSectionResult result;
} SectionTypeInfo;
static ELFLoadSectionResult
elf_load_section_data(ELFFile* elf, ELFSection* section, Elf32_Shdr* section_header) {
if(section_header->sh_size == 0) {
FURI_LOG_D(TAG, "No data for section");
return true;
return ELFLoadSectionResultSuccess;
}
size_t safe_size = section_header->sh_size + 1024;
furi_kernel_lock();
if(memmgr_heap_get_max_free_block() < safe_size) {
furi_kernel_unlock();
FURI_LOG_E(TAG, "Not enough memory to load section data");
return ELFLoadSectionResultNoMemory;
}
section->data = aligned_malloc(section_header->sh_size, section_header->sh_addralign);
section->size = section_header->sh_size;
furi_kernel_unlock();
if(section_header->sh_type == SHT_NOBITS) {
// BSS section, no data to load
return true;
return ELFLoadSectionResultSuccess;
}
if((!storage_file_seek(elf->fd, section_header->sh_offset, true)) ||
(storage_file_read(elf->fd, section->data, section_header->sh_size) !=
section_header->sh_size)) {
FURI_LOG_E(TAG, " seek/read fail");
return false;
return ELFLoadSectionResultError;
}
FURI_LOG_D(TAG, "0x%p", section->data);
return true;
return ELFLoadSectionResultSuccess;
}
static SectionType elf_preload_section(
static SectionTypeInfo elf_preload_section(
ELFFile* elf,
size_t section_idx,
Elf32_Shdr* section_header,
FuriString* name_string) {
const char* name = furi_string_get_cstr(name_string);
SectionTypeInfo info;
#ifdef ELF_DEBUG_LOG
// log section name, type and flags
@@ -527,7 +549,10 @@ static SectionType elf_preload_section(
if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.") ||
str_prefix(name, ".fast.rel.ARM.")) {
FURI_LOG_D(TAG, "Ignoring ARM section");
return SectionTypeUnused;
info.type = SectionTypeUnused;
info.result = ELFLoadSectionResultSuccess;
return info;
}
// Load allocable section
@@ -546,26 +571,32 @@ static SectionType elf_preload_section(
elf->fini_array = section_p;
}
if(!elf_load_section_data(elf, section_p, section_header)) {
info.type = SectionTypeData;
info.result = elf_load_section_data(elf, section_p, section_header);
if(info.result != ELFLoadSectionResultSuccess) {
FURI_LOG_E(TAG, "Error loading section '%s'", name);
return SectionTypeERROR;
} else {
return SectionTypeData;
}
return info;
}
// Load link info section
if(section_header->sh_flags & SHF_INFO_LINK) {
info.type = SectionTypeRelData;
if(str_prefix(name, ".rel")) {
name = name + strlen(".rel");
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel);
section_p->rel_offset = section_header->sh_offset;
return SectionTypeRelData;
info.result = ELFLoadSectionResultSuccess;
} else {
FURI_LOG_E(TAG, "Unknown link info section '%s'", name);
return SectionTypeERROR;
info.result = ELFLoadSectionResultError;
}
return info;
}
// Load fast rel section
@@ -574,13 +605,16 @@ static SectionType elf_preload_section(
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
section_p->fast_rel = malloc(sizeof(ELFSection));
if(!elf_load_section_data(elf, section_p->fast_rel, section_header)) {
info.type = SectionTypeFastRelData;
info.result = elf_load_section_data(elf, section_p->fast_rel, section_header);
if(info.result != ELFLoadSectionResultSuccess) {
FURI_LOG_E(TAG, "Error loading section '%s'", name);
return SectionTypeERROR;
} else {
FURI_LOG_D(TAG, "Loaded fast rel section for '%s'", name);
}
FURI_LOG_D(TAG, "Loaded fast rel section for '%s'", name);
return SectionTypeFastRelData;
return info;
}
// Load symbol table
@@ -588,27 +622,39 @@ static SectionType elf_preload_section(
FURI_LOG_D(TAG, "Found .symtab section");
elf->symbol_table = section_header->sh_offset;
elf->symbol_count = section_header->sh_size / sizeof(Elf32_Sym);
return SectionTypeSymTab;
info.type = SectionTypeSymTab;
info.result = ELFLoadSectionResultSuccess;
return info;
}
// Load string table
if(strcmp(name, ".strtab") == 0) {
FURI_LOG_D(TAG, "Found .strtab section");
elf->symbol_table_strings = section_header->sh_offset;
return SectionTypeStrTab;
info.type = SectionTypeStrTab;
info.result = ELFLoadSectionResultSuccess;
return info;
}
// Load debug link section
if(strcmp(name, ".gnu_debuglink") == 0) {
FURI_LOG_D(TAG, "Found .gnu_debuglink section");
info.type = SectionTypeDebugLink;
if(elf_load_debug_link(elf, section_header)) {
return SectionTypeDebugLink;
info.result = ELFLoadSectionResultSuccess;
return info;
} else {
return SectionTypeERROR;
info.result = ELFLoadSectionResultError;
return info;
}
}
return SectionTypeUnused;
info.type = SectionTypeUnused;
info.result = ELFLoadSectionResultSuccess;
return info;
}
static Elf32_Addr elf_address_of_by_hash(ELFFile* elf, uint32_t hash) {
@@ -836,35 +882,57 @@ bool elf_file_open(ELFFile* elf, const char* path) {
return true;
}
bool elf_file_load_section_table(ELFFile* elf) {
SectionType loaded_sections = SectionTypeERROR;
ElfLoadSectionTableResult elf_file_load_section_table(ELFFile* elf) {
SectionType loaded_sections = 0;
FuriString* name = furi_string_alloc();
ElfLoadSectionTableResult result = ElfLoadSectionTableResultSuccess;
FURI_LOG_D(TAG, "Scan ELF indexs...");
// TODO FL-3526: why we start from 1?
for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) {
Elf32_Shdr section_header;
furi_string_reset(name);
if(!elf_read_section(elf, section_idx, &section_header, name)) {
loaded_sections = SectionTypeERROR;
loaded_sections = 0;
break;
}
FURI_LOG_D(
TAG, "Preloading data for section #%d %s", section_idx, furi_string_get_cstr(name));
SectionType section_type = elf_preload_section(elf, section_idx, &section_header, name);
loaded_sections |= section_type;
SectionTypeInfo section_type_info =
elf_preload_section(elf, section_idx, &section_header, name);
loaded_sections |= section_type_info.type;
if(section_type == SectionTypeERROR) {
loaded_sections = SectionTypeERROR;
if(section_type_info.result != ELFLoadSectionResultSuccess) {
if(section_type_info.result == ELFLoadSectionResultNoMemory) {
FURI_LOG_E(TAG, "Not enough memory");
result = ElfLoadSectionTableResultNoMemory;
} else if(section_type_info.result == ELFLoadSectionResultError) {
FURI_LOG_E(TAG, "Error loading section");
result = ElfLoadSectionTableResultError;
}
loaded_sections = 0;
break;
}
}
furi_string_free(name);
return IS_FLAGS_SET(loaded_sections, SectionTypeValid);
if(result != ElfLoadSectionTableResultSuccess) {
return result;
} else {
bool sections_valid =
IS_FLAGS_SET(loaded_sections, SectionTypeSymTab | SectionTypeStrTab) |
IS_FLAGS_SET(loaded_sections, SectionTypeFastRelData);
if(sections_valid) {
return ElfLoadSectionTableResultSuccess;
} else {
FURI_LOG_E(TAG, "No valid sections found");
return ElfLoadSectionTableResultError;
}
}
}
ElfProcessSectionResult elf_process_section(
@@ -877,7 +945,6 @@ ElfProcessSectionResult elf_process_section(
Elf32_Shdr section_header;
// find section
// TODO FL-3526: why we start from 1?
for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) {
furi_string_reset(section_name);
if(!elf_read_section(elf, section_idx, &section_header, section_name)) {

View File

@@ -33,7 +33,6 @@ typedef struct {
typedef enum {
ELFFileLoadStatusSuccess = 0,
ELFFileLoadStatusUnspecifiedError,
ELFFileLoadStatusNoFreeMemory,
ELFFileLoadStatusMissingImports,
} ELFFileLoadStatus;
@@ -43,6 +42,12 @@ typedef enum {
ElfProcessSectionResultSuccess,
} ElfProcessSectionResult;
typedef enum {
ElfLoadSectionTableResultError,
ElfLoadSectionTableResultNoMemory,
ElfLoadSectionTableResultSuccess,
} ElfLoadSectionTableResult;
typedef bool(ElfProcessSection)(File* file, size_t offset, size_t size, void* context);
/**
@@ -70,9 +75,9 @@ bool elf_file_open(ELFFile* elf_file, const char* path);
/**
* @brief Load ELF file section table (load stage #1)
* @param elf_file
* @return bool
* @return ElfLoadSectionTableResult
*/
bool elf_file_load_section_table(ELFFile* elf_file);
ElfLoadSectionTableResult elf_file_load_section_table(ELFFile* elf_file);
/**
* @brief Load and relocate ELF file sections (load stage #2)

View File

@@ -162,8 +162,11 @@ static FlipperApplicationPreloadStatus
// if we are loading full file
if(load_full) {
// load section table
if(!elf_file_load_section_table(app->elf)) {
ElfLoadSectionTableResult load_result = elf_file_load_section_table(app->elf);
if(load_result == ElfLoadSectionTableResultError) {
return FlipperApplicationPreloadStatusInvalidFile;
} else if(load_result == ElfLoadSectionTableResultNoMemory) {
return FlipperApplicationPreloadStatusNotEnoughMemory;
}
// load assets section
@@ -220,8 +223,6 @@ FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplicatio
elf_file_init_debug_info(app->elf, &app->state);
flipper_application_list_add_app(app);
return FlipperApplicationLoadStatusSuccess;
case ELFFileLoadStatusNoFreeMemory:
return FlipperApplicationLoadStatusNoFreeMemory;
case ELFFileLoadStatusMissingImports:
return FlipperApplicationLoadStatusMissingImports;
default:
@@ -273,38 +274,38 @@ FuriThread* flipper_application_alloc_thread(FlipperApplication* app, const char
return app->thread;
}
static const char* preload_status_strings[] = {
[FlipperApplicationPreloadStatusSuccess] = "Success",
[FlipperApplicationPreloadStatusUnspecifiedError] = "Unknown error",
[FlipperApplicationPreloadStatusInvalidFile] = "Invalid file",
[FlipperApplicationPreloadStatusInvalidManifest] = "Invalid file manifest",
[FlipperApplicationPreloadStatusApiTooOld] =
"Update Application to use with this Firmware (ApiTooOld)",
[FlipperApplicationPreloadStatusApiTooNew] =
"Update Firmware to use with this Application (ApiTooNew)",
[FlipperApplicationPreloadStatusTargetMismatch] = "Hardware target mismatch",
};
static const char* load_status_strings[] = {
[FlipperApplicationLoadStatusSuccess] = "Success",
[FlipperApplicationLoadStatusUnspecifiedError] = "Unknown error",
[FlipperApplicationLoadStatusNoFreeMemory] = "Out of memory",
[FlipperApplicationLoadStatusMissingImports] =
"Update Application/Firmware to use this (MissingImports)",
};
const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status) {
if(status >= COUNT_OF(preload_status_strings) || preload_status_strings[status] == NULL) {
return "Unknown error";
switch(status) {
case FlipperApplicationPreloadStatusSuccess:
return "Success";
case FlipperApplicationPreloadStatusInvalidFile:
return "Invalid file";
case FlipperApplicationPreloadStatusNotEnoughMemory:
return "Not enough memory";
case FlipperApplicationPreloadStatusInvalidManifest:
return "Invalid file manifest";
case FlipperApplicationPreloadStatusApiTooOld:
return "Update Application to use with this Firmware (ApiTooOld)";
case FlipperApplicationPreloadStatusApiTooNew:
return "Update Firmware to use with this Application (ApiTooNew)";
case FlipperApplicationPreloadStatusTargetMismatch:
return "Hardware target mismatch";
}
return preload_status_strings[status];
return "Unknown error";
}
const char* flipper_application_load_status_to_string(FlipperApplicationLoadStatus status) {
if(status >= COUNT_OF(load_status_strings) || load_status_strings[status] == NULL) {
switch(status) {
case FlipperApplicationLoadStatusSuccess:
return "Success";
case FlipperApplicationLoadStatusUnspecifiedError:
return "Unknown error";
case FlipperApplicationLoadStatusMissingImports:
return "Update Firmware to use with this Application (MissingImports)";
}
return load_status_strings[status];
return "Unknown error";
}
const FlipperAppPluginDescriptor*

View File

@@ -18,8 +18,8 @@ extern "C" {
typedef enum {
FlipperApplicationPreloadStatusSuccess = 0,
FlipperApplicationPreloadStatusUnspecifiedError,
FlipperApplicationPreloadStatusInvalidFile,
FlipperApplicationPreloadStatusNotEnoughMemory,
FlipperApplicationPreloadStatusInvalidManifest,
FlipperApplicationPreloadStatusApiTooOld,
FlipperApplicationPreloadStatusApiTooNew,
@@ -29,7 +29,6 @@ typedef enum {
typedef enum {
FlipperApplicationLoadStatusSuccess = 0,
FlipperApplicationLoadStatusUnspecifiedError,
FlipperApplicationLoadStatusNoFreeMemory,
FlipperApplicationLoadStatusMissingImports,
} FlipperApplicationLoadStatus;

View File

@@ -49,7 +49,7 @@ static void nfc_generate_mf_ul_orig(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_common(mfu_data);
mfu_data->type = MfUltralightTypeUnknown;
mfu_data->type = MfUltralightTypeOrigin;
mfu_data->pages_total = 16;
mfu_data->pages_read = 16;
memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage));

View File

@@ -4,13 +4,15 @@
MF_PLUS_FFF_PICC_PREFIX " " \
"Version"
#define MF_PLUS_T1_TK_VALUE_LEN 7
#define MF_PLUS_FFF_SECURITY_LEVEL_KEY "Security Level"
#define MF_PLUS_FFF_CARD_TYPE_KEY "Card Type"
#define MF_PLUS_FFF_MEMORY_SIZE_KEY "Memory Size"
#define TAG "MfPlus"
const uint8_t mf_plus_ats_t1_tk_values[][7] = {
const uint8_t mf_plus_ats_t1_tk_values[][MF_PLUS_T1_TK_VALUE_LEN] = {
{0xC1, 0x05, 0x2F, 0x2F, 0x00, 0x35, 0xC7}, // Mifare Plus S
{0xC1, 0x05, 0x2F, 0x2F, 0x01, 0xBC, 0xD6}, // Mifare Plus X
{0xC1, 0x05, 0x2F, 0x2F, 0x00, 0xF6, 0xD1}, // Mifare Plus SE
@@ -97,6 +99,10 @@ MfPlusError
MfPlusError error = MfPlusErrorProtocol;
if(simple_array_get_count(iso4_data->ats_data.t1_tk) != MF_PLUS_T1_TK_VALUE_LEN) {
return MfPlusErrorProtocol;
}
switch(iso4_data->iso14443_3a_data->sak) {
case 0x08:
if(memcmp(

View File

@@ -26,7 +26,7 @@ typedef struct {
static const uint32_t mf_ultralight_data_format_version = 2;
static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = {
[MfUltralightTypeUnknown] =
[MfUltralightTypeOrigin] =
{
.device_name = "Mifare Ultralight",
.total_pages = 16,
@@ -215,7 +215,7 @@ static const char*
mf_ultralight_get_device_name_by_type(MfUltralightType type, NfcDeviceNameType name_type) {
if(name_type == NfcDeviceNameTypeShort &&
(type == MfUltralightTypeUL11 || type == MfUltralightTypeUL21)) {
type = MfUltralightTypeUnknown;
type = MfUltralightTypeOrigin;
}
return mf_ultralight_features[type].device_name;
@@ -512,7 +512,7 @@ Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data) {
MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) {
furi_check(version);
MfUltralightType type = MfUltralightTypeUnknown;
MfUltralightType type = MfUltralightTypeOrigin;
if(version->storage_size == 0x0B || version->storage_size == 0x00) {
type = MfUltralightTypeUL11;
@@ -575,12 +575,14 @@ uint8_t mf_ultralight_get_write_end_page(MfUltralightType type) {
furi_assert(
type == MfUltralightTypeUL11 || type == MfUltralightTypeUL21 ||
type == MfUltralightTypeNTAG213 || type == MfUltralightTypeNTAG215 ||
type == MfUltralightTypeNTAG216);
type == MfUltralightTypeNTAG216 || type == MfUltralightTypeOrigin);
uint8_t end_page = mf_ultralight_get_config_page_num(type);
if(type == MfUltralightTypeNTAG213 || type == MfUltralightTypeNTAG215 ||
type == MfUltralightTypeNTAG216) {
end_page -= 1;
} else if(type == MfUltralightTypeOrigin) {
end_page = mf_ultralight_features[type].total_pages;
}
return end_page;

View File

@@ -48,7 +48,7 @@ typedef enum {
} MfUltralightError;
typedef enum {
MfUltralightTypeUnknown,
MfUltralightTypeOrigin,
MfUltralightTypeNTAG203,
MfUltralightTypeMfulC,
MfUltralightTypeUL11,

View File

@@ -281,12 +281,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller
} else {
FURI_LOG_D(TAG, "Original Ultralight detected");
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
instance->data->type = MfUltralightTypeUnknown;
if(instance->mode == MfUltralightPollerModeWrite) {
instance->mfu_event.type = MfUltralightPollerEventTypeCardMismatch;
instance->callback(instance->general_event, instance->context);
next_state = MfUltralightPollerStateWriteFail;
}
instance->data->type = MfUltralightTypeOrigin;
}
instance->state = next_state;
@@ -575,10 +570,12 @@ static NfcCommand mf_ultralight_poller_handler_request_write_data(MfUltralightPo
break;
}
if(!instance->auth_context.auth_success) {
FURI_LOG_D(TAG, "Unknown password");
instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked;
break;
if(mf_ultralight_support_feature(features, MfUltralightFeatureSupportPasswordAuth)) {
if(!instance->auth_context.auth_success) {
FURI_LOG_D(TAG, "Unknown password");
instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked;
break;
}
}
const MfUltralightPage staticlock_page = tag_data->page[2];

View File

@@ -14,6 +14,7 @@
#define TAG "SubGhzProtocolPrinceton"
#define PRINCETON_GUARD_TIME_DEFALUT 30 //GUARD_TIME = PRINCETON_GUARD_TIME_DEFALUT * TE
// Guard Time value should be between 15 -> 72 otherwise default value will be used
static const SubGhzBlockConst subghz_protocol_princeton_const = {
.te_short = 390,
@@ -176,6 +177,11 @@ SubGhzProtocolStatus
if(!flipper_format_read_uint32(
flipper_format, "Guard_time", (uint32_t*)&instance->guard_time, 1)) {
instance->guard_time = PRINCETON_GUARD_TIME_DEFALUT;
} else {
// Guard Time value should be between 15 -> 72 otherwise default value will be used
if((instance->guard_time < 15) || (instance->guard_time > 72)) {
instance->guard_time = PRINCETON_GUARD_TIME_DEFALUT;
}
}
flipper_format_read_uint32(
@@ -272,6 +278,10 @@ void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
instance->guard_time = roundf((float)duration / instance->te);
// Guard Time value should be between 15 -> 72 otherwise default value will be used
if((instance->guard_time < 15) || (instance->guard_time > 72)) {
instance->guard_time = PRINCETON_GUARD_TIME_DEFALUT;
}
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
@@ -373,7 +383,13 @@ SubGhzProtocolStatus
if(!flipper_format_read_uint32(
flipper_format, "Guard_time", (uint32_t*)&instance->guard_time, 1)) {
instance->guard_time = PRINCETON_GUARD_TIME_DEFALUT;
} else {
// Guard Time value should be between 15 -> 72 otherwise default value will be used
if((instance->guard_time < 15) || (instance->guard_time > 72)) {
instance->guard_time = PRINCETON_GUARD_TIME_DEFALUT;
}
}
} while(false);
return ret;
@@ -392,12 +408,13 @@ void subghz_protocol_decoder_princeton_get_string(void* context, FuriString* out
"Key:0x%08lX\r\n"
"Yek:0x%08lX\r\n"
"Sn:0x%05lX Btn:%01X\r\n"
"Te:%luus\r\n",
"Te:%luus GT:Te*%lu\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data & 0xFFFFFF),
data_rev,
instance->generic.serial,
instance->generic.btn,
instance->te);
instance->te,
instance->guard_time);
}

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,65.0,,
Version,+,66.0,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Header,+,applications/services/cli/cli.h,,
1 entry status name type params
2 Version + 65.0 66.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/bt/bt_service/bt_keys_storage.h
5 Header + applications/services/cli/cli.h

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,65.0,,
Version,+,66.0,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/main/archive/helpers/archive_helpers_ext.h,,
Header,+,applications/main/subghz/subghz_fap.h,,
@@ -3992,6 +3992,14 @@ Variable,+,I_dolph_cry_49x54,Icon,
Variable,+,I_dry_19x20,Icon,
Variable,+,I_dry_hover_19x20,Icon,
Variable,+,I_dry_text_15x5,Icon,
Variable,+,I_err_01,Icon,
Variable,+,I_err_02,Icon,
Variable,+,I_err_03,Icon,
Variable,+,I_err_04,Icon,
Variable,+,I_err_05,Icon,
Variable,+,I_err_06,Icon,
Variable,+,I_err_07,Icon,
Variable,+,I_err_09,Icon,
Variable,+,I_exit_19x20,Icon,
Variable,+,I_exit_hover_19x20,Icon,
Variable,+,I_exit_text_18x5,Icon,
1 entry status name type params
2 Version + 65.0 66.0
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/main/archive/helpers/archive_helpers_ext.h
5 Header + applications/main/subghz/subghz_fap.h
3992 Variable + I_dry_19x20 Icon
3993 Variable + I_dry_hover_19x20 Icon
3994 Variable + I_dry_text_15x5 Icon
3995 Variable + I_err_01 Icon
3996 Variable + I_err_02 Icon
3997 Variable + I_err_03 Icon
3998 Variable + I_err_04 Icon
3999 Variable + I_err_05 Icon
4000 Variable + I_err_06 Icon
4001 Variable + I_err_07 Icon
4002 Variable + I_err_09 Icon
4003 Variable + I_exit_19x20 Icon
4004 Variable + I_exit_hover_19x20 Icon
4005 Variable + I_exit_text_18x5 Icon