Merge branch 'release-candidate' into release
This commit is contained in:
		
						commit
						b7f406d43b
					
				
							
								
								
									
										42
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -139,7 +139,7 @@ jobs: | ||||
| 
 | ||||
|       - name: 'Find Previous Comment' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }} | ||||
|         uses: peter-evans/find-comment@v1 | ||||
|         uses: peter-evans/find-comment@v2 | ||||
|         id: fc | ||||
|         with: | ||||
|           issue-number: ${{ github.event.pull_request.number }} | ||||
| @ -148,7 +148,7 @@ jobs: | ||||
| 
 | ||||
|       - name: 'Create or update comment' | ||||
|         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request}} | ||||
|         uses: peter-evans/create-or-update-comment@v1 | ||||
|         uses: peter-evans/create-or-update-comment@v3 | ||||
|         with: | ||||
|           comment-id: ${{ steps.fc.outputs.comment-id }} | ||||
|           issue-number: ${{ github.event.pull_request.number }} | ||||
| @ -162,6 +162,9 @@ jobs: | ||||
|   compact: | ||||
|     if: ${{ !startsWith(github.ref, 'refs/tags') }} | ||||
|     runs-on: [self-hosted,FlipperZeroShell] | ||||
|     strategy: | ||||
|       matrix: | ||||
|         target: [f7, f18] | ||||
|     steps: | ||||
|       - name: 'Wipe workspace' | ||||
|         run: find ./ -mount -maxdepth 1 -exec rm -rf {} \;  | ||||
| @ -185,9 +188,40 @@ jobs: | ||||
|           python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" || cat "${{ github.event_path }}" | ||||
| 
 | ||||
|       - name: 'Build the firmware' | ||||
|         id: build-fw | ||||
|         run: | | ||||
|           set -e | ||||
|           for TARGET in ${TARGETS}; do | ||||
|             TARGET="$(echo "${TARGET}" | sed 's/f//')"; \ | ||||
|           TARGET="$(echo '${{ matrix.target }}' | sed 's/f//')"; \ | ||||
|           ./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 fap_dist updater_package | ||||
|           echo "sdk-file=$(ls dist/${{ matrix.target }}-*/flipper-z-${{ matrix.target }}-sdk-*.zip)" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: Deploy uFBT with SDK | ||||
|         uses: flipperdevices/flipperzero-ufbt-action@v0.1.0 | ||||
|         with: | ||||
|           task: setup | ||||
|           sdk-file: ${{ steps.build-fw.outputs.sdk-file }} | ||||
| 
 | ||||
|       - name: Build test app with SDK | ||||
|         run: | | ||||
|           mkdir testapp | ||||
|           cd testapp | ||||
|           ufbt create APPID=testapp | ||||
|           ufbt | ||||
|        | ||||
|       - name: Build example & external apps with uFBT | ||||
|         run: | | ||||
|           for appdir in 'applications/external' 'applications/examples'; do | ||||
|             for app in $(find "$appdir" -maxdepth 1 -mindepth 1 -type d); do | ||||
|               pushd $app | ||||
|               TARGETS_FAM=$(grep "targets" application.fam || echo "${{ matrix.target }}") | ||||
|               if ! grep -q "${{ matrix.target }}" <<< $TARGETS_FAM ; then | ||||
|                   echo Skipping unsupported app: $app | ||||
|                   popd | ||||
|                   continue | ||||
|               fi | ||||
|               echo Building $app | ||||
|               ufbt | ||||
|               popd | ||||
|             done | ||||
|           done | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										32
									
								
								.github/workflows/lint_and_submodule_check.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								.github/workflows/lint_and_submodule_check.yml
									
									
									
									
										vendored
									
									
								
							| @ -40,7 +40,7 @@ jobs: | ||||
|           COMMITS_IN_BRANCH="$(git rev-list --count dev)"; | ||||
|           if [ $COMMITS_IN_BRANCH -lt $SUB_COMMITS_MIN ]; then | ||||
|             echo "name=fails::error" >> $GITHUB_OUTPUT; | ||||
|             echo "::error::Error: Too low commits in $SUB_BRANCH of submodule $SUB_PATH: $COMMITS_IN_BRANCH(expected $SUB_COMMITS_MIN+)"; | ||||
|             echo "::error::Error: Too few commits in $SUB_BRANCH of submodule $SUB_PATH: $COMMITS_IN_BRANCH(expected $SUB_COMMITS_MIN+)"; | ||||
|             exit 1; | ||||
|           fi | ||||
|           if ! grep -q "/$SUB_BRANCH" <<< "$BRANCHES"; then | ||||
| @ -51,12 +51,36 @@ jobs: | ||||
| 
 | ||||
|       - name: 'Check Python code formatting' | ||||
|         id: syntax_check_py | ||||
|         run: ./fbt lint_py 2>&1 >/dev/null || echo "errors=1" >> $GITHUB_OUTPUT | ||||
|         run: | | ||||
|           set +e; | ||||
|           ./fbt -s lint_py 2>&1 | tee lint-py.log; | ||||
|           if [ "${PIPESTATUS[0]}" -ne 0 ]; then | ||||
|             # Save multiline output | ||||
|             echo "errors=1" >> $GITHUB_OUTPUT; | ||||
|             printf "Python Lint errors:\n\`\`\`\n" >> $GITHUB_STEP_SUMMARY; | ||||
|             echo "$(cat lint-py.log)" >> $GITHUB_STEP_SUMMARY; | ||||
|             printf "\n\`\`\`\n" >> $GITHUB_STEP_SUMMARY; | ||||
|             exit 1; | ||||
|           else | ||||
|             echo "Python Lint: all good ✨" >> $GITHUB_STEP_SUMMARY; | ||||
|           fi | ||||
|    | ||||
|       - name: 'Check C++ code formatting' | ||||
|         if: always() | ||||
|         id: syntax_check_cpp | ||||
|         run: ./fbt lint 2>&1 >/dev/null || echo "errors=1" >> $GITHUB_OUTPUT | ||||
|         if: always() | ||||
|         run: | | ||||
|           set +e; | ||||
|           ./fbt -s lint 2>&1 | tee lint-cpp.log; | ||||
|           if [ "${PIPESTATUS[0]}" -ne 0 ]; then | ||||
|             # Save multiline output | ||||
|             echo "errors=1" >> $GITHUB_OUTPUT; | ||||
|             printf "C Lint errors:\n\`\`\`\n" >> $GITHUB_STEP_SUMMARY; | ||||
|             echo "$(cat lint-cpp.log)" >> $GITHUB_STEP_SUMMARY; | ||||
|             printf "\n\`\`\`\n" >> $GITHUB_STEP_SUMMARY; | ||||
|             exit 1; | ||||
|           else | ||||
|             echo "C Lint: all good ✨" >> $GITHUB_STEP_SUMMARY; | ||||
|           fi | ||||
| 
 | ||||
