1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 12:42:30 +04:00

Merge remote-tracking branch 'OFW/dev' into dev

This commit is contained in:
MX
2024-10-14 16:50:56 +03:00
27 changed files with 523 additions and 330 deletions

View File

@@ -445,13 +445,11 @@ static void bt_change_profile(Bt* bt, BtMessage* message) {
*message->profile_instance = NULL; *message->profile_instance = NULL;
} }
} }
if(message->lock) api_lock_unlock(message->lock);
} }
static void bt_close_connection(Bt* bt, BtMessage* message) { static void bt_close_connection(Bt* bt) {
bt_close_rpc_connection(bt); bt_close_rpc_connection(bt);
furi_hal_bt_stop_advertising(); furi_hal_bt_stop_advertising();
if(message->lock) api_lock_unlock(message->lock);
} }
static void bt_apply_settings(Bt* bt) { static void bt_apply_settings(Bt* bt) {
@@ -499,19 +497,13 @@ static void bt_load_settings(Bt* bt) {
} }
static void bt_handle_get_settings(Bt* bt, BtMessage* message) { static void bt_handle_get_settings(Bt* bt, BtMessage* message) {
furi_assert(message->lock);
*message->data.settings = bt->bt_settings; *message->data.settings = bt->bt_settings;
api_lock_unlock(message->lock);
} }
static void bt_handle_set_settings(Bt* bt, BtMessage* message) { static void bt_handle_set_settings(Bt* bt, BtMessage* message) {
furi_assert(message->lock);
bt->bt_settings = *message->data.csettings; bt->bt_settings = *message->data.csettings;
bt_apply_settings(bt); bt_apply_settings(bt);
bt_settings_save(&bt->bt_settings); bt_settings_save(&bt->bt_settings);
api_lock_unlock(message->lock);
} }
static void bt_handle_reload_keys_settings(Bt* bt) { static void bt_handle_reload_keys_settings(Bt* bt) {
@@ -576,6 +568,12 @@ int32_t bt_srv(void* p) {
while(1) { while(1) {
furi_check( furi_check(
furi_message_queue_get(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk); furi_message_queue_get(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk);
FURI_LOG_D(
TAG,
"call %d, lock 0x%p, result 0x%p",
message.type,
(void*)message.lock,
(void*)message.result);
if(message.type == BtMessageTypeUpdateStatus) { if(message.type == BtMessageTypeUpdateStatus) {
// Update view ports // Update view ports
bt_statusbar_update(bt); bt_statusbar_update(bt);
@@ -599,7 +597,7 @@ int32_t bt_srv(void* p) {
} else if(message.type == BtMessageTypeSetProfile) { } else if(message.type == BtMessageTypeSetProfile) {
bt_change_profile(bt, &message); bt_change_profile(bt, &message);
} else if(message.type == BtMessageTypeDisconnect) { } else if(message.type == BtMessageTypeDisconnect) {
bt_close_connection(bt, &message); bt_close_connection(bt);
} else if(message.type == BtMessageTypeForgetBondedDevices) { } else if(message.type == BtMessageTypeForgetBondedDevices) {
bt_keys_storage_delete(bt->keys_storage); bt_keys_storage_delete(bt->keys_storage);
} else if(message.type == BtMessageTypeGetSettings) { } else if(message.type == BtMessageTypeGetSettings) {
@@ -609,6 +607,8 @@ int32_t bt_srv(void* p) {
} else if(message.type == BtMessageTypeReloadKeysSettings) { } else if(message.type == BtMessageTypeReloadKeysSettings) {
bt_handle_reload_keys_settings(bt); bt_handle_reload_keys_settings(bt);
} }
if(message.lock) api_lock_unlock(message.lock);
} }
return 0; return 0;

View File

@@ -54,11 +54,14 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow
ret = file_browser_context->result; ret = file_browser_context->result;
view_holder_set_view(view_holder, NULL); view_holder_set_view(view_holder, NULL);
view_holder_free(view_holder);
file_browser_stop(file_browser); file_browser_stop(file_browser);
file_browser_free(file_browser); file_browser_free(file_browser);
view_holder_free(view_holder);
api_lock_free(file_browser_context->lock); api_lock_free(file_browser_context->lock);
free(file_browser_context); free(file_browser_context);
furi_record_close(RECORD_GUI); furi_record_close(RECORD_GUI);
return ret; return ret;

View File

@@ -67,7 +67,7 @@ static RpcSystemCallbacks rpc_systems[] = {
struct RpcSession { struct RpcSession {
Rpc* rpc; Rpc* rpc;
FuriThreadId thread_id; FuriThread* thread;
RpcHandlerDict_t handlers; RpcHandlerDict_t handlers;
FuriStreamBuffer* stream; FuriStreamBuffer* stream;
@@ -172,7 +172,7 @@ size_t rpc_session_feed(
size_t bytes_sent = furi_stream_buffer_send(session->stream, encoded_bytes, size, timeout); size_t bytes_sent = furi_stream_buffer_send(session->stream, encoded_bytes, size, timeout);
furi_thread_flags_set(session->thread_id, RpcEvtNewData); furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtNewData);
return bytes_sent; return bytes_sent;
} }
@@ -220,7 +220,7 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
break; break;
} else { } else {
/* Save disconnect flag and continue reading buffer */ /* Save disconnect flag and continue reading buffer */
furi_thread_flags_set(session->thread_id, RpcEvtDisconnect); furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect);
} }
} else if(flags & RpcEvtNewData) { } else if(flags & RpcEvtNewData) {
// Just wake thread up // Just wake thread up
@@ -347,32 +347,37 @@ static int32_t rpc_session_worker(void* context) {
return 0; return 0;
} }
static void rpc_session_thread_release_callback( static void rpc_session_thread_pending_callback(void* context, uint32_t arg) {
FuriThread* thread, UNUSED(arg);
FuriThreadState thread_state, RpcSession* session = (RpcSession*)context;
void* context) {
if(thread_state == FuriThreadStateStopped) {
RpcSession* session = (RpcSession*)context;
for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) {
if(rpc_systems[i].free) { if(rpc_systems[i].free) {
(rpc_systems[i].free)(session->system_contexts[i]); (rpc_systems[i].free)(session->system_contexts[i]);
}
} }
free(session->system_contexts); }
free(session->decoded_message); free(session->system_contexts);
RpcHandlerDict_clear(session->handlers); free(session->decoded_message);
furi_stream_buffer_free(session->stream); RpcHandlerDict_clear(session->handlers);
furi_stream_buffer_free(session->stream);
furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever);
if(session->terminated_callback) { if(session->terminated_callback) {
session->terminated_callback(session->context); session->terminated_callback(session->context);
} }
furi_mutex_release(session->callbacks_mutex); furi_mutex_release(session->callbacks_mutex);
furi_mutex_free(session->callbacks_mutex); furi_mutex_free(session->callbacks_mutex);
furi_thread_free(thread); furi_thread_join(session->thread);
free(session); furi_thread_free(session->thread);
free(session);
}
static void
rpc_session_thread_state_callback(FuriThread* thread, FuriThreadState state, void* context) {
UNUSED(thread);
if(state == FuriThreadStateStopped) {
furi_timer_pending_callback(rpc_session_thread_pending_callback, context, 0);
} }
} }
@@ -404,14 +409,12 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) {
}; };
rpc_add_handler(session, PB_Main_stop_session_tag, &rpc_handler); rpc_add_handler(session, PB_Main_stop_session_tag, &rpc_handler);
FuriThread* thread = session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session);
furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session);
session->thread_id = furi_thread_get_id(thread);
furi_thread_set_state_context(thread, session); furi_thread_set_state_context(session->thread, session);
furi_thread_set_state_callback(thread, rpc_session_thread_release_callback); furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback);
furi_thread_start(thread); furi_thread_start(session->thread);
return session; return session;
} }
@@ -423,7 +426,7 @@ void rpc_session_close(RpcSession* session) {
rpc_session_set_send_bytes_callback(session, NULL); rpc_session_set_send_bytes_callback(session, NULL);
rpc_session_set_close_callback(session, NULL); rpc_session_set_close_callback(session, NULL);
rpc_session_set_buffer_is_empty_callback(session, NULL); rpc_session_set_buffer_is_empty_callback(session, NULL);
furi_thread_flags_set(session->thread_id, RpcEvtDisconnect); furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect);
} }
void rpc_on_system_start(void* p) { void rpc_on_system_start(void* p) {

View File

@@ -0,0 +1,88 @@
# Debugging via the Devboard {#dev_board_debugging_guide}
On this page, you'll learn about how debugging via the Wi-Fi Developer Board works. To illustrate this process, we'll start a debug session for Flipper Zero's firmware in VS Code using the native Flipper Build Tool.
***
## Overview
The Developer Board acts as the debug probe, which provides a bridge between the IDE (integrated development environment) with a debugger running on a host computer and the target microcontroller (in your Flipper Zero). The user controls the debugging process on the computer connected to the Developer Board via [Wi-Fi](#dev_board_wifi_connection) or [USB cable](#dev_board_usb_connection).
\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_hardware_CDN.jpg width=700
Data exchange between the Wi-Fi Developer Board and your Flipper Zero is conducted via the Serial Wire Debug interface. The following GPIO pins serve this purpose:
- **Pin 10:** Serial Wire Clock (SWCLK)
- **Pin 12:** Serial Wire Debug Data I/O (SWDIO)
To learn more about Flipper Zero pinout, visit [GPIO & modules in Flipper Docs](https://docs.flipper.net/gpio-and-modules).
***
## Prerequisites
### Step 1. Installing Git
You'll need Git installed on your computer to clone the firmware repository. If you don't have Git, install it following the [official installation guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git).
### Step 2. Building the firmware
Before starting debugging, you need to clone and build Flipper Zero firmware:
1. Open the **Terminal** (on Linux & macOS) or **PowerShell** (on Windows) in the directory where you want to store the firmware source code.
2. Clone the firmware repository:
```
git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git
cd flipperzero-firmware
```
3. Run the **Flipper Build Tool (FBT)** to build the firmware:
```
./fbt
```
***
## Debugging the firmware
From the **flipperzero-firmware** directory that you cloned earlier, run the following command:
```
./fbt flash
```
This will upload the firmware you've just built to your Flipper Zero via the Developer Board. After that, you can start debugging the firmware. We recommend using **VS Code** with the recommended extensions (as described below), and we have pre-made configurations for it.
To debug in **VS Code**, do the following:
1. In VS Code, open the **flipperzero-firmware** directory.
2. You should see a notification about recommended extensions. Install them.
If there were no notifications, open the **Extensions** tab, enter `@recommended` in the search bar, and install the workspace recommendations.
3. Run the `./fbt vscode_dist` command. This will generate the VS Code configuration files needed for debugging.
4. In VS Code, open the **Run and Debug** tab and select a debugger from the dropdown menu:
- **Attach FW (blackmagic):** Can be used via **Wi-Fi** or **USB**
- **Attach FW (DAP):** Can be used via **USB** only
Note that when debugging via USB, you need to make sure the selected debugger matches the debug mode on your Devboard. To check the debug mode on your Devboard, access the Devboard's web interface as described [here](#dev_board_wifi_connection) and check the **USB mode** field. If you want to use a different debug mode, enable this mode by following the steps in [Devboard debug modes](#dev_board_debug_modes).
5. If needed, flash your Flipper Zero with the `./fbt flash` command, then click the ▷ **Start Debugging** button in the debug sidebar to start the debugging session.
6. Note that starting a debug session halts the execution of the firmware, so you'll need to click the I▷ **Continue** button on the toolbar at the top of your VS Code window to continue execution.
\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_VS_Code.jpg width=900
> [!note]
> If you want to use a different debug mode on your Developer Board, visit [Devboard debug modes](#dev_board_debug_modes).
>
> If you want to read logs via the Developer Board, see [Reading logs via the Devboard](#dev_board_reading_logs).
>
> To learn about debugging in VS Code, see [VS Code official guide](https://code.visualstudio.com/docs/editor/debugging).

View File

@@ -0,0 +1,33 @@
# Devboard debug modes {#dev_board_debug_modes}
The Wi-Fi Devboard for Flipper Zero supports **Black Magic** and **DAPLink** debug modes, and you can switch between them depending on your needs. Note that available modes depend on connection:
- **Wi-Fi:** Only **Black Magic** mode is available.
- **USB:** Switch between **Black Magic** (default) and **DAPLink**. Learn more about switching debug modes for USB connection below.
> [!note]
> Black Magic mode doesn't support RTOS threads, but you can still perform other debugging operations.
***
## Switching debug modes for USB connection
Switching debug modes for working via USB has to be done wirelessly (yes, you read that correctly). Additionally, depending on how the Devboard wireless connection is configured, you may need to follow different steps for **Wi-Fi access point mode** or **Wi-Fi client mode**:
1. If the Devboard isn't connected to your Flipper Zero, turn off your Flipper Zero and connect the Developer Board, then turn the device back on.
2. Access the Devboard's web interface:
- [Wi-Fi access point mode](#wifi-access-point)
- [Wi-Fi client mode](#wifi-client-mode)
3. In the **WiFi** tab, click the **USB mode** option and select **BlackMagicProbe** or **DapLink**.
4. Click **SAVE**, then click **REBOOT** to apply the changes.
\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_switching_modes_CDN.jpg width=700
> [!note]
> After switching debug modes on your Devboard, remember to select the same debugger in **VS Code** in the **Run and Debug** tab, and click the ▷ **Start Debugging** button.

View File

@@ -1,104 +1,112 @@
# Firmware update on Developer Board {#dev_board_fw_update} # Firmware update on Developer Board {#dev_board_fw_update}
> [!IMPORTANT] It's important to regularly update your Developer Board to ensure that you have access to the latest features and bug fixes. This page will guide you through the necessary steps to update the firmware of your Developer Board.
>
> It's important to regularly update your Developer Board to ensure that you have access to the latest features and bug fixes.
> This tutorial will guide you through the necessary steps to update the firmware of your Developer Board.
This tutorial assumes that you're familiar with the basics of the command line. > [!note]
> This guide assumes that you're familiar with the basics of the command line. If you're new to it, we recommend checking out these [Windows](https://learn.microsoft.com/en-us/powershell/scripting/learn/ps101/01-getting-started?view=powershell-7.4) or [macOS/Linux](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) command line tutorials.
If youre not, please refer to the [Windows](https://www.digitalcitizen.life/command-prompt-how-use-basic-commands/) or [MacOS / Linux](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) command line tutorials. If youre not, please refer to the [Windows](https://www.digitalcitizen.life/command-prompt-how-use-basic-commands/) or [MacOS / Linux](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) command line tutorials.
## Installing the micro Flipper Build Tool ## Step 1. Install the micro Flipper Build Tool
Micro Flipper Build Tool (uFBT) is a cross-platform tool that enables basic development tasks for Flipper Zero, such as building and debugging applications, flashing firmware, and creating VS Code development configurations. is a cross-platform tool developed and supported by our team that enables basic development tasks for Flipper Zero, such as building and debugging applications, flashing firmware, creating VS Code development configurations, and flashing firmware to the Wi-Fi Developer Board.
Install uFBT on your computer by running the following command in the Terminal: **On Linux & macOS:**
**For Linux & macOS:** Run the following command in the Terminal:
```bash ```
python3 -m pip install --upgrade ufbt python3 -m pip install --upgrade ufbt
``` ```
**For Windows:** **On Windows:**
```powershell 1. Download the latest version of Python on
python -m pip install --upgrade ufbt 2. Run the following command in the PowerShell
```
If you want to learn more about uFBT, visit [the project's page](https://pypi.org/project/ufbt/). ```
py -m pip install --upgrade ufbt
```
## Connecting the Developer Board to your computer ***
## Step 2. Connect the Devboard to PC
To update the firmware, you need to switch your Developer Board to Bootloader mode, connect to a PC via a USB cable, and make sure that the PC detects the Developer Board:
1. List all of the serial devices on your computer. 1. List all of the serial devices on your computer.
**Windows** - **macOS:** Run the `ls /dev/cu.*` command in the Terminal.
On Windows, go to Device Manager and expand the Ports (COM & LPT) section. - **Linux:** Run the `ls /dev/tty*` command in the Terminal.
**macOS** - **Windows:** Go to **Device Manager** and expand the **Ports (COM & LPT)** section.
On macOS, you can run the following command in the Terminal:
```bash
ls /dev/cu.*
```
**Linux**
On Linux, you can run the following command in the Terminal:
```text
ls /dev/tty*
```
View the devices in the list.
2. Connect the Developer Board to your computer using a USB-C cable. 2. Connect the Developer Board to your computer using a USB-C cable.
![The Developer Board in Wired mode](https://github.com/user-attachments/assets/d13e4e90-d83d-45bf-8787-6eadba590795)
4. Switch your Developer Board to Bootloader mode:
3.1. Press and hold the **BOOT** button.
3.2. Press the **RESET** button while holding the **BOOT** button.
3.3. Release the **BOOT** button.
![You can easily switch the Dev Board to Bootloader mode](https://github.com/user-attachments/assets/aecc957f-f37b-4bec-af9f-9efd4837152e)
6. Repeat Step 1 and view the name of your Developer Board that appeared in the list.
For example, on macOS: \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_update_wired_connection.jpg width=700
```shell 3. Switch your Developer Board to Bootloader mode:
/dev/cu.usbmodem01
```
## Flashing the firmware 1. Press and hold the **BOOT** button.
2. Press the **RESET** button while holding the **BOOT** button.
3. Release the **BOOT** button.
To flash the firmware onto your Developer Board, run the following command in the terminal: \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot_to_bootloader.png width=700
```shell 4. Repeat **Step 1** and view the name of your Developer Board that appeared in the list.
***
## Step 3. Flash the firmware
**On Linux & macOS:**
```
python3 -m ufbt devboard_flash python3 -m ufbt devboard_flash
``` ```
**On Windows:** Run the following command in the PowerShell:
```
py -m ufbt devboard_flash
```
You should see the following message: `WiFi board flashed successfully`. You should see the following message: `WiFi board flashed successfully`.
## If flashing failed ### If flashing failed
If you get an error message during the flashing process, such as this: Occasionally, you might get an error message during the flashing process, such as:
```shell ```
A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption. A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption.
``` ```
Or this: *or*
```shell ```
FileNotFoundError: [Errno 2] No such file or directory: '/dev/cu.usbmodem01' FileNotFoundError: [Errno 2] No such file or directory: '/dev/cu.usbmodem01'
``` ```
Try doing the following: To fix it, try doing the following:
* Disconnect the Developer Board from your computer, then reconnect it.
* Use a different USB port on your computer.
* Use a different USB-C cable.
## Finishing the installation - Disconnect the Developer Board from your computer, then reconnect it. After that, switch your Developer Board to Bootloader mode once again, as described in
After flashing the firmware: - Use a different USB port on your computer.
1. Reboot the Developer Board by pressing the **RESET** button. ![Reset the Developer Board](https://github.com/user-attachments/assets/7527dd7b-eaa5-4fac-8d67-7ba52e552756)
3. Disconnect and reconnect the USB-C cable. - Use a different USB-C cable.
***
## Step 4. Finish the installation
1. Reboot the Developer Board by pressing the **RESET** button.
\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot_after_flashing.jpg width=700
2. Disconnect and reconnect the USB-C cable.
You've successfully updated the firmware of your Developer Board!
If you followed the **Get started with the Devboard** guide, you're ready for the next step: [Step 3. Plug the Devboard into Flipper Zero](#dev_board_get_started_step-3).
The Developer Board should appear as a serial device on your computer. Now, you can use it with the Black Magic Debug client of your choice.

View File

@@ -1,175 +1,80 @@
# Get started with the Dev Board {#dev_board_get_started} # Get started with the Dev Board {#dev_board_get_started}
The Wi-Fi Developer Board serves as a tool to debug the Flipper Zero firmware. To debug the firmware, the initial step involves compiling the firmware from its source code. This process enables the debugging functionality within the firmware and generates all the necessary files required for debugging purposes. \image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_developer_board_box_CDN.jpg width=700
> [!IMPORTANT] Before you start using your Devboard, you need to prepare your Flipper Zero and Devboard for debugging. In this guide, we'll walk you through all the necessary steps and provide links to explore the Devboard's capabilities further.
>
> Building and debugging the Flipper Zero firmware is fully supported on MacOS and Linux.
> Support for Windows is in beta test.
## Updating the firmware of your Developer Board
Update the firmware of your Developer Board before using it. For more information, visit [Firmware update on Developer Board](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/update).
## Installing Git
You'll need Git installed on your computer to clone the firmware repository. If you don't have Git, install it by doing the following:
### MacOS
On MacOS, install the **Xcode Command Line Tools** package, which includes Git as one of the pre-installed command-line utilities, by running in the Terminal the following command:
```bash
xcode-select --install
```
### Linux
On Linux, you can install Git using your package manager. For example, on Ubuntu, run in the Terminal the following command:
```bash
sudo apt install git
```
For other distributions, refer to your package manager documentation.
*** ***
## Building the firmware ## Step 1. Enable Debug Mode on your Flipper Zero
First, clone the firmware repository: Since the main purpose of the Developer board is to debug applications on Flipper Zero, you first need to enable Debug Mode. To do so, go to **Settings → System** and set **Debug** to **ON**.
```bash \image html https://cdn.flipperzero.one/Flipper_Zero_enamble_debug_CDN.jpg width=700
git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git
cd flipperzero-firmware
```
Then, run the **Flipper Build Tool** (FBT) to build the firmware: > [!note]
> Debug Mode needs to be re-enabled after each update of Flipper Zero's firmware.
```bash Debug Mode allows you to debug your apps for Flipper Zero, as well as access debugging options in apps via the user interface and CLI. To learn more about Flipper Zero CLI, visit [Command-line interface in Flipper Docs](https://docs.flipper.net/development/cli).
./fbt
``` \image html https://cdn.flipperzero.one/Flipper_Zero_Command_Line_Interface_CDN.jpg width=700
*** ***
## Connecting the Developer Board ## Step 2. Update firmware on the Developer Board
The Developer Board can work in the **Wired** mode and two **Wireless** modes: **Wi-Fi access point (AP)** mode and **Wi-Fi client (STA)** mode. The Wired mode is the simplest to set up, but requires a USB Type-C cable. The Wireless modes are more complex to set up, but they allow you to debug your Flipper Zero wirelessly. The Developer Board comes with stock firmware that may not include all the latest features and bug fixes. To ensure optimal performance, please update your board's firmware using the instructions in [Firmware update on Devboard](#dev_board_fw_update).
> [!TIP] ***
>
> Use the following credentials when connecting to the Developer Board in **Wi-Fi access point** mode:
> Name: **blackmagic**
> Password: **iamwitcher**
## Wired ## Step 3. Plug the Devboard into Flipper Zero {#dev_board_get_started_step-3}
![The Developer Board in Wired mode](https://github.com/user-attachments/assets/32938d4a-20b7-4a53-8b36-608cf0112c9a) Once your Developer Board firmware is up to date, you can proceed to plug it into your Flipper Zero. Two important things to keep in mind:
To connect the Developer Board in **Wired** mode, do the following: 1. **Power off your Flipper Zero before plugging in the Developer Board.**
1. Cold-plug the Developer Board by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on. If you skip this step, you may corrupt the data stored on the microSD card. Connecting external modules with a large capacitive load may affect the microSD card's power supply since both the microSD card and external module are powered from the same 3.3 V power source inside Flipper Zero.
2. On your computer, open the **Terminal** and run the following: 2. **Make sure the Developer Board is inserted all the way in.**
### MacOS If your Flipper Zero isn't in a silicone case, insert the module all the way in so there is no gap between your Flipper Zero and the Devboard. You may need to apply more force to insert it completely. After that, press and hold the **BACK** button to power on your Flipper Zero.
```shell
ls /dev/cu.*
```
### Linux
```bash
ls /dev/tty*
```
Note the list of devices.
3. Connect the Developer Board to your computer via a USB-C cable. \image html https://cdn.flipperzero.one/Flipper_Zero_external_module_without_case_CDN.jpg width=700
4. Rerun the command. Two new devices have to appear: this is the Developer Board. If your Flipper Zero is in a silicone case, insert the module all the way in so there is no gap in the middle between the silicone case and the module. After that, press and hold the **BACK** button to power on your Flipper Zero.
> [!NOTE] \image html https://cdn.flipperzero.one/Flipper_Zero_external_module_with_case_CDN.jpg width=700
>
> If the Developer Board doesn't appear in the list of devices, try using a different cable, USB port, or computer.
<br /> ***
> [!IMPORTANT] ## Step 4. Connect to a computer
>
> Flipper Zero logs can only be viewed when the Developer Board is connected via USB.
> The option to view logs over Wi-Fi will be added in future updates.
> For more information, visit [Reading logs via the Dev Board](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/reading-logs).
## Wireless Now, you can connect the Developer Board to your computer via USB or Wi-Fi, depending on your needs. We described both methods in separate documents:
### Wi-Fi access point (AP) mode - **[Via USB cable](#dev_board_usb_connection)** for debugging in DAP Link or Black Magic mode, and reading logs.
- [Via Wi-Fi](#dev_board_wifi_connection) for debugging in Black Magic mode.
![The Developer Board in Wi-Fi access point mode](https://github.com/user-attachments/assets/1f210e91-3ac8-4f4c-a910-cc7c52b94346) ***
Out of the box, the Developer Board is configured to work as a **Wi-Fi access point**. This means it'll create its own Wi-Fi network to which you can connect. If your Developer Board doesn't create a Wi-Fi network, it is probably configured to work in **Wi-Fi client** mode. To reset your Developer Board back to **Wi-Fi access point** mode, press and hold the **BOOT** button for 10 seconds, then wait for the module to reboot. ## Next steps
![You can reconfigure the Developer Board mode by pressing and holding the BOOT button](https://github.com/user-attachments/assets/8fee05de-fb1e-475a-b23a-d1ddca9cd701) You are ready to debug now! To further explore what you can do with the Devboard, check out these pages:
To connect the Developer Board in **Wi-Fi access point** mode, do the following: - [Debugging via the Devboard](#dev_board_debugging_guide)
- [Devboard debug modes](#dev_board_debug_modes)
- [Reading logs via the Devboard](#dev_board_reading_logs)
1. Cold-plug the Developer Board by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on. These guides should help you get started with your Devboard. If you have any questions or you want to share your experience, don't hesitate to join our community on [Reddit](https://www.reddit.com/r/flipperzero/) and [Discord](https://discord.com/invite/flipper), where we have a dedicated #wifi-devboard channel.
2. Open Wi-Fi settings on your client device (phone, laptop, or other).
3. Connect to the network:
* Name: `blackmagic`
* Password: `iamwitcher`
4. To configure the Developer Board, open a browser and go to `http://192.168.4.1`.
### Wi-Fi client (STA) mode
![The Developer Board in Wi-Fi client mode](https://github.com/user-attachments/assets/42e7e69e-51b0-4914-b082-431c68bc75d3)
To connect the Developer Board in **Wi-Fi client** mode, you need to configure it to connect to your Wi-Fi network by doing the following:
1. Cold-plug the Developer Board by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on.
2. Connect to the Developer Board in **Wi-Fi access point** mode.
3. In a browser, go to the configuration page on `http://192.168.4.1`.
4. Select the **STA** mode and enter your network's **SSID** (name) and **password**. For convenience, you can click the **+** button to see the list of nearby networks.
5. Save the configuration and reboot the Developer Board.
6. In the Wi-Fi tab, you can set the Developer Board mode
![Developer Board mode](https://github.com/user-attachments/assets/fbeea000-1117-4297-8a0d-5d580123e938)
After rebooting, the Developer Board connects to your Wi-Fi network. You can connect to the device using the mDNS name `blackmagic.local` or the IP address it got from your router (you'll have to figure this out yourself, every router is different).
After connecting to your debugger via [http://blackmagic.local](http://blackmagic.local), you can find its IP address in the **SYS** tab. You can also change the debugger's mode to **AP** or **STA** there.
![In the SYS tab, you can view the IP address of your Developer Board](https://github.com/user-attachments/assets/aa3afc64-a2ec-46a6-a827-eea187a97c04)
## Debugging the firmware
Open the **Terminal** in the `flipperzero-firmware` directory that you cloned earlier and run the following command:
```bash
./fbt flash
```
This will upload the firmware you've just built to your Flipper Zero via the Developer Board. After that, you can start debugging the firmware using the [GDB](https://www.gnu.org/software/gdb/) debugger. We recommend using **VSCode** with the recommended extensions, and we have pre-made configurations for it.
To debug in **VSCode**, do the following:
1. In VSCode, open the `flipperzero-firmware` directory.
2. You should see a notification about recommended extensions. Install them.
> [!TIP]
>
> If there were no notifications, open the `Extensions` tab,
> enter `@recommended` in the search bar,
> and install the workspace recommendations.
>
3. In the **Terminal**, run the `./fbt vscode_dist` command. This will generate the VSCode configuration files needed for debugging.
4. In VSCode, open the **Run and Debug** tab and select **Attach FW (blackmagic)** from the dropdown menu.
5. If needed, flash your Flipper Zero with the `./fbt flash` command, then click the **Play** button in the debug sidebar to start the debugging session.
6. Note that starting a debug session halts the execution of the firmware, so you'll need to click the **Continue** button on the toolbar at the top of your VSCode window to continue execution.
![Click Continue in the toolbar to continue execution of the firmware](https://github.com/user-attachments/assets/74f26bdb-8511-4e5a-8aa8-c44212aa6228)
To learn about debugging, visit the following pages:
* [Debugging with GDB](https://sourceware.org/gdb/current/onlinedocs/gdb.pdf)
* [Debugging in VSCode](https://code.visualstudio.com/docs/editor/debugging)

View File

@@ -9,17 +9,17 @@ The Developer Board allows you to read Flipper Zero logs via UART. Unlike readin
## Setting the log level ## Setting the log level
Depending on your needs, you can set the log level by going to **Main Menu → Settings → Log Level**. To learn more about logging levels, visit [Settings](https://docs.flipperzero.one/basics/settings#d5TAt). Depending on your needs, you can set the log level by going to **Main Menu → Settings → Log Level**. To learn more about logging levels, visit [Settings](https://docs.flipper.net/basics/settings#d5TAt).
![You can manually set the preferred log level](https://github.com/user-attachments/assets/b1317d01-8b9b-4544-8720-303c87b85324) \image html https://cdn.flipperzero.one/Flipper_Zero_log_level.jpg "You can manually set the preferred log level" width=700
## Viewing Flipper Zero logs ## Viewing Flipper Zero logs
Depending on your operating system, you need to install an additional application on your computer to read logs via the Developer Board: Depending on your operating system, you need to install an additional application on your computer to read logs via the Developer Board:
### MacOS ### macOS
On MacOS, you need to install the `minicom` communication program by doing the following: On macOS, you need to install the **minicom** communication program by doing the following:
1. [Install Homebrew](https://brew.sh/) by running the following command in the Terminal: 1. [Install Homebrew](https://brew.sh/) by running the following command in the Terminal:
```bash ```bash
@@ -41,9 +41,11 @@ After installation of `minicom` on your macOS computer, you can connect to the D
> >
> The list of devices. > The list of devices.
3. Connect the developer board to your computer using a USB Type-C cable. 3. Connect the developer board to your computer using a USB Type-C cable.
![Connect the developer board with a USB-C cable](https://github.com/user-attachments/assets/0f469a31-2dd1-4559-918a-ff3ca3309531) \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_developer_board_wired.png width=700
5. Rerun the command. Two new devices have to appear: this is the Developer Board.
```bash 4. Rerun the command. Two new devices have to appear: this is the Developer Board.
```text
/dev/cu.usbmodemblackmagic1 /dev/cu.usbmodemblackmagic1
``` ```
```bash ```bash
@@ -81,7 +83,8 @@ After installation of `minicom` on your Linux computer, you can connect to the D
``` ```
Note the list of devices. Note the list of devices.
3. Connect the developer board to your computer using a USB Type-C cable. 3. Connect the developer board to your computer using a USB Type-C cable.
![Connect the developer board with a USB-C cable](https://github.com/user-attachments/assets/0f469a31-2dd1-4559-918a-ff3ca3309531) \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_developer_board_wired.png width=700
4. Rerun the command. Two new devices have to appear: this is the Developer Board. 4. Rerun the command. Two new devices have to appear: this is the Developer Board.
```bash ```bash
/dev/ttyACM0 /dev/ttyACM0
@@ -116,25 +119,17 @@ On Windows, do the following:
1. On your computer, [install the PuTTY application](https://www.chiark.greenend.org.uk/\~sgtatham/putty/latest.html). 1. On your computer, [install the PuTTY application](https://www.chiark.greenend.org.uk/\~sgtatham/putty/latest.html).
2. Cold-plug the Developer Board into your Flipper Zero by turning off the Flipper Zero, connecting the developer board, and then turning it back on. 2. Cold-plug the Developer Board into your Flipper Zero by turning off the Flipper Zero, connecting the developer board, and then turning it back on.
3. Connect the developer board to your computer using a USB Type-C cable. 3. Connect the developer board to your computer using a USB Type-C cable.
![Connect the developer board with a USB-C cable](https://github.com/user-attachments/assets/0f469a31-2dd1-4559-918a-ff3ca3309531) \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_developer_board_wired.png width=700
4. Find the serial port that the developer board is connected to by going to `Device Manager -> Ports (COM & LPT)` and looking for a new port that appears when you connect the Wi-Fi developer board.
![Find the serial port in your Device Manager](https://github.com/user-attachments/assets/aa542fe6-4781-45dc-86f6-e98ab34952b0)
6. Run the `PuTTY` application and select `Serial` as the connection type.
7. Enter the port number you found in the previous step into the `Serial line` field.
8. Set the `Speed` parameter to `230400` and click `Open`.
![Set speed to 230400](https://github.com/user-attachments/assets/93463c78-9776-479b-a6cc-d68ed712d0c4)
10. View logs of your Flipper Zero in the PuTTY terminal window.
11. To quit, close the PuTTY window.
4. Find the serial port that the developer board is connected to by going to **Device Manager → Ports (COM & LPT)** and looking for a new port that appears when you connect the Wi-Fi developer board. 4. Find the serial port that the developer board is connected to by going to **Device Manager → Ports (COM & LPT)** and looking for a new port that appears when you connect the Wi-Fi developer board.
![Find the serial port in your Device Manager](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/KKLQJK1lvqmI5iab3d__C_image.png) \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_Device_Manager.png width=700
5. Run the PuTTY application and select **Serial** as the connection type. 5. Run the PuTTY application and select **Serial** as the connection type.
6. Enter the port number you found in the previous step into the **Serial line** field. 6. Enter the port number you found in the previous step into the **Serial line** field.
7. Set the **Speed** parameter to **230400** and click **Open**. 7. Set the **Speed** parameter to **230400** and click **Open**.
![Set speed to 230400](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/ROBSJyfQ_CXiy4GUZcPbs_monosnap-miro-2023-07-12-13-56-47.jpg) \image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_PuTTy.jpg width=700
8. View logs of your Flipper Zero in the PuTTY terminal window. 8. View logs of your Flipper Zero in the PuTTY terminal window.

View File

@@ -0,0 +1,22 @@
# USB connection to the Devboard {#dev_board_usb_connection}
\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_USB_connection_CDN.jpg width=700
To connect to the Developer Board via USB, do the following:
1. If the Devboard isn't connected to your Flipper Zero, turn off your Flipper Zero and connect the Developer Board to it. Then, turn your Flipper Zero back on.
2. On your computer, check the list of serial devices.
- **macOS:** On your computer, run `ls /dev/cu.*` in the Terminal.
- **Linux:** On your computer, run `ls /dev/tty*` in the Terminal.
- **Windows:** Go to **Device Manager** and expand the **Ports (COM & LPT)** section.
3. Connect the Devboard to your computer via a USB-C cable.
4. Repeat **Step 2**. Two new devices will appear — this is the Developer Board.
> [!warning]
> If the Developer Board doesn't appear in the list of devices, try using a different cable, USB port, or computer.

View File

@@ -0,0 +1,60 @@
# Wi-Fi connection to the Devboard {#dev_board_wifi_connection}
You can connect to the Developer Board wirelessly in two ways:
- **Wi-Fi access point mode (default):** The Devboard creates its own Wi-Fi network, which you can connect to in order to access its web interface and debug via Wi-Fi. The downside is that you will need to disconnect from your current Wi-Fi network, resulting in a loss of internet connection.
- **Wi-Fi client mode:** You can connect to the Devboard through an existing Wi-Fi network, allowing you to access the Devboard web interface and debug via Wi-Fi without losing your internet connection.
Let's go over both of these modes below.
***
## Wi-Fi access point (AP) mode {#wifi-access-point}
\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_Access_Point_CDN.jpg width=700
Out of the box, the Developer Board is configured to work as a Wi-Fi access point. To connect the Developer Board in this mode, do the following:
1. Plug the Wi-Fi Devboard into your Flipper Zero by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on.
2. Open Wi-Fi settings on your client device (phone, laptop, or other).
3. Connect to the network:
Name: `blackmagic`
Password: `iamwitcher`
If your computer fails to find the **blackmagic** network, read the [troubleshooting section](#wifi-access-point_troubleshooting) below.
4. To access the Devboard's web interface, open a browser and go to <http://192.168.4.1> or <http://blackmagic.local>.
### If your computer fails to find the black magic network {#wifi-access-point_troubleshooting}
- Reset Wi-Fi connection on your computer.
- The Developer Board is probably configured to work in Wi-Fi client mode. → Reset your Developer Board settings to default by pressing and holding the **BOOT** button for **10 seconds**, then wait for the Devboard to reboot. After the reset, the Devboard will work in Wi-Fi access point mode.
\image html https://cdn.flipperzero.one/Flipper_Zero_Wi-Fi_devboard_reboot.jpg width=700
***
## Wi-Fi client (STA) mode {#wifi-client-mode}
\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_STA_CDN.jpg width=700
To connect the Developer Board in **Wi-Fi client** mode, you need to configure it to connect to your Wi-Fi network by doing the following:
1. Plug the Wi-Fi Devboard into your Flipper Zero by turning off your Flipper Zero and connecting the Developer Board, and then turning the device back on.
2. Connect to the Developer Board in [Wi-Fi access point](#wifi-access-point) mode.
3. In a browser, go to the Devboard's web interface at <http://192.168.4.1> or <http://blackmagic.local>.
4. Select the **STA** mode and enter your network's **SSID** (name) and **password**. For convenience, you can click the **+** button to see the list of nearby 2.4 GHz networks (5 GHz networks aren't supported).
5. Save the configuration and reboot the Developer Board.
\image html https://cdn.flipperzero.one/Flipper_Zero_WiFi_devboard_connect_to_WiFi_CDN.jpg width=700
6. Now, you can access the Devboard's web interface at [http://blackmagic.local](https://blackmagic.local) via the existing Wi-Fi network without losing connection to the internet.

View File

@@ -61,7 +61,7 @@ Running other tasks, like firmware flashing or building update bundles *for a di
## VSCode integration ## VSCode integration
`fbt` includes basic development environment configuration for VSCode. Run `./fbt vscode_dist` to deploy it. `fbt` includes basic development environment configuration for VS Code. Run `./fbt vscode_dist` to deploy it. That will copy the initial environment configuration to the `.vscode` folder. After that, you can use that configuration by starting VS Code and choosing the firmware root folder in the "File > Open Folder" menu.
That will copy the initial environment configuration to the `.vscode` folder. That will copy the initial environment configuration to the `.vscode` folder.

View File

@@ -33,7 +33,7 @@ bool furi_kernel_is_irq_or_masked(void) {
} }
bool furi_kernel_is_running(void) { bool furi_kernel_is_running(void) {
return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING; return xTaskGetSchedulerState() == taskSCHEDULER_RUNNING;
} }
int32_t furi_kernel_lock(void) { int32_t furi_kernel_lock(void) {
@@ -129,6 +129,8 @@ uint32_t furi_kernel_get_tick_frequency(void) {
void furi_delay_tick(uint32_t ticks) { void furi_delay_tick(uint32_t ticks) {
furi_check(!furi_kernel_is_irq_or_masked()); furi_check(!furi_kernel_is_irq_or_masked());
furi_check(furi_thread_get_current_id() != xTaskGetIdleTaskHandle());
if(ticks == 0U) { if(ticks == 0U) {
taskYIELD(); taskYIELD();
} else { } else {
@@ -138,6 +140,7 @@ void furi_delay_tick(uint32_t ticks) {
FuriStatus furi_delay_until_tick(uint32_t tick) { FuriStatus furi_delay_until_tick(uint32_t tick) {
furi_check(!furi_kernel_is_irq_or_masked()); furi_check(!furi_kernel_is_irq_or_masked());
furi_check(furi_thread_get_current_id() != xTaskGetIdleTaskHandle());
TickType_t tcnt, delay; TickType_t tcnt, delay;
FuriStatus stat; FuriStatus stat;

View File

@@ -108,10 +108,17 @@ void furi_log_puts(const char* data) {
} }
void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) { void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) {
if(level <= furi_log.log_level && do {
furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk) { if(level > furi_log.log_level) {
FuriString* string; break;
string = furi_string_alloc(); }
if(furi_mutex_acquire(furi_log.mutex, furi_kernel_is_running() ? FuriWaitForever : 0) !=
FuriStatusOk) {
break;
}
FuriString* string = furi_string_alloc();
const char* color = _FURI_LOG_CLR_RESET; const char* color = _FURI_LOG_CLR_RESET;
const char* log_letter = " "; const char* log_letter = " ";
@@ -157,7 +164,7 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form
furi_log_puts("\r\n"); furi_log_puts("\r\n");
furi_mutex_release(furi_log.mutex); furi_mutex_release(furi_log.mutex);
} } while(0);
} }
void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) { void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) {

View File

@@ -1,6 +1,7 @@
#include "thread.h" #include "thread_i.h"
#include "thread_list_i.h" #include "thread_list_i.h"
#include "kernel.h" #include "kernel.h"
#include "message_queue.h"
#include "memmgr.h" #include "memmgr.h"
#include "memmgr_heap.h" #include "memmgr_heap.h"
#include "check.h" #include "check.h"
@@ -67,6 +68,8 @@ static_assert(offsetof(FuriThread, container) == 0);
// Our idle priority should be equal to the one from FreeRTOS // Our idle priority should be equal to the one from FreeRTOS
static_assert(FuriThreadPriorityIdle == tskIDLE_PRIORITY); static_assert(FuriThreadPriorityIdle == tskIDLE_PRIORITY);
static FuriMessageQueue* furi_thread_scrub_message_queue = NULL;
static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size); static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size);
static int32_t __furi_thread_stdout_flush(FuriThread* thread); static int32_t __furi_thread_stdout_flush(FuriThread* thread);
@@ -125,7 +128,9 @@ static void furi_thread_body(void* context) {
furi_thread_set_state(thread, FuriThreadStateStopping); furi_thread_set_state(thread, FuriThreadStateStopping);
vTaskDelete(NULL); furi_message_queue_put(furi_thread_scrub_message_queue, &thread, FuriWaitForever);
vTaskSuspend(NULL);
furi_thread_catch(); furi_thread_catch();
} }
@@ -159,6 +164,31 @@ static void furi_thread_init_common(FuriThread* thread) {
} }
} }
void furi_thread_init(void) {
furi_thread_scrub_message_queue = furi_message_queue_alloc(8, sizeof(FuriThread*));
}
void furi_thread_scrub(void) {
FuriThread* thread_to_scrub = NULL;
while(true) {
furi_check(
furi_message_queue_get(
furi_thread_scrub_message_queue, &thread_to_scrub, FuriWaitForever) ==
FuriStatusOk);
TaskHandle_t task = (TaskHandle_t)thread_to_scrub;
// Delete task: FreeRTOS will remove task from all lists where it may be
vTaskDelete(task);
// Sanity check: ensure that local storage is ours and clear it
furi_check(pvTaskGetThreadLocalStoragePointer(task, 0) == thread_to_scrub);
vTaskSetThreadLocalStoragePointer(task, 0, NULL);
// Deliver thread stopped callback
furi_thread_set_state(thread_to_scrub, FuriThreadStateStopped);
}
}
FuriThread* furi_thread_alloc(void) { FuriThread* furi_thread_alloc(void) {
FuriThread* thread = malloc(sizeof(FuriThread)); FuriThread* thread = malloc(sizeof(FuriThread));
@@ -358,16 +388,6 @@ void furi_thread_start(FuriThread* thread) {
&thread->container) == (TaskHandle_t)thread); &thread->container) == (TaskHandle_t)thread);
} }
void furi_thread_cleanup_tcb_event(TaskHandle_t task) {
FuriThread* thread = pvTaskGetThreadLocalStoragePointer(task, 0);
if(thread) {
// clear thread local storage
vTaskSetThreadLocalStoragePointer(task, 0, NULL);
furi_check(thread == (FuriThread*)task);
furi_thread_set_state(thread, FuriThreadStateStopped);
}
}
bool furi_thread_join(FuriThread* thread) { bool furi_thread_join(FuriThread* thread) {
furi_check(thread); furi_check(thread);
// Cannot join a service thread // Cannot join a service thread

View File

@@ -21,10 +21,10 @@ extern "C" {
* Many of the FuriThread functions MUST ONLY be called when the thread is STOPPED. * Many of the FuriThread functions MUST ONLY be called when the thread is STOPPED.
*/ */
typedef enum { typedef enum {
FuriThreadStateStopped, /**< Thread is stopped and is safe to release */ FuriThreadStateStopped, /**< Thread is stopped and is safe to release. Event delivered from system init thread(TCB cleanup routine). It is safe to release thread instance. */
FuriThreadStateStopping, /**< Thread is stopping */ FuriThreadStateStopping, /**< Thread is stopping. Event delivered from child thread. */
FuriThreadStateStarting, /**< Thread is starting */ FuriThreadStateStarting, /**< Thread is starting. Event delivered from parent(self) thread. */
FuriThreadStateRunning, /**< Thread is running */ FuriThreadStateRunning, /**< Thread is running. Event delivered from child thread. */
} FuriThreadState; } FuriThreadState;
/** /**
@@ -32,6 +32,7 @@ typedef enum {
*/ */
typedef enum { typedef enum {
FuriThreadPriorityIdle = 0, /**< Idle priority */ FuriThreadPriorityIdle = 0, /**< Idle priority */
FuriThreadPriorityInit = 4, /**< Init System Thread Priority */
FuriThreadPriorityLowest = 14, /**< Lowest */ FuriThreadPriorityLowest = 14, /**< Lowest */
FuriThreadPriorityLow = 15, /**< Low */ FuriThreadPriorityLow = 15, /**< Low */
FuriThreadPriorityNormal = 16, /**< Normal, system default */ FuriThreadPriorityNormal = 16, /**< Normal, system default */
@@ -77,13 +78,15 @@ typedef int32_t (*FuriThreadCallback)(void* context);
typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size); typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size);
/** /**
* @brief State change callback function pointer type. * @brief State change callback function pointer type.
* *
* The function to be used as a state callback MUST follow this signature. * The function to be used as a state callback MUST follow this
* signature.
* *
* @param[in] pointer to the FuriThread instance that changed the state * @param[in] thread to the FuriThread instance that changed the state
* @param[in] state identifier of the state the thread has transitioned to * @param[in] state identifier of the state the thread has transitioned
* @param[in,out] context pointer to a user-specified object * to
* @param[in,out] context pointer to a user-specified object
*/ */
typedef void (*FuriThreadStateCallback)(FuriThread* thread, FuriThreadState state, void* context); typedef void (*FuriThreadStateCallback)(FuriThread* thread, FuriThreadState state, void* context);

7
furi/core/thread_i.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include "thread.h"
void furi_thread_init(void);
void furi_thread_scrub(void);

View File

@@ -17,12 +17,24 @@ static_assert(offsetof(FuriTimer, container) == 0);
#define TIMER_DELETED_EVENT (1U << 0) #define TIMER_DELETED_EVENT (1U << 0)
static void TimerCallback(TimerHandle_t hTimer) { static void furi_timer_callback(TimerHandle_t hTimer) {
FuriTimer* instance = pvTimerGetTimerID(hTimer); FuriTimer* instance = pvTimerGetTimerID(hTimer);
furi_check(instance); furi_check(instance);
instance->cb_func(instance->cb_context); instance->cb_func(instance->cb_context);
} }
static void furi_timer_flush_epilogue(void* context, uint32_t arg) {
furi_assert(context);
UNUSED(arg);
EventGroupHandle_t hEvent = context;
// See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/1142
vTaskSuspendAll();
xEventGroupSetBits(hEvent, TIMER_DELETED_EVENT);
(void)xTaskResumeAll();
}
FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* context) { FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* context) {
furi_check((furi_kernel_is_irq_or_masked() == 0U) && (func != NULL)); furi_check((furi_kernel_is_irq_or_masked() == 0U) && (func != NULL));
@@ -33,23 +45,13 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co
const UBaseType_t reload = (type == FuriTimerTypeOnce ? pdFALSE : pdTRUE); const UBaseType_t reload = (type == FuriTimerTypeOnce ? pdFALSE : pdTRUE);
const TimerHandle_t hTimer = xTimerCreateStatic( const TimerHandle_t hTimer = xTimerCreateStatic(
NULL, portMAX_DELAY, reload, instance, TimerCallback, &instance->container); NULL, portMAX_DELAY, reload, instance, furi_timer_callback, &instance->container);
furi_check(hTimer == (TimerHandle_t)instance); furi_check(hTimer == (TimerHandle_t)instance);
return instance; return instance;
} }
static void furi_timer_epilogue(void* context, uint32_t arg) {
furi_assert(context);
UNUSED(arg);
EventGroupHandle_t hEvent = context;
vTaskSuspendAll();
xEventGroupSetBits(hEvent, TIMER_DELETED_EVENT);
(void)xTaskResumeAll();
}
void furi_timer_free(FuriTimer* instance) { void furi_timer_free(FuriTimer* instance) {
furi_check(!furi_kernel_is_irq_or_masked()); furi_check(!furi_kernel_is_irq_or_masked());
furi_check(instance); furi_check(instance);
@@ -57,16 +59,21 @@ void furi_timer_free(FuriTimer* instance) {
TimerHandle_t hTimer = (TimerHandle_t)instance; TimerHandle_t hTimer = (TimerHandle_t)instance;
furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS); furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS);
furi_timer_flush();
free(instance);
}
void furi_timer_flush(void) {
StaticEventGroup_t event_container = {}; StaticEventGroup_t event_container = {};
EventGroupHandle_t hEvent = xEventGroupCreateStatic(&event_container); EventGroupHandle_t hEvent = xEventGroupCreateStatic(&event_container);
furi_check(xTimerPendFunctionCall(furi_timer_epilogue, hEvent, 0, portMAX_DELAY) == pdPASS); furi_check(
xTimerPendFunctionCall(furi_timer_flush_epilogue, hEvent, 0, portMAX_DELAY) == pdPASS);
furi_check( furi_check(
xEventGroupWaitBits(hEvent, TIMER_DELETED_EVENT, pdFALSE, pdTRUE, portMAX_DELAY) == xEventGroupWaitBits(hEvent, TIMER_DELETED_EVENT, pdFALSE, pdTRUE, portMAX_DELAY) ==
TIMER_DELETED_EVENT); TIMER_DELETED_EVENT);
vEventGroupDelete(hEvent); vEventGroupDelete(hEvent);
free(instance);
} }
FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) {
@@ -112,6 +119,8 @@ FuriStatus furi_timer_stop(FuriTimer* instance) {
furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS);
furi_timer_flush();
return FuriStatusOk; return FuriStatusOk;
} }

View File

@@ -35,6 +35,12 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co
*/ */
void furi_timer_free(FuriTimer* instance); void furi_timer_free(FuriTimer* instance);
/** Flush timer task control message queue
*
* Ensures that all commands before this point was processed.
*/
void furi_timer_flush(void);
/** Start timer /** Start timer
* *
* @warning This is asynchronous call, real operation will happen as soon as * @warning This is asynchronous call, real operation will happen as soon as
@@ -61,8 +67,7 @@ FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks);
/** Stop timer /** Stop timer
* *
* @warning This is asynchronous call, real operation will happen as soon as * @warning This is synchronous call that will be blocked till timer queue processed.
* timer service process this request.
* *
* @param instance The pointer to FuriTimer instance * @param instance The pointer to FuriTimer instance
* *

View File

@@ -1,5 +1,7 @@
#include "furi.h" #include "furi.h"
#include "core/thread_i.h"
#include <FreeRTOS.h> #include <FreeRTOS.h>
#include <queue.h> #include <queue.h>
@@ -7,6 +9,7 @@ void furi_init(void) {
furi_check(!furi_kernel_is_irq_or_masked()); furi_check(!furi_kernel_is_irq_or_masked());
furi_check(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED); furi_check(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED);
furi_thread_init();
furi_log_init(); furi_log_init();
furi_record_init(); furi_record_init();
} }
@@ -18,3 +21,7 @@ void furi_run(void) {
/* Start the kernel scheduler */ /* Start the kernel scheduler */
vTaskStartScheduler(); vTaskStartScheduler();
} }
void furi_background(void) {
furi_thread_scrub();
}

View File

@@ -35,6 +35,8 @@ void furi_init(void);
void furi_run(void); void furi_run(void);
void furi_background(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,76.0,, Version,+,77.0,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
@@ -1102,6 +1102,7 @@ Function,-,ftello,off_t,FILE*
Function,-,ftrylockfile,int,FILE* Function,-,ftrylockfile,int,FILE*
Function,-,funlockfile,void,FILE* Function,-,funlockfile,void,FILE*
Function,-,funopen,FILE*,"const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)" Function,-,funopen,FILE*,"const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)"
Function,-,furi_background,void,
Function,+,furi_delay_ms,void,uint32_t Function,+,furi_delay_ms,void,uint32_t
Function,+,furi_delay_tick,void,uint32_t Function,+,furi_delay_tick,void,uint32_t
Function,+,furi_delay_until_tick,FuriStatus,uint32_t Function,+,furi_delay_until_tick,FuriStatus,uint32_t
@@ -1672,6 +1673,7 @@ Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
Function,+,furi_thread_suspend,void,FuriThreadId Function,+,furi_thread_suspend,void,FuriThreadId
Function,+,furi_thread_yield,void, Function,+,furi_thread_yield,void,
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
Function,+,furi_timer_flush,void,
Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_free,void,FuriTimer*
Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer* Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer*
Function,+,furi_timer_is_running,uint32_t,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer*
1 entry status name type params
2 Version + 76.0 77.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/bt/bt_service/bt_keys_storage.h
5 Header + applications/services/cli/cli.h
1102 Function - ftrylockfile int FILE*
1103 Function - funlockfile void FILE*
1104 Function - funopen FILE* const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)
1105 Function - furi_background void
1106 Function + furi_delay_ms void uint32_t
1107 Function + furi_delay_tick void uint32_t
1108 Function + furi_delay_until_tick FuriStatus uint32_t
1673 Function + furi_thread_suspend void FuriThreadId
1674 Function + furi_thread_yield void
1675 Function + furi_timer_alloc FuriTimer* FuriTimerCallback, FuriTimerType, void*
1676 Function + furi_timer_flush void
1677 Function + furi_timer_free void FuriTimer*
1678 Function + furi_timer_get_expire_time uint32_t FuriTimer*
1679 Function + furi_timer_is_running uint32_t FuriTimer*

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,76.0,, Version,+,77.0,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
@@ -1243,6 +1243,7 @@ Function,-,ftello,off_t,FILE*
Function,-,ftrylockfile,int,FILE* Function,-,ftrylockfile,int,FILE*
Function,-,funlockfile,void,FILE* Function,-,funlockfile,void,FILE*
Function,-,funopen,FILE*,"const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)" Function,-,funopen,FILE*,"const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)"
Function,-,furi_background,void,
Function,+,furi_delay_ms,void,uint32_t Function,+,furi_delay_ms,void,uint32_t
Function,+,furi_delay_tick,void,uint32_t Function,+,furi_delay_tick,void,uint32_t
Function,+,furi_delay_until_tick,FuriStatus,uint32_t Function,+,furi_delay_until_tick,FuriStatus,uint32_t
@@ -1936,6 +1937,7 @@ Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
Function,+,furi_thread_suspend,void,FuriThreadId Function,+,furi_thread_suspend,void,FuriThreadId
Function,+,furi_thread_yield,void, Function,+,furi_thread_yield,void,
Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*"
Function,+,furi_timer_flush,void,
Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_free,void,FuriTimer*
Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer* Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer*
Function,+,furi_timer_is_running,uint32_t,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer*
1 entry status name type params
2 Version + 76.0 77.0
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/bt/bt_service/bt_keys_storage.h
1243 Function - ftrylockfile int FILE*
1244 Function - funlockfile void FILE*
1245 Function - funopen FILE* const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)
1246 Function - furi_background void
1247 Function + furi_delay_ms void uint32_t
1248 Function + furi_delay_tick void uint32_t
1249 Function + furi_delay_until_tick FuriStatus uint32_t
1937 Function + furi_thread_suspend void FuriThreadId
1938 Function + furi_thread_yield void
1939 Function + furi_timer_alloc FuriTimer* FuriTimerCallback, FuriTimerType, void*
1940 Function + furi_timer_flush void
1941 Function + furi_timer_free void FuriTimer*
1942 Function + furi_timer_get_expire_time uint32_t FuriTimer*
1943 Function + furi_timer_is_running uint32_t FuriTimer*

View File

@@ -87,6 +87,8 @@ void ble_glue_init(void) {
TL_Init(); TL_Init();
ble_glue->shci_mtx = furi_mutex_alloc(FuriMutexTypeNormal); ble_glue->shci_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
// Take mutex, SHCI will release it in most unusual way later
furi_check(furi_mutex_acquire(ble_glue->shci_mtx, FuriWaitForever) == FuriStatusOk);
// FreeRTOS system task creation // FreeRTOS system task creation
ble_event_thread_start(); ble_event_thread_start();
@@ -248,7 +250,9 @@ void ble_glue_stop(void) {
ble_event_thread_stop(); ble_event_thread_stop();
// Free resources // Free resources
furi_mutex_free(ble_glue->shci_mtx); furi_mutex_free(ble_glue->shci_mtx);
ble_glue->shci_mtx = NULL;
furi_timer_free(ble_glue->hardfault_check_timer); furi_timer_free(ble_glue->hardfault_check_timer);
ble_glue->hardfault_check_timer = NULL;
ble_glue_clear_shared_memory(); ble_glue_clear_shared_memory();
free(ble_glue); free(ble_glue);
@@ -309,10 +313,13 @@ BleGlueCommandResult ble_glue_force_c2_mode(BleGlueC2Mode desired_mode) {
static void ble_sys_status_not_callback(SHCI_TL_CmdStatus_t status) { static void ble_sys_status_not_callback(SHCI_TL_CmdStatus_t status) {
switch(status) { switch(status) {
case SHCI_TL_CmdBusy: case SHCI_TL_CmdBusy:
furi_mutex_acquire(ble_glue->shci_mtx, FuriWaitForever); furi_check(
furi_mutex_acquire(
ble_glue->shci_mtx, furi_kernel_is_running() ? FuriWaitForever : 0) ==
FuriStatusOk);
break; break;
case SHCI_TL_CmdAvailable: case SHCI_TL_CmdAvailable:
furi_mutex_release(ble_glue->shci_mtx); furi_check(furi_mutex_release(ble_glue->shci_mtx) == FuriStatusOk);
break; break;
default: default:
break; break;

View File

@@ -144,7 +144,7 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) {
event_pckt = (hci_event_pckt*)((hci_uart_pckt*)pckt)->data; event_pckt = (hci_event_pckt*)((hci_uart_pckt*)pckt)->data;
furi_check(gap); furi_check(gap);
furi_mutex_acquire(gap->state_mutex, FuriWaitForever); furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
switch(event_pckt->evt) { switch(event_pckt->evt) {
case HCI_DISCONNECTION_COMPLETE_EVT_CODE: { case HCI_DISCONNECTION_COMPLETE_EVT_CODE: {
@@ -328,7 +328,7 @@ BleEventFlowStatus ble_event_app_notification(void* pckt) {
break; break;
} }
furi_mutex_release(gap->state_mutex); furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk);
return BleEventFlowEnable; return BleEventFlowEnable;
} }
@@ -514,7 +514,7 @@ static void gap_advertise_stop(void) {
} }
void gap_start_advertising(void) { void gap_start_advertising(void) {
furi_mutex_acquire(gap->state_mutex, FuriWaitForever); furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
if(gap->state == GapStateIdle) { if(gap->state == GapStateIdle) {
gap->state = GapStateStartingAdv; gap->state = GapStateStartingAdv;
FURI_LOG_I(TAG, "Start advertising"); FURI_LOG_I(TAG, "Start advertising");
@@ -522,18 +522,18 @@ void gap_start_advertising(void) {
GapCommand command = GapCommandAdvFast; GapCommand command = GapCommandAdvFast;
furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk); furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk);
} }
furi_mutex_release(gap->state_mutex); furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk);
} }
void gap_stop_advertising(void) { void gap_stop_advertising(void) {
furi_mutex_acquire(gap->state_mutex, FuriWaitForever); furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
if(gap->state > GapStateIdle) { if(gap->state > GapStateIdle) {
FURI_LOG_I(TAG, "Stop advertising"); FURI_LOG_I(TAG, "Stop advertising");
gap->enable_adv = false; gap->enable_adv = false;
GapCommand command = GapCommandAdvStop; GapCommand command = GapCommandAdvStop;
furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk); furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk);
} }
furi_mutex_release(gap->state_mutex); furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk);
} }
static void gap_advertise_timer_callback(void* context) { static void gap_advertise_timer_callback(void* context) {
@@ -604,9 +604,9 @@ uint32_t gap_get_remote_conn_rssi(int8_t* rssi) {
GapState gap_get_state(void) { GapState gap_get_state(void) {
GapState state; GapState state;
if(gap) { if(gap) {
furi_mutex_acquire(gap->state_mutex, FuriWaitForever); furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
state = gap->state; state = gap->state;
furi_mutex_release(gap->state_mutex); furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk);
} else { } else {
state = GapStateUninitialized; state = GapStateUninitialized;
} }
@@ -615,17 +615,21 @@ GapState gap_get_state(void) {
void gap_thread_stop(void) { void gap_thread_stop(void) {
if(gap) { if(gap) {
furi_mutex_acquire(gap->state_mutex, FuriWaitForever); furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
gap->enable_adv = false; gap->enable_adv = false;
GapCommand command = GapCommandKillThread; GapCommand command = GapCommandKillThread;
furi_message_queue_put(gap->command_queue, &command, FuriWaitForever); furi_message_queue_put(gap->command_queue, &command, FuriWaitForever);
furi_mutex_release(gap->state_mutex); furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk);
furi_thread_join(gap->thread); furi_thread_join(gap->thread);
furi_thread_free(gap->thread); furi_thread_free(gap->thread);
gap->thread = NULL;
// Free resources // Free resources
furi_mutex_free(gap->state_mutex); furi_mutex_free(gap->state_mutex);
gap->state_mutex = NULL;
furi_message_queue_free(gap->command_queue); furi_message_queue_free(gap->command_queue);
gap->command_queue = NULL;
furi_timer_free(gap->advertise_timer); furi_timer_free(gap->advertise_timer);
gap->advertise_timer = NULL;
ble_event_dispatcher_reset(); ble_event_dispatcher_reset();
free(gap); free(gap);
@@ -642,7 +646,7 @@ static int32_t gap_app(void* context) {
FURI_LOG_E(TAG, "Message queue get error: %d", status); FURI_LOG_E(TAG, "Message queue get error: %d", status);
continue; continue;
} }
furi_mutex_acquire(gap->state_mutex, FuriWaitForever); furi_check(furi_mutex_acquire(gap->state_mutex, FuriWaitForever) == FuriStatusOk);
if(command == GapCommandKillThread) { if(command == GapCommandKillThread) {
break; break;
} }
@@ -653,7 +657,7 @@ static int32_t gap_app(void* context) {
} else if(command == GapCommandAdvStop) { } else if(command == GapCommandAdvStop) {
gap_advertise_stop(); gap_advertise_stop();
} }
furi_mutex_release(gap->state_mutex); furi_check(furi_mutex_release(gap->state_mutex) == FuriStatusOk);
} }
return 0; return 0;

View File

@@ -202,7 +202,7 @@ bool furi_hal_spi_bus_trx_dma(
furi_check(size > 0); furi_check(size > 0);
// If scheduler is not running, use blocking mode // If scheduler is not running, use blocking mode
if(furi_kernel_is_running()) { if(!furi_kernel_is_running()) {
return furi_hal_spi_bus_trx(handle, tx_buffer, rx_buffer, size, timeout_ms); return furi_hal_spi_bus_trx(handle, tx_buffer, rx_buffer, size, timeout_ms);
} }

View File

@@ -84,6 +84,7 @@ to exclude the API function. */
#define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
/* Workaround for various notification issues: /* Workaround for various notification issues:
* - First one used by system primitives * - First one used by system primitives
@@ -129,25 +130,11 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY \ #define configMAX_SYSCALL_INTERRUPT_PRIORITY \
(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
#ifdef DEBUG
#include <core/check.h>
#define configASSERT(x) \
if((x) == 0) { \
furi_crash("FreeRTOS Assert"); \
}
#endif
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */ standard names. */
#define vPortSVCHandler SVC_Handler #define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler #define xPortPendSVHandler PendSV_Handler
#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION \
1 /* required only for Keil but does not hurt otherwise */
#define traceTASK_SWITCHED_IN() \ #define traceTASK_SWITCHED_IN() \
extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \ extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \
furi_hal_mpu_set_stack_protection((uint32_t*)pxCurrentTCB->pxStack); \ furi_hal_mpu_set_stack_protection((uint32_t*)pxCurrentTCB->pxStack); \
@@ -157,6 +144,14 @@ standard names. */
// referencing `FreeRTOS_errno' here vvvvv because FreeRTOS calls our hook _before_ copying the value into the TCB, hence a manual write to the TCB would get overwritten // referencing `FreeRTOS_errno' here vvvvv because FreeRTOS calls our hook _before_ copying the value into the TCB, hence a manual write to the TCB would get overwritten
#define traceTASK_SWITCHED_OUT() FreeRTOS_errno = errno #define traceTASK_SWITCHED_OUT() FreeRTOS_errno = errno
#define portCLEAN_UP_TCB(pxTCB) \ /* Normal assert() semantics without relying on the provision of an assert.h
extern void furi_thread_cleanup_tcb_event(TaskHandle_t task); \ header file. */
furi_thread_cleanup_tcb_event(pxTCB) #ifdef DEBUG
#define configASSERT(x) \
if((x) == 0) { \
furi_crash("FreeRTOS Assert"); \
}
#endif
// Must be last line of config because of recursion
#include <core/check.h>

View File

@@ -15,6 +15,8 @@ int32_t init_task(void* context) {
// Init flipper // Init flipper
flipper_init(); flipper_init();
furi_background();
return 0; return 0;
} }
@@ -25,7 +27,8 @@ int main(void) {
// Flipper critical FURI HAL // Flipper critical FURI HAL
furi_hal_init_early(); furi_hal_init_early();
FuriThread* main_thread = furi_thread_alloc_ex("Init", 4096, init_task, NULL); FuriThread* main_thread = furi_thread_alloc_ex("InitSrv", 1024, init_task, NULL);
furi_thread_set_priority(main_thread, FuriThreadPriorityInit);
#ifdef FURI_RAM_EXEC #ifdef FURI_RAM_EXEC
// Prevent entering sleep mode when executed from RAM // Prevent entering sleep mode when executed from RAM