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

Merge branch 'fz-dev' into dev

This commit is contained in:
MX
2023-02-08 12:09:57 +03:00
199 changed files with 6363 additions and 2393 deletions

View File

@@ -11,5 +11,8 @@
"augustocdias.tasks-shell-input" "augustocdias.tasks-shell-input"
], ],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace. // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [] "unwantedRecommendations": [
"twxs.cmake",
"ms-vscode.cmake-tools"
]
} }

View File

@@ -2,6 +2,7 @@ App(
appid="accessor", appid="accessor",
name="Accessor", name="Accessor",
apptype=FlipperAppType.DEBUG, apptype=FlipperAppType.DEBUG,
targets=["f7"],
entry_point="accessor_app", entry_point="accessor_app",
cdefines=["APP_ACCESSOR"], cdefines=["APP_ACCESSOR"],
requires=["gui"], requires=["gui"],

View File

@@ -1,7 +1,7 @@
#include "bt_carrier_test.h" #include "bt_carrier_test.h"
#include "bt_test.h" #include "bt_test.h"
#include "bt_test_types.h" #include "bt_test_types.h"
#include "furi_hal_bt.h" #include <furi_hal_bt.h>
struct BtCarrierTest { struct BtCarrierTest {
BtTest* bt_test; BtTest* bt_test;

View File

@@ -1,7 +1,7 @@
#include "bt_packet_test.h" #include "bt_packet_test.h"
#include "bt_test.h" #include "bt_test.h"
#include "bt_test_types.h" #include "bt_test_types.h"
#include "furi_hal_bt.h" #include <furi_hal_bt.h>
struct BtPacketTest { struct BtPacketTest {
BtTest* bt_test; BtTest* bt_test;

View File

@@ -1,10 +1,11 @@
#include <file_browser_test_icons.h>
#include "file_browser_app_i.h" #include "file_browser_app_i.h"
#include "gui/modules/file_browser.h" #include <file_browser_test_icons.h>
#include <furi.h>
#include <furi_hal.h> #include <gui/modules/file_browser.h>
#include <storage/storage.h> #include <storage/storage.h>
#include <lib/toolbox/path.h> #include <lib/toolbox/path.h>
#include <furi.h>
#include <furi_hal.h>
static bool file_browser_app_custom_event_callback(void* context, uint32_t event) { static bool file_browser_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context); furi_assert(context);

View File

@@ -2,6 +2,7 @@ App(
appid="lfrfid_debug", appid="lfrfid_debug",
name="LF-RFID Debug", name="LF-RFID Debug",
apptype=FlipperAppType.DEBUG, apptype=FlipperAppType.DEBUG,
targets=["f7"],
entry_point="lfrfid_debug_app", entry_point="lfrfid_debug_app",
requires=[ requires=[
"gui", "gui",

View File

@@ -89,7 +89,7 @@ static void test_rpc_setup(void) {
} }
furi_check(rpc_session[0].session); furi_check(rpc_session[0].session);
rpc_session[0].output_stream = furi_stream_buffer_alloc(1000, 1); rpc_session[0].output_stream = furi_stream_buffer_alloc(4096, 1);
rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback); rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback);
rpc_session[0].close_session_semaphore = xSemaphoreCreateBinary(); rpc_session[0].close_session_semaphore = xSemaphoreCreateBinary();
rpc_session[0].terminate_semaphore = xSemaphoreCreateBinary(); rpc_session[0].terminate_semaphore = xSemaphoreCreateBinary();

View File

@@ -0,0 +1,44 @@
# 1-Wire Thermometer
This example application demonstrates the use of the 1-Wire library with a DS18B20 thermometer.
It also covers basic GUI, input handling, threads and localisation.
## Electrical connections
Before launching the application, connect the sensor to Flipper's external GPIO according to the table below:
| DS18B20 | Flipper |
| :-----: | :-----: |
| VDD | 9 |
| GND | 18 |
| DQ | 17 |
*NOTE 1*: GND is also available on pins 8 and 11.
*NOTE 2*: For any other pin than 17, connect an external 4.7k pull-up resistor to pin 9.
## Launching the application
In order to launch this demo, follow the steps below:
1. Make sure your Flipper has an SD card installed.
2. Connect your Flipper to the computer via a USB cable.
3. Run `./fbt launch_app APPSRC=example_thermo` in your terminal emulator of choice.
## Changing the data pin
It is possible to use other GPIO pin as a 1-Wire data pin. In order to change it, set the `THERMO_GPIO_PIN` macro to any of the options listed below:
```c
/* Possible GPIO pin choices:
- gpio_ext_pc0
- gpio_ext_pc1
- gpio_ext_pc3
- gpio_ext_pb2
- gpio_ext_pb3
- gpio_ext_pa4
- gpio_ext_pa6
- gpio_ext_pa7
- ibutton_gpio
*/
#define THERMO_GPIO_PIN (ibutton_gpio)
```
Do not forget about the external pull-up resistor as these pins do not have one built-in.
With the changes been made, recompile and launch the application again.
The on-screen text should reflect it by asking to connect the thermometer to another pin.

View File

@@ -0,0 +1,10 @@
App(
appid="example_thermo",
name="Example: Thermometer",
apptype=FlipperAppType.EXTERNAL,
entry_point="example_thermo_main",
requires=["gui"],
stack_size=1 * 1024,
fap_icon="example_thermo_10px.png",
fap_category="Examples",
)

View File

@@ -0,0 +1,356 @@
/*
* This file contains an example application that reads and displays
* the temperature from a DS18B20 1-wire thermometer.
*
* It also covers basic GUI, input handling, threads and localisation.
*
* References:
* [1] DS18B20 Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/DS18B20.pdf
*/
#include <gui/gui.h>
#include <gui/view_port.h>
#include <core/thread.h>
#include <core/kernel.h>
#include <locale/locale.h>
#include <one_wire/maxim_crc.h>
#include <one_wire/one_wire_host.h>
#define UPDATE_PERIOD_MS 1000UL
#define TEXT_STORE_SIZE 64U
#define DS18B20_CMD_CONVERT 0x44U
#define DS18B20_CMD_READ_SCRATCHPAD 0xbeU
#define DS18B20_CFG_RESOLUTION_POS 5U
#define DS18B20_CFG_RESOLUTION_MASK 0x03U
#define DS18B20_DECIMAL_PART_MASK 0x0fU
#define DS18B20_SIGN_MASK 0xf0U
/* Possible GPIO pin choices:
- gpio_ext_pc0
- gpio_ext_pc1
- gpio_ext_pc3
- gpio_ext_pb2
- gpio_ext_pb3
- gpio_ext_pa4
- gpio_ext_pa6
- gpio_ext_pa7
- ibutton_gpio
*/
#define THERMO_GPIO_PIN (ibutton_gpio)
/* Flags which the reader thread responds to */
typedef enum {
ReaderThreadFlagExit = 1,
} ReaderThreadFlag;
typedef union {
struct {
uint8_t temp_lsb; /* Least significant byte of the temperature */
uint8_t temp_msb; /* Most significant byte of the temperature */
uint8_t user_alarm_high; /* User register 1 (Temp high alarm) */
uint8_t user_alarm_low; /* User register 2 (Temp low alarm) */
uint8_t config; /* Configuration register */
uint8_t reserved[3]; /* Not used */
uint8_t crc; /* CRC checksum for error detection */
} fields;
uint8_t bytes[9];
} DS18B20Scratchpad;
/* Application context structure */
typedef struct {
Gui* gui;
ViewPort* view_port;
FuriThread* reader_thread;
FuriMessageQueue* event_queue;
OneWireHost* onewire;
float temp_celsius;
bool has_device;
} ExampleThermoContext;
/*************** 1-Wire Communication and Processing *****************/
/* Commands the thermometer to begin measuring the temperature. */
static void example_thermo_request_temperature(ExampleThermoContext* context) {
OneWireHost* onewire = context->onewire;
/* All 1-wire transactions must happen in a critical section, i.e
not interrupted by other threads. */
FURI_CRITICAL_ENTER();
bool success = false;
do {
/* Each communication with a 1-wire device starts by a reset.
The functon will return true if a device responded with a presence pulse. */
if(!onewire_host_reset(onewire)) break;
/* After the reset, a ROM operation must follow.
If there is only one device connected, the "Skip ROM" command is most appropriate
(it can also be used to address all of the connected devices in some cases).*/
onewire_host_skip(onewire);
/* After the ROM operation, a device-specific command is issued.
In this case, it's a request to start measuring the temperature. */
onewire_host_write(onewire, DS18B20_CMD_CONVERT);
success = true;
} while(false);
context->has_device = success;
FURI_CRITICAL_EXIT();
}
/* Reads the measured temperature from the thermometer. */
static void example_thermo_read_temperature(ExampleThermoContext* context) {
/* If there was no device detected, don't try to read the temperature */
if(!context->has_device) {
return;
}
OneWireHost* onewire = context->onewire;
/* All 1-wire transactions must happen in a critical section, i.e
not interrupted by other threads. */
FURI_CRITICAL_ENTER();
bool success = false;
do {
DS18B20Scratchpad buf;
/* Attempt reading the temperature 10 times before giving up */
size_t attempts_left = 10;
do {
/* Each communication with a 1-wire device starts by a reset.
The functon will return true if a device responded with a presence pulse. */
if(!onewire_host_reset(onewire)) continue;
/* After the reset, a ROM operation must follow.
If there is only one device connected, the "Skip ROM" command is most appropriate
(it can also be used to address all of the connected devices in some cases).*/
onewire_host_skip(onewire);
/* After the ROM operation, a device-specific command is issued.
This time, it will be the "Read Scratchpad" command which will
prepare the device's internal buffer memory for reading. */
onewire_host_write(onewire, DS18B20_CMD_READ_SCRATCHPAD);
/* The actual reading happens here. A total of 9 bytes is read. */
onewire_host_read_bytes(onewire, buf.bytes, sizeof(buf.bytes));
/* Calculate the checksum and compare it with one provided by the device. */
const uint8_t crc = maxim_crc8(buf.bytes, sizeof(buf.bytes) - 1, MAXIM_CRC8_INIT);
/* Checksums match, exit the loop */
if(crc == buf.fields.crc) break;
} while(--attempts_left);
if(attempts_left == 0) break;
/* Get the measurement resolution from the configuration register. (See [1] page 9) */
const uint8_t resolution_mode = (buf.fields.config >> DS18B20_CFG_RESOLUTION_POS) &
DS18B20_CFG_RESOLUTION_MASK;
/* Generate a mask for undefined bits in the decimal part. (See [1] page 6) */
const uint8_t decimal_mask =
(DS18B20_DECIMAL_PART_MASK << (DS18B20_CFG_RESOLUTION_MASK - resolution_mode)) &
DS18B20_DECIMAL_PART_MASK;
/* Get the integer and decimal part of the temperature (See [1] page 6) */
const uint8_t integer_part = (buf.fields.temp_msb << 4U) | (buf.fields.temp_lsb >> 4U);
const uint8_t decimal_part = buf.fields.temp_lsb & decimal_mask;
/* Calculate the sign of the temperature (See [1] page 6) */
const bool is_negative = (buf.fields.temp_msb & DS18B20_SIGN_MASK) != 0;
/* Combine the integer and decimal part together */
const float temp_celsius_abs = integer_part + decimal_part / 16.f;
/* Set the appropriate sign */
context->temp_celsius = is_negative ? -temp_celsius_abs : temp_celsius_abs;
success = true;
} while(false);
context->has_device = success;
FURI_CRITICAL_EXIT();
}
/* Periodically requests measurements and reads temperature. This function runs in a separare thread. */
static int32_t example_thermo_reader_thread_callback(void* ctx) {
ExampleThermoContext* context = ctx;
for(;;) {
/* Tell the termometer to start measuring the temperature. The process may take up to 750ms. */
example_thermo_request_temperature(context);
/* Wait for the measurement to finish. At the same time wait for an exit signal. */
const uint32_t flags =
furi_thread_flags_wait(ReaderThreadFlagExit, FuriFlagWaitAny, UPDATE_PERIOD_MS);
/* If an exit signal was received, return from this thread. */
if(flags != (unsigned)FuriFlagErrorTimeout) break;
/* The measurement is now ready, read it from the termometer. */
example_thermo_read_temperature(context);
}
return 0;
}
/*************** GUI, Input and Main Loop *****************/
/* Draw the GUI of the application. The screen is completely redrawn during each call. */
static void example_thermo_draw_callback(Canvas* canvas, void* ctx) {
ExampleThermoContext* context = ctx;
char text_store[TEXT_STORE_SIZE];
const size_t middle_x = canvas_width(canvas) / 2U;
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, middle_x, 12, AlignCenter, AlignBottom, "Thermometer Demo");
canvas_draw_line(canvas, 0, 16, 128, 16);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, middle_x, 30, AlignCenter, AlignBottom, "Connnect thermometer");
snprintf(
text_store,
TEXT_STORE_SIZE,
"to GPIO pin %ld",
furi_hal_resources_get_ext_pin_number(&THERMO_GPIO_PIN));
canvas_draw_str_aligned(canvas, middle_x, 42, AlignCenter, AlignBottom, text_store);
canvas_set_font(canvas, FontKeyboard);
if(context->has_device) {
float temp;
char temp_units;
/* The applicaton is locale-aware.
Change Settings->System->Units to check it out. */
switch(locale_get_measurement_unit()) {
case LocaleMeasurementUnitsMetric:
temp = context->temp_celsius;
temp_units = 'C';
break;
case LocaleMeasurementUnitsImperial:
temp = locale_celsius_to_fahrenheit(context->temp_celsius);
temp_units = 'F';
break;
default:
furi_crash("Illegal measurement units");
}
/* If a reading is available, display it */
snprintf(text_store, TEXT_STORE_SIZE, "Temperature: %+.1f%c", (double)temp, temp_units);
} else {
/* Or show a message that no data is available */
strncpy(text_store, "-- No data --", TEXT_STORE_SIZE);
}
canvas_draw_str_aligned(canvas, middle_x, 58, AlignCenter, AlignBottom, text_store);
}
/* This function is called from the GUI thread. All it does is put the event
into the application's queue so it can be processed later. */
static void example_thermo_input_callback(InputEvent* event, void* ctx) {
ExampleThermoContext* context = ctx;
furi_message_queue_put(context->event_queue, event, FuriWaitForever);
}
/* Starts the reader thread and handles the input */
static void example_thermo_run(ExampleThermoContext* context) {
/* Configure the hardware in host mode */
onewire_host_start(context->onewire);
/* Start the reader thread. It will talk to the thermometer in the background. */
furi_thread_start(context->reader_thread);
/* An endless loop which handles the input*/
for(bool is_running = true; is_running;) {
InputEvent event;
/* Wait for an input event. Input events come from the GUI thread via a callback. */
const FuriStatus status =
furi_message_queue_get(context->event_queue, &event, FuriWaitForever);
/* This application is only interested in short button presses. */
if((status != FuriStatusOk) || (event.type != InputTypeShort)) {
continue;
}
/* When the user presses the "Back" button, break the loop and exit the application. */
if(event.key == InputKeyBack) {
is_running = false;
}
}
/* Signal the reader thread to cease operation and exit */
furi_thread_flags_set(furi_thread_get_id(context->reader_thread), ReaderThreadFlagExit);
/* Wait for the reader thread to finish */
furi_thread_join(context->reader_thread);
/* Reset the hardware */
onewire_host_stop(context->onewire);
}
/******************** Initialisation & startup *****************************/
/* Allocate the memory and initialise the variables */
static ExampleThermoContext* example_thermo_context_alloc() {
ExampleThermoContext* context = malloc(sizeof(ExampleThermoContext));
context->view_port = view_port_alloc();
view_port_draw_callback_set(context->view_port, example_thermo_draw_callback, context);
view_port_input_callback_set(context->view_port, example_thermo_input_callback, context);
context->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
context->reader_thread = furi_thread_alloc();
furi_thread_set_stack_size(context->reader_thread, 1024U);
furi_thread_set_context(context->reader_thread, context);
furi_thread_set_callback(context->reader_thread, example_thermo_reader_thread_callback);
context->gui = furi_record_open(RECORD_GUI);
gui_add_view_port(context->gui, context->view_port, GuiLayerFullscreen);
context->onewire = onewire_host_alloc(&THERMO_GPIO_PIN);
return context;
}
/* Release the unused resources and deallocate memory */
static void example_thermo_context_free(ExampleThermoContext* context) {
view_port_enabled_set(context->view_port, false);
gui_remove_view_port(context->gui, context->view_port);
onewire_host_free(context->onewire);
furi_thread_free(context->reader_thread);
furi_message_queue_free(context->event_queue);
view_port_free(context->view_port);
furi_record_close(RECORD_GUI);
}
/* The application's entry point. Execution starts from here. */
int32_t example_thermo_main(void* p) {
UNUSED(p);
/* Allocate all of the necessary structures */
ExampleThermoContext* context = example_thermo_context_alloc();
/* Start the applicaton's main loop. It won't return until the application was requested to exit. */
example_thermo_run(context);
/* Release all unneeded resources */
example_thermo_context_free(context);
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -1,10 +1,11 @@
#include <archive/views/archive_browser_view.h>
#include "archive_files.h" #include "archive_files.h"
#include "archive_apps.h" #include "archive_apps.h"
#include "archive_browser.h" #include "archive_browser.h"
#include "../views/archive_browser_view.h"
#include <core/common_defines.h> #include <core/common_defines.h>
#include <core/log.h> #include <core/log.h>
#include "gui/modules/file_browser_worker.h" #include <gui/modules/file_browser_worker.h>
#include <fap_loader/fap_loader_app.h> #include <fap_loader/fap_loader_app.h>
#include <math.h> #include <math.h>

View File

@@ -1,15 +1,15 @@
#pragma once #pragma once
#include "../helpers/archive_files.h"
#include "../helpers/archive_favorites.h"
#include <gui/gui_i.h> #include <gui/gui_i.h>
#include <gui/view.h> #include <gui/view.h>
#include <gui/canvas.h> #include <gui/canvas.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <furi.h> #include <gui/modules/file_browser_worker.h>
#include <storage/storage.h> #include <storage/storage.h>
#include "../helpers/archive_files.h" #include <furi.h>
#include "../helpers/archive_menu.h"
#include "../helpers/archive_favorites.h"
#include "gui/modules/file_browser_worker.h"
#define MAX_LEN_PX 110 #define MAX_LEN_PX 110
#define MAX_NAME_LEN 255 #define MAX_NAME_LEN 255

View File

@@ -1,6 +1,6 @@
#include "../bad_usb_app_i.h" #include "../bad_usb_app_i.h"
#include "furi_hal_power.h" #include <furi_hal_power.h>
#include "furi_hal_usb.h" #include <furi_hal_usb.h>
#include <storage/storage.h> #include <storage/storage.h>
static bool bad_usb_file_select(BadUsbApp* bad_usb) { static bool bad_usb_file_select(BadUsbApp* bad_usb) {

View File

@@ -1,7 +1,7 @@
#include "../bad_usb_script.h" #include "../bad_usb_script.h"
#include "../bad_usb_app_i.h" #include "../bad_usb_app_i.h"
#include "../views/bad_usb_view.h" #include "../views/bad_usb_view.h"
#include "furi_hal.h" #include <furi_hal.h>
#include "toolbox/path.h" #include "toolbox/path.h"
void bad_usb_scene_work_button_callback(InputKey key, void* context) { void bad_usb_scene_work_button_callback(InputKey key, void* context) {

View File

@@ -25,6 +25,7 @@ GpioApp* gpio_app_alloc() {
GpioApp* app = malloc(sizeof(GpioApp)); GpioApp* app = malloc(sizeof(GpioApp));
app->gui = furi_record_open(RECORD_GUI); app->gui = furi_record_open(RECORD_GUI);
app->gpio_items = gpio_items_alloc();
app->view_dispatcher = view_dispatcher_alloc(); app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app); app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app);
@@ -47,7 +48,7 @@ GpioApp* gpio_app_alloc() {
app->view_dispatcher, app->view_dispatcher,
GpioAppViewVarItemList, GpioAppViewVarItemList,
variable_item_list_get_view(app->var_item_list)); variable_item_list_get_view(app->var_item_list));
app->gpio_test = gpio_test_alloc(); app->gpio_test = gpio_test_alloc(app->gpio_items);
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, GpioAppViewGpioTest, gpio_test_get_view(app->gpio_test)); app->view_dispatcher, GpioAppViewGpioTest, gpio_test_get_view(app->gpio_test));
@@ -91,6 +92,7 @@ void gpio_app_free(GpioApp* app) {
furi_record_close(RECORD_GUI); furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_NOTIFICATION);
gpio_items_free(app->gpio_items);
free(app); free(app);
} }

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "gpio_app.h" #include "gpio_app.h"
#include "gpio_item.h" #include "gpio_items.h"
#include "scenes/gpio_scene.h" #include "scenes/gpio_scene.h"
#include "gpio_custom_event.h" #include "gpio_custom_event.h"
#include "usb_uart_bridge.h" #include "usb_uart_bridge.h"
@@ -28,6 +28,7 @@ struct GpioApp {
VariableItem* var_item_flow; VariableItem* var_item_flow;
GpioTest* gpio_test; GpioTest* gpio_test;
GpioUsbUart* gpio_usb_uart; GpioUsbUart* gpio_usb_uart;
GPIOItems* gpio_items;
UsbUartBridge* usb_uart_bridge; UsbUartBridge* usb_uart_bridge;
UsbUartConfig* usb_uart_cfg; UsbUartConfig* usb_uart_cfg;
}; };

View File

@@ -1,51 +0,0 @@
#include "gpio_item.h"
#include <furi_hal_resources.h>
typedef struct {
const char* name;
const GpioPin* pin;
} GpioItem;
static const GpioItem gpio_item[GPIO_ITEM_COUNT] = {
{"1.2: PA7", &gpio_ext_pa7},
{"1.3: PA6", &gpio_ext_pa6},
{"1.4: PA4", &gpio_ext_pa4},
{"1.5: PB3", &gpio_ext_pb3},
{"1.6: PB2", &gpio_ext_pb2},
{"1.7: PC3", &gpio_ext_pc3},
{"2.7: PC1", &gpio_ext_pc1},
{"2.8: PC0", &gpio_ext_pc0},
};
void gpio_item_configure_pin(uint8_t index, GpioMode mode) {
furi_assert(index < GPIO_ITEM_COUNT);
furi_hal_gpio_write(gpio_item[index].pin, false);
furi_hal_gpio_init(gpio_item[index].pin, mode, GpioPullNo, GpioSpeedVeryHigh);
}
void gpio_item_configure_all_pins(GpioMode mode) {
for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) {
gpio_item_configure_pin(i, mode);
}
}
void gpio_item_set_pin(uint8_t index, bool level) {
furi_assert(index < GPIO_ITEM_COUNT);
furi_hal_gpio_write(gpio_item[index].pin, level);
}
void gpio_item_set_all_pins(bool level) {
for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) {
gpio_item_set_pin(i, level);
}
}
const char* gpio_item_get_pin_name(uint8_t index) {
furi_assert(index < GPIO_ITEM_COUNT + 1);
if(index == GPIO_ITEM_COUNT) {
return "ALL";
} else {
return gpio_item[index].name;
}
}

