diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index be981768..689dd203 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -96,14 +96,14 @@ jobs: - name: 'Upload map analyser files to storage' if: ${{ !github.event.pull_request.head.repo.fork }} - uses: keithweaver/aws-s3-github-action@v1.0.0 + uses: prewk/s3-cp-action@v2 with: - source: map_analyser_files/ - destination: "s3://${{ secrets.MAP_REPORT_AWS_BUCKET }}/${{steps.names.outputs.random_hash}}" + aws_s3_endpoint: "${{ secrets.MAP_REPORT_AWS_ENDPOINT }}" aws_access_key_id: "${{ secrets.MAP_REPORT_AWS_ACCESS_KEY }}" aws_secret_access_key: "${{ secrets.MAP_REPORT_AWS_SECRET_KEY }}" - aws_region: "${{ secrets.MAP_REPORT_AWS_REGION }}" - flags: --recursive + source: "./map_analyser_files/" + dest: "s3://${{ secrets.MAP_REPORT_AWS_BUCKET }}/${{steps.names.outputs.random_hash}}" + flags: "--recursive --acl public-read" - name: 'Trigger map file reporter' if: ${{ !github.event.pull_request.head.repo.fork }} @@ -114,7 +114,6 @@ jobs: event-type: map-file-analyse client-payload: '{"random_hash": "${{steps.names.outputs.random_hash}}", "event_type": "${{steps.names.outputs.event_type}}"}' - - name: 'Upload artifacts to update server' if: ${{ !github.event.pull_request.head.repo.fork }} run: | diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index a4ac6e30..65a8b615 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -54,17 +54,16 @@ jobs: ./fbt COMPACT=1 PVSNOBROWSER=1 firmware_pvs || WARNINGS=1 echo "warnings=${WARNINGS}" >> $GITHUB_OUTPUT - - name: 'Upload artifacts to update server' + - name: 'Upload report' if: ${{ !github.event.pull_request.head.repo.fork && (steps.pvs-warn.outputs.warnings != 0) }} - run: | - mkdir -p ~/.ssh - ssh-keyscan -p ${{ secrets.RSYNC_DEPLOY_PORT }} -H ${{ secrets.RSYNC_DEPLOY_HOST }} > ~/.ssh/known_hosts - echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; - chmod 600 ./deploy_key; - rsync -avrzP --mkpath \ - -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ - build/f7-firmware-DC/pvsreport/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:/home/data/firmware-pvs-studio-report/"${BRANCH_NAME}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/"; - rm ./deploy_key; + uses: prewk/s3-cp-action@v2 + with: + aws_s3_endpoint: "${{ secrets.PVS_AWS_ENDPOINT }}" + aws_access_key_id: "${{ secrets.PVS_AWS_ACCESS_KEY }}" + aws_secret_access_key: "${{ secrets.PVS_AWS_SECRET_KEY }}" + source: "./build/f7-firmware-DC/pvsreport" + dest: "s3://${{ secrets.PVS_AWS_BUCKET }}/${{steps.names.outputs.branch_name}}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/" + flags: "--recursive --acl public-read" - name: 'Find Previous Comment' if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request && (steps.pvs-warn.outputs.warnings != 0) }} @@ -83,7 +82,7 @@ jobs: issue-number: ${{ github.event.pull_request.number }} body: | **PVS-Studio report for commit `${{steps.names.outputs.commit_sha}}`:** - - [Report](https://update.flipperzero.one/builds/firmware-pvs-studio-report/${{steps.names.outputs.branch_name}}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/index.html) + - [Report](https://pvs.flipp.dev/${{steps.names.outputs.branch_name}}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/index.html) edit-mode: replace - name: 'Raise exception' diff --git a/applications/debug/example_custom_font/application.fam b/applications/debug/example_custom_font/application.fam index 02285b8a..06c0a7f6 100644 --- a/applications/debug/example_custom_font/application.fam +++ b/applications/debug/example_custom_font/application.fam @@ -1,7 +1,7 @@ App( appid="example_custom_font", name="Example: custom font", - apptype=FlipperAppType.EXTERNAL, + apptype=FlipperAppType.DEBUG, entry_point="example_custom_font_main", requires=["gui"], stack_size=1 * 1024, diff --git a/applications/main/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c index 5f2aa478..1b249579 100644 --- a/applications/main/bad_usb/bad_usb_app.c +++ b/applications/main/bad_usb/bad_usb_app.c @@ -115,8 +115,12 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { if(furi_hal_usb_is_locked()) { app->error = BadUsbAppErrorCloseRpc; + app->usb_if_prev = NULL; scene_manager_next_scene(app->scene_manager, BadUsbSceneError); } else { + app->usb_if_prev = furi_hal_usb_get_config(); + furi_check(furi_hal_usb_set_config(NULL, NULL)); + if(!furi_string_empty(app->file_path)) { app->bad_usb_script = bad_usb_script_open(app->file_path); bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout); @@ -138,6 +142,10 @@ void bad_usb_app_free(BadUsbApp* app) { app->bad_usb_script = NULL; } + if(app->usb_if_prev) { + furi_check(furi_hal_usb_set_config(app->usb_if_prev, NULL)); + } + // Views view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); bad_usb_free(app->bad_usb_view); diff --git a/applications/main/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h index 1bd1964c..588c4c2d 100644 --- a/applications/main/bad_usb/bad_usb_app_i.h +++ b/applications/main/bad_usb/bad_usb_app_i.h @@ -14,6 +14,7 @@ #include #include #include "views/bad_usb_view.h" +#include #define BAD_USB_APP_BASE_FOLDER ANY_PATH("badusb") #define BAD_USB_APP_PATH_LAYOUT_FOLDER BAD_USB_APP_BASE_FOLDER "/assets/layouts" @@ -39,6 +40,8 @@ struct BadUsbApp { FuriString* keyboard_layout; BadUsb* bad_usb_view; BadUsbScript* bad_usb_script; + + FuriHalUsbInterface* usb_if_prev; }; typedef enum { diff --git a/applications/main/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c index 0fadbcc0..34dfec2c 100644 --- a/applications/main/bad_usb/bad_usb_script.c +++ b/applications/main/bad_usb/bad_usb_script.c @@ -490,8 +490,6 @@ static int32_t bad_usb_worker(void* context) { BadUsbWorkerState worker_state = BadUsbStateInit; int32_t delay_val = 0; - FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); - FURI_LOG_I(WORKER_TAG, "Init"); File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); bad_usb->line = furi_string_alloc(); @@ -642,8 +640,6 @@ static int32_t bad_usb_worker(void* context) { furi_hal_hid_set_state_callback(NULL, NULL); - furi_hal_usb_set_config(usb_mode_prev, NULL); - storage_file_close(script_file); storage_file_free(script_file); furi_string_free(bad_usb->line); diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c index 69bf9eb5..4b808969 100644 --- a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c @@ -26,7 +26,7 @@ void nfc_magic_scene_wrong_card_on_enter(void* context) { AlignLeft, AlignTop, FontSecondary, - "Writing is supported\nonly for 4 bytes UID\nMifare CLassic 1k"); + "Writing is supported\nonly for 4 bytes UID\nMifare Classic 1k"); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wrong_card_widget_callback, nfc_magic); diff --git a/applications/system/updater/scenes/updater_scene_error.c b/applications/system/updater/scenes/updater_scene_error.c index 21bf1637..dbe97c96 100644 --- a/applications/system/updater/scenes/updater_scene_error.c +++ b/applications/system/updater/scenes/updater_scene_error.c @@ -58,8 +58,12 @@ bool updater_scene_error_on_event(void* context, SceneManagerEvent event) { } void updater_scene_error_on_exit(void* context) { + furi_assert(context); Updater* updater = (Updater*)context; widget_reset(updater->widget); - free(updater->pending_update); + + if(updater->loaded_manifest) { + update_manifest_free(updater->loaded_manifest); + } } diff --git a/applications/system/updater/scenes/updater_scene_loadcfg.c b/applications/system/updater/scenes/updater_scene_loadcfg.c index 14f7b203..99866a6d 100644 --- a/applications/system/updater/scenes/updater_scene_loadcfg.c +++ b/applications/system/updater/scenes/updater_scene_loadcfg.c @@ -21,11 +21,9 @@ void updater_scene_loadcfg_apply_callback(GuiButtonType result, InputType type, void updater_scene_loadcfg_on_enter(void* context) { Updater* updater = (Updater*)context; - UpdaterManifestProcessingState* pending_upd = updater->pending_update = - malloc(sizeof(UpdaterManifestProcessingState)); - pending_upd->manifest = update_manifest_alloc(); + UpdateManifest* loaded_manifest = updater->loaded_manifest = update_manifest_alloc(); - if(update_manifest_init(pending_upd->manifest, furi_string_get_cstr(updater->startup_arg))) { + if(update_manifest_init(loaded_manifest, furi_string_get_cstr(updater->startup_arg))) { widget_add_string_element( updater->widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, "Update"); @@ -37,7 +35,7 @@ void updater_scene_loadcfg_on_enter(void* context) { 32, AlignCenter, AlignCenter, - furi_string_get_cstr(pending_upd->manifest->version), + furi_string_get_cstr(loaded_manifest->version), true); widget_add_button_element( @@ -95,13 +93,12 @@ bool updater_scene_loadcfg_on_event(void* context, SceneManagerEvent event) { } void updater_scene_loadcfg_on_exit(void* context) { + furi_assert(context); Updater* updater = (Updater*)context; - if(updater->pending_update) { - update_manifest_free(updater->pending_update->manifest); - furi_string_free(updater->pending_update->message); - } - widget_reset(updater->widget); - free(updater->pending_update); + + if(updater->loaded_manifest) { + update_manifest_free(updater->loaded_manifest); + } } diff --git a/applications/system/updater/updater_i.h b/applications/system/updater/updater_i.h index ae249f38..4e3c704d 100644 --- a/applications/system/updater/updater_i.h +++ b/applications/system/updater/updater_i.h @@ -33,12 +33,6 @@ typedef enum { UpdaterCustomEventSdUnmounted, } UpdaterCustomEvent; -typedef struct UpdaterManifestProcessingState { - UpdateManifest* manifest; - FuriString* message; - bool ready_to_be_applied; -} UpdaterManifestProcessingState; - typedef struct { // GUI Gui* gui; @@ -49,7 +43,7 @@ typedef struct { UpdaterMainView* main_view; - UpdaterManifestProcessingState* pending_update; + UpdateManifest* loaded_manifest; UpdatePrepareResult preparation_result; UpdateTask* update_task; diff --git a/applications/system/updater/util/update_task.c b/applications/system/updater/util/update_task.c index 54fe2799..708d10ce 100644 --- a/applications/system/updater/util/update_task.c +++ b/applications/system/updater/util/update_task.c @@ -41,22 +41,22 @@ typedef struct { static const UpdateTaskStageGroupMap update_task_stage_progress[] = { [UpdateTaskStageProgress] = STAGE_DEF(UpdateTaskStageGroupMisc, 0), - [UpdateTaskStageReadManifest] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 5), - [UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 15), + [UpdateTaskStageReadManifest] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 45), + [UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 5), [UpdateTaskStageRadioImageValidate] = STAGE_DEF(UpdateTaskStageGroupRadio, 15), - [UpdateTaskStageRadioErase] = STAGE_DEF(UpdateTaskStageGroupRadio, 60), - [UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 80), - [UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 60), - [UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 80), + [UpdateTaskStageRadioErase] = STAGE_DEF(UpdateTaskStageGroupRadio, 35), + [UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 60), + [UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 30), + [UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 5), - [UpdateTaskStageOBValidation] = STAGE_DEF(UpdateTaskStageGroupOptionBytes, 10), + [UpdateTaskStageOBValidation] = STAGE_DEF(UpdateTaskStageGroupOptionBytes, 2), - [UpdateTaskStageValidateDFUImage] = STAGE_DEF(UpdateTaskStageGroupFirmware, 50), - [UpdateTaskStageFlashWrite] = STAGE_DEF(UpdateTaskStageGroupFirmware, 200), - [UpdateTaskStageFlashValidate] = STAGE_DEF(UpdateTaskStageGroupFirmware, 30), + [UpdateTaskStageValidateDFUImage] = STAGE_DEF(UpdateTaskStageGroupFirmware, 30), + [UpdateTaskStageFlashWrite] = STAGE_DEF(UpdateTaskStageGroupFirmware, 150), + [UpdateTaskStageFlashValidate] = STAGE_DEF(UpdateTaskStageGroupFirmware, 15), - [UpdateTaskStageLfsRestore] = STAGE_DEF(UpdateTaskStageGroupPostUpdate, 30), + [UpdateTaskStageLfsRestore] = STAGE_DEF(UpdateTaskStageGroupPostUpdate, 5), [UpdateTaskStageResourcesUpdate] = STAGE_DEF(UpdateTaskStageGroupResources, 255), [UpdateTaskStageSplashscreenInstall] = STAGE_DEF(UpdateTaskStageGroupSplashscreen, 5), diff --git a/applications/system/updater/util/update_task_worker_backup.c b/applications/system/updater/util/update_task_worker_backup.c index 78040106..ed53c353 100644 --- a/applications/system/updater/util/update_task_worker_backup.c +++ b/applications/system/updater/util/update_task_worker_backup.c @@ -41,6 +41,14 @@ static bool update_task_pre_update(UpdateTask* update_task) { return success; } +typedef enum { + UpdateTaskResourcesWeightsFileCleanup = 20, + UpdateTaskResourcesWeightsDirCleanup = 20, + UpdateTaskResourcesWeightsFileUnpack = 60, +} UpdateTaskResourcesWeights; + +#define UPDATE_TASK_RESOURCES_FILE_TO_TOTAL_PERCENT 90 + typedef struct { UpdateTask* update_task; int32_t total_files, processed_files; @@ -54,33 +62,36 @@ static bool update_task_resource_unpack_cb(const char* name, bool is_directory, update_task_set_progress( unpack_progress->update_task, UpdateTaskStageProgress, - /* For this stage, last 70% of progress = extraction */ - 30 + (unpack_progress->processed_files * 70) / (unpack_progress->total_files + 1)); + /* For this stage, last progress segment = extraction */ + (UpdateTaskResourcesWeightsFileCleanup + UpdateTaskResourcesWeightsDirCleanup) + + (unpack_progress->processed_files * UpdateTaskResourcesWeightsFileUnpack) / + (unpack_progress->total_files + 1)); return true; } -static void - update_task_cleanup_resources(UpdateTask* update_task, uint32_t n_approx_file_entries) { +static void update_task_cleanup_resources(UpdateTask* update_task, const uint32_t n_tar_entries) { ResourceManifestReader* manifest_reader = resource_manifest_reader_alloc(update_task->storage); do { - FURI_LOG_I(TAG, "Cleaning up old manifest"); + FURI_LOG_D(TAG, "Cleaning up old manifest"); if(!resource_manifest_reader_open(manifest_reader, EXT_PATH("Manifest"))) { FURI_LOG_W(TAG, "No existing manifest"); break; } - /* We got # of entries in TAR file. Approx 1/4th is dir entries, we skip them */ - n_approx_file_entries = n_approx_file_entries * 3 / 4 + 1; - uint32_t n_processed_files = 0; + const uint32_t n_approx_file_entries = + n_tar_entries * UPDATE_TASK_RESOURCES_FILE_TO_TOTAL_PERCENT / 100 + 1; + uint32_t n_dir_entries = 1; ResourceManifestEntry* entry_ptr = NULL; + uint32_t n_processed_entries = 0; while((entry_ptr = resource_manifest_reader_next(manifest_reader))) { if(entry_ptr->type == ResourceManifestEntryTypeFile) { update_task_set_progress( update_task, UpdateTaskStageProgress, - /* For this stage, first 20% of progress = cleanup files */ - (n_processed_files++ * 20) / (n_approx_file_entries + 1)); + /* For this stage, first pass = old manifest's file cleanup */ + (n_processed_entries++ * UpdateTaskResourcesWeightsFileCleanup) / + n_approx_file_entries); FuriString* file_path = furi_string_alloc(); path_concat( @@ -88,16 +99,21 @@ static void FURI_LOG_D(TAG, "Removing %s", furi_string_get_cstr(file_path)); storage_simply_remove(update_task->storage, furi_string_get_cstr(file_path)); furi_string_free(file_path); + } else if(entry_ptr->type == ResourceManifestEntryTypeDirectory) { + n_dir_entries++; } } + n_processed_entries = 0; while((entry_ptr = resource_manifest_reader_previous(manifest_reader))) { if(entry_ptr->type == ResourceManifestEntryTypeDirectory) { update_task_set_progress( update_task, UpdateTaskStageProgress, /* For this stage, second 10% of progress = cleanup directories */ - (n_processed_files++ * 10) / (n_approx_file_entries + 1)); + UpdateTaskResourcesWeightsFileCleanup + + (n_processed_entries++ * UpdateTaskResourcesWeightsDirCleanup) / + n_dir_entries); FuriString* folder_path = furi_string_alloc(); File* folder_file = storage_file_alloc(update_task->storage); diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 0038bd34..fc679114 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -340,7 +340,7 @@ static void usb_process_mode_start(FuriHalUsbInterface* interface, void* context } static void usb_process_mode_change(FuriHalUsbInterface* interface, void* context) { - if(interface != usb.interface) { + if((interface != usb.interface) || (context != usb.interface_context)) { if(usb.enabled) { // Disable current interface susp_evt(&udev, 0, 0); diff --git a/lib/one_wire/ibutton/ibutton_worker_modes.c b/lib/one_wire/ibutton/ibutton_worker_modes.c index da6b1076..4f7f0855 100644 --- a/lib/one_wire/ibutton/ibutton_worker_modes.c +++ b/lib/one_wire/ibutton/ibutton_worker_modes.c @@ -237,10 +237,8 @@ void ibutton_worker_emulate_timer_cb(void* context) { const LevelDuration level_duration = protocol_dict_encoder_yield(worker->protocols, worker->protocol_to_encode); - const bool level = level_duration_get_level(level_duration); - - furi_hal_ibutton_emulate_set_next(level); - furi_hal_ibutton_pin_write(level); + furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level_duration)); + furi_hal_ibutton_pin_write(level_duration_get_level(level_duration)); } void ibutton_worker_emulate_timer_start(iButtonWorker* worker) { diff --git a/lib/toolbox/tar/tar_archive.c b/lib/toolbox/tar/tar_archive.c index fd0d175e..01969b47 100644 --- a/lib/toolbox/tar/tar_archive.c +++ b/lib/toolbox/tar/tar_archive.c @@ -106,6 +106,7 @@ void tar_archive_set_file_callback(TarArchive* archive, tar_unpack_file_cb callb static int tar_archive_entry_counter(mtar_t* tar, const mtar_header_t* header, void* param) { UNUSED(tar); UNUSED(header); + furi_assert(param); int32_t* counter = param; (*counter)++; return 0; diff --git a/scripts/fbt_tools/pvsstudio.py b/scripts/fbt_tools/pvsstudio.py index 02014836..593559a3 100644 --- a/scripts/fbt_tools/pvsstudio.py +++ b/scripts/fbt_tools/pvsstudio.py @@ -1,6 +1,6 @@ from SCons.Builder import Builder from SCons.Action import Action -from SCons.Script import Delete, Mkdir, GetBuildFailures +from SCons.Script import Delete, Mkdir, GetBuildFailures, Flatten import multiprocessing import webbrowser import atexit @@ -30,13 +30,14 @@ def atexist_handler(): return for bf in GetBuildFailures(): - if bf.node.exists and bf.node.name.endswith(".html"): - # macOS - if sys.platform == "darwin": - subprocess.run(["open", bf.node.abspath]) - else: - webbrowser.open(bf.node.abspath) - break + for node in Flatten(bf.node): + if node.exists and node.name.endswith(".html"): + # macOS + if sys.platform == "darwin": + subprocess.run(["open", node.abspath]) + else: + webbrowser.open(node.abspath) + break def generate(env): diff --git a/scripts/merge_report_qa.py b/scripts/merge_report_qa.py index c0707848..caa74240 100755 --- a/scripts/merge_report_qa.py +++ b/scripts/merge_report_qa.py @@ -17,7 +17,7 @@ def parse_args(): def checkCommitMessage(msg): - regex = re.compile(r"^'?\[FL-\d+\]") + regex = re.compile(r"^'?\[(FL-\d+,?\s?)+\]") if regex.match(msg): return True return False