|       - name: Report code formatting errors | ||||
|         if: ( steps.syntax_check_py.outputs.errors || steps.syntax_check_cpp.outputs.errors ) && github.event.pull_request | ||||
|  | ||||
| @ -84,7 +84,7 @@ static void test_rpc_setup(void) { | ||||
| 
 | ||||
|     rpc = furi_record_open(RECORD_RPC); | ||||
|     for(int i = 0; !(rpc_session[0].session) && (i < 10000); ++i) { | ||||
|         rpc_session[0].session = rpc_session_open(rpc); | ||||
|         rpc_session[0].session = rpc_session_open(rpc, RpcOwnerUnknown); | ||||
|         furi_delay_tick(1); | ||||
|     } | ||||
|     furi_check(rpc_session[0].session); | ||||
| @ -104,7 +104,7 @@ static void test_rpc_setup_second_session(void) { | ||||
|     furi_check(!(rpc_session[1].session)); | ||||
| 
 | ||||
|     for(int i = 0; !(rpc_session[1].session) && (i < 10000); ++i) { | ||||
|         rpc_session[1].session = rpc_session_open(rpc); | ||||
|         rpc_session[1].session = rpc_session_open(rpc, RpcOwnerUnknown); | ||||
|         furi_delay_tick(1); | ||||
|     } | ||||
|     furi_check(rpc_session[1].session); | ||||
|  | ||||
| @ -570,7 +570,7 @@ void picopass_worker_elite_dict_attack(PicopassWorker* picopass_worker) { | ||||
|                 picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context); | ||||
|                 break; | ||||
|             } | ||||
|             picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context); | ||||
|             picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context); | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
| @ -596,6 +596,9 @@ int32_t picopass_worker_task(void* context) { | ||||
|         picopass_worker_write_key(picopass_worker); | ||||
|     } else if(picopass_worker->state == PicopassWorkerStateEliteDictAttack) { | ||||
|         picopass_worker_elite_dict_attack(picopass_worker); | ||||
|     } else if(picopass_worker->state == PicopassWorkerStateStop) { | ||||
|         FURI_LOG_D(TAG, "Worker state stop"); | ||||
|         // no-op
 | ||||
|     } else { | ||||
|         FURI_LOG_W(TAG, "Unknown state %d", picopass_worker->state); | ||||
|     } | ||||
|  | ||||
| @ -116,8 +116,7 @@ bool picopass_scene_elite_dict_attack_on_event(void* context, SceneManagerEvent | ||||
|     uint32_t state = | ||||
|         scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneEliteDictAttack); | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == PicopassWorkerEventSuccess || | ||||
|            event.event == PicopassWorkerEventAborted) { | ||||
|         if(event.event == PicopassWorkerEventSuccess) { | ||||
|             if(state == DictAttackStateUserDictInProgress || | ||||
|                state == DictAttackStateStandardDictInProgress) { | ||||
|                 picopass_worker_stop(picopass->worker); | ||||
| @ -127,6 +126,9 @@ bool picopass_scene_elite_dict_attack_on_event(void* context, SceneManagerEvent | ||||
|                 scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); | ||||
|                 consumed = true; | ||||
|             } | ||||
|         } else if(event.event == PicopassWorkerEventAborted) { | ||||
|             scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); | ||||
|             consumed = true; | ||||
|         } else if(event.event == PicopassWorkerEventCardDetected) { | ||||
|             dict_attack_set_card_detected(picopass->dict_attack); | ||||
|             consumed = true; | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "fap_loader_app.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <furi_hal_debug.h> | ||||
| 
 | ||||
| #include <assets_icons.h> | ||||
| #include <gui/gui.h> | ||||
| @ -23,8 +24,6 @@ struct FapLoader { | ||||
|     Loading* loading; | ||||
| }; | ||||
| 
 | ||||
| volatile bool fap_loader_debug_active = false; | ||||
| 
 | ||||
| bool fap_loader_load_name_and_icon( | ||||
|     FuriString* path, | ||||
|     Storage* storage, | ||||
| @ -111,7 +110,7 @@ static bool fap_loader_run_selected_app(FapLoader* loader) { | ||||
|         FuriThread* thread = flipper_application_spawn(loader->app, NULL); | ||||
| 
 | ||||
|         /* This flag is set by the debugger - to break on app start */ | ||||
|         if(fap_loader_debug_active) { | ||||
|         if(furi_hal_debug_is_gdb_session_active()) { | ||||
|             FURI_LOG_W(TAG, "Triggering BP for debugger"); | ||||
|             /* After hitting this, you can set breakpoints in your .fap's code
 | ||||
|              * Note that you have to toggle breakpoints that were set before */ | ||||
|  | ||||
| @ -225,7 +225,7 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) { | ||||
|         furi_event_flag_clear(bt->rpc_event, BT_RPC_EVENT_DISCONNECTED); | ||||
|         if(bt->profile == BtProfileSerial) { | ||||
|             // Open RPC session
 | ||||
|             bt->rpc_session = rpc_session_open(bt->rpc); | ||||
|             bt->rpc_session = rpc_session_open(bt->rpc, RpcOwnerBle); | ||||
|             if(bt->rpc_session) { | ||||
|                 FURI_LOG_I(TAG, "Open RPC connection"); | ||||
|                 rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback); | ||||
|  | ||||
| @ -46,6 +46,12 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) | ||||
|     canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); | ||||
| } | ||||
| 
 | ||||
| static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) { | ||||
|     UNUSED(context); | ||||
|     furi_assert(canvas); | ||||
|     canvas_draw_icon(canvas, 0, 0, &I_Muted_8x8); | ||||
| } | ||||
| 
 | ||||
| static bool desktop_custom_event_callback(void* context, uint32_t event) { | ||||
|     furi_assert(context); | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
| @ -153,6 +159,17 @@ void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { | ||||
|     desktop->in_transition = false; | ||||
| } | ||||
| 
 | ||||
| void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) { | ||||
|     desktop->in_transition = true; | ||||
|     if(enabled) { | ||||
|         furi_hal_rtc_set_flag(FuriHalRtcFlagStealthMode); | ||||
|     } else { | ||||
|         furi_hal_rtc_reset_flag(FuriHalRtcFlagStealthMode); | ||||
|     } | ||||
|     view_port_enabled_set(desktop->stealth_mode_icon_viewport, enabled); | ||||
|     desktop->in_transition = false; | ||||
| } | ||||
| 
 | ||||
| Desktop* desktop_alloc() { | ||||
|     Desktop* desktop = malloc(sizeof(Desktop)); | ||||
| 
 | ||||
| @ -244,6 +261,18 @@ Desktop* desktop_alloc() { | ||||
|     view_port_enabled_set(desktop->dummy_mode_icon_viewport, false); | ||||
|     gui_add_view_port(desktop->gui, desktop->dummy_mode_icon_viewport, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     // Stealth mode icon
 | ||||
|     desktop->stealth_mode_icon_viewport = view_port_alloc(); | ||||
|     view_port_set_width(desktop->stealth_mode_icon_viewport, icon_get_width(&I_Muted_8x8)); | ||||
|     view_port_draw_callback_set( | ||||
|         desktop->stealth_mode_icon_viewport, desktop_stealth_mode_icon_draw_callback, desktop); | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { | ||||
|         view_port_enabled_set(desktop->stealth_mode_icon_viewport, true); | ||||
|     } else { | ||||
|         view_port_enabled_set(desktop->stealth_mode_icon_viewport, false); | ||||
|     } | ||||
|     gui_add_view_port(desktop->gui, desktop->stealth_mode_icon_viewport, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     // Special case: autostart application is already running
 | ||||
|     desktop->loader = furi_record_open(RECORD_LOADER); | ||||
|     if(loader_is_locked(desktop->loader) && | ||||
|  | ||||
| @ -59,6 +59,7 @@ struct Desktop { | ||||
| 
 | ||||
|     ViewPort* lock_icon_viewport; | ||||
|     ViewPort* dummy_mode_icon_viewport; | ||||
|     ViewPort* stealth_mode_icon_viewport; | ||||
| 
 | ||||
|     AnimationManager* animation_manager; | ||||
| 
 | ||||
| @ -79,3 +80,4 @@ void desktop_free(Desktop* desktop); | ||||
| void desktop_lock(Desktop* desktop); | ||||
| void desktop_unlock(Desktop* desktop); | ||||
| void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled); | ||||
| void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled); | ||||
|  | ||||
| @ -27,6 +27,8 @@ void desktop_scene_lock_menu_on_enter(void* context) { | ||||
|     desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); | ||||
|     desktop_lock_menu_set_pin_state(desktop->lock_menu, desktop->settings.pin_code.length > 0); | ||||
|     desktop_lock_menu_set_dummy_mode_state(desktop->lock_menu, desktop->settings.dummy_mode); | ||||
|     desktop_lock_menu_set_stealth_mode_state( | ||||
|         desktop->lock_menu, furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)); | ||||
|     desktop_lock_menu_set_idx(desktop->lock_menu, 0); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLockMenu); | ||||
| @ -78,6 +80,16 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 desktop->scene_manager, DesktopSceneMain); | ||||
|             break; | ||||
|         case DesktopLockMenuEventStealthModeOn: | ||||
|             desktop_set_stealth_mode_state(desktop, true); | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 desktop->scene_manager, DesktopSceneMain); | ||||
|             break; | ||||
|         case DesktopLockMenuEventStealthModeOff: | ||||
|             desktop_set_stealth_mode_state(desktop, false); | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 desktop->scene_manager, DesktopSceneMain); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|  | ||||
| @ -34,6 +34,8 @@ typedef enum { | ||||
|     DesktopLockMenuEventPinLock, | ||||
|     DesktopLockMenuEventDummyModeOn, | ||||
|     DesktopLockMenuEventDummyModeOff, | ||||
|     DesktopLockMenuEventStealthModeOn, | ||||
|     DesktopLockMenuEventStealthModeOff, | ||||
| 
 | ||||
|     DesktopAnimationEventCheckAnimation, | ||||
|     DesktopAnimationEventNewIdleAnimation, | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
| 
 | ||||
| typedef enum { | ||||
|     DesktopLockMenuIndexLock, | ||||
|     DesktopLockMenuIndexPinLock, | ||||
|     DesktopLockMenuIndexStealth, | ||||
|     DesktopLockMenuIndexDummy, | ||||
| 
 | ||||
|     DesktopLockMenuIndexTotalCount | ||||
| @ -39,6 +39,14 @@ void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode) { | ||||
|     with_view_model( | ||||
|         lock_menu->view, | ||||
|         DesktopLockMenuViewModel * model, | ||||
|         { model->stealth_mode = stealth_mode; }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { | ||||
|     furi_assert(idx < DesktopLockMenuIndexTotalCount); | ||||
|     with_view_model( | ||||
| @ -58,11 +66,11 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { | ||||
| 
 | ||||
|         if(i == DesktopLockMenuIndexLock) { | ||||
|             str = "Lock"; | ||||
|         } else if(i == DesktopLockMenuIndexPinLock) { | ||||
|             if(m->pin_is_set) { | ||||
|                 str = "Lock with PIN"; | ||||
|         } else if(i == DesktopLockMenuIndexStealth) { | ||||
|             if(m->stealth_mode) { | ||||
|                 str = "Sound Mode"; | ||||
|             } else { | ||||
|                 str = "Set PIN"; | ||||
|                 str = "Stealth Mode"; | ||||
|             } | ||||
|         } else if(i == DesktopLockMenuIndexDummy) { //-V547
 | ||||
|             if(m->dummy_mode) { | ||||
| @ -93,6 +101,8 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { | ||||
|     uint8_t idx = 0; | ||||
|     bool consumed = false; | ||||
|     bool dummy_mode = false; | ||||
|     bool stealth_mode = false; | ||||
|     bool pin_is_set = false; | ||||
|     bool update = false; | ||||
| 
 | ||||
|     with_view_model( | ||||
| @ -120,14 +130,24 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { | ||||
|             } | ||||
|             idx = model->idx; | ||||
|             dummy_mode = model->dummy_mode; | ||||
|             stealth_mode = model->stealth_mode; | ||||
|             pin_is_set = model->pin_is_set; | ||||
|         }, | ||||
|         update); | ||||
| 
 | ||||
|     if(event->key == InputKeyOk) { | ||||
|         if((idx == DesktopLockMenuIndexLock) && (event->type == InputTypeShort)) { | ||||
|             lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); | ||||
|         } else if((idx == DesktopLockMenuIndexPinLock) && (event->type == InputTypeShort)) { | ||||
|         if((idx == DesktopLockMenuIndexLock)) { | ||||
|             if((pin_is_set) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventPinLock, lock_menu->context); | ||||
|             } else if((pin_is_set == false) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); | ||||
|             } | ||||
|         } else if(idx == DesktopLockMenuIndexStealth) { | ||||
|             if((stealth_mode == false) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventStealthModeOn, lock_menu->context); | ||||
|             } else if((stealth_mode == true) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventStealthModeOff, lock_menu->context); | ||||
|             } | ||||
|         } else if(idx == DesktopLockMenuIndexDummy) { | ||||
|             if((dummy_mode == false) && (event->type == InputTypeShort)) { | ||||
|                 lock_menu->callback(DesktopLockMenuEventDummyModeOn, lock_menu->context); | ||||
|  | ||||
| @ -19,6 +19,7 @@ typedef struct { | ||||
|     uint8_t idx; | ||||
|     bool pin_is_set; | ||||
|     bool dummy_mode; | ||||
|     bool stealth_mode; | ||||
| } DesktopLockMenuViewModel; | ||||
| 
 | ||||
| void desktop_lock_menu_set_callback( | ||||
| @ -29,6 +30,7 @@ void desktop_lock_menu_set_callback( | ||||
| View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu); | ||||
| void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set); | ||||
| void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool dummy_mode); | ||||
| void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode); | ||||
| void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx); | ||||
| DesktopLockMenuView* desktop_lock_menu_alloc(); | ||||
| void desktop_lock_menu_free(DesktopLockMenuView* lock_menu); | ||||
|  | ||||
| @ -20,9 +20,9 @@ static const uint8_t reset_sound_mask = 1 << 4; | ||||
| static const uint8_t reset_display_mask = 1 << 5; | ||||
| static const uint8_t reset_blink_mask = 1 << 6; | ||||
| 
 | ||||
| void notification_vibro_on(); | ||||
| void notification_vibro_on(bool force); | ||||
| void notification_vibro_off(); | ||||
| void notification_sound_on(float freq, float volume); | ||||
| void notification_sound_on(float freq, float volume, bool force); | ||||
| void notification_sound_off(); | ||||
| 
 | ||||
| uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value); | ||||
| @ -141,18 +141,22 @@ uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) { | ||||
| } | ||||
| 
 | ||||
| // generics
 | ||||
| void notification_vibro_on() { | ||||
| void notification_vibro_on(bool force) { | ||||
|     if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { | ||||
|         furi_hal_vibro_on(true); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void notification_vibro_off() { | ||||
|     furi_hal_vibro_on(false); | ||||
| } | ||||
| 
 | ||||
| void notification_sound_on(float freq, float volume) { | ||||
| void notification_sound_on(float freq, float volume, bool force) { | ||||
|     if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { | ||||
|         if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { | ||||
|             furi_hal_speaker_start(freq, volume); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void notification_sound_off() { | ||||
| @ -174,6 +178,8 @@ void notification_process_notification_message( | ||||
|     NotificationApp* app, | ||||
|     NotificationAppMessage* message) { | ||||
|     uint32_t notification_message_index = 0; | ||||
|     bool force_volume = false; | ||||
|     bool force_vibro = false; | ||||
|     const NotificationMessage* notification_message; | ||||
|     notification_message = (*message->sequence)[notification_message_index]; | ||||
| 
 | ||||
| @ -269,7 +275,7 @@ void notification_process_notification_message( | ||||
|             break; | ||||
|         case NotificationMessageTypeVibro: | ||||
|             if(notification_message->data.vibro.on) { | ||||
|                 if(vibro_setting) notification_vibro_on(); | ||||
|                 if(vibro_setting) notification_vibro_on(force_vibro); | ||||
|             } else { | ||||
|                 notification_vibro_off(); | ||||
|             } | ||||
| @ -278,7 +284,8 @@ void notification_process_notification_message( | ||||
|         case NotificationMessageTypeSoundOn: | ||||
|             notification_sound_on( | ||||
|                 notification_message->data.sound.frequency, | ||||
|                 notification_message->data.sound.volume * speaker_volume_setting); | ||||
|                 notification_message->data.sound.volume * speaker_volume_setting, | ||||
|                 force_volume); | ||||
|             reset_mask |= reset_sound_mask; | ||||
|             break; | ||||
|         case NotificationMessageTypeSoundOff: | ||||
| @ -307,9 +314,11 @@ void notification_process_notification_message( | ||||
|             break; | ||||
|         case NotificationMessageTypeForceSpeakerVolumeSetting: | ||||
|             speaker_volume_setting = notification_message->data.forced_settings.speaker_volume; | ||||
|             force_volume = true; | ||||
|             break; | ||||
|         case NotificationMessageTypeForceVibroSetting: | ||||
|             vibro_setting = notification_message->data.forced_settings.vibro; | ||||
|             force_vibro = true; | ||||
|             break; | ||||
|         case NotificationMessageTypeForceDisplayBrightnessSetting: | ||||
|             display_brightness_setting = | ||||
|  | ||||
| @ -76,6 +76,7 @@ struct RpcSession { | ||||
|     RpcBufferIsEmptyCallback buffer_is_empty_callback; | ||||
|     RpcSessionClosedCallback closed_callback; | ||||
|     RpcSessionTerminatedCallback terminated_callback; | ||||
|     RpcOwner owner; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| @ -83,6 +84,11 @@ struct Rpc { | ||||
|     FuriMutex* busy_mutex; | ||||
| }; | ||||
| 
 | ||||
| RpcOwner rpc_session_get_owner(RpcSession* session) { | ||||
|     furi_assert(session); | ||||
|     return session->owner; | ||||
| } | ||||
| 
 | ||||
| static void rpc_close_session_process(const PB_Main* request, void* context) { | ||||
|     furi_assert(request); | ||||
|     furi_assert(context); | ||||
| @ -348,7 +354,7 @@ static void rpc_session_free_callback(FuriThreadState thread_state, void* contex | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| RpcSession* rpc_session_open(Rpc* rpc) { | ||||
| RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { | ||||
|     furi_assert(rpc); | ||||
| 
 | ||||
|     RpcSession* session = malloc(sizeof(RpcSession)); | ||||
| @ -357,6 +363,7 @@ RpcSession* rpc_session_open(Rpc* rpc) { | ||||
|     session->rpc = rpc; | ||||
|     session->terminate = false; | ||||
|     session->decode_error = false; | ||||
|     session->owner = owner; | ||||
|     RpcHandlerDict_init(session->handlers); | ||||
| 
 | ||||
|     session->decoded_message = malloc(sizeof(PB_Main)); | ||||
|  | ||||
| @ -30,6 +30,21 @@ typedef void (*RpcSessionClosedCallback)(void* context); | ||||
|  * and all operations were finished */ | ||||
| typedef void (*RpcSessionTerminatedCallback)(void* context); | ||||
| 
 | ||||
| /** RPC owner */ | ||||
| typedef enum { | ||||
|     RpcOwnerUnknown = 0, | ||||
|     RpcOwnerBle, | ||||
|     RpcOwnerUsb, | ||||
|     RpcOwnerCount, | ||||
| } RpcOwner; | ||||
| 
 | ||||
| /** Get RPC session owner
 | ||||
|  * | ||||
|  * @param   session     pointer to RpcSession descriptor | ||||
|  * @return              session owner | ||||
|  */ | ||||
| RpcOwner rpc_session_get_owner(RpcSession* session); | ||||
| 
 | ||||
| /** Open RPC session
 | ||||
|  * | ||||
|  * USAGE: | ||||
| @ -44,10 +59,11 @@ typedef void (*RpcSessionTerminatedCallback)(void* context); | ||||
|  * | ||||
|  * | ||||
|  * @param   rpc     instance | ||||
|  * @param   owner   owner of session | ||||
|  * @return          pointer to RpcSession descriptor, or | ||||
|  *                  NULL if RPC is busy and can't open session now | ||||
|  */ | ||||
| RpcSession* rpc_session_open(Rpc* rpc); | ||||
| RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner); | ||||
| 
 | ||||
| /** Close RPC session
 | ||||
|  * It is guaranteed that no callbacks will be called | ||||
|  | ||||
| @ -47,7 +47,7 @@ void rpc_cli_command_start_session(Cli* cli, FuriString* args, void* context) { | ||||
|     FURI_LOG_D(TAG, "Free memory %lu", mem_before); | ||||
| 
 | ||||
|     furi_hal_usb_lock(); | ||||
|     RpcSession* rpc_session = rpc_session_open(rpc); | ||||
|     RpcSession* rpc_session = rpc_session_open(rpc, RpcOwnerUsb); | ||||
|     if(rpc_session == NULL) { | ||||
|         printf("Session start error\r\n"); | ||||
|         furi_hal_usb_unlock(); | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| #include "rpc_i.h" | ||||
| #include "gui.pb.h" | ||||
| #include <gui/gui_i.h> | ||||
| #include <assets_icons.h> | ||||
| 
 | ||||
| #define TAG "RpcGui" | ||||
| 
 | ||||
| @ -31,6 +32,8 @@ typedef struct { | ||||
| 
 | ||||
|     uint32_t input_key_counter[InputKeyMAX]; | ||||
|     uint32_t input_counter; | ||||
| 
 | ||||
|     ViewPort* rpc_session_active_viewport; | ||||
| } RpcGuiSystem; | ||||
| 
 | ||||
| static const PB_Gui_ScreenOrientation rpc_system_gui_screen_orientation_map[] = { | ||||
| @ -352,6 +355,12 @@ static void rpc_system_gui_virtual_display_frame_process(const PB_Main* request, | ||||
|     (void)session; | ||||
| } | ||||
| 
 | ||||
| static void rpc_active_session_icon_draw_callback(Canvas* canvas, void* context) { | ||||
|     UNUSED(context); | ||||
|     furi_assert(canvas); | ||||
|     canvas_draw_icon(canvas, 0, 0, &I_Rpc_active_7x8); | ||||
| } | ||||
| 
 | ||||
| void* rpc_system_gui_alloc(RpcSession* session) { | ||||
|     furi_assert(session); | ||||
| 
 | ||||
| @ -359,6 +368,18 @@ void* rpc_system_gui_alloc(RpcSession* session) { | ||||
|     rpc_gui->gui = furi_record_open(RECORD_GUI); | ||||
|     rpc_gui->session = session; | ||||
| 
 | ||||
|     // Active session icon
 | ||||
|     rpc_gui->rpc_session_active_viewport = view_port_alloc(); | ||||
|     view_port_set_width(rpc_gui->rpc_session_active_viewport, icon_get_width(&I_Rpc_active_7x8)); | ||||
|     view_port_draw_callback_set( | ||||
|         rpc_gui->rpc_session_active_viewport, rpc_active_session_icon_draw_callback, session); | ||||
|     if(rpc_session_get_owner(rpc_gui->session) != RpcOwnerBle) { | ||||
|         view_port_enabled_set(rpc_gui->rpc_session_active_viewport, true); | ||||
|     } else { | ||||
|         view_port_enabled_set(rpc_gui->rpc_session_active_viewport, false); | ||||
|     } | ||||
|     gui_add_view_port(rpc_gui->gui, rpc_gui->rpc_session_active_viewport, GuiLayerStatusBarLeft); | ||||
| 
 | ||||
|     RpcHandler rpc_handler = { | ||||
|         .message_handler = NULL, | ||||
|         .decode_submessage = NULL, | ||||
| @ -399,6 +420,9 @@ void rpc_system_gui_free(void* context) { | ||||
|         rpc_gui->virtual_display_not_empty = false; | ||||
|     } | ||||
| 
 | ||||
|     gui_remove_view_port(rpc_gui->gui, rpc_gui->rpc_session_active_viewport); | ||||
|     view_port_free(rpc_gui->rpc_session_active_viewport); | ||||
| 
 | ||||
|     if(rpc_gui->is_streaming) { | ||||
|         rpc_gui->is_streaming = false; | ||||
|         // Remove GUI framebuffer callback
 | ||||
|  | ||||
| @ -157,18 +157,33 @@ static NotificationAppSettings* alloc_settings() { | ||||
|     variable_item_set_current_value_index(item, value_index); | ||||
|     variable_item_set_current_value_text(item, backlight_text[value_index]); | ||||
| 
 | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { | ||||
|         item = variable_item_list_add(app->variable_item_list, "Volume", 1, NULL, app); | ||||
|         value_index = 0; | ||||
|         variable_item_set_current_value_index(item, value_index); | ||||
|         variable_item_set_current_value_text(item, "Stealth"); | ||||
|     } else { | ||||
|         item = variable_item_list_add( | ||||
|             app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); | ||||
|     value_index = | ||||
|         value_index_float(app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); | ||||
|         value_index = value_index_float( | ||||
|             app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); | ||||
|         variable_item_set_current_value_index(item, value_index); | ||||
|         variable_item_set_current_value_text(item, volume_text[value_index]); | ||||
|     } | ||||
| 
 | ||||
|     item = | ||||
|         variable_item_list_add(app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); | ||||
|     value_index = value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { | ||||
|         item = variable_item_list_add(app->variable_item_list, "Vibro", 1, NULL, app); | ||||
|         value_index = 0; | ||||
|         variable_item_set_current_value_index(item, value_index); | ||||
|         variable_item_set_current_value_text(item, "Stealth"); | ||||
|     } else { | ||||
|         item = variable_item_list_add( | ||||
|             app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); | ||||
|         value_index = | ||||
|             value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); | ||||
|         variable_item_set_current_value_index(item, value_index); | ||||
|         variable_item_set_current_value_text(item, vibro_text[value_index]); | ||||
|     } | ||||
| 
 | ||||
|     app->view_dispatcher = view_dispatcher_alloc(); | ||||
|     view_dispatcher_enable_queue(app->view_dispatcher); | ||||
|  | ||||
| @ -4,8 +4,8 @@ | ||||
| #include <assets_icons.h> | ||||
| #include <locale/locale.h> | ||||
| 
 | ||||
| #define LOW_CHARGE_THRESHOLD 10 | ||||
| #define HIGH_DRAIN_CURRENT_THRESHOLD 100 | ||||
| #define LOW_CHARGE_THRESHOLD (10) | ||||
| #define HIGH_DRAIN_CURRENT_THRESHOLD (-100) | ||||
| 
 | ||||
| struct BatteryInfo { | ||||
|     View* view; | ||||
| @ -25,14 +25,13 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { | ||||
|     char header[20] = {}; | ||||
|     char value[20] = {}; | ||||
| 
 | ||||
|     int32_t drain_current = data->gauge_current * (-1000); | ||||
|     uint32_t charge_current = data->gauge_current * 1000; | ||||
|     int32_t current = 1000.0f * data->gauge_current; | ||||
| 
 | ||||
|     // Draw battery
 | ||||
|     canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28); | ||||
|     if(charge_current > 0) { | ||||
|     if(current > 0) { | ||||
|         canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14); | ||||
|     } else if(drain_current > HIGH_DRAIN_CURRENT_THRESHOLD) { | ||||
|     } else if(current < HIGH_DRAIN_CURRENT_THRESHOLD) { | ||||
|         canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14); | ||||
|     } else if(data->charge < LOW_CHARGE_THRESHOLD) { | ||||
|         canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14); | ||||
| @ -44,7 +43,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { | ||||
|     elements_bubble(canvas, 53, 0, 71, 39); | ||||
| 
 | ||||
|     // Set text
 | ||||
|     if(charge_current > 0) { | ||||
|     if(current > 0) { | ||||
|         snprintf(emote, sizeof(emote), "%s", "Yummy!"); | ||||
|         snprintf(header, sizeof(header), "%s", "Charging at"); | ||||
|         snprintf( | ||||
| @ -53,23 +52,22 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { | ||||
|             "%lu.%luV   %lumA", | ||||
|             (uint32_t)(data->vbus_voltage), | ||||
|             (uint32_t)(data->vbus_voltage * 10) % 10, | ||||
|             charge_current); | ||||
|     } else if(drain_current > 0) { | ||||
|             current); | ||||
|     } else if(current < 0) { | ||||
|         snprintf( | ||||
|             emote, | ||||
|             sizeof(emote), | ||||
|             "%s", | ||||
|             drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "Oh no!" : "Om-nom-nom!"); | ||||
|             current < HIGH_DRAIN_CURRENT_THRESHOLD ? "Oh no!" : "Om-nom-nom!"); | ||||
|         snprintf(header, sizeof(header), "%s", "Consumption is"); | ||||
|         snprintf( | ||||
|             value, | ||||
|             sizeof(value), | ||||
|             "%ld %s", | ||||
|             drain_current, | ||||
|             drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); | ||||
|     } else if(drain_current != 0) { | ||||
|         snprintf(header, 20, "..."); | ||||
|     } else if(data->charge_voltage_limit < 4.2) { | ||||
|             ABS(current), | ||||
|             current < HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); | ||||
|     } else if(data->vbus_voltage > 0) { | ||||
|         if(data->charge_voltage_limit < 4.2) { | ||||
|             // Non-default battery charging limit, mention it
 | ||||
|             snprintf(emote, sizeof(emote), "Charged!"); | ||||
|             snprintf(header, sizeof(header), "Limited to"); | ||||
| @ -82,6 +80,9 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { | ||||
|         } else { | ||||
|             snprintf(header, sizeof(header), "Charged!"); | ||||
|         } | ||||
|     } else { | ||||
|         snprintf(header, sizeof(header), "Napping..."); | ||||
|     } | ||||
| 
 | ||||
|     canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote); | ||||
|     canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header); | ||||
|  | ||||
| @ -141,6 +141,21 @@ static void hand_orient_changed(VariableItem* item) { | ||||
|     loader_update_menu(); | ||||
| } | ||||
| 
 | ||||
| const char* const sleep_method[] = { | ||||
|     "Default", | ||||
|     "Legacy", | ||||
| }; | ||||
| 
 | ||||
| static void sleep_method_changed(VariableItem* item) { | ||||
|     uint8_t index = variable_item_get_current_value_index(item); | ||||
|     variable_item_set_current_value_text(item, sleep_method[index]); | ||||
|     if(index) { | ||||
|         furi_hal_rtc_set_flag(FuriHalRtcFlagLegacySleep); | ||||
|     } else { | ||||
|         furi_hal_rtc_reset_flag(FuriHalRtcFlagLegacySleep); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static uint32_t system_settings_exit(void* context) { | ||||
|     UNUSED(context); | ||||
|     return VIEW_NONE; | ||||
| @ -218,6 +233,12 @@ SystemSettings* system_settings_alloc() { | ||||
|     variable_item_set_current_value_index(item, value_index); | ||||
|     variable_item_set_current_value_text(item, heap_trace_mode_text[value_index]); | ||||
| 
 | ||||
|     item = variable_item_list_add( | ||||
|         app->var_item_list, "Sleep Method", COUNT_OF(sleep_method), sleep_method_changed, app); | ||||
|     value_index = furi_hal_rtc_is_flag_set(FuriHalRtcFlagLegacySleep) ? 1 : 0; | ||||
|     variable_item_set_current_value_index(item, value_index); | ||||
|     variable_item_set_current_value_text(item, sleep_method[value_index]); | ||||
| 
 | ||||
|     view_set_previous_callback( | ||||
|         variable_item_list_get_view(app->var_item_list), system_settings_exit); | ||||
|     view_dispatcher_add_view( | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/StatusBar/Muted_8x8.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/StatusBar/Muted_8x8.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/StatusBar/Rpc_active_7x8.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/StatusBar/Rpc_active_7x8.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.5 KiB | 
| @ -135,6 +135,7 @@ class FlipperAppStateHelper: | ||||
|         self.app_list_ptr = None | ||||
|         self.app_list_entry_type = None | ||||
|         self._current_apps: list[AppState] = [] | ||||
|         self.set_debug_mode(True) | ||||
| 
 | ||||
|     def _walk_app_list(self, list_head): | ||||
|         while list_head: | ||||
| @ -195,7 +196,7 @@ class FlipperAppStateHelper: | ||||
|         self.set_debug_mode(False) | ||||
| 
 | ||||
|     def set_debug_mode(self, mode: bool) -> None: | ||||
|         gdb.execute(f"set variable fap_loader_debug_active = {int(mode)}") | ||||
|         gdb.execute(f"set variable furi_hal_debug_gdb_session_active = {int(mode)}") | ||||
| 
 | ||||
| 
 | ||||
| # Init additional 'fap-set-debug-elf-root' command and set up hooks | ||||
|  | ||||
							
								
								
									
										26
									
								
								documentation/FuriHalDebuging.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								documentation/FuriHalDebuging.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| # Furi HAL Debugging | ||||
| 
 | ||||
| Some Furi subsystem got additional debugging features that can be enabled by adding additional defines to firmware compilation. | ||||
| Usually they are used for low level tracing and profiling or signal redirection/duplication. | ||||
| 
 | ||||
| 
 | ||||
| ## FuriHalOs | ||||
| 
 | ||||
| `--extra-define=FURI_HAL_OS_DEBUG` enables tick, tick suppression, idle and time flow. | ||||
| 
 | ||||
| There are 3 signals that will be exposed to external GPIO pins: | ||||
| 
 | ||||
| - `AWAKE`   - `PA7` - High when system is busy with computations, low when sleeping. Can be used to track transitions to sleep mode. | ||||
| - `TICK`    - `PA6` - Flipped on system tick, only flips when no tick suppression in progress. Can be used to track tick skew and abnormal task scheduling. | ||||
| - `SECOND`  - `PA4` - Flipped each second. Can be used for tracing RT issue: time flow disturbance means system doesn't conforms Hard RT. | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| ## FuriHalPower | ||||
| 
 | ||||
| `--extra-define=FURI_HAL_POWER_DEBUG` enables power subsystem mode transitions tracing. | ||||
| 
 | ||||
| There are 2 signals that will be exposed to external GPIO pins: | ||||
| 
 | ||||
| - `WFI`     - `PB2` - Light sleep (wait for interrupt) used. Basically this is lightest and most non-breaking things power save mode. All function and debug should work correctly in this mode. | ||||
| - `STOP`    - `PC3` - STOP mode used. Platform deep sleep mode. Extremely fragile mode where most of the silicon is disabled or in unusable state. Debugging MCU in this mode is nearly impossible. | ||||
							
								
								
									
										23
									
								
								documentation/LFRFIDRaw.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								documentation/LFRFIDRaw.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| # Reading RAW RFID data | ||||
| 
 | ||||
| Flipper Zero has the option to read RAW data from 125 kHz cards that allows you to record the card's data and save it, similar to how a dictaphone records sound. | ||||
| 
 | ||||
| To use this function, you need to activate the Debug mode on your Flipper Zero by doing the following: | ||||
| 
 | ||||
| 1. Go to **Main Menu** → **Settings** → **System**. | ||||
| 
 | ||||
| 2. Set **Debug** to **ON**. | ||||
| 
 | ||||
| Once the Debug mode is activated on your Flipper Zero, you can read RAW data from 125 kHz RFID cards: | ||||
| 
 | ||||
| 1. Go to **Main Menu** → **125 kHz RFID** → **Extra Actions**. | ||||
| 
 | ||||
| 2. Select **RAW RFID** data and name the raw file. | ||||
| 
 | ||||
| 3. Read instructions and press **OK**. | ||||
| 
 | ||||
| 4. Apply the card to Flipper Zero's back. | ||||
| 
 | ||||
| 5. Once the reading is finished, press **OK**. | ||||
| 
 | ||||
| Two files with data (with ASK and PSK modulations) will be saved in the `lfrfid` folder on the microSD card. Now, you can share it and the card's photo with developers by creating an issue on GitHub. | ||||
| @ -105,6 +105,7 @@ To run cleanup (think of `make clean`) for specified targets, add the `-c` optio | ||||
| - `--options optionfile.py` (default value `fbt_options.py`) - load a file with multiple configuration values | ||||
| - `--extra-int-apps=app1,app2,appN` - force listed apps to be built as internal with the `firmware` target | ||||
| - `--extra-ext-apps=app1,app2,appN` - force listed apps to be built as external with the `firmware_extapps` target | ||||
| - `--extra-define=A --extra-define=B=C ` - extra global defines that will be passed to the C/C++ compiler, can be specified multiple times | ||||
| - `--proxy-env=VAR1,VAR2` - additional environment variables to expose to subprocesses spawned by `fbt`. By default, `fbt` sanitizes the execution environment and doesn't forward all inherited environment variables. You can find the list of variables that are always forwarded in the `environ.scons` file. | ||||
| 
 | ||||
| ## Configuration | ||||
|  | ||||
| @ -20,7 +20,7 @@ DIST_SUFFIX = "local" | ||||
| COPRO_OB_DATA = "scripts/ob.data" | ||||
| 
 | ||||
| # Must match lib/STM32CubeWB version | ||||
| COPRO_CUBE_VERSION = "1.13.3" | ||||
| COPRO_CUBE_VERSION = "1.15.0" | ||||
| 
 | ||||
| COPRO_CUBE_DIR = "lib/STM32CubeWB" | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| entry,status,name,type,params | ||||
| Version,+,21.0,, | ||||
| Version,+,23.0,, | ||||
| Header,+,applications/services/bt/bt_service/bt.h,, | ||||
| Header,+,applications/services/cli/cli.h,, | ||||
| Header,+,applications/services/cli/cli_vcp.h,, | ||||
| @ -176,17 +176,17 @@ Header,+,lib/toolbox/tar/tar_archive.h,, | ||||
| Header,+,lib/toolbox/value_index.h,, | ||||
| Header,+,lib/toolbox/version.h,, | ||||
| Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* | ||||
| Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" | ||||
| Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, const LL_ADC_CommonInitTypeDef*" | ||||
| Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* | ||||
| Function,-,LL_ADC_DeInit,ErrorStatus,ADC_TypeDef* | ||||
| Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_INJ_InitTypeDef*" | ||||
| Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_INJ_InitTypeDef*" | ||||
| Function,-,LL_ADC_INJ_StructInit,void,LL_ADC_INJ_InitTypeDef* | ||||
| Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_InitTypeDef*" | ||||
| Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_REG_InitTypeDef*" | ||||
| Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_InitTypeDef*" | ||||
| Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_REG_InitTypeDef*" | ||||
| Function,-,LL_ADC_REG_StructInit,void,LL_ADC_REG_InitTypeDef* | ||||
| Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* | ||||
| Function,-,LL_COMP_DeInit,ErrorStatus,COMP_TypeDef* | ||||
| Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, LL_COMP_InitTypeDef*" | ||||
| Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, const LL_COMP_InitTypeDef*" | ||||
| Function,-,LL_COMP_StructInit,void,LL_COMP_InitTypeDef* | ||||
| Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* | ||||
| Function,-,LL_CRS_DeInit,ErrorStatus, | ||||
| @ -205,10 +205,10 @@ Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef* | ||||
| Function,-,LL_Init1msTick,void,uint32_t | ||||
| Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* | ||||
| Function,-,LL_LPTIM_Disable,void,LPTIM_TypeDef* | ||||
| Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, LL_LPTIM_InitTypeDef*" | ||||
| Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, const LL_LPTIM_InitTypeDef*" | ||||
| Function,-,LL_LPTIM_StructInit,void,LL_LPTIM_InitTypeDef* | ||||
| Function,-,LL_LPUART_DeInit,ErrorStatus,USART_TypeDef* | ||||
| Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, LL_LPUART_InitTypeDef*" | ||||
| Function,-,LL_LPUART_DeInit,ErrorStatus,const USART_TypeDef* | ||||
| Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, const LL_LPUART_InitTypeDef*" | ||||
| Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* | ||||
| Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* | ||||
| Function,-,LL_PKA_Init,ErrorStatus,"PKA_TypeDef*, LL_PKA_InitTypeDef*" | ||||
| @ -253,23 +253,23 @@ Function,+,LL_SPI_Init,ErrorStatus,"SPI_TypeDef*, LL_SPI_InitTypeDef*" | ||||
| Function,-,LL_SPI_StructInit,void,LL_SPI_InitTypeDef* | ||||
| Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t | ||||
| Function,+,LL_SetSystemCoreClock,void,uint32_t | ||||
| Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_BDTR_InitTypeDef*" | ||||
| Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_BDTR_InitTypeDef*" | ||||
| Function,-,LL_TIM_BDTR_StructInit,void,LL_TIM_BDTR_InitTypeDef* | ||||
| Function,+,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* | ||||
| Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_ENCODER_InitTypeDef*" | ||||
| Function,-,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* | ||||
| Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_ENCODER_InitTypeDef*" | ||||
| Function,-,LL_TIM_ENCODER_StructInit,void,LL_TIM_ENCODER_InitTypeDef* | ||||
| Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_HALLSENSOR_InitTypeDef*" | ||||
| Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_HALLSENSOR_InitTypeDef*" | ||||
| Function,-,LL_TIM_HALLSENSOR_StructInit,void,LL_TIM_HALLSENSOR_InitTypeDef* | ||||
| Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_IC_InitTypeDef*" | ||||
| Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_IC_InitTypeDef*" | ||||
| Function,-,LL_TIM_IC_StructInit,void,LL_TIM_IC_InitTypeDef* | ||||
| Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_InitTypeDef*" | ||||
| Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_OC_InitTypeDef*" | ||||
| Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_InitTypeDef*" | ||||
| Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_OC_InitTypeDef*" | ||||
| Function,-,LL_TIM_OC_StructInit,void,LL_TIM_OC_InitTypeDef* | ||||
| Function,-,LL_TIM_StructInit,void,LL_TIM_InitTypeDef* | ||||
| Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, LL_USART_ClockInitTypeDef*" | ||||
| Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, const LL_USART_ClockInitTypeDef*" | ||||
| Function,-,LL_USART_ClockStructInit,void,LL_USART_ClockInitTypeDef* | ||||
| Function,-,LL_USART_DeInit,ErrorStatus,USART_TypeDef* | ||||
| Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, LL_USART_InitTypeDef*" | ||||
| Function,-,LL_USART_DeInit,ErrorStatus,const USART_TypeDef* | ||||
| Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, const LL_USART_InitTypeDef*" | ||||
| Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* | ||||
| Function,-,LL_mDelay,void,uint32_t | ||||
| Function,-,SystemCoreClockUpdate,void, | ||||
| @ -901,6 +901,7 @@ Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*" | ||||
| Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t | ||||
| Function,+,furi_hal_debug_disable,void, | ||||
| Function,+,furi_hal_debug_enable,void, | ||||
| Function,+,furi_hal_debug_is_gdb_session_active,_Bool, | ||||
| Function,-,furi_hal_deinit_early,void, | ||||
| Function,-,furi_hal_flash_erase,void,uint8_t | ||||
| Function,-,furi_hal_flash_get_base,size_t, | ||||
| @ -983,7 +984,6 @@ Function,-,furi_hal_os_init,void, | ||||
| Function,+,furi_hal_os_tick,void, | ||||
| Function,+,furi_hal_power_check_otg_status,void, | ||||
| Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, void*" | ||||
| Function,+,furi_hal_power_deep_sleep_available,_Bool, | ||||
| Function,+,furi_hal_power_disable_external_3_3v,void, | ||||
| Function,+,furi_hal_power_disable_otg,void, | ||||
| Function,+,furi_hal_power_enable_external_3_3v,void, | ||||
| @ -1059,6 +1059,7 @@ Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits | ||||
| Function,+,furi_hal_rtc_set_log_level,void,uint8_t | ||||
| Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t | ||||
| Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" | ||||
| Function,+,furi_hal_rtc_sync_shadow,void, | ||||
| Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* | ||||
| Function,+,furi_hal_speaker_acquire,_Bool,uint32_t | ||||
| Function,-,furi_hal_speaker_deinit,void, | ||||
| @ -1595,7 +1596,8 @@ Function,-,rindex,char*,"const char*, int" | ||||
| Function,+,rpc_session_close,void,RpcSession* | ||||
| Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" | ||||
| Function,+,rpc_session_get_available_size,size_t,RpcSession* | ||||
| Function,+,rpc_session_open,RpcSession*,Rpc* | ||||
| Function,+,rpc_session_get_owner,RpcOwner,RpcSession* | ||||
| Function,+,rpc_session_open,RpcSession*,"Rpc*, RpcOwner" | ||||
| Function,+,rpc_session_set_buffer_is_empty_callback,void,"RpcSession*, RpcBufferIsEmptyCallback" | ||||
| Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" | ||||
| Function,+,rpc_session_set_context,void,"RpcSession*, void*" | ||||
| @ -2149,6 +2151,8 @@ Variable,+,gpio_ext_pd0,const GpioPin, | ||||
| Variable,+,gpio_ext_pe4,const GpioPin, | ||||
| Variable,+,gpio_i2c_power_scl,const GpioPin, | ||||
| Variable,+,gpio_i2c_power_sda,const GpioPin, | ||||
| Variable,+,gpio_ibutton,const GpioPin, | ||||
| Variable,+,gpio_periph_power,const GpioPin, | ||||
| Variable,+,gpio_pins,const GpioPinRecord[], | ||||
| Variable,+,gpio_pins_count,const size_t, | ||||
| Variable,+,gpio_sdcard_cd,const GpioPin, | ||||
| @ -2157,11 +2161,13 @@ Variable,+,gpio_speaker,const GpioPin, | ||||
| Variable,+,gpio_spi_d_miso,const GpioPin, | ||||
| Variable,+,gpio_spi_d_mosi,const GpioPin, | ||||
| Variable,+,gpio_spi_d_sck,const GpioPin, | ||||
| Variable,+,gpio_swclk,const GpioPin, | ||||
| Variable,+,gpio_swdio,const GpioPin, | ||||
| Variable,+,gpio_usart_rx,const GpioPin, | ||||
| Variable,+,gpio_usart_tx,const GpioPin, | ||||
| Variable,+,gpio_usb_dm,const GpioPin, | ||||
| Variable,+,gpio_usb_dp,const GpioPin, | ||||
| Variable,+,gpio_ibutton,const GpioPin, | ||||
| Variable,+,gpio_vibro,const GpioPin, | ||||
| Variable,+,input_pins,const InputPin[], | ||||
| Variable,+,input_pins_count,const size_t, | ||||
| Variable,+,message_blink_set_color_blue,const NotificationMessage, | ||||
| @ -2309,7 +2315,6 @@ Variable,+,message_red_255,const NotificationMessage, | ||||
| Variable,+,message_sound_off,const NotificationMessage, | ||||
| Variable,+,message_vibro_off,const NotificationMessage, | ||||
| Variable,+,message_vibro_on,const NotificationMessage, | ||||
| Variable,+,gpio_periph_power,const GpioPin, | ||||
| Variable,+,sequence_audiovisual_alert,const NotificationSequence, | ||||
| Variable,+,sequence_blink_blue_10,const NotificationSequence, | ||||
| Variable,+,sequence_blink_blue_100,const NotificationSequence, | ||||
| @ -2364,4 +2369,3 @@ Variable,+,usb_cdc_single,FuriHalUsbInterface, | ||||
| Variable,+,usb_hid,FuriHalUsbInterface, | ||||
| Variable,+,usb_hid_u2f,FuriHalUsbInterface, | ||||
| Variable,+,usbd_devfs,const usbd_driver, | ||||
| Variable,+,gpio_vibro,const GpioPin, | ||||
|  | ||||
| 
 | 
| @ -6,6 +6,9 @@ | ||||
| 
 | ||||
| #define TAG "FuriHalResources" | ||||
| 
 | ||||
| const GpioPin gpio_swdio = {.port = GPIOA, .pin = LL_GPIO_PIN_13}; | ||||
| const GpioPin gpio_swclk = {.port = GPIOA, .pin = LL_GPIO_PIN_14}; | ||||
| 
 | ||||
| const GpioPin gpio_vibro = {.port = GPIOA, .pin = LL_GPIO_PIN_8}; | ||||
| const GpioPin gpio_ibutton = {.port = GPIOB, .pin = LL_GPIO_PIN_14}; | ||||
| 
 | ||||
| @ -166,8 +169,9 @@ void furi_hal_resources_init() { | ||||
|     furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall); | ||||
| 
 | ||||
|     // Explicit pulls pins
 | ||||
|     furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow); | ||||
|     furi_hal_gpio_init(&gpio_vibro, GpioModeAnalog, GpioPullDown, GpioSpeedLow); | ||||
|     LL_PWR_EnablePUPDCfg(); | ||||
|     LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_8); // gpio_speaker
 | ||||
|     LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_A, LL_PWR_GPIO_BIT_8); // gpio_vibro
 | ||||
| 
 | ||||
|     // Display pins
 | ||||
|     furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||
|  | ||||
| @ -50,6 +50,9 @@ extern const size_t input_pins_count; | ||||
| extern const GpioPinRecord gpio_pins[]; | ||||
| extern const size_t gpio_pins_count; | ||||
| 
 | ||||
| extern const GpioPin gpio_swdio; | ||||
| extern const GpioPin gpio_swclk; | ||||
| 
 | ||||
| extern const GpioPin gpio_vibro; | ||||
| extern const GpioPin gpio_ibutton; | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| entry,status,name,type,params | ||||
| Version,+,21.0,, | ||||
| Version,+,23.0,, | ||||
| Header,+,applications/services/bt/bt_service/bt.h,, | ||||
| Header,+,applications/services/cli/cli.h,, | ||||
| Header,+,applications/services/cli/cli_vcp.h,, | ||||
| @ -208,17 +208,17 @@ Header,+,lib/toolbox/tar/tar_archive.h,, | ||||
| Header,+,lib/toolbox/value_index.h,, | ||||
| Header,+,lib/toolbox/version.h,, | ||||
| Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* | ||||
| Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" | ||||
| Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, const LL_ADC_CommonInitTypeDef*" | ||||
| Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* | ||||
| Function,-,LL_ADC_DeInit,ErrorStatus,ADC_TypeDef* | ||||
| Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_INJ_InitTypeDef*" | ||||
| Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_INJ_InitTypeDef*" | ||||
| Function,-,LL_ADC_INJ_StructInit,void,LL_ADC_INJ_InitTypeDef* | ||||
| Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_InitTypeDef*" | ||||
| Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_REG_InitTypeDef*" | ||||
| Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_InitTypeDef*" | ||||
| Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_REG_InitTypeDef*" | ||||
| Function,-,LL_ADC_REG_StructInit,void,LL_ADC_REG_InitTypeDef* | ||||
| Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* | ||||
| Function,-,LL_COMP_DeInit,ErrorStatus,COMP_TypeDef* | ||||
| Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, LL_COMP_InitTypeDef*" | ||||
| Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, const LL_COMP_InitTypeDef*" | ||||
| Function,-,LL_COMP_StructInit,void,LL_COMP_InitTypeDef* | ||||
| Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* | ||||
| Function,-,LL_CRS_DeInit,ErrorStatus, | ||||
| @ -237,10 +237,10 @@ Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef* | ||||
| Function,-,LL_Init1msTick,void,uint32_t | ||||
| Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* | ||||
| Function,-,LL_LPTIM_Disable,void,LPTIM_TypeDef* | ||||
| Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, LL_LPTIM_InitTypeDef*" | ||||
| Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, const LL_LPTIM_InitTypeDef*" | ||||
| Function,-,LL_LPTIM_StructInit,void,LL_LPTIM_InitTypeDef* | ||||
| Function,-,LL_LPUART_DeInit,ErrorStatus,USART_TypeDef* | ||||
| Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, LL_LPUART_InitTypeDef*" | ||||
| Function,-,LL_LPUART_DeInit,ErrorStatus,const USART_TypeDef* | ||||
| Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, const LL_LPUART_InitTypeDef*" | ||||
| Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* | ||||
| Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* | ||||
| Function,-,LL_PKA_Init,ErrorStatus,"PKA_TypeDef*, LL_PKA_InitTypeDef*" | ||||
| @ -285,23 +285,23 @@ Function,+,LL_SPI_Init,ErrorStatus,"SPI_TypeDef*, LL_SPI_InitTypeDef*" | ||||
| Function,-,LL_SPI_StructInit,void,LL_SPI_InitTypeDef* | ||||
| Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t | ||||
| Function,+,LL_SetSystemCoreClock,void,uint32_t | ||||
| Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_BDTR_InitTypeDef*" | ||||
| Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_BDTR_InitTypeDef*" | ||||
| Function,-,LL_TIM_BDTR_StructInit,void,LL_TIM_BDTR_InitTypeDef* | ||||
| Function,+,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* | ||||
| Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_ENCODER_InitTypeDef*" | ||||
| Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_ENCODER_InitTypeDef*" | ||||
| Function,-,LL_TIM_ENCODER_StructInit,void,LL_TIM_ENCODER_InitTypeDef* | ||||
| Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_HALLSENSOR_InitTypeDef*" | ||||
| Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_HALLSENSOR_InitTypeDef*" | ||||
| Function,-,LL_TIM_HALLSENSOR_StructInit,void,LL_TIM_HALLSENSOR_InitTypeDef* | ||||
| Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_IC_InitTypeDef*" | ||||
| Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_IC_InitTypeDef*" | ||||
| Function,-,LL_TIM_IC_StructInit,void,LL_TIM_IC_InitTypeDef* | ||||
| Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_InitTypeDef*" | ||||
| Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_OC_InitTypeDef*" | ||||
| Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_InitTypeDef*" | ||||
| Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_OC_InitTypeDef*" | ||||
| Function,-,LL_TIM_OC_StructInit,void,LL_TIM_OC_InitTypeDef* | ||||
| Function,-,LL_TIM_StructInit,void,LL_TIM_InitTypeDef* | ||||
| Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, LL_USART_ClockInitTypeDef*" | ||||
| Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, const LL_USART_ClockInitTypeDef*" | ||||
| Function,-,LL_USART_ClockStructInit,void,LL_USART_ClockInitTypeDef* | ||||
| Function,-,LL_USART_DeInit,ErrorStatus,USART_TypeDef* | ||||
| Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, LL_USART_InitTypeDef*" | ||||
| Function,-,LL_USART_DeInit,ErrorStatus,const USART_TypeDef* | ||||
| Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, const LL_USART_InitTypeDef*" | ||||
| Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* | ||||
| Function,-,LL_mDelay,void,uint32_t | ||||
| Function,-,SystemCoreClockUpdate,void, | ||||
| @ -1082,6 +1082,7 @@ Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*" | ||||
| Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t | ||||
| Function,+,furi_hal_debug_disable,void, | ||||
| Function,+,furi_hal_debug_enable,void, | ||||
| Function,+,furi_hal_debug_is_gdb_session_active,_Bool, | ||||
| Function,-,furi_hal_deinit_early,void, | ||||
| Function,-,furi_hal_flash_erase,void,uint8_t | ||||
| Function,-,furi_hal_flash_get_base,size_t, | ||||
| @ -1212,7 +1213,6 @@ Function,-,furi_hal_os_init,void, | ||||
| Function,+,furi_hal_os_tick,void, | ||||
| Function,+,furi_hal_power_check_otg_status,void, | ||||
| Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, void*" | ||||
| Function,+,furi_hal_power_deep_sleep_available,_Bool, | ||||
| Function,+,furi_hal_power_disable_external_3_3v,void, | ||||
| Function,+,furi_hal_power_disable_otg,void, | ||||
| Function,+,furi_hal_power_enable_external_3_3v,void, | ||||
| @ -1313,6 +1313,7 @@ Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits | ||||
| Function,+,furi_hal_rtc_set_log_level,void,uint8_t | ||||
| Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t | ||||
| Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" | ||||
| Function,+,furi_hal_rtc_sync_shadow,void, | ||||
| Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* | ||||
| Function,+,furi_hal_speaker_acquire,_Bool,uint32_t | ||||
| Function,-,furi_hal_speaker_deinit,void, | ||||
| @ -2372,7 +2373,8 @@ Function,-,roundl,long double,long double | ||||
| Function,+,rpc_session_close,void,RpcSession* | ||||
| Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" | ||||
| Function,+,rpc_session_get_available_size,size_t,RpcSession* | ||||
| Function,+,rpc_session_open,RpcSession*,Rpc* | ||||
| Function,+,rpc_session_get_owner,RpcOwner,RpcSession* | ||||
| Function,+,rpc_session_open,RpcSession*,"Rpc*, RpcOwner" | ||||
| Function,+,rpc_session_set_buffer_is_empty_callback,void,"RpcSession*, RpcBufferIsEmptyCallback" | ||||
| Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" | ||||
| Function,+,rpc_session_set_context,void,"RpcSession*, void*" | ||||
| @ -3076,10 +3078,12 @@ Variable,+,gpio_ext_pc1,const GpioPin, | ||||
| Variable,+,gpio_ext_pc3,const GpioPin, | ||||
| Variable,+,gpio_i2c_power_scl,const GpioPin, | ||||
| Variable,+,gpio_i2c_power_sda,const GpioPin, | ||||
| Variable,+,gpio_ibutton,const GpioPin, | ||||
| Variable,+,gpio_infrared_rx,const GpioPin, | ||||
| Variable,+,gpio_infrared_tx,const GpioPin, | ||||
| Variable,+,gpio_nfc_cs,const GpioPin, | ||||
| Variable,+,gpio_nfc_irq_rfid_pull,const GpioPin, | ||||
| Variable,+,gpio_periph_power,const GpioPin, | ||||
| Variable,+,gpio_pins,const GpioPinRecord[], | ||||
| Variable,+,gpio_pins_count,const size_t, | ||||
| Variable,+,gpio_rf_sw_0,const GpioPin, | ||||
| @ -3096,11 +3100,13 @@ Variable,+,gpio_spi_r_miso,const GpioPin, | ||||
| Variable,+,gpio_spi_r_mosi,const GpioPin, | ||||
| Variable,+,gpio_spi_r_sck,const GpioPin, | ||||
| Variable,+,gpio_subghz_cs,const GpioPin, | ||||
| Variable,+,gpio_swclk,const GpioPin, | ||||
| Variable,+,gpio_swdio,const GpioPin, | ||||
| Variable,+,gpio_usart_rx,const GpioPin, | ||||
| Variable,+,gpio_usart_tx,const GpioPin, | ||||
| Variable,+,gpio_usb_dm,const GpioPin, | ||||
| Variable,+,gpio_usb_dp,const GpioPin, | ||||
| Variable,+,gpio_ibutton,const GpioPin, | ||||
| Variable,+,gpio_vibro,const GpioPin, | ||||
| Variable,+,input_pins,const InputPin[], | ||||
| Variable,+,input_pins_count,const size_t, | ||||
| Variable,+,lfrfid_protocols,const ProtocolBase*[], | ||||
| @ -3249,7 +3255,6 @@ Variable,+,message_red_255,const NotificationMessage, | ||||
| Variable,+,message_sound_off,const NotificationMessage, | ||||
| Variable,+,message_vibro_off,const NotificationMessage, | ||||
| Variable,+,message_vibro_on,const NotificationMessage, | ||||
| Variable,+,gpio_periph_power,const GpioPin, | ||||
| Variable,+,sequence_audiovisual_alert,const NotificationSequence, | ||||
| Variable,+,sequence_blink_blue_10,const NotificationSequence, | ||||
| Variable,+,sequence_blink_blue_100,const NotificationSequence, | ||||
| @ -3307,4 +3312,3 @@ Variable,+,usb_cdc_single,FuriHalUsbInterface, | ||||
| Variable,+,usb_hid,FuriHalUsbInterface, | ||||
| Variable,+,usb_hid_u2f,FuriHalUsbInterface, | ||||
| Variable,+,usbd_devfs,const usbd_driver, | ||||
| Variable,+,gpio_vibro,const GpioPin, | ||||
|  | ||||
| 
 | 
| @ -33,6 +33,7 @@ extern "C" { | ||||
| #include <stdarg.h> | ||||
| 
 | ||||
| #include <core/common_defines.h> | ||||
| #include <tl.h> | ||||
| 
 | ||||
| #include "app_conf.h" | ||||
| 
 | ||||
|  | ||||
| @ -8,6 +8,8 @@ | ||||
| 
 | ||||
| #define CFG_TX_POWER (0x19) /* +0dBm */ | ||||
| 
 | ||||
| #define CFG_IDENTITY_ADDRESS GAP_PUBLIC_ADDR | ||||
| 
 | ||||
| /**
 | ||||
|  * Define Advertising parameters | ||||
|  */ | ||||
|  | ||||
| @ -33,7 +33,8 @@ PLACE_IN_SECTION("MB_MEM2") | ||||
| ALIGN(4) static SHCI_C2_DEBUG_TracesConfig_t APPD_TracesConfig = {0, 0, 0, 0}; | ||||
| PLACE_IN_SECTION("MB_MEM2") | ||||
| ALIGN(4) | ||||
| static SHCI_C2_DEBUG_GeneralConfig_t APPD_GeneralConfig = {BLE_DTB_CFG, SYS_DBG_CFG1, {0, 0}}; | ||||
| static SHCI_C2_DEBUG_GeneralConfig_t APPD_GeneralConfig = | ||||
|     {BLE_DTB_CFG, SYS_DBG_CFG1, {0, 0}, 0, 0, 0, 0, 0}; | ||||
| 
 | ||||
| /**
 | ||||
|  * THE DEBUG ON GPIO FOR CPU2 IS INTENDED TO BE USED ONLY ON REQUEST FROM ST SUPPORT | ||||
| @ -68,7 +69,7 @@ static const APPD_GpioConfig_t aGpioConfigList[GPIO_CFG_NBR_OF_FEATURES] = { | ||||
|     {GPIOA, LL_GPIO_PIN_0, 0, 0}, /* END_OF_CONNECTION_EVENT - Set on Entry / Reset on Exit */ | ||||
|     {GPIOA, LL_GPIO_PIN_0, 0, 0}, /* TIMER_SERVER_CALLBACK - Toggle on Entry */ | ||||
|     {GPIOA, LL_GPIO_PIN_4, 1, 0}, /* PES_ACTIVITY - Set on Entry / Reset on Exit */ | ||||
|     {GPIOB, LL_GPIO_PIN_2, 1, 0}, /* MB_BLE_SEND_EVT - Set on Entry / Reset on Exit */ | ||||
|     {GPIOC, LL_GPIO_PIN_0, 1, 0}, /* MB_BLE_SEND_EVT - Set on Entry / Reset on Exit */ | ||||
|     /* From v1.3.0 */ | ||||
|     {GPIOA, LL_GPIO_PIN_0, 0, 0}, /* BLE_NO_DELAY - Set on Entry / Reset on Exit */ | ||||
|     {GPIOA, LL_GPIO_PIN_0, 0, 0}, /* BLE_STACK_STORE_NVM_CB - Set on Entry / Reset on Exit */ | ||||
|  | ||||
| @ -18,8 +18,8 @@ PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer; | ||||
| PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; | ||||
| 
 | ||||
| _Static_assert( | ||||
|     sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 49, | ||||
|     "Ble stack config structure size mismatch"); | ||||
|     sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 57, | ||||
|     "Ble stack config structure size mismatch (check new config options - last updated for v.1.15.0)"); | ||||
| 
 | ||||
| typedef struct { | ||||
|     FuriMutex* hci_mtx; | ||||
| @ -88,6 +88,12 @@ bool ble_app_init() { | ||||
|             .min_tx_power = 0, | ||||
|             .max_tx_power = 0, | ||||
|             .rx_model_config = 1, | ||||
|             /* New stack (13.3->15.0) */ | ||||
|             .max_adv_set_nbr = 1, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set
 | ||||
|             .max_adv_data_len = 31, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set
 | ||||
|             .tx_path_compens = 0, // RF TX Path Compensation, * 0.1 dB
 | ||||
|             .rx_path_compens = 0, // RF RX Path Compensation, * 0.1 dB
 | ||||
|             .ble_core_version = 11, // BLE Core Version: 11(5.2), 12(5.3)
 | ||||
|         }}; | ||||
|     status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); | ||||
|     if(status) { | ||||
| @ -137,39 +143,34 @@ static int32_t ble_app_hci_thread(void* arg) { | ||||
| // Called by WPAN lib
 | ||||
| void hci_notify_asynch_evt(void* pdata) { | ||||
|     UNUSED(pdata); | ||||
|     if(ble_app) { | ||||
|     furi_check(ble_app); | ||||
|     FuriThreadId thread_id = furi_thread_get_id(ble_app->thread); | ||||
|     furi_assert(thread_id); | ||||
|     furi_thread_flags_set(thread_id, BLE_APP_FLAG_HCI_EVENT); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void hci_cmd_resp_release(uint32_t flag) { | ||||
|     UNUSED(flag); | ||||
|     if(ble_app) { | ||||
|         furi_semaphore_release(ble_app->hci_sem); | ||||
|     } | ||||
|     furi_check(ble_app); | ||||
|     furi_check(furi_semaphore_release(ble_app->hci_sem) == FuriStatusOk); | ||||
| } | ||||
| 
 | ||||
| void hci_cmd_resp_wait(uint32_t timeout) { | ||||
|     UNUSED(timeout); | ||||
|     if(ble_app) { | ||||
|         furi_semaphore_acquire(ble_app->hci_sem, FuriWaitForever); | ||||
|     } | ||||
|     furi_check(ble_app); | ||||
|     furi_check(furi_semaphore_acquire(ble_app->hci_sem, timeout) == FuriStatusOk); | ||||
| } | ||||
| 
 | ||||
| static void ble_app_hci_event_handler(void* pPayload) { | ||||
|     SVCCTL_UserEvtFlowStatus_t svctl_return_status; | ||||
|     tHCI_UserEvtRxParam* pParam = (tHCI_UserEvtRxParam*)pPayload; | ||||
| 
 | ||||
|     if(ble_app) { | ||||
|     furi_check(ble_app); | ||||
|     svctl_return_status = SVCCTL_UserEvtRx((void*)&(pParam->pckt->evtserial)); | ||||
|     if(svctl_return_status != SVCCTL_UserEvtFlowDisable) { | ||||
|         pParam->status = HCI_TL_UserEventFlow_Enable; | ||||
|     } else { | ||||
|         pParam->status = HCI_TL_UserEventFlow_Disable; | ||||
|     } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status) { | ||||
|  | ||||
| @ -23,6 +23,7 @@ | ||||
| #include <ble/core/ble_std.h> | ||||
| #include <ble/core/ble_defs.h> | ||||
| #include "osal.h" | ||||
| #include "compiler.h" | ||||
| 
 | ||||
| /* Default BLE variant */ | ||||
| #ifndef BASIC_FEATURES | ||||
| @ -34,6 +35,9 @@ | ||||
| #ifndef LL_ONLY | ||||
| #define LL_ONLY 0 | ||||
| #endif | ||||
| #ifndef LL_ONLY_BASIC | ||||
| #define LL_ONLY_BASIC 0 | ||||
| #endif | ||||
| #ifndef BEACON_ONLY | ||||
| #define BEACON_ONLY 0 | ||||
| #endif | ||||
|  | ||||
| @ -58,12 +58,6 @@ void ble_glue_init() { | ||||
|     ble_glue = malloc(sizeof(BleGlue)); | ||||
|     ble_glue->status = BleGlueStatusStartup; | ||||
| 
 | ||||
|     // Configure the system Power Mode
 | ||||
|     // Select HSI as system clock source after Wake Up from Stop mode
 | ||||
|     LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); | ||||
|     /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ | ||||
|     LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); | ||||
| 
 | ||||
| #ifdef BLE_GLUE_DEBUG | ||||
|     APPD_Init(); | ||||
| #endif | ||||
| @ -409,7 +403,9 @@ void shci_cmd_resp_release(uint32_t flag) { | ||||
| void shci_cmd_resp_wait(uint32_t timeout) { | ||||
|     UNUSED(timeout); | ||||
|     if(ble_glue) { | ||||
|         furi_hal_power_insomnia_enter(); | ||||
|         furi_semaphore_acquire(ble_glue->shci_sem, FuriWaitForever); | ||||
|         furi_hal_power_insomnia_exit(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|  ***************************************************************************** | ||||
|  * @attention | ||||
|  * | ||||
|  * Copyright (c) 2018-2022 STMicroelectronics. | ||||
|  * Copyright (c) 2018-2023 STMicroelectronics. | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * This software is licensed under terms that can be found in the LICENSE file | ||||
| @ -18,6 +18,14 @@ | ||||
| #ifndef COMPILER_H__ | ||||
| #define COMPILER_H__ | ||||
| 
 | ||||
| #ifndef __PACKED_STRUCT | ||||
| #define __PACKED_STRUCT PACKED(struct) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef __PACKED_UNION | ||||
| #define __PACKED_UNION PACKED(union) | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|   * @brief  This is the section dedicated to IAR toolchain | ||||
|   */ | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "gap.h" | ||||
| 
 | ||||
| #include "app_common.h" | ||||
| #include <ble/ble.h> | ||||
| 
 | ||||
| #include <furi_hal.h> | ||||
| @ -85,7 +86,7 @@ static void gap_verify_connection_parameters(Gap* gap) { | ||||
| SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|     hci_event_pckt* event_pckt; | ||||
|     evt_le_meta_event* meta_evt; | ||||
|     evt_blue_aci* blue_evt; | ||||
|     evt_blecore_aci* blue_evt; | ||||
|     hci_le_phy_update_complete_event_rp0* evt_le_phy_update_complete; | ||||
|     uint8_t tx_phy; | ||||
|     uint8_t rx_phy; | ||||
| @ -97,7 +98,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|         furi_mutex_acquire(gap->state_mutex, FuriWaitForever); | ||||
|     } | ||||
|     switch(event_pckt->evt) { | ||||
|     case EVT_DISCONN_COMPLETE: { | ||||
|     case HCI_DISCONNECTION_COMPLETE_EVT_CODE: { | ||||
|         hci_disconnection_complete_event_rp0* disconnection_complete_event = | ||||
|             (hci_disconnection_complete_event_rp0*)event_pckt->data; | ||||
|         if(disconnection_complete_event->Connection_Handle == gap->service.connection_handle) { | ||||
| @ -106,6 +107,8 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|             FURI_LOG_I( | ||||
|                 TAG, "Disconnect from client. Reason: %02X", disconnection_complete_event->Reason); | ||||
|         } | ||||
|         // Enterprise sleep
 | ||||
|         furi_delay_us(666 + 666); | ||||
|         if(gap->enable_adv) { | ||||
|             // Restart advertising
 | ||||
|             gap_advertise_start(GapStateAdvFast); | ||||
| @ -114,10 +117,10 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|         gap->on_event_cb(event, gap->context); | ||||
|     } break; | ||||
| 
 | ||||
|     case EVT_LE_META_EVENT: | ||||
|     case HCI_LE_META_EVT_CODE: | ||||
|         meta_evt = (evt_le_meta_event*)event_pckt->data; | ||||
|         switch(meta_evt->subevent) { | ||||
|         case EVT_LE_CONN_UPDATE_COMPLETE: { | ||||
|         case HCI_LE_CONNECTION_UPDATE_COMPLETE_SUBEVT_CODE: { | ||||
|             hci_le_connection_update_complete_event_rp0* event = | ||||
|                 (hci_le_connection_update_complete_event_rp0*)meta_evt->data; | ||||
|             gap->connection_params.conn_interval = event->Conn_Interval; | ||||
| @ -128,7 +131,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case EVT_LE_PHY_UPDATE_COMPLETE: | ||||
|         case HCI_LE_PHY_UPDATE_COMPLETE_SUBEVT_CODE: | ||||
|             evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; | ||||
|             if(evt_le_phy_update_complete->Status) { | ||||
|                 FURI_LOG_E( | ||||
| @ -144,7 +147,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_LE_CONN_COMPLETE: { | ||||
|         case HCI_LE_CONNECTION_COMPLETE_SUBEVT_CODE: { | ||||
|             hci_le_connection_complete_event_rp0* event = | ||||
|                 (hci_le_connection_complete_event_rp0*)meta_evt->data; | ||||
|             gap->connection_params.conn_interval = event->Conn_Interval; | ||||
| @ -168,16 +171,16 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|         } | ||||
|         break; | ||||
| 
 | ||||
|     case EVT_VENDOR: | ||||
|         blue_evt = (evt_blue_aci*)event_pckt->data; | ||||
|     case HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE: | ||||
|         blue_evt = (evt_blecore_aci*)event_pckt->data; | ||||
|         switch(blue_evt->ecode) { | ||||
|             aci_gap_pairing_complete_event_rp0* pairing_complete; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_LIMITED_DISCOVERABLE: | ||||
|         case ACI_GAP_LIMITED_DISCOVERABLE_VSEVT_CODE: | ||||
|             FURI_LOG_I(TAG, "Limited discoverable event"); | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_PASS_KEY_REQUEST: { | ||||
|         case ACI_GAP_PASS_KEY_REQ_VSEVT_CODE: { | ||||
|             // Generate random PIN code
 | ||||
|             uint32_t pin = rand() % 999999; //-V1064
 | ||||
|             aci_gap_pass_key_resp(gap->service.connection_handle, pin); | ||||
| @ -190,7 +193,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|             gap->on_event_cb(event, gap->context); | ||||
|         } break; | ||||
| 
 | ||||
|         case EVT_BLUE_ATT_EXCHANGE_MTU_RESP: { | ||||
|         case ACI_ATT_EXCHANGE_MTU_RESP_VSEVT_CODE: { | ||||
|             aci_att_exchange_mtu_resp_event_rp0* pr = (void*)blue_evt->data; | ||||
|             FURI_LOG_I(TAG, "Rx MTU size: %d", pr->Server_RX_MTU); | ||||
|             // Set maximum packet size given header size is 3 bytes
 | ||||
| @ -199,32 +202,28 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|             gap->on_event_cb(event, gap->context); | ||||
|         } break; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: | ||||
|         case ACI_GAP_AUTHORIZATION_REQ_VSEVT_CODE: | ||||
|             FURI_LOG_D(TAG, "Authorization request event"); | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: | ||||
|         case ACI_GAP_SLAVE_SECURITY_INITIATED_VSEVT_CODE: | ||||
|             FURI_LOG_D(TAG, "Slave security initiated"); | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_BOND_LOST: | ||||
|         case ACI_GAP_BOND_LOST_VSEVT_CODE: | ||||
|             FURI_LOG_D(TAG, "Bond lost event. Start rebonding"); | ||||
|             aci_gap_allow_rebond(gap->service.connection_handle); | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_DEVICE_FOUND: | ||||
|             FURI_LOG_D(TAG, "Device found event"); | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_ADDR_NOT_RESOLVED: | ||||
|         case ACI_GAP_ADDR_NOT_RESOLVED_VSEVT_CODE: | ||||
|             FURI_LOG_D(TAG, "Address not resolved event"); | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: | ||||
|         case ACI_GAP_KEYPRESS_NOTIFICATION_VSEVT_CODE: | ||||
|             FURI_LOG_D(TAG, "Key press notification event"); | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: { | ||||
|         case ACI_GAP_NUMERIC_COMPARISON_VALUE_VSEVT_CODE: { | ||||
|             uint32_t pin = | ||||
|                 ((aci_gap_numeric_comparison_value_event_rp0*)(blue_evt->data))->Numeric_Value; | ||||
|             FURI_LOG_I(TAG, "Verify numeric comparison: %06lu", pin); | ||||
| @ -234,7 +233,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_PAIRING_CMPLT: | ||||
|         case ACI_GAP_PAIRING_COMPLETE_VSEVT_CODE: | ||||
|             pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data; | ||||
|             if(pairing_complete->Status) { | ||||
|                 FURI_LOG_E( | ||||
| @ -249,11 +248,11 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_BLUE_GAP_PROCEDURE_COMPLETE: | ||||
|         case ACI_L2CAP_CONNECTION_UPDATE_RESP_VSEVT_CODE: | ||||
|             FURI_LOG_D(TAG, "Procedure complete event"); | ||||
|             break; | ||||
| 
 | ||||
|         case EVT_BLUE_L2CAP_CONNECTION_UPDATE_RESP: { | ||||
|         case ACI_L2CAP_CONNECTION_UPDATE_REQ_VSEVT_CODE: { | ||||
|             uint16_t result = | ||||
|                 ((aci_l2cap_connection_update_resp_event_rp0*)(blue_evt->data))->Result; | ||||
|             if(result == 0) { | ||||
| @ -289,8 +288,6 @@ static void gap_init_svc(Gap* gap) { | ||||
|     tBleStatus status; | ||||
|     uint32_t srd_bd_addr[2]; | ||||
| 
 | ||||
|     // HCI Reset to synchronise BLE Stack
 | ||||
|     hci_reset(); | ||||
|     // Configure mac address
 | ||||
|     aci_hal_write_config_data( | ||||
|         CONFIG_DATA_PUBADDR_OFFSET, CONFIG_DATA_PUBADDR_LEN, gap->config->mac_address); | ||||
| @ -364,7 +361,7 @@ static void gap_init_svc(Gap* gap) { | ||||
|         CFG_ENCRYPTION_KEY_SIZE_MAX, | ||||
|         CFG_USED_FIXED_PIN, | ||||
|         0, | ||||
|         PUBLIC_ADDR); | ||||
|         CFG_IDENTITY_ADDRESS); | ||||
|     // Configure whitelist
 | ||||
|     aci_gap_configure_whitelist(); | ||||
| } | ||||
| @ -399,7 +396,7 @@ static void gap_advertise_start(GapState new_state) { | ||||
|         ADV_IND, | ||||
|         min_interval, | ||||
|         max_interval, | ||||
|         PUBLIC_ADDR, | ||||
|         CFG_IDENTITY_ADDRESS, | ||||
|         0, | ||||
|         strlen(gap->service.adv_name), | ||||
|         (uint8_t*)gap->service.adv_name, | ||||
|  | ||||
| @ -84,9 +84,7 @@ void furi_hal_bt_init() { | ||||
|     } | ||||
| 
 | ||||
|     // Explicitly tell that we are in charge of CLK48 domain
 | ||||
|     if(!LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_CLK48_CONFIG_SEMID)) { | ||||
|     furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0); | ||||
|     } | ||||
| 
 | ||||
|     // Start Core2
 | ||||
|     ble_glue_init(); | ||||
| @ -129,9 +127,7 @@ bool furi_hal_bt_start_radio_stack() { | ||||
|     furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever); | ||||
| 
 | ||||
|     // Explicitly tell that we are in charge of CLK48 domain
 | ||||
|     if(!LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_CLK48_CONFIG_SEMID)) { | ||||
|     furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0); | ||||
|     } | ||||
| 
 | ||||
|     do { | ||||
|         // Wait until C2 is started or timeout
 | ||||
|  | ||||
| @ -63,6 +63,10 @@ void furi_hal_clock_init() { | ||||
|     LL_RCC_HSI_Enable(); | ||||
|     while(!HS_CLOCK_IS_READY()) | ||||
|         ; | ||||
|     /* Select HSI as system clock source after Wake Up from Stop mode
 | ||||
|      * Must be set before enabling CSS */ | ||||
|     LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); | ||||
| 
 | ||||
|     LL_RCC_HSE_EnableCSS(); | ||||
| 
 | ||||
|     /* LSE and LSI1 configuration and activation */ | ||||
| @ -140,6 +144,7 @@ void furi_hal_clock_init() { | ||||
|     LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); | ||||
|     LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); | ||||
|     LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1); | ||||
|     LL_RCC_HSI_EnableInStopMode(); // Ensure that MR is capable of work in STOP0
 | ||||
|     LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); | ||||
|     LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); | ||||
|     LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); | ||||
| @ -203,25 +208,36 @@ void furi_hal_clock_switch_to_hsi() { | ||||
|     while(!LL_RCC_HSI_IsReady()) | ||||
|         ; | ||||
| 
 | ||||
|     LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI); | ||||
|     LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI); | ||||
|     LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI); | ||||
| 
 | ||||
|     while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) | ||||
|         ; | ||||
| 
 | ||||
|     LL_FLASH_SetLatency(LL_FLASH_LATENCY_1); | ||||
|     LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); | ||||
| 
 | ||||
|     LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); | ||||
|     while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0) | ||||
|         ; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_clock_switch_to_pll() { | ||||
|     LL_RCC_HSE_Enable(); | ||||
|     LL_RCC_PLL_Enable(); | ||||
|     LL_RCC_PLLSAI1_Enable(); | ||||
| 
 | ||||
|     while(!LL_RCC_HSE_IsReady()) | ||||
|         ; | ||||
|     while(!LL_RCC_PLL_IsReady()) | ||||
|         ; | ||||
|     while(!LL_RCC_PLLSAI1_IsReady()) | ||||
|         ; | ||||
| 
 | ||||
|     LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); | ||||
| 
 | ||||
|     LL_FLASH_SetLatency(LL_FLASH_LATENCY_3); | ||||
|     while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3) | ||||
|         ; | ||||
| 
 | ||||
|     LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); | ||||
|     LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); | ||||
|  | ||||
| @ -3,12 +3,26 @@ | ||||
| #include <stm32wbxx_ll_exti.h> | ||||
| #include <stm32wbxx_ll_system.h> | ||||
| 
 | ||||
| #include <furi_hal_gpio.h> | ||||
| #include <furi_hal_resources.h> | ||||
| 
 | ||||
| volatile bool furi_hal_debug_gdb_session_active = false; | ||||
| 
 | ||||
| void furi_hal_debug_enable() { | ||||
|     // Low power mode debug
 | ||||
|     LL_DBGMCU_EnableDBGSleepMode(); | ||||
|     LL_DBGMCU_EnableDBGStopMode(); | ||||
|     LL_DBGMCU_EnableDBGStandbyMode(); | ||||
|     LL_EXTI_EnableIT_32_63(LL_EXTI_LINE_48); | ||||
|     // SWD GPIO
 | ||||
|     furi_hal_gpio_init_ex( | ||||
|         &gpio_swdio, | ||||
|         GpioModeAltFunctionPushPull, | ||||
|         GpioPullUp, | ||||
|         GpioSpeedVeryHigh, | ||||
|         GpioAltFn0JTMS_SWDIO); | ||||
|     furi_hal_gpio_init_ex( | ||||
|         &gpio_swclk, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn0JTCK_SWCLK); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_debug_disable() { | ||||
| @ -17,4 +31,11 @@ void furi_hal_debug_disable() { | ||||
|     LL_DBGMCU_DisableDBGStopMode(); | ||||
|     LL_DBGMCU_DisableDBGStandbyMode(); | ||||
|     LL_EXTI_DisableIT_32_63(LL_EXTI_LINE_48); | ||||
|     // SWD GPIO
 | ||||
|     furi_hal_gpio_init_simple(&gpio_swdio, GpioModeAnalog); | ||||
|     furi_hal_gpio_init_simple(&gpio_swclk, GpioModeAnalog); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_debug_is_gdb_session_active() { | ||||
|     return furi_hal_debug_gdb_session_active; | ||||
| } | ||||
| @ -1,5 +1,7 @@ | ||||
| #include <furi_hal_flash.h> | ||||
| #include <furi_hal_bt.h> | ||||
| #include <furi_hal_power.h> | ||||
| #include <furi_hal_cortex.h> | ||||
| #include <furi.h> | ||||
| #include <ble/ble.h> | ||||
| #include <interface/patterns/ble_thread/shci/shci.h> | ||||
| @ -25,6 +27,16 @@ | ||||
| #define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F | ||||
| #define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2)) | ||||
| 
 | ||||
| /* lib/STM32CubeWB/Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_RfWithFlash/Core/Src/flash_driver.c
 | ||||
|  * ProcessSingleFlashOperation, quote: | ||||
|   > In most BLE application, the flash should not be blocked by the CPU2 longer than FLASH_TIMEOUT_VALUE (1000ms) | ||||
|   > However, it could be that for some marginal application, this time is longer. | ||||
|   > ... there is no other way than waiting the operation to be completed. | ||||
|   > If for any reason this test is never passed, this means there is a failure in the system and there is no other | ||||
|   > way to recover than applying a device reset.  | ||||
|  */ | ||||
| #define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS 3000u /* 3 seconds */ | ||||
| 
 | ||||
| #define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL)) | ||||
| #define IS_FLASH_PROGRAM_ADDRESS(__VALUE__)                                             \ | ||||
|     (((__VALUE__) >= FLASH_BASE) && ((__VALUE__) <= (FLASH_BASE + FLASH_SIZE - 8UL)) && \ | ||||
| @ -114,6 +126,7 @@ static void furi_hal_flash_lock(void) { | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_flash_begin_with_core2(bool erase_flag) { | ||||
|     furi_hal_power_insomnia_enter(); | ||||
|     /* Take flash controller ownership */ | ||||
|     while(LL_HSEM_1StepLock(HSEM, CFG_HW_FLASH_SEMID) != 0) { | ||||
|         furi_thread_yield(); | ||||
| @ -129,9 +142,11 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) { | ||||
|     for(volatile uint32_t i = 0; i < 35; i++) | ||||
|         ; | ||||
| 
 | ||||
|     FuriHalCortexTimer timer = furi_hal_cortex_timer_get(FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS * 1000); | ||||
|     while(true) { | ||||
|         /* Wait till flash controller become usable */ | ||||
|         while(LL_FLASH_IsActiveFlag_OperationSuspended()) { | ||||
|             furi_check(!furi_hal_cortex_timer_is_expired(timer)); | ||||
|             furi_thread_yield(); | ||||
|         }; | ||||
| 
 | ||||
| @ -141,6 +156,7 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) { | ||||
|         /* Actually we already have mutex for it, but specification is specification  */ | ||||
|         if(LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) { | ||||
|             taskEXIT_CRITICAL(); | ||||
|             furi_check(!furi_hal_cortex_timer_is_expired(timer)); | ||||
|             furi_thread_yield(); | ||||
|             continue; | ||||
|         } | ||||
| @ -148,6 +164,7 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) { | ||||
|         /* Take sempahopre and prevent core2 from anything funky */ | ||||
|         if(LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != 0) { | ||||
|             taskEXIT_CRITICAL(); | ||||
|             furi_check(!furi_hal_cortex_timer_is_expired(timer)); | ||||
|             furi_thread_yield(); | ||||
|             continue; | ||||
|         } | ||||
| @ -188,6 +205,7 @@ static void furi_hal_flash_end_with_core2(bool erase_flag) { | ||||
| 
 | ||||
|     /* Release flash controller ownership */ | ||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_FLASH_SEMID, 0); | ||||
|     furi_hal_power_insomnia_exit(); | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_flash_end(bool erase_flag) { | ||||
| @ -228,17 +246,13 @@ static void furi_hal_flush_cache(void) { | ||||
| 
 | ||||
| bool furi_hal_flash_wait_last_operation(uint32_t timeout) { | ||||
|     uint32_t error = 0; | ||||
|     uint32_t countdown = 0; | ||||
| 
 | ||||
|     /* Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
 | ||||
|        Even if the FLASH operation fails, the BUSY flag will be reset and an error | ||||
|        flag will be set */ | ||||
|     countdown = timeout; | ||||
|     FuriHalCortexTimer timer = furi_hal_cortex_timer_get(timeout * 1000); | ||||
|     while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) { | ||||
|         if(LL_SYSTICK_IsActiveCounterFlag()) { | ||||
|             countdown--; | ||||
|         } | ||||
|         if(countdown == 0) { | ||||
|         if(furi_hal_cortex_timer_is_expired(timer)) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| @ -261,12 +275,9 @@ bool furi_hal_flash_wait_last_operation(uint32_t timeout) { | ||||
|     CLEAR_BIT(FLASH->SR, error); | ||||
| 
 | ||||
|     /* Wait for control register to be written */ | ||||
|     countdown = timeout; | ||||
|     timer = furi_hal_cortex_timer_get(timeout * 1000); | ||||
|     while(READ_BIT(FLASH->SR, FLASH_SR_CFGBSY)) { | ||||
|         if(LL_SYSTICK_IsActiveCounterFlag()) { | ||||
|             countdown--; | ||||
|         } | ||||
|         if(countdown == 0) { | ||||
|         if(furi_hal_cortex_timer_is_expired(timer)) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -28,11 +28,24 @@ | ||||
| // Arbitrary (but small) number for better tick consistency
 | ||||
| #define FURI_HAL_OS_EXTRA_CNT 3 | ||||
| 
 | ||||
| #ifndef FURI_HAL_OS_DEBUG_AWAKE_GPIO | ||||
| #define FURI_HAL_OS_DEBUG_AWAKE_GPIO (&gpio_ext_pa7) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FURI_HAL_OS_DEBUG_TICK_GPIO | ||||
| #define FURI_HAL_OS_DEBUG_TICK_GPIO (&gpio_ext_pa6) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FURI_HAL_OS_DEBUG_SECOND_GPIO | ||||
| #define FURI_HAL_OS_DEBUG_SECOND_GPIO (&gpio_ext_pa4) | ||||
| #endif | ||||
| 
 | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| 
 | ||||
| void furi_hal_os_timer_callback() { | ||||
|     furi_hal_gpio_write(&gpio_ext_pa4, !furi_hal_gpio_read(&gpio_ext_pa4)); | ||||
|     furi_hal_gpio_write( | ||||
|         FURI_HAL_OS_DEBUG_SECOND_GPIO, !furi_hal_gpio_read(FURI_HAL_OS_DEBUG_SECOND_GPIO)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| @ -44,9 +57,11 @@ void furi_hal_os_init() { | ||||
|     furi_hal_idle_timer_init(); | ||||
| 
 | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
|     furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); | ||||
|     furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull); | ||||
|     furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull); | ||||
|     furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_AWAKE_GPIO, GpioModeOutputPushPull); | ||||
|     furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_TICK_GPIO, GpioModeOutputPushPull); | ||||
|     furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_SECOND_GPIO, GpioModeOutputPushPull); | ||||
|     furi_hal_gpio_write(FURI_HAL_OS_DEBUG_AWAKE_GPIO, 1); | ||||
| 
 | ||||
|     FuriTimer* second_timer = | ||||
|         furi_timer_alloc(furi_hal_os_timer_callback, FuriTimerTypePeriodic, NULL); | ||||
|     furi_timer_start(second_timer, FURI_HAL_OS_TICK_HZ); | ||||
| @ -58,7 +73,8 @@ void furi_hal_os_init() { | ||||
| void furi_hal_os_tick() { | ||||
|     if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
|         furi_hal_gpio_write(&gpio_ext_pa6, !furi_hal_gpio_read(&gpio_ext_pa6)); | ||||
|         furi_hal_gpio_write( | ||||
|             FURI_HAL_OS_DEBUG_TICK_GPIO, !furi_hal_gpio_read(FURI_HAL_OS_DEBUG_TICK_GPIO)); | ||||
| #endif | ||||
|         xPortSysTickHandler(); | ||||
|     } | ||||
| @ -121,14 +137,14 @@ static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) { | ||||
|     furi_hal_idle_timer_start(FURI_HAL_OS_TICKS_TO_IDLE_CNT(expected_idle_ticks)); | ||||
| 
 | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
|     furi_hal_gpio_write(&gpio_ext_pa7, 0); | ||||
|     furi_hal_gpio_write(FURI_HAL_OS_DEBUG_AWAKE_GPIO, 0); | ||||
| #endif | ||||
| 
 | ||||
|     // Go to sleep mode
 | ||||
|     furi_hal_power_sleep(); | ||||
| 
 | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
|     furi_hal_gpio_write(&gpio_ext_pa7, 1); | ||||
|     furi_hal_gpio_write(FURI_HAL_OS_DEBUG_AWAKE_GPIO, 1); | ||||
| #endif | ||||
| 
 | ||||
|     // Calculate how much time we spent in the sleep
 | ||||
|  | ||||
| @ -4,6 +4,8 @@ | ||||
| #include <furi_hal_vibro.h> | ||||
| #include <furi_hal_resources.h> | ||||
| #include <furi_hal_uart.h> | ||||
| #include <furi_hal_rtc.h> | ||||
| #include <furi_hal_debug.h> | ||||
| 
 | ||||
| #include <stm32wbxx_ll_rcc.h> | ||||
| #include <stm32wbxx_ll_pwr.h> | ||||
| @ -19,15 +21,20 @@ | ||||
| 
 | ||||
| #define TAG "FuriHalPower" | ||||
| 
 | ||||
| #ifdef FURI_HAL_POWER_DEEP_SLEEP_ENABLED | ||||
| #define FURI_HAL_POWER_DEEP_INSOMNIA 0 | ||||
| #else | ||||
| #define FURI_HAL_POWER_DEEP_INSOMNIA 1 | ||||
| #ifndef FURI_HAL_POWER_DEBUG_WFI_GPIO | ||||
| #define FURI_HAL_POWER_DEBUG_WFI_GPIO (&gpio_ext_pb2) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FURI_HAL_POWER_DEBUG_STOP_GPIO | ||||
| #define FURI_HAL_POWER_DEBUG_STOP_GPIO (&gpio_ext_pc3) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FURI_HAL_POWER_STOP_MODE | ||||
| #define FURI_HAL_POWER_STOP_MODE (LL_PWR_MODE_STOP2) | ||||
| #endif | ||||
| 
 | ||||
| typedef struct { | ||||
|     volatile uint8_t insomnia; | ||||
|     volatile uint8_t deep_insomnia; | ||||
|     volatile uint8_t suppress_charge; | ||||
| 
 | ||||
|     uint8_t gauge_initialized; | ||||
| @ -36,7 +43,6 @@ typedef struct { | ||||
| 
 | ||||
| static volatile FuriHalPower furi_hal_power = { | ||||
|     .insomnia = 0, | ||||
|     .deep_insomnia = FURI_HAL_POWER_DEEP_INSOMNIA, | ||||
|     .suppress_charge = 0, | ||||
| }; | ||||
| 
 | ||||
| @ -79,19 +85,24 @@ const ParamCEDV cedv = { | ||||
| }; | ||||
| 
 | ||||
| void furi_hal_power_init() { | ||||
| #ifdef FURI_HAL_POWER_DEBUG | ||||
|     furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_WFI_GPIO, GpioModeOutputPushPull); | ||||
|     furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_STOP_GPIO, GpioModeOutputPushPull); | ||||
|     furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 0); | ||||
|     furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 0); | ||||
| #endif | ||||
| 
 | ||||
|     LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); | ||||
|     LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN); | ||||
| 
 | ||||
|     LL_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE); | ||||
|     LL_C2_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE); | ||||
| 
 | ||||
|     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||
|     bq27220_init(&furi_hal_i2c_handle_power, &cedv); | ||||
|     bq25896_init(&furi_hal_i2c_handle_power); | ||||
|     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||
| 
 | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
|     furi_hal_gpio_init_simple(&gpio_ext_pb2, GpioModeOutputPushPull); | ||||
|     furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeOutputPushPull); | ||||
| #endif | ||||
| 
 | ||||
|     FURI_LOG_I(TAG, "Init OK"); | ||||
| } | ||||
| 
 | ||||
| @ -140,11 +151,12 @@ bool furi_hal_power_sleep_available() { | ||||
|     return furi_hal_power.insomnia == 0; | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_power_deep_sleep_available() { | ||||
|     return furi_hal_bt_is_alive() && furi_hal_power.deep_insomnia == 0; | ||||
| static inline bool furi_hal_power_deep_sleep_available() { | ||||
|     return furi_hal_bt_is_alive() && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagLegacySleep) && | ||||
|            !furi_hal_debug_is_gdb_session_active(); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_power_light_sleep() { | ||||
| static inline void furi_hal_power_light_sleep() { | ||||
|     __WFI(); | ||||
| } | ||||
| 
 | ||||
| @ -152,17 +164,15 @@ static inline void furi_hal_power_suspend_aux_periphs() { | ||||
|     // Disable USART
 | ||||
|     furi_hal_uart_suspend(FuriHalUartIdUSART1); | ||||
|     furi_hal_uart_suspend(FuriHalUartIdLPUART1); | ||||
|     // TODO: Disable USB
 | ||||
| } | ||||
| 
 | ||||
| static inline void furi_hal_power_resume_aux_periphs() { | ||||
|     // Re-enable USART
 | ||||
|     furi_hal_uart_resume(FuriHalUartIdUSART1); | ||||
|     furi_hal_uart_resume(FuriHalUartIdLPUART1); | ||||
|     // TODO: Re-enable USB
 | ||||
| } | ||||
| 
 | ||||
| void furi_hal_power_deep_sleep() { | ||||
| static inline void furi_hal_power_deep_sleep() { | ||||
|     furi_hal_power_suspend_aux_periphs(); | ||||
| 
 | ||||
|     while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) | ||||
| @ -187,8 +197,6 @@ void furi_hal_power_deep_sleep() { | ||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); | ||||
| 
 | ||||
|     // Prepare deep sleep
 | ||||
|     LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2); | ||||
|     LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2); | ||||
|     LL_LPM_EnableDeepSleep(); | ||||
| 
 | ||||
| #if defined(__CC_ARM) | ||||
| @ -200,13 +208,6 @@ void furi_hal_power_deep_sleep() { | ||||
| 
 | ||||
|     LL_LPM_EnableSleep(); | ||||
| 
 | ||||
|     // Make sure that values differ to prevent disaster on wfi
 | ||||
|     LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0); | ||||
|     LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); | ||||
| 
 | ||||
|     LL_PWR_ClearFlag_C1STOP_C1STB(); | ||||
|     LL_PWR_ClearFlag_C2STOP_C2STB(); | ||||
| 
 | ||||
|     /* Release ENTRY_STOP_MODE semaphore */ | ||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0); | ||||
| 
 | ||||
| @ -220,28 +221,25 @@ void furi_hal_power_deep_sleep() { | ||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); | ||||
| 
 | ||||
|     furi_hal_power_resume_aux_periphs(); | ||||
|     furi_hal_rtc_sync_shadow(); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_power_sleep() { | ||||
|     if(furi_hal_power_deep_sleep_available()) { | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
|         furi_hal_gpio_write(&gpio_ext_pc3, 1); | ||||
| #ifdef FURI_HAL_POWER_DEBUG | ||||
|         furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 1); | ||||
| #endif | ||||
| 
 | ||||
|         furi_hal_power_deep_sleep(); | ||||
| 
 | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
|         furi_hal_gpio_write(&gpio_ext_pc3, 0); | ||||
| #ifdef FURI_HAL_POWER_DEBUG | ||||
|         furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 0); | ||||
| #endif | ||||
|     } else { | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
|         furi_hal_gpio_write(&gpio_ext_pb2, 1); | ||||
| #ifdef FURI_HAL_POWER_DEBUG | ||||
|         furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 1); | ||||
| #endif | ||||
| 
 | ||||
|         furi_hal_power_light_sleep(); | ||||
| 
 | ||||
| #ifdef FURI_HAL_OS_DEBUG | ||||
|         furi_hal_gpio_write(&gpio_ext_pb2, 0); | ||||
| #ifdef FURI_HAL_POWER_DEBUG | ||||
|         furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 0); | ||||
| #endif | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -9,19 +9,35 @@ | ||||
| 
 | ||||
| #define TAG "FuriHalRandom" | ||||
| 
 | ||||
| static uint32_t furi_hal_random_read_rng() { | ||||
|     while(LL_RNG_IsActiveFlag_CECS(RNG) && LL_RNG_IsActiveFlag_SECS(RNG) && | ||||
|           !LL_RNG_IsActiveFlag_DRDY(RNG)) { | ||||
|         /* Error handling as described in RM0434, pg. 582-583 */ | ||||
|         if(LL_RNG_IsActiveFlag_CECS(RNG)) { | ||||
|             /* Clock error occurred */ | ||||
|             LL_RNG_ClearFlag_CEIS(RNG); | ||||
|         } | ||||
| 
 | ||||
|         if(LL_RNG_IsActiveFlag_SECS(RNG)) { | ||||
|             /* Noise source error occurred */ | ||||
|             LL_RNG_ClearFlag_SEIS(RNG); | ||||
| 
 | ||||
|             for(uint32_t i = 0; i < 12; ++i) { | ||||
|                 const volatile uint32_t discard = LL_RNG_ReadRandData32(RNG); | ||||
|                 UNUSED(discard); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return LL_RNG_ReadRandData32(RNG); | ||||
| } | ||||
| 
 | ||||
| uint32_t furi_hal_random_get() { | ||||
|     while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)) | ||||
|         ; | ||||
|     LL_RNG_Enable(RNG); | ||||
| 
 | ||||
|     while(!LL_RNG_IsActiveFlag_DRDY(RNG)) | ||||
|         ; | ||||
| 
 | ||||
|     if((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { | ||||
|         furi_crash("TRNG error"); | ||||
|     } | ||||
| 
 | ||||
|     uint32_t random_val = LL_RNG_ReadRandData32(RNG); | ||||
|     const uint32_t random_val = furi_hal_random_read_rng(); | ||||
| 
 | ||||
|     LL_RNG_Disable(RNG); | ||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); | ||||
| @ -35,15 +51,7 @@ void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) { | ||||
|     LL_RNG_Enable(RNG); | ||||
| 
 | ||||
|     for(uint32_t i = 0; i < len; i += 4) { | ||||
|         while(!LL_RNG_IsActiveFlag_DRDY(RNG)) | ||||
|             ; | ||||
| 
 | ||||
|         if((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { | ||||
|             furi_crash("TRNG error"); | ||||
|         } | ||||
| 
 | ||||
|         uint32_t random_val = LL_RNG_ReadRandData32(RNG); | ||||
| 
 | ||||
|         const uint32_t random_val = furi_hal_random_read_rng(); | ||||
|         uint8_t len_cur = ((i + 4) < len) ? (4) : (len - i); | ||||
|         memcpy(&buf[i], &random_val, len_cur); | ||||
|     } | ||||
|  | ||||
| @ -6,6 +6,9 @@ | ||||
| 
 | ||||
| #define TAG "FuriHalResources" | ||||
| 
 | ||||
| const GpioPin gpio_swdio = {.port = GPIOA, .pin = LL_GPIO_PIN_13}; | ||||
| const GpioPin gpio_swclk = {.port = GPIOA, .pin = LL_GPIO_PIN_14}; | ||||
| 
 | ||||
| const GpioPin gpio_vibro = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin}; | ||||
| const GpioPin gpio_ibutton = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin}; | ||||
| 
 | ||||
| @ -153,10 +156,11 @@ void furi_hal_resources_init() { | ||||
|     // Button pins
 | ||||
|     furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall); | ||||
| 
 | ||||
|     // Explicit pulls pins
 | ||||
|     furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow); | ||||
|     furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow); | ||||
|     furi_hal_gpio_init(&gpio_vibro, GpioModeAnalog, GpioPullDown, GpioSpeedLow); | ||||
|     // Explicit, surviving reset, pulls
 | ||||
|     LL_PWR_EnablePUPDCfg(); | ||||
|     LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_9); // gpio_infrared_tx
 | ||||
|     LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_8); // gpio_speaker
 | ||||
|     LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_A, LL_PWR_GPIO_BIT_8); // gpio_vibro
 | ||||
| 
 | ||||
|     // Display pins
 | ||||
|     furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||
|  | ||||
| @ -50,6 +50,9 @@ extern const size_t input_pins_count; | ||||
| extern const GpioPinRecord gpio_pins[]; | ||||
| extern const size_t gpio_pins_count; | ||||
| 
 | ||||
| extern const GpioPin gpio_swdio; | ||||
| extern const GpioPin gpio_swclk; | ||||
| 
 | ||||
| extern const GpioPin gpio_vibro; | ||||
| extern const GpioPin gpio_ibutton; | ||||
| 
 | ||||
|  | ||||
| @ -165,6 +165,14 @@ void furi_hal_rtc_init() { | ||||
|     FURI_LOG_I(TAG, "Init OK"); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_rtc_sync_shadow() { | ||||
|     if(!LL_RTC_IsShadowRegBypassEnabled(RTC)) { | ||||
|         LL_RTC_ClearFlag_RS(RTC); | ||||
|         while(!LL_RTC_IsActiveFlag_RS(RTC)) { | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg) { | ||||
|     return LL_RTC_BAK_GetRegister(RTC, reg); | ||||
| } | ||||
| @ -312,12 +320,7 @@ void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) { | ||||
|     /* Exit Initialization mode */ | ||||
|     LL_RTC_DisableInitMode(RTC); | ||||
| 
 | ||||
|     /* If RTC_CR_BYPSHAD bit = 0, wait for synchro else this check is not needed */ | ||||
|     if(!LL_RTC_IsShadowRegBypassEnabled(RTC)) { | ||||
|         LL_RTC_ClearFlag_RS(RTC); | ||||
|         while(!LL_RTC_IsActiveFlag_RS(RTC)) { | ||||
|         }; | ||||
|     } | ||||
|     furi_hal_rtc_sync_shadow(); | ||||
| 
 | ||||
|     /* Enable write protection */ | ||||
|     LL_RTC_EnableWriteProtection(RTC); | ||||
|  | ||||
| @ -29,6 +29,8 @@ int main() { | ||||
|     FuriThread* main_thread = furi_thread_alloc_ex("Init", 4096, init_task, NULL); | ||||
| 
 | ||||
| #ifdef FURI_RAM_EXEC | ||||
|     // Prevent entering sleep mode when executed from RAM
 | ||||
|     furi_hal_power_insomnia_enter(); | ||||
|     furi_thread_start(main_thread); | ||||
| #else | ||||
|     furi_hal_light_sequence("RGB"); | ||||
| @ -44,6 +46,7 @@ int main() { | ||||
|         furi_hal_power_reset(); | ||||
|     } else if(boot_mode == FuriHalRtcBootModeUpdate) { | ||||
|         furi_hal_light_sequence("rgb BR"); | ||||
|         // Do update
 | ||||
|         flipper_boot_update_exec(); | ||||
|         // if things go nice, we shouldn't reach this point.
 | ||||
|         // But if we do, abandon to avoid bootloops
 | ||||
|  | ||||
| @ -18,6 +18,9 @@ void furi_hal_debug_enable(); | ||||
| /** Disable MCU debug */ | ||||
| void furi_hal_debug_disable(); | ||||
| 
 | ||||
| /** Check if GDB debug session is active */ | ||||
| bool furi_hal_debug_is_gdb_session_active(); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -58,12 +58,6 @@ void furi_hal_power_insomnia_exit(); | ||||
|  */ | ||||
| bool furi_hal_power_sleep_available(); | ||||
| 
 | ||||
| /** Check if deep sleep availble
 | ||||
|  * | ||||
|  * @return     true if available | ||||
|  */ | ||||
| bool furi_hal_power_deep_sleep_available(); | ||||
| 
 | ||||
| /** Go to sleep
 | ||||
|  */ | ||||
| void furi_hal_power_sleep(); | ||||
|  | ||||
| @ -30,6 +30,8 @@ typedef enum { | ||||
|     FuriHalRtcFlagLock = (1 << 2), | ||||
|     FuriHalRtcFlagC2Update = (1 << 3), | ||||
|     FuriHalRtcFlagHandOrient = (1 << 4), | ||||
|     FuriHalRtcFlagLegacySleep = (1 << 5), | ||||
|     FuriHalRtcFlagStealthMode = (1 << 6), | ||||
| } FuriHalRtcFlag; | ||||
| 
 | ||||
| typedef enum { | ||||
| @ -85,6 +87,9 @@ void furi_hal_rtc_deinit_early(); | ||||
| /** Initialize RTC subsystem */ | ||||
| void furi_hal_rtc_init(); | ||||
| 
 | ||||
| /** Force sync shadow registers */ | ||||
| void furi_hal_rtc_sync_shadow(); | ||||
| 
 | ||||
| /** Get RTC register content
 | ||||
|  * | ||||
|  * @param[in]  reg   The register identifier | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include <furi_hal_console.h> | ||||
| #include <furi_hal_power.h> | ||||
| #include <furi_hal_rtc.h> | ||||
| #include <furi_hal_debug.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include <FreeRTOS.h> | ||||
| @ -13,7 +14,7 @@ | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| PLACE_IN_SECTION("MB_MEM2") const char* __furi_check_message = NULL; | ||||
| PLACE_IN_SECTION("MB_MEM2") uint32_t __furi_check_registers[12] = {0}; | ||||
| PLACE_IN_SECTION("MB_MEM2") uint32_t __furi_check_registers[13] = {0}; | ||||
| 
 | ||||
| /** Load r12 value to __furi_check_message and store registers to __furi_check_registers */ | ||||
| #define GET_MESSAGE_AND_STORE_REGISTERS()               \ | ||||
| @ -21,6 +22,7 @@ PLACE_IN_SECTION("MB_MEM2") uint32_t __furi_check_registers[12] = {0}; | ||||
|                  "str r12, [r11]                    \n" \ | ||||
|                  "ldr r12, =__furi_check_registers  \n" \ | ||||
|                  "stm r12, {r0-r11}                 \n" \ | ||||
|                  "str lr, [r12, #48]                \n" \ | ||||
|                  :                                      \ | ||||
|                  :                                      \ | ||||
|                  : "memory"); | ||||
| @ -61,6 +63,25 @@ static void __furi_put_uint32_as_text(uint32_t data) { | ||||
|     furi_hal_console_puts(tmp_str); | ||||
| } | ||||
| 
 | ||||
| static void __furi_put_uint32_as_hex(uint32_t data) { | ||||
|     char tmp_str[] = "0xFFFFFFFF"; | ||||
|     itoa(data, tmp_str, 16); | ||||
|     furi_hal_console_puts(tmp_str); | ||||
| } | ||||
| 
 | ||||
| static void __furi_print_register_info() { | ||||
|     // Print registers
 | ||||
|     for(uint8_t i = 0; i < 12; i++) { | ||||
|         furi_hal_console_puts("\r\n\tr"); | ||||
|         __furi_put_uint32_as_text(i); | ||||
|         furi_hal_console_puts(" : "); | ||||
|         __furi_put_uint32_as_hex(__furi_check_registers[i]); | ||||
|     } | ||||
| 
 | ||||
|     furi_hal_console_puts("\r\n\tlr : "); | ||||
|     __furi_put_uint32_as_hex(__furi_check_registers[12]); | ||||
| } | ||||
| 
 | ||||
| static void __furi_print_stack_info() { | ||||
|     furi_hal_console_puts("\r\n\tstack watermark: "); | ||||
|     __furi_put_uint32_as_text(uxTaskGetStackHighWaterMark(NULL) * 4); | ||||
| @ -100,30 +121,41 @@ FURI_NORETURN void __furi_crash() { | ||||
| 
 | ||||
|     if(__furi_check_message == NULL) { | ||||
|         __furi_check_message = "Fatal Error"; | ||||
|     } else if(__furi_check_message == (void*)__FURI_ASSERT_MESSAGE_FLAG) { | ||||
|         __furi_check_message = "furi_assert failed"; | ||||
|     } else if(__furi_check_message == (void*)__FURI_CHECK_MESSAGE_FLAG) { | ||||
|         __furi_check_message = "furi_check failed"; | ||||
|     } | ||||
| 
 | ||||
|     furi_hal_console_puts("\r\n\033[0;31m[CRASH]"); | ||||
|     __furi_print_name(isr); | ||||
|     furi_hal_console_puts(__furi_check_message); | ||||
| 
 | ||||
|     __furi_print_register_info(); | ||||
|     if(!isr) { | ||||
|         __furi_print_stack_info(); | ||||
|     } | ||||
|     __furi_print_heap_info(); | ||||
| 
 | ||||
| #ifndef FURI_DEBUG | ||||
|     // Check if debug enabled by DAP
 | ||||
|     // https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/Debug-register-support-in-the-SCS/Debug-Halting-Control-and-Status-Register--DHCSR?lang=en
 | ||||
|     bool debug = CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk; | ||||
|     if(debug) { | ||||
| #endif | ||||
|         furi_hal_console_puts("\r\nSystem halted. Connect debugger for more info\r\n"); | ||||
|         furi_hal_console_puts("\033[0m\r\n"); | ||||
|         furi_hal_debug_enable(); | ||||
| 
 | ||||
|         RESTORE_REGISTERS_AND_HALT_MCU(true); | ||||
| #ifndef FURI_DEBUG | ||||
|     } else { | ||||
|         furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message); | ||||
|         furi_hal_console_puts("\r\nRebooting system.\r\n"); | ||||
|         furi_hal_console_puts("\033[0m\r\n"); | ||||
|         furi_hal_power_reset(); | ||||
|     } | ||||
| #endif | ||||
|     __builtin_unreachable(); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -21,6 +21,10 @@ extern "C" { | ||||
| #define FURI_NORETURN noreturn | ||||
| #endif | ||||
| 
 | ||||
| // Flags instead of pointers will save ~4 bytes on furi_assert and furi_check calls.
 | ||||
| #define __FURI_ASSERT_MESSAGE_FLAG (0x01) | ||||
| #define __FURI_CHECK_MESSAGE_FLAG (0x02) | ||||
| 
 | ||||
| /** Crash system */ | ||||
| FURI_NORETURN void __furi_crash(); | ||||
| 
 | ||||
| @ -47,7 +51,7 @@ FURI_NORETURN void __furi_halt(); | ||||
| #define furi_check(__e)                            \ | ||||
|     do {                                           \ | ||||
|         if(!(__e)) {                               \ | ||||
|             furi_crash("furi_check failed\r\n"); \ | ||||
|             furi_crash(__FURI_CHECK_MESSAGE_FLAG); \ | ||||
|         }                                          \ | ||||
|     } while(0) | ||||
| 
 | ||||
| @ -56,7 +60,7 @@ FURI_NORETURN void __furi_halt(); | ||||
| #define furi_assert(__e)                            \ | ||||
|     do {                                            \ | ||||
|         if(!(__e)) {                                \ | ||||
|             furi_crash("furi_assert failed\r\n"); \ | ||||
|             furi_crash(__FURI_ASSERT_MESSAGE_FLAG); \ | ||||
|         }                                           \ | ||||
|     } while(0) | ||||
| #else | ||||
|  | ||||
| @ -24,6 +24,10 @@ extern "C" { | ||||
|     }) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef ABS | ||||
| #define ABS(a) ({ (a) < 0 ? -(a) : (a); }) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef ROUND_UP_TO | ||||
| #define ROUND_UP_TO(a, b)       \ | ||||
|     ({                          \ | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit a9e29b431f6dac95b6fc860a717834f35b7f78e5 | ||||
| Subproject commit c4cec8ae57a79e949a184cd0b4117a008a0a25a7 | ||||
| @ -112,6 +112,8 @@ def DistCommand(env, name, source, **kw): | ||||
| 
 | ||||
| 
 | ||||
| def generate(env): | ||||
|     if not env["VERBOSE"]: | ||||
|         env.SetDefault(COPROCOMSTR="\tCOPRO\t${TARGET}") | ||||
|     env.AddMethod(AddFwProject) | ||||
|     env.AddMethod(DistCommand) | ||||
|     env.AddMethod(AddOpenOCDFlashTarget) | ||||
| @ -147,7 +149,7 @@ def generate(env): | ||||
|                         '--stack_file="${COPRO_STACK_BIN}" ' | ||||
|                         "--stack_addr=${COPRO_STACK_ADDR} ", | ||||
|                     ], | ||||
|                     "\tCOPRO\t${TARGET}", | ||||
|                     "$COPROCOMSTR", | ||||
|                 ) | ||||
|             ), | ||||
|         } | ||||
|  | ||||
| @ -34,7 +34,7 @@ class Copro: | ||||
|         self.mcu_copro = None | ||||
|         self.logger = logging.getLogger(self.__class__.__name__) | ||||
| 
 | ||||
|     def loadCubeInfo(self, cube_dir, cube_version): | ||||
|     def loadCubeInfo(self, cube_dir, reference_cube_version): | ||||
|         if not os.path.isdir(cube_dir): | ||||
|             raise Exception(f'"{cube_dir}" doesn\'t exists') | ||||
|         self.cube_dir = cube_dir | ||||
| @ -50,7 +50,7 @@ class Copro: | ||||
|         if not cube_version or not cube_version.startswith("FW.WB"): | ||||
|             raise Exception(f"Incorrect Cube package or version info") | ||||
|         cube_version = cube_version.replace("FW.WB.", "", 1) | ||||
|         if cube_version != cube_version: | ||||
|         if cube_version != reference_cube_version: | ||||
|             raise Exception(f"Unsupported cube version") | ||||
|         self.version = cube_version | ||||
| 
 | ||||
|  | ||||
| @ -335,7 +335,9 @@ class FlipperStorage: | ||||
| 
 | ||||
|     def _check_no_error(self, response, path=None): | ||||
|         if self.has_error(response): | ||||
|             raise FlipperStorageException.from_error_code(self.get_error(response)) | ||||
|             raise FlipperStorageException.from_error_code( | ||||
|                 path, self.get_error(response) | ||||
|             ) | ||||
| 
 | ||||
|     def size(self, path: str): | ||||
|         """file size on Flipper""" | ||||
|  | ||||
| @ -14,7 +14,7 @@ IWDGSTOP:0x1:rw | ||||
| IWDGSW:0x1:rw | ||||
| IPCCDBA:0x0:rw | ||||
| ESE:0x1:r | ||||
| SFSA:0xD7:r | ||||
| SFSA:0xD5:r | ||||
| FSD:0x0:r | ||||
| DDS:0x1:r | ||||
| C2OPT:0x1:r | ||||
| @ -22,7 +22,7 @@ NBRSD:0x0:r | ||||
| SNBRSA:0xD:r | ||||
| BRSD:0x0:r | ||||
| SBRSA:0x12:r | ||||
| SBRV:0x35C00:r | ||||
| SBRV:0x35400:r | ||||
| PCROP1A_STRT:0x1FF:r | ||||
| PCROP1A_END:0x0:r | ||||
| PCROP_RDP:0x1:rw | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| from SCons.Platform import TempFileMunge | ||||
| from SCons.Node import FS | ||||
| from SCons.Errors import UserError | ||||
| from SCons.Warnings import warn, WarningOnByDefault | ||||
| 
 | ||||
| 
 | ||||
| import os | ||||
| import multiprocessing | ||||
| @ -246,7 +248,12 @@ known_extapps = [ | ||||
|     for apptype in apps_to_build_as_faps | ||||
|     for app in appenv["APPBUILD"].get_apps_of_type(apptype, True) | ||||
| ] | ||||
| incompatible_apps = [] | ||||
| for app in known_extapps: | ||||
|     if not app.supports_hardware_target(appenv.subst("f${TARGET_HW}")): | ||||
|         incompatible_apps.append(app) | ||||
|         continue | ||||
| 
 | ||||
|     app_artifacts = appenv.BuildAppElf(app) | ||||
|     app_src_dir = extract_abs_dir(app_artifacts.app._appdir) | ||||
|     app_artifacts.installer = [ | ||||
| @ -254,6 +261,13 @@ for app in known_extapps: | ||||
|         appenv.Install(app_src_dir.Dir("dist").Dir("debug"), app_artifacts.debug), | ||||
|     ] | ||||
| 
 | ||||
| if len(incompatible_apps): | ||||
|     print( | ||||
|         "WARNING: The following apps are not compatible with the current target hardware and will not be built: {}".format( | ||||
|             ", ".join([app.name for app in incompatible_apps]) | ||||
|         ) | ||||
|     ) | ||||
| 
 | ||||
| if appenv["FORCE"]: | ||||
|     appenv.AlwaysBuild([extapp.compact for extapp in apps_artifacts.values()]) | ||||
| 
 | ||||
|  | ||||
| @ -36,6 +36,7 @@ ENV.AppendUnique( | ||||
|     ], | ||||
|     CPPDEFINES=[ | ||||
|         "_GNU_SOURCE", | ||||
|         *GetOption("extra_defines"), | ||||
|     ], | ||||
|     LINKFLAGS=[ | ||||
|         "-mcpu=cortex-m4", | ||||
|  | ||||
| @ -26,6 +26,14 @@ AddOption( | ||||
|     help="List of applications to add to firmware's built-ins. Also see FIRMWARE_APP_SET and FIRMWARE_APPS", | ||||
| ) | ||||
| 
 | ||||
| AddOption( | ||||
|     "--extra-define", | ||||
|     action="append", | ||||
|     dest="extra_defines", | ||||
|     default=[], | ||||
|     help="Extra global define that will be passed to C/C++ compiler, can be specified multiple times", | ||||
| ) | ||||
| 
 | ||||
| AddOption( | ||||
|     "--extra-ext-apps", | ||||
|     action="store", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Aleksandr Kutuzov
						Aleksandr Kutuzov