View File

@@ -1,15 +0,0 @@
#pragma once
#include <furi_hal_gpio.h>
#define GPIO_ITEM_COUNT 8
void gpio_item_configure_pin(uint8_t index, GpioMode mode);
void gpio_item_configure_all_pins(GpioMode mode);
void gpio_item_set_pin(uint8_t index, bool level);
void gpio_item_set_all_pins(bool level);
const char* gpio_item_get_pin_name(uint8_t index);

View File

@@ -0,0 +1,69 @@
#include "gpio_items.h"
#include <furi_hal_resources.h>
struct GPIOItems {
GpioPinRecord* pins;
size_t count;
};
GPIOItems* gpio_items_alloc() {
GPIOItems* items = malloc(sizeof(GPIOItems));
items->count = 0;
for(size_t i = 0; i < gpio_pins_count; i++) {
if(!gpio_pins[i].debug) {
items->count++;
}
}
items->pins = malloc(sizeof(GpioPinRecord) * items->count);
for(size_t i = 0; i < items->count; i++) {
if(!gpio_pins[i].debug) {
items->pins[i].pin = gpio_pins[i].pin;
items->pins[i].name = gpio_pins[i].name;
}
}
return items;
}
void gpio_items_free(GPIOItems* items) {
free(items->pins);
free(items);
}
uint8_t gpio_items_get_count(GPIOItems* items) {
return items->count;
}
void gpio_items_configure_pin(GPIOItems* items, uint8_t index, GpioMode mode) {
furi_assert(index < items->count);
furi_hal_gpio_write(items->pins[index].pin, false);
furi_hal_gpio_init(items->pins[index].pin, mode, GpioPullNo, GpioSpeedVeryHigh);
}
void gpio_items_configure_all_pins(GPIOItems* items, GpioMode mode) {
for(uint8_t i = 0; i < items->count; i++) {
gpio_items_configure_pin(items, i, mode);
}
}
void gpio_items_set_pin(GPIOItems* items, uint8_t index, bool level) {
furi_assert(index < items->count);
furi_hal_gpio_write(items->pins[index].pin, level);
}
void gpio_items_set_all_pins(GPIOItems* items, bool level) {
for(uint8_t i = 0; i < items->count; i++) {
gpio_items_set_pin(items, i, level);
}
}
const char* gpio_items_get_pin_name(GPIOItems* items, uint8_t index) {
furi_assert(index < items->count + 1);
if(index == items->count) {
return "ALL";
} else {
return items->pins[index].name;
}
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <furi_hal_gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct GPIOItems GPIOItems;
GPIOItems* gpio_items_alloc();
void gpio_items_free(GPIOItems* items);
uint8_t gpio_items_get_count(GPIOItems* items);
void gpio_items_configure_pin(GPIOItems* items, uint8_t index, GpioMode mode);
void gpio_items_configure_all_pins(GPIOItems* items, GpioMode mode);
void gpio_items_set_pin(GPIOItems* items, uint8_t index, bool level);
void gpio_items_set_all_pins(GPIOItems* items, bool level);
const char* gpio_items_get_pin_name(GPIOItems* items, uint8_t index);
#ifdef __cplusplus
}
#endif

