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' |       - name: 'Find Previous Comment' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }} |         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 |         id: fc | ||||||
|         with: |         with: | ||||||
|           issue-number: ${{ github.event.pull_request.number }} |           issue-number: ${{ github.event.pull_request.number }} | ||||||
| @ -148,7 +148,7 @@ jobs: | |||||||
| 
 | 
 | ||||||
|       - name: 'Create or update comment' |       - name: 'Create or update comment' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request}} |         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: |         with: | ||||||
|           comment-id: ${{ steps.fc.outputs.comment-id }} |           comment-id: ${{ steps.fc.outputs.comment-id }} | ||||||
|           issue-number: ${{ github.event.pull_request.number }} |           issue-number: ${{ github.event.pull_request.number }} | ||||||
| @ -162,6 +162,9 @@ jobs: | |||||||
|   compact: |   compact: | ||||||
|     if: ${{ !startsWith(github.ref, 'refs/tags') }} |     if: ${{ !startsWith(github.ref, 'refs/tags') }} | ||||||
|     runs-on: [self-hosted,FlipperZeroShell] |     runs-on: [self-hosted,FlipperZeroShell] | ||||||
|  |     strategy: | ||||||
|  |       matrix: | ||||||
|  |         target: [f7, f18] | ||||||
|     steps: |     steps: | ||||||
|       - name: 'Wipe workspace' |       - name: 'Wipe workspace' | ||||||
|         run: find ./ -mount -maxdepth 1 -exec rm -rf {} \;  |         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 }}" |           python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" || cat "${{ github.event_path }}" | ||||||
| 
 | 
 | ||||||
|       - name: 'Build the firmware' |       - name: 'Build the firmware' | ||||||
|  |         id: build-fw | ||||||
|         run: | |         run: | | ||||||
|           set -e |           set -e | ||||||
|           for TARGET in ${TARGETS}; do |           TARGET="$(echo '${{ matrix.target }}' | sed 's/f//')"; \ | ||||||
|             TARGET="$(echo "${TARGET}" | sed 's/f//')"; \ |  | ||||||
|           ./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 fap_dist updater_package |           ./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 | ||||||
|  |           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)"; |           COMMITS_IN_BRANCH="$(git rev-list --count dev)"; | ||||||
|           if [ $COMMITS_IN_BRANCH -lt $SUB_COMMITS_MIN ]; then |           if [ $COMMITS_IN_BRANCH -lt $SUB_COMMITS_MIN ]; then | ||||||
|             echo "name=fails::error" >> $GITHUB_OUTPUT; |             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; |             exit 1; | ||||||
|           fi |           fi | ||||||
|           if ! grep -q "/$SUB_BRANCH" <<< "$BRANCHES"; then |           if ! grep -q "/$SUB_BRANCH" <<< "$BRANCHES"; then | ||||||
| @ -51,12 +51,36 @@ jobs: | |||||||
| 
 | 
 | ||||||
