mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
Merge branch 'fz-dev' into dev
This commit is contained in:
7
.vscode/extensions.json
vendored
7
.vscode/extensions.json
vendored
@@ -11,5 +11,8 @@
|
||||
"augustocdias.tasks-shell-input"
|
||||
],
|
||||
// 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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ App(
|
||||
appid="accessor",
|
||||
name="Accessor",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
targets=["f7"],
|
||||
entry_point="accessor_app",
|
||||
cdefines=["APP_ACCESSOR"],
|
||||
requires=["gui"],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "bt_carrier_test.h"
|
||||
#include "bt_test.h"
|
||||
#include "bt_test_types.h"
|
||||
#include "furi_hal_bt.h"
|
||||
#include <furi_hal_bt.h>
|
||||
|
||||
struct BtCarrierTest {
|
||||
BtTest* bt_test;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "bt_packet_test.h"
|
||||
#include "bt_test.h"
|
||||
#include "bt_test_types.h"
|
||||
#include "furi_hal_bt.h"
|
||||
#include <furi_hal_bt.h>
|
||||
|
||||
struct BtPacketTest {
|
||||
BtTest* bt_test;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include <file_browser_test_icons.h>
|
||||
#include "file_browser_app_i.h"
|
||||
#include "gui/modules/file_browser.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <file_browser_test_icons.h>
|
||||
|
||||
#include <gui/modules/file_browser.h>
|
||||
#include <storage/storage.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) {
|
||||
furi_assert(context);
|
||||
|
||||
@@ -2,6 +2,7 @@ App(
|
||||
appid="lfrfid_debug",
|
||||
name="LF-RFID Debug",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
targets=["f7"],
|
||||
entry_point="lfrfid_debug_app",
|
||||
requires=[
|
||||
"gui",
|
||||
|
||||
@@ -89,7 +89,7 @@ static void test_rpc_setup(void) {
|
||||
}
|
||||
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[0].close_session_semaphore = xSemaphoreCreateBinary();
|
||||
rpc_session[0].terminate_semaphore = xSemaphoreCreateBinary();
|
||||
|
||||
44
applications/examples/example_thermo/README.md
Normal file
44
applications/examples/example_thermo/README.md
Normal 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.
|
||||
10
applications/examples/example_thermo/application.fam
Normal file
10
applications/examples/example_thermo/application.fam
Normal 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",
|
||||
)
|
||||
356
applications/examples/example_thermo/example_thermo.c
Normal file
356
applications/examples/example_thermo/example_thermo.c
Normal 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;
|
||||
}
|
||||
BIN
applications/examples/example_thermo/example_thermo_10px.png
Normal file
BIN
applications/examples/example_thermo/example_thermo_10px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
@@ -1,10 +1,11 @@
|
||||
#include <archive/views/archive_browser_view.h>
|
||||
#include "archive_files.h"
|
||||
#include "archive_apps.h"
|
||||
#include "archive_browser.h"
|
||||
#include "../views/archive_browser_view.h"
|
||||
|
||||
#include <core/common_defines.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 <math.h>
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "../helpers/archive_files.h"
|
||||
#include "../helpers/archive_favorites.h"
|
||||
|
||||
#include <gui/gui_i.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
#include <gui/modules/file_browser_worker.h>
|
||||
#include <storage/storage.h>
|
||||
#include "../helpers/archive_files.h"
|
||||
#include "../helpers/archive_menu.h"
|
||||
#include "../helpers/archive_favorites.h"
|
||||
#include "gui/modules/file_browser_worker.h"
|
||||
#include <furi.h>
|
||||
|
||||
#define MAX_LEN_PX 110
|
||||
#define MAX_NAME_LEN 255
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../bad_usb_app_i.h"
|
||||
#include "furi_hal_power.h"
|
||||
#include "furi_hal_usb.h"
|
||||
#include <furi_hal_power.h>
|
||||
#include <furi_hal_usb.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
static bool bad_usb_file_select(BadUsbApp* bad_usb) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "../bad_usb_script.h"
|
||||
#include "../bad_usb_app_i.h"
|
||||
#include "../views/bad_usb_view.h"
|
||||
#include "furi_hal.h"
|
||||
#include <furi_hal.h>
|
||||
#include "toolbox/path.h"
|
||||
|
||||
void bad_usb_scene_work_button_callback(InputKey key, void* context) {
|
||||
|
||||
@@ -25,6 +25,7 @@ GpioApp* gpio_app_alloc() {
|
||||
GpioApp* app = malloc(sizeof(GpioApp));
|
||||
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->gpio_items = gpio_items_alloc();
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app);
|
||||
@@ -47,7 +48,7 @@ GpioApp* gpio_app_alloc() {
|
||||
app->view_dispatcher,
|
||||
GpioAppViewVarItemList,
|
||||
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(
|
||||
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_NOTIFICATION);
|
||||
|
||||
gpio_items_free(app->gpio_items);
|
||||
free(app);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "gpio_app.h"
|
||||
#include "gpio_item.h"
|
||||
#include "gpio_items.h"
|
||||
#include "scenes/gpio_scene.h"
|
||||
#include "gpio_custom_event.h"
|
||||
#include "usb_uart_bridge.h"
|
||||
@@ -28,6 +28,7 @@ struct GpioApp {
|
||||
VariableItem* var_item_flow;
|
||||
GpioTest* gpio_test;
|
||||
GpioUsbUart* gpio_usb_uart;
|
||||
GPIOItems* gpio_items;
|
||||
UsbUartBridge* usb_uart_bridge;
|
||||
UsbUartConfig* usb_uart_cfg;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
69
applications/main/gpio/gpio_items.c
Normal file
69
applications/main/gpio/gpio_items.c
Normal 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;
|
||||
}
|
||||
}
|
||||
29
applications/main/gpio/gpio_items.h
Normal file
29
applications/main/gpio/gpio_items.h
Normal 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
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../gpio_app_i.h"
|
||||
#include "furi_hal_power.h"
|
||||
#include "furi_hal_usb.h"
|
||||
#include <furi_hal_power.h>
|
||||
#include <furi_hal_usb.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
enum GpioItem {
|
||||
|
||||
@@ -12,8 +12,9 @@ void gpio_scene_test_ok_callback(InputType type, void* context) {
|
||||
}
|
||||
|
||||
void gpio_scene_test_on_enter(void* context) {
|
||||
furi_assert(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);
|
||||
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) {
|
||||
UNUSED(context);
|
||||
gpio_item_configure_all_pins(GpioModeAnalog);
|
||||
furi_assert(context);
|
||||
GpioApp* app = context;
|
||||
gpio_items_configure_all_pins(app->gpio_items, GpioModeAnalog);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../usb_uart_bridge.h"
|
||||
#include "../gpio_app_i.h"
|
||||
#include "furi_hal.h"
|
||||
#include <furi_hal.h>
|
||||
|
||||
typedef enum {
|
||||
UsbUartLineIndexVcp,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "usb_uart_bridge.h"
|
||||
#include "furi_hal.h"
|
||||
#include <furi_hal_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 "cli/cli.h"
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_usb_cdc.h>
|
||||
|
||||
#define USB_CDC_PKT_LEN CDC_DATA_SZ
|
||||
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "gpio_test.h"
|
||||
#include "../gpio_item.h"
|
||||
#include "../gpio_items.h"
|
||||
|
||||
#include <gui/elements.h>
|
||||
|
||||
@@ -11,6 +11,7 @@ struct GpioTest {
|
||||
|
||||
typedef struct {
|
||||
uint8_t pin_idx;
|
||||
GPIOItems* gpio_items;
|
||||
} GpioTestModel;
|
||||
|
||||
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(
|
||||
canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin");
|
||||
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) {
|
||||
@@ -64,7 +70,7 @@ static bool gpio_test_process_right(GpioTest* gpio_test) {
|
||||
gpio_test->view,
|
||||
GpioTestModel * model,
|
||||
{
|
||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
||||
if(model->pin_idx < gpio_items_get_count(model->gpio_items)) {
|
||||
model->pin_idx++;
|
||||
}
|
||||
},
|
||||
@@ -80,17 +86,17 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
|
||||
GpioTestModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress) {
|
||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
||||
gpio_item_set_pin(model->pin_idx, true);
|
||||
if(model->pin_idx < gpio_items_get_count(model->gpio_items)) {
|
||||
gpio_items_set_pin(model->gpio_items, model->pin_idx, true);
|
||||
} else {
|
||||
gpio_item_set_all_pins(true);
|
||||
gpio_items_set_all_pins(model->gpio_items, true);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
||||
gpio_item_set_pin(model->pin_idx, false);
|
||||
if(model->pin_idx < gpio_items_get_count(model->gpio_items)) {
|
||||
gpio_items_set_pin(model->gpio_items, model->pin_idx, false);
|
||||
} else {
|
||||
gpio_item_set_all_pins(false);
|
||||
gpio_items_set_all_pins(model->gpio_items, false);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
@@ -101,11 +107,15 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
GpioTest* gpio_test_alloc() {
|
||||
GpioTest* gpio_test_alloc(GPIOItems* gpio_items) {
|
||||
GpioTest* gpio_test = malloc(sizeof(GpioTest));
|
||||
|
||||
gpio_test->view = view_alloc();
|
||||
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_draw_callback(gpio_test->view, gpio_test_draw_callback);
|
||||
view_set_input_callback(gpio_test->view, gpio_test_input_callback);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gpio_items.h"
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct GpioTest GpioTest;
|
||||
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);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../usb_uart_bridge.h"
|
||||
#include "../gpio_app_i.h"
|
||||
#include "furi_hal.h"
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
struct GpioUsbUart {
|
||||
|
||||
@@ -2,6 +2,7 @@ App(
|
||||
appid="ibutton",
|
||||
name="iButton",
|
||||
apptype=FlipperAppType.APP,
|
||||
targets=["f7"],
|
||||
entry_point="ibutton_app",
|
||||
cdefines=["APP_IBUTTON"],
|
||||
requires=[
|
||||
|
||||
@@ -271,7 +271,7 @@ void onewire_cli_print_usage() {
|
||||
|
||||
static void onewire_cli_search(Cli* cli) {
|
||||
UNUSED(cli);
|
||||
OneWireHost* onewire = onewire_host_alloc();
|
||||
OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio);
|
||||
uint8_t address[8];
|
||||
bool done = false;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ App(
|
||||
name="Infrared",
|
||||
apptype=FlipperAppType.APP,
|
||||
entry_point="infrared_app",
|
||||
targets=["f7"],
|
||||
cdefines=["APP_INFRARED"],
|
||||
requires=[
|
||||
"gui",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "../infrared_i.h"
|
||||
#include "gui/canvas.h"
|
||||
#include <gui/canvas.h>
|
||||
|
||||
typedef enum {
|
||||
InfraredRpcStateIdle,
|
||||
|
||||
@@ -52,7 +52,8 @@ void infrared_scene_universal_on_enter(void* context) {
|
||||
infrared_scene_universal_submenu_callback,
|
||||
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);
|
||||
}
|
||||
@@ -79,6 +80,7 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(scene_manager, InfraredSceneUniversal, event.event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "infrared_debug_view.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define INFRARED_DEBUG_TEXT_LENGTH 64
|
||||
|
||||
struct InfraredDebugView {
|
||||
|
||||
@@ -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 "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>
|
||||
|
||||
struct InfraredProgressView {
|
||||
|
||||
@@ -2,6 +2,7 @@ App(
|
||||
appid="lfrfid",
|
||||
name="125 kHz RFID",
|
||||
apptype=FlipperAppType.APP,
|
||||
targets=["f7"],
|
||||
entry_point="lfrfid_app",
|
||||
cdefines=["APP_LF_RFID"],
|
||||
requires=[
|
||||
|
||||
@@ -47,21 +47,28 @@ bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexRead) {
|
||||
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexRead);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
|
||||
DOLPHIN_DEED(DolphinDeedRfidRead);
|
||||
consumed = true;
|
||||
} 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);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexAddManually) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, LfRfidSceneStart, SubmenuIndexAddManually);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexExtraActions) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, LfRfidSceneStart, SubmenuIndexExtraActions);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, event.event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
|
||||
@@ -2,6 +2,7 @@ App(
|
||||
appid="nfc",
|
||||
name="NFC",
|
||||
apptype=FlipperAppType.APP,
|
||||
targets=["f7"],
|
||||
entry_point="nfc_app",
|
||||
cdefines=["APP_NFC"],
|
||||
requires=[
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "nfc_i.h"
|
||||
#include "furi_hal_nfc.h"
|
||||
#include <furi_hal_nfc.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
bool nfc_custom_event_callback(void* context, uint32_t event) {
|
||||
|
||||
@@ -4,7 +4,7 @@ ADD_SCENE(nfc, saved_menu, SavedMenu)
|
||||
ADD_SCENE(nfc, extra_actions, ExtraActions)
|
||||
ADD_SCENE(nfc, set_type, SetType)
|
||||
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, generate_info, GenerateInfo)
|
||||
ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
|
||||
|
||||
@@ -30,7 +30,7 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
|
||||
nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||
} else {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneStart);
|
||||
nfc->scene_manager, NfcSceneFileSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ void nfc_scene_extra_actions_on_enter(void* context) {
|
||||
SubmenuIndexMfUltralightUnlock,
|
||||
nfc_scene_extra_actions_submenu_callback,
|
||||
nfc);
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions));
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ void nfc_scene_set_atqa_on_enter(void* context) {
|
||||
|
||||
// Setup view
|
||||
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,
|
||||
nfc_scene_set_atqa_byte_input_callback,
|
||||
|
||||
@@ -28,7 +28,7 @@ bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventByteInputDone) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqa);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ void nfc_scene_set_uid_on_enter(void* context) {
|
||||
|
||||
// Setup view
|
||||
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;
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
|
||||
@@ -48,11 +48,14 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexRead) {
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead);
|
||||
nfc->dev->dev_data.read_mode = NfcReadModeAuto;
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||
consumed = true;
|
||||
} 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;
|
||||
if(sd_exist) {
|
||||
nfc_device_data_clear(&nfc->dev->dev_data);
|
||||
@@ -63,19 +66,27 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
consumed = true;
|
||||
} 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);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexExtraAction) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneStart, SubmenuIndexExtraAction);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexAddManually) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManually);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexDebug) {
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, event.event);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ App(
|
||||
appid="subghz",
|
||||
name="Sub-GHz",
|
||||
apptype=FlipperAppType.APP,
|
||||
targets=["f7"],
|
||||
entry_point="subghz_app",
|
||||
cdefines=["APP_SUBGHZ"],
|
||||
requires=[
|
||||
|
||||
@@ -31,6 +31,9 @@ bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
|
||||
} else if(scene_manager_search_and_switch_to_previous_scene(
|
||||
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);
|
||||
} else {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "../u2f_app_i.h"
|
||||
#include "../views/u2f_view.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
#include "furi_hal.h"
|
||||
#include <furi_hal.h>
|
||||
#include "../u2f.h"
|
||||
|
||||
#define U2F_REQUEST_TIMEOUT 500
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <storage/storage.h>
|
||||
#include <lib/flipper_format/flipper_format.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <m-array.h>
|
||||
|
||||
#define TAG "MusicPlayerWorker"
|
||||
|
||||
@@ -2,6 +2,7 @@ App(
|
||||
appid="nfc_magic",
|
||||
name="NFC Magic",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
targets=["f7"],
|
||||
entry_point="nfc_magic_app",
|
||||
requires=[
|
||||
"storage",
|
||||
|
||||
@@ -136,9 +136,9 @@ void nfc_magic_free(NfcMagic* 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_set_color_blue,
|
||||
&message_blink_set_color_cyan,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
@@ -149,7 +149,7 @@ static const NotificationSequence nfc_magic_sequence_blink_stop = {
|
||||
};
|
||||
|
||||
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) {
|
||||
|
||||
@@ -40,16 +40,24 @@ bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexCheck) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck);
|
||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck);
|
||||
consumed = true;
|
||||
} 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);
|
||||
consumed = true;
|
||||
} 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);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(nfc_magic->scene_manager, NfcMagicSceneStart, event.event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
|
||||
@@ -2,6 +2,7 @@ App(
|
||||
appid="Picopass",
|
||||
name="PicoPass Reader",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
targets=["f7"],
|
||||
entry_point="picopass_app",
|
||||
requires=[
|
||||
"storage",
|
||||
|
||||
@@ -137,9 +137,9 @@ void picopass_text_store_clear(Picopass* picopass) {
|
||||
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_set_color_blue,
|
||||
&message_blink_set_color_cyan,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
@@ -150,7 +150,7 @@ static const NotificationSequence picopass_sequence_blink_stop = {
|
||||
};
|
||||
|
||||
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) {
|
||||
|
||||
@@ -32,13 +32,18 @@ bool picopass_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexRead) {
|
||||
scene_manager_set_scene_state(
|
||||
picopass->scene_manager, PicopassSceneStart, SubmenuIndexRead);
|
||||
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCard);
|
||||
consumed = true;
|
||||
} 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);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(picopass->scene_manager, PicopassSceneStart, event.event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "scenes/signal_gen_scene.h"
|
||||
|
||||
#include "furi_hal_clock.h"
|
||||
#include "furi_hal_pwm.h"
|
||||
#include <furi_hal_clock.h>
|
||||
#include <furi_hal_pwm.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
#include "furi_hal.h"
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
#include <Signal_Generator_icons.h>
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ App(
|
||||
appid="weather_station",
|
||||
name="Weather Station",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
targets=["f7"],
|
||||
entry_point="weather_station_app",
|
||||
cdefines=["APP_WEATHER_STATION"],
|
||||
requires=["gui"],
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <lib/flipper_format/flipper_format.h>
|
||||
#include "furi.h"
|
||||
#include "furi_hal.h"
|
||||
#include <furi_hal.h>
|
||||
#include <lib/subghz/types.h>
|
||||
#include <locale/locale.h>
|
||||
|
||||
|
||||
@@ -5,28 +5,6 @@
|
||||
#include <furi_hal.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() {
|
||||
printf("Usage:\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) {
|
||||
bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
|
||||
for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) {
|
||||
if(furi_string_equal(pin_name, cli_command_gpio_pins[i].name)) {
|
||||
if(!cli_command_gpio_pins[i].debug || is_debug_mode) {
|
||||
for(size_t i = 0; i < gpio_pins_count; i++) {
|
||||
if(furi_string_equal(pin_name, gpio_pins[i].name)) {
|
||||
if(!gpio_pins[i].debug || is_debug_mode) {
|
||||
*result = i;
|
||||
return true;
|
||||
}
|
||||
@@ -53,9 +31,9 @@ static bool pin_name_to_int(FuriString* pin_name, size_t* result) {
|
||||
static void gpio_print_pins(void) {
|
||||
printf("Wrong pin name. Available pins: ");
|
||||
bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug);
|
||||
for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) {
|
||||
if(!cli_command_gpio_pins[i].debug || is_debug_mode) {
|
||||
printf("%s ", cli_command_gpio_pins[i].name);
|
||||
for(size_t i = 0; i < gpio_pins_count; i++) {
|
||||
if(!gpio_pins[i].debug || is_debug_mode) {
|
||||
printf("%s ", gpio_pins[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,7 +91,7 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(cli_command_gpio_pins[num].debug) { //-V779
|
||||
if(gpio_pins[num].debug) { //-V779
|
||||
printf(
|
||||
"Changing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n");
|
||||
char c = cli_getc(cli);
|
||||
@@ -124,12 +102,12 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
|
||||
}
|
||||
|
||||
if(value == 1) { // output
|
||||
furi_hal_gpio_write(cli_command_gpio_pins[num].pin, false);
|
||||
furi_hal_gpio_init_simple(cli_command_gpio_pins[num].pin, GpioModeOutputPushPull);
|
||||
printf("Pin %s is now an output (low)", cli_command_gpio_pins[num].name);
|
||||
furi_hal_gpio_write(gpio_pins[num].pin, false);
|
||||
furi_hal_gpio_init_simple(gpio_pins[num].pin, GpioModeOutputPushPull);
|
||||
printf("Pin %s is now an output (low)", gpio_pins[num].name);
|
||||
} else { // input
|
||||
furi_hal_gpio_init_simple(cli_command_gpio_pins[num].pin, GpioModeInput);
|
||||
printf("Pin %s is now an input", cli_command_gpio_pins[num].name);
|
||||
furi_hal_gpio_init_simple(gpio_pins[num].pin, GpioModeInput);
|
||||
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
|
||||
LL_GPIO_GetPinMode(
|
||||
cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) {
|
||||
printf("Err: pin %s is not set as an input.", cli_command_gpio_pins[num].name);
|
||||
LL_GPIO_GetPinMode(gpio_pins[num].pin->port, gpio_pins[num].pin->pin)) {
|
||||
printf("Err: pin %s is not set as an input.", gpio_pins[num].name);
|
||||
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) {
|
||||
@@ -174,14 +151,13 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) {
|
||||
}
|
||||
|
||||
if(LL_GPIO_MODE_OUTPUT != //-V779
|
||||
LL_GPIO_GetPinMode(
|
||||
cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) {
|
||||
printf("Err: pin %s is not set as an output.", cli_command_gpio_pins[num].name);
|
||||
LL_GPIO_GetPinMode(gpio_pins[num].pin->port, gpio_pins[num].pin->pin)) {
|
||||
printf("Err: pin %s is not set as an output.", gpio_pins[num].name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Extra check if debug pins used
|
||||
if(cli_command_gpio_pins[num].debug) {
|
||||
if(gpio_pins[num].debug) {
|
||||
printf(
|
||||
"Setting this pin may damage hardware. Are you sure you want to continue? (y/n)?\r\n");
|
||||
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);
|
||||
printf("Pin %s => %u", cli_command_gpio_pins[num].name, !!value);
|
||||
furi_hal_gpio_write(gpio_pins[num].pin, !!value);
|
||||
printf("Pin %s => %u", gpio_pins[num].name, !!value);
|
||||
}
|
||||
|
||||
void cli_command_gpio(Cli* cli, FuriString* args, void* context) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "dialogs/dialogs_message.h"
|
||||
#include "dialogs_message.h"
|
||||
#include "dialogs_i.h"
|
||||
#include <toolbox/api_lock.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "dialogs_i.h"
|
||||
|
||||
#include <gui/modules/file_browser.h>
|
||||
#include <toolbox/api_lock.h>
|
||||
#include "gui/modules/file_browser.h"
|
||||
|
||||
typedef struct {
|
||||
FuriApiLock lock;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <core/pubsub.h>
|
||||
#include "gui/view.h"
|
||||
#include "helpers/dolphin_deed.h"
|
||||
|
||||
#include <gui/view.h>
|
||||
#include <core/pubsub.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#include "elements.h"
|
||||
#include "m-core.h"
|
||||
#include <m-core.h>
|
||||
#include <assets_icons.h>
|
||||
#include "furi_hal_resources.h"
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi_hal.h>
|
||||
#include "gui/canvas.h"
|
||||
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/icon_i.h>
|
||||
#include <gui/icon_animation_i.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include "canvas_i.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "gui/canvas.h"
|
||||
#include "gui_i.h"
|
||||
#include <assets_icons.h>
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#include "button_menu.h"
|
||||
#include "gui/canvas.h"
|
||||
#include "gui/elements.h"
|
||||
#include "input/input.h"
|
||||
#include <m-array.h>
|
||||
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/elements.h>
|
||||
#include <input/input.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include <stdint.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <m-array.h>
|
||||
|
||||
#define ITEM_FIRST_OFFSET 17
|
||||
#define ITEM_NEXT_OFFSET 4
|
||||
#define ITEM_HEIGHT 14
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#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-i-list.h>
|
||||
#include <m-list.h>
|
||||
#include <furi.h>
|
||||
#include <gui/elements.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
// uint16_t to support multi-screen, wide button panel
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include <furi.h>
|
||||
#include <gui/elements.h>
|
||||
#include <assets_icons.h>
|
||||
#include "byte_input.h"
|
||||
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
struct ByteInput {
|
||||
View* view;
|
||||
};
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#include "file_browser.h"
|
||||
#include "assets_icons.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/common_defines.h>
|
||||
#include <core/log.h>
|
||||
#include "furi_hal_resources.h"
|
||||
#include <m-array.h>
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
#include "toolbox/path.h"
|
||||
|
||||
#define LIST_ITEMS 5u
|
||||
#define MAX_LEN_PX 110
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
#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/common_defines.h>
|
||||
#include "storage/filesystem_api_defines.h"
|
||||
#include <furi.h>
|
||||
|
||||
#include <m-array.h>
|
||||
#include <stdbool.h>
|
||||
#include <storage/storage.h>
|
||||
#include <furi.h>
|
||||
#include <stddef.h>
|
||||
#include "toolbox/path.h"
|
||||
|
||||
#define TAG "BrowserWorker"
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include <stdint.h>
|
||||
#include <furi.h>
|
||||
#include <assets_icons.h>
|
||||
#include "loading.h"
|
||||
|
||||
#include <gui/icon_animation.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/view.h>
|
||||
#include <input/input.h>
|
||||
|
||||
#include "loading.h"
|
||||
#include <furi.h>
|
||||
#include <assets_icons.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct Loading {
|
||||
View* view;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "menu.h"
|
||||
|
||||
#include <m-array.h>
|
||||
#include <gui/elements.h>
|
||||
#include <assets_icons.h>
|
||||
#include <furi.h>
|
||||
#include <m-array.h>
|
||||
|
||||
struct Menu {
|
||||
View* view;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "submenu.h"
|
||||
|
||||
#include <m-array.h>
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
#include <m-array.h>
|
||||
|
||||
struct Submenu {
|
||||
View* view;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "text_box.h"
|
||||
#include "gui/canvas.h"
|
||||
#include <furi.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct TextBox {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <furi.h>
|
||||
#include "validators.h"
|
||||
#include <storage/storage.h>
|
||||
#include <furi.h>
|
||||
|
||||
struct ValidatorIsFile {
|
||||
char* app_path_folder;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <core/common_defines.h>
|
||||
#include <core/string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "variable_item_list.h"
|
||||
#include "gui/canvas.h"
|
||||
#include <m-array.h>
|
||||
#include <furi.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <furi.h>
|
||||
#include <m-array.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct VariableItem {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <furi.h>
|
||||
#include "widget.h"
|
||||
#include <m-array.h>
|
||||
#include "widget_elements/widget_element_i.h"
|
||||
#include <furi.h>
|
||||
#include <m-array.h>
|
||||
|
||||
ARRAY_DEF(ElementArray, WidgetElement*, M_PTR_OPLIST);
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "gui/view.h"
|
||||
#include <core/memmgr.h>
|
||||
#include "view_stack.h"
|
||||
#include "view_i.h"
|
||||
|
||||
#include <gui/view.h>
|
||||
#include <core/memmgr.h>
|
||||
|
||||
#define MAX_VIEWS 3
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "furi_hal_light.h"
|
||||
#include <furi_hal_light.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "furi_hal_resources.h"
|
||||
#include <furi_hal_resources.h>
|
||||
#include "notification.h"
|
||||
#include "notification_messages_notes.h"
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <stm32_adafruit_sd.h>
|
||||
|
||||
#include <cli/cli.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) {
|
||||
SDInfo sd_info;
|
||||
SD_CID sd_cid;
|
||||
FS_Error error = storage_sd_info(api, &sd_info);
|
||||
BSP_SD_GetCIDRegister(&sd_cid);
|
||||
|
||||
if(error != FSE_OK) {
|
||||
storage_cli_print_error(error);
|
||||
} else {
|
||||
printf(
|
||||
"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_api_get_fs_type_text(sd_info.fs_type),
|
||||
sd_info.kb_total,
|
||||
sd_info.kb_free,
|
||||
sd_cid.ManufacturerID,
|
||||
sd_cid.OEM_AppliID,
|
||||
sd_cid.ProdName,
|
||||
sd_cid.ProdRev >> 4,
|
||||
sd_cid.ProdRev & 0xf,
|
||||
sd_cid.ProdSN,
|
||||
sd_cid.ManufactMonth,
|
||||
sd_cid.ManufactYear + 2000);
|
||||
sd_info.manufacturer_id,
|
||||
sd_info.oem_id,
|
||||
sd_info.product_name,
|
||||
sd_info.product_revision_major,
|
||||
sd_info.product_revision_minor,
|
||||
sd_info.product_serial_number,
|
||||
sd_info.manufacturing_month,
|
||||
sd_info.manufacturing_year);
|
||||
}
|
||||
} else {
|
||||
storage_cli_print_usage();
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
|
||||
#define TAG "StorageAPI"
|
||||
|
||||
#define S_API_PROLOGUE \
|
||||
FuriSemaphore* semaphore = furi_semaphore_alloc(1, 0); \
|
||||
furi_check(semaphore != NULL);
|
||||
#define S_API_PROLOGUE FuriApiLock lock = api_lock_alloc_locked();
|
||||
|
||||
#define S_FILE_API_PROLOGUE \
|
||||
Storage* storage = file->storage; \
|
||||
@@ -24,13 +22,12 @@
|
||||
furi_check( \
|
||||
furi_message_queue_put(storage->message_queue, &message, FuriWaitForever) == \
|
||||
FuriStatusOk); \
|
||||
furi_semaphore_acquire(semaphore, FuriWaitForever); \
|
||||
furi_semaphore_free(semaphore);
|
||||
api_lock_wait_unlock_and_free(lock)
|
||||
|
||||
#define S_API_MESSAGE(_command) \
|
||||
SAReturn return_data; \
|
||||
StorageMessage message = { \
|
||||
.semaphore = semaphore, \
|
||||
.lock = lock, \
|
||||
.command = _command, \
|
||||
.data = &data, \
|
||||
.return_data = &return_data, \
|
||||
|
||||
@@ -31,29 +31,13 @@ void storage_file_clear(StorageFile* obj) {
|
||||
/****************** storage data ******************/
|
||||
|
||||
void storage_data_init(StorageData* storage) {
|
||||
storage->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
furi_check(storage->mutex != NULL);
|
||||
storage->data = NULL;
|
||||
storage->status = StorageStatusNotReady;
|
||||
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 status;
|
||||
|
||||
storage_data_lock(storage);
|
||||
status = storage->status;
|
||||
storage_data_unlock(storage);
|
||||
|
||||
return status;
|
||||
return storage->status;
|
||||
}
|
||||
|
||||
const char* storage_data_status_text(StorageData* storage) {
|
||||
|
||||
@@ -38,8 +38,6 @@ void storage_file_set(StorageFile* obj, const StorageFile* src);
|
||||
void storage_file_clear(StorageFile* obj);
|
||||
|
||||
void storage_data_init(StorageData* storage);
|
||||
bool storage_data_lock(StorageData* storage);
|
||||
bool storage_data_unlock(StorageData* storage);
|
||||
StorageStatus storage_data_status(StorageData* storage);
|
||||
const char* storage_data_status_text(StorageData* storage);
|
||||
void storage_data_timestamp(StorageData* storage);
|
||||
@@ -57,7 +55,6 @@ struct StorageData {
|
||||
const FS_Api* fs_api;
|
||||
StorageApi api;
|
||||
void* data;
|
||||
FuriMutex* mutex;
|
||||
StorageStatus status;
|
||||
StorageFileList_t files;
|
||||
uint32_t timestamp;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <toolbox/api_lock.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -130,7 +131,7 @@ typedef enum {
|
||||
} StorageCommand;
|
||||
|
||||
typedef struct {
|
||||
FuriSemaphore* semaphore;
|
||||
FuriApiLock lock;
|
||||
StorageCommand command;
|
||||
SAData* data;
|
||||
SAReturn* return_data;
|
||||
|
||||
@@ -2,15 +2,7 @@
|
||||
#include <m-list.h>
|
||||
#include <m-dict.h>
|
||||
|
||||
#define FS_CALL(_storage, _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);
|
||||
#define FS_CALL(_storage, _fn) ret = _storage->fs_api->_fn;
|
||||
|
||||
static StorageData* storage_get_storage_by_type(Storage* app, StorageType type) {
|
||||
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) {
|
||||
StorageType type = ST_ERROR;
|
||||
if(strlen(path) >= strlen(STORAGE_EXT_PATH_PREFIX) &&
|
||||
memcmp(path, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) {
|
||||
if(memcmp(path, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) {
|
||||
type = ST_EXT;
|
||||
} else if(
|
||||
strlen(path) >= strlen(STORAGE_INT_PATH_PREFIX) &&
|
||||
memcmp(path, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) {
|
||||
} else if(memcmp(path, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) {
|
||||
type = ST_INT;
|
||||
} else if(
|
||||
strlen(path) >= strlen(STORAGE_ANY_PATH_PREFIX) &&
|
||||
memcmp(path, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) {
|
||||
} else if(memcmp(path, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) {
|
||||
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) {
|
||||
if(memcmp(
|
||||
furi_string_get_cstr(path), STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) ==
|
||||
0) {
|
||||
if(furi_string_search(path, STORAGE_ANY_PATH_PREFIX) == 0) {
|
||||
switch(real_storage) {
|
||||
case ST_EXT:
|
||||
furi_string_set_char(path, 0, STORAGE_EXT_PATH_PREFIX[0]);
|
||||
furi_string_set_char(path, 1, STORAGE_EXT_PATH_PREFIX[1]);
|
||||
furi_string_set_char(path, 2, STORAGE_EXT_PATH_PREFIX[2]);
|
||||
furi_string_set_char(path, 3, STORAGE_EXT_PATH_PREFIX[3]);
|
||||
furi_string_replace_at(
|
||||
path, 0, strlen(STORAGE_EXT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX);
|
||||
break;
|
||||
case ST_INT:
|
||||
furi_string_set_char(path, 0, STORAGE_INT_PATH_PREFIX[0]);
|
||||
furi_string_set_char(path, 1, STORAGE_INT_PATH_PREFIX[1]);
|
||||
furi_string_set_char(path, 2, STORAGE_INT_PATH_PREFIX[2]);
|
||||
furi_string_set_char(path, 3, STORAGE_INT_PATH_PREFIX[3]);
|
||||
furi_string_replace_at(
|
||||
path, 0, strlen(STORAGE_INT_PATH_PREFIX), STORAGE_INT_PATH_PREFIX);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -604,7 +585,7 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) {
|
||||
break;
|
||||
}
|
||||
|
||||
furi_semaphore_release(message->semaphore);
|
||||
api_lock_unlock(message->lock);
|
||||
}
|
||||
|
||||
void storage_process_message(Storage* app, StorageMessage* message) {
|
||||
|
||||
@@ -23,6 +23,16 @@ typedef struct {
|
||||
uint16_t cluster_size;
|
||||
uint16_t sector_size;
|
||||
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;
|
||||
} SDInfo;
|
||||
|
||||
|
||||
@@ -26,12 +26,10 @@ static FS_Error storage_ext_parse_error(SDError error);
|
||||
|
||||
static bool sd_mount_card(StorageData* storage, bool notify) {
|
||||
bool result = false;
|
||||
uint8_t counter = BSP_SD_MaxMountRetryCount();
|
||||
uint8_t counter = sd_max_mount_retry_count();
|
||||
uint8_t bsp_result;
|
||||
SDData* sd_data = storage->data;
|
||||
|
||||
storage_data_lock(storage);
|
||||
|
||||
while(result == false && counter > 0 && hal_sd_detect()) {
|
||||
if(notify) {
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
@@ -41,9 +39,9 @@ static bool sd_mount_card(StorageData* storage, bool notify) {
|
||||
|
||||
if((counter % 2) == 0) {
|
||||
// power reset sd card
|
||||
bsp_result = BSP_SD_Init(true);
|
||||
bsp_result = sd_init(true);
|
||||
} else {
|
||||
bsp_result = BSP_SD_Init(false);
|
||||
bsp_result = sd_init(false);
|
||||
}
|
||||
|
||||
if(bsp_result) {
|
||||
@@ -91,7 +89,6 @@ static bool sd_mount_card(StorageData* storage, bool notify) {
|
||||
}
|
||||
|
||||
storage_data_timestamp(storage);
|
||||
storage_data_unlock(storage);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -100,14 +97,12 @@ FS_Error sd_unmount_card(StorageData* storage) {
|
||||
SDData* sd_data = storage->data;
|
||||
SDError error;
|
||||
|
||||
storage_data_lock(storage);
|
||||
storage->status = StorageStatusNotReady;
|
||||
error = FR_DISK_ERR;
|
||||
|
||||
// TODO do i need to close the files?
|
||||
|
||||
f_mount(0, sd_data->path, 0);
|
||||
storage_data_unlock(storage);
|
||||
|
||||
return storage_ext_parse_error(error);
|
||||
}
|
||||
|
||||
@@ -120,8 +115,6 @@ FS_Error sd_format_card(StorageData* storage) {
|
||||
SDData* sd_data = storage->data;
|
||||
SDError error;
|
||||
|
||||
storage_data_lock(storage);
|
||||
|
||||
work_area = malloc(_MAX_SS);
|
||||
error = f_mkfs(sd_data->path, FM_ANY, 0, work_area, _MAX_SS);
|
||||
free(work_area);
|
||||
@@ -138,8 +131,6 @@ FS_Error sd_format_card(StorageData* storage) {
|
||||
storage->status = StorageStatusOK;
|
||||
} while(false);
|
||||
|
||||
storage_data_unlock(storage);
|
||||
|
||||
return storage_ext_parse_error(error);
|
||||
#endif
|
||||
}
|
||||
@@ -156,14 +147,12 @@ FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info) {
|
||||
memset(sd_info, 0, sizeof(SDInfo));
|
||||
|
||||
// get fs info
|
||||
storage_data_lock(storage);
|
||||
error = f_getlabel(sd_data->path, sd_info->label, NULL);
|
||||
if(error == FR_OK) {
|
||||
#ifndef FURI_RAM_EXEC
|
||||
error = f_getfree(sd_data->path, &free_clusters, &fs);
|
||||
#endif
|
||||
}
|
||||
storage_data_unlock(storage);
|
||||
|
||||
if(error == FR_OK) {
|
||||
// calculate size
|
||||
@@ -210,6 +199,20 @@ FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info) {
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,17 +13,29 @@ typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMess
|
||||
static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
|
||||
const char* screen_header = "Product: Flipper Zero\n"
|
||||
"Model: FZ.1\n";
|
||||
const char* screen_text = "FCC ID: 2A2V6-FZ\n"
|
||||
"IC: 27624-FZ";
|
||||
FuriString* screen_header = furi_string_alloc_printf(
|
||||
"Product: %s\n"
|
||||
"Model: %s",
|
||||
furi_hal_version_get_model_name(),
|
||||
furi_hal_version_get_model_code());
|
||||
|
||||
dialog_message_set_header(message, screen_header, 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_text(message, screen_text, 0, 26, AlignLeft, AlignTop);
|
||||
FuriString* screen_text = furi_string_alloc_printf(
|
||||
"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);
|
||||
dialog_message_set_header(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#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) {
|
||||
furi_assert(context);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#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) {
|
||||
BtSettingsApp* app = context;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "../bt_settings_app.h"
|
||||
#include "furi_hal_bt.h"
|
||||
#include <furi_hal_bt.h>
|
||||
|
||||
enum BtSetting {
|
||||
BtSettingOff,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "../storage_settings.h"
|
||||
#include <stm32_adafruit_sd.h>
|
||||
|
||||
static void storage_settings_scene_sd_info_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
@@ -12,9 +11,7 @@ void storage_settings_scene_sd_info_on_enter(void* context) {
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
SDInfo sd_info;
|
||||
SD_CID sd_cid;
|
||||
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);
|
||||
|
||||
@@ -31,19 +28,19 @@ void storage_settings_scene_sd_info_on_enter(void* context) {
|
||||
furi_string_printf(
|
||||
app->text_string,
|
||||
"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_api_get_fs_type_text(sd_info.fs_type),
|
||||
sd_info.kb_total,
|
||||
sd_info.kb_free,
|
||||
sd_cid.ManufacturerID,
|
||||
sd_cid.OEM_AppliID,
|
||||
sd_cid.ProdName,
|
||||
sd_cid.ProdRev >> 4,
|
||||
sd_cid.ProdRev & 0xf,
|
||||
sd_cid.ProdSN,
|
||||
sd_cid.ManufactMonth,
|
||||
sd_cid.ManufactYear + 2000);
|
||||
sd_info.manufacturer_id,
|
||||
sd_info.oem_id,
|
||||
sd_info.product_name,
|
||||
sd_info.product_revision_major,
|
||||
sd_info.product_revision_minor,
|
||||
sd_info.product_serial_number,
|
||||
sd_info.manufacturing_month,
|
||||
sd_info.manufacturing_year);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, furi_string_get_cstr(app->text_string), 4, 1, AlignLeft, AlignTop);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "../storage_move_to_sd.h"
|
||||
#include "gui/canvas.h"
|
||||
#include "gui/modules/widget_elements/widget_element_i.h"
|
||||
#include "storage/storage.h"
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/modules/widget_elements/widget_element_i.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
static void storage_move_to_sd_scene_confirm_widget_callback(
|
||||
GuiButtonType result,
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
#pragma once
|
||||
#include "gui/modules/widget_elements/widget_element_i.h"
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#include <gui/modules/widget.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_sd_api.h>
|
||||
#include <furi.h>
|
||||
|
||||
#include "scenes/storage_move_to_sd_scene.h"
|
||||
|
||||
|
||||
@@ -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) {
|
||||
const CliSubcommand* subcmd_def = &update_cli_subcommands[idx];
|
||||
if(furi_string_cmp_str(subcommand, subcmd_def->command) == 0) {
|
||||
furi_string_free(subcommand);
|
||||
subcmd_def->handler(args);
|
||||
furi_string_free(subcommand);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +287,9 @@ bool update_task_parse_manifest(UpdateTask* update_task) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
44
documentation/HardwareTargets.md
Normal file
44
documentation/HardwareTargets.md
Normal 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
Reference in New Issue
Block a user