View File

@@ -1,6 +1,6 @@
#include "../gpio_app_i.h" #include "../gpio_app_i.h"
#include "furi_hal_power.h" #include <furi_hal_power.h>
#include "furi_hal_usb.h" #include <furi_hal_usb.h>
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
enum GpioItem { enum GpioItem {

View File

@@ -12,8 +12,9 @@ void gpio_scene_test_ok_callback(InputType type, void* context) {
} }
void gpio_scene_test_on_enter(void* context) { void gpio_scene_test_on_enter(void* context) {
furi_assert(context);
GpioApp* app = context; GpioApp* app = context;
gpio_item_configure_all_pins(GpioModeOutputPushPull); gpio_items_configure_all_pins(app->gpio_items, GpioModeOutputPushPull);
gpio_test_set_ok_callback(app->gpio_test, gpio_scene_test_ok_callback, app); gpio_test_set_ok_callback(app->gpio_test, gpio_scene_test_ok_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewGpioTest); view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewGpioTest);
} }
@@ -25,6 +26,7 @@ bool gpio_scene_test_on_event(void* context, SceneManagerEvent event) {
} }
void gpio_scene_test_on_exit(void* context) { void gpio_scene_test_on_exit(void* context) {
UNUSED(context); furi_assert(context);
gpio_item_configure_all_pins(GpioModeAnalog); GpioApp* app = context;
gpio_items_configure_all_pins(app->gpio_items, GpioModeAnalog);
} }

View File