|       - name: 'Check Python code formatting' |       - name: 'Check Python code formatting' | ||||||
|         id: syntax_check_py |         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' |       - name: 'Check C++ code formatting' | ||||||
|         if: always() |  | ||||||
|         id: syntax_check_cpp |         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 |       - name: Report code formatting errors | ||||||
|         if: ( steps.syntax_check_py.outputs.errors || steps.syntax_check_cpp.outputs.errors ) && github.event.pull_request |         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); |     rpc = furi_record_open(RECORD_RPC); | ||||||
|     for(int i = 0; !(rpc_session[0].session) && (i < 10000); ++i) { |     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_delay_tick(1); | ||||||
|     } |     } | ||||||
|     furi_check(rpc_session[0].session); |     furi_check(rpc_session[0].session); | ||||||
| @ -104,7 +104,7 @@ static void test_rpc_setup_second_session(void) { | |||||||
|     furi_check(!(rpc_session[1].session)); |     furi_check(!(rpc_session[1].session)); | ||||||
| 
 | 
 | ||||||
|     for(int i = 0; !(rpc_session[1].session) && (i < 10000); ++i) { |     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_delay_tick(1); | ||||||
|     } |     } | ||||||
|     furi_check(rpc_session[1].session); |     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); |                 picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context); |             picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -596,6 +596,9 @@ int32_t picopass_worker_task(void* context) { | |||||||
|         picopass_worker_write_key(picopass_worker); |         picopass_worker_write_key(picopass_worker); | ||||||
|     } else if(picopass_worker->state == PicopassWorkerStateEliteDictAttack) { |     } else if(picopass_worker->state == PicopassWorkerStateEliteDictAttack) { | ||||||
|         picopass_worker_elite_dict_attack(picopass_worker); |         picopass_worker_elite_dict_attack(picopass_worker); | ||||||
|  |     } else if(picopass_worker->state == PicopassWorkerStateStop) { | ||||||
|  |         FURI_LOG_D(TAG, "Worker state stop"); | ||||||
|  |         // no-op
 | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_W(TAG, "Unknown state %d", picopass_worker->state); |         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 = |     uint32_t state = | ||||||
|         scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneEliteDictAttack); |         scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneEliteDictAttack); | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == PicopassWorkerEventSuccess || |         if(event.event == PicopassWorkerEventSuccess) { | ||||||
|            event.event == PicopassWorkerEventAborted) { |  | ||||||
|             if(state == DictAttackStateUserDictInProgress || |             if(state == DictAttackStateUserDictInProgress || | ||||||
|                state == DictAttackStateStandardDictInProgress) { |                state == DictAttackStateStandardDictInProgress) { | ||||||
|                 picopass_worker_stop(picopass->worker); |                 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); |                 scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); | ||||||
|                 consumed = true; |                 consumed = true; | ||||||
|             } |             } | ||||||
|  |         } else if(event.event == PicopassWorkerEventAborted) { | ||||||
|  |             scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); | ||||||
|  |             consumed = true; | ||||||
|         } else if(event.event == PicopassWorkerEventCardDetected) { |         } else if(event.event == PicopassWorkerEventCardDetected) { | ||||||
|             dict_attack_set_card_detected(picopass->dict_attack); |             dict_attack_set_card_detected(picopass->dict_attack); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "fap_loader_app.h" | #include "fap_loader_app.h" | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
|  | #include <furi_hal_debug.h> | ||||||
| 
 | 
 | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| @ -23,8 +24,6 @@ struct FapLoader { | |||||||
|     Loading* loading; |     Loading* loading; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| volatile bool fap_loader_debug_active = false; |  | ||||||
| 
 |  | ||||||
| bool fap_loader_load_name_and_icon( | bool fap_loader_load_name_and_icon( | ||||||
|     FuriString* path, |     FuriString* path, | ||||||
|     Storage* storage, |     Storage* storage, | ||||||
| @ -111,7 +110,7 @@ static bool fap_loader_run_selected_app(FapLoader* loader) { | |||||||
|         FuriThread* thread = flipper_application_spawn(loader->app, NULL); |         FuriThread* thread = flipper_application_spawn(loader->app, NULL); | ||||||
| 
 | 
 | ||||||
|         /* This flag is set by the debugger - to break on app start */ |         /* 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"); |             FURI_LOG_W(TAG, "Triggering BP for debugger"); | ||||||
|             /* After hitting this, you can set breakpoints in your .fap's code
 |             /* After hitting this, you can set breakpoints in your .fap's code
 | ||||||
|              * Note that you have to toggle breakpoints that were set before */ |              * 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); |         furi_event_flag_clear(bt->rpc_event, BT_RPC_EVENT_DISCONNECTED); | ||||||
|         if(bt->profile == BtProfileSerial) { |         if(bt->profile == BtProfileSerial) { | ||||||
|             // Open RPC session
 |             // Open RPC session
 | ||||||
|             bt->rpc_session = rpc_session_open(bt->rpc); |             bt->rpc_session = rpc_session_open(bt->rpc, RpcOwnerBle); | ||||||
|             if(bt->rpc_session) { |             if(bt->rpc_session) { | ||||||
|                 FURI_LOG_I(TAG, "Open RPC connection"); |                 FURI_LOG_I(TAG, "Open RPC connection"); | ||||||
|                 rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback); |                 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); |     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) { | static bool desktop_custom_event_callback(void* context, uint32_t event) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Desktop* desktop = (Desktop*)context; |     Desktop* desktop = (Desktop*)context; | ||||||
| @ -153,6 +159,17 @@ void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { | |||||||
|     desktop->in_transition = false; |     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_alloc() { | ||||||
|     Desktop* desktop = malloc(sizeof(Desktop)); |     Desktop* desktop = malloc(sizeof(Desktop)); | ||||||
| 
 | 
 | ||||||
| @ -244,6 +261,18 @@ Desktop* desktop_alloc() { | |||||||
|     view_port_enabled_set(desktop->dummy_mode_icon_viewport, false); |     view_port_enabled_set(desktop->dummy_mode_icon_viewport, false); | ||||||
|     gui_add_view_port(desktop->gui, desktop->dummy_mode_icon_viewport, GuiLayerStatusBarLeft); |     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
 |     // Special case: autostart application is already running
 | ||||||
|     desktop->loader = furi_record_open(RECORD_LOADER); |     desktop->loader = furi_record_open(RECORD_LOADER); | ||||||
|     if(loader_is_locked(desktop->loader) && |     if(loader_is_locked(desktop->loader) && | ||||||
|  | |||||||
| @ -59,6 +59,7 @@ struct Desktop { | |||||||
| 
 | 
 | ||||||
|     ViewPort* lock_icon_viewport; |     ViewPort* lock_icon_viewport; | ||||||
|     ViewPort* dummy_mode_icon_viewport; |     ViewPort* dummy_mode_icon_viewport; | ||||||
|  |     ViewPort* stealth_mode_icon_viewport; | ||||||
| 
 | 
 | ||||||
|     AnimationManager* animation_manager; |     AnimationManager* animation_manager; | ||||||
| 
 | 
 | ||||||
| @ -79,3 +80,4 @@ void desktop_free(Desktop* desktop); | |||||||
| void desktop_lock(Desktop* desktop); | void desktop_lock(Desktop* desktop); | ||||||
| void desktop_unlock(Desktop* desktop); | void desktop_unlock(Desktop* desktop); | ||||||
| void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled); | 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_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_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_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); |     desktop_lock_menu_set_idx(desktop->lock_menu, 0); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLockMenu); |     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( |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|                 desktop->scene_manager, DesktopSceneMain); |                 desktop->scene_manager, DesktopSceneMain); | ||||||
|             break; |             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: |         default: | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -34,6 +34,8 @@ typedef enum { | |||||||
|     DesktopLockMenuEventPinLock, |     DesktopLockMenuEventPinLock, | ||||||
|     DesktopLockMenuEventDummyModeOn, |     DesktopLockMenuEventDummyModeOn, | ||||||
|     DesktopLockMenuEventDummyModeOff, |     DesktopLockMenuEventDummyModeOff, | ||||||
|  |     DesktopLockMenuEventStealthModeOn, | ||||||
|  |     DesktopLockMenuEventStealthModeOff, | ||||||
| 
 | 
 | ||||||
|     DesktopAnimationEventCheckAnimation, |     DesktopAnimationEventCheckAnimation, | ||||||
|     DesktopAnimationEventNewIdleAnimation, |     DesktopAnimationEventNewIdleAnimation, | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     DesktopLockMenuIndexLock, |     DesktopLockMenuIndexLock, | ||||||
|     DesktopLockMenuIndexPinLock, |     DesktopLockMenuIndexStealth, | ||||||
|     DesktopLockMenuIndexDummy, |     DesktopLockMenuIndexDummy, | ||||||
| 
 | 
 | ||||||
|     DesktopLockMenuIndexTotalCount |     DesktopLockMenuIndexTotalCount | ||||||
| @ -39,6 +39,14 @@ void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool | |||||||
|         true); |         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) { | void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { | ||||||
|     furi_assert(idx < DesktopLockMenuIndexTotalCount); |     furi_assert(idx < DesktopLockMenuIndexTotalCount); | ||||||
|     with_view_model( |     with_view_model( | ||||||
| @ -58,11 +66,11 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { | |||||||
| 
 | 
 | ||||||
|         if(i == DesktopLockMenuIndexLock) { |         if(i == DesktopLockMenuIndexLock) { | ||||||
|             str = "Lock"; |             str = "Lock"; | ||||||
|         } else if(i == DesktopLockMenuIndexPinLock) { |         } else if(i == DesktopLockMenuIndexStealth) { | ||||||
|             if(m->pin_is_set) { |             if(m->stealth_mode) { | ||||||
|                 str = "Lock with PIN"; |                 str = "Sound Mode"; | ||||||
|             } else { |             } else { | ||||||
|                 str = "Set PIN"; |                 str = "Stealth Mode"; | ||||||
|             } |             } | ||||||
|         } else if(i == DesktopLockMenuIndexDummy) { //-V547
 |         } else if(i == DesktopLockMenuIndexDummy) { //-V547
 | ||||||
|             if(m->dummy_mode) { |             if(m->dummy_mode) { | ||||||
| @ -93,6 +101,8 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { | |||||||
|     uint8_t idx = 0; |     uint8_t idx = 0; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
|     bool dummy_mode = false; |     bool dummy_mode = false; | ||||||
|  |     bool stealth_mode = false; | ||||||
|  |     bool pin_is_set = false; | ||||||
|     bool update = false; |     bool update = false; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
| @ -120,14 +130,24 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { | |||||||
|             } |             } | ||||||
|             idx = model->idx; |             idx = model->idx; | ||||||
|             dummy_mode = model->dummy_mode; |             dummy_mode = model->dummy_mode; | ||||||
|  |             stealth_mode = model->stealth_mode; | ||||||
|  |             pin_is_set = model->pin_is_set; | ||||||
|         }, |         }, | ||||||
|         update); |         update); | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyOk) { |     if(event->key == InputKeyOk) { | ||||||
|         if((idx == DesktopLockMenuIndexLock) && (event->type == InputTypeShort)) { |         if((idx == DesktopLockMenuIndexLock)) { | ||||||
|             lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); |             if((pin_is_set) && (event->type == InputTypeShort)) { | ||||||
|         } else if((idx == DesktopLockMenuIndexPinLock) && (event->type == InputTypeShort)) { |  | ||||||
|                 lock_menu->callback(DesktopLockMenuEventPinLock, lock_menu->context); |                 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) { |         } else if(idx == DesktopLockMenuIndexDummy) { | ||||||
|             if((dummy_mode == false) && (event->type == InputTypeShort)) { |             if((dummy_mode == false) && (event->type == InputTypeShort)) { | ||||||
|                 lock_menu->callback(DesktopLockMenuEventDummyModeOn, lock_menu->context); |                 lock_menu->callback(DesktopLockMenuEventDummyModeOn, lock_menu->context); | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ typedef struct { | |||||||
|     uint8_t idx; |     uint8_t idx; | ||||||
|     bool pin_is_set; |     bool pin_is_set; | ||||||
|     bool dummy_mode; |     bool dummy_mode; | ||||||
|  |     bool stealth_mode; | ||||||
| } DesktopLockMenuViewModel; | } DesktopLockMenuViewModel; | ||||||
| 
 | 
 | ||||||
| void desktop_lock_menu_set_callback( | 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); | 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_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_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); | void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx); | ||||||
| DesktopLockMenuView* desktop_lock_menu_alloc(); | DesktopLockMenuView* desktop_lock_menu_alloc(); | ||||||
| void desktop_lock_menu_free(DesktopLockMenuView* lock_menu); | 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_display_mask = 1 << 5; | ||||||
| static const uint8_t reset_blink_mask = 1 << 6; | 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_vibro_off(); | ||||||
| void notification_sound_on(float freq, float volume); | void notification_sound_on(float freq, float volume, bool force); | ||||||
| void notification_sound_off(); | void notification_sound_off(); | ||||||
| 
 | 
 | ||||||
| uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value); | uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value); | ||||||
| @ -141,19 +141,23 @@ uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // generics
 | // 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); |         furi_hal_vibro_on(true); | ||||||
|     } |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void notification_vibro_off() { | void notification_vibro_off() { | ||||||
|     furi_hal_vibro_on(false); |     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)) { |         if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { | ||||||
|             furi_hal_speaker_start(freq, volume); |             furi_hal_speaker_start(freq, volume); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void notification_sound_off() { | void notification_sound_off() { | ||||||
|     if(furi_hal_speaker_is_mine()) { |     if(furi_hal_speaker_is_mine()) { | ||||||
| @ -174,6 +178,8 @@ void notification_process_notification_message( | |||||||
|     NotificationApp* app, |     NotificationApp* app, | ||||||
|     NotificationAppMessage* message) { |     NotificationAppMessage* message) { | ||||||
|     uint32_t notification_message_index = 0; |     uint32_t notification_message_index = 0; | ||||||
|  |     bool force_volume = false; | ||||||
|  |     bool force_vibro = false; | ||||||
|     const NotificationMessage* notification_message; |     const NotificationMessage* notification_message; | ||||||
|     notification_message = (*message->sequence)[notification_message_index]; |     notification_message = (*message->sequence)[notification_message_index]; | ||||||
| 
 | 
 | ||||||
| @ -269,7 +275,7 @@ void notification_process_notification_message( | |||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeVibro: |         case NotificationMessageTypeVibro: | ||||||
|             if(notification_message->data.vibro.on) { |             if(notification_message->data.vibro.on) { | ||||||
|                 if(vibro_setting) notification_vibro_on(); |                 if(vibro_setting) notification_vibro_on(force_vibro); | ||||||
|             } else { |             } else { | ||||||
|                 notification_vibro_off(); |                 notification_vibro_off(); | ||||||
|             } |             } | ||||||
| @ -278,7 +284,8 @@ void notification_process_notification_message( | |||||||
|         case NotificationMessageTypeSoundOn: |         case NotificationMessageTypeSoundOn: | ||||||
|             notification_sound_on( |             notification_sound_on( | ||||||
|                 notification_message->data.sound.frequency, |                 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; |             reset_mask |= reset_sound_mask; | ||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeSoundOff: |         case NotificationMessageTypeSoundOff: | ||||||
| @ -307,9 +314,11 @@ void notification_process_notification_message( | |||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeForceSpeakerVolumeSetting: |         case NotificationMessageTypeForceSpeakerVolumeSetting: | ||||||
|             speaker_volume_setting = notification_message->data.forced_settings.speaker_volume; |             speaker_volume_setting = notification_message->data.forced_settings.speaker_volume; | ||||||
|  |             force_volume = true; | ||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeForceVibroSetting: |         case NotificationMessageTypeForceVibroSetting: | ||||||
|             vibro_setting = notification_message->data.forced_settings.vibro; |             vibro_setting = notification_message->data.forced_settings.vibro; | ||||||
|  |             force_vibro = true; | ||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeForceDisplayBrightnessSetting: |         case NotificationMessageTypeForceDisplayBrightnessSetting: | ||||||
|             display_brightness_setting = |             display_brightness_setting = | ||||||
|  | |||||||
| @ -76,6 +76,7 @@ struct RpcSession { | |||||||
|     RpcBufferIsEmptyCallback buffer_is_empty_callback; |     RpcBufferIsEmptyCallback buffer_is_empty_callback; | ||||||
|     RpcSessionClosedCallback closed_callback; |     RpcSessionClosedCallback closed_callback; | ||||||
|     RpcSessionTerminatedCallback terminated_callback; |     RpcSessionTerminatedCallback terminated_callback; | ||||||
|  |     RpcOwner owner; | ||||||
|     void* context; |     void* context; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -83,6 +84,11 @@ struct Rpc { | |||||||
|     FuriMutex* busy_mutex; |     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) { | static void rpc_close_session_process(const PB_Main* request, void* context) { | ||||||
|     furi_assert(request); |     furi_assert(request); | ||||||
|     furi_assert(context); |     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); |     furi_assert(rpc); | ||||||
| 
 | 
 | ||||||
|     RpcSession* session = malloc(sizeof(RpcSession)); |     RpcSession* session = malloc(sizeof(RpcSession)); | ||||||
| @ -357,6 +363,7 @@ RpcSession* rpc_session_open(Rpc* rpc) { | |||||||
|     session->rpc = rpc; |     session->rpc = rpc; | ||||||
|     session->terminate = false; |     session->terminate = false; | ||||||
|     session->decode_error = false; |     session->decode_error = false; | ||||||
|  |     session->owner = owner; | ||||||
|     RpcHandlerDict_init(session->handlers); |     RpcHandlerDict_init(session->handlers); | ||||||
| 
 | 
 | ||||||
|     session->decoded_message = malloc(sizeof(PB_Main)); |     session->decoded_message = malloc(sizeof(PB_Main)); | ||||||
|  | |||||||
| @ -30,6 +30,21 @@ typedef void (*RpcSessionClosedCallback)(void* context); | |||||||
|  * and all operations were finished */ |  * and all operations were finished */ | ||||||
| typedef void (*RpcSessionTerminatedCallback)(void* context); | 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
 | /** Open RPC session
 | ||||||
|  * |  * | ||||||
|  * USAGE: |  * USAGE: | ||||||
| @ -44,10 +59,11 @@ typedef void (*RpcSessionTerminatedCallback)(void* context); | |||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * @param   rpc     instance |  * @param   rpc     instance | ||||||
|  |  * @param   owner   owner of session | ||||||
|  * @return          pointer to RpcSession descriptor, or |  * @return          pointer to RpcSession descriptor, or | ||||||
|  *                  NULL if RPC is busy and can't open session now |  *                  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
 | /** Close RPC session
 | ||||||
|  * It is guaranteed that no callbacks will be called |  * 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_LOG_D(TAG, "Free memory %lu", mem_before); | ||||||
| 
 | 
 | ||||||
|     furi_hal_usb_lock(); |     furi_hal_usb_lock(); | ||||||
|     RpcSession* rpc_session = rpc_session_open(rpc); |     RpcSession* rpc_session = rpc_session_open(rpc, RpcOwnerUsb); | ||||||
|     if(rpc_session == NULL) { |     if(rpc_session == NULL) { | ||||||
|         printf("Session start error\r\n"); |         printf("Session start error\r\n"); | ||||||
|         furi_hal_usb_unlock(); |         furi_hal_usb_unlock(); | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| #include "rpc_i.h" | #include "rpc_i.h" | ||||||
| #include "gui.pb.h" | #include "gui.pb.h" | ||||||
| #include <gui/gui_i.h> | #include <gui/gui_i.h> | ||||||
|  | #include <assets_icons.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "RpcGui" | #define TAG "RpcGui" | ||||||
| 
 | 
 | ||||||
| @ -31,6 +32,8 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
|     uint32_t input_key_counter[InputKeyMAX]; |     uint32_t input_key_counter[InputKeyMAX]; | ||||||
|     uint32_t input_counter; |     uint32_t input_counter; | ||||||
|  | 
 | ||||||
|  |     ViewPort* rpc_session_active_viewport; | ||||||
| } RpcGuiSystem; | } RpcGuiSystem; | ||||||
| 
 | 
 | ||||||
| static const PB_Gui_ScreenOrientation rpc_system_gui_screen_orientation_map[] = { | 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; |     (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) { | void* rpc_system_gui_alloc(RpcSession* session) { | ||||||
|     furi_assert(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->gui = furi_record_open(RECORD_GUI); | ||||||
|     rpc_gui->session = session; |     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 = { |     RpcHandler rpc_handler = { | ||||||
|         .message_handler = NULL, |         .message_handler = NULL, | ||||||
|         .decode_submessage = NULL, |         .decode_submessage = NULL, | ||||||
| @ -399,6 +420,9 @@ void rpc_system_gui_free(void* context) { | |||||||
|         rpc_gui->virtual_display_not_empty = false; |         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) { |     if(rpc_gui->is_streaming) { | ||||||
|         rpc_gui->is_streaming = false; |         rpc_gui->is_streaming = false; | ||||||
|         // Remove GUI framebuffer callback
 |         // 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_index(item, value_index); | ||||||
|     variable_item_set_current_value_text(item, backlight_text[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( |         item = variable_item_list_add( | ||||||
|             app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); |             app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); | ||||||
|     value_index = |         value_index = value_index_float( | ||||||
|         value_index_float(app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); |             app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); | ||||||
|         variable_item_set_current_value_index(item, value_index); |         variable_item_set_current_value_index(item, value_index); | ||||||
|         variable_item_set_current_value_text(item, volume_text[value_index]); |         variable_item_set_current_value_text(item, volume_text[value_index]); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     item = |     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { | ||||||
|         variable_item_list_add(app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); |         item = variable_item_list_add(app->variable_item_list, "Vibro", 1, NULL, app); | ||||||
|     value_index = value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); |         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_index(item, value_index); | ||||||
|         variable_item_set_current_value_text(item, vibro_text[value_index]); |         variable_item_set_current_value_text(item, vibro_text[value_index]); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     app->view_dispatcher = view_dispatcher_alloc(); |     app->view_dispatcher = view_dispatcher_alloc(); | ||||||
|     view_dispatcher_enable_queue(app->view_dispatcher); |     view_dispatcher_enable_queue(app->view_dispatcher); | ||||||
|  | |||||||
| @ -4,8 +4,8 @@ | |||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| #include <locale/locale.h> | #include <locale/locale.h> | ||||||
| 
 | 
 | ||||||
| #define LOW_CHARGE_THRESHOLD 10 | #define LOW_CHARGE_THRESHOLD (10) | ||||||
| #define HIGH_DRAIN_CURRENT_THRESHOLD 100 | #define HIGH_DRAIN_CURRENT_THRESHOLD (-100) | ||||||
| 
 | 
 | ||||||
| struct BatteryInfo { | struct BatteryInfo { | ||||||
|     View* view; |     View* view; | ||||||
| @ -25,14 +25,13 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { | |||||||
|     char header[20] = {}; |     char header[20] = {}; | ||||||
|     char value[20] = {}; |     char value[20] = {}; | ||||||
| 
 | 
 | ||||||
|     int32_t drain_current = data->gauge_current * (-1000); |     int32_t current = 1000.0f * data->gauge_current; | ||||||
|     uint32_t charge_current = data->gauge_current * 1000; |  | ||||||
| 
 | 
 | ||||||
|     // Draw battery
 |     // Draw battery
 | ||||||
|     canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28); |     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); |         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); |         canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14); | ||||||
|     } else if(data->charge < LOW_CHARGE_THRESHOLD) { |     } else if(data->charge < LOW_CHARGE_THRESHOLD) { | ||||||
|         canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14); |         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); |     elements_bubble(canvas, 53, 0, 71, 39); | ||||||
| 
 | 
 | ||||||
|     // Set text
 |     // Set text
 | ||||||
|     if(charge_current > 0) { |     if(current > 0) { | ||||||
|         snprintf(emote, sizeof(emote), "%s", "Yummy!"); |         snprintf(emote, sizeof(emote), "%s", "Yummy!"); | ||||||
|         snprintf(header, sizeof(header), "%s", "Charging at"); |         snprintf(header, sizeof(header), "%s", "Charging at"); | ||||||
|         snprintf( |         snprintf( | ||||||
| @ -53,23 +52,22 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { | |||||||
|             "%lu.%luV   %lumA", |             "%lu.%luV   %lumA", | ||||||
|             (uint32_t)(data->vbus_voltage), |             (uint32_t)(data->vbus_voltage), | ||||||
|             (uint32_t)(data->vbus_voltage * 10) % 10, |             (uint32_t)(data->vbus_voltage * 10) % 10, | ||||||
|             charge_current); |             current); | ||||||
|     } else if(drain_current > 0) { |     } else if(current < 0) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             emote, |             emote, | ||||||
|             sizeof(emote), |             sizeof(emote), | ||||||
|             "%s", |             "%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(header, sizeof(header), "%s", "Consumption is"); | ||||||
|         snprintf( |         snprintf( | ||||||
|             value, |             value, | ||||||
|             sizeof(value), |             sizeof(value), | ||||||
|             "%ld %s", |             "%ld %s", | ||||||
|             drain_current, |             ABS(current), | ||||||
|             drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); |             current < HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); | ||||||
|     } else if(drain_current != 0) { |     } else if(data->vbus_voltage > 0) { | ||||||
|         snprintf(header, 20, "..."); |         if(data->charge_voltage_limit < 4.2) { | ||||||
|     } else if(data->charge_voltage_limit < 4.2) { |  | ||||||
|             // Non-default battery charging limit, mention it
 |             // Non-default battery charging limit, mention it
 | ||||||
|             snprintf(emote, sizeof(emote), "Charged!"); |             snprintf(emote, sizeof(emote), "Charged!"); | ||||||
|             snprintf(header, sizeof(header), "Limited to"); |             snprintf(header, sizeof(header), "Limited to"); | ||||||
| @ -82,6 +80,9 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { | |||||||
|         } else { |         } else { | ||||||
|             snprintf(header, sizeof(header), "Charged!"); |             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 + 3, AlignCenter, AlignCenter, emote); | ||||||
|     canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header); |     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(); |     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) { | static uint32_t system_settings_exit(void* context) { | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     return VIEW_NONE; |     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_index(item, value_index); | ||||||
|     variable_item_set_current_value_text(item, heap_trace_mode_text[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( |     view_set_previous_callback( | ||||||
|         variable_item_list_get_view(app->var_item_list), system_settings_exit); |         variable_item_list_get_view(app->var_item_list), system_settings_exit); | ||||||
|     view_dispatcher_add_view( |     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_ptr = None | ||||||
|         self.app_list_entry_type = None |         self.app_list_entry_type = None | ||||||
|         self._current_apps: list[AppState] = [] |         self._current_apps: list[AppState] = [] | ||||||
|  |         self.set_debug_mode(True) | ||||||
| 
 | 
 | ||||||
|     def _walk_app_list(self, list_head): |     def _walk_app_list(self, list_head): | ||||||
|         while list_head: |         while list_head: | ||||||
| @ -195,7 +196,7 @@ class FlipperAppStateHelper: | |||||||
|         self.set_debug_mode(False) |         self.set_debug_mode(False) | ||||||
| 
 | 
 | ||||||
|     def set_debug_mode(self, mode: bool) -> None: |     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 | # 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 | - `--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-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-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. | - `--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 | ## Configuration | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ DIST_SUFFIX = "local" | |||||||
| COPRO_OB_DATA = "scripts/ob.data" | COPRO_OB_DATA = "scripts/ob.data" | ||||||
| 
 | 
 | ||||||
| # Must match lib/STM32CubeWB version | # Must match lib/STM32CubeWB version | ||||||
| COPRO_CUBE_VERSION = "1.13.3" | COPRO_CUBE_VERSION = "1.15.0" | ||||||
| 
 | 
 | ||||||
| COPRO_CUBE_DIR = "lib/STM32CubeWB" | COPRO_CUBE_DIR = "lib/STM32CubeWB" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,21.0,, | Version,+,23.0,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.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/value_index.h,, | ||||||
| Header,+,lib/toolbox/version.h,, | Header,+,lib/toolbox/version.h,, | ||||||
| Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* | 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_CommonStructInit,void,LL_ADC_CommonInitTypeDef* | ||||||
| Function,-,LL_ADC_DeInit,ErrorStatus,ADC_TypeDef* | 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_INJ_StructInit,void,LL_ADC_INJ_InitTypeDef* | ||||||
| Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_InitTypeDef*" | Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_InitTypeDef*" | ||||||
| Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_REG_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_REG_StructInit,void,LL_ADC_REG_InitTypeDef* | ||||||
| Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* | Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* | ||||||
| Function,-,LL_COMP_DeInit,ErrorStatus,COMP_TypeDef* | 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_COMP_StructInit,void,LL_COMP_InitTypeDef* | ||||||
| Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* | Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* | ||||||
| Function,-,LL_CRS_DeInit,ErrorStatus, | 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_Init1msTick,void,uint32_t | ||||||
| Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* | Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* | ||||||
| Function,-,LL_LPTIM_Disable,void,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_LPTIM_StructInit,void,LL_LPTIM_InitTypeDef* | ||||||
| Function,-,LL_LPUART_DeInit,ErrorStatus,USART_TypeDef* | Function,-,LL_LPUART_DeInit,ErrorStatus,const USART_TypeDef* | ||||||
| Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, LL_LPUART_InitTypeDef*" | Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, const LL_LPUART_InitTypeDef*" | ||||||
| Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* | Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* | ||||||
| Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* | Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* | ||||||
| Function,-,LL_PKA_Init,ErrorStatus,"PKA_TypeDef*, LL_PKA_InitTypeDef*" | 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_SPI_StructInit,void,LL_SPI_InitTypeDef* | ||||||
| Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t | Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t | ||||||
| Function,+,LL_SetSystemCoreClock,void,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_BDTR_StructInit,void,LL_TIM_BDTR_InitTypeDef* | ||||||
| Function,+,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* | 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_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_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_IC_StructInit,void,LL_TIM_IC_InitTypeDef* | ||||||
| Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_InitTypeDef*" | Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_InitTypeDef*" | ||||||
| Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_OC_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_OC_StructInit,void,LL_TIM_OC_InitTypeDef* | ||||||
| Function,-,LL_TIM_StructInit,void,LL_TIM_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_ClockStructInit,void,LL_USART_ClockInitTypeDef* | ||||||
| Function,-,LL_USART_DeInit,ErrorStatus,USART_TypeDef* | Function,-,LL_USART_DeInit,ErrorStatus,const USART_TypeDef* | ||||||
| Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, LL_USART_InitTypeDef*" | Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, const LL_USART_InitTypeDef*" | ||||||
| Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* | Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* | ||||||
| Function,-,LL_mDelay,void,uint32_t | Function,-,LL_mDelay,void,uint32_t | ||||||
| Function,-,SystemCoreClockUpdate,void, | 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_crypto_verify_key,_Bool,uint8_t | ||||||
| Function,+,furi_hal_debug_disable,void, | Function,+,furi_hal_debug_disable,void, | ||||||
| Function,+,furi_hal_debug_enable,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_deinit_early,void, | ||||||
| Function,-,furi_hal_flash_erase,void,uint8_t | Function,-,furi_hal_flash_erase,void,uint8_t | ||||||
| Function,-,furi_hal_flash_get_base,size_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_os_tick,void, | ||||||
| Function,+,furi_hal_power_check_otg_status,void, | Function,+,furi_hal_power_check_otg_status,void, | ||||||
| Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, 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_external_3_3v,void, | ||||||
| Function,+,furi_hal_power_disable_otg,void, | Function,+,furi_hal_power_disable_otg,void, | ||||||
| Function,+,furi_hal_power_enable_external_3_3v,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_log_level,void,uint8_t | ||||||
| Function,+,furi_hal_rtc_set_pin_fails,void,uint32_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_set_register,void,"FuriHalRtcRegister, uint32_t" | ||||||
|  | Function,+,furi_hal_rtc_sync_shadow,void, | ||||||
| Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* | Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* | ||||||
| Function,+,furi_hal_speaker_acquire,_Bool,uint32_t | Function,+,furi_hal_speaker_acquire,_Bool,uint32_t | ||||||
| Function,-,furi_hal_speaker_deinit,void, | 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_close,void,RpcSession* | ||||||
| Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" | 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_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_buffer_is_empty_callback,void,"RpcSession*, RpcBufferIsEmptyCallback" | ||||||
| Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" | Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" | ||||||
| Function,+,rpc_session_set_context,void,"RpcSession*, void*" | 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_ext_pe4,const GpioPin, | ||||||
| Variable,+,gpio_i2c_power_scl,const GpioPin, | Variable,+,gpio_i2c_power_scl,const GpioPin, | ||||||
| Variable,+,gpio_i2c_power_sda,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,const GpioPinRecord[], | ||||||
| Variable,+,gpio_pins_count,const size_t, | Variable,+,gpio_pins_count,const size_t, | ||||||
| Variable,+,gpio_sdcard_cd,const GpioPin, | 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_miso,const GpioPin, | ||||||
| Variable,+,gpio_spi_d_mosi,const GpioPin, | Variable,+,gpio_spi_d_mosi,const GpioPin, | ||||||
| Variable,+,gpio_spi_d_sck,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_rx,const GpioPin, | ||||||
| Variable,+,gpio_usart_tx,const GpioPin, | Variable,+,gpio_usart_tx,const GpioPin, | ||||||
| Variable,+,gpio_usb_dm,const GpioPin, | Variable,+,gpio_usb_dm,const GpioPin, | ||||||
| Variable,+,gpio_usb_dp,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,const InputPin[], | ||||||
| Variable,+,input_pins_count,const size_t, | Variable,+,input_pins_count,const size_t, | ||||||
| Variable,+,message_blink_set_color_blue,const NotificationMessage, | 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_sound_off,const NotificationMessage, | ||||||
| Variable,+,message_vibro_off,const NotificationMessage, | Variable,+,message_vibro_off,const NotificationMessage, | ||||||
| Variable,+,message_vibro_on,const NotificationMessage, | Variable,+,message_vibro_on,const NotificationMessage, | ||||||
| Variable,+,gpio_periph_power,const GpioPin, |  | ||||||
| Variable,+,sequence_audiovisual_alert,const NotificationSequence, | Variable,+,sequence_audiovisual_alert,const NotificationSequence, | ||||||
| Variable,+,sequence_blink_blue_10,const NotificationSequence, | Variable,+,sequence_blink_blue_10,const NotificationSequence, | ||||||
| Variable,+,sequence_blink_blue_100,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,FuriHalUsbInterface, | ||||||
| Variable,+,usb_hid_u2f,FuriHalUsbInterface, | Variable,+,usb_hid_u2f,FuriHalUsbInterface, | ||||||
| Variable,+,usbd_devfs,const usbd_driver, | Variable,+,usbd_devfs,const usbd_driver, | ||||||
| Variable,+,gpio_vibro,const GpioPin, |  | ||||||
|  | |||||||
| 
 | 
| @ -6,6 +6,9 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalResources" | #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_vibro = {.port = GPIOA, .pin = LL_GPIO_PIN_8}; | ||||||
| const GpioPin gpio_ibutton = {.port = GPIOB, .pin = LL_GPIO_PIN_14}; | 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); |     furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall); | ||||||
| 
 | 
 | ||||||
|     // Explicit pulls pins
 |     // Explicit pulls pins
 | ||||||
|     furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow); |     LL_PWR_EnablePUPDCfg(); | ||||||
|     furi_hal_gpio_init(&gpio_vibro, GpioModeAnalog, GpioPullDown, GpioSpeedLow); |     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
 |     // Display pins
 | ||||||
|     furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |     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 GpioPinRecord gpio_pins[]; | ||||||
| extern const size_t gpio_pins_count; | 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_vibro; | ||||||
| extern const GpioPin gpio_ibutton; | extern const GpioPin gpio_ibutton; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,21.0,, | Version,+,23.0,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.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/value_index.h,, | ||||||
| Header,+,lib/toolbox/version.h,, | Header,+,lib/toolbox/version.h,, | ||||||
| Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* | 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_CommonStructInit,void,LL_ADC_CommonInitTypeDef* | ||||||
| Function,-,LL_ADC_DeInit,ErrorStatus,ADC_TypeDef* | 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_INJ_StructInit,void,LL_ADC_INJ_InitTypeDef* | ||||||
| Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_InitTypeDef*" | Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_InitTypeDef*" | ||||||
| Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_REG_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_REG_StructInit,void,LL_ADC_REG_InitTypeDef* | ||||||
| Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* | Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* | ||||||
| Function,-,LL_COMP_DeInit,ErrorStatus,COMP_TypeDef* | 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_COMP_StructInit,void,LL_COMP_InitTypeDef* | ||||||
| Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* | Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* | ||||||
| Function,-,LL_CRS_DeInit,ErrorStatus, | 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_Init1msTick,void,uint32_t | ||||||
| Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* | Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* | ||||||
| Function,-,LL_LPTIM_Disable,void,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_LPTIM_StructInit,void,LL_LPTIM_InitTypeDef* | ||||||
| Function,-,LL_LPUART_DeInit,ErrorStatus,USART_TypeDef* | Function,-,LL_LPUART_DeInit,ErrorStatus,const USART_TypeDef* | ||||||
| Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, LL_LPUART_InitTypeDef*" | Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, const LL_LPUART_InitTypeDef*" | ||||||
| Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* | Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* | ||||||
| Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* | Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* | ||||||
| Function,-,LL_PKA_Init,ErrorStatus,"PKA_TypeDef*, LL_PKA_InitTypeDef*" | 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_SPI_StructInit,void,LL_SPI_InitTypeDef* | ||||||
| Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t | Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t | ||||||
| Function,+,LL_SetSystemCoreClock,void,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_BDTR_StructInit,void,LL_TIM_BDTR_InitTypeDef* | ||||||
| Function,+,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* | 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_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_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_IC_StructInit,void,LL_TIM_IC_InitTypeDef* | ||||||
| Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_InitTypeDef*" | Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_InitTypeDef*" | ||||||
| Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_OC_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_OC_StructInit,void,LL_TIM_OC_InitTypeDef* | ||||||
| Function,-,LL_TIM_StructInit,void,LL_TIM_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_ClockStructInit,void,LL_USART_ClockInitTypeDef* | ||||||
| Function,-,LL_USART_DeInit,ErrorStatus,USART_TypeDef* | Function,-,LL_USART_DeInit,ErrorStatus,const USART_TypeDef* | ||||||
| Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, LL_USART_InitTypeDef*" | Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, const LL_USART_InitTypeDef*" | ||||||
| Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* | Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* | ||||||
| Function,-,LL_mDelay,void,uint32_t | Function,-,LL_mDelay,void,uint32_t | ||||||
| Function,-,SystemCoreClockUpdate,void, | 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_crypto_verify_key,_Bool,uint8_t | ||||||
| Function,+,furi_hal_debug_disable,void, | Function,+,furi_hal_debug_disable,void, | ||||||
| Function,+,furi_hal_debug_enable,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_deinit_early,void, | ||||||
| Function,-,furi_hal_flash_erase,void,uint8_t | Function,-,furi_hal_flash_erase,void,uint8_t | ||||||
| Function,-,furi_hal_flash_get_base,size_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_os_tick,void, | ||||||
| Function,+,furi_hal_power_check_otg_status,void, | Function,+,furi_hal_power_check_otg_status,void, | ||||||
| Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, 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_external_3_3v,void, | ||||||
| Function,+,furi_hal_power_disable_otg,void, | Function,+,furi_hal_power_disable_otg,void, | ||||||
| Function,+,furi_hal_power_enable_external_3_3v,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_log_level,void,uint8_t | ||||||
| Function,+,furi_hal_rtc_set_pin_fails,void,uint32_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_set_register,void,"FuriHalRtcRegister, uint32_t" | ||||||
|  | Function,+,furi_hal_rtc_sync_shadow,void, | ||||||
| Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* | Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* | ||||||
| Function,+,furi_hal_speaker_acquire,_Bool,uint32_t | Function,+,furi_hal_speaker_acquire,_Bool,uint32_t | ||||||
| Function,-,furi_hal_speaker_deinit,void, | 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_close,void,RpcSession* | ||||||
| Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" | 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_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_buffer_is_empty_callback,void,"RpcSession*, RpcBufferIsEmptyCallback" | ||||||
| Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" | Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" | ||||||
| Function,+,rpc_session_set_context,void,"RpcSession*, void*" | 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_ext_pc3,const GpioPin, | ||||||
| Variable,+,gpio_i2c_power_scl,const GpioPin, | Variable,+,gpio_i2c_power_scl,const GpioPin, | ||||||
| Variable,+,gpio_i2c_power_sda,const GpioPin, | Variable,+,gpio_i2c_power_sda,const GpioPin, | ||||||
|  | Variable,+,gpio_ibutton,const GpioPin, | ||||||
| Variable,+,gpio_infrared_rx,const GpioPin, | Variable,+,gpio_infrared_rx,const GpioPin, | ||||||
| Variable,+,gpio_infrared_tx,const GpioPin, | Variable,+,gpio_infrared_tx,const GpioPin, | ||||||
| Variable,+,gpio_nfc_cs,const GpioPin, | Variable,+,gpio_nfc_cs,const GpioPin, | ||||||
| Variable,+,gpio_nfc_irq_rfid_pull,const GpioPin, | Variable,+,gpio_nfc_irq_rfid_pull,const GpioPin, | ||||||
|  | Variable,+,gpio_periph_power,const GpioPin, | ||||||
| Variable,+,gpio_pins,const GpioPinRecord[], | Variable,+,gpio_pins,const GpioPinRecord[], | ||||||
| Variable,+,gpio_pins_count,const size_t, | Variable,+,gpio_pins_count,const size_t, | ||||||
| Variable,+,gpio_rf_sw_0,const GpioPin, | 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_mosi,const GpioPin, | ||||||
| Variable,+,gpio_spi_r_sck,const GpioPin, | Variable,+,gpio_spi_r_sck,const GpioPin, | ||||||
| Variable,+,gpio_subghz_cs,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_rx,const GpioPin, | ||||||
| Variable,+,gpio_usart_tx,const GpioPin, | Variable,+,gpio_usart_tx,const GpioPin, | ||||||
| Variable,+,gpio_usb_dm,const GpioPin, | Variable,+,gpio_usb_dm,const GpioPin, | ||||||
| Variable,+,gpio_usb_dp,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,const InputPin[], | ||||||
| Variable,+,input_pins_count,const size_t, | Variable,+,input_pins_count,const size_t, | ||||||
| Variable,+,lfrfid_protocols,const ProtocolBase*[], | Variable,+,lfrfid_protocols,const ProtocolBase*[], | ||||||
| @ -3249,7 +3255,6 @@ Variable,+,message_red_255,const NotificationMessage, | |||||||
| Variable,+,message_sound_off,const NotificationMessage, | Variable,+,message_sound_off,const NotificationMessage, | ||||||
| Variable,+,message_vibro_off,const NotificationMessage, | Variable,+,message_vibro_off,const NotificationMessage, | ||||||
| Variable,+,message_vibro_on,const NotificationMessage, | Variable,+,message_vibro_on,const NotificationMessage, | ||||||
| Variable,+,gpio_periph_power,const GpioPin, |  | ||||||
| Variable,+,sequence_audiovisual_alert,const NotificationSequence, | Variable,+,sequence_audiovisual_alert,const NotificationSequence, | ||||||
| Variable,+,sequence_blink_blue_10,const NotificationSequence, | Variable,+,sequence_blink_blue_10,const NotificationSequence, | ||||||
| Variable,+,sequence_blink_blue_100,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,FuriHalUsbInterface, | ||||||
| Variable,+,usb_hid_u2f,FuriHalUsbInterface, | Variable,+,usb_hid_u2f,FuriHalUsbInterface, | ||||||
| Variable,+,usbd_devfs,const usbd_driver, | Variable,+,usbd_devfs,const usbd_driver, | ||||||
| Variable,+,gpio_vibro,const GpioPin, |  | ||||||
|  | |||||||
| 
 | 
| @ -33,6 +33,7 @@ extern "C" { | |||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
| 
 | 
 | ||||||
| #include <core/common_defines.h> | #include <core/common_defines.h> | ||||||
|  | #include <tl.h> | ||||||
| 
 | 
 | ||||||
| #include "app_conf.h" | #include "app_conf.h" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,6 +8,8 @@ | |||||||
| 
 | 
 | ||||||
| #define CFG_TX_POWER (0x19) /* +0dBm */ | #define CFG_TX_POWER (0x19) /* +0dBm */ | ||||||
| 
 | 
 | ||||||
|  | #define CFG_IDENTITY_ADDRESS GAP_PUBLIC_ADDR | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Define Advertising parameters |  * 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}; | ALIGN(4) static SHCI_C2_DEBUG_TracesConfig_t APPD_TracesConfig = {0, 0, 0, 0}; | ||||||
| PLACE_IN_SECTION("MB_MEM2") | PLACE_IN_SECTION("MB_MEM2") | ||||||
| ALIGN(4) | 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 |  * 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}, /* 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_0, 0, 0}, /* TIMER_SERVER_CALLBACK - Toggle on Entry */ | ||||||
|     {GPIOA, LL_GPIO_PIN_4, 1, 0}, /* PES_ACTIVITY - Set on Entry / Reset on Exit */ |     {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 */ |     /* 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_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 */ |     {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]; | PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; | ||||||
| 
 | 
 | ||||||
| _Static_assert( | _Static_assert( | ||||||
|     sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 49, |     sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 57, | ||||||
|     "Ble stack config structure size mismatch"); |     "Ble stack config structure size mismatch (check new config options - last updated for v.1.15.0)"); | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     FuriMutex* hci_mtx; |     FuriMutex* hci_mtx; | ||||||
| @ -88,6 +88,12 @@ bool ble_app_init() { | |||||||
|             .min_tx_power = 0, |             .min_tx_power = 0, | ||||||
|             .max_tx_power = 0, |             .max_tx_power = 0, | ||||||
|             .rx_model_config = 1, |             .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); |     status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); | ||||||
|     if(status) { |     if(status) { | ||||||
| @ -137,32 +143,28 @@ static int32_t ble_app_hci_thread(void* arg) { | |||||||
| // Called by WPAN lib
 | // Called by WPAN lib
 | ||||||
| void hci_notify_asynch_evt(void* pdata) { | void hci_notify_asynch_evt(void* pdata) { | ||||||
|     UNUSED(pdata); |     UNUSED(pdata); | ||||||
|     if(ble_app) { |     furi_check(ble_app); | ||||||
|     FuriThreadId thread_id = furi_thread_get_id(ble_app->thread); |     FuriThreadId thread_id = furi_thread_get_id(ble_app->thread); | ||||||
|     furi_assert(thread_id); |     furi_assert(thread_id); | ||||||
|     furi_thread_flags_set(thread_id, BLE_APP_FLAG_HCI_EVENT); |     furi_thread_flags_set(thread_id, BLE_APP_FLAG_HCI_EVENT); | ||||||
| } | } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void hci_cmd_resp_release(uint32_t flag) { | void hci_cmd_resp_release(uint32_t flag) { | ||||||
|     UNUSED(flag); |     UNUSED(flag); | ||||||
|     if(ble_app) { |     furi_check(ble_app); | ||||||
|         furi_semaphore_release(ble_app->hci_sem); |     furi_check(furi_semaphore_release(ble_app->hci_sem) == FuriStatusOk); | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void hci_cmd_resp_wait(uint32_t timeout) { | void hci_cmd_resp_wait(uint32_t timeout) { | ||||||
|     UNUSED(timeout); |     furi_check(ble_app); | ||||||
|     if(ble_app) { |     furi_check(furi_semaphore_acquire(ble_app->hci_sem, timeout) == FuriStatusOk); | ||||||
|         furi_semaphore_acquire(ble_app->hci_sem, FuriWaitForever); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ble_app_hci_event_handler(void* pPayload) { | static void ble_app_hci_event_handler(void* pPayload) { | ||||||
|     SVCCTL_UserEvtFlowStatus_t svctl_return_status; |     SVCCTL_UserEvtFlowStatus_t svctl_return_status; | ||||||
|     tHCI_UserEvtRxParam* pParam = (tHCI_UserEvtRxParam*)pPayload; |     tHCI_UserEvtRxParam* pParam = (tHCI_UserEvtRxParam*)pPayload; | ||||||
| 
 | 
 | ||||||
|     if(ble_app) { |     furi_check(ble_app); | ||||||
|     svctl_return_status = SVCCTL_UserEvtRx((void*)&(pParam->pckt->evtserial)); |     svctl_return_status = SVCCTL_UserEvtRx((void*)&(pParam->pckt->evtserial)); | ||||||
|     if(svctl_return_status != SVCCTL_UserEvtFlowDisable) { |     if(svctl_return_status != SVCCTL_UserEvtFlowDisable) { | ||||||
|         pParam->status = HCI_TL_UserEventFlow_Enable; |         pParam->status = HCI_TL_UserEventFlow_Enable; | ||||||
| @ -170,7 +172,6 @@ static void ble_app_hci_event_handler(void* pPayload) { | |||||||
|         pParam->status = HCI_TL_UserEventFlow_Disable; |         pParam->status = HCI_TL_UserEventFlow_Disable; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status) { | static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status) { | ||||||
|     if(status == HCI_TL_CmdBusy) { |     if(status == HCI_TL_CmdBusy) { | ||||||
|  | |||||||
| @ -23,6 +23,7 @@ | |||||||
| #include <ble/core/ble_std.h> | #include <ble/core/ble_std.h> | ||||||
| #include <ble/core/ble_defs.h> | #include <ble/core/ble_defs.h> | ||||||
| #include "osal.h" | #include "osal.h" | ||||||
|  | #include "compiler.h" | ||||||
| 
 | 
 | ||||||
| /* Default BLE variant */ | /* Default BLE variant */ | ||||||
| #ifndef BASIC_FEATURES | #ifndef BASIC_FEATURES | ||||||
| @ -34,6 +35,9 @@ | |||||||
| #ifndef LL_ONLY | #ifndef LL_ONLY | ||||||
| #define LL_ONLY 0 | #define LL_ONLY 0 | ||||||
| #endif | #endif | ||||||
|  | #ifndef LL_ONLY_BASIC | ||||||
|  | #define LL_ONLY_BASIC 0 | ||||||
|  | #endif | ||||||
| #ifndef BEACON_ONLY | #ifndef BEACON_ONLY | ||||||
| #define BEACON_ONLY 0 | #define BEACON_ONLY 0 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -58,12 +58,6 @@ void ble_glue_init() { | |||||||
|     ble_glue = malloc(sizeof(BleGlue)); |     ble_glue = malloc(sizeof(BleGlue)); | ||||||
|     ble_glue->status = BleGlueStatusStartup; |     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 | #ifdef BLE_GLUE_DEBUG | ||||||
|     APPD_Init(); |     APPD_Init(); | ||||||
| #endif | #endif | ||||||
| @ -409,7 +403,9 @@ void shci_cmd_resp_release(uint32_t flag) { | |||||||
| void shci_cmd_resp_wait(uint32_t timeout) { | void shci_cmd_resp_wait(uint32_t timeout) { | ||||||
|     UNUSED(timeout); |     UNUSED(timeout); | ||||||
|     if(ble_glue) { |     if(ble_glue) { | ||||||
|  |         furi_hal_power_insomnia_enter(); | ||||||
|         furi_semaphore_acquire(ble_glue->shci_sem, FuriWaitForever); |         furi_semaphore_acquire(ble_glue->shci_sem, FuriWaitForever); | ||||||
|  |         furi_hal_power_insomnia_exit(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|  ***************************************************************************** |  ***************************************************************************** | ||||||
|  * @attention |  * @attention | ||||||
|  * |  * | ||||||
|  * Copyright (c) 2018-2022 STMicroelectronics. |  * Copyright (c) 2018-2023 STMicroelectronics. | ||||||
|  * All rights reserved. |  * All rights reserved. | ||||||
|  * |  * | ||||||
|  * This software is licensed under terms that can be found in the LICENSE file |  * This software is licensed under terms that can be found in the LICENSE file | ||||||
| @ -18,6 +18,14 @@ | |||||||
| #ifndef COMPILER_H__ | #ifndef COMPILER_H__ | ||||||
| #define 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 |   * @brief  This is the section dedicated to IAR toolchain | ||||||
|   */ |   */ | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include "gap.h" | #include "gap.h" | ||||||
| 
 | 
 | ||||||
|  | #include "app_common.h" | ||||||
| #include <ble/ble.h> | #include <ble/ble.h> | ||||||
| 
 | 
 | ||||||
| #include <furi_hal.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) { | SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | ||||||
|     hci_event_pckt* event_pckt; |     hci_event_pckt* event_pckt; | ||||||
|     evt_le_meta_event* meta_evt; |     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; |     hci_le_phy_update_complete_event_rp0* evt_le_phy_update_complete; | ||||||
|     uint8_t tx_phy; |     uint8_t tx_phy; | ||||||
|     uint8_t rx_phy; |     uint8_t rx_phy; | ||||||
| @ -97,7 +98,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | |||||||
|         furi_mutex_acquire(gap->state_mutex, FuriWaitForever); |         furi_mutex_acquire(gap->state_mutex, FuriWaitForever); | ||||||
|     } |     } | ||||||
|     switch(event_pckt->evt) { |     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* disconnection_complete_event = | ||||||
|             (hci_disconnection_complete_event_rp0*)event_pckt->data; |             (hci_disconnection_complete_event_rp0*)event_pckt->data; | ||||||
|         if(disconnection_complete_event->Connection_Handle == gap->service.connection_handle) { |         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( |             FURI_LOG_I( | ||||||
|                 TAG, "Disconnect from client. Reason: %02X", disconnection_complete_event->Reason); |                 TAG, "Disconnect from client. Reason: %02X", disconnection_complete_event->Reason); | ||||||
|         } |         } | ||||||
|  |         // Enterprise sleep
 | ||||||
|  |         furi_delay_us(666 + 666); | ||||||
|         if(gap->enable_adv) { |         if(gap->enable_adv) { | ||||||
|             // Restart advertising
 |             // Restart advertising
 | ||||||
|             gap_advertise_start(GapStateAdvFast); |             gap_advertise_start(GapStateAdvFast); | ||||||
| @ -114,10 +117,10 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | |||||||
|         gap->on_event_cb(event, gap->context); |         gap->on_event_cb(event, gap->context); | ||||||
|     } break; |     } break; | ||||||
| 
 | 
 | ||||||
|     case EVT_LE_META_EVENT: |     case HCI_LE_META_EVT_CODE: | ||||||
|         meta_evt = (evt_le_meta_event*)event_pckt->data; |         meta_evt = (evt_le_meta_event*)event_pckt->data; | ||||||
|         switch(meta_evt->subevent) { |         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* event = | ||||||
|                 (hci_le_connection_update_complete_event_rp0*)meta_evt->data; |                 (hci_le_connection_update_complete_event_rp0*)meta_evt->data; | ||||||
|             gap->connection_params.conn_interval = event->Conn_Interval; |             gap->connection_params.conn_interval = event->Conn_Interval; | ||||||
| @ -128,7 +131,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | |||||||
|             break; |             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; |             evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; | ||||||
|             if(evt_le_phy_update_complete->Status) { |             if(evt_le_phy_update_complete->Status) { | ||||||
|                 FURI_LOG_E( |                 FURI_LOG_E( | ||||||
| @ -144,7 +147,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | |||||||
|             } |             } | ||||||
|             break; |             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* event = | ||||||
|                 (hci_le_connection_complete_event_rp0*)meta_evt->data; |                 (hci_le_connection_complete_event_rp0*)meta_evt->data; | ||||||
|             gap->connection_params.conn_interval = event->Conn_Interval; |             gap->connection_params.conn_interval = event->Conn_Interval; | ||||||
| @ -168,16 +171,16 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | |||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case EVT_VENDOR: |     case HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE: | ||||||
|         blue_evt = (evt_blue_aci*)event_pckt->data; |         blue_evt = (evt_blecore_aci*)event_pckt->data; | ||||||
|         switch(blue_evt->ecode) { |         switch(blue_evt->ecode) { | ||||||
|             aci_gap_pairing_complete_event_rp0* pairing_complete; |             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"); |             FURI_LOG_I(TAG, "Limited discoverable event"); | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case EVT_BLUE_GAP_PASS_KEY_REQUEST: { |         case ACI_GAP_PASS_KEY_REQ_VSEVT_CODE: { | ||||||
|             // Generate random PIN code
 |             // Generate random PIN code
 | ||||||
|             uint32_t pin = rand() % 999999; //-V1064
 |             uint32_t pin = rand() % 999999; //-V1064
 | ||||||
|             aci_gap_pass_key_resp(gap->service.connection_handle, pin); |             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); |             gap->on_event_cb(event, gap->context); | ||||||
|         } break; |         } 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; |             aci_att_exchange_mtu_resp_event_rp0* pr = (void*)blue_evt->data; | ||||||
|             FURI_LOG_I(TAG, "Rx MTU size: %d", pr->Server_RX_MTU); |             FURI_LOG_I(TAG, "Rx MTU size: %d", pr->Server_RX_MTU); | ||||||
|             // Set maximum packet size given header size is 3 bytes
 |             // 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); |             gap->on_event_cb(event, gap->context); | ||||||
|         } break; |         } break; | ||||||
| 
 | 
 | ||||||
|         case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: |         case ACI_GAP_AUTHORIZATION_REQ_VSEVT_CODE: | ||||||
|             FURI_LOG_D(TAG, "Authorization request event"); |             FURI_LOG_D(TAG, "Authorization request event"); | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: |         case ACI_GAP_SLAVE_SECURITY_INITIATED_VSEVT_CODE: | ||||||
|             FURI_LOG_D(TAG, "Slave security initiated"); |             FURI_LOG_D(TAG, "Slave security initiated"); | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case EVT_BLUE_GAP_BOND_LOST: |         case ACI_GAP_BOND_LOST_VSEVT_CODE: | ||||||
|             FURI_LOG_D(TAG, "Bond lost event. Start rebonding"); |             FURI_LOG_D(TAG, "Bond lost event. Start rebonding"); | ||||||
|             aci_gap_allow_rebond(gap->service.connection_handle); |             aci_gap_allow_rebond(gap->service.connection_handle); | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case EVT_BLUE_GAP_DEVICE_FOUND: |         case ACI_GAP_ADDR_NOT_RESOLVED_VSEVT_CODE: | ||||||
|             FURI_LOG_D(TAG, "Device found event"); |  | ||||||
|             break; |  | ||||||
| 
 |  | ||||||
|         case EVT_BLUE_GAP_ADDR_NOT_RESOLVED: |  | ||||||
|             FURI_LOG_D(TAG, "Address not resolved event"); |             FURI_LOG_D(TAG, "Address not resolved event"); | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: |         case ACI_GAP_KEYPRESS_NOTIFICATION_VSEVT_CODE: | ||||||
|             FURI_LOG_D(TAG, "Key press notification event"); |             FURI_LOG_D(TAG, "Key press notification event"); | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: { |         case ACI_GAP_NUMERIC_COMPARISON_VALUE_VSEVT_CODE: { | ||||||
|             uint32_t pin = |             uint32_t pin = | ||||||
|                 ((aci_gap_numeric_comparison_value_event_rp0*)(blue_evt->data))->Numeric_Value; |                 ((aci_gap_numeric_comparison_value_event_rp0*)(blue_evt->data))->Numeric_Value; | ||||||
|             FURI_LOG_I(TAG, "Verify numeric comparison: %06lu", pin); |             FURI_LOG_I(TAG, "Verify numeric comparison: %06lu", pin); | ||||||
| @ -234,7 +233,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | |||||||
|             break; |             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; |             pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data; | ||||||
|             if(pairing_complete->Status) { |             if(pairing_complete->Status) { | ||||||
|                 FURI_LOG_E( |                 FURI_LOG_E( | ||||||
| @ -249,11 +248,11 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { | |||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case EVT_BLUE_GAP_PROCEDURE_COMPLETE: |         case ACI_L2CAP_CONNECTION_UPDATE_RESP_VSEVT_CODE: | ||||||
|             FURI_LOG_D(TAG, "Procedure complete event"); |             FURI_LOG_D(TAG, "Procedure complete event"); | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case EVT_BLUE_L2CAP_CONNECTION_UPDATE_RESP: { |         case ACI_L2CAP_CONNECTION_UPDATE_REQ_VSEVT_CODE: { | ||||||
|             uint16_t result = |             uint16_t result = | ||||||
|                 ((aci_l2cap_connection_update_resp_event_rp0*)(blue_evt->data))->Result; |                 ((aci_l2cap_connection_update_resp_event_rp0*)(blue_evt->data))->Result; | ||||||
|             if(result == 0) { |             if(result == 0) { | ||||||
| @ -289,8 +288,6 @@ static void gap_init_svc(Gap* gap) { | |||||||
|     tBleStatus status; |     tBleStatus status; | ||||||
|     uint32_t srd_bd_addr[2]; |     uint32_t srd_bd_addr[2]; | ||||||
| 
 | 
 | ||||||
|     // HCI Reset to synchronise BLE Stack
 |  | ||||||
|     hci_reset(); |  | ||||||
|     // Configure mac address
 |     // Configure mac address
 | ||||||
|     aci_hal_write_config_data( |     aci_hal_write_config_data( | ||||||
|         CONFIG_DATA_PUBADDR_OFFSET, CONFIG_DATA_PUBADDR_LEN, gap->config->mac_address); |         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_ENCRYPTION_KEY_SIZE_MAX, | ||||||
|         CFG_USED_FIXED_PIN, |         CFG_USED_FIXED_PIN, | ||||||
|         0, |         0, | ||||||
|         PUBLIC_ADDR); |         CFG_IDENTITY_ADDRESS); | ||||||
|     // Configure whitelist
 |     // Configure whitelist
 | ||||||
|     aci_gap_configure_whitelist(); |     aci_gap_configure_whitelist(); | ||||||
| } | } | ||||||
| @ -399,7 +396,7 @@ static void gap_advertise_start(GapState new_state) { | |||||||
|         ADV_IND, |         ADV_IND, | ||||||
|         min_interval, |         min_interval, | ||||||
|         max_interval, |         max_interval, | ||||||
|         PUBLIC_ADDR, |         CFG_IDENTITY_ADDRESS, | ||||||
|         0, |         0, | ||||||
|         strlen(gap->service.adv_name), |         strlen(gap->service.adv_name), | ||||||
|         (uint8_t*)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
 |     // 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); |     furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0); | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // Start Core2
 |     // Start Core2
 | ||||||
|     ble_glue_init(); |     ble_glue_init(); | ||||||
| @ -129,9 +127,7 @@ bool furi_hal_bt_start_radio_stack() { | |||||||
|     furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever); |     furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever); | ||||||
| 
 | 
 | ||||||
|     // Explicitly tell that we are in charge of CLK48 domain
 |     // 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); |     furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0); | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         // Wait until C2 is started or timeout
 |         // Wait until C2 is started or timeout
 | ||||||
|  | |||||||
| @ -63,6 +63,10 @@ void furi_hal_clock_init() { | |||||||
|     LL_RCC_HSI_Enable(); |     LL_RCC_HSI_Enable(); | ||||||
|     while(!HS_CLOCK_IS_READY()) |     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(); |     LL_RCC_HSE_EnableCSS(); | ||||||
| 
 | 
 | ||||||
|     /* LSE and LSI1 configuration and activation */ |     /* 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_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); | ||||||
|     LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); |     LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); | ||||||
|     LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_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_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); | ||||||
|     LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); |     LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); | ||||||
|     LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); |     LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); | ||||||
| @ -203,25 +208,36 @@ void furi_hal_clock_switch_to_hsi() { | |||||||
|     while(!LL_RCC_HSI_IsReady()) |     while(!LL_RCC_HSI_IsReady()) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|     LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI); |  | ||||||
|     LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_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) |     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() { | void furi_hal_clock_switch_to_pll() { | ||||||
|     LL_RCC_HSE_Enable(); |     LL_RCC_HSE_Enable(); | ||||||
|     LL_RCC_PLL_Enable(); |     LL_RCC_PLL_Enable(); | ||||||
|  |     LL_RCC_PLLSAI1_Enable(); | ||||||
| 
 | 
 | ||||||
|     while(!LL_RCC_HSE_IsReady()) |     while(!LL_RCC_HSE_IsReady()) | ||||||
|         ; |         ; | ||||||
|     while(!LL_RCC_PLL_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); |     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_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); | ||||||
|     LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); |     LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); | ||||||
|  | |||||||
| @ -3,12 +3,26 @@ | |||||||
| #include <stm32wbxx_ll_exti.h> | #include <stm32wbxx_ll_exti.h> | ||||||
| #include <stm32wbxx_ll_system.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() { | void furi_hal_debug_enable() { | ||||||
|     // Low power mode debug
 |     // Low power mode debug
 | ||||||
|     LL_DBGMCU_EnableDBGSleepMode(); |     LL_DBGMCU_EnableDBGSleepMode(); | ||||||
|     LL_DBGMCU_EnableDBGStopMode(); |     LL_DBGMCU_EnableDBGStopMode(); | ||||||
|     LL_DBGMCU_EnableDBGStandbyMode(); |     LL_DBGMCU_EnableDBGStandbyMode(); | ||||||
|     LL_EXTI_EnableIT_32_63(LL_EXTI_LINE_48); |     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() { | void furi_hal_debug_disable() { | ||||||
| @ -17,4 +31,11 @@ void furi_hal_debug_disable() { | |||||||
|     LL_DBGMCU_DisableDBGStopMode(); |     LL_DBGMCU_DisableDBGStopMode(); | ||||||
|     LL_DBGMCU_DisableDBGStandbyMode(); |     LL_DBGMCU_DisableDBGStandbyMode(); | ||||||
|     LL_EXTI_DisableIT_32_63(LL_EXTI_LINE_48); |     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_flash.h> | ||||||
| #include <furi_hal_bt.h> | #include <furi_hal_bt.h> | ||||||
|  | #include <furi_hal_power.h> | ||||||
|  | #include <furi_hal_cortex.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <ble/ble.h> | #include <ble/ble.h> | ||||||
| #include <interface/patterns/ble_thread/shci/shci.h> | #include <interface/patterns/ble_thread/shci/shci.h> | ||||||
| @ -25,6 +27,16 @@ | |||||||
| #define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F | #define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F | ||||||
| #define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2)) | #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_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL)) | ||||||
| #define IS_FLASH_PROGRAM_ADDRESS(__VALUE__)                                             \ | #define IS_FLASH_PROGRAM_ADDRESS(__VALUE__)                                             \ | ||||||
|     (((__VALUE__) >= FLASH_BASE) && ((__VALUE__) <= (FLASH_BASE + FLASH_SIZE - 8UL)) && \ |     (((__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) { | static void furi_hal_flash_begin_with_core2(bool erase_flag) { | ||||||
|  |     furi_hal_power_insomnia_enter(); | ||||||
|     /* Take flash controller ownership */ |     /* Take flash controller ownership */ | ||||||
|     while(LL_HSEM_1StepLock(HSEM, CFG_HW_FLASH_SEMID) != 0) { |     while(LL_HSEM_1StepLock(HSEM, CFG_HW_FLASH_SEMID) != 0) { | ||||||
|         furi_thread_yield(); |         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++) |     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) { |     while(true) { | ||||||
|         /* Wait till flash controller become usable */ |         /* Wait till flash controller become usable */ | ||||||
|         while(LL_FLASH_IsActiveFlag_OperationSuspended()) { |         while(LL_FLASH_IsActiveFlag_OperationSuspended()) { | ||||||
|  |             furi_check(!furi_hal_cortex_timer_is_expired(timer)); | ||||||
|             furi_thread_yield(); |             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  */ |         /* Actually we already have mutex for it, but specification is specification  */ | ||||||
|         if(LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) { |         if(LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) { | ||||||
|             taskEXIT_CRITICAL(); |             taskEXIT_CRITICAL(); | ||||||
|  |             furi_check(!furi_hal_cortex_timer_is_expired(timer)); | ||||||
|             furi_thread_yield(); |             furi_thread_yield(); | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
| @ -148,6 +164,7 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) { | |||||||
|         /* Take sempahopre and prevent core2 from anything funky */ |         /* Take sempahopre and prevent core2 from anything funky */ | ||||||
|         if(LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != 0) { |         if(LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != 0) { | ||||||
|             taskEXIT_CRITICAL(); |             taskEXIT_CRITICAL(); | ||||||
|  |             furi_check(!furi_hal_cortex_timer_is_expired(timer)); | ||||||
|             furi_thread_yield(); |             furi_thread_yield(); | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
| @ -188,6 +205,7 @@ static void furi_hal_flash_end_with_core2(bool erase_flag) { | |||||||
| 
 | 
 | ||||||
|     /* Release flash controller ownership */ |     /* Release flash controller ownership */ | ||||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_FLASH_SEMID, 0); |     LL_HSEM_ReleaseLock(HSEM, CFG_HW_FLASH_SEMID, 0); | ||||||
|  |     furi_hal_power_insomnia_exit(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void furi_hal_flash_end(bool erase_flag) { | 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) { | bool furi_hal_flash_wait_last_operation(uint32_t timeout) { | ||||||
|     uint32_t error = 0; |     uint32_t error = 0; | ||||||
|     uint32_t countdown = 0; |  | ||||||
| 
 | 
 | ||||||
|     /* Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
 |     /* 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 |        Even if the FLASH operation fails, the BUSY flag will be reset and an error | ||||||
|        flag will be set */ |        flag will be set */ | ||||||
|     countdown = timeout; |     FuriHalCortexTimer timer = furi_hal_cortex_timer_get(timeout * 1000); | ||||||
|     while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) { |     while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) { | ||||||
|         if(LL_SYSTICK_IsActiveCounterFlag()) { |         if(furi_hal_cortex_timer_is_expired(timer)) { | ||||||
|             countdown--; |  | ||||||
|         } |  | ||||||
|         if(countdown == 0) { |  | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -261,12 +275,9 @@ bool furi_hal_flash_wait_last_operation(uint32_t timeout) { | |||||||
|     CLEAR_BIT(FLASH->SR, error); |     CLEAR_BIT(FLASH->SR, error); | ||||||
| 
 | 
 | ||||||
|     /* Wait for control register to be written */ |     /* 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)) { |     while(READ_BIT(FLASH->SR, FLASH_SR_CFGBSY)) { | ||||||
|         if(LL_SYSTICK_IsActiveCounterFlag()) { |         if(furi_hal_cortex_timer_is_expired(timer)) { | ||||||
|             countdown--; |  | ||||||
|         } |  | ||||||
|         if(countdown == 0) { |  | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -28,11 +28,24 @@ | |||||||
| // Arbitrary (but small) number for better tick consistency
 | // Arbitrary (but small) number for better tick consistency
 | ||||||
| #define FURI_HAL_OS_EXTRA_CNT 3 | #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 | #ifdef FURI_HAL_OS_DEBUG | ||||||
| #include <stm32wbxx_ll_gpio.h> | #include <stm32wbxx_ll_gpio.h> | ||||||
| 
 | 
 | ||||||
| void furi_hal_os_timer_callback() { | 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 | #endif | ||||||
| 
 | 
 | ||||||
| @ -44,9 +57,11 @@ void furi_hal_os_init() { | |||||||
|     furi_hal_idle_timer_init(); |     furi_hal_idle_timer_init(); | ||||||
| 
 | 
 | ||||||
| #ifdef FURI_HAL_OS_DEBUG | #ifdef FURI_HAL_OS_DEBUG | ||||||
|     furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); |     furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_AWAKE_GPIO, GpioModeOutputPushPull); | ||||||
|     furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull); |     furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_TICK_GPIO, GpioModeOutputPushPull); | ||||||
|     furi_hal_gpio_init_simple(&gpio_ext_pa4, 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 = |     FuriTimer* second_timer = | ||||||
|         furi_timer_alloc(furi_hal_os_timer_callback, FuriTimerTypePeriodic, NULL); |         furi_timer_alloc(furi_hal_os_timer_callback, FuriTimerTypePeriodic, NULL); | ||||||
|     furi_timer_start(second_timer, FURI_HAL_OS_TICK_HZ); |     furi_timer_start(second_timer, FURI_HAL_OS_TICK_HZ); | ||||||
| @ -58,7 +73,8 @@ void furi_hal_os_init() { | |||||||
| void furi_hal_os_tick() { | void furi_hal_os_tick() { | ||||||
|     if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { |     if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { | ||||||
| #ifdef FURI_HAL_OS_DEBUG | #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 | #endif | ||||||
|         xPortSysTickHandler(); |         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)); |     furi_hal_idle_timer_start(FURI_HAL_OS_TICKS_TO_IDLE_CNT(expected_idle_ticks)); | ||||||
| 
 | 
 | ||||||
| #ifdef FURI_HAL_OS_DEBUG | #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 | #endif | ||||||
| 
 | 
 | ||||||
|     // Go to sleep mode
 |     // Go to sleep mode
 | ||||||
|     furi_hal_power_sleep(); |     furi_hal_power_sleep(); | ||||||
| 
 | 
 | ||||||
| #ifdef FURI_HAL_OS_DEBUG | #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 | #endif | ||||||
| 
 | 
 | ||||||
|     // Calculate how much time we spent in the sleep
 |     // Calculate how much time we spent in the sleep
 | ||||||
|  | |||||||
| @ -4,6 +4,8 @@ | |||||||
| #include <furi_hal_vibro.h> | #include <furi_hal_vibro.h> | ||||||
| #include <furi_hal_resources.h> | #include <furi_hal_resources.h> | ||||||
| #include <furi_hal_uart.h> | #include <furi_hal_uart.h> | ||||||
|  | #include <furi_hal_rtc.h> | ||||||
|  | #include <furi_hal_debug.h> | ||||||
| 
 | 
 | ||||||
| #include <stm32wbxx_ll_rcc.h> | #include <stm32wbxx_ll_rcc.h> | ||||||
| #include <stm32wbxx_ll_pwr.h> | #include <stm32wbxx_ll_pwr.h> | ||||||
| @ -19,15 +21,20 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalPower" | #define TAG "FuriHalPower" | ||||||
| 
 | 
 | ||||||
| #ifdef FURI_HAL_POWER_DEEP_SLEEP_ENABLED | #ifndef FURI_HAL_POWER_DEBUG_WFI_GPIO | ||||||
| #define FURI_HAL_POWER_DEEP_INSOMNIA 0 | #define FURI_HAL_POWER_DEBUG_WFI_GPIO (&gpio_ext_pb2) | ||||||
| #else | #endif | ||||||
| #define FURI_HAL_POWER_DEEP_INSOMNIA 1 | 
 | ||||||
|  | #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 | #endif | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     volatile uint8_t insomnia; |     volatile uint8_t insomnia; | ||||||
|     volatile uint8_t deep_insomnia; |  | ||||||
|     volatile uint8_t suppress_charge; |     volatile uint8_t suppress_charge; | ||||||
| 
 | 
 | ||||||
|     uint8_t gauge_initialized; |     uint8_t gauge_initialized; | ||||||
| @ -36,7 +43,6 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| static volatile FuriHalPower furi_hal_power = { | static volatile FuriHalPower furi_hal_power = { | ||||||
|     .insomnia = 0, |     .insomnia = 0, | ||||||
|     .deep_insomnia = FURI_HAL_POWER_DEEP_INSOMNIA, |  | ||||||
|     .suppress_charge = 0, |     .suppress_charge = 0, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -79,19 +85,24 @@ const ParamCEDV cedv = { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void furi_hal_power_init() { | 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_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); | ||||||
|     LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN); |     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); |     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||||
|     bq27220_init(&furi_hal_i2c_handle_power, &cedv); |     bq27220_init(&furi_hal_i2c_handle_power, &cedv); | ||||||
|     bq25896_init(&furi_hal_i2c_handle_power); |     bq25896_init(&furi_hal_i2c_handle_power); | ||||||
|     furi_hal_i2c_release(&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"); |     FURI_LOG_I(TAG, "Init OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -140,11 +151,12 @@ bool furi_hal_power_sleep_available() { | |||||||
|     return furi_hal_power.insomnia == 0; |     return furi_hal_power.insomnia == 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_power_deep_sleep_available() { | static inline bool furi_hal_power_deep_sleep_available() { | ||||||
|     return furi_hal_bt_is_alive() && furi_hal_power.deep_insomnia == 0; |     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(); |     __WFI(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -152,17 +164,15 @@ static inline void furi_hal_power_suspend_aux_periphs() { | |||||||
|     // Disable USART
 |     // Disable USART
 | ||||||
|     furi_hal_uart_suspend(FuriHalUartIdUSART1); |     furi_hal_uart_suspend(FuriHalUartIdUSART1); | ||||||
|     furi_hal_uart_suspend(FuriHalUartIdLPUART1); |     furi_hal_uart_suspend(FuriHalUartIdLPUART1); | ||||||
|     // TODO: Disable USB
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void furi_hal_power_resume_aux_periphs() { | static inline void furi_hal_power_resume_aux_periphs() { | ||||||
|     // Re-enable USART
 |     // Re-enable USART
 | ||||||
|     furi_hal_uart_resume(FuriHalUartIdUSART1); |     furi_hal_uart_resume(FuriHalUartIdUSART1); | ||||||
|     furi_hal_uart_resume(FuriHalUartIdLPUART1); |     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(); |     furi_hal_power_suspend_aux_periphs(); | ||||||
| 
 | 
 | ||||||
|     while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) |     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); |     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); | ||||||
| 
 | 
 | ||||||
|     // Prepare deep sleep
 |     // Prepare deep sleep
 | ||||||
|     LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2); |  | ||||||
|     LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2); |  | ||||||
|     LL_LPM_EnableDeepSleep(); |     LL_LPM_EnableDeepSleep(); | ||||||
| 
 | 
 | ||||||
| #if defined(__CC_ARM) | #if defined(__CC_ARM) | ||||||
| @ -200,13 +208,6 @@ void furi_hal_power_deep_sleep() { | |||||||
| 
 | 
 | ||||||
|     LL_LPM_EnableSleep(); |     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 */ |     /* Release ENTRY_STOP_MODE semaphore */ | ||||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0); |     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); |     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); | ||||||
| 
 | 
 | ||||||
|     furi_hal_power_resume_aux_periphs(); |     furi_hal_power_resume_aux_periphs(); | ||||||
|  |     furi_hal_rtc_sync_shadow(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_power_sleep() { | void furi_hal_power_sleep() { | ||||||
|     if(furi_hal_power_deep_sleep_available()) { |     if(furi_hal_power_deep_sleep_available()) { | ||||||
| #ifdef FURI_HAL_OS_DEBUG | #ifdef FURI_HAL_POWER_DEBUG | ||||||
|         furi_hal_gpio_write(&gpio_ext_pc3, 1); |         furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 1); | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
|         furi_hal_power_deep_sleep(); |         furi_hal_power_deep_sleep(); | ||||||
| 
 | #ifdef FURI_HAL_POWER_DEBUG | ||||||
| #ifdef FURI_HAL_OS_DEBUG |         furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 0); | ||||||
|         furi_hal_gpio_write(&gpio_ext_pc3, 0); |  | ||||||
| #endif | #endif | ||||||
|     } else { |     } else { | ||||||
| #ifdef FURI_HAL_OS_DEBUG | #ifdef FURI_HAL_POWER_DEBUG | ||||||
|         furi_hal_gpio_write(&gpio_ext_pb2, 1); |         furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 1); | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
|         furi_hal_power_light_sleep(); |         furi_hal_power_light_sleep(); | ||||||
| 
 | #ifdef FURI_HAL_POWER_DEBUG | ||||||
| #ifdef FURI_HAL_OS_DEBUG |         furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 0); | ||||||
|         furi_hal_gpio_write(&gpio_ext_pb2, 0); |  | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,19 +9,35 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalRandom" | #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() { | uint32_t furi_hal_random_get() { | ||||||
|     while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)) |     while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)) | ||||||
|         ; |         ; | ||||||
|     LL_RNG_Enable(RNG); |     LL_RNG_Enable(RNG); | ||||||
| 
 | 
 | ||||||
|     while(!LL_RNG_IsActiveFlag_DRDY(RNG)) |     const uint32_t random_val = furi_hal_random_read_rng(); | ||||||
|         ; |  | ||||||
| 
 |  | ||||||
|     if((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { |  | ||||||
|         furi_crash("TRNG error"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     uint32_t random_val = LL_RNG_ReadRandData32(RNG); |  | ||||||
| 
 | 
 | ||||||
|     LL_RNG_Disable(RNG); |     LL_RNG_Disable(RNG); | ||||||
|     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); |     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); |     LL_RNG_Enable(RNG); | ||||||
| 
 | 
 | ||||||
|     for(uint32_t i = 0; i < len; i += 4) { |     for(uint32_t i = 0; i < len; i += 4) { | ||||||
|         while(!LL_RNG_IsActiveFlag_DRDY(RNG)) |         const uint32_t random_val = furi_hal_random_read_rng(); | ||||||
|             ; |  | ||||||
| 
 |  | ||||||
|         if((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { |  | ||||||
|             furi_crash("TRNG error"); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t random_val = LL_RNG_ReadRandData32(RNG); |  | ||||||
| 
 |  | ||||||
|         uint8_t len_cur = ((i + 4) < len) ? (4) : (len - i); |         uint8_t len_cur = ((i + 4) < len) ? (4) : (len - i); | ||||||
|         memcpy(&buf[i], &random_val, len_cur); |         memcpy(&buf[i], &random_val, len_cur); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -6,6 +6,9 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalResources" | #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_vibro = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin}; | ||||||
| const GpioPin gpio_ibutton = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin}; | const GpioPin gpio_ibutton = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin}; | ||||||
| 
 | 
 | ||||||
| @ -153,10 +156,11 @@ void furi_hal_resources_init() { | |||||||
|     // Button pins
 |     // Button pins
 | ||||||
|     furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall); |     furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall); | ||||||
| 
 | 
 | ||||||
|     // Explicit pulls pins
 |     // Explicit, surviving reset, pulls
 | ||||||
|     furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow); |     LL_PWR_EnablePUPDCfg(); | ||||||
|     furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow); |     LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_9); // gpio_infrared_tx
 | ||||||
|     furi_hal_gpio_init(&gpio_vibro, GpioModeAnalog, GpioPullDown, GpioSpeedLow); |     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
 |     // Display pins
 | ||||||
|     furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |     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 GpioPinRecord gpio_pins[]; | ||||||
| extern const size_t gpio_pins_count; | 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_vibro; | ||||||
| extern const GpioPin gpio_ibutton; | extern const GpioPin gpio_ibutton; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -165,6 +165,14 @@ void furi_hal_rtc_init() { | |||||||
|     FURI_LOG_I(TAG, "Init OK"); |     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) { | uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg) { | ||||||
|     return LL_RTC_BAK_GetRegister(RTC, reg); |     return LL_RTC_BAK_GetRegister(RTC, reg); | ||||||
| } | } | ||||||
| @ -312,12 +320,7 @@ void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) { | |||||||
|     /* Exit Initialization mode */ |     /* Exit Initialization mode */ | ||||||
|     LL_RTC_DisableInitMode(RTC); |     LL_RTC_DisableInitMode(RTC); | ||||||
| 
 | 
 | ||||||
|     /* If RTC_CR_BYPSHAD bit = 0, wait for synchro else this check is not needed */ |     furi_hal_rtc_sync_shadow(); | ||||||
|     if(!LL_RTC_IsShadowRegBypassEnabled(RTC)) { |  | ||||||
|         LL_RTC_ClearFlag_RS(RTC); |  | ||||||
|         while(!LL_RTC_IsActiveFlag_RS(RTC)) { |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /* Enable write protection */ |     /* Enable write protection */ | ||||||
|     LL_RTC_EnableWriteProtection(RTC); |     LL_RTC_EnableWriteProtection(RTC); | ||||||
|  | |||||||
| @ -29,6 +29,8 @@ int main() { | |||||||
|     FuriThread* main_thread = furi_thread_alloc_ex("Init", 4096, init_task, NULL); |     FuriThread* main_thread = furi_thread_alloc_ex("Init", 4096, init_task, NULL); | ||||||
| 
 | 
 | ||||||
| #ifdef FURI_RAM_EXEC | #ifdef FURI_RAM_EXEC | ||||||
|  |     // Prevent entering sleep mode when executed from RAM
 | ||||||
|  |     furi_hal_power_insomnia_enter(); | ||||||
|     furi_thread_start(main_thread); |     furi_thread_start(main_thread); | ||||||
| #else | #else | ||||||
|     furi_hal_light_sequence("RGB"); |     furi_hal_light_sequence("RGB"); | ||||||
| @ -44,6 +46,7 @@ int main() { | |||||||
|         furi_hal_power_reset(); |         furi_hal_power_reset(); | ||||||
|     } else if(boot_mode == FuriHalRtcBootModeUpdate) { |     } else if(boot_mode == FuriHalRtcBootModeUpdate) { | ||||||
|         furi_hal_light_sequence("rgb BR"); |         furi_hal_light_sequence("rgb BR"); | ||||||
|  |         // Do update
 | ||||||
|         flipper_boot_update_exec(); |         flipper_boot_update_exec(); | ||||||
|         // if things go nice, we shouldn't reach this point.
 |         // if things go nice, we shouldn't reach this point.
 | ||||||
|         // But if we do, abandon to avoid bootloops
 |         // But if we do, abandon to avoid bootloops
 | ||||||
|  | |||||||
| @ -18,6 +18,9 @@ void furi_hal_debug_enable(); | |||||||
| /** Disable MCU debug */ | /** Disable MCU debug */ | ||||||
| void furi_hal_debug_disable(); | void furi_hal_debug_disable(); | ||||||
| 
 | 
 | ||||||
|  | /** Check if GDB debug session is active */ | ||||||
|  | bool furi_hal_debug_is_gdb_session_active(); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -58,12 +58,6 @@ void furi_hal_power_insomnia_exit(); | |||||||
|  */ |  */ | ||||||
| bool furi_hal_power_sleep_available(); | 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
 | /** Go to sleep
 | ||||||
|  */ |  */ | ||||||
| void furi_hal_power_sleep(); | void furi_hal_power_sleep(); | ||||||
|  | |||||||
| @ -30,6 +30,8 @@ typedef enum { | |||||||
|     FuriHalRtcFlagLock = (1 << 2), |     FuriHalRtcFlagLock = (1 << 2), | ||||||
|     FuriHalRtcFlagC2Update = (1 << 3), |     FuriHalRtcFlagC2Update = (1 << 3), | ||||||
|     FuriHalRtcFlagHandOrient = (1 << 4), |     FuriHalRtcFlagHandOrient = (1 << 4), | ||||||
|  |     FuriHalRtcFlagLegacySleep = (1 << 5), | ||||||
|  |     FuriHalRtcFlagStealthMode = (1 << 6), | ||||||
| } FuriHalRtcFlag; | } FuriHalRtcFlag; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -85,6 +87,9 @@ void furi_hal_rtc_deinit_early(); | |||||||
| /** Initialize RTC subsystem */ | /** Initialize RTC subsystem */ | ||||||
| void furi_hal_rtc_init(); | void furi_hal_rtc_init(); | ||||||
| 
 | 
 | ||||||
|  | /** Force sync shadow registers */ | ||||||
|  | void furi_hal_rtc_sync_shadow(); | ||||||
|  | 
 | ||||||
| /** Get RTC register content
 | /** Get RTC register content
 | ||||||
|  * |  * | ||||||
|  * @param[in]  reg   The register identifier |  * @param[in]  reg   The register identifier | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| #include <furi_hal_console.h> | #include <furi_hal_console.h> | ||||||
| #include <furi_hal_power.h> | #include <furi_hal_power.h> | ||||||
| #include <furi_hal_rtc.h> | #include <furi_hal_rtc.h> | ||||||
|  | #include <furi_hal_debug.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| #include <FreeRTOS.h> | #include <FreeRTOS.h> | ||||||
| @ -13,7 +14,7 @@ | |||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| 
 | 
 | ||||||
| PLACE_IN_SECTION("MB_MEM2") const char* __furi_check_message = NULL; | 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 */ | /** Load r12 value to __furi_check_message and store registers to __furi_check_registers */ | ||||||
| #define GET_MESSAGE_AND_STORE_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" \ |                  "str r12, [r11]                    \n" \ | ||||||
|                  "ldr r12, =__furi_check_registers  \n" \ |                  "ldr r12, =__furi_check_registers  \n" \ | ||||||
|                  "stm r12, {r0-r11}                 \n" \ |                  "stm r12, {r0-r11}                 \n" \ | ||||||
|  |                  "str lr, [r12, #48]                \n" \ | ||||||
|                  :                                      \ |                  :                                      \ | ||||||
|                  :                                      \ |                  :                                      \ | ||||||
|                  : "memory"); |                  : "memory"); | ||||||
| @ -61,6 +63,25 @@ static void __furi_put_uint32_as_text(uint32_t data) { | |||||||
|     furi_hal_console_puts(tmp_str); |     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() { | static void __furi_print_stack_info() { | ||||||
|     furi_hal_console_puts("\r\n\tstack watermark: "); |     furi_hal_console_puts("\r\n\tstack watermark: "); | ||||||
|     __furi_put_uint32_as_text(uxTaskGetStackHighWaterMark(NULL) * 4); |     __furi_put_uint32_as_text(uxTaskGetStackHighWaterMark(NULL) * 4); | ||||||
| @ -100,30 +121,41 @@ FURI_NORETURN void __furi_crash() { | |||||||
| 
 | 
 | ||||||
|     if(__furi_check_message == NULL) { |     if(__furi_check_message == NULL) { | ||||||
|         __furi_check_message = "Fatal Error"; |         __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_hal_console_puts("\r\n\033[0;31m[CRASH]"); | ||||||
|     __furi_print_name(isr); |     __furi_print_name(isr); | ||||||
|     furi_hal_console_puts(__furi_check_message); |     furi_hal_console_puts(__furi_check_message); | ||||||
| 
 | 
 | ||||||
|  |     __furi_print_register_info(); | ||||||
|     if(!isr) { |     if(!isr) { | ||||||
|         __furi_print_stack_info(); |         __furi_print_stack_info(); | ||||||
|     } |     } | ||||||
|     __furi_print_heap_info(); |     __furi_print_heap_info(); | ||||||
| 
 | 
 | ||||||
|  | #ifndef FURI_DEBUG | ||||||
|     // Check if debug enabled by DAP
 |     // 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
 |     // 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; |     bool debug = CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk; | ||||||
|     if(debug) { |     if(debug) { | ||||||
|  | #endif | ||||||
|         furi_hal_console_puts("\r\nSystem halted. Connect debugger for more info\r\n"); |         furi_hal_console_puts("\r\nSystem halted. Connect debugger for more info\r\n"); | ||||||
|         furi_hal_console_puts("\033[0m\r\n"); |         furi_hal_console_puts("\033[0m\r\n"); | ||||||
|  |         furi_hal_debug_enable(); | ||||||
|  | 
 | ||||||
|         RESTORE_REGISTERS_AND_HALT_MCU(true); |         RESTORE_REGISTERS_AND_HALT_MCU(true); | ||||||
|  | #ifndef FURI_DEBUG | ||||||
|     } else { |     } else { | ||||||
|         furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message); |         furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message); | ||||||
|         furi_hal_console_puts("\r\nRebooting system.\r\n"); |         furi_hal_console_puts("\r\nRebooting system.\r\n"); | ||||||
|         furi_hal_console_puts("\033[0m\r\n"); |         furi_hal_console_puts("\033[0m\r\n"); | ||||||
|         furi_hal_power_reset(); |         furi_hal_power_reset(); | ||||||
|     } |     } | ||||||
|  | #endif | ||||||
|     __builtin_unreachable(); |     __builtin_unreachable(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -21,6 +21,10 @@ extern "C" { | |||||||
| #define FURI_NORETURN noreturn | #define FURI_NORETURN noreturn | ||||||
| #endif | #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 */ | /** Crash system */ | ||||||
| FURI_NORETURN void __furi_crash(); | FURI_NORETURN void __furi_crash(); | ||||||
| 
 | 
 | ||||||
| @ -47,7 +51,7 @@ FURI_NORETURN void __furi_halt(); | |||||||
| #define furi_check(__e)                            \ | #define furi_check(__e)                            \ | ||||||
|     do {                                           \ |     do {                                           \ | ||||||
|         if(!(__e)) {                               \ |         if(!(__e)) {                               \ | ||||||
|             furi_crash("furi_check failed\r\n"); \ |             furi_crash(__FURI_CHECK_MESSAGE_FLAG); \ | ||||||
|         }                                          \ |         }                                          \ | ||||||
|     } while(0) |     } while(0) | ||||||
| 
 | 
 | ||||||
| @ -56,7 +60,7 @@ FURI_NORETURN void __furi_halt(); | |||||||
| #define furi_assert(__e)                            \ | #define furi_assert(__e)                            \ | ||||||
|     do {                                            \ |     do {                                            \ | ||||||
|         if(!(__e)) {                                \ |         if(!(__e)) {                                \ | ||||||
|             furi_crash("furi_assert failed\r\n"); \ |             furi_crash(__FURI_ASSERT_MESSAGE_FLAG); \ | ||||||
|         }                                           \ |         }                                           \ | ||||||
|     } while(0) |     } while(0) | ||||||
| #else | #else | ||||||
|  | |||||||
| @ -24,6 +24,10 @@ extern "C" { | |||||||
|     }) |     }) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifndef ABS | ||||||
|  | #define ABS(a) ({ (a) < 0 ? -(a) : (a); }) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifndef ROUND_UP_TO | #ifndef ROUND_UP_TO | ||||||
| #define ROUND_UP_TO(a, b)       \ | #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): | def generate(env): | ||||||
|  |     if not env["VERBOSE"]: | ||||||
|  |         env.SetDefault(COPROCOMSTR="\tCOPRO\t${TARGET}") | ||||||
|     env.AddMethod(AddFwProject) |     env.AddMethod(AddFwProject) | ||||||
|     env.AddMethod(DistCommand) |     env.AddMethod(DistCommand) | ||||||
|     env.AddMethod(AddOpenOCDFlashTarget) |     env.AddMethod(AddOpenOCDFlashTarget) | ||||||
| @ -147,7 +149,7 @@ def generate(env): | |||||||
|                         '--stack_file="${COPRO_STACK_BIN}" ' |                         '--stack_file="${COPRO_STACK_BIN}" ' | ||||||
|                         "--stack_addr=${COPRO_STACK_ADDR} ", |                         "--stack_addr=${COPRO_STACK_ADDR} ", | ||||||
|                     ], |                     ], | ||||||
|                     "\tCOPRO\t${TARGET}", |                     "$COPROCOMSTR", | ||||||
|                 ) |                 ) | ||||||
|             ), |             ), | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ class Copro: | |||||||
|         self.mcu_copro = None |         self.mcu_copro = None | ||||||
|         self.logger = logging.getLogger(self.__class__.__name__) |         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): |         if not os.path.isdir(cube_dir): | ||||||
|             raise Exception(f'"{cube_dir}" doesn\'t exists') |             raise Exception(f'"{cube_dir}" doesn\'t exists') | ||||||
|         self.cube_dir = cube_dir |         self.cube_dir = cube_dir | ||||||
| @ -50,7 +50,7 @@ class Copro: | |||||||
|         if not cube_version or not cube_version.startswith("FW.WB"): |         if not cube_version or not cube_version.startswith("FW.WB"): | ||||||
|             raise Exception(f"Incorrect Cube package or version info") |             raise Exception(f"Incorrect Cube package or version info") | ||||||
|         cube_version = cube_version.replace("FW.WB.", "", 1) |         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") |             raise Exception(f"Unsupported cube version") | ||||||
|         self.version = cube_version |         self.version = cube_version | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -335,7 +335,9 @@ class FlipperStorage: | |||||||
| 
 | 
 | ||||||
|     def _check_no_error(self, response, path=None): |     def _check_no_error(self, response, path=None): | ||||||
|         if self.has_error(response): |         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): |     def size(self, path: str): | ||||||
|         """file size on Flipper""" |         """file size on Flipper""" | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ IWDGSTOP:0x1:rw | |||||||
| IWDGSW:0x1:rw | IWDGSW:0x1:rw | ||||||
| IPCCDBA:0x0:rw | IPCCDBA:0x0:rw | ||||||
| ESE:0x1:r | ESE:0x1:r | ||||||
| SFSA:0xD7:r | SFSA:0xD5:r | ||||||
| FSD:0x0:r | FSD:0x0:r | ||||||
| DDS:0x1:r | DDS:0x1:r | ||||||
| C2OPT:0x1:r | C2OPT:0x1:r | ||||||
| @ -22,7 +22,7 @@ NBRSD:0x0:r | |||||||
| SNBRSA:0xD:r | SNBRSA:0xD:r | ||||||
| BRSD:0x0:r | BRSD:0x0:r | ||||||
| SBRSA:0x12:r | SBRSA:0x12:r | ||||||
| SBRV:0x35C00:r | SBRV:0x35400:r | ||||||
| PCROP1A_STRT:0x1FF:r | PCROP1A_STRT:0x1FF:r | ||||||
| PCROP1A_END:0x0:r | PCROP1A_END:0x0:r | ||||||
| PCROP_RDP:0x1:rw | PCROP_RDP:0x1:rw | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| from SCons.Platform import TempFileMunge | from SCons.Platform import TempFileMunge | ||||||
| from SCons.Node import FS | from SCons.Node import FS | ||||||
| from SCons.Errors import UserError | from SCons.Errors import UserError | ||||||
|  | from SCons.Warnings import warn, WarningOnByDefault | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| import os | import os | ||||||
| import multiprocessing | import multiprocessing | ||||||
| @ -246,7 +248,12 @@ known_extapps = [ | |||||||
|     for apptype in apps_to_build_as_faps |     for apptype in apps_to_build_as_faps | ||||||
|     for app in appenv["APPBUILD"].get_apps_of_type(apptype, True) |     for app in appenv["APPBUILD"].get_apps_of_type(apptype, True) | ||||||
| ] | ] | ||||||
|  | incompatible_apps = [] | ||||||
| for app in known_extapps: | 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_artifacts = appenv.BuildAppElf(app) | ||||||
|     app_src_dir = extract_abs_dir(app_artifacts.app._appdir) |     app_src_dir = extract_abs_dir(app_artifacts.app._appdir) | ||||||
|     app_artifacts.installer = [ |     app_artifacts.installer = [ | ||||||
| @ -254,6 +261,13 @@ for app in known_extapps: | |||||||
|         appenv.Install(app_src_dir.Dir("dist").Dir("debug"), app_artifacts.debug), |         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"]: | if appenv["FORCE"]: | ||||||
|     appenv.AlwaysBuild([extapp.compact for extapp in apps_artifacts.values()]) |     appenv.AlwaysBuild([extapp.compact for extapp in apps_artifacts.values()]) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -36,6 +36,7 @@ ENV.AppendUnique( | |||||||
|     ], |     ], | ||||||
|     CPPDEFINES=[ |     CPPDEFINES=[ | ||||||
|         "_GNU_SOURCE", |         "_GNU_SOURCE", | ||||||
|  |         *GetOption("extra_defines"), | ||||||
|     ], |     ], | ||||||
|     LINKFLAGS=[ |     LINKFLAGS=[ | ||||||
|         "-mcpu=cortex-m4", |         "-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", |     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( | AddOption( | ||||||
|     "--extra-ext-apps", |     "--extra-ext-apps", | ||||||
|     action="store", |     action="store", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Aleksandr Kutuzov
						Aleksandr Kutuzov