Merge branch 'dev' into nfcf
@@ -48,7 +48,7 @@ FileBrowserApp* file_browser_app_alloc(char* arg) {
|
|||||||
|
|
||||||
app->file_path = furi_string_alloc();
|
app->file_path = furi_string_alloc();
|
||||||
app->file_browser = file_browser_alloc(app->file_path);
|
app->file_browser = file_browser_alloc(app->file_path);
|
||||||
file_browser_configure(app->file_browser, "*", true, &I_badusb_10px, true);
|
file_browser_configure(app->file_browser, "*", NULL, true, &I_badusb_10px, true);
|
||||||
|
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
app->view_dispatcher, FileBrowserAppViewStart, widget_get_view(app->widget));
|
app->view_dispatcher, FileBrowserAppViewStart, widget_get_view(app->widget));
|
||||||
|
|||||||
@@ -215,26 +215,26 @@ static UartEchoApp* uart_echo_app_alloc() {
|
|||||||
view_dispatcher_add_view(app->view_dispatcher, 0, app->view);
|
view_dispatcher_add_view(app->view_dispatcher, 0, app->view);
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
|
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
|
||||||
|
|
||||||
|
app->worker_thread = furi_thread_alloc_ex("UsbUartWorker", 1024, uart_echo_worker, app);
|
||||||
|
furi_thread_start(app->worker_thread);
|
||||||
|
|
||||||
// Enable uart listener
|
// Enable uart listener
|
||||||
furi_hal_console_disable();
|
furi_hal_console_disable();
|
||||||
furi_hal_uart_set_br(FuriHalUartIdUSART1, 115200);
|
furi_hal_uart_set_br(FuriHalUartIdUSART1, 115200);
|
||||||
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_echo_on_irq_cb, app);
|
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_echo_on_irq_cb, app);
|
||||||
|
|
||||||
app->worker_thread = furi_thread_alloc_ex("UsbUartWorker", 1024, uart_echo_worker, app);
|
|
||||||
furi_thread_start(app->worker_thread);
|
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uart_echo_app_free(UartEchoApp* app) {
|
static void uart_echo_app_free(UartEchoApp* app) {
|
||||||
furi_assert(app);
|
furi_assert(app);
|
||||||
|
|
||||||
|
furi_hal_console_enable(); // this will also clear IRQ callback so thread is no longer referenced
|
||||||
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventStop);
|
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventStop);
|
||||||
furi_thread_join(app->worker_thread);
|
furi_thread_join(app->worker_thread);
|
||||||
furi_thread_free(app->worker_thread);
|
furi_thread_free(app->worker_thread);
|
||||||
|
|
||||||
furi_hal_console_enable();
|
|
||||||
|
|
||||||
// Free views
|
// Free views
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, 0);
|
view_dispatcher_remove_view(app->view_dispatcher, 0);
|
||||||
|
|
||||||
|
|||||||
116
applications/debug/unit_tests/furi_hal/furi_hal_tests.c
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
#include <lp5562_reg.h>
|
||||||
|
#include "../minunit.h"
|
||||||
|
|
||||||
|
#define DATA_SIZE 4
|
||||||
|
|
||||||
|
static void furi_hal_i2c_int_setup() {
|
||||||
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void furi_hal_i2c_int_teardown() {
|
||||||
|
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(furi_hal_i2c_int_1b) {
|
||||||
|
bool ret = false;
|
||||||
|
uint8_t data_one = 0;
|
||||||
|
|
||||||
|
// 1 byte: read, write, read
|
||||||
|
ret = furi_hal_i2c_read_reg_8(
|
||||||
|
&furi_hal_i2c_handle_power,
|
||||||
|
LP5562_ADDRESS,
|
||||||
|
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
|
||||||
|
&data_one,
|
||||||
|
LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(ret, "0 read_reg_8 failed");
|
||||||
|
mu_assert(data_one != 0, "0 invalid data");
|
||||||
|
ret = furi_hal_i2c_write_reg_8(
|
||||||
|
&furi_hal_i2c_handle_power,
|
||||||
|
LP5562_ADDRESS,
|
||||||
|
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
|
||||||
|
data_one,
|
||||||
|
LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(ret, "1 write_reg_8 failed");
|
||||||
|
ret = furi_hal_i2c_read_reg_8(
|
||||||
|
&furi_hal_i2c_handle_power,
|
||||||
|
LP5562_ADDRESS,
|
||||||
|
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
|
||||||
|
&data_one,
|
||||||
|
LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(ret, "2 read_reg_8 failed");
|
||||||
|
mu_assert(data_one != 0, "2 invalid data");
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(furi_hal_i2c_int_3b) {
|
||||||
|
bool ret = false;
|
||||||
|
uint8_t data_many[DATA_SIZE] = {0};
|
||||||
|
|
||||||
|
// 3 byte: read, write, read
|
||||||
|
data_many[0] = LP5562_CHANNEL_BLUE_CURRENT_REGISTER;
|
||||||
|
ret = furi_hal_i2c_tx(
|
||||||
|
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, 1, LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(ret, "3 tx failed");
|
||||||
|
ret = furi_hal_i2c_rx(
|
||||||
|
&furi_hal_i2c_handle_power,
|
||||||
|
LP5562_ADDRESS,
|
||||||
|
data_many + 1,
|
||||||
|
DATA_SIZE - 1,
|
||||||
|
LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(ret, "4 rx failed");
|
||||||
|
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "4 invalid data_many");
|
||||||
|
|
||||||
|
ret = furi_hal_i2c_tx(
|
||||||
|
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, DATA_SIZE, LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(ret, "5 tx failed");
|
||||||
|
|
||||||
|
ret = furi_hal_i2c_tx(
|
||||||
|
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, 1, LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(ret, "6 tx failed");
|
||||||
|
ret = furi_hal_i2c_rx(
|
||||||
|
&furi_hal_i2c_handle_power,
|
||||||
|
LP5562_ADDRESS,
|
||||||
|
data_many + 1,
|
||||||
|
DATA_SIZE - 1,
|
||||||
|
LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(ret, "7 rx failed");
|
||||||
|
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "7 invalid data_many");
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(furi_hal_i2c_int_1b_fail) {
|
||||||
|
bool ret = false;
|
||||||
|
uint8_t data_one = 0;
|
||||||
|
|
||||||
|
// 1 byte: fail, read, fail, write, fail, read
|
||||||
|
data_one = 0;
|
||||||
|
ret = furi_hal_i2c_read_reg_8(
|
||||||
|
&furi_hal_i2c_handle_power,
|
||||||
|
LP5562_ADDRESS + 0x10,
|
||||||
|
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
|
||||||
|
&data_one,
|
||||||
|
LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(!ret, "8 read_reg_8 failed");
|
||||||
|
mu_assert(data_one == 0, "8 invalid data");
|
||||||
|
ret = furi_hal_i2c_read_reg_8(
|
||||||
|
&furi_hal_i2c_handle_power,
|
||||||
|
LP5562_ADDRESS,
|
||||||
|
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
|
||||||
|
&data_one,
|
||||||
|
LP5562_I2C_TIMEOUT);
|
||||||
|
mu_assert(ret, "9 read_reg_8 failed");
|
||||||
|
mu_assert(data_one != 0, "9 invalid data");
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(furi_hal_i2c_int_suite) {
|
||||||
|
MU_SUITE_CONFIGURE(&furi_hal_i2c_int_setup, &furi_hal_i2c_int_teardown);
|
||||||
|
MU_RUN_TEST(furi_hal_i2c_int_1b);
|
||||||
|
MU_RUN_TEST(furi_hal_i2c_int_3b);
|
||||||
|
MU_RUN_TEST(furi_hal_i2c_int_1b_fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_minunit_test_furi_hal() {
|
||||||
|
MU_RUN_SUITE(furi_hal_i2c_int_suite);
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
||||||
@@ -316,7 +316,7 @@ void minunit_print_fail(const char* error);
|
|||||||
MU__SAFE_BLOCK( \
|
MU__SAFE_BLOCK( \
|
||||||
double minunit_tmp_e; double minunit_tmp_r; minunit_assert++; minunit_tmp_e = (expected); \
|
double minunit_tmp_e; double minunit_tmp_r; minunit_assert++; minunit_tmp_e = (expected); \
|
||||||
minunit_tmp_r = (result); \
|
minunit_tmp_r = (result); \
|
||||||
if(fabs(minunit_tmp_e - minunit_tmp_r) > MINUNIT_EPSILON) { \
|
if(fabs(minunit_tmp_e - minunit_tmp_r) > (double)MINUNIT_EPSILON) { \
|
||||||
int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON); \
|
int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON); \
|
||||||
snprintf( \
|
snprintf( \
|
||||||
minunit_last_message, \
|
minunit_last_message, \
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) {
|
|||||||
"nfc_device_save == true assert failed\r\n");
|
"nfc_device_save == true assert failed\r\n");
|
||||||
// Verify that key cache is saved
|
// Verify that key cache is saved
|
||||||
FuriString* key_cache_name = furi_string_alloc();
|
FuriString* key_cache_name = furi_string_alloc();
|
||||||
furi_string_set_str(key_cache_name, "/ext/nfc/cache/");
|
furi_string_set_str(key_cache_name, "/ext/nfc/.cache/");
|
||||||
for(size_t i = 0; i < uid_len; i++) {
|
for(size_t i = 0; i < uid_len; i++) {
|
||||||
furi_string_cat_printf(key_cache_name, "%02X", uid[i]);
|
furi_string_cat_printf(key_cache_name, "%02X", uid[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
62
applications/debug/unit_tests/power/power_test.c
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
#include "../minunit.h"
|
||||||
|
|
||||||
|
static void power_test_deinit(void) {
|
||||||
|
// Try to reset to default charging voltage
|
||||||
|
furi_hal_power_set_battery_charging_voltage(4.208f);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_power_charge_voltage_exact) {
|
||||||
|
// Power of 16mV charge voltages get applied exactly
|
||||||
|
// (bq25896 charge controller works in 16mV increments)
|
||||||
|
//
|
||||||
|
// This test may need adapted if other charge controllers are used in the future.
|
||||||
|
for(uint16_t charge_mv = 3840; charge_mv <= 4208; charge_mv += 16) {
|
||||||
|
float charge_volt = (float)charge_mv / 1000.0f;
|
||||||
|
furi_hal_power_set_battery_charging_voltage(charge_volt);
|
||||||
|
mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charging_voltage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_power_charge_voltage_floating_imprecision) {
|
||||||
|
// 4.016f should act as 4.016 V, even with floating point imprecision
|
||||||
|
furi_hal_power_set_battery_charging_voltage(4.016f);
|
||||||
|
mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charging_voltage());
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_power_charge_voltage_inexact) {
|
||||||
|
// Charge voltages that are not power of 16mV get truncated down
|
||||||
|
furi_hal_power_set_battery_charging_voltage(3.841f);
|
||||||
|
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
|
||||||
|
|
||||||
|
furi_hal_power_set_battery_charging_voltage(3.900f);
|
||||||
|
mu_assert_double_eq(3.888, furi_hal_power_get_battery_charging_voltage());
|
||||||
|
|
||||||
|
furi_hal_power_set_battery_charging_voltage(4.200f);
|
||||||
|
mu_assert_double_eq(4.192, furi_hal_power_get_battery_charging_voltage());
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_power_charge_voltage_invalid_clamped) {
|
||||||
|
// Out-of-range charge voltages get clamped to 3.840 V and 4.208 V
|
||||||
|
furi_hal_power_set_battery_charging_voltage(3.808f);
|
||||||
|
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
|
||||||
|
|
||||||
|
// NOTE: Intentionally picking a small increment above 4.208 V to reduce the risk of an
|
||||||
|
// unhappy battery if this fails.
|
||||||
|
furi_hal_power_set_battery_charging_voltage(4.240f);
|
||||||
|
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charging_voltage());
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(test_power_suite) {
|
||||||
|
MU_RUN_TEST(test_power_charge_voltage_exact);
|
||||||
|
MU_RUN_TEST(test_power_charge_voltage_floating_imprecision);
|
||||||
|
MU_RUN_TEST(test_power_charge_voltage_inexact);
|
||||||
|
MU_RUN_TEST(test_power_charge_voltage_invalid_clamped);
|
||||||
|
power_test_deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_minunit_test_power() {
|
||||||
|
MU_RUN_SUITE(test_power_suite);
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#define TAG "UnitTests"
|
#define TAG "UnitTests"
|
||||||
|
|
||||||
int run_minunit_test_furi();
|
int run_minunit_test_furi();
|
||||||
|
int run_minunit_test_furi_hal();
|
||||||
int run_minunit_test_furi_string();
|
int run_minunit_test_furi_string();
|
||||||
int run_minunit_test_infrared();
|
int run_minunit_test_infrared();
|
||||||
int run_minunit_test_rpc();
|
int run_minunit_test_rpc();
|
||||||
@@ -18,6 +19,7 @@ int run_minunit_test_stream();
|
|||||||
int run_minunit_test_storage();
|
int run_minunit_test_storage();
|
||||||
int run_minunit_test_subghz();
|
int run_minunit_test_subghz();
|
||||||
int run_minunit_test_dirwalk();
|
int run_minunit_test_dirwalk();
|
||||||
|
int run_minunit_test_power();
|
||||||
int run_minunit_test_protocol_dict();
|
int run_minunit_test_protocol_dict();
|
||||||
int run_minunit_test_lfrfid_protocols();
|
int run_minunit_test_lfrfid_protocols();
|
||||||
int run_minunit_test_nfc();
|
int run_minunit_test_nfc();
|
||||||
@@ -32,6 +34,7 @@ typedef struct {
|
|||||||
|
|
||||||
const UnitTest unit_tests[] = {
|
const UnitTest unit_tests[] = {
|
||||||
{.name = "furi", .entry = run_minunit_test_furi},
|
{.name = "furi", .entry = run_minunit_test_furi},
|
||||||
|
{.name = "furi_hal", .entry = run_minunit_test_furi_hal},
|
||||||
{.name = "furi_string", .entry = run_minunit_test_furi_string},
|
{.name = "furi_string", .entry = run_minunit_test_furi_string},
|
||||||
{.name = "storage", .entry = run_minunit_test_storage},
|
{.name = "storage", .entry = run_minunit_test_storage},
|
||||||
{.name = "stream", .entry = run_minunit_test_stream},
|
{.name = "stream", .entry = run_minunit_test_stream},
|
||||||
@@ -42,6 +45,7 @@ const UnitTest unit_tests[] = {
|
|||||||
{.name = "subghz", .entry = run_minunit_test_subghz},
|
{.name = "subghz", .entry = run_minunit_test_subghz},
|
||||||
{.name = "infrared", .entry = run_minunit_test_infrared},
|
{.name = "infrared", .entry = run_minunit_test_infrared},
|
||||||
{.name = "nfc", .entry = run_minunit_test_nfc},
|
{.name = "nfc", .entry = run_minunit_test_nfc},
|
||||||
|
{.name = "power", .entry = run_minunit_test_power},
|
||||||
{.name = "protocol_dict", .entry = run_minunit_test_protocol_dict},
|
{.name = "protocol_dict", .entry = run_minunit_test_protocol_dict},
|
||||||
{.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols},
|
{.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols},
|
||||||
{.name = "bit_lib", .entry = run_minunit_test_bit_lib},
|
{.name = "bit_lib", .entry = run_minunit_test_bit_lib},
|
||||||
|
|||||||
@@ -80,10 +80,12 @@ static void archive_file_browser_set_path(
|
|||||||
ArchiveBrowserView* browser,
|
ArchiveBrowserView* browser,
|
||||||
FuriString* path,
|
FuriString* path,
|
||||||
const char* filter_ext,
|
const char* filter_ext,
|
||||||
bool skip_assets) {
|
bool skip_assets,
|
||||||
|
bool hide_dot_files) {
|
||||||
furi_assert(browser);
|
furi_assert(browser);
|
||||||
if(!browser->worker_running) {
|
if(!browser->worker_running) {
|
||||||
browser->worker = file_browser_worker_alloc(path, filter_ext, skip_assets);
|
browser->worker =
|
||||||
|
file_browser_worker_alloc(path, NULL, filter_ext, skip_assets, hide_dot_files);
|
||||||
file_browser_worker_set_callback_context(browser->worker, browser);
|
file_browser_worker_set_callback_context(browser->worker, browser);
|
||||||
file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb);
|
file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb);
|
||||||
file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb);
|
file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb);
|
||||||
@@ -92,7 +94,8 @@ static void archive_file_browser_set_path(
|
|||||||
browser->worker_running = true;
|
browser->worker_running = true;
|
||||||
} else {
|
} else {
|
||||||
furi_assert(browser->worker);
|
furi_assert(browser->worker);
|
||||||
file_browser_worker_set_config(browser->worker, path, filter_ext, skip_assets);
|
file_browser_worker_set_config(
|
||||||
|
browser->worker, path, filter_ext, skip_assets, hide_dot_files);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,8 +475,10 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
|
|||||||
tab = archive_get_tab(browser);
|
tab = archive_get_tab(browser);
|
||||||
if(archive_is_dir_exists(browser->path)) {
|
if(archive_is_dir_exists(browser->path)) {
|
||||||
bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
|
bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
|
||||||
|
// Hide dot files everywhere except Browser
|
||||||
|
bool hide_dot_files = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
|
||||||
archive_file_browser_set_path(
|
archive_file_browser_set_path(
|
||||||
browser, browser->path, archive_get_tab_ext(tab), skip_assets);
|
browser, browser->path, archive_get_tab_ext(tab), skip_assets, hide_dot_files);
|
||||||
tab_empty = false; // Empty check will be performed later
|
tab_empty = false; // Empty check will be performed later
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
#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>
|
||||||
|
|
||||||
static bool bad_usb_file_select(BadUsbApp* bad_usb) {
|
static bool bad_usb_file_select(BadUsbApp* bad_usb) {
|
||||||
furi_assert(bad_usb);
|
furi_assert(bad_usb);
|
||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
DialogsFileBrowserOptions browser_options;
|
||||||
dialog_file_browser_set_basic_options(&browser_options, BAD_USB_APP_EXTENSION, &I_badusb_10px);
|
dialog_file_browser_set_basic_options(&browser_options, BAD_USB_APP_EXTENSION, &I_badusb_10px);
|
||||||
|
browser_options.base_path = BAD_USB_APP_PATH_FOLDER;
|
||||||
|
|
||||||
// Input events and views are managed by file_browser
|
// Input events and views are managed by file_browser
|
||||||
bool res = dialog_file_browser_show(
|
bool res = dialog_file_browser_show(
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ static bool fap_loader_select_app(FapLoader* loader) {
|
|||||||
.hide_ext = true,
|
.hide_ext = true,
|
||||||
.item_loader_callback = fap_loader_item_callback,
|
.item_loader_callback = fap_loader_item_callback,
|
||||||
.item_loader_context = loader,
|
.item_loader_context = loader,
|
||||||
|
.base_path = EXT_PATH("apps"),
|
||||||
};
|
};
|
||||||
|
|
||||||
return dialog_file_browser_show(
|
return dialog_file_browser_show(
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ void ibutton_free(iButton* ibutton) {
|
|||||||
bool ibutton_file_select(iButton* ibutton) {
|
bool ibutton_file_select(iButton* ibutton) {
|
||||||
DialogsFileBrowserOptions browser_options;
|
DialogsFileBrowserOptions browser_options;
|
||||||
dialog_file_browser_set_basic_options(&browser_options, IBUTTON_APP_EXTENSION, &I_ibutt_10px);
|
dialog_file_browser_set_basic_options(&browser_options, IBUTTON_APP_EXTENSION, &I_ibutt_10px);
|
||||||
|
browser_options.base_path = IBUTTON_APP_FOLDER;
|
||||||
|
|
||||||
bool success = dialog_file_browser_show(
|
bool success = dialog_file_browser_show(
|
||||||
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options);
|
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ void infrared_scene_remote_list_on_enter(void* context) {
|
|||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
DialogsFileBrowserOptions browser_options;
|
||||||
dialog_file_browser_set_basic_options(&browser_options, INFRARED_APP_EXTENSION, &I_ir_10px);
|
dialog_file_browser_set_basic_options(&browser_options, INFRARED_APP_EXTENSION, &I_ir_10px);
|
||||||
|
browser_options.base_path = INFRARED_APP_FOLDER;
|
||||||
|
|
||||||
bool success = dialog_file_browser_show(
|
bool success = dialog_file_browser_show(
|
||||||
infrared->dialogs, infrared->file_path, infrared->file_path, &browser_options);
|
infrared->dialogs, infrared->file_path, infrared->file_path, &browser_options);
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ bool lfrfid_load_key_from_file_select(LfRfid* app) {
|
|||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
DialogsFileBrowserOptions browser_options;
|
||||||
dialog_file_browser_set_basic_options(&browser_options, LFRFID_APP_EXTENSION, &I_125_10px);
|
dialog_file_browser_set_basic_options(&browser_options, LFRFID_APP_EXTENSION, &I_125_10px);
|
||||||
|
browser_options.base_path = LFRFID_APP_FOLDER;
|
||||||
|
|
||||||
// Input events and views are managed by file_browser
|
// Input events and views are managed by file_browser
|
||||||
bool result =
|
bool result =
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
|
|||||||
FuriString* info_str;
|
FuriString* info_str;
|
||||||
info_str = furi_string_alloc();
|
info_str = furi_string_alloc();
|
||||||
|
|
||||||
widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61);
|
widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61);
|
||||||
widget_add_string_element(widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Emulating UID");
|
widget_add_string_element(widget, 57, 13, AlignLeft, AlignTop, FontPrimary, "Emulating UID");
|
||||||
if(strcmp(nfc->dev->dev_name, "")) {
|
if(strcmp(nfc->dev->dev_name, "")) {
|
||||||
furi_string_printf(info_str, "%s", nfc->dev->dev_name);
|
furi_string_printf(info_str, "%s", nfc->dev->dev_name);
|
||||||
} else {
|
} else {
|
||||||
@@ -48,7 +48,7 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
|
|||||||
}
|
}
|
||||||
furi_string_trim(info_str);
|
furi_string_trim(info_str);
|
||||||
widget_add_text_box_element(
|
widget_add_text_box_element(
|
||||||
widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true);
|
widget, 57, 28, 67, 25, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true);
|
||||||
furi_string_free(info_str);
|
furi_string_free(info_str);
|
||||||
if(data_received) {
|
if(data_received) {
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ void nfc_scene_mf_classic_emulate_on_enter(void* context) {
|
|||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = nfc->popup;
|
Popup* popup = nfc->popup;
|
||||||
|
popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop);
|
||||||
if(strcmp(nfc->dev->dev_name, "")) {
|
if(strcmp(nfc->dev->dev_name, "")) {
|
||||||
nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name);
|
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
|
||||||
} else {
|
} else {
|
||||||
nfc_text_store_set(nfc, "Emulating\nMf Classic", nfc->dev->dev_name);
|
nfc_text_store_set(nfc, "MIFARE\nClassic");
|
||||||
}
|
}
|
||||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61);
|
||||||
popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop);
|
popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop);
|
||||||
|
|
||||||
// Setup and start worker
|
// Setup and start worker
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
|||||||
@@ -16,14 +16,20 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) {
|
|||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
|
MfUltralightType type = nfc->dev->dev_data.mf_ul_data.type;
|
||||||
|
bool is_ultralight = (type == MfUltralightTypeUL11) || (type == MfUltralightTypeUL21) ||
|
||||||
|
(type == MfUltralightTypeUnknown);
|
||||||
Popup* popup = nfc->popup;
|
Popup* popup = nfc->popup;
|
||||||
|
popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop);
|
||||||
if(strcmp(nfc->dev->dev_name, "")) {
|
if(strcmp(nfc->dev->dev_name, "")) {
|
||||||
nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name);
|
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
|
||||||
|
} else if(is_ultralight) {
|
||||||
|
nfc_text_store_set(nfc, "MIFARE\nUltralight");
|
||||||
} else {
|
} else {
|
||||||
nfc_text_store_set(nfc, "Emulating\nMf Ultralight", nfc->dev->dev_name);
|
nfc_text_store_set(nfc, "MIFARE\nNTAG");
|
||||||
}
|
}
|
||||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61);
|
||||||
popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop);
|
popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop);
|
||||||
|
|
||||||
// Setup and start worker
|
// Setup and start worker
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ void nfc_scene_rpc_on_enter(void* context) {
|
|||||||
popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom);
|
popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom);
|
||||||
popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
|
popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
|
||||||
|
|
||||||
popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
|
popup_set_icon(popup, 0, 12, &I_NFC_dolphin_emulation_47x61);
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
|
||||||
|
|||||||
13
applications/main/subghz/helpers/subghz_error_type.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
|
||||||
|
/** SubGhzErrorType */
|
||||||
|
typedef enum {
|
||||||
|
SubGhzErrorTypeNoError = 0, /** There are no errors */
|
||||||
|
SubGhzErrorTypeParseFile =
|
||||||
|
1, /** File parsing error, or wrong file structure, or missing required parameters. more accurate data can be obtained through the debug port */
|
||||||
|
SubGhzErrorTypeOnlyRX =
|
||||||
|
2, /** Transmission on this frequency is blocked by regional settings */
|
||||||
|
} SubGhzErrorType;
|
||||||
@@ -43,6 +43,12 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
|||||||
result = subghz_tx_start(subghz, subghz->txrx->fff_data);
|
result = subghz_tx_start(subghz, subghz->txrx->fff_data);
|
||||||
if(result) subghz_blink_start(subghz);
|
if(result) subghz_blink_start(subghz);
|
||||||
}
|
}
|
||||||
|
if(!result) {
|
||||||
|
rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeOnlyRX);
|
||||||
|
rpc_system_app_set_error_text(
|
||||||
|
subghz->rpc_ctx,
|
||||||
|
"Transmission on this frequency is restricted in your region");
|
||||||
|
}
|
||||||
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result);
|
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result);
|
||||||
} else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) {
|
} else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
@@ -74,6 +80,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
|||||||
popup_set_text(popup, subghz->file_name_tmp, 89, 44, AlignCenter, AlignTop);
|
popup_set_text(popup, subghz->file_name_tmp, 89, 44, AlignCenter, AlignTop);
|
||||||
|
|
||||||
furi_string_free(file_name);
|
furi_string_free(file_name);
|
||||||
|
} else {
|
||||||
|
rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeParseFile);
|
||||||
|
rpc_system_app_set_error_text(subghz->rpc_ctx, "Cannot parse file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventLoadFile, result);
|
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventLoadFile, result);
|
||||||
|
|||||||
@@ -454,6 +454,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) {
|
|||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
DialogsFileBrowserOptions browser_options;
|
||||||
dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
|
dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
|
||||||
|
browser_options.base_path = SUBGHZ_APP_FOLDER;
|
||||||
|
|
||||||
// Input events and views are managed by file_select
|
// Input events and views are managed by file_select
|
||||||
bool res = dialog_file_browser_show(
|
bool res = dialog_file_browser_show(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "helpers/subghz_types.h"
|
#include "helpers/subghz_types.h"
|
||||||
|
#include "helpers/subghz_error_type.h"
|
||||||
#include <lib/subghz/types.h>
|
#include <lib/subghz/types.h>
|
||||||
#include "subghz.h"
|
#include "subghz.h"
|
||||||
#include "views/receiver.h"
|
#include "views/receiver.h"
|
||||||
|
|||||||
@@ -313,6 +313,7 @@ int32_t music_player_app(void* p) {
|
|||||||
dialog_file_browser_set_basic_options(
|
dialog_file_browser_set_basic_options(
|
||||||
&browser_options, MUSIC_PLAYER_APP_EXTENSION, &I_music_10px);
|
&browser_options, MUSIC_PLAYER_APP_EXTENSION, &I_music_10px);
|
||||||
browser_options.hide_ext = false;
|
browser_options.hide_ext = false;
|
||||||
|
browser_options.base_path = MUSIC_PLAYER_APP_PATH_FOLDER;
|
||||||
|
|
||||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
bool res = dialog_file_browser_show(dialogs, file_path, file_path, &browser_options);
|
bool res = dialog_file_browser_show(dialogs, file_path, file_path, &browser_options);
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ bool picopass_file_select(PicopassDevice* dev) {
|
|||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
DialogsFileBrowserOptions browser_options;
|
||||||
dialog_file_browser_set_basic_options(&browser_options, PICOPASS_APP_EXTENSION, &I_Nfc_10px);
|
dialog_file_browser_set_basic_options(&browser_options, PICOPASS_APP_EXTENSION, &I_Nfc_10px);
|
||||||
|
browser_options.base_path = PICOPASS_APP_FOLDER;
|
||||||
|
|
||||||
bool res = dialog_file_browser_show(
|
bool res = dialog_file_browser_show(
|
||||||
dev->dialogs, dev->load_path, picopass_app_folder, &browser_options);
|
dev->dialogs, dev->load_path, picopass_app_folder, &browser_options);
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ static const SubGhzBlockConst ws_oregon2_const = {
|
|||||||
#define ID_UV800 0xd874
|
#define ID_UV800 0xd874
|
||||||
#define ID_THN129 0xcc43 // THN129 Temp only
|
#define ID_THN129 0xcc43 // THN129 Temp only
|
||||||
#define ID_RTHN129 0x0cd3 // RTHN129 Temp, clock sensors
|
#define ID_RTHN129 0x0cd3 // RTHN129 Temp, clock sensors
|
||||||
|
#define ID_RTHN129_1 0x9cd3
|
||||||
|
#define ID_RTHN129_2 0xacd3
|
||||||
|
#define ID_RTHN129_3 0xbcd3
|
||||||
|
#define ID_RTHN129_4 0xccd3
|
||||||
|
#define ID_RTHN129_5 0xdcd3
|
||||||
#define ID_BTHGN129 0x5d53 // Baro, Temp, Hygro sensor
|
#define ID_BTHGN129 0x5d53 // Baro, Temp, Hygro sensor
|
||||||
#define ID_UVR128 0xec70
|
#define ID_UVR128 0xec70
|
||||||
#define ID_THGR328N 0xcc23 // Temp & Hygro sensor similar to THR228N with 5 channel instead of 3
|
#define ID_THGR328N 0xcc23 // Temp & Hygro sensor similar to THR228N with 5 channel instead of 3
|
||||||
@@ -137,11 +142,19 @@ static ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration
|
|||||||
// From sensor id code return amount of bits in variable section
|
// From sensor id code return amount of bits in variable section
|
||||||
// https://temofeev.ru/info/articles/o-dekodirovanii-protokola-pogodnykh-datchikov-oregon-scientific
|
// https://temofeev.ru/info/articles/o-dekodirovanii-protokola-pogodnykh-datchikov-oregon-scientific
|
||||||
static uint8_t oregon2_sensor_id_var_bits(uint16_t sensor_id) {
|
static uint8_t oregon2_sensor_id_var_bits(uint16_t sensor_id) {
|
||||||
if(sensor_id == ID_THR228N) return 16;
|
switch(sensor_id) {
|
||||||
|
case ID_THR228N:
|
||||||
if(sensor_id == ID_THGR122N) return 24;
|
case ID_RTHN129_1:
|
||||||
|
case ID_RTHN129_2:
|
||||||
return 0;
|
case ID_RTHN129_3:
|
||||||
|
case ID_RTHN129_4:
|
||||||
|
case ID_RTHN129_5:
|
||||||
|
return 16;
|
||||||
|
case ID_THGR122N:
|
||||||
|
return 24;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ws_oregon2_decode_const_data(WSBlockGeneric* ws_block) {
|
static void ws_oregon2_decode_const_data(WSBlockGeneric* ws_block) {
|
||||||
@@ -171,16 +184,22 @@ static float ws_oregon2_decode_temp(uint32_t data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void ws_oregon2_decode_var_data(WSBlockGeneric* ws_b, uint16_t sensor_id, uint32_t data) {
|
static void ws_oregon2_decode_var_data(WSBlockGeneric* ws_b, uint16_t sensor_id, uint32_t data) {
|
||||||
if(sensor_id == ID_THR228N) {
|
switch(sensor_id) {
|
||||||
|
case ID_THR228N:
|
||||||
|
case ID_RTHN129_1:
|
||||||
|
case ID_RTHN129_2:
|
||||||
|
case ID_RTHN129_3:
|
||||||
|
case ID_RTHN129_4:
|
||||||
|
case ID_RTHN129_5:
|
||||||
ws_b->temp = ws_oregon2_decode_temp(data);
|
ws_b->temp = ws_oregon2_decode_temp(data);
|
||||||
ws_b->humidity = WS_NO_HUMIDITY;
|
ws_b->humidity = WS_NO_HUMIDITY;
|
||||||
return;
|
return;
|
||||||
}
|
case ID_THGR122N:
|
||||||
|
|
||||||
if(sensor_id == ID_THGR122N) {
|
|
||||||
ws_b->humidity = bcd_decode_short(data);
|
ws_b->humidity = bcd_decode_short(data);
|
||||||
ws_b->temp = ws_oregon2_decode_temp(data >> 8);
|
ws_b->temp = ws_oregon2_decode_temp(data >> 8);
|
||||||
return;
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,12 @@
|
|||||||
|
|
||||||
#define VCP_IF_NUM 0
|
#define VCP_IF_NUM 0
|
||||||
|
|
||||||
|
#ifdef CLI_VCP_DEBUG
|
||||||
|
#define VCP_DEBUG(...) FURI_LOG_D(TAG, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define VCP_DEBUG(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VcpEvtStop = (1 << 0),
|
VcpEvtStop = (1 << 0),
|
||||||
VcpEvtConnect = (1 << 1),
|
VcpEvtConnect = (1 << 1),
|
||||||
@@ -104,9 +110,8 @@ static int32_t vcp_worker(void* context) {
|
|||||||
|
|
||||||
// VCP session opened
|
// VCP session opened
|
||||||
if(flags & VcpEvtConnect) {
|
if(flags & VcpEvtConnect) {
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("Connect");
|
||||||
FURI_LOG_D(TAG, "Connect");
|
|
||||||
#endif
|
|
||||||
if(vcp->connected == false) {
|
if(vcp->connected == false) {
|
||||||
vcp->connected = true;
|
vcp->connected = true;
|
||||||
furi_stream_buffer_send(vcp->rx_stream, &ascii_soh, 1, FuriWaitForever);
|
furi_stream_buffer_send(vcp->rx_stream, &ascii_soh, 1, FuriWaitForever);
|
||||||
@@ -115,9 +120,8 @@ static int32_t vcp_worker(void* context) {
|
|||||||
|
|
||||||
// VCP session closed
|
// VCP session closed
|
||||||
if(flags & VcpEvtDisconnect) {
|
if(flags & VcpEvtDisconnect) {
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("Disconnect");
|
||||||
FURI_LOG_D(TAG, "Disconnect");
|
|
||||||
#endif
|
|
||||||
if(vcp->connected == true) {
|
if(vcp->connected == true) {
|
||||||
vcp->connected = false;
|
vcp->connected = false;
|
||||||
furi_stream_buffer_receive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
|
furi_stream_buffer_receive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
|
||||||
@@ -127,9 +131,8 @@ static int32_t vcp_worker(void* context) {
|
|||||||
|
|
||||||
// Rx buffer was read, maybe there is enough space for new data?
|
// Rx buffer was read, maybe there is enough space for new data?
|
||||||
if((flags & VcpEvtStreamRx) && (missed_rx > 0)) {
|
if((flags & VcpEvtStreamRx) && (missed_rx > 0)) {
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("StreamRx");
|
||||||
FURI_LOG_D(TAG, "StreamRx");
|
|
||||||
#endif
|
|
||||||
if(furi_stream_buffer_spaces_available(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
|
if(furi_stream_buffer_spaces_available(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
|
||||||
flags |= VcpEvtRx;
|
flags |= VcpEvtRx;
|
||||||
missed_rx--;
|
missed_rx--;
|
||||||
@@ -140,9 +143,8 @@ static int32_t vcp_worker(void* context) {
|
|||||||
if(flags & VcpEvtRx) {
|
if(flags & VcpEvtRx) {
|
||||||
if(furi_stream_buffer_spaces_available(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
|
if(furi_stream_buffer_spaces_available(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
|
||||||
int32_t len = furi_hal_cdc_receive(VCP_IF_NUM, vcp->data_buffer, USB_CDC_PKT_LEN);
|
int32_t len = furi_hal_cdc_receive(VCP_IF_NUM, vcp->data_buffer, USB_CDC_PKT_LEN);
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("Rx %ld", len);
|
||||||
FURI_LOG_D(TAG, "Rx %d", len);
|
|
||||||
#endif
|
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
furi_check(
|
furi_check(
|
||||||
furi_stream_buffer_send(
|
furi_stream_buffer_send(
|
||||||
@@ -150,18 +152,15 @@ static int32_t vcp_worker(void* context) {
|
|||||||
(size_t)len);
|
(size_t)len);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("Rx missed");
|
||||||
FURI_LOG_D(TAG, "Rx missed");
|
|
||||||
#endif
|
|
||||||
missed_rx++;
|
missed_rx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New data in Tx buffer
|
// New data in Tx buffer
|
||||||
if(flags & VcpEvtStreamTx) {
|
if(flags & VcpEvtStreamTx) {
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("StreamTx");
|
||||||
FURI_LOG_D(TAG, "StreamTx");
|
|
||||||
#endif
|
|
||||||
if(tx_idle) {
|
if(tx_idle) {
|
||||||
flags |= VcpEvtTx;
|
flags |= VcpEvtTx;
|
||||||
}
|
}
|
||||||
@@ -171,9 +170,9 @@ static int32_t vcp_worker(void* context) {
|
|||||||
if(flags & VcpEvtTx) {
|
if(flags & VcpEvtTx) {
|
||||||
size_t len =
|
size_t len =
|
||||||
furi_stream_buffer_receive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
|
furi_stream_buffer_receive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
|
||||||
#ifdef CLI_VCP_DEBUG
|
|
||||||
FURI_LOG_D(TAG, "Tx %d", len);
|
VCP_DEBUG("Tx %d", len);
|
||||||
#endif
|
|
||||||
if(len > 0) { // Some data left in Tx buffer. Sending it now
|
if(len > 0) { // Some data left in Tx buffer. Sending it now
|
||||||
tx_idle = false;
|
tx_idle = false;
|
||||||
furi_hal_cdc_send(VCP_IF_NUM, vcp->data_buffer, len);
|
furi_hal_cdc_send(VCP_IF_NUM, vcp->data_buffer, len);
|
||||||
@@ -216,9 +215,7 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("rx %u start", size);
|
||||||
FURI_LOG_D(TAG, "rx %u start", size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t rx_cnt = 0;
|
size_t rx_cnt = 0;
|
||||||
|
|
||||||
@@ -227,19 +224,21 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) {
|
|||||||
if(batch_size > VCP_RX_BUF_SIZE) batch_size = VCP_RX_BUF_SIZE;
|
if(batch_size > VCP_RX_BUF_SIZE) batch_size = VCP_RX_BUF_SIZE;
|
||||||
|
|
||||||
size_t len = furi_stream_buffer_receive(vcp->rx_stream, buffer, batch_size, timeout);
|
size_t len = furi_stream_buffer_receive(vcp->rx_stream, buffer, batch_size, timeout);
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("rx %u ", batch_size);
|
||||||
FURI_LOG_D(TAG, "rx %u ", batch_size);
|
|
||||||
#endif
|
|
||||||
if(len == 0) break;
|
if(len == 0) break;
|
||||||
|
if(vcp->running == false) {
|
||||||
|
// EOT command is received after VCP session close
|
||||||
|
rx_cnt += len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamRx);
|
furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamRx);
|
||||||
size -= len;
|
size -= len;
|
||||||
buffer += len;
|
buffer += len;
|
||||||
rx_cnt += len;
|
rx_cnt += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("rx %u end", size);
|
||||||
FURI_LOG_D(TAG, "rx %u end", size);
|
|
||||||
#endif
|
|
||||||
return rx_cnt;
|
return rx_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,9 +250,7 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("tx %u start", size);
|
||||||
FURI_LOG_D(TAG, "tx %u start", size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while(size > 0 && vcp->connected) {
|
while(size > 0 && vcp->connected) {
|
||||||
size_t batch_size = size;
|
size_t batch_size = size;
|
||||||
@@ -261,17 +258,13 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
|
|||||||
|
|
||||||
furi_stream_buffer_send(vcp->tx_stream, buffer, batch_size, FuriWaitForever);
|
furi_stream_buffer_send(vcp->tx_stream, buffer, batch_size, FuriWaitForever);
|
||||||
furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamTx);
|
furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamTx);
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("tx %u", batch_size);
|
||||||
FURI_LOG_D(TAG, "tx %u", batch_size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
size -= batch_size;
|
size -= batch_size;
|
||||||
buffer += batch_size;
|
buffer += batch_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CLI_VCP_DEBUG
|
VCP_DEBUG("tx %u end", size);
|
||||||
FURI_LOG_D(TAG, "tx %u end", size);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cli_vcp_tx_stdout(const char* data, size_t size) {
|
static void cli_vcp_tx_stdout(const char* data, size_t size) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ void dialog_file_browser_set_basic_options(
|
|||||||
options->hide_ext = true;
|
options->hide_ext = true;
|
||||||
options->item_loader_callback = NULL;
|
options->item_loader_callback = NULL;
|
||||||
options->item_loader_context = NULL;
|
options->item_loader_context = NULL;
|
||||||
|
options->base_path = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DialogsApp* dialogs_app_alloc() {
|
static DialogsApp* dialogs_app_alloc() {
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ typedef struct DialogsApp DialogsApp;
|
|||||||
/**
|
/**
|
||||||
* File browser dialog extra options
|
* File browser dialog extra options
|
||||||
* @param extension file extension to be offered for selection
|
* @param extension file extension to be offered for selection
|
||||||
|
* @param base_path root folder path for navigation with back key
|
||||||
* @param skip_assets true - do not show assets folders
|
* @param skip_assets true - do not show assets folders
|
||||||
|
* @param hide_dot_files true - hide dot files
|
||||||
* @param icon file icon pointer, NULL for default icon
|
* @param icon file icon pointer, NULL for default icon
|
||||||
* @param hide_ext true - hide extensions for files
|
* @param hide_ext true - hide extensions for files
|
||||||
* @param item_loader_callback callback function for providing custom icon & entry name
|
* @param item_loader_callback callback function for providing custom icon & entry name
|
||||||
@@ -26,7 +28,9 @@ typedef struct DialogsApp DialogsApp;
|
|||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* extension;
|
const char* extension;
|
||||||
|
const char* base_path;
|
||||||
bool skip_assets;
|
bool skip_assets;
|
||||||
|
bool hide_dot_files;
|
||||||
const Icon* icon;
|
const Icon* icon;
|
||||||
bool hide_ext;
|
bool hide_ext;
|
||||||
FileBrowserLoadItemCallback item_loader_callback;
|
FileBrowserLoadItemCallback item_loader_callback;
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ bool dialog_file_browser_show(
|
|||||||
.file_icon = options ? options->icon : NULL,
|
.file_icon = options ? options->icon : NULL,
|
||||||
.hide_ext = options ? options->hide_ext : true,
|
.hide_ext = options ? options->hide_ext : true,
|
||||||
.skip_assets = options ? options->skip_assets : true,
|
.skip_assets = options ? options->skip_assets : true,
|
||||||
|
.hide_dot_files = options ? options->hide_dot_files : true,
|
||||||
.preselected_filename = path,
|
.preselected_filename = path,
|
||||||
.item_callback = options ? options->item_loader_callback : NULL,
|
.item_callback = options ? options->item_loader_callback : NULL,
|
||||||
.item_callback_context = options ? options->item_loader_context : NULL,
|
.item_callback_context = options ? options->item_loader_context : NULL,
|
||||||
|
.base_path = options ? options->base_path : NULL,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
DialogsAppReturn return_data;
|
DialogsAppReturn return_data;
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ typedef struct {
|
|||||||
const char* extension;
|
const char* extension;
|
||||||
bool skip_assets;
|
bool skip_assets;
|
||||||
bool hide_ext;
|
bool hide_ext;
|
||||||
|
bool hide_dot_files;
|
||||||
const Icon* file_icon;
|
const Icon* file_icon;
|
||||||
FuriString* result_path;
|
FuriString* result_path;
|
||||||
FuriString* preselected_filename;
|
FuriString* preselected_filename;
|
||||||
FileBrowserLoadItemCallback item_callback;
|
FileBrowserLoadItemCallback item_callback;
|
||||||
void* item_callback_context;
|
void* item_callback_context;
|
||||||
|
const char* base_path;
|
||||||
} DialogsAppMessageDataFileBrowser;
|
} DialogsAppMessageDataFileBrowser;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -38,7 +38,13 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow
|
|||||||
file_browser_set_callback(
|
file_browser_set_callback(
|
||||||
file_browser, dialogs_app_file_browser_callback, file_browser_context);
|
file_browser, dialogs_app_file_browser_callback, file_browser_context);
|
||||||
file_browser_configure(
|
file_browser_configure(
|
||||||
file_browser, data->extension, data->skip_assets, data->file_icon, data->hide_ext);
|
file_browser,
|
||||||
|
data->extension,
|
||||||
|
data->base_path,
|
||||||
|
data->skip_assets,
|
||||||
|
data->hide_dot_files,
|
||||||
|
data->file_icon,
|
||||||
|
data->hide_ext);
|
||||||
file_browser_set_item_callback(file_browser, data->item_callback, data->item_callback_context);
|
file_browser_set_item_callback(file_browser, data->item_callback, data->item_callback_context);
|
||||||
file_browser_start(file_browser, data->preselected_filename);
|
file_browser_start(file_browser, data->preselected_filename);
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,9 @@ struct FileBrowser {
|
|||||||
View* view;
|
View* view;
|
||||||
BrowserWorker* worker;
|
BrowserWorker* worker;
|
||||||
const char* ext_filter;
|
const char* ext_filter;
|
||||||
|
const char* base_path;
|
||||||
bool skip_assets;
|
bool skip_assets;
|
||||||
|
bool hide_dot_files;
|
||||||
bool hide_ext;
|
bool hide_ext;
|
||||||
|
|
||||||
FileBrowserCallback callback;
|
FileBrowserCallback callback;
|
||||||
@@ -162,7 +164,9 @@ View* file_browser_get_view(FileBrowser* browser) {
|
|||||||
void file_browser_configure(
|
void file_browser_configure(
|
||||||
FileBrowser* browser,
|
FileBrowser* browser,
|
||||||
const char* extension,
|
const char* extension,
|
||||||
|
const char* base_path,
|
||||||
bool skip_assets,
|
bool skip_assets,
|
||||||
|
bool hide_dot_files,
|
||||||
const Icon* file_icon,
|
const Icon* file_icon,
|
||||||
bool hide_ext) {
|
bool hide_ext) {
|
||||||
furi_assert(browser);
|
furi_assert(browser);
|
||||||
@@ -170,6 +174,8 @@ void file_browser_configure(
|
|||||||
browser->ext_filter = extension;
|
browser->ext_filter = extension;
|
||||||
browser->skip_assets = skip_assets;
|
browser->skip_assets = skip_assets;
|
||||||
browser->hide_ext = hide_ext;
|
browser->hide_ext = hide_ext;
|
||||||
|
browser->base_path = base_path;
|
||||||
|
browser->hide_dot_files = hide_dot_files;
|
||||||
|
|
||||||
with_view_model(
|
with_view_model(
|
||||||
browser->view,
|
browser->view,
|
||||||
@@ -183,7 +189,12 @@ void file_browser_configure(
|
|||||||
|
|
||||||
void file_browser_start(FileBrowser* browser, FuriString* path) {
|
void file_browser_start(FileBrowser* browser, FuriString* path) {
|
||||||
furi_assert(browser);
|
furi_assert(browser);
|
||||||
browser->worker = file_browser_worker_alloc(path, browser->ext_filter, browser->skip_assets);
|
browser->worker = file_browser_worker_alloc(
|
||||||
|
path,
|
||||||
|
browser->base_path,
|
||||||
|
browser->ext_filter,
|
||||||
|
browser->skip_assets,
|
||||||
|
browser->hide_dot_files);
|
||||||
file_browser_worker_set_callback_context(browser->worker, browser);
|
file_browser_worker_set_callback_context(browser->worker, browser);
|
||||||
file_browser_worker_set_folder_callback(browser->worker, browser_folder_open_cb);
|
file_browser_worker_set_folder_callback(browser->worker, browser_folder_open_cb);
|
||||||
file_browser_worker_set_list_callback(browser->worker, browser_list_load_cb);
|
file_browser_worker_set_list_callback(browser->worker, browser_list_load_cb);
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ View* file_browser_get_view(FileBrowser* browser);
|
|||||||
void file_browser_configure(
|
void file_browser_configure(
|
||||||
FileBrowser* browser,
|
FileBrowser* browser,
|
||||||
const char* extension,
|
const char* extension,
|
||||||
|
const char* base_path,
|
||||||
bool skip_assets,
|
bool skip_assets,
|
||||||
|
bool hide_dot_files,
|
||||||
const Icon* file_icon,
|
const Icon* file_icon,
|
||||||
bool hide_ext);
|
bool hide_ext);
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ struct BrowserWorker {
|
|||||||
uint32_t load_offset;
|
uint32_t load_offset;
|
||||||
uint32_t load_count;
|
uint32_t load_count;
|
||||||
bool skip_assets;
|
bool skip_assets;
|
||||||
|
bool hide_dot_files;
|
||||||
idx_last_array_t idx_last;
|
idx_last_array_t idx_last;
|
||||||
|
|
||||||
void* cb_ctx;
|
void* cb_ctx;
|
||||||
@@ -76,6 +77,13 @@ static bool browser_path_trim(FuriString* path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool browser_filter_by_name(BrowserWorker* browser, FuriString* name, bool is_folder) {
|
static bool browser_filter_by_name(BrowserWorker* browser, FuriString* name, bool is_folder) {
|
||||||
|
// Skip dot files if enabled
|
||||||
|
if(browser->hide_dot_files) {
|
||||||
|
if(furi_string_start_with_str(name, ".")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(is_folder) {
|
if(is_folder) {
|
||||||
// Skip assets folders (if enabled)
|
// Skip assets folders (if enabled)
|
||||||
if(browser->skip_assets) {
|
if(browser->skip_assets) {
|
||||||
@@ -361,20 +369,26 @@ static int32_t browser_worker(void* context) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserWorker*
|
BrowserWorker* file_browser_worker_alloc(
|
||||||
file_browser_worker_alloc(FuriString* path, const char* filter_ext, bool skip_assets) {
|
FuriString* path,
|
||||||
|
const char* base_path,
|
||||||
|
const char* filter_ext,
|
||||||
|
bool skip_assets,
|
||||||
|
bool hide_dot_files) {
|
||||||
BrowserWorker* browser = malloc(sizeof(BrowserWorker)); //-V773
|
BrowserWorker* browser = malloc(sizeof(BrowserWorker)); //-V773
|
||||||
|
|
||||||
idx_last_array_init(browser->idx_last);
|
idx_last_array_init(browser->idx_last);
|
||||||
|
|
||||||
browser->filter_extension = furi_string_alloc_set(filter_ext);
|
browser->filter_extension = furi_string_alloc_set(filter_ext);
|
||||||
browser->skip_assets = skip_assets;
|
browser->skip_assets = skip_assets;
|
||||||
browser->path_start = furi_string_alloc_set(path);
|
browser->hide_dot_files = hide_dot_files;
|
||||||
|
|
||||||
browser->path_current = furi_string_alloc_set(path);
|
browser->path_current = furi_string_alloc_set(path);
|
||||||
browser->path_next = furi_string_alloc_set(path);
|
browser->path_next = furi_string_alloc_set(path);
|
||||||
|
|
||||||
if(browser_path_is_file(browser->path_start)) {
|
browser->path_start = furi_string_alloc();
|
||||||
browser_path_trim(browser->path_start);
|
if(base_path) {
|
||||||
|
furi_string_set_str(browser->path_start, base_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
browser->thread = furi_thread_alloc_ex("BrowserWorker", 2048, browser_worker, browser);
|
browser->thread = furi_thread_alloc_ex("BrowserWorker", 2048, browser_worker, browser);
|
||||||
@@ -437,11 +451,13 @@ void file_browser_worker_set_config(
|
|||||||
BrowserWorker* browser,
|
BrowserWorker* browser,
|
||||||
FuriString* path,
|
FuriString* path,
|
||||||
const char* filter_ext,
|
const char* filter_ext,
|
||||||
bool skip_assets) {
|
bool skip_assets,
|
||||||
|
bool hide_dot_files) {
|
||||||
furi_assert(browser);
|
furi_assert(browser);
|
||||||
furi_string_set(browser->path_next, path);
|
furi_string_set(browser->path_next, path);
|
||||||
furi_string_set(browser->filter_extension, filter_ext);
|
furi_string_set(browser->filter_extension, filter_ext);
|
||||||
browser->skip_assets = skip_assets;
|
browser->skip_assets = skip_assets;
|
||||||
|
browser->hide_dot_files = hide_dot_files;
|
||||||
furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtConfigChange);
|
furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtConfigChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,12 @@ typedef void (*BrowserWorkerListItemCallback)(
|
|||||||
bool is_last);
|
bool is_last);
|
||||||
typedef void (*BrowserWorkerLongLoadCallback)(void* context);
|
typedef void (*BrowserWorkerLongLoadCallback)(void* context);
|
||||||
|
|
||||||
BrowserWorker*
|
BrowserWorker* file_browser_worker_alloc(
|
||||||
file_browser_worker_alloc(FuriString* path, const char* filter_ext, bool skip_assets);
|
FuriString* path,
|
||||||
|
const char* base_path,
|
||||||
|
const char* filter_ext,
|
||||||
|
bool skip_assets,
|
||||||
|
bool hide_dot_files);
|
||||||
|
|
||||||
void file_browser_worker_free(BrowserWorker* browser);
|
void file_browser_worker_free(BrowserWorker* browser);
|
||||||
|
|
||||||
@@ -48,7 +52,8 @@ void file_browser_worker_set_config(
|
|||||||
BrowserWorker* browser,
|
BrowserWorker* browser,
|
||||||
FuriString* path,
|
FuriString* path,
|
||||||
const char* filter_ext,
|
const char* filter_ext,
|
||||||
bool skip_assets);
|
bool skip_assets,
|
||||||
|
bool hide_dot_files);
|
||||||
|
|
||||||
void file_browser_worker_folder_enter(BrowserWorker* browser, FuriString* path, int32_t item_idx);
|
void file_browser_worker_folder_enter(BrowserWorker* browser, FuriString* path, int32_t item_idx);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,20 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
if(power->info.gauge_is_ok) {
|
if(power->info.gauge_is_ok) {
|
||||||
canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4);
|
canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4);
|
||||||
|
if(power->info.voltage_battery_charging < 4.2) {
|
||||||
|
// Battery charging voltage is modified, indicate with cross pattern
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
uint8_t battery_bar_width = (power->info.charge + 4) / 5;
|
||||||
|
bool cross_odd = false;
|
||||||
|
// Start 1 further in from the battery bar's x position
|
||||||
|
for(uint8_t x = 3; x <= battery_bar_width; x++) {
|
||||||
|
// Cross pattern is from the center of the battery bar
|
||||||
|
// y = 2 + 1 (inset) + 1 (for every other)
|
||||||
|
canvas_draw_dot(canvas, x, 3 + (uint8_t)cross_odd);
|
||||||
|
cross_odd = !cross_odd;
|
||||||
|
}
|
||||||
|
canvas_invert_color(canvas);
|
||||||
|
}
|
||||||
if(power->state == PowerStateCharging) {
|
if(power->state == PowerStateCharging) {
|
||||||
canvas_set_bitmap_mode(canvas, 1);
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
@@ -132,6 +146,7 @@ static bool power_update_info(Power* power) {
|
|||||||
info.capacity_full = furi_hal_power_get_battery_full_capacity();
|
info.capacity_full = furi_hal_power_get_battery_full_capacity();
|
||||||
info.current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger);
|
info.current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger);
|
||||||
info.current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge);
|
info.current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge);
|
||||||
|
info.voltage_battery_charging = furi_hal_power_get_battery_charging_voltage();
|
||||||
info.voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger);
|
info.voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger);
|
||||||
info.voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge);
|
info.voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge);
|
||||||
info.voltage_vbus = furi_hal_power_get_usb_voltage();
|
info.voltage_vbus = furi_hal_power_get_usb_voltage();
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ typedef struct {
|
|||||||
float current_charger;
|
float current_charger;
|
||||||
float current_gauge;
|
float current_gauge;
|
||||||
|
|
||||||
|
float voltage_battery_charging;
|
||||||
float voltage_charger;
|
float voltage_charger;
|
||||||
float voltage_gauge;
|
float voltage_gauge;
|
||||||
float voltage_vbus;
|
float voltage_vbus;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context)
|
|||||||
furi_assert(request->which_content == PB_Main_app_start_request_tag);
|
furi_assert(request->which_content == PB_Main_app_start_request_tag);
|
||||||
RpcAppSystem* rpc_app = context;
|
RpcAppSystem* rpc_app = context;
|
||||||
RpcSession* session = rpc_app->session;
|
RpcSession* session = rpc_app->session;
|
||||||
|
rpc_system_app_error_reset(rpc_app);
|
||||||
furi_assert(session);
|
furi_assert(session);
|
||||||
char args_temp[RPC_SYSTEM_APP_TEMP_ARGS_SIZE];
|
char args_temp[RPC_SYSTEM_APP_TEMP_ARGS_SIZE];
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ static void rpc_system_app_lock_status_process(const PB_Main* request, void* con
|
|||||||
|
|
||||||
furi_assert(request->which_content == PB_Main_app_lock_status_request_tag);
|
furi_assert(request->which_content == PB_Main_app_lock_status_request_tag);
|
||||||
RpcAppSystem* rpc_app = context;
|
RpcAppSystem* rpc_app = context;
|
||||||
|
rpc_system_app_error_reset(rpc_app);
|
||||||
RpcSession* session = rpc_app->session;
|
RpcSession* session = rpc_app->session;
|
||||||
furi_assert(session);
|
furi_assert(session);
|
||||||
|
|
||||||
@@ -108,6 +110,7 @@ static void rpc_system_app_exit_request(const PB_Main* request, void* context) {
|
|||||||
|
|
||||||
furi_assert(request->which_content == PB_Main_app_exit_request_tag);
|
furi_assert(request->which_content == PB_Main_app_exit_request_tag);
|
||||||
RpcAppSystem* rpc_app = context;
|
RpcAppSystem* rpc_app = context;
|
||||||
|
rpc_system_app_error_reset(rpc_app);
|
||||||
RpcSession* session = rpc_app->session;
|
RpcSession* session = rpc_app->session;
|
||||||
furi_assert(session);
|
furi_assert(session);
|
||||||
|
|
||||||
@@ -133,6 +136,7 @@ static void rpc_system_app_load_file(const PB_Main* request, void* context) {
|
|||||||
|
|
||||||
furi_assert(request->which_content == PB_Main_app_load_file_request_tag);
|
furi_assert(request->which_content == PB_Main_app_load_file_request_tag);
|
||||||
RpcAppSystem* rpc_app = context;
|
RpcAppSystem* rpc_app = context;
|
||||||
|
rpc_system_app_error_reset(rpc_app);
|
||||||
RpcSession* session = rpc_app->session;
|
RpcSession* session = rpc_app->session;
|
||||||
furi_assert(session);
|
furi_assert(session);
|
||||||
|
|
||||||
@@ -158,6 +162,7 @@ static void rpc_system_app_button_press(const PB_Main* request, void* context) {
|
|||||||
|
|
||||||
furi_assert(request->which_content == PB_Main_app_button_press_request_tag);
|
furi_assert(request->which_content == PB_Main_app_button_press_request_tag);
|
||||||
RpcAppSystem* rpc_app = context;
|
RpcAppSystem* rpc_app = context;
|
||||||
|
rpc_system_app_error_reset(rpc_app);
|
||||||
RpcSession* session = rpc_app->session;
|
RpcSession* session = rpc_app->session;
|
||||||
furi_assert(session);
|
furi_assert(session);
|
||||||
|
|
||||||
@@ -183,6 +188,7 @@ static void rpc_system_app_button_release(const PB_Main* request, void* context)
|
|||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
RpcAppSystem* rpc_app = context;
|
RpcAppSystem* rpc_app = context;
|
||||||
|
rpc_system_app_error_reset(rpc_app);
|
||||||
RpcSession* session = rpc_app->session;
|
RpcSession* session = rpc_app->session;
|
||||||
furi_assert(session);
|
furi_assert(session);
|
||||||
|
|
||||||
@@ -222,6 +228,7 @@ static void rpc_system_app_data_exchange_process(const PB_Main* request, void* c
|
|||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
RpcAppSystem* rpc_app = context;
|
RpcAppSystem* rpc_app = context;
|
||||||
|
rpc_system_app_error_reset(rpc_app);
|
||||||
RpcSession* session = rpc_app->session;
|
RpcSession* session = rpc_app->session;
|
||||||
furi_assert(session);
|
furi_assert(session);
|
||||||
|
|
||||||
@@ -326,6 +333,13 @@ void rpc_system_app_set_error_text(RpcAppSystem* rpc_app, const char* error_text
|
|||||||
content->text = error_text ? strdup(error_text) : NULL;
|
content->text = error_text ? strdup(error_text) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rpc_system_app_error_reset(RpcAppSystem* rpc_app) {
|
||||||
|
furi_assert(rpc_app);
|
||||||
|
|
||||||
|
rpc_system_app_set_error_code(rpc_app, 0);
|
||||||
|
rpc_system_app_set_error_text(rpc_app, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void rpc_system_app_set_data_exchange_callback(
|
void rpc_system_app_set_data_exchange_callback(
|
||||||
RpcAppSystem* rpc_app,
|
RpcAppSystem* rpc_app,
|
||||||
RpcAppSystemDataExchangeCallback callback,
|
RpcAppSystemDataExchangeCallback callback,
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ void rpc_system_app_set_error_code(RpcAppSystem* rpc_app, uint32_t error_code);
|
|||||||
|
|
||||||
void rpc_system_app_set_error_text(RpcAppSystem* rpc_app, const char* error_text);
|
void rpc_system_app_set_error_text(RpcAppSystem* rpc_app, const char* error_text);
|
||||||
|
|
||||||
|
void rpc_system_app_error_reset(RpcAppSystem* rpc_app);
|
||||||
|
|
||||||
void rpc_system_app_set_data_exchange_callback(
|
void rpc_system_app_set_data_exchange_callback(
|
||||||
RpcAppSystem* rpc_app,
|
RpcAppSystem* rpc_app,
|
||||||
RpcAppSystemDataExchangeCallback callback,
|
RpcAppSystemDataExchangeCallback callback,
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e
|
|||||||
.hide_ext = true,
|
.hide_ext = true,
|
||||||
.item_loader_callback = favorite_fap_selector_item_callback,
|
.item_loader_callback = favorite_fap_selector_item_callback,
|
||||||
.item_loader_context = app,
|
.item_loader_context = app,
|
||||||
|
.base_path = EXT_PATH("apps"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if(primary_favorite) { // Select favorite fap in file browser
|
if(primary_favorite) { // Select favorite fap in file browser
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ static void power_settings_scene_battery_info_update_model(PowerSettingsApp* app
|
|||||||
.gauge_voltage = app->info.voltage_gauge,
|
.gauge_voltage = app->info.voltage_gauge,
|
||||||
.gauge_current = app->info.current_gauge,
|
.gauge_current = app->info.current_gauge,
|
||||||
.gauge_temperature = app->info.temperature_gauge,
|
.gauge_temperature = app->info.temperature_gauge,
|
||||||
|
.charging_voltage = app->info.voltage_battery_charging,
|
||||||
.charge = app->info.charge,
|
.charge = app->info.charge,
|
||||||
.health = app->info.health,
|
.health = app->info.health,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,6 +68,16 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
|
|||||||
drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA");
|
drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA");
|
||||||
} else if(drain_current != 0) {
|
} else if(drain_current != 0) {
|
||||||
snprintf(header, 20, "...");
|
snprintf(header, 20, "...");
|
||||||
|
} else if(data->charging_voltage < 4.2) {
|
||||||
|
// Non-default battery charging limit, mention it
|
||||||
|
snprintf(emote, sizeof(emote), "Charged!");
|
||||||
|
snprintf(header, sizeof(header), "Limited to");
|
||||||
|
snprintf(
|
||||||
|
value,
|
||||||
|
sizeof(value),
|
||||||
|
"%ld.%ldV",
|
||||||
|
(uint32_t)(data->charging_voltage),
|
||||||
|
(uint32_t)(data->charging_voltage * 10) % 10);
|
||||||
} else {
|
} else {
|
||||||
snprintf(header, sizeof(header), "Charged!");
|
snprintf(header, sizeof(header), "Charged!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ typedef struct {
|
|||||||
float gauge_voltage;
|
float gauge_voltage;
|
||||||
float gauge_current;
|
float gauge_current;
|
||||||
float gauge_temperature;
|
float gauge_temperature;
|
||||||
|
float charging_voltage;
|
||||||
uint8_t charge;
|
uint8_t charge;
|
||||||
uint8_t health;
|
uint8_t health;
|
||||||
} BatteryInfoModel;
|
} BatteryInfoModel;
|
||||||
|
|||||||
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_0.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_1.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_10.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_11.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_12.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_13.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_14.png
vendored
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_15.png
vendored
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_16.png
vendored
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_17.png
vendored
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_18.png
vendored
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_19.png
vendored
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_2.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_20.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_3.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_4.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_5.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_6.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_7.png
vendored
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_8.png
vendored
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/dolphin/external/L2_Wake_up_128x64/frame_9.png
vendored
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
14
assets/dolphin/external/L2_Wake_up_128x64/meta.txt
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Filetype: Flipper Animation
|
||||||
|
Version: 1
|
||||||
|
|
||||||
|
Width: 128
|
||||||
|
Height: 64
|
||||||
|
Passive frames: 10
|
||||||
|
Active frames: 18
|
||||||
|
Frames order: 0 1 0 1 0 1 0 2 3 4 0 5 6 7 8 9 10 11 10 12 13 14 15 16 17 18 19 20
|
||||||
|
Active cycles: 1
|
||||||
|
Frame rate: 2
|
||||||
|
Duration: 3600
|
||||||
|
Active cooldown: 7
|
||||||
|
|
||||||
|
Bubble slots: 0
|
||||||
73
assets/dolphin/external/manifest.txt
vendored
@@ -36,19 +36,12 @@ Min level: 1
|
|||||||
Max level: 1
|
Max level: 1
|
||||||
Weight: 3
|
Weight: 3
|
||||||
|
|
||||||
Name: L2_Furippa2_128x64
|
Name: L2_Wake_up_128x64
|
||||||
Min butthurt: 0
|
Min butthurt: 0
|
||||||
Max butthurt: 6
|
Max butthurt: 12
|
||||||
Min level: 2
|
Min level: 2
|
||||||
Max level: 2
|
|
||||||
Weight: 3
|
|
||||||
|
|
||||||
Name: L3_Furippa3_128x64
|
|
||||||
Min butthurt: 0
|
|
||||||
Max butthurt: 6
|
|
||||||
Min level: 3
|
|
||||||
Max level: 3
|
Max level: 3
|
||||||
Weight: 3
|
Weight: 4
|
||||||
|
|
||||||
Name: L1_Read_books_128x64
|
Name: L1_Read_books_128x64
|
||||||
Min butthurt: 0
|
Min butthurt: 0
|
||||||
@@ -57,13 +50,6 @@ Min level: 1
|
|||||||
Max level: 1
|
Max level: 1
|
||||||
Weight: 3
|
Weight: 3
|
||||||
|
|
||||||
Name: L2_Hacking_pc_128x64
|
|
||||||
Min butthurt: 0
|
|
||||||
Max butthurt: 8
|
|
||||||
Min level: 2
|
|
||||||
Max level: 2
|
|
||||||
Weight: 3
|
|
||||||
|
|
||||||
Name: L1_Cry_128x64
|
Name: L1_Cry_128x64
|
||||||
Min butthurt: 8
|
Min butthurt: 8
|
||||||
Max butthurt: 13
|
Max butthurt: 13
|
||||||
@@ -90,14 +76,49 @@ Min butthurt: 0
|
|||||||
Max butthurt: 9
|
Max butthurt: 9
|
||||||
Min level: 1
|
Min level: 1
|
||||||
Max level: 3
|
Max level: 3
|
||||||
Weight: 5
|
Weight: 4
|
||||||
|
|
||||||
Name: L1_Painting_128x64
|
Name: L1_Painting_128x64
|
||||||
Min butthurt: 0
|
Min butthurt: 0
|
||||||
Max butthurt: 7
|
Max butthurt: 7
|
||||||
Min level: 1
|
Min level: 1
|
||||||
Max level: 3
|
Max level: 3
|
||||||
Weight: 4
|
Weight: 3
|
||||||
|
|
||||||
|
Name: L1_Leaving_sad_128x64
|
||||||
|
Min butthurt: 14
|
||||||
|
Max butthurt: 14
|
||||||
|
Min level: 1
|
||||||
|
Max level: 3
|
||||||
|
Weight: 3
|
||||||
|
|
||||||
|
Name: L2_Furippa2_128x64
|
||||||
|
Min butthurt: 0
|
||||||
|
Max butthurt: 6
|
||||||
|
Min level: 2
|
||||||
|
Max level: 2
|
||||||
|
Weight: 3
|
||||||
|
|
||||||
|
Name: L2_Hacking_pc_128x64
|
||||||
|
Min butthurt: 0
|
||||||
|
Max butthurt: 8
|
||||||
|
Min level: 2
|
||||||
|
Max level: 2
|
||||||
|
Weight: 3
|
||||||
|
|
||||||
|
Name: L2_Soldering_128x64
|
||||||
|
Min butthurt: 0
|
||||||
|
Max butthurt: 10
|
||||||
|
Min level: 2
|
||||||
|
Max level: 2
|
||||||
|
Weight: 3
|
||||||
|
|
||||||
|
Name: L3_Furippa3_128x64
|
||||||
|
Min butthurt: 0
|
||||||
|
Max butthurt: 6
|
||||||
|
Min level: 3
|
||||||
|
Max level: 3
|
||||||
|
Weight: 3
|
||||||
|
|
||||||
Name: L3_Hijack_radio_128x64
|
Name: L3_Hijack_radio_128x64
|
||||||
Min butthurt: 0
|
Min butthurt: 0
|
||||||
@@ -112,17 +133,3 @@ Max butthurt: 10
|
|||||||
Min level: 3
|
Min level: 3
|
||||||
Max level: 3
|
Max level: 3
|
||||||
Weight: 3
|
Weight: 3
|
||||||
|
|
||||||
Name: L2_Soldering_128x64
|
|
||||||
Min butthurt: 0
|
|
||||||
Max butthurt: 10
|
|
||||||
Min level: 2
|
|
||||||
Max level: 2
|
|
||||||
Weight: 3
|
|
||||||
|
|
||||||
Name: L1_Leaving_sad_128x64
|
|
||||||
Min butthurt: 14
|
|
||||||
Max butthurt: 14
|
|
||||||
Min level: 1
|
|
||||||
Max level: 3
|
|
||||||
Weight: 3
|
|
||||||
|
|||||||
BIN
assets/icons/NFC/NFC_dolphin_emulation_47x61.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1620,3 +1620,39 @@ type: raw
|
|||||||
frequency: 38000
|
frequency: 38000
|
||||||
duty_cycle: 0.33
|
duty_cycle: 0.33
|
||||||
data: 7847 3931 470 1448 467 495 472 1443 472 490 467 1451 464 491 466 499 468 491 466 4413 467 1455 470 486 471 1449 466 495 472 1441 464 501 466 492 465 494 463 22093 7851 3934 467 1454 471 490 467 1446 469 496 471 1446 469 489 468 494 473 484 473 4410 470 1449 466 489 468 1455 470 489 468 1449 466 496 471 486 471 490 467
|
data: 7847 3931 470 1448 467 495 472 1443 472 490 467 1451 464 491 466 499 468 491 466 4413 467 1455 470 486 471 1449 466 495 472 1441 464 501 466 492 465 494 463 22093 7851 3934 467 1454 471 490 467 1446 469 496 471 1446 469 489 468 494 473 484 473 4410 470 1449 466 489 468 1455 470 489 468 1449 466 496 471 486 471 490 467
|
||||||
|
#
|
||||||
|
name: Power
|
||||||
|
type: parsed
|
||||||
|
protocol: RC5
|
||||||
|
address: 01 00 00 00
|
||||||
|
command: 0C 00 00 00
|
||||||
|
#
|
||||||
|
name: Mute
|
||||||
|
type: parsed
|
||||||
|
protocol: RC5
|
||||||
|
address: 01 00 00 00
|
||||||
|
command: 0D 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_up
|
||||||
|
type: parsed
|
||||||
|
protocol: RC5
|
||||||
|
address: 01 00 00 00
|
||||||
|
command: 10 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_dn
|
||||||
|
type: parsed
|
||||||
|
protocol: RC5
|
||||||
|
address: 01 00 00 00
|
||||||
|
command: 11 00 00 00
|
||||||
|
#
|
||||||
|
name: Ch_next
|
||||||
|
type: parsed
|
||||||
|
protocol: RC5
|
||||||
|
address: 01 00 00 00
|
||||||
|
command: 20 00 00 00
|
||||||
|
#
|
||||||
|
name: Ch_prev
|
||||||
|
type: parsed
|
||||||
|
protocol: RC5
|
||||||
|
address: 01 00 00 00
|
||||||
|
command: 21 00 00 00
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,8.3,,
|
Version,+,10.1,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
Header,+,applications/services/cli/cli_vcp.h,,
|
Header,+,applications/services/cli/cli_vcp.h,,
|
||||||
@@ -821,14 +821,14 @@ Function,-,fgetpos,int,"FILE*, fpos_t*"
|
|||||||
Function,-,fgets,char*,"char*, int, FILE*"
|
Function,-,fgets,char*,"char*, int, FILE*"
|
||||||
Function,-,fgets_unlocked,char*,"char*, int, FILE*"
|
Function,-,fgets_unlocked,char*,"char*, int, FILE*"
|
||||||
Function,+,file_browser_alloc,FileBrowser*,FuriString*
|
Function,+,file_browser_alloc,FileBrowser*,FuriString*
|
||||||
Function,+,file_browser_configure,void,"FileBrowser*, const char*, _Bool, const Icon*, _Bool"
|
Function,+,file_browser_configure,void,"FileBrowser*, const char*, const char*, _Bool, _Bool, const Icon*, _Bool"
|
||||||
Function,+,file_browser_free,void,FileBrowser*
|
Function,+,file_browser_free,void,FileBrowser*
|
||||||
Function,+,file_browser_get_view,View*,FileBrowser*
|
Function,+,file_browser_get_view,View*,FileBrowser*
|
||||||
Function,+,file_browser_set_callback,void,"FileBrowser*, FileBrowserCallback, void*"
|
Function,+,file_browser_set_callback,void,"FileBrowser*, FileBrowserCallback, void*"
|
||||||
Function,+,file_browser_set_item_callback,void,"FileBrowser*, FileBrowserLoadItemCallback, void*"
|
Function,+,file_browser_set_item_callback,void,"FileBrowser*, FileBrowserLoadItemCallback, void*"
|
||||||
Function,+,file_browser_start,void,"FileBrowser*, FuriString*"
|
Function,+,file_browser_start,void,"FileBrowser*, FuriString*"
|
||||||
Function,+,file_browser_stop,void,FileBrowser*
|
Function,+,file_browser_stop,void,FileBrowser*
|
||||||
Function,+,file_browser_worker_alloc,BrowserWorker*,"FuriString*, const char*, _Bool"
|
Function,+,file_browser_worker_alloc,BrowserWorker*,"FuriString*, const char*, const char*, _Bool, _Bool"
|
||||||
Function,+,file_browser_worker_folder_enter,void,"BrowserWorker*, FuriString*, int32_t"
|
Function,+,file_browser_worker_folder_enter,void,"BrowserWorker*, FuriString*, int32_t"
|
||||||
Function,+,file_browser_worker_folder_exit,void,BrowserWorker*
|
Function,+,file_browser_worker_folder_exit,void,BrowserWorker*
|
||||||
Function,+,file_browser_worker_folder_refresh,void,"BrowserWorker*, int32_t"
|
Function,+,file_browser_worker_folder_refresh,void,"BrowserWorker*, int32_t"
|
||||||
@@ -836,7 +836,7 @@ Function,+,file_browser_worker_free,void,BrowserWorker*
|
|||||||
Function,+,file_browser_worker_is_in_start_folder,_Bool,BrowserWorker*
|
Function,+,file_browser_worker_is_in_start_folder,_Bool,BrowserWorker*
|
||||||
Function,+,file_browser_worker_load,void,"BrowserWorker*, uint32_t, uint32_t"
|
Function,+,file_browser_worker_load,void,"BrowserWorker*, uint32_t, uint32_t"
|
||||||
Function,+,file_browser_worker_set_callback_context,void,"BrowserWorker*, void*"
|
Function,+,file_browser_worker_set_callback_context,void,"BrowserWorker*, void*"
|
||||||
Function,+,file_browser_worker_set_config,void,"BrowserWorker*, FuriString*, const char*, _Bool"
|
Function,+,file_browser_worker_set_config,void,"BrowserWorker*, FuriString*, const char*, _Bool, _Bool"
|
||||||
Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, BrowserWorkerFolderOpenCallback"
|
Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, BrowserWorkerFolderOpenCallback"
|
||||||
Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback"
|
Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback"
|
||||||
Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback"
|
Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback"
|
||||||
@@ -1209,6 +1209,7 @@ Function,+,furi_hal_power_enable_external_3_3v,void,
|
|||||||
Function,+,furi_hal_power_enable_otg,void,
|
Function,+,furi_hal_power_enable_otg,void,
|
||||||
Function,+,furi_hal_power_gauge_is_ok,_Bool,
|
Function,+,furi_hal_power_gauge_is_ok,_Bool,
|
||||||
Function,+,furi_hal_power_get_bat_health_pct,uint8_t,
|
Function,+,furi_hal_power_get_bat_health_pct,uint8_t,
|
||||||
|
Function,+,furi_hal_power_get_battery_charging_voltage,float,
|
||||||
Function,+,furi_hal_power_get_battery_current,float,FuriHalPowerIC
|
Function,+,furi_hal_power_get_battery_current,float,FuriHalPowerIC
|
||||||
Function,+,furi_hal_power_get_battery_design_capacity,uint32_t,
|
Function,+,furi_hal_power_get_battery_design_capacity,uint32_t,
|
||||||
Function,+,furi_hal_power_get_battery_full_capacity,uint32_t,
|
Function,+,furi_hal_power_get_battery_full_capacity,uint32_t,
|
||||||
@@ -1227,6 +1228,7 @@ Function,+,furi_hal_power_is_charging_done,_Bool,
|
|||||||
Function,+,furi_hal_power_is_otg_enabled,_Bool,
|
Function,+,furi_hal_power_is_otg_enabled,_Bool,
|
||||||
Function,+,furi_hal_power_off,void,
|
Function,+,furi_hal_power_off,void,
|
||||||
Function,+,furi_hal_power_reset,void,
|
Function,+,furi_hal_power_reset,void,
|
||||||
|
Function,+,furi_hal_power_set_battery_charging_voltage,void,float
|
||||||
Function,+,furi_hal_power_shutdown,void,
|
Function,+,furi_hal_power_shutdown,void,
|
||||||
Function,+,furi_hal_power_sleep,void,
|
Function,+,furi_hal_power_sleep,void,
|
||||||
Function,+,furi_hal_power_sleep_available,_Bool,
|
Function,+,furi_hal_power_sleep_available,_Bool,
|
||||||
@@ -2301,6 +2303,7 @@ Function,+,rpc_session_set_context,void,"RpcSession*, void*"
|
|||||||
Function,+,rpc_session_set_send_bytes_callback,void,"RpcSession*, RpcSendBytesCallback"
|
Function,+,rpc_session_set_send_bytes_callback,void,"RpcSession*, RpcSendBytesCallback"
|
||||||
Function,+,rpc_session_set_terminated_callback,void,"RpcSession*, RpcSessionTerminatedCallback"
|
Function,+,rpc_session_set_terminated_callback,void,"RpcSession*, RpcSessionTerminatedCallback"
|
||||||
Function,+,rpc_system_app_confirm,void,"RpcAppSystem*, RpcAppSystemEvent, _Bool"
|
Function,+,rpc_system_app_confirm,void,"RpcAppSystem*, RpcAppSystemEvent, _Bool"
|
||||||
|
Function,+,rpc_system_app_error_reset,void,RpcAppSystem*
|
||||||
Function,+,rpc_system_app_exchange_data,void,"RpcAppSystem*, const uint8_t*, size_t"
|
Function,+,rpc_system_app_exchange_data,void,"RpcAppSystem*, const uint8_t*, size_t"
|
||||||
Function,+,rpc_system_app_get_data,const char*,RpcAppSystem*
|
Function,+,rpc_system_app_get_data,const char*,RpcAppSystem*
|
||||||
Function,+,rpc_system_app_send_exited,void,RpcAppSystem*
|
Function,+,rpc_system_app_send_exited,void,RpcAppSystem*
|
||||||
|
|||||||
|
@@ -259,6 +259,9 @@ bool furi_hal_nfc_listen(
|
|||||||
params.lmConfigPA.SEL_RES = sak;
|
params.lmConfigPA.SEL_RES = sak;
|
||||||
rfalNfcDiscover(¶ms);
|
rfalNfcDiscover(¶ms);
|
||||||
|
|
||||||
|
// Disable EMD suppression.
|
||||||
|
st25r3916ModifyRegister(ST25R3916_REG_EMD_SUP_CONF, ST25R3916_REG_EMD_SUP_CONF_emd_emv, 0);
|
||||||
|
|
||||||
uint32_t start = DWT->CYCCNT;
|
uint32_t start = DWT->CYCCNT;
|
||||||
while(state != RFAL_NFC_STATE_ACTIVATED) {
|
while(state != RFAL_NFC_STATE_ACTIVATED) {
|
||||||
rfalNfcWorker();
|
rfalNfcWorker();
|
||||||
|
|||||||
@@ -341,6 +341,20 @@ bool furi_hal_power_is_otg_enabled() {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float furi_hal_power_get_battery_charging_voltage() {
|
||||||
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
|
float ret = (float)bq25896_get_vreg_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||||
|
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void furi_hal_power_set_battery_charging_voltage(float voltage) {
|
||||||
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
|
// Adding 0.0005 is necessary because 4.016f is 4.015999794000, which gets truncated
|
||||||
|
bq25896_set_vreg_voltage(&furi_hal_i2c_handle_power, (uint16_t)(voltage * 1000.0f + 0.0005f));
|
||||||
|
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||||
|
}
|
||||||
|
|
||||||
void furi_hal_power_check_otg_status() {
|
void furi_hal_power_check_otg_status() {
|
||||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
if(bq25896_check_otg_fault(&furi_hal_i2c_handle_power))
|
if(bq25896_check_otg_fault(&furi_hal_i2c_handle_power))
|
||||||
@@ -470,10 +484,10 @@ void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context)
|
|||||||
|
|
||||||
if(sep == '.') {
|
if(sep == '.') {
|
||||||
property_value_out(&property_context, NULL, 2, "format", "major", "2");
|
property_value_out(&property_context, NULL, 2, "format", "major", "2");
|
||||||
property_value_out(&property_context, NULL, 2, "format", "minor", "0");
|
property_value_out(&property_context, NULL, 2, "format", "minor", "1");
|
||||||
} else {
|
} else {
|
||||||
property_value_out(&property_context, NULL, 3, "power", "info", "major", "1");
|
property_value_out(&property_context, NULL, 3, "power", "info", "major", "1");
|
||||||
property_value_out(&property_context, NULL, 3, "power", "info", "minor", "0");
|
property_value_out(&property_context, NULL, 3, "power", "info", "minor", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t charge = furi_hal_power_get_pct();
|
uint8_t charge = furi_hal_power_get_pct();
|
||||||
@@ -481,7 +495,7 @@ void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context)
|
|||||||
|
|
||||||
const char* charge_state;
|
const char* charge_state;
|
||||||
if(furi_hal_power_is_charging()) {
|
if(furi_hal_power_is_charging()) {
|
||||||
if(charge < 100) {
|
if((charge < 100) && (!furi_hal_power_is_charging_done())) {
|
||||||
charge_state = "charging";
|
charge_state = "charging";
|
||||||
} else {
|
} else {
|
||||||
charge_state = "charged";
|
charge_state = "charged";
|
||||||
@@ -491,6 +505,8 @@ void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
property_value_out(&property_context, NULL, 2, "charge", "state", charge_state);
|
property_value_out(&property_context, NULL, 2, "charge", "state", charge_state);
|
||||||
|
uint16_t charge_voltage = (uint16_t)(furi_hal_power_get_battery_charging_voltage() * 1000.f);
|
||||||
|
property_value_out(&property_context, "%u", 2, "charge", "voltage", charge_voltage);
|
||||||
uint16_t voltage =
|
uint16_t voltage =
|
||||||
(uint16_t)(furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge) * 1000.f);
|
(uint16_t)(furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge) * 1000.f);
|
||||||
property_value_out(&property_context, "%u", 2, "battery", "voltage", voltage);
|
property_value_out(&property_context, "%u", 2, "battery", "voltage", voltage);
|
||||||
@@ -567,6 +583,13 @@ void furi_hal_power_debug_get(PropertyValueCallback out, void* context) {
|
|||||||
"charger",
|
"charger",
|
||||||
"vbat",
|
"vbat",
|
||||||
bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power));
|
bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power));
|
||||||
|
property_value_out(
|
||||||
|
&property_context,
|
||||||
|
"%d",
|
||||||
|
2,
|
||||||
|
"charger",
|
||||||
|
"vreg",
|
||||||
|
bq25896_get_vreg_voltage(&furi_hal_i2c_handle_power));
|
||||||
property_value_out(
|
property_value_out(
|
||||||
&property_context,
|
&property_context,
|
||||||
"%d",
|
"%d",
|
||||||
|
|||||||
@@ -121,6 +121,22 @@ void furi_hal_power_check_otg_status();
|
|||||||
*/
|
*/
|
||||||
bool furi_hal_power_is_otg_enabled();
|
bool furi_hal_power_is_otg_enabled();
|
||||||
|
|
||||||
|
/** Get battery charging voltage in V
|
||||||
|
*
|
||||||
|
* @return voltage in V
|
||||||
|
*/
|
||||||
|
float furi_hal_power_get_battery_charging_voltage();
|
||||||
|
|
||||||
|
/** Set battery charging voltage in V
|
||||||
|
*
|
||||||
|
* Invalid values will be clamped to the nearest valid value.
|
||||||
|
*
|
||||||
|
* @param voltage[in] voltage in V
|
||||||
|
*
|
||||||
|
* @return voltage in V
|
||||||
|
*/
|
||||||
|
void furi_hal_power_set_battery_charging_voltage(float voltage);
|
||||||
|
|
||||||
/** Get remaining battery battery capacity in mAh
|
/** Get remaining battery battery capacity in mAh
|
||||||
*
|
*
|
||||||
* @return capacity in mAh
|
* @return capacity in mAh
|
||||||
|
|||||||
@@ -132,6 +132,33 @@ bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle) {
|
|||||||
return bq25896_regs.r03.OTG_CONFIG;
|
return bq25896_regs.r03.OTG_CONFIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t bq25896_get_vreg_voltage(FuriHalI2cBusHandle* handle) {
|
||||||
|
furi_hal_i2c_read_reg_8(
|
||||||
|
handle, BQ25896_ADDRESS, 0x06, (uint8_t*)&bq25896_regs.r06, BQ25896_I2C_TIMEOUT);
|
||||||
|
return (uint16_t)bq25896_regs.r06.VREG * 16 + 3840;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bq25896_set_vreg_voltage(FuriHalI2cBusHandle* handle, uint16_t vreg_voltage) {
|
||||||
|
if(vreg_voltage < 3840) {
|
||||||
|
// Minimum value is 3840 mV
|
||||||
|
bq25896_regs.r06.VREG = 0;
|
||||||
|
} else {
|
||||||
|
// Find the nearest voltage value (subtract offset, divide into sections)
|
||||||
|
// Values are truncated downward as needed (e.g. 4200mV -> 4192 mV)
|
||||||
|
bq25896_regs.r06.VREG = (uint8_t)((vreg_voltage - 3840) / 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not allow values above 23 (0x17, 4208mV)
|
||||||
|
// Exceeding 4.2v will overcharge the battery!
|
||||||
|
if(bq25896_regs.r06.VREG > 23) {
|
||||||
|
bq25896_regs.r06.VREG = 23;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply changes
|
||||||
|
furi_hal_i2c_write_reg_8(
|
||||||
|
handle, BQ25896_ADDRESS, 0x06, *(uint8_t*)&bq25896_regs.r06, BQ25896_I2C_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
bool bq25896_check_otg_fault(FuriHalI2cBusHandle* handle) {
|
bool bq25896_check_otg_fault(FuriHalI2cBusHandle* handle) {
|
||||||
furi_hal_i2c_read_reg_8(
|
furi_hal_i2c_read_reg_8(
|
||||||
handle, BQ25896_ADDRESS, 0x0C, (uint8_t*)&bq25896_regs.r0C, BQ25896_I2C_TIMEOUT);
|
handle, BQ25896_ADDRESS, 0x0C, (uint8_t*)&bq25896_regs.r0C, BQ25896_I2C_TIMEOUT);
|
||||||
|
|||||||
@@ -36,6 +36,15 @@ void bq25896_disable_otg(FuriHalI2cBusHandle* handle);
|
|||||||
/** Is otg enabled */
|
/** Is otg enabled */
|
||||||
bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle);
|
bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
|
/** Get VREG (charging) voltage in mV */
|
||||||
|
uint16_t bq25896_get_vreg_voltage(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
|
/** Set VREG (charging) voltage in mV
|
||||||
|
*
|
||||||
|
* Valid range: 3840mV - 4208mV, in steps of 16mV
|
||||||
|
*/
|
||||||
|
void bq25896_set_vreg_voltage(FuriHalI2cBusHandle* handle, uint16_t vreg_voltage);
|
||||||
|
|
||||||
/** Check OTG BOOST Fault status */
|
/** Check OTG BOOST Fault status */
|
||||||
bool bq25896_check_otg_fault(FuriHalI2cBusHandle* handle);
|
bool bq25896_check_otg_fault(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
#include <flipper_format/flipper_format.h>
|
#include <flipper_format/flipper_format.h>
|
||||||
|
|
||||||
#define TAG "NfcDevice"
|
#define TAG "NfcDevice"
|
||||||
#define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/cache")
|
#define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/.cache")
|
||||||
#define NFC_DEVICE_KEYS_EXTENSION ".keys"
|
#define NFC_DEVICE_KEYS_EXTENSION ".keys"
|
||||||
|
|
||||||
static const char* nfc_file_header = "Flipper NFC device";
|
static const char* nfc_file_header = "Flipper NFC device";
|
||||||
static const uint32_t nfc_file_version = 2;
|
static const uint32_t nfc_file_version = 3;
|
||||||
|
|
||||||
static const char* nfc_keys_file_header = "Flipper NFC keys";
|
static const char* nfc_keys_file_header = "Flipper NFC keys";
|
||||||
static const uint32_t nfc_keys_file_version = 1;
|
static const uint32_t nfc_keys_file_version = 1;
|
||||||
@@ -27,6 +27,11 @@ NfcDevice* nfc_device_alloc() {
|
|||||||
nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS);
|
nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
nfc_dev->load_path = furi_string_alloc();
|
nfc_dev->load_path = furi_string_alloc();
|
||||||
nfc_dev->dev_data.parsed_data = furi_string_alloc();
|
nfc_dev->dev_data.parsed_data = furi_string_alloc();
|
||||||
|
|
||||||
|
// Rename cache folder name for backward compatibility
|
||||||
|
if(storage_common_stat(nfc_dev->storage, "/ext/nfc/cache", NULL) == FSE_OK) {
|
||||||
|
storage_common_rename(nfc_dev->storage, "/ext/nfc/cache", NFC_DEVICE_KEYS_FOLDER);
|
||||||
|
}
|
||||||
return nfc_dev;
|
return nfc_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1041,7 +1046,9 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
|
|||||||
if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
|
if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
|
||||||
break;
|
break;
|
||||||
if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
|
if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
|
||||||
if(!flipper_format_write_hex(file, "ATQA", data->a_data.atqa, 2)) break;
|
// Save ATQA in MSB order for correct companion apps display
|
||||||
|
uint8_t atqa[2] = {data->a_data.atqa[1], data->a_data.atqa[0]};
|
||||||
|
if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break;
|
||||||
if(!flipper_format_write_hex(file, "SAK", &data->a_data.sak, 1)) break;
|
if(!flipper_format_write_hex(file, "SAK", &data->a_data.sak, 1)) break;
|
||||||
// Save more data if necessary
|
// Save more data if necessary
|
||||||
if(dev->format == NfcDeviceSaveFormatMifareUl) {
|
if(dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||||
@@ -1089,6 +1096,9 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
|
|||||||
temp_str = furi_string_alloc();
|
temp_str = furi_string_alloc();
|
||||||
bool deprecated_version = false;
|
bool deprecated_version = false;
|
||||||
|
|
||||||
|
// Version 2 of file format had ATQA bytes swapped
|
||||||
|
uint32_t version_with_lsb_atqa = 2;
|
||||||
|
|
||||||
if(dev->loading_cb) {
|
if(dev->loading_cb) {
|
||||||
dev->loading_cb(dev->loading_cb_ctx, true);
|
dev->loading_cb(dev->loading_cb_ctx, true);
|
||||||
}
|
}
|
||||||
@@ -1107,9 +1117,12 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
|
|||||||
// Read and verify file header
|
// Read and verify file header
|
||||||
uint32_t version = 0;
|
uint32_t version = 0;
|
||||||
if(!flipper_format_read_header(file, temp_str, &version)) break;
|
if(!flipper_format_read_header(file, temp_str, &version)) break;
|
||||||
if(furi_string_cmp_str(temp_str, nfc_file_header) || (version != nfc_file_version)) {
|
if(furi_string_cmp_str(temp_str, nfc_file_header)) break;
|
||||||
deprecated_version = true;
|
if(version != nfc_file_version) {
|
||||||
break;
|
if(version < version_with_lsb_atqa) {
|
||||||
|
deprecated_version = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Read Nfc device type
|
// Read Nfc device type
|
||||||
if(!flipper_format_read_string(file, "Device type", temp_str)) break;
|
if(!flipper_format_read_string(file, "Device type", temp_str)) break;
|
||||||
@@ -1119,7 +1132,14 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
|
|||||||
if(!(data_cnt == 4 || data_cnt == 7)) break;
|
if(!(data_cnt == 4 || data_cnt == 7)) break;
|
||||||
data->uid_len = data_cnt;
|
data->uid_len = data_cnt;
|
||||||
if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
|
if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
|
||||||
if(!flipper_format_read_hex(file, "ATQA", data->a_data.atqa, 2)) break;
|
if(version == version_with_lsb_atqa) {
|
||||||
|
if(!flipper_format_read_hex(file, "ATQA", data->a_data.atqa, 2)) break;
|
||||||
|
} else {
|
||||||
|
uint8_t atqa[2] = {};
|
||||||
|
if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break;
|
||||||
|
data->a_data.atqa[0] = atqa[1];
|
||||||
|
data->a_data.atqa[1] = atqa[0];
|
||||||
|
}
|
||||||
if(!flipper_format_read_hex(file, "SAK", &data->a_data.sak, 1)) break;
|
if(!flipper_format_read_hex(file, "SAK", &data->a_data.sak, 1)) break;
|
||||||
// Load CUID
|
// Load CUID
|
||||||
uint8_t* cuid_start = data->uid;
|
uint8_t* cuid_start = data->uid;
|
||||||
@@ -1187,10 +1207,12 @@ bool nfc_file_select(NfcDevice* dev) {
|
|||||||
const DialogsFileBrowserOptions browser_options = {
|
const DialogsFileBrowserOptions browser_options = {
|
||||||
.extension = NFC_APP_EXTENSION,
|
.extension = NFC_APP_EXTENSION,
|
||||||
.skip_assets = true,
|
.skip_assets = true,
|
||||||
|
.hide_dot_files = true,
|
||||||
.icon = &I_Nfc_10px,
|
.icon = &I_Nfc_10px,
|
||||||
.hide_ext = true,
|
.hide_ext = true,
|
||||||
.item_loader_callback = NULL,
|
.item_loader_callback = NULL,
|
||||||
.item_loader_context = NULL,
|
.item_loader_context = NULL,
|
||||||
|
.base_path = NFC_APP_FOLDER,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool res =
|
bool res =
|
||||||
|
|||||||
@@ -712,46 +712,16 @@ uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data
|
|||||||
furi_assert(tx_rx);
|
furi_assert(tx_rx);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
|
|
||||||
uint8_t sectors_read = 0;
|
|
||||||
Crypto1 crypto = {};
|
|
||||||
uint8_t total_sectors = mf_classic_get_total_sectors_num(data->type);
|
uint8_t total_sectors = mf_classic_get_total_sectors_num(data->type);
|
||||||
uint64_t key_a = 0;
|
|
||||||
uint64_t key_b = 0;
|
|
||||||
MfClassicSectorReader sec_reader = {};
|
|
||||||
MfClassicSector temp_sector = {};
|
|
||||||
|
|
||||||
for(size_t i = 0; i < total_sectors; i++) {
|
for(size_t i = 0; i < total_sectors; i++) {
|
||||||
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i);
|
mf_classic_read_sector(tx_rx, data, i);
|
||||||
// Load key A
|
|
||||||
if(mf_classic_is_key_found(data, i, MfClassicKeyA)) {
|
|
||||||
sec_reader.key_a = nfc_util_bytes2num(sec_tr->key_a, 6);
|
|
||||||
} else {
|
|
||||||
sec_reader.key_a = MF_CLASSIC_NO_KEY;
|
|
||||||
}
|
|
||||||
// Load key B
|
|
||||||
if(mf_classic_is_key_found(data, i, MfClassicKeyB)) {
|
|
||||||
sec_reader.key_b = nfc_util_bytes2num(sec_tr->key_b, 6);
|
|
||||||
} else {
|
|
||||||
sec_reader.key_b = MF_CLASSIC_NO_KEY;
|
|
||||||
}
|
|
||||||
if((key_a != MF_CLASSIC_NO_KEY) || (key_b != MF_CLASSIC_NO_KEY)) {
|
|
||||||
sec_reader.sector_num = i;
|
|
||||||
if(mf_classic_read_sector_with_reader(tx_rx, &crypto, &sec_reader, &temp_sector)) {
|
|
||||||
uint8_t first_block = mf_classic_get_first_block_num_of_sector(i);
|
|
||||||
for(uint8_t j = 0; j < temp_sector.total_blocks; j++) {
|
|
||||||
mf_classic_set_block_read(data, first_block + j, &temp_sector.block[j]);
|
|
||||||
}
|
|
||||||
sectors_read++;
|
|
||||||
} else {
|
|
||||||
// Invalid key, set it to not found
|
|
||||||
if(key_a != MF_CLASSIC_NO_KEY) {
|
|
||||||
mf_classic_set_key_not_found(data, i, MfClassicKeyA);
|
|
||||||
} else {
|
|
||||||
mf_classic_set_key_not_found(data, i, MfClassicKeyB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
uint8_t sectors_read = 0;
|
||||||
|
uint8_t keys_found = 0;
|
||||||
|
mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found);
|
||||||
|
FURI_LOG_D(TAG, "Read %d sectors and %d keys", sectors_read, keys_found);
|
||||||
|
|
||||||
return sectors_read;
|
return sectors_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -238,9 +238,9 @@ class FlipperStorage:
|
|||||||
while read_size < size:
|
while read_size < size:
|
||||||
self.read.until("Ready?" + self.CLI_EOL)
|
self.read.until("Ready?" + self.CLI_EOL)
|
||||||
self.send("y")
|
self.send("y")
|
||||||
read_size = min(size - read_size, buffer_size)
|
chunk_size = min(size - read_size, buffer_size)
|
||||||
filedata.extend(self.port.read(read_size))
|
filedata.extend(self.port.read(chunk_size))
|
||||||
read_size = read_size + read_size
|
read_size = read_size + chunk_size
|
||||||
|
|
||||||
percent = str(math.ceil(read_size / size * 100))
|
percent = str(math.ceil(read_size / size * 100))
|
||||||
total_chunks = str(math.ceil(size / buffer_size))
|
total_chunks = str(math.ceil(size / buffer_size))
|
||||||
|
|||||||