@@ -1,6 +1,6 @@
#include "../usb_uart_bridge.h" #include "../usb_uart_bridge.h"
#include "../gpio_app_i.h" #include "../gpio_app_i.h"
#include "furi_hal.h" #include <furi_hal.h>
typedef enum { typedef enum {
UsbUartLineIndexVcp, UsbUartLineIndexVcp,

View File

@@ -1,10 +1,10 @@
#include "usb_uart_bridge.h" #include "usb_uart_bridge.h"
#include "furi_hal.h"
#include <furi_hal_usb_cdc.h>
#include "usb_cdc.h" #include "usb_cdc.h"
#include "cli/cli_vcp.h" #include <cli/cli_vcp.h>
#include <cli/cli.h>
#include <toolbox/api_lock.h> #include <toolbox/api_lock.h>
#include "cli/cli.h" #include <furi_hal.h>
#include <furi_hal_usb_cdc.h>
#define USB_CDC_PKT_LEN CDC_DATA_SZ #define USB_CDC_PKT_LEN CDC_DATA_SZ
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) #define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)

View File

@@ -1,5 +1,5 @@
#include "gpio_test.h" #include "gpio_test.h"
#include "../gpio_item.h" #include "../gpio_items.h"
#include <gui/elements.h> #include <gui/elements.h>
@@ -11,6 +11,7 @@ struct GpioTest {
typedef struct { typedef struct {
uint8_t pin_idx; uint8_t pin_idx;
GPIOItems* gpio_items;
} GpioTestModel; } GpioTestModel;
static bool gpio_test_process_left(GpioTest* gpio_test); static bool gpio_test_process_left(GpioTest* gpio_test);
@@ -25,7 +26,12 @@ static void gpio_test_draw_callback(Canvas* canvas, void* _model) {
elements_multiline_text_aligned( elements_multiline_text_aligned(
canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin"); canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin");
elements_multiline_text_aligned( elements_multiline_text_aligned(
canvas, 64, 32, AlignCenter, AlignTop, gpio_item_get_pin_name(model->pin_idx)); canvas,
64,
32,
AlignCenter,
AlignTop,
gpio_items_get_pin_name(model->gpio_items, model->pin_idx));
} }
static bool gpio_test_input_callback(InputEvent* event, void* context) { static bool gpio_test_input_callback(InputEvent* event, void* context) {
@@ -64,7 +70,7 @@ static bool gpio_test_process_right(GpioTest* gpio_test) {
gpio_test->view, gpio_test->view,
GpioTestModel * model, GpioTestModel * model,
{ {
if(model->pin_idx < GPIO_ITEM_COUNT) { if(model->pin_idx < gpio_items_get_count(model->gpio_items)) {
model->pin_idx++; model->pin_idx++;
} }
}, },
@@ -80,17 +86,17 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
GpioTestModel * model, GpioTestModel * model,
{ {
if(event->type == InputTypePress) { if(event->type == InputTypePress) {
if(model->pin_idx < GPIO_ITEM_COUNT) { if(model->pin_idx < gpio_items_get_count(model->gpio_items)) {
gpio_item_set_pin(model->pin_idx, true); gpio_items_set_pin(model->gpio_items, model->pin_idx, true);
} else { } else {
gpio_item_set_all_pins(true); gpio_items_set_all_pins(model->gpio_items, true);
} }
consumed = true; consumed = true;
} else if(event->type == InputTypeRelease) { } else if(event->type == InputTypeRelease) {
if(model->pin_idx < GPIO_ITEM_COUNT) { if(model->pin_idx < gpio_items_get_count(model->gpio_items)) {
gpio_item_set_pin(model->pin_idx, false); gpio_items_set_pin(model->gpio_items, model->pin_idx, false);
} else { } else {
gpio_item_set_all_pins(false); gpio_items_set_all_pins(model->gpio_items, false);
} }
consumed = true; consumed = true;
} }
@@ -101,11 +107,15 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
return consumed; return consumed;
} }
GpioTest* gpio_test_alloc() { GpioTest* gpio_test_alloc(GPIOItems* gpio_items) {
GpioTest* gpio_test = malloc(sizeof(GpioTest)); GpioTest* gpio_test = malloc(sizeof(GpioTest));
gpio_test->view = view_alloc(); gpio_test->view = view_alloc();
view_allocate_model(gpio_test->view, ViewModelTypeLocking, sizeof(GpioTestModel)); view_allocate_model(gpio_test->view, ViewModelTypeLocking, sizeof(GpioTestModel));
with_view_model(
gpio_test->view, GpioTestModel * model, { model->gpio_items = gpio_items; }, false);
view_set_context(gpio_test->view, gpio_test); view_set_context(gpio_test->view, gpio_test);
view_set_draw_callback(gpio_test->view, gpio_test_draw_callback); view_set_draw_callback(gpio_test->view, gpio_test_draw_callback);
view_set_input_callback(gpio_test->view, gpio_test_input_callback); view_set_input_callback(gpio_test->view, gpio_test_input_callback);

View File

@@ -1,11 +1,13 @@
#pragma once #pragma once
#include "../gpio_items.h"
#include <gui/view.h> #include <gui/view.h>
typedef struct GpioTest GpioTest; typedef struct GpioTest GpioTest;
typedef void (*GpioTestOkCallback)(InputType type, void* context); typedef void (*GpioTestOkCallback)(InputType type, void* context);
GpioTest* gpio_test_alloc(); GpioTest* gpio_test_alloc(GPIOItems* gpio_items);
void gpio_test_free(GpioTest* gpio_test); void gpio_test_free(GpioTest* gpio_test);

View File

@@ -1,6 +1,6 @@
#include "../usb_uart_bridge.h" #include "../usb_uart_bridge.h"
#include "../gpio_app_i.h" #include "../gpio_app_i.h"
#include "furi_hal.h" #include <furi_hal.h>
#include <gui/elements.h> #include <gui/elements.h>
struct GpioUsbUart { struct GpioUsbUart {

View File

@@ -2,6 +2,7 @@ App(
appid="ibutton", appid="ibutton",
name="iButton", name="iButton",
apptype=FlipperAppType.APP, apptype=FlipperAppType.APP,
targets=["f7"],
entry_point="ibutton_app", entry_point="ibutton_app",
cdefines=["APP_IBUTTON"], cdefines=["APP_IBUTTON"],
requires=[ requires=[

View File

@@ -271,7 +271,7 @@ void onewire_cli_print_usage() {
static void onewire_cli_search(Cli* cli) { static void onewire_cli_search(Cli* cli) {
UNUSED(cli); UNUSED(cli);
OneWireHost* onewire = onewire_host_alloc(); OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio);
uint8_t address[8]; uint8_t address[8];
bool done = false; bool done = false;

View File

@@ -3,6 +3,7 @@ App(
name="Infrared", name="Infrared",
apptype=FlipperAppType.APP, apptype=FlipperAppType.APP,
entry_point="infrared_app", entry_point="infrared_app",
targets=["f7"],
cdefines=["APP_INFRARED"], cdefines=["APP_INFRARED"],
requires=[ requires=[
"gui", "gui",

View File

@@ -1,5 +1,5 @@
#include "../infrared_i.h" #include "../infrared_i.h"
#include "gui/canvas.h" #include <gui/canvas.h>
typedef enum { typedef enum {
InfraredRpcStateIdle, InfraredRpcStateIdle,

View File

@@ -52,7 +52,8 @@ void infrared_scene_universal_on_enter(void* context) {
infrared_scene_universal_submenu_callback, infrared_scene_universal_submenu_callback,
context); context);
submenu_set_selected_item(submenu, 0); submenu_set_selected_item(
submenu, scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneUniversal));
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu);
} }
@@ -79,6 +80,7 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC); scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC);
consumed = true; consumed = true;
} }
scene_manager_set_scene_state(scene_manager, InfraredSceneUniversal, event.event);
} }
return consumed; return consumed;

View File

@@ -1,11 +1,11 @@
#include "infrared_debug_view.h" #include "infrared_debug_view.h"
#include <stdlib.h>
#include <string.h>
#include <gui/canvas.h> #include <gui/canvas.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <stdlib.h>
#include <string.h>
#define INFRARED_DEBUG_TEXT_LENGTH 64 #define INFRARED_DEBUG_TEXT_LENGTH 64
struct InfraredDebugView { struct InfraredDebugView {

View File

@@ -1,13 +1,15 @@
#include <core/check.h>
#include "furi_hal_resources.h"
#include "assets_icons.h"
#include "gui/canvas.h"
#include "gui/view.h"
#include "input/input.h"
#include <gui/elements.h>
#include <furi.h>
#include "infrared_progress_view.h" #include "infrared_progress_view.h"
#include "gui/modules/button_panel.h"
#include <assets_icons.h>
#include <gui/canvas.h>
#include <gui/view.h>
#include <gui/elements.h>
#include <gui/modules/button_panel.h>
#include <input/input.h>
#include <furi.h>
#include <furi_hal_resources.h>
#include <core/check.h>
#include <stdint.h> #include <stdint.h>
struct InfraredProgressView { struct InfraredProgressView {

View File

@@ -2,6 +2,7 @@ App(
appid="lfrfid", appid="lfrfid",
name="125 kHz RFID", name="125 kHz RFID",
apptype=FlipperAppType.APP, apptype=FlipperAppType.APP,
targets=["f7"],
entry_point="lfrfid_app", entry_point="lfrfid_app",
cdefines=["APP_LF_RFID"], cdefines=["APP_LF_RFID"],
requires=[ requires=[

View File

@@ -47,21 +47,28 @@ bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexRead) { if(event.event == SubmenuIndexRead) {
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexRead);
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
DOLPHIN_DEED(DolphinDeedRfidRead); DOLPHIN_DEED(DolphinDeedRfidRead);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexSaved) { } else if(event.event == SubmenuIndexSaved) {
// Like in the other apps, explicitly save the scene state
// in each branch in case the user cancels loading a file.
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexSaved);
furi_string_set(app->file_path, LFRFID_APP_FOLDER); furi_string_set(app->file_path, LFRFID_APP_FOLDER);
scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey); scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexAddManually) { } else if(event.event == SubmenuIndexAddManually) {
scene_manager_set_scene_state(
app->scene_manager, LfRfidSceneStart, SubmenuIndexAddManually);
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType); scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexExtraActions) { } else if(event.event == SubmenuIndexExtraActions) {
scene_manager_set_scene_state(
app->scene_manager, LfRfidSceneStart, SubmenuIndexExtraActions);
scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions); scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions);
consumed = true; consumed = true;
} }
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, event.event);
} }
return consumed; return consumed;

View File

@@ -2,6 +2,7 @@ App(
appid="nfc", appid="nfc",
name="NFC", name="NFC",
apptype=FlipperAppType.APP, apptype=FlipperAppType.APP,
targets=["f7"],
entry_point="nfc_app", entry_point="nfc_app",
cdefines=["APP_NFC"], cdefines=["APP_NFC"],
requires=[ requires=[

View File

@@ -1,5 +1,5 @@
#include "nfc_i.h" #include "nfc_i.h"
#include "furi_hal_nfc.h" #include <furi_hal_nfc.h>
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
bool nfc_custom_event_callback(void* context, uint32_t event) { bool nfc_custom_event_callback(void* context, uint32_t event) {

View File

@@ -4,7 +4,7 @@ ADD_SCENE(nfc, saved_menu, SavedMenu)
ADD_SCENE(nfc, extra_actions, ExtraActions) ADD_SCENE(nfc, extra_actions, ExtraActions)
ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_type, SetType)
ADD_SCENE(nfc, set_sak, SetSak) ADD_SCENE(nfc, set_sak, SetSak)
ADD_SCENE(nfc, set_atqa, SetAtqua) ADD_SCENE(nfc, set_atqa, SetAtqa)
ADD_SCENE(nfc, set_uid, SetUid) ADD_SCENE(nfc, set_uid, SetUid)
ADD_SCENE(nfc, generate_info, GenerateInfo) ADD_SCENE(nfc, generate_info, GenerateInfo)
ADD_SCENE(nfc, read_card_success, ReadCardSuccess) ADD_SCENE(nfc, read_card_success, ReadCardSuccess)

View File

@@ -30,7 +30,7 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
nfc->scene_manager, NfcSceneMfClassicKeys); nfc->scene_manager, NfcSceneMfClassicKeys);
} else { } else {
consumed = scene_manager_search_and_switch_to_previous_scene( consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart); nfc->scene_manager, NfcSceneFileSelect);
} }
} }
} }

View File

@@ -34,6 +34,8 @@ void nfc_scene_extra_actions_on_enter(void* context) {
SubmenuIndexMfUltralightUnlock, SubmenuIndexMfUltralightUnlock,
nfc_scene_extra_actions_submenu_callback, nfc_scene_extra_actions_submenu_callback,
nfc); nfc);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions));
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
} }

View File

@@ -11,7 +11,7 @@ void nfc_scene_set_atqa_on_enter(void* context) {
// Setup view // Setup view
ByteInput* byte_input = nfc->byte_input; ByteInput* byte_input = nfc->byte_input;
byte_input_set_header_text(byte_input, "Enter atqa in hex"); byte_input_set_header_text(byte_input, "Enter ATQA in hex");
byte_input_set_result_callback( byte_input_set_result_callback(
byte_input, byte_input,
nfc_scene_set_atqa_byte_input_callback, nfc_scene_set_atqa_byte_input_callback,

View File

@@ -28,7 +28,7 @@ bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) { if(event.event == NfcCustomEventByteInputDone) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqa);
consumed = true; consumed = true;
} }
} }

View File

@@ -11,7 +11,7 @@ void nfc_scene_set_uid_on_enter(void* context) {
// Setup view // Setup view
ByteInput* byte_input = nfc->byte_input; ByteInput* byte_input = nfc->byte_input;
byte_input_set_header_text(byte_input, "Enter uid in hex"); byte_input_set_header_text(byte_input, "Enter UID in hex");
nfc->dev_edit_data = nfc->dev->dev_data.nfc_data; nfc->dev_edit_data = nfc->dev->dev_data.nfc_data;
byte_input_set_result_callback( byte_input_set_result_callback(
byte_input, byte_input,

View File

@@ -48,11 +48,14 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexRead) { if(event.event == SubmenuIndexRead) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead);
nfc->dev->dev_data.read_mode = NfcReadModeAuto; nfc->dev->dev_data.read_mode = NfcReadModeAuto;
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
DOLPHIN_DEED(DolphinDeedNfcRead); DOLPHIN_DEED(DolphinDeedNfcRead);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexDetectReader) { } else if(event.event == SubmenuIndexDetectReader) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneStart, SubmenuIndexDetectReader);
bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK;
if(sd_exist) { if(sd_exist) {
nfc_device_data_clear(&nfc->dev->dev_data); nfc_device_data_clear(&nfc->dev->dev_data);
@@ -63,19 +66,27 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
} }
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexSaved) { } else if(event.event == SubmenuIndexSaved) {
// Save the scene state explicitly in each branch, so that
// if the user cancels loading a file, the Saved menu item
// is properly reselected.
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexSaved);
scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect); scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexExtraAction) { } else if(event.event == SubmenuIndexExtraAction) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneStart, SubmenuIndexExtraAction);
scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions); scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexAddManually) { } else if(event.event == SubmenuIndexAddManually) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManually);
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexDebug) { } else if(event.event == SubmenuIndexDebug) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug);
scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug); scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug);
consumed = true; consumed = true;
} }
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, event.event);
} }
return consumed; return consumed;
} }

View File

@@ -2,6 +2,7 @@ App(
appid="subghz", appid="subghz",
name="Sub-GHz", name="Sub-GHz",
apptype=FlipperAppType.APP, apptype=FlipperAppType.APP,
targets=["f7"],
entry_point="subghz_app", entry_point="subghz_app",
cdefines=["APP_SUBGHZ"], cdefines=["APP_SUBGHZ"],
requires=[ requires=[

View File

@@ -31,6 +31,9 @@ bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
} else if(scene_manager_search_and_switch_to_previous_scene( } else if(scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneSaved)) { subghz->scene_manager, SubGhzSceneSaved)) {
// Commented so that the user doesn't have to press
// back twice to get to the main SubGhz menu after
// deleting a file.
//scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); //scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
} else { } else {
scene_manager_search_and_switch_to_previous_scene( scene_manager_search_and_switch_to_previous_scene(

View File

@@ -1,7 +1,7 @@
#include "../u2f_app_i.h" #include "../u2f_app_i.h"
#include "../views/u2f_view.h" #include "../views/u2f_view.h"
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#include "furi_hal.h" #include <furi_hal.h>
#include "../u2f.h" #include "../u2f.h"
#define U2F_REQUEST_TIMEOUT 500 #define U2F_REQUEST_TIMEOUT 500

View File

@@ -6,6 +6,7 @@
#include <storage/storage.h> #include <storage/storage.h>
#include <lib/flipper_format/flipper_format.h> #include <lib/flipper_format/flipper_format.h>
#include <math.h>
#include <m-array.h> #include <m-array.h>
#define TAG "MusicPlayerWorker" #define TAG "MusicPlayerWorker"

View File

@@ -2,6 +2,7 @@ App(
appid="nfc_magic", appid="nfc_magic",
name="NFC Magic", name="NFC Magic",
apptype=FlipperAppType.EXTERNAL, apptype=FlipperAppType.EXTERNAL,
targets=["f7"],
entry_point="nfc_magic_app", entry_point="nfc_magic_app",
requires=[ requires=[
"storage", "storage",

View File

@@ -136,9 +136,9 @@ void nfc_magic_free(NfcMagic* nfc_magic) {
free(nfc_magic); free(nfc_magic);
} }
static const NotificationSequence nfc_magic_sequence_blink_start_blue = { static const NotificationSequence nfc_magic_sequence_blink_start_cyan = {
&message_blink_start_10, &message_blink_start_10,
&message_blink_set_color_blue, &message_blink_set_color_cyan,
&message_do_not_reset, &message_do_not_reset,
NULL, NULL,
}; };
@@ -149,7 +149,7 @@ static const NotificationSequence nfc_magic_sequence_blink_stop = {
}; };
void nfc_magic_blink_start(NfcMagic* nfc_magic) { void nfc_magic_blink_start(NfcMagic* nfc_magic) {
notification_message(nfc_magic->notifications, &nfc_magic_sequence_blink_start_blue); notification_message(nfc_magic->notifications, &nfc_magic_sequence_blink_start_cyan);
} }
void nfc_magic_blink_stop(NfcMagic* nfc_magic) { void nfc_magic_blink_stop(NfcMagic* nfc_magic) {

View File

@@ -40,16 +40,24 @@ bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexCheck) { if(event.event == SubmenuIndexCheck) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck);
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck); scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexWriteGen1A) { } else if(event.event == SubmenuIndexWriteGen1A) {
// Explicitly save state in each branch so that the
// correct option is reselected if the user cancels
// loading a file.
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexWriteGen1A);
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect); scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexWipe) { } else if(event.event == SubmenuIndexWipe) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexWipe);
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe); scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe);
consumed = true; consumed = true;
} }
scene_manager_set_scene_state(nfc_magic->scene_manager, NfcMagicSceneStart, event.event);
} }
return consumed; return consumed;

View File

@@ -2,6 +2,7 @@ App(
appid="Picopass", appid="Picopass",
name="PicoPass Reader", name="PicoPass Reader",
apptype=FlipperAppType.EXTERNAL, apptype=FlipperAppType.EXTERNAL,
targets=["f7"],
entry_point="picopass_app", entry_point="picopass_app",
requires=[ requires=[
"storage", "storage",

View File

@@ -137,9 +137,9 @@ void picopass_text_store_clear(Picopass* picopass) {
memset(picopass->text_store, 0, sizeof(picopass->text_store)); memset(picopass->text_store, 0, sizeof(picopass->text_store));
} }
static const NotificationSequence picopass_sequence_blink_start_blue = { static const NotificationSequence picopass_sequence_blink_start_cyan = {
&message_blink_start_10, &message_blink_start_10,
&message_blink_set_color_blue, &message_blink_set_color_cyan,
&message_do_not_reset, &message_do_not_reset,
NULL, NULL,
}; };
@@ -150,7 +150,7 @@ static const NotificationSequence picopass_sequence_blink_stop = {
}; };
void picopass_blink_start(Picopass* picopass) { void picopass_blink_start(Picopass* picopass) {
notification_message(picopass->notifications, &picopass_sequence_blink_start_blue); notification_message(picopass->notifications, &picopass_sequence_blink_start_cyan);
} }
void picopass_blink_stop(Picopass* picopass) { void picopass_blink_stop(Picopass* picopass) {

View File

@@ -32,13 +32,18 @@ bool picopass_scene_start_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexRead) { if(event.event == SubmenuIndexRead) {
scene_manager_set_scene_state(
picopass->scene_manager, PicopassSceneStart, SubmenuIndexRead);
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCard); scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCard);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexSaved) { } else if(event.event == SubmenuIndexSaved) {
// Explicitly save state so that the correct item is
// reselected if the user cancels loading a file.
scene_manager_set_scene_state(
picopass->scene_manager, PicopassSceneStart, SubmenuIndexSaved);
scene_manager_next_scene(picopass->scene_manager, PicopassSceneFileSelect); scene_manager_next_scene(picopass->scene_manager, PicopassSceneFileSelect);
consumed = true; consumed = true;
} }
scene_manager_set_scene_state(picopass->scene_manager, PicopassSceneStart, event.event);
} }
return consumed; return consumed;

View File

@@ -2,8 +2,8 @@
#include "scenes/signal_gen_scene.h" #include "scenes/signal_gen_scene.h"
#include "furi_hal_clock.h" #include <furi_hal_clock.h>
#include "furi_hal_pwm.h" #include <furi_hal_pwm.h>
#include <gui/gui.h> #include <gui/gui.h>
#include <gui/view_dispatcher.h> #include <gui/view_dispatcher.h>

View File

@@ -1,5 +1,5 @@
#include "../signal_gen_app_i.h" #include "../signal_gen_app_i.h"
#include "furi_hal.h" #include <furi_hal.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <Signal_Generator_icons.h> #include <Signal_Generator_icons.h>

View File

@@ -2,6 +2,7 @@ App(
appid="weather_station", appid="weather_station",
name="Weather Station", name="Weather Station",
apptype=FlipperAppType.PLUGIN, apptype=FlipperAppType.PLUGIN,
targets=["f7"],
entry_point="weather_station_app", entry_point="weather_station_app",
cdefines=["APP_WEATHER_STATION"], cdefines=["APP_WEATHER_STATION"],
requires=["gui"], requires=["gui"],

View File

@@ -6,7 +6,7 @@
#include <lib/flipper_format/flipper_format.h> #include <lib/flipper_format/flipper_format.h>
#include "furi.h" #include "furi.h"
#include "furi_hal.h" #include <furi_hal.h>
#include <lib/subghz/types.h> #include <lib/subghz/types.h>
#include <locale/locale.h> #include <locale/locale.h>

View File

@@ -5,28 +5,6 @@
#include <furi_hal.h> #include <furi_hal.h>
#include <lib/toolbox/args.h> #include <lib/toolbox/args.h>
typedef struct {
const GpioPin* pin;
const char* name;
const bool debug;
} CliCommandGpio;
const CliCommandGpio cli_command_gpio_pins[] = {
{.pin = &gpio_ext_pc0, .name = "PC0", .debug = false},
{.pin = &gpio_ext_pc1, .name = "PC1", .debug = false},
{.pin = &gpio_ext_pc3, .name = "PC3", .debug = false},
{.pin = &gpio_ext_pb2, .name = "PB2", .debug = false},
{.pin = &gpio_ext_pb3, .name = "PB3", .debug = false},
{.pin = &gpio_ext_pa4, .name = "PA4", .debug = false},
{.pin = &gpio_ext_pa6, .name = "PA6", .debug = false},
{.pin = &gpio_ext_pa7, .name = "PA7", .debug = false},
/* Dangerous pins, may damage hardware */
{.pin = &gpio_infrared_rx, .name = "PA0", .debug = true},
{.pin = &gpio_usart_rx, .name = "PB7", .debug = true},
{.pin = &gpio_speaker, .name = "PB8", .debug = true},
{.pin = &gpio_infrared_tx, .name = "PB9", .debug = true},
};
void cli_command_gpio_print_usage() { void cli_command_gpio_print_usage() {
printf("Usage:\r\n"); printf("Usage:\r\n");
printf("gpio <cmd> <args>\r\n"); printf("gpio <cmd> <args>\r\n");
@@ -38,9 +16,9 @@ void cli_command_gpio_print_usage() {
static bool pin_name_to_int(FuriString* pin_name, size_t* result) { static bool pin_name_to_int(FuriString* pin_name, size_t* result) {
bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) { for(size_t i = 0; i < gpio_pins_count; i++) {
if(furi_string_equal(pin_name, cli_command_gpio_pins[i].name)) { if(furi_string_equal(pin_name, gpio_pins[i].name)) {
if(!cli_command_gpio_pins[i].debug || is_debug_mode) { if(!gpio_pins[i].debug || is_debug_mode) {
*result = i; *result = i;
return true; return true;
} }
@@ -53,9 +31,9 @@ static bool pin_name_to_int(FuriString* pin_name, size_t* result) {
static void gpio_print_pins(void) { static void gpio_print_pins(void) {
printf("Wrong pin name. Available pins: "); printf("Wrong pin name. Available pins: ");
bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) { for(size_t i = 0; i < gpio_pins_count; i++) {
if(!cli_command_gpio_pins[i].debug || is_debug_mode) { if(!gpio_pins[i].debug || is_debug_mode) {
printf("%s ", cli_command_gpio_pins[i].name); printf("%s ", gpio_pins[i].name);
} }
} }
} }
@@ -113,7 +91,7 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
return; return;
} }
if(cli_command_gpio_pins[num].debug) { //-V779 if(gpio_pins[num].debug) { //-V779
printf( printf(
"Changing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n"); "Changing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n");
char c = cli_getc(cli); char c = cli_getc(cli);
@@ -124,12 +102,12 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
} }
if(value == 1) { // output if(value == 1) { // output
furi_hal_gpio_write(cli_command_gpio_pins[num].pin, false); furi_hal_gpio_write(gpio_pins[num].pin, false);
furi_hal_gpio_init_simple(cli_command_gpio_pins[num].pin, GpioModeOutputPushPull); furi_hal_gpio_init_simple(gpio_pins[num].pin, GpioModeOutputPushPull);
printf("Pin %s is now an output (low)", cli_command_gpio_pins[num].name); printf("Pin %s is now an output (low)", gpio_pins[num].name);
} else { // input } else { // input
furi_hal_gpio_init_simple(cli_command_gpio_pins[num].pin, GpioModeInput); furi_hal_gpio_init_simple(gpio_pins[num].pin, GpioModeInput);
printf("Pin %s is now an input", cli_command_gpio_pins[num].name); printf("Pin %s is now an input", gpio_pins[num].name);
} }
} }
@@ -144,15 +122,14 @@ void cli_command_gpio_read(Cli* cli, FuriString* args, void* context) {
} }
if(LL_GPIO_MODE_INPUT != //-V779 if(LL_GPIO_MODE_INPUT != //-V779
LL_GPIO_GetPinMode( LL_GPIO_GetPinMode(gpio_pins[num].pin->port, gpio_pins[num].pin->pin)) {
cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) { printf("Err: pin %s is not set as an input.", gpio_pins[num].name);
printf("Err: pin %s is not set as an input.", cli_command_gpio_pins[num].name);
return; return;
} }
uint8_t val = !!furi_hal_gpio_read(cli_command_gpio_pins[num].pin); uint8_t val = !!furi_hal_gpio_read(gpio_pins[num].pin);
printf("Pin %s <= %u", cli_command_gpio_pins[num].name, val); printf("Pin %s <= %u", gpio_pins[num].name, val);
} }
void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) { void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) {
@@ -174,14 +151,13 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) {
} }
if(LL_GPIO_MODE_OUTPUT != //-V779 if(LL_GPIO_MODE_OUTPUT != //-V779
LL_GPIO_GetPinMode( LL_GPIO_GetPinMode(gpio_pins[num].pin->port, gpio_pins[num].pin->pin)) {
cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) { printf("Err: pin %s is not set as an output.", gpio_pins[num].name);
printf("Err: pin %s is not set as an output.", cli_command_gpio_pins[num].name);
return; return;
} }
// Extra check if debug pins used // Extra check if debug pins used
if(cli_command_gpio_pins[num].debug) { if(gpio_pins[num].debug) {
printf( printf(
"Setting this pin may damage hardware. Are you sure you want to continue? (y/n)?\r\n"); "Setting this pin may damage hardware. Are you sure you want to continue? (y/n)?\r\n");
char c = cli_getc(cli); char c = cli_getc(cli);
@@ -191,8 +167,8 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) {
} }
} }
furi_hal_gpio_write(cli_command_gpio_pins[num].pin, !!value); furi_hal_gpio_write(gpio_pins[num].pin, !!value);
printf("Pin %s => %u", cli_command_gpio_pins[num].name, !!value); printf("Pin %s => %u", gpio_pins[num].name, !!value);
} }
void cli_command_gpio(Cli* cli, FuriString* args, void* context) { void cli_command_gpio(Cli* cli, FuriString* args, void* context) {

View File

@@ -1,4 +1,4 @@
#include "dialogs/dialogs_message.h" #include "dialogs_message.h"
#include "dialogs_i.h" #include "dialogs_i.h"
#include <toolbox/api_lock.h> #include <toolbox/api_lock.h>
#include <assets_icons.h> #include <assets_icons.h>

View File

@@ -1,6 +1,7 @@
#include "dialogs_i.h" #include "dialogs_i.h"
#include <gui/modules/file_browser.h>
#include <toolbox/api_lock.h> #include <toolbox/api_lock.h>
#include "gui/modules/file_browser.h"
typedef struct { typedef struct {
FuriApiLock lock; FuriApiLock lock;

View File

@@ -1,8 +1,9 @@
#pragma once #pragma once
#include <core/pubsub.h>
#include "gui/view.h"
#include "helpers/dolphin_deed.h" #include "helpers/dolphin_deed.h"
#include <gui/view.h>
#include <core/pubsub.h>
#include <stdbool.h> #include <stdbool.h>
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -1,16 +1,17 @@
#include "elements.h" #include "elements.h"
#include "m-core.h" #include <m-core.h>
#include <assets_icons.h> #include <assets_icons.h>
#include "furi_hal_resources.h" #include <furi_hal_resources.h>
#include <furi_hal.h> #include <furi_hal.h>
#include "gui/canvas.h"
#include <gui/canvas.h>
#include <gui/icon_i.h> #include <gui/icon_i.h>
#include <gui/icon_animation_i.h> #include <gui/icon_animation_i.h>
#include <furi.h> #include <furi.h>
#include "canvas_i.h" #include "canvas_i.h"
#include <math.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>

View File

@@ -1,4 +1,3 @@
#include "gui/canvas.h"
#include "gui_i.h" #include "gui_i.h"
#include <assets_icons.h> #include <assets_icons.h>

View File

@@ -1,12 +1,15 @@
#include "button_menu.h" #include "button_menu.h"
#include "gui/canvas.h"
#include "gui/elements.h" #include <gui/canvas.h>
#include "input/input.h" #include <gui/elements.h>
#include <m-array.h> #include <input/input.h>
#include <furi.h> #include <furi.h>
#include <stdint.h>
#include <assets_icons.h> #include <assets_icons.h>
#include <stdint.h>
#include <m-array.h>
#define ITEM_FIRST_OFFSET 17 #define ITEM_FIRST_OFFSET 17
#define ITEM_NEXT_OFFSET 4 #define ITEM_NEXT_OFFSET 4
#define ITEM_HEIGHT 14 #define ITEM_HEIGHT 14

View File

@@ -1,12 +1,15 @@
#include "button_panel.h" #include "button_panel.h"
#include "furi_hal_resources.h"
#include "gui/canvas.h" #include <gui/canvas.h>
#include <gui/elements.h>
#include <furi.h>
#include <furi_hal_resources.h>
#include <stdint.h>
#include <m-array.h> #include <m-array.h>
#include <m-i-list.h> #include <m-i-list.h>
#include <m-list.h> #include <m-list.h>
#include <furi.h>
#include <gui/elements.h>
#include <stdint.h>
typedef struct { typedef struct {
// uint16_t to support multi-screen, wide button panel // uint16_t to support multi-screen, wide button panel

View File

@@ -1,8 +1,9 @@
#include <furi.h>
#include <gui/elements.h>
#include <assets_icons.h>
#include "byte_input.h" #include "byte_input.h"
#include <gui/elements.h>
#include <furi.h>
#include <assets_icons.h>
struct ByteInput { struct ByteInput {
View* view; View* view;
}; };

View File

@@ -1,14 +1,17 @@
#include "file_browser.h" #include "file_browser.h"
#include "assets_icons.h"
#include "file_browser_worker.h" #include "file_browser_worker.h"
#include <gui/elements.h>
#include <assets_icons.h>
#include <toolbox/path.h>
#include <furi.h>
#include <furi_hal_resources.h>
#include <core/check.h> #include <core/check.h>
#include <core/common_defines.h> #include <core/common_defines.h>
#include <core/log.h> #include <core/log.h>
#include "furi_hal_resources.h"
#include <m-array.h> #include <m-array.h>
#include <gui/elements.h>
#include <furi.h>
#include "toolbox/path.h"
#define LIST_ITEMS 5u #define LIST_ITEMS 5u
#define MAX_LEN_PX 110 #define MAX_LEN_PX 110

View File

@@ -1,13 +1,16 @@
#include "file_browser_worker.h" #include "file_browser_worker.h"
#include <storage/filesystem_api_defines.h>
#include <storage/storage.h>
#include <toolbox/path.h>
#include <core/check.h> #include <core/check.h>
#include <core/common_defines.h> #include <core/common_defines.h>
#include "storage/filesystem_api_defines.h" #include <furi.h>
#include <m-array.h> #include <m-array.h>
#include <stdbool.h> #include <stdbool.h>
#include <storage/storage.h>
#include <furi.h>
#include <stddef.h> #include <stddef.h>
#include "toolbox/path.h"
#define TAG "BrowserWorker" #define TAG "BrowserWorker"

View File

@@ -1,13 +1,14 @@
#include <stdint.h> #include "loading.h"
#include <furi.h>
#include <assets_icons.h>
#include <gui/icon_animation.h> #include <gui/icon_animation.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <gui/canvas.h> #include <gui/canvas.h>
#include <gui/view.h> #include <gui/view.h>
#include <input/input.h> #include <input/input.h>
#include "loading.h" #include <furi.h>
#include <assets_icons.h>
#include <stdint.h>
struct Loading { struct Loading {
View* view; View* view;

View File

@@ -1,9 +1,9 @@
#include "menu.h" #include "menu.h"
#include <m-array.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <assets_icons.h> #include <assets_icons.h>
#include <furi.h> #include <furi.h>
#include <m-array.h>
struct Menu { struct Menu {
View* view; View* view;

View File

@@ -1,8 +1,8 @@
#include "submenu.h" #include "submenu.h"
#include <m-array.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <furi.h> #include <furi.h>
#include <m-array.h>
struct Submenu { struct Submenu {
View* view; View* view;

View File

@@ -1,7 +1,7 @@
#include "text_box.h" #include "text_box.h"
#include "gui/canvas.h" #include <gui/canvas.h>
#include <furi.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <furi.h>
#include <stdint.h> #include <stdint.h>
struct TextBox { struct TextBox {

View File

@@ -1,6 +1,6 @@
#include <furi.h>
#include "validators.h" #include "validators.h"
#include <storage/storage.h> #include <storage/storage.h>
#include <furi.h>
struct ValidatorIsFile { struct ValidatorIsFile {
char* app_path_folder; char* app_path_folder;

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <core/common_defines.h> #include <core/common_defines.h>
#include <core/string.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View File

@@ -1,8 +1,8 @@
#include "variable_item_list.h" #include "variable_item_list.h"
#include "gui/canvas.h"
#include <m-array.h>
#include <furi.h>
#include <gui/elements.h> #include <gui/elements.h>
#include <gui/canvas.h>
#include <furi.h>
#include <m-array.h>
#include <stdint.h> #include <stdint.h>
struct VariableItem { struct VariableItem {

View File

@@ -1,7 +1,7 @@
#include <furi.h>
#include "widget.h" #include "widget.h"
#include <m-array.h>
#include "widget_elements/widget_element_i.h" #include "widget_elements/widget_element_i.h"
#include <furi.h>
#include <m-array.h>
ARRAY_DEF(ElementArray, WidgetElement*, M_PTR_OPLIST); ARRAY_DEF(ElementArray, WidgetElement*, M_PTR_OPLIST);

View File

@@ -1,8 +1,9 @@
#include "gui/view.h"
#include <core/memmgr.h>
#include "view_stack.h" #include "view_stack.h"
#include "view_i.h" #include "view_i.h"
#include <gui/view.h>
#include <core/memmgr.h>
#define MAX_VIEWS 3 #define MAX_VIEWS 3
typedef struct { typedef struct {

View File

@@ -1,4 +1,4 @@
#include "furi_hal_light.h" #include <furi_hal_light.h>
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include <storage/storage.h> #include <storage/storage.h>

View File

@@ -1,4 +1,4 @@
#include "furi_hal_resources.h" #include <furi_hal_resources.h>
#include "notification.h" #include "notification.h"
#include "notification_messages_notes.h" #include "notification_messages_notes.h"
#include <stddef.h> #include <stddef.h>

View File

@@ -1,6 +1,5 @@
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include <stm32_adafruit_sd.h>
#include <cli/cli.h> #include <cli/cli.h>
#include <lib/toolbox/args.h> #include <lib/toolbox/args.h>
@@ -61,28 +60,26 @@ static void storage_cli_info(Cli* cli, FuriString* path) {
} }
} else if(furi_string_cmp_str(path, STORAGE_EXT_PATH_PREFIX) == 0) { } else if(furi_string_cmp_str(path, STORAGE_EXT_PATH_PREFIX) == 0) {
SDInfo sd_info; SDInfo sd_info;
SD_CID sd_cid;
FS_Error error = storage_sd_info(api, &sd_info); FS_Error error = storage_sd_info(api, &sd_info);
BSP_SD_GetCIDRegister(&sd_cid);
if(error != FSE_OK) { if(error != FSE_OK) {
storage_cli_print_error(error); storage_cli_print_error(error);
} else { } else {
printf( printf(
"Label: %s\r\nType: %s\r\n%luKiB total\r\n%luKiB free\r\n" "Label: %s\r\nType: %s\r\n%luKiB total\r\n%luKiB free\r\n"
"%02x%2.2s %5.5s %i.%i\r\nSN:%04lx %02i/%i\r\n", "%02x%s %s v%i.%i\r\nSN:%04lx %02i/%i\r\n",
sd_info.label, sd_info.label,
sd_api_get_fs_type_text(sd_info.fs_type), sd_api_get_fs_type_text(sd_info.fs_type),
sd_info.kb_total, sd_info.kb_total,
sd_info.kb_free, sd_info.kb_free,
sd_cid.ManufacturerID, sd_info.manufacturer_id,
sd_cid.OEM_AppliID, sd_info.oem_id,
sd_cid.ProdName, sd_info.product_name,
sd_cid.ProdRev >> 4, sd_info.product_revision_major,
sd_cid.ProdRev & 0xf, sd_info.product_revision_minor,
sd_cid.ProdSN, sd_info.product_serial_number,
sd_cid.ManufactMonth, sd_info.manufacturing_month,
sd_cid.ManufactYear + 2000); sd_info.manufacturing_year);
} }
} else { } else {
storage_cli_print_usage(); storage_cli_print_usage();

View File

@@ -12,9 +12,7 @@
#define TAG "StorageAPI" #define TAG "StorageAPI"
#define S_API_PROLOGUE \ #define S_API_PROLOGUE FuriApiLock lock = api_lock_alloc_locked();
FuriSemaphore* semaphore = furi_semaphore_alloc(1, 0); \
furi_check(semaphore != NULL);
#define S_FILE_API_PROLOGUE \ #define S_FILE_API_PROLOGUE \
Storage* storage = file->storage; \ Storage* storage = file->storage; \
@@ -24,13 +22,12 @@
furi_check( \ furi_check( \
furi_message_queue_put(storage->message_queue, &message, FuriWaitForever) == \ furi_message_queue_put(storage->message_queue, &message, FuriWaitForever) == \
FuriStatusOk); \ FuriStatusOk); \
furi_semaphore_acquire(semaphore, FuriWaitForever); \ api_lock_wait_unlock_and_free(lock)
furi_semaphore_free(semaphore);
#define S_API_MESSAGE(_command) \ #define S_API_MESSAGE(_command) \
SAReturn return_data; \ SAReturn return_data; \
StorageMessage message = { \ StorageMessage message = { \
.semaphore = semaphore, \ .lock = lock, \
.command = _command, \ .command = _command, \
.data = &data, \ .data = &data, \
.return_data = &return_data, \ .return_data = &return_data, \

View File

@@ -31,29 +31,13 @@ void storage_file_clear(StorageFile* obj) {
/****************** storage data ******************/ /****************** storage data ******************/
void storage_data_init(StorageData* storage) { void storage_data_init(StorageData* storage) {
storage->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
furi_check(storage->mutex != NULL);
storage->data = NULL; storage->data = NULL;
storage->status = StorageStatusNotReady; storage->status = StorageStatusNotReady;
StorageFileList_init(storage->files); StorageFileList_init(storage->files);
} }
bool storage_data_lock(StorageData* storage) {
return (furi_mutex_acquire(storage->mutex, FuriWaitForever) == FuriStatusOk);
}
bool storage_data_unlock(StorageData* storage) {
return (furi_mutex_release(storage->mutex) == FuriStatusOk);
}
StorageStatus storage_data_status(StorageData* storage) { StorageStatus storage_data_status(StorageData* storage) {
StorageStatus status; return storage->status;
storage_data_lock(storage);
status = storage->status;
storage_data_unlock(storage);
return status;
} }
const char* storage_data_status_text(StorageData* storage) { const char* storage_data_status_text(StorageData* storage) {

View File

@@ -38,8 +38,6 @@ void storage_file_set(StorageFile* obj, const StorageFile* src);
void storage_file_clear(StorageFile* obj); void storage_file_clear(StorageFile* obj);
void storage_data_init(StorageData* storage); void storage_data_init(StorageData* storage);
bool storage_data_lock(StorageData* storage);
bool storage_data_unlock(StorageData* storage);
StorageStatus storage_data_status(StorageData* storage); StorageStatus storage_data_status(StorageData* storage);
const char* storage_data_status_text(StorageData* storage); const char* storage_data_status_text(StorageData* storage);
void storage_data_timestamp(StorageData* storage); void storage_data_timestamp(StorageData* storage);
@@ -57,7 +55,6 @@ struct StorageData {
const FS_Api* fs_api; const FS_Api* fs_api;
StorageApi api; StorageApi api;
void* data; void* data;
FuriMutex* mutex;
StorageStatus status; StorageStatus status;
StorageFileList_t files; StorageFileList_t files;
uint32_t timestamp; uint32_t timestamp;

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <furi.h> #include <furi.h>
#include <toolbox/api_lock.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -130,7 +131,7 @@ typedef enum {
} StorageCommand; } StorageCommand;
typedef struct { typedef struct {
FuriSemaphore* semaphore; FuriApiLock lock;
StorageCommand command; StorageCommand command;
SAData* data; SAData* data;
SAReturn* return_data; SAReturn* return_data;

View File

@@ -2,15 +2,7 @@
#include <m-list.h> #include <m-list.h>
#include <m-dict.h> #include <m-dict.h>
#define FS_CALL(_storage, _fn) \ #define FS_CALL(_storage, _fn) ret = _storage->fs_api->_fn;
storage_data_lock(_storage); \
ret = _storage->fs_api->_fn; \
storage_data_unlock(_storage);
#define ST_CALL(_storage, _fn) \
storage_data_lock(_storage); \
ret = _storage->api._fn; \
storage_data_unlock(_storage);
static StorageData* storage_get_storage_by_type(Storage* app, StorageType type) { static StorageData* storage_get_storage_by_type(Storage* app, StorageType type) {
furi_check(type == ST_EXT || type == ST_INT); furi_check(type == ST_EXT || type == ST_INT);
@@ -44,16 +36,11 @@ static const char* remove_vfs(const char* path) {
static StorageType storage_get_type_by_path(Storage* app, const char* path) { static StorageType storage_get_type_by_path(Storage* app, const char* path) {
StorageType type = ST_ERROR; StorageType type = ST_ERROR;
if(strlen(path) >= strlen(STORAGE_EXT_PATH_PREFIX) && if(memcmp(path, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) {
memcmp(path, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) {
type = ST_EXT; type = ST_EXT;
} else if( } else if(memcmp(path, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) {
strlen(path) >= strlen(STORAGE_INT_PATH_PREFIX) &&
memcmp(path, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) {
type = ST_INT; type = ST_INT;
} else if( } else if(memcmp(path, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) {
strlen(path) >= strlen(STORAGE_ANY_PATH_PREFIX) &&
memcmp(path, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) {
type = ST_ANY; type = ST_ANY;
} }
@@ -68,21 +55,15 @@ static StorageType storage_get_type_by_path(Storage* app, const char* path) {
} }
static void storage_path_change_to_real_storage(FuriString* path, StorageType real_storage) { static void storage_path_change_to_real_storage(FuriString* path, StorageType real_storage) {
if(memcmp( if(furi_string_search(path, STORAGE_ANY_PATH_PREFIX) == 0) {
furi_string_get_cstr(path), STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) ==
0) {
switch(real_storage) { switch(real_storage) {
case ST_EXT: case ST_EXT:
furi_string_set_char(path, 0, STORAGE_EXT_PATH_PREFIX[0]); furi_string_replace_at(
furi_string_set_char(path, 1, STORAGE_EXT_PATH_PREFIX[1]); path, 0, strlen(STORAGE_EXT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX);
furi_string_set_char(path, 2, STORAGE_EXT_PATH_PREFIX[2]);
furi_string_set_char(path, 3, STORAGE_EXT_PATH_PREFIX[3]);
break; break;
case ST_INT: case ST_INT:
furi_string_set_char(path, 0, STORAGE_INT_PATH_PREFIX[0]); furi_string_replace_at(
furi_string_set_char(path, 1, STORAGE_INT_PATH_PREFIX[1]); path, 0, strlen(STORAGE_INT_PATH_PREFIX), STORAGE_INT_PATH_PREFIX);
furi_string_set_char(path, 2, STORAGE_INT_PATH_PREFIX[2]);
furi_string_set_char(path, 3, STORAGE_INT_PATH_PREFIX[3]);
break; break;
default: default:
break; break;
@@ -604,7 +585,7 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) {
break; break;
} }
furi_semaphore_release(message->semaphore); api_lock_unlock(message->lock);
} }
void storage_process_message(Storage* app, StorageMessage* message) { void storage_process_message(Storage* app, StorageMessage* message) {

View File

@@ -23,6 +23,16 @@ typedef struct {
uint16_t cluster_size; uint16_t cluster_size;
uint16_t sector_size; uint16_t sector_size;
char label[SD_LABEL_LENGTH]; char label[SD_LABEL_LENGTH];
uint8_t manufacturer_id;
char oem_id[3];
char product_name[6];
uint8_t product_revision_major;
uint8_t product_revision_minor;
uint32_t product_serial_number;
uint8_t manufacturing_month;
uint16_t manufacturing_year;
FS_Error error; FS_Error error;
} SDInfo; } SDInfo;

View File

@@ -26,12 +26,10 @@ static FS_Error storage_ext_parse_error(SDError error);
static bool sd_mount_card(StorageData* storage, bool notify) { static bool sd_mount_card(StorageData* storage, bool notify) {
bool result = false; bool result = false;
uint8_t counter = BSP_SD_MaxMountRetryCount(); uint8_t counter = sd_max_mount_retry_count();
uint8_t bsp_result; uint8_t bsp_result;
SDData* sd_data = storage->data; SDData* sd_data = storage->data;
storage_data_lock(storage);
while(result == false && counter > 0 && hal_sd_detect()) { while(result == false && counter > 0 && hal_sd_detect()) {
if(notify) { if(notify) {
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
@@ -41,9 +39,9 @@ static bool sd_mount_card(StorageData* storage, bool notify) {
if((counter % 2) == 0) { if((counter % 2) == 0) {
// power reset sd card // power reset sd card
bsp_result = BSP_SD_Init(true); bsp_result = sd_init(true);
} else { } else {
bsp_result = BSP_SD_Init(false); bsp_result = sd_init(false);
} }
if(bsp_result) { if(bsp_result) {
@@ -91,7 +89,6 @@ static bool sd_mount_card(StorageData* storage, bool notify) {
} }
storage_data_timestamp(storage); storage_data_timestamp(storage);
storage_data_unlock(storage);
return result; return result;
} }
@@ -100,14 +97,12 @@ FS_Error sd_unmount_card(StorageData* storage) {
SDData* sd_data = storage->data; SDData* sd_data = storage->data;
SDError error; SDError error;
storage_data_lock(storage);
storage->status = StorageStatusNotReady; storage->status = StorageStatusNotReady;
error = FR_DISK_ERR; error = FR_DISK_ERR;
// TODO do i need to close the files? // TODO do i need to close the files?
f_mount(0, sd_data->path, 0); f_mount(0, sd_data->path, 0);
storage_data_unlock(storage);
return storage_ext_parse_error(error); return storage_ext_parse_error(error);
} }
@@ -120,8 +115,6 @@ FS_Error sd_format_card(StorageData* storage) {
SDData* sd_data = storage->data; SDData* sd_data = storage->data;
SDError error; SDError error;
storage_data_lock(storage);
work_area = malloc(_MAX_SS); work_area = malloc(_MAX_SS);
error = f_mkfs(sd_data->path, FM_ANY, 0, work_area, _MAX_SS); error = f_mkfs(sd_data->path, FM_ANY, 0, work_area, _MAX_SS);
free(work_area); free(work_area);
@@ -138,8 +131,6 @@ FS_Error sd_format_card(StorageData* storage) {
storage->status = StorageStatusOK; storage->status = StorageStatusOK;
} while(false); } while(false);
storage_data_unlock(storage);
return storage_ext_parse_error(error); return storage_ext_parse_error(error);
#endif #endif
} }
@@ -156,14 +147,12 @@ FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info) {
memset(sd_info, 0, sizeof(SDInfo)); memset(sd_info, 0, sizeof(SDInfo));
// get fs info // get fs info
storage_data_lock(storage);
error = f_getlabel(sd_data->path, sd_info->label, NULL); error = f_getlabel(sd_data->path, sd_info->label, NULL);
if(error == FR_OK) { if(error == FR_OK) {
#ifndef FURI_RAM_EXEC #ifndef FURI_RAM_EXEC
error = f_getfree(sd_data->path, &free_clusters, &fs); error = f_getfree(sd_data->path, &free_clusters, &fs);
#endif #endif
} }
storage_data_unlock(storage);
if(error == FR_OK) { if(error == FR_OK) {
// calculate size // calculate size
@@ -210,6 +199,20 @@ FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info) {
#endif #endif
} }
SD_CID cid;
SdSpiStatus status = sd_get_cid(&cid);
if(status == SdSpiStatusOK) {
sd_info->manufacturer_id = cid.ManufacturerID;
memcpy(sd_info->oem_id, cid.OEM_AppliID, sizeof(cid.OEM_AppliID));
memcpy(sd_info->product_name, cid.ProdName, sizeof(cid.ProdName));
sd_info->product_revision_major = cid.ProdRev >> 4;
sd_info->product_revision_minor = cid.ProdRev & 0x0F;
sd_info->product_serial_number = cid.ProdSN;
sd_info->manufacturing_year = 2000 + cid.ManufactYear;
sd_info->manufacturing_month = cid.ManufactMonth;
}
return storage_ext_parse_error(error); return storage_ext_parse_error(error);
} }

View File

@@ -13,17 +13,29 @@ typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMess
static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* message) { static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* message) {
DialogMessageButton result; DialogMessageButton result;
const char* screen_header = "Product: Flipper Zero\n" FuriString* screen_header = furi_string_alloc_printf(
"Model: FZ.1\n"; "Product: %s\n"
const char* screen_text = "FCC ID: 2A2V6-FZ\n" "Model: %s",
"IC: 27624-FZ"; furi_hal_version_get_model_name(),
furi_hal_version_get_model_code());
dialog_message_set_header(message, screen_header, 0, 0, AlignLeft, AlignTop); FuriString* screen_text = furi_string_alloc_printf(
dialog_message_set_text(message, screen_text, 0, 26, AlignLeft, AlignTop); "FCC ID: %s\n"
"IC: %s",
furi_hal_version_get_fcc_id(),
furi_hal_version_get_ic_id());
dialog_message_set_header(
message, furi_string_get_cstr(screen_header), 0, 0, AlignLeft, AlignTop);
dialog_message_set_text(
message, furi_string_get_cstr(screen_text), 0, 26, AlignLeft, AlignTop);
result = dialog_message_show(dialogs, message); result = dialog_message_show(dialogs, message);
dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop); dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop);
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
furi_string_free(screen_header);
furi_string_free(screen_text);
return result; return result;
} }

View File

@@ -1,5 +1,5 @@
#include "../bt_settings_app.h" #include "../bt_settings_app.h"
#include "furi_hal_bt.h" #include <furi_hal_bt.h>
void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result, void* context) { void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result, void* context) {
furi_assert(context); furi_assert(context);

View File

@@ -1,5 +1,5 @@
#include "../bt_settings_app.h" #include "../bt_settings_app.h"
#include "furi_hal_bt.h" #include <furi_hal_bt.h>
void bt_settings_app_scene_forget_dev_success_popup_callback(void* context) { void bt_settings_app_scene_forget_dev_success_popup_callback(void* context) {
BtSettingsApp* app = context; BtSettingsApp* app = context;

View File

@@ -1,5 +1,5 @@
#include "../bt_settings_app.h" #include "../bt_settings_app.h"
#include "furi_hal_bt.h" #include <furi_hal_bt.h>
enum BtSetting { enum BtSetting {
BtSettingOff, BtSettingOff,

View File

@@ -1,5 +1,4 @@
#include "../storage_settings.h" #include "../storage_settings.h"
#include <stm32_adafruit_sd.h>
static void storage_settings_scene_sd_info_dialog_callback(DialogExResult result, void* context) { static void storage_settings_scene_sd_info_dialog_callback(DialogExResult result, void* context) {
StorageSettings* app = context; StorageSettings* app = context;
@@ -12,9 +11,7 @@ void storage_settings_scene_sd_info_on_enter(void* context) {
DialogEx* dialog_ex = app->dialog_ex; DialogEx* dialog_ex = app->dialog_ex;
SDInfo sd_info; SDInfo sd_info;
SD_CID sd_cid;
FS_Error sd_status = storage_sd_info(app->fs_api, &sd_info); FS_Error sd_status = storage_sd_info(app->fs_api, &sd_info);
BSP_SD_GetCIDRegister(&sd_cid);
scene_manager_set_scene_state(app->scene_manager, StorageSettingsSDInfo, sd_status); scene_manager_set_scene_state(app->scene_manager, StorageSettingsSDInfo, sd_status);
@@ -31,19 +28,19 @@ void storage_settings_scene_sd_info_on_enter(void* context) {
furi_string_printf( furi_string_printf(
app->text_string, app->text_string,
"Label: %s\nType: %s\n%lu KiB total\n%lu KiB free\n" "Label: %s\nType: %s\n%lu KiB total\n%lu KiB free\n"
"%02X%2.2s %5.5s %i.%i\nSN:%04lX %02i/%i", "%02X%s %s v%i.%i\nSN:%04lX %02i/%i",
sd_info.label, sd_info.label,
sd_api_get_fs_type_text(sd_info.fs_type), sd_api_get_fs_type_text(sd_info.fs_type),
sd_info.kb_total, sd_info.kb_total,
sd_info.kb_free, sd_info.kb_free,
sd_cid.ManufacturerID, sd_info.manufacturer_id,
sd_cid.OEM_AppliID, sd_info.oem_id,
sd_cid.ProdName, sd_info.product_name,
sd_cid.ProdRev >> 4, sd_info.product_revision_major,
sd_cid.ProdRev & 0xf, sd_info.product_revision_minor,
sd_cid.ProdSN, sd_info.product_serial_number,
sd_cid.ManufactMonth, sd_info.manufacturing_month,
sd_cid.ManufactYear + 2000); sd_info.manufacturing_year);
dialog_ex_set_text( dialog_ex_set_text(
dialog_ex, furi_string_get_cstr(app->text_string), 4, 1, AlignLeft, AlignTop); dialog_ex, furi_string_get_cstr(app->text_string), 4, 1, AlignLeft, AlignTop);
} }

View File

@@ -1,7 +1,7 @@
#include "../storage_move_to_sd.h" #include "../storage_move_to_sd.h"
#include "gui/canvas.h" #include <gui/canvas.h>
#include "gui/modules/widget_elements/widget_element_i.h" #include <gui/modules/widget_elements/widget_element_i.h>
#include "storage/storage.h" #include <storage/storage.h>
static void storage_move_to_sd_scene_confirm_widget_callback( static void storage_move_to_sd_scene_confirm_widget_callback(
GuiButtonType result, GuiButtonType result,

View File

@@ -1,17 +1,16 @@
#pragma once #pragma once
#include "gui/modules/widget_elements/widget_element_i.h"
#include <furi.h>
#include <gui/gui.h> #include <gui/gui.h>
#include <gui/view.h> #include <gui/view.h>
#include <gui/view_dispatcher.h> #include <gui/view_dispatcher.h>
#include <gui/scene_manager.h> #include <gui/scene_manager.h>
#include <notification/notification_messages.h>
#include <gui/modules/widget.h> #include <gui/modules/widget.h>
#include <gui/modules/popup.h> #include <gui/modules/popup.h>
#include <gui/modules/widget_elements/widget_element_i.h>
#include <notification/notification_messages.h>
#include <storage/storage.h> #include <storage/storage.h>
#include <storage/storage_sd_api.h> #include <storage/storage_sd_api.h>
#include <furi.h>
#include "scenes/storage_move_to_sd_scene.h" #include "scenes/storage_move_to_sd_scene.h"

View File

@@ -76,8 +76,8 @@ static void updater_cli_ep(Cli* cli, FuriString* args, void* context) {
for(size_t idx = 0; idx < COUNT_OF(update_cli_subcommands); ++idx) { for(size_t idx = 0; idx < COUNT_OF(update_cli_subcommands); ++idx) {
const CliSubcommand* subcmd_def = &update_cli_subcommands[idx]; const CliSubcommand* subcmd_def = &update_cli_subcommands[idx];
if(furi_string_cmp_str(subcommand, subcmd_def->command) == 0) { if(furi_string_cmp_str(subcommand, subcmd_def->command) == 0) {
furi_string_free(subcommand);
subcmd_def->handler(args); subcmd_def->handler(args);
furi_string_free(subcommand);
return; return;
} }
} }

View File

@@ -287,7 +287,9 @@ bool update_task_parse_manifest(UpdateTask* update_task) {
} }
update_task_set_progress(update_task, UpdateTaskStageProgress, 50); update_task_set_progress(update_task, UpdateTaskStageProgress, 50);
if(manifest->target != furi_hal_version_get_hw_target()) { /* Check target only if it's set - skipped for pre-production samples */
if(furi_hal_version_get_hw_target() &&
(manifest->target != furi_hal_version_get_hw_target())) {
break; break;
} }

View File

@@ -0,0 +1,44 @@
## What a Firmware Target is
Flipper's firmware is modular and supports different hardware configurations in a common code base. It encapsulates hardware-specific differences in `furi_hal`, board initialization code, linker files, SDK data and other information in a _target definition_.
Target-specific files are placed in a single sub-folder in `firmware/targets`. It must contain a target definition file, `target.json`, and may contain other files if they are referenced by current target's definition. By default, `fbt` gathers all source files in target folder, unless they are explicitly excluded.
Targets can inherit most code parts from other targets, to reduce common code duplication.
## Target Definition File
A target definition file, `target.json`, is a JSON file that can contain the following fields:
* `include_paths`: list of strings, folder paths relative to current target folder to add to global C/C++ header path lookup list.
* `sdk_header_paths`: list of strings, folder paths relative to current target folder to gather headers from for including in SDK.
* `startup_script`: filename of a startup script, performing initial hardware initialization.
* `linker_script_flash`: filename of a linker script for creating the main firmware image.
* `linker_script_ram`: filename of a linker script to use in "updater" build configuration.
* `linker_script_app`: filename of a linker script to use for linking .fap files.
* `sdk_symbols`: filename of a .csv file containing current SDK configuration for this target.
* `linker_dependencies`: list of libraries to link the firmware with. Note that those not in the list won't be built by `fbt`. Also several link passes might be needed, in such case you may need to specify same library name twice.
* `inherit`: string, specifies hardware target to borrow main configuration from. Current configuration may specify additional values for parameters that are lists of strings, or override values that are not lists.
* `excluded_sources`: list of filenames from the inherited configuration(s) NOT to be built.
* `excluded_headers`: list of headers from the inherited configuration(s) NOT to be included in generated SDK.
* `excluded_modules`: list of strings specifying fbt library (module) names to exclude from being used to configure build environment.
## Applications & Hardware
Not all applications are available on different hardware targets.
* For applications built into the firmware, you have to specify a compatible application set using `FIRMWARE_APP_SET=...` fbt option. See [fbt docs](./fbt.md#firmware-application-set) for details on build configurations.
* For applications built as external .faps, you have to explicitly specify compatible targets in application's manifest, `application.fam`. For example, to limit application to a single target, add `targets=["f7"],` to the manifest. It won't be built for other targets.
For details on application manifests, check out [their docs page](./AppManifests.md).
## Building Firmware for a Specific Target
You have to specify TARGET_HW (and, optionally, FIRMWARE_APP_SET) for `fbt` to build firmware for non-default target. For example, building and flashing debug firmware for f18 can be done with
./fbt TARGET_HW=18 flash_usb_full

Some files were not shown because too many files have changed in this diff Show More