Merge branch 'dev' of https://github.com/ClaraCrazy/Flipper-Xtreme into fix-bad_kb_bt-flipper_app-conflict
7
.gitignore
vendored
@@ -34,6 +34,10 @@ Brewfile.lock.json
|
|||||||
# Visual Studio
|
# Visual Studio
|
||||||
.vs/
|
.vs/
|
||||||
|
|
||||||
|
# Kate
|
||||||
|
.kateproject
|
||||||
|
.kateconfig
|
||||||
|
|
||||||
# legendary cmake's
|
# legendary cmake's
|
||||||
build
|
build
|
||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
@@ -68,9 +72,8 @@ PVS-Studio.log
|
|||||||
# Automate files, etc
|
# Automate files, etc
|
||||||
automate.py
|
automate.py
|
||||||
deployments/
|
deployments/
|
||||||
fbt_options.py
|
|
||||||
commitnotes.md
|
commitnotes.md
|
||||||
lib/STM32CubeWB
|
fbt_options.py
|
||||||
|
|
||||||
# Asset packs
|
# Asset packs
|
||||||
assets/dolphin/custom/*
|
assets/dolphin/custom/*
|
||||||
|
|||||||
@@ -86,4 +86,4 @@ Small applications providing configuration for basic firmware and its services.
|
|||||||
Utility apps not visible in other menus.
|
Utility apps not visible in other menus.
|
||||||
|
|
||||||
- `storage_move_to_sd` - Data migration tool for internal storage
|
- `storage_move_to_sd` - Data migration tool for internal storage
|
||||||
- `updater` - updater service & application
|
- `updater` - Update service & application
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ void AccessorApp::run(void) {
|
|||||||
AccessorApp::AccessorApp()
|
AccessorApp::AccessorApp()
|
||||||
: text_store{0} {
|
: text_store{0} {
|
||||||
notification = static_cast<NotificationApp*>(furi_record_open(RECORD_NOTIFICATION));
|
notification = static_cast<NotificationApp*>(furi_record_open(RECORD_NOTIFICATION));
|
||||||
onewire_host = onewire_host_alloc();
|
onewire_host = onewire_host_alloc(&ibutton_gpio);
|
||||||
furi_hal_power_enable_otg();
|
furi_hal_power_enable_otg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,56 +3,63 @@
|
|||||||
#include "../minunit.h"
|
#include "../minunit.h"
|
||||||
|
|
||||||
static void power_test_deinit(void) {
|
static void power_test_deinit(void) {
|
||||||
// Try to reset to default charging voltage
|
// Try to reset to default charge voltage limit
|
||||||
furi_hal_power_set_battery_charging_voltage(4.208f);
|
furi_hal_power_set_battery_charge_voltage_limit(4.208f);
|
||||||
}
|
}
|
||||||
|
|
||||||
MU_TEST(test_power_charge_voltage_exact) {
|
MU_TEST(test_power_charge_voltage_limit_exact) {
|
||||||
// Power of 16mV charge voltages get applied exactly
|
// Power of 16mV charge voltage limits get applied exactly
|
||||||
// (bq25896 charge controller works in 16mV increments)
|
// (bq25896 charge controller works in 16mV increments)
|
||||||
//
|
//
|
||||||
// This test may need adapted if other charge controllers are used in the future.
|
// 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) {
|
for(uint16_t charge_mv = 3840; charge_mv <= 4208; charge_mv += 16) {
|
||||||
float charge_volt = (float)charge_mv / 1000.0f;
|
float charge_volt = (float)charge_mv / 1000.0f;
|
||||||
furi_hal_power_set_battery_charging_voltage(charge_volt);
|
furi_hal_power_set_battery_charge_voltage_limit(charge_volt);
|
||||||
mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charging_voltage());
|
mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charge_voltage_limit());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MU_TEST(test_power_charge_voltage_floating_imprecision) {
|
MU_TEST(test_power_charge_voltage_limit_floating_imprecision) {
|
||||||
// 4.016f should act as 4.016 V, even with floating point imprecision
|
// 4.016f should act as 4.016 V, even with floating point imprecision
|
||||||
furi_hal_power_set_battery_charging_voltage(4.016f);
|
furi_hal_power_set_battery_charge_voltage_limit(4.016f);
|
||||||
mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charging_voltage());
|
mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charge_voltage_limit());
|
||||||
}
|
}
|
||||||
|
|
||||||
MU_TEST(test_power_charge_voltage_inexact) {
|
MU_TEST(test_power_charge_voltage_limit_inexact) {
|
||||||
// Charge voltages that are not power of 16mV get truncated down
|
// Charge voltage limits that are not power of 16mV get truncated down
|
||||||
furi_hal_power_set_battery_charging_voltage(3.841f);
|
furi_hal_power_set_battery_charge_voltage_limit(3.841f);
|
||||||
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
|
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
|
||||||
|
|
||||||
furi_hal_power_set_battery_charging_voltage(3.900f);
|
furi_hal_power_set_battery_charge_voltage_limit(3.900f);
|
||||||
mu_assert_double_eq(3.888, furi_hal_power_get_battery_charging_voltage());
|
mu_assert_double_eq(3.888, furi_hal_power_get_battery_charge_voltage_limit());
|
||||||
|
|
||||||
furi_hal_power_set_battery_charging_voltage(4.200f);
|
furi_hal_power_set_battery_charge_voltage_limit(4.200f);
|
||||||
mu_assert_double_eq(4.192, furi_hal_power_get_battery_charging_voltage());
|
mu_assert_double_eq(4.192, furi_hal_power_get_battery_charge_voltage_limit());
|
||||||
}
|
}
|
||||||
|
|
||||||
MU_TEST(test_power_charge_voltage_invalid_clamped) {
|
MU_TEST(test_power_charge_voltage_limit_invalid_clamped) {
|
||||||
// Out-of-range charge voltages get clamped to 3.840 V and 4.208 V
|
// Out-of-range charge voltage limits get clamped to 3.840 V and 4.208 V
|
||||||
furi_hal_power_set_battery_charging_voltage(3.808f);
|
furi_hal_power_set_battery_charge_voltage_limit(3.808f);
|
||||||
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
|
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
|
||||||
|
furi_hal_power_set_battery_charge_voltage_limit(1.0f);
|
||||||
|
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
|
||||||
|
|
||||||
// NOTE: Intentionally picking a small increment above 4.208 V to reduce the risk of an
|
// NOTE: Intentionally picking a small increment above 4.208 V to reduce the risk of an
|
||||||
// unhappy battery if this fails.
|
// unhappy battery if this fails.
|
||||||
furi_hal_power_set_battery_charging_voltage(4.240f);
|
furi_hal_power_set_battery_charge_voltage_limit(4.240f);
|
||||||
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charging_voltage());
|
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit());
|
||||||
|
// Likewise, picking a number that the uint8_t wraparound in the driver would result in a
|
||||||
|
// VREG value under 23 if this test fails.
|
||||||
|
// E.g. (uint8_t)((8105-3840)/16) -> 10
|
||||||
|
furi_hal_power_set_battery_charge_voltage_limit(8.105f);
|
||||||
|
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit());
|
||||||
}
|
}
|
||||||
|
|
||||||
MU_TEST_SUITE(test_power_suite) {
|
MU_TEST_SUITE(test_power_suite) {
|
||||||
MU_RUN_TEST(test_power_charge_voltage_exact);
|
MU_RUN_TEST(test_power_charge_voltage_limit_exact);
|
||||||
MU_RUN_TEST(test_power_charge_voltage_floating_imprecision);
|
MU_RUN_TEST(test_power_charge_voltage_limit_floating_imprecision);
|
||||||
MU_RUN_TEST(test_power_charge_voltage_inexact);
|
MU_RUN_TEST(test_power_charge_voltage_limit_inexact);
|
||||||
MU_RUN_TEST(test_power_charge_voltage_invalid_clamped);
|
MU_RUN_TEST(test_power_charge_voltage_limit_invalid_clamped);
|
||||||
power_test_deinit();
|
power_test_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ static void test_rpc_setup(void) {
|
|||||||
}
|
}
|
||||||
furi_check(rpc_session[0].session);
|
furi_check(rpc_session[0].session);
|
||||||
|
|
||||||
rpc_session[0].output_stream = furi_stream_buffer_alloc(1000, 1);
|
rpc_session[0].output_stream = furi_stream_buffer_alloc(4096, 1);
|
||||||
rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback);
|
rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback);
|
||||||
rpc_session[0].close_session_semaphore = xSemaphoreCreateBinary();
|
rpc_session[0].close_session_semaphore = xSemaphoreCreateBinary();
|
||||||
rpc_session[0].terminate_semaphore = xSemaphoreCreateBinary();
|
rpc_session[0].terminate_semaphore = xSemaphoreCreateBinary();
|
||||||
|
|||||||
@@ -12,8 +12,9 @@
|
|||||||
#define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes")
|
#define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes")
|
||||||
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
|
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
|
||||||
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
|
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
|
||||||
|
#define ALUTECH_AT_4N_DIR_NAME EXT_PATH("subghz/assets/alutech_at_4n")
|
||||||
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub")
|
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub")
|
||||||
#define TEST_RANDOM_COUNT_PARSE 273
|
#define TEST_RANDOM_COUNT_PARSE 329
|
||||||
#define TEST_TIMEOUT 10000
|
#define TEST_TIMEOUT 10000
|
||||||
|
|
||||||
static SubGhzEnvironment* environment_handler;
|
static SubGhzEnvironment* environment_handler;
|
||||||
@@ -43,6 +44,8 @@ static void subghz_test_init(void) {
|
|||||||
environment_handler, CAME_ATOMO_DIR_NAME);
|
environment_handler, CAME_ATOMO_DIR_NAME);
|
||||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||||
environment_handler, NICE_FLOR_S_DIR_NAME);
|
environment_handler, NICE_FLOR_S_DIR_NAME);
|
||||||
|
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
||||||
|
environment_handler, ALUTECH_AT_4N_DIR_NAME);
|
||||||
subghz_environment_set_protocol_registry(
|
subghz_environment_set_protocol_registry(
|
||||||
environment_handler, (void*)&subghz_protocol_registry);
|
environment_handler, (void*)&subghz_protocol_registry);
|
||||||
|
|
||||||
@@ -489,6 +492,14 @@ MU_TEST(subghz_decoder_linear_test) {
|
|||||||
"Test decoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n");
|
"Test decoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST(subghz_decoder_linear_delta3_test) {
|
||||||
|
mu_assert(
|
||||||
|
subghz_decoder_test(
|
||||||
|
EXT_PATH("unit_tests/subghz/linear_delta3_raw.sub"),
|
||||||
|
SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME),
|
||||||
|
"Test decoder " SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME " error\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
MU_TEST(subghz_decoder_megacode_test) {
|
MU_TEST(subghz_decoder_megacode_test) {
|
||||||
mu_assert(
|
mu_assert(
|
||||||
subghz_decoder_test(
|
subghz_decoder_test(
|
||||||
@@ -590,12 +601,6 @@ MU_TEST(subghz_decoder_ansonic_test) {
|
|||||||
"Test decoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n");
|
"Test decoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
MU_TEST(subghz_decoder_pocsag_test) {
|
|
||||||
mu_assert(
|
|
||||||
subghz_decoder_test(EXT_PATH("unit_tests/subghz/pocsag.sub"), SUBGHZ_PROTOCOL_POCSAG_NAME),
|
|
||||||
"Test decoder " SUBGHZ_PROTOCOL_POCSAG_NAME " error\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
MU_TEST(subghz_decoder_smc5326_test) {
|
MU_TEST(subghz_decoder_smc5326_test) {
|
||||||
mu_assert(
|
mu_assert(
|
||||||
subghz_decoder_test(
|
subghz_decoder_test(
|
||||||
@@ -610,6 +615,36 @@ MU_TEST(subghz_decoder_holtek_ht12x_test) {
|
|||||||
"Test decoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n");
|
"Test decoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST(subghz_decoder_dooya_test) {
|
||||||
|
mu_assert(
|
||||||
|
subghz_decoder_test(
|
||||||
|
EXT_PATH("unit_tests/subghz/dooya_raw.sub"), SUBGHZ_PROTOCOL_DOOYA_NAME),
|
||||||
|
"Test decoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(subghz_decoder_alutech_at_4n_test) {
|
||||||
|
mu_assert(
|
||||||
|
subghz_decoder_test(
|
||||||
|
EXT_PATH("unit_tests/subghz/alutech_at_4n_raw.sub"),
|
||||||
|
SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME),
|
||||||
|
"Test decoder " SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME " error\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(subghz_decoder_nice_one_test) {
|
||||||
|
mu_assert(
|
||||||
|
subghz_decoder_test(
|
||||||
|
EXT_PATH("unit_tests/subghz/nice_one_raw.sub"), SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME),
|
||||||
|
"Test decoder " SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME " error\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(subghz_decoder_kinggates_stylo4k_test) {
|
||||||
|
mu_assert(
|
||||||
|
subghz_decoder_test(
|
||||||
|
EXT_PATH("unit_tests/subghz/kinggates_stylo4k_raw.sub"),
|
||||||
|
SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME),
|
||||||
|
"Test decoder " SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME " error\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
//test encoders
|
//test encoders
|
||||||
MU_TEST(subghz_encoder_princeton_test) {
|
MU_TEST(subghz_encoder_princeton_test) {
|
||||||
mu_assert(
|
mu_assert(
|
||||||
@@ -653,6 +688,12 @@ MU_TEST(subghz_encoder_linear_test) {
|
|||||||
"Test encoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n");
|
"Test encoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST(subghz_encoder_linear_delta3_test) {
|
||||||
|
mu_assert(
|
||||||
|
subghz_encoder_test(EXT_PATH("unit_tests/subghz/linear_delta3.sub")),
|
||||||
|
"Test encoder " SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME " error\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
MU_TEST(subghz_encoder_megacode_test) {
|
MU_TEST(subghz_encoder_megacode_test) {
|
||||||
mu_assert(
|
mu_assert(
|
||||||
subghz_encoder_test(EXT_PATH("unit_tests/subghz/megacode.sub")),
|
subghz_encoder_test(EXT_PATH("unit_tests/subghz/megacode.sub")),
|
||||||
@@ -749,6 +790,12 @@ MU_TEST(subghz_encoder_holtek_ht12x_test) {
|
|||||||
"Test encoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n");
|
"Test encoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST(subghz_encoder_dooya_test) {
|
||||||
|
mu_assert(
|
||||||
|
subghz_encoder_test(EXT_PATH("unit_tests/subghz/dooya.sub")),
|
||||||
|
"Test encoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
MU_TEST(subghz_random_test) {
|
MU_TEST(subghz_random_test) {
|
||||||
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
|
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
|
||||||
}
|
}
|
||||||
@@ -778,6 +825,7 @@ MU_TEST_SUITE(subghz) {
|
|||||||
MU_RUN_TEST(subghz_decoder_somfy_telis_test);
|
MU_RUN_TEST(subghz_decoder_somfy_telis_test);
|
||||||
MU_RUN_TEST(subghz_decoder_star_line_test);
|
MU_RUN_TEST(subghz_decoder_star_line_test);
|
||||||
MU_RUN_TEST(subghz_decoder_linear_test);
|
MU_RUN_TEST(subghz_decoder_linear_test);
|
||||||
|
MU_RUN_TEST(subghz_decoder_linear_delta3_test);
|
||||||
MU_RUN_TEST(subghz_decoder_megacode_test);
|
MU_RUN_TEST(subghz_decoder_megacode_test);
|
||||||
MU_RUN_TEST(subghz_decoder_secplus_v1_test);
|
MU_RUN_TEST(subghz_decoder_secplus_v1_test);
|
||||||
MU_RUN_TEST(subghz_decoder_secplus_v2_test);
|
MU_RUN_TEST(subghz_decoder_secplus_v2_test);
|
||||||
@@ -792,9 +840,12 @@ MU_TEST_SUITE(subghz) {
|
|||||||
MU_RUN_TEST(subghz_decoder_intertechno_v3_test);
|
MU_RUN_TEST(subghz_decoder_intertechno_v3_test);
|
||||||
MU_RUN_TEST(subghz_decoder_clemsa_test);
|
MU_RUN_TEST(subghz_decoder_clemsa_test);
|
||||||
MU_RUN_TEST(subghz_decoder_ansonic_test);
|
MU_RUN_TEST(subghz_decoder_ansonic_test);
|
||||||
MU_RUN_TEST(subghz_decoder_pocsag_test);
|
|
||||||
MU_RUN_TEST(subghz_decoder_smc5326_test);
|
MU_RUN_TEST(subghz_decoder_smc5326_test);
|
||||||
MU_RUN_TEST(subghz_decoder_holtek_ht12x_test);
|
MU_RUN_TEST(subghz_decoder_holtek_ht12x_test);
|
||||||
|
MU_RUN_TEST(subghz_decoder_dooya_test);
|
||||||
|
MU_RUN_TEST(subghz_decoder_alutech_at_4n_test);
|
||||||
|
MU_RUN_TEST(subghz_decoder_nice_one_test);
|
||||||
|
MU_RUN_TEST(subghz_decoder_kinggates_stylo4k_test);
|
||||||
|
|
||||||
MU_RUN_TEST(subghz_encoder_princeton_test);
|
MU_RUN_TEST(subghz_encoder_princeton_test);
|
||||||
MU_RUN_TEST(subghz_encoder_came_test);
|
MU_RUN_TEST(subghz_encoder_came_test);
|
||||||
@@ -803,6 +854,7 @@ MU_TEST_SUITE(subghz) {
|
|||||||
MU_RUN_TEST(subghz_encoder_nice_flo_test);
|
MU_RUN_TEST(subghz_encoder_nice_flo_test);
|
||||||
MU_RUN_TEST(subghz_encoder_keelog_test);
|
MU_RUN_TEST(subghz_encoder_keelog_test);
|
||||||
MU_RUN_TEST(subghz_encoder_linear_test);
|
MU_RUN_TEST(subghz_encoder_linear_test);
|
||||||
|
MU_RUN_TEST(subghz_encoder_linear_delta3_test);
|
||||||
MU_RUN_TEST(subghz_encoder_megacode_test);
|
MU_RUN_TEST(subghz_encoder_megacode_test);
|
||||||
MU_RUN_TEST(subghz_encoder_holtek_test);
|
MU_RUN_TEST(subghz_encoder_holtek_test);
|
||||||
MU_RUN_TEST(subghz_encoder_secplus_v1_test);
|
MU_RUN_TEST(subghz_encoder_secplus_v1_test);
|
||||||
@@ -819,6 +871,7 @@ MU_TEST_SUITE(subghz) {
|
|||||||
MU_RUN_TEST(subghz_encoder_ansonic_test);
|
MU_RUN_TEST(subghz_encoder_ansonic_test);
|
||||||
MU_RUN_TEST(subghz_encoder_smc5326_test);
|
MU_RUN_TEST(subghz_encoder_smc5326_test);
|
||||||
MU_RUN_TEST(subghz_encoder_holtek_ht12x_test);
|
MU_RUN_TEST(subghz_encoder_holtek_ht12x_test);
|
||||||
|
MU_RUN_TEST(subghz_encoder_dooya_test);
|
||||||
|
|
||||||
MU_RUN_TEST(subghz_random_test);
|
MU_RUN_TEST(subghz_random_test);
|
||||||
subghz_test_deinit();
|
subghz_test_deinit();
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ void minunit_print_progress() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void minunit_print_fail(const char* str) {
|
void minunit_print_fail(const char* str) {
|
||||||
printf(FURI_LOG_CLR_E "%s\r\n" FURI_LOG_CLR_RESET, str);
|
printf(_FURI_LOG_CLR_E "%s\r\n" _FURI_LOG_CLR_RESET, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
|
void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <gui/modules/file_browser_worker.h>
|
#include <gui/modules/file_browser_worker.h>
|
||||||
#include <fap_loader/fap_loader_app.h>
|
#include <fap_loader/fap_loader_app.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
archive_folder_open_cb(void* context, uint32_t item_cnt, int32_t file_idx, bool is_root) {
|
archive_folder_open_cb(void* context, uint32_t item_cnt, int32_t file_idx, bool is_root) {
|
||||||
@@ -464,14 +465,17 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
|
|||||||
|
|
||||||
browser->last_tab_switch_dir = key;
|
browser->last_tab_switch_dir = key;
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++) {
|
if(key == InputKeyLeft) {
|
||||||
|
tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal;
|
||||||
|
} else {
|
||||||
|
tab = (tab + 1) % ArchiveTabTotal;
|
||||||
|
}
|
||||||
|
if(tab == ArchiveTabInternal && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
if(key == InputKeyLeft) {
|
if(key == InputKeyLeft) {
|
||||||
tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal;
|
tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal;
|
||||||
} else {
|
} else {
|
||||||
tab = (tab + 1) % ArchiveTabTotal;
|
tab = (tab + 1) % ArchiveTabTotal;
|
||||||
}
|
}
|
||||||
if(tab == ArchiveTabInternal && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) continue;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
browser->is_root = true;
|
browser->is_root = true;
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else if(event.event == GpioStartEventUsbUart) {
|
} else if(event.event == GpioStartEventUsbUart) {
|
||||||
scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart);
|
scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart);
|
||||||
if(!furi_hal_usb_is_locked()) {
|
if(!furi_hal_usb_is_locked()) {
|
||||||
|
DOLPHIN_DEED(DolphinDeedGpioUartBridge);
|
||||||
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart);
|
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc);
|
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc);
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ void onewire_cli_print_usage() {
|
|||||||
|
|
||||||
static void onewire_cli_search(Cli* cli) {
|
static void onewire_cli_search(Cli* cli) {
|
||||||
UNUSED(cli);
|
UNUSED(cli);
|
||||||
OneWireHost* onewire = onewire_host_alloc();
|
OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio);
|
||||||
uint8_t address[8];
|
uint8_t address[8];
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
if(event.event == SubmenuIndexRead) {
|
if(event.event == SubmenuIndexRead) {
|
||||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);
|
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);
|
||||||
//DOLPHIN_DEED(DolphinDeedIbuttonRead);
|
DOLPHIN_DEED(DolphinDeedIbuttonRead);
|
||||||
} else if(event.event == SubmenuIndexSaved) {
|
} else if(event.event == SubmenuIndexSaved) {
|
||||||
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
|
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
|
||||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey);
|
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey);
|
||||||
|
|||||||
@@ -148,6 +148,12 @@ static Infrared* infrared_alloc() {
|
|||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
view_dispatcher, InfraredViewTextInput, text_input_get_view(infrared->text_input));
|
view_dispatcher, InfraredViewTextInput, text_input_get_view(infrared->text_input));
|
||||||
|
|
||||||
|
infrared->variable_item_list = variable_item_list_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
infrared->view_dispatcher,
|
||||||
|
InfraredViewVariableItemList,
|
||||||
|
variable_item_list_get_view(infrared->variable_item_list));
|
||||||
|
|
||||||
infrared->dialog_ex = dialog_ex_alloc();
|
infrared->dialog_ex = dialog_ex_alloc();
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
view_dispatcher, InfraredViewDialogEx, dialog_ex_get_view(infrared->dialog_ex));
|
view_dispatcher, InfraredViewDialogEx, dialog_ex_get_view(infrared->dialog_ex));
|
||||||
@@ -195,6 +201,9 @@ static void infrared_free(Infrared* infrared) {
|
|||||||
view_dispatcher_remove_view(view_dispatcher, InfraredViewTextInput);
|
view_dispatcher_remove_view(view_dispatcher, InfraredViewTextInput);
|
||||||
text_input_free(infrared->text_input);
|
text_input_free(infrared->text_input);
|
||||||
|
|
||||||
|
view_dispatcher_remove_view(infrared->view_dispatcher, InfraredViewVariableItemList);
|
||||||
|
variable_item_list_free(infrared->variable_item_list);
|
||||||
|
|
||||||
view_dispatcher_remove_view(view_dispatcher, InfraredViewDialogEx);
|
view_dispatcher_remove_view(view_dispatcher, InfraredViewDialogEx);
|
||||||
dialog_ex_free(infrared->dialog_ex);
|
dialog_ex_free(infrared->dialog_ex);
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ static void infrared_cli_print_usage(void) {
|
|||||||
printf("\tir universal <remote_name> <signal_name>\r\n");
|
printf("\tir universal <remote_name> <signal_name>\r\n");
|
||||||
printf("\tir universal list <remote_name>\r\n");
|
printf("\tir universal list <remote_name>\r\n");
|
||||||
// TODO: Do not hardcode universal remote names
|
// TODO: Do not hardcode universal remote names
|
||||||
printf("\tAvailable universal remotes: tv audio ac\r\n");
|
printf("\tAvailable universal remotes: tv audio ac projector\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) {
|
static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/view.h>
|
#include <gui/view.h>
|
||||||
|
#include <assets_icons.h>
|
||||||
#include <gui/view_stack.h>
|
#include <gui/view_stack.h>
|
||||||
#include <gui/view_dispatcher.h>
|
#include <gui/view_dispatcher.h>
|
||||||
#include <gui/scene_manager.h>
|
#include <gui/scene_manager.h>
|
||||||
@@ -9,6 +10,7 @@
|
|||||||
#include <gui/modules/popup.h>
|
#include <gui/modules/popup.h>
|
||||||
#include <gui/modules/loading.h>
|
#include <gui/modules/loading.h>
|
||||||
#include <gui/modules/submenu.h>
|
#include <gui/modules/submenu.h>
|
||||||
|
#include <gui/modules/variable_item_list.h>
|
||||||
#include <gui/modules/dialog_ex.h>
|
#include <gui/modules/dialog_ex.h>
|
||||||
#include <gui/modules/text_input.h>
|
#include <gui/modules/text_input.h>
|
||||||
#include <gui/modules/button_menu.h>
|
#include <gui/modules/button_menu.h>
|
||||||
@@ -32,8 +34,6 @@
|
|||||||
|
|
||||||
#include "rpc/rpc_app.h"
|
#include "rpc/rpc_app.h"
|
||||||
|
|
||||||
#include <assets_icons.h>
|
|
||||||
|
|
||||||
#define INFRARED_FILE_NAME_SIZE 100
|
#define INFRARED_FILE_NAME_SIZE 100
|
||||||
#define INFRARED_TEXT_STORE_NUM 2
|
#define INFRARED_TEXT_STORE_NUM 2
|
||||||
#define INFRARED_TEXT_STORE_SIZE 128
|
#define INFRARED_TEXT_STORE_SIZE 128
|
||||||
@@ -87,6 +87,7 @@ struct Infrared {
|
|||||||
|
|
||||||
Submenu* submenu;
|
Submenu* submenu;
|
||||||
TextInput* text_input;
|
TextInput* text_input;
|
||||||
|
VariableItemList* variable_item_list;
|
||||||
DialogEx* dialog_ex;
|
DialogEx* dialog_ex;
|
||||||
ButtonMenu* button_menu;
|
ButtonMenu* button_menu;
|
||||||
Popup* popup;
|
Popup* popup;
|
||||||
@@ -108,6 +109,7 @@ struct Infrared {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
InfraredViewSubmenu,
|
InfraredViewSubmenu,
|
||||||
InfraredViewTextInput,
|
InfraredViewTextInput,
|
||||||
|
InfraredViewVariableItemList,
|
||||||
InfraredViewDialogEx,
|
InfraredViewDialogEx,
|
||||||
InfraredViewButtonMenu,
|
InfraredViewButtonMenu,
|
||||||
InfraredViewPopup,
|
InfraredViewPopup,
|
||||||
|
|||||||
@@ -21,4 +21,5 @@ ADD_SCENE(infrared, universal_audio, UniversalAudio)
|
|||||||
ADD_SCENE(infrared, universal_projector, UniversalProjector)
|
ADD_SCENE(infrared, universal_projector, UniversalProjector)
|
||||||
ADD_SCENE(infrared, debug, Debug)
|
ADD_SCENE(infrared, debug, Debug)
|
||||||
ADD_SCENE(infrared, error_databases, ErrorDatabases)
|
ADD_SCENE(infrared, error_databases, ErrorDatabases)
|
||||||
|
ADD_SCENE(infrared, debug_settings, DebugSettings)
|
||||||
ADD_SCENE(infrared, rpc, Rpc)
|
ADD_SCENE(infrared, rpc, Rpc)
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#include "../infrared_i.h"
|
||||||
|
#include <furi_hal_infrared.h>
|
||||||
|
|
||||||
|
uint8_t value_index_ir;
|
||||||
|
|
||||||
|
#define DEB_PINS_COUNT (sizeof(infrared_debug_cfg_variables_text) / sizeof(char* const))
|
||||||
|
const char* const infrared_debug_cfg_variables_text[] = {
|
||||||
|
"Internal",
|
||||||
|
"2 (A7)",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void infrared_scene_debug_settings_changed(VariableItem* item) {
|
||||||
|
Infrared* infrared = variable_item_get_context(item);
|
||||||
|
value_index_ir = variable_item_get_current_value_index(item);
|
||||||
|
UNUSED(infrared);
|
||||||
|
|
||||||
|
variable_item_set_current_value_text(item, infrared_debug_cfg_variables_text[value_index_ir]);
|
||||||
|
|
||||||
|
furi_hal_infrared_set_debug_out(value_index_ir);
|
||||||
|
}
|
||||||
|
static void infrared_debug_settings_start_var_list_enter_callback(void* context, uint32_t index) {
|
||||||
|
Infrared* infrared = context;
|
||||||
|
view_dispatcher_send_custom_event(infrared->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infrared_scene_debug_settings_on_enter(void* context) {
|
||||||
|
Infrared* infrared = context;
|
||||||
|
|
||||||
|
VariableItemList* variable_item_list = infrared->variable_item_list;
|
||||||
|
|
||||||
|
value_index_ir = furi_hal_infrared_get_debug_out_status();
|
||||||
|
VariableItem* item = variable_item_list_add(
|
||||||
|
variable_item_list,
|
||||||
|
"Send signal to",
|
||||||
|
DEB_PINS_COUNT,
|
||||||
|
infrared_scene_debug_settings_changed,
|
||||||
|
infrared);
|
||||||
|
|
||||||
|
variable_item_list_set_enter_callback(
|
||||||
|
variable_item_list, infrared_debug_settings_start_var_list_enter_callback, infrared);
|
||||||
|
|
||||||
|
variable_item_set_current_value_index(item, value_index_ir);
|
||||||
|
variable_item_set_current_value_text(item, infrared_debug_cfg_variables_text[value_index_ir]);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewVariableItemList);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool infrared_scene_debug_settings_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Infrared* infrared = context;
|
||||||
|
UNUSED(infrared);
|
||||||
|
UNUSED(event);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void infrared_scene_debug_settings_on_exit(void* context) {
|
||||||
|
Infrared* infrared = context;
|
||||||
|
variable_item_list_reset(infrared->variable_item_list);
|
||||||
|
}
|
||||||
@@ -5,7 +5,8 @@ enum SubmenuIndex {
|
|||||||
SubmenuIndexLearnNewRemote,
|
SubmenuIndexLearnNewRemote,
|
||||||
SubmenuIndexLearnNewRemoteRaw,
|
SubmenuIndexLearnNewRemoteRaw,
|
||||||
SubmenuIndexSavedRemotes,
|
SubmenuIndexSavedRemotes,
|
||||||
SubmenuIndexDebug
|
SubmenuIndexDebug,
|
||||||
|
SubmenuIndexDebugSettings
|
||||||
};
|
};
|
||||||
|
|
||||||
static void infrared_scene_start_submenu_callback(void* context, uint32_t index) {
|
static void infrared_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||||
@@ -45,7 +46,17 @@ void infrared_scene_start_on_enter(void* context) {
|
|||||||
infrared_scene_start_submenu_callback,
|
infrared_scene_start_submenu_callback,
|
||||||
infrared);
|
infrared);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Debug", SubmenuIndexDebug, infrared_scene_start_submenu_callback, infrared);
|
submenu,
|
||||||
|
"Debug RX",
|
||||||
|
SubmenuIndexDebug,
|
||||||
|
infrared_scene_start_submenu_callback,
|
||||||
|
infrared);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Debug Settings",
|
||||||
|
SubmenuIndexDebugSettings,
|
||||||
|
infrared_scene_start_submenu_callback,
|
||||||
|
infrared);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t submenu_index =
|
const uint32_t submenu_index =
|
||||||
@@ -85,6 +96,9 @@ bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else if(submenu_index == SubmenuIndexDebug) {
|
} else if(submenu_index == SubmenuIndexDebug) {
|
||||||
scene_manager_next_scene(scene_manager, InfraredSceneDebug);
|
scene_manager_next_scene(scene_manager, InfraredSceneDebug);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
} else if(submenu_index == SubmenuIndexDebugSettings) {
|
||||||
|
scene_manager_next_scene(scene_manager, InfraredSceneDebugSettings);
|
||||||
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC);
|
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
|
scene_manager_set_scene_state(scene_manager, InfraredSceneUniversal, event.event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
|
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/view.h>
|
#include <gui/view.h>
|
||||||
|
#include <assets_icons.h>
|
||||||
#include <gui/view_dispatcher.h>
|
#include <gui/view_dispatcher.h>
|
||||||
#include <gui/scene_manager.h>
|
#include <gui/scene_manager.h>
|
||||||
|
#include <cli/cli.h>
|
||||||
#include <notification/notification_messages.h>
|
#include <notification/notification_messages.h>
|
||||||
|
|
||||||
#include <gui/modules/submenu.h>
|
#include <gui/modules/submenu.h>
|
||||||
@@ -32,8 +34,6 @@
|
|||||||
#include <lfrfid/lfrfid_worker.h>
|
#include <lfrfid/lfrfid_worker.h>
|
||||||
|
|
||||||
#include <lfrfid/scenes/lfrfid_scene.h>
|
#include <lfrfid/scenes/lfrfid_scene.h>
|
||||||
#include <assets_icons.h>
|
|
||||||
// #include <lfrfid_icons.h>
|
|
||||||
|
|
||||||
#define LFRFID_KEY_NAME_SIZE 22
|
#define LFRFID_KEY_NAME_SIZE 22
|
||||||
#define LFRFID_TEXT_STORE_SIZE 40
|
#define LFRFID_TEXT_STORE_SIZE 40
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ void lfrfid_scene_extra_actions_on_enter(void* context) {
|
|||||||
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Read ASK (Animal, FDX)",
|
"Read ASK (FDX,Regular)",
|
||||||
SubmenuIndexASK,
|
SubmenuIndexASK,
|
||||||
lfrfid_scene_extra_actions_submenu_callback,
|
lfrfid_scene_extra_actions_submenu_callback,
|
||||||
app);
|
app);
|
||||||
|
|||||||
@@ -47,21 +47,28 @@ bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexRead) {
|
if(event.event == SubmenuIndexRead) {
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexRead);
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
|
||||||
DOLPHIN_DEED(DolphinDeedRfidRead);
|
DOLPHIN_DEED(DolphinDeedRfidRead);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexSaved) {
|
} else if(event.event == SubmenuIndexSaved) {
|
||||||
|
// Like in the other apps, explicitly save the scene state
|
||||||
|
// in each branch in case the user cancels loading a file.
|
||||||
|
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexSaved);
|
||||||
furi_string_set(app->file_path, LFRFID_APP_FOLDER);
|
furi_string_set(app->file_path, LFRFID_APP_FOLDER);
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexAddManually) {
|
} else if(event.event == SubmenuIndexAddManually) {
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
app->scene_manager, LfRfidSceneStart, SubmenuIndexAddManually);
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexExtraActions) {
|
} else if(event.event == SubmenuIndexExtraActions) {
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
app->scene_manager, LfRfidSceneStart, SubmenuIndexExtraActions);
|
||||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions);
|
scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, event.event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
|
|||||||
@@ -8,11 +8,14 @@ typedef enum {
|
|||||||
//SubmenuIndex
|
//SubmenuIndex
|
||||||
SubmenuIndexFaacSLH_433,
|
SubmenuIndexFaacSLH_433,
|
||||||
SubmenuIndexFaacSLH_868,
|
SubmenuIndexFaacSLH_868,
|
||||||
SubmenuIndexBFT,
|
SubmenuIndexBFTClone,
|
||||||
|
SubmenuIndexBFTMitto,
|
||||||
|
SubmenuIndexSomfyTelis,
|
||||||
SubmenuIndexPricenton,
|
SubmenuIndexPricenton,
|
||||||
SubmenuIndexNiceFlo12bit,
|
SubmenuIndexNiceFlo12bit,
|
||||||
SubmenuIndexNiceFlo24bit,
|
SubmenuIndexNiceFlo24bit,
|
||||||
SubmenuIndexNiceFlorS_433_92,
|
SubmenuIndexNiceFlorS_433_92,
|
||||||
|
SubmenuIndexNiceOne_433_92,
|
||||||
SubmenuIndexNiceSmilo_433_92,
|
SubmenuIndexNiceSmilo_433_92,
|
||||||
SubmenuIndexCAME12bit,
|
SubmenuIndexCAME12bit,
|
||||||
SubmenuIndexCAME24bit,
|
SubmenuIndexCAME24bit,
|
||||||
@@ -64,6 +67,7 @@ typedef enum {
|
|||||||
SubGhzCustomEventViewReceiverBack,
|
SubGhzCustomEventViewReceiverBack,
|
||||||
SubGhzCustomEventViewReceiverOffDisplay,
|
SubGhzCustomEventViewReceiverOffDisplay,
|
||||||
SubGhzCustomEventViewReceiverUnlock,
|
SubGhzCustomEventViewReceiverUnlock,
|
||||||
|
SubGhzCustomEventViewReceiverDeleteItem,
|
||||||
|
|
||||||
SubGhzCustomEventViewReadRAWBack,
|
SubGhzCustomEventViewReadRAWBack,
|
||||||
SubGhzCustomEventViewReadRAWIDLE,
|
SubGhzCustomEventViewReadRAWIDLE,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#include "../subghz_i.h"
|
#include "../subghz_i.h"
|
||||||
#include "../helpers/subghz_custom_event.h"
|
#include "../helpers/subghz_custom_event.h"
|
||||||
|
|
||||||
uint8_t value_index;
|
uint8_t value_index_exm;
|
||||||
uint8_t value_index2;
|
uint8_t value_index_dpin;
|
||||||
|
uint8_t value_index_cnt;
|
||||||
|
|
||||||
#define EXT_MODULES_COUNT (sizeof(radio_modules_variables_text) / sizeof(char* const))
|
#define EXT_MODULES_COUNT (sizeof(radio_modules_variables_text) / sizeof(char* const))
|
||||||
const char* const radio_modules_variables_text[] = {
|
const char* const radio_modules_variables_text[] = {
|
||||||
@@ -16,12 +17,22 @@ const char* const debug_pin_text[DEBUG_P_COUNT] = {
|
|||||||
"17(1W)",
|
"17(1W)",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DEBUG_COUNTER_COUNT 6
|
||||||
|
const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = {
|
||||||
|
"+1",
|
||||||
|
"+2",
|
||||||
|
"+3",
|
||||||
|
"+4",
|
||||||
|
"+5",
|
||||||
|
"+10",
|
||||||
|
};
|
||||||
|
|
||||||
static void subghz_scene_ext_module_changed(VariableItem* item) {
|
static void subghz_scene_ext_module_changed(VariableItem* item) {
|
||||||
SubGhz* subghz = variable_item_get_context(item);
|
SubGhz* subghz = variable_item_get_context(item);
|
||||||
value_index = variable_item_get_current_value_index(item);
|
value_index_exm = variable_item_get_current_value_index(item);
|
||||||
UNUSED(subghz);
|
UNUSED(subghz);
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, radio_modules_variables_text[value_index]);
|
variable_item_set_current_value_text(item, radio_modules_variables_text[value_index_exm]);
|
||||||
}
|
}
|
||||||
static void subghz_ext_module_start_var_list_enter_callback(void* context, uint32_t index) {
|
static void subghz_ext_module_start_var_list_enter_callback(void* context, uint32_t index) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
@@ -37,20 +48,49 @@ static void subghz_scene_receiver_config_set_debug_pin(VariableItem* item) {
|
|||||||
subghz->txrx->debug_pin_state = index == 1;
|
subghz->txrx->debug_pin_state = index == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) {
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
|
||||||
|
variable_item_set_current_value_text(item, debug_counter_text[index]);
|
||||||
|
|
||||||
|
switch(index) {
|
||||||
|
case 0:
|
||||||
|
furi_hal_subghz_set_rolling_counter_mult(1);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
furi_hal_subghz_set_rolling_counter_mult(2);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
furi_hal_subghz_set_rolling_counter_mult(3);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
furi_hal_subghz_set_rolling_counter_mult(4);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
furi_hal_subghz_set_rolling_counter_mult(5);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
furi_hal_subghz_set_rolling_counter_mult(10);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void subghz_scene_ext_module_settings_on_enter(void* context) {
|
void subghz_scene_ext_module_settings_on_enter(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
VariableItemList* variable_item_list = subghz->variable_item_list;
|
VariableItemList* variable_item_list = subghz->variable_item_list;
|
||||||
|
|
||||||
value_index = furi_hal_subghz.radio_type;
|
value_index_exm = furi_hal_subghz.radio_type;
|
||||||
VariableItem* item = variable_item_list_add(
|
VariableItem* item = variable_item_list_add(
|
||||||
variable_item_list, "Module", EXT_MODULES_COUNT, subghz_scene_ext_module_changed, subghz);
|
variable_item_list, "Module", EXT_MODULES_COUNT, subghz_scene_ext_module_changed, subghz);
|
||||||
|
|
||||||
variable_item_list_set_enter_callback(
|
variable_item_list_set_enter_callback(
|
||||||
variable_item_list, subghz_ext_module_start_var_list_enter_callback, subghz);
|
variable_item_list, subghz_ext_module_start_var_list_enter_callback, subghz);
|
||||||
|
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index_exm);
|
||||||
variable_item_set_current_value_text(item, radio_modules_variables_text[value_index]);
|
variable_item_set_current_value_text(item, radio_modules_variables_text[value_index_exm]);
|
||||||
|
|
||||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
@@ -59,9 +99,40 @@ void subghz_scene_ext_module_settings_on_enter(void* context) {
|
|||||||
DEBUG_P_COUNT,
|
DEBUG_P_COUNT,
|
||||||
subghz_scene_receiver_config_set_debug_pin,
|
subghz_scene_receiver_config_set_debug_pin,
|
||||||
subghz);
|
subghz);
|
||||||
value_index2 = subghz->txrx->debug_pin_state;
|
value_index_dpin = subghz->txrx->debug_pin_state;
|
||||||
variable_item_set_current_value_index(item, value_index2);
|
variable_item_set_current_value_index(item, value_index_dpin);
|
||||||
variable_item_set_current_value_text(item, debug_pin_text[value_index2]);
|
variable_item_set_current_value_text(item, debug_pin_text[value_index_dpin]);
|
||||||
|
|
||||||
|
item = variable_item_list_add(
|
||||||
|
subghz->variable_item_list,
|
||||||
|
"Counter Mult:",
|
||||||
|
DEBUG_COUNTER_COUNT,
|
||||||
|
subghz_scene_receiver_config_set_debug_counter,
|
||||||
|
subghz);
|
||||||
|
switch(furi_hal_subghz_get_rolling_counter_mult()) {
|
||||||
|
case 1:
|
||||||
|
value_index_cnt = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value_index_cnt = 1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
value_index_cnt = 2;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
value_index_cnt = 3;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
value_index_cnt = 4;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
value_index_cnt = 5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
variable_item_set_current_value_index(item, value_index_cnt);
|
||||||
|
variable_item_set_current_value_text(item, debug_counter_text[value_index_cnt]);
|
||||||
}
|
}
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
|
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
|
||||||
@@ -73,12 +144,12 @@ bool subghz_scene_ext_module_settings_on_event(void* context, SceneManagerEvent
|
|||||||
UNUSED(event);
|
UNUSED(event);
|
||||||
|
|
||||||
// Set selected radio module
|
// Set selected radio module
|
||||||
furi_hal_subghz_set_radio_type(value_index);
|
furi_hal_subghz_set_radio_type(value_index_exm);
|
||||||
|
|
||||||
// Check if module is present, if no -> show error
|
// Check if module is present, if no -> show error
|
||||||
if(!furi_hal_subghz_check_radio()) {
|
if(!furi_hal_subghz_check_radio()) {
|
||||||
value_index = 0;
|
value_index_exm = 0;
|
||||||
furi_hal_subghz_set_radio_type(value_index);
|
furi_hal_subghz_set_radio_type(value_index_exm);
|
||||||
furi_string_set(subghz->error_str, "Please connect\nexternal radio");
|
furi_string_set(subghz->error_str, "Please connect\nexternal radio");
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,6 +204,16 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
|||||||
DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo);
|
DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
case SubGhzCustomEventViewReceiverDeleteItem:
|
||||||
|
subghz->txrx->idx_menu_chosen =
|
||||||
|
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||||
|
|
||||||
|
subghz_history_delete_item(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
|
||||||
|
subghz_view_receiver_delete_element_callback(subghz->subghz_receiver);
|
||||||
|
|
||||||
|
subghz_scene_receiver_update_statusbar(subghz);
|
||||||
|
consumed = true;
|
||||||
|
break;
|
||||||
case SubGhzCustomEventViewReceiverConfig:
|
case SubGhzCustomEventViewReceiverConfig:
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
subghz->txrx->idx_menu_chosen =
|
subghz->txrx->idx_menu_chosen =
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
#include "../helpers/subghz_custom_event.h"
|
#include "../helpers/subghz_custom_event.h"
|
||||||
#include <lib/subghz/protocols/keeloq.h>
|
#include <lib/subghz/protocols/keeloq.h>
|
||||||
#include <lib/subghz/protocols/star_line.h>
|
#include <lib/subghz/protocols/star_line.h>
|
||||||
|
#include <lib/subghz/protocols/alutech_at_4n.h>
|
||||||
|
#include <lib/subghz/protocols/nice_flor_s.h>
|
||||||
|
#include <lib/subghz/protocols/somfy_telis.h>
|
||||||
|
|
||||||
void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) {
|
void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
@@ -233,6 +236,10 @@ void subghz_scene_receiver_info_on_exit(void* context) {
|
|||||||
widget_reset(subghz->widget);
|
widget_reset(subghz->widget);
|
||||||
keeloq_reset_mfname();
|
keeloq_reset_mfname();
|
||||||
keeloq_reset_kl_type();
|
keeloq_reset_kl_type();
|
||||||
|
keeloq_reset_original_btn();
|
||||||
|
alutech_reset_original_btn();
|
||||||
|
nice_flors_reset_original_btn();
|
||||||
|
somfy_telis_reset_original_btn();
|
||||||
star_line_reset_mfname();
|
star_line_reset_mfname();
|
||||||
star_line_reset_kl_type();
|
star_line_reset_kl_type();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#include "../subghz_i.h"
|
#include "../subghz_i.h"
|
||||||
#include <lib/subghz/protocols/keeloq.h>
|
#include <lib/subghz/protocols/keeloq.h>
|
||||||
#include <lib/subghz/protocols/star_line.h>
|
#include <lib/subghz/protocols/star_line.h>
|
||||||
|
#include <lib/subghz/protocols/alutech_at_4n.h>
|
||||||
|
#include <lib/subghz/protocols/nice_flor_s.h>
|
||||||
|
#include <lib/subghz/protocols/somfy_telis.h>
|
||||||
|
|
||||||
#include "xtreme/assets.h"
|
#include "xtreme/assets.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -110,6 +114,10 @@ void subghz_scene_rpc_on_exit(void* context) {
|
|||||||
|
|
||||||
keeloq_reset_mfname();
|
keeloq_reset_mfname();
|
||||||
keeloq_reset_kl_type();
|
keeloq_reset_kl_type();
|
||||||
|
keeloq_reset_original_btn();
|
||||||
|
alutech_reset_original_btn();
|
||||||
|
nice_flors_reset_original_btn();
|
||||||
|
somfy_telis_reset_original_btn();
|
||||||
star_line_reset_mfname();
|
star_line_reset_mfname();
|
||||||
star_line_reset_kl_type();
|
star_line_reset_kl_type();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,10 +79,22 @@ void subghz_scene_set_type_on_enter(void* context) {
|
|||||||
SubmenuIndexFaacSLH_433,
|
SubmenuIndexFaacSLH_433,
|
||||||
subghz_scene_set_type_submenu_callback,
|
subghz_scene_set_type_submenu_callback,
|
||||||
subghz);
|
subghz);
|
||||||
|
submenu_add_item(
|
||||||
|
subghz->submenu,
|
||||||
|
"BFT [Manual] 433MHz",
|
||||||
|
SubmenuIndexBFTClone,
|
||||||
|
subghz_scene_set_type_submenu_callback,
|
||||||
|
subghz);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
subghz->submenu,
|
subghz->submenu,
|
||||||
"BFT Mitto 433MHz",
|
"BFT Mitto 433MHz",
|
||||||
SubmenuIndexBFT,
|
SubmenuIndexBFTMitto,
|
||||||
|
subghz_scene_set_type_submenu_callback,
|
||||||
|
subghz);
|
||||||
|
submenu_add_item(
|
||||||
|
subghz->submenu,
|
||||||
|
"Somfy Telis 433MHz",
|
||||||
|
SubmenuIndexSomfyTelis,
|
||||||
subghz_scene_set_type_submenu_callback,
|
subghz_scene_set_type_submenu_callback,
|
||||||
subghz);
|
subghz);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
@@ -115,6 +127,12 @@ void subghz_scene_set_type_on_enter(void* context) {
|
|||||||
SubmenuIndexNiceFlorS_433_92,
|
SubmenuIndexNiceFlorS_433_92,
|
||||||
subghz_scene_set_type_submenu_callback,
|
subghz_scene_set_type_submenu_callback,
|
||||||
subghz);
|
subghz);
|
||||||
|
submenu_add_item(
|
||||||
|
subghz->submenu,
|
||||||
|
"Nice One 433MHz",
|
||||||
|
SubmenuIndexNiceOne_433_92,
|
||||||
|
subghz_scene_set_type_submenu_callback,
|
||||||
|
subghz);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
subghz->submenu,
|
subghz->submenu,
|
||||||
"CAME 12bit 433MHz",
|
"CAME 12bit 433MHz",
|
||||||
@@ -230,7 +248,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
case SubmenuIndexFaacSLH_433:
|
case SubmenuIndexFaacSLH_433:
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac);
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexBFT:
|
case SubmenuIndexBFTClone:
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixBft);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixBft);
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexPricenton:
|
case SubmenuIndexPricenton:
|
||||||
@@ -306,6 +324,66 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SubmenuIndexBFTMitto:
|
||||||
|
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
||||||
|
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
||||||
|
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
|
||||||
|
if(subghz->txrx->transmitter) {
|
||||||
|
subghz_protocol_keeloq_bft_create_data(
|
||||||
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
|
subghz->txrx->fff_data,
|
||||||
|
key & 0x000FFFFF,
|
||||||
|
0x2,
|
||||||
|
0x0002,
|
||||||
|
key & 0x000FFFFF,
|
||||||
|
"BFT",
|
||||||
|
subghz->txrx->preset);
|
||||||
|
|
||||||
|
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
||||||
|
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
||||||
|
seed_data[sizeof(uint32_t) - i - 1] = ((key & 0x000FFFFF) >> i * 8) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
flipper_format_write_hex(
|
||||||
|
subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t));
|
||||||
|
|
||||||
|
flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "BFT");
|
||||||
|
|
||||||
|
generated_protocol = true;
|
||||||
|
} else {
|
||||||
|
generated_protocol = false;
|
||||||
|
}
|
||||||
|
subghz_transmitter_free(subghz->txrx->transmitter);
|
||||||
|
if(!generated_protocol) {
|
||||||
|
furi_string_set(
|
||||||
|
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||||
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SubmenuIndexSomfyTelis:
|
||||||
|
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
||||||
|
subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME);
|
||||||
|
subghz_preset_init(
|
||||||
|
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
||||||
|
if(subghz->txrx->transmitter) {
|
||||||
|
subghz_protocol_somfy_telis_create_data(
|
||||||
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
|
subghz->txrx->fff_data,
|
||||||
|
key & 0x00FFFFFF,
|
||||||
|
0x2,
|
||||||
|
0x0003,
|
||||||
|
subghz->txrx->preset);
|
||||||
|
generated_protocol = true;
|
||||||
|
} else {
|
||||||
|
generated_protocol = false;
|
||||||
|
}
|
||||||
|
subghz_transmitter_free(subghz->txrx->transmitter);
|
||||||
|
if(!generated_protocol) {
|
||||||
|
furi_string_set(
|
||||||
|
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||||
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SubmenuIndexDoorHan_433_92:
|
case SubmenuIndexDoorHan_433_92:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
||||||
@@ -367,7 +445,33 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
key & 0x0FFFFFFF,
|
key & 0x0FFFFFFF,
|
||||||
0x1,
|
0x1,
|
||||||
0x0003,
|
0x0003,
|
||||||
subghz->txrx->preset);
|
subghz->txrx->preset,
|
||||||
|
false);
|
||||||
|
generated_protocol = true;
|
||||||
|
} else {
|
||||||
|
generated_protocol = false;
|
||||||
|
}
|
||||||
|
subghz_transmitter_free(subghz->txrx->transmitter);
|
||||||
|
if(!generated_protocol) {
|
||||||
|
furi_string_set(
|
||||||
|
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||||
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SubmenuIndexNiceOne_433_92:
|
||||||
|
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
||||||
|
subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME);
|
||||||
|
subghz_preset_init(
|
||||||
|
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
||||||
|
if(subghz->txrx->transmitter) {
|
||||||
|
subghz_protocol_nice_flor_s_create_data(
|
||||||
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
|
subghz->txrx->fff_data,
|
||||||
|
key & 0x0FFFFFFF,
|
||||||
|
0x1,
|
||||||
|
0x0003,
|
||||||
|
subghz->txrx->preset,
|
||||||
|
true);
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
} else {
|
} else {
|
||||||
generated_protocol = false;
|
generated_protocol = false;
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
#include "../views/transmitter.h"
|
#include "../views/transmitter.h"
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
#include <lib/subghz/protocols/keeloq.h>
|
#include <lib/subghz/protocols/keeloq.h>
|
||||||
|
#include <lib/subghz/protocols/alutech_at_4n.h>
|
||||||
#include <lib/subghz/protocols/star_line.h>
|
#include <lib/subghz/protocols/star_line.h>
|
||||||
|
#include <lib/subghz/protocols/nice_flor_s.h>
|
||||||
|
#include <lib/subghz/protocols/somfy_telis.h>
|
||||||
|
|
||||||
void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
|
void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
@@ -89,6 +92,27 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
|
|||||||
subghz_tx_stop(subghz);
|
subghz_tx_stop(subghz);
|
||||||
subghz_sleep(subghz);
|
subghz_sleep(subghz);
|
||||||
}
|
}
|
||||||
|
if(keeloq_get_custom_btn() != 0) {
|
||||||
|
keeloq_set_btn(0);
|
||||||
|
alutech_set_btn(0);
|
||||||
|
nice_flors_set_btn(0);
|
||||||
|
somfy_telis_set_btn(0);
|
||||||
|
uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult();
|
||||||
|
furi_hal_subghz_set_rolling_counter_mult(0);
|
||||||
|
// Calling restore!
|
||||||
|
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
||||||
|
subghz_rx_end(subghz);
|
||||||
|
}
|
||||||
|
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
||||||
|
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||||
|
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||||
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subghz_tx_stop(subghz);
|
||||||
|
subghz_sleep(subghz);
|
||||||
|
furi_hal_subghz_set_rolling_counter_mult(tmp_counter);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if(event.event == SubGhzCustomEventViewTransmitterBack) {
|
} else if(event.event == SubGhzCustomEventViewTransmitterBack) {
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
@@ -113,6 +137,10 @@ void subghz_scene_transmitter_on_exit(void* context) {
|
|||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
keeloq_reset_mfname();
|
keeloq_reset_mfname();
|
||||||
keeloq_reset_kl_type();
|
keeloq_reset_kl_type();
|
||||||
|
keeloq_reset_original_btn();
|
||||||
|
alutech_reset_original_btn();
|
||||||
|
nice_flors_reset_original_btn();
|
||||||
|
somfy_telis_reset_original_btn();
|
||||||
star_line_reset_mfname();
|
star_line_reset_mfname();
|
||||||
star_line_reset_kl_type();
|
star_line_reset_kl_type();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,28 @@ void subghz_history_reset(SubGhzHistory* instance) {
|
|||||||
instance->code_last_hash_data = 0;
|
instance->code_last_hash_data = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id) {
|
||||||
|
furi_assert(instance);
|
||||||
|
|
||||||
|
SubGhzHistoryItemArray_it_t it;
|
||||||
|
//SubGhzHistoryItem* target_item = SubGhzHistoryItemArray_get(instance->history->data, item_id);
|
||||||
|
SubGhzHistoryItemArray_it_last(it, instance->history->data);
|
||||||
|
while(!SubGhzHistoryItemArray_end_p(it)) {
|
||||||
|
SubGhzHistoryItem* item = SubGhzHistoryItemArray_ref(it);
|
||||||
|
|
||||||
|
if(it->index == (size_t)(item_id)) {
|
||||||
|
furi_string_free(item->item_str);
|
||||||
|
furi_string_free(item->preset->name);
|
||||||
|
free(item->preset);
|
||||||
|
flipper_format_free(item->flipper_string);
|
||||||
|
item->type = 0;
|
||||||
|
SubGhzHistoryItemArray_remove(instance->history->data, it);
|
||||||
|
}
|
||||||
|
SubGhzHistoryItemArray_previous(it);
|
||||||
|
}
|
||||||
|
instance->last_index_write--;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t subghz_history_get_item(SubGhzHistory* instance) {
|
uint16_t subghz_history_get_item(SubGhzHistory* instance) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
return instance->last_index_write;
|
return instance->last_index_write;
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ void subghz_history_free(SubGhzHistory* instance);
|
|||||||
*/
|
*/
|
||||||
void subghz_history_reset(SubGhzHistory* instance);
|
void subghz_history_reset(SubGhzHistory* instance);
|
||||||
|
|
||||||
|
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id);
|
||||||
|
|
||||||
/** Get frequency to history[idx]
|
/** Get frequency to history[idx]
|
||||||
*
|
*
|
||||||
* @param instance - SubGhzHistory instance
|
* @param instance - SubGhzHistory instance
|
||||||
|
|||||||
@@ -431,6 +431,34 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
|
|||||||
true);
|
true);
|
||||||
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
|
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
|
||||||
subghz_receiver->callback(SubGhzCustomEventViewReceiverConfig, subghz_receiver->context);
|
subghz_receiver->callback(SubGhzCustomEventViewReceiverConfig, subghz_receiver->context);
|
||||||
|
} else if(event->key == InputKeyRight && event->type == InputTypeLong) {
|
||||||
|
with_view_model(
|
||||||
|
subghz_receiver->view,
|
||||||
|
SubGhzViewReceiverModel * model,
|
||||||
|
{
|
||||||
|
if(model->history_item != 0) {
|
||||||
|
SubGhzReceiverMenuItemArray_it_t it;
|
||||||
|
// SubGhzReceiverMenuItem* target_item =
|
||||||
|
// SubGhzReceiverMenuItemArray_get(model->history->data, model->idx);
|
||||||
|
SubGhzReceiverMenuItemArray_it_last(it, model->history->data);
|
||||||
|
while(!SubGhzReceiverMenuItemArray_end_p(it)) {
|
||||||
|
SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it);
|
||||||
|
|
||||||
|
if(it->index == (size_t)(model->idx)) {
|
||||||
|
furi_string_free(item->item_str);
|
||||||
|
item->type = 0;
|
||||||
|
SubGhzReceiverMenuItemArray_remove(model->history->data, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzReceiverMenuItemArray_previous(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
subghz_receiver->callback(
|
||||||
|
SubGhzCustomEventViewReceiverDeleteItem, subghz_receiver->context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
||||||
with_view_model(
|
with_view_model(
|
||||||
subghz_receiver->view,
|
subghz_receiver->view,
|
||||||
@@ -544,12 +572,34 @@ View* subghz_view_receiver_get_view(SubGhzViewReceiver* subghz_receiver) {
|
|||||||
|
|
||||||
uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver) {
|
uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver) {
|
||||||
furi_assert(subghz_receiver);
|
furi_assert(subghz_receiver);
|
||||||
uint32_t idx = 0;
|
uint16_t idx = 0;
|
||||||
with_view_model(
|
with_view_model(
|
||||||
subghz_receiver->view, SubGhzViewReceiverModel * model, { idx = model->idx; }, false);
|
subghz_receiver->view, SubGhzViewReceiverModel * model, { idx = model->idx; }, false);
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver) {
|
||||||
|
furi_assert(subghz_receiver);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
subghz_receiver->view,
|
||||||
|
SubGhzViewReceiverModel * model,
|
||||||
|
{
|
||||||
|
if(model->history_item == 5) {
|
||||||
|
if(model->idx >= 2) {
|
||||||
|
model->idx = model->history_item - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model->history_item--;
|
||||||
|
|
||||||
|
if(model->idx != 0) {
|
||||||
|
model->idx--;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
furi_delay_ms(200);
|
||||||
|
}
|
||||||
|
|
||||||
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) {
|
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) {
|
||||||
furi_assert(subghz_receiver);
|
furi_assert(subghz_receiver);
|
||||||
with_view_model(
|
with_view_model(
|
||||||
|
|||||||
@@ -46,4 +46,6 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver);
|
|||||||
|
|
||||||
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx);
|
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx);
|
||||||
|
|
||||||
|
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver);
|
||||||
|
|
||||||
void subghz_view_receiver_exit(void* context);
|
void subghz_view_receiver_exit(void* context);
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
|
|
||||||
|
#include <lib/subghz/protocols/keeloq.h>
|
||||||
|
#include <lib/subghz/protocols/alutech_at_4n.h>
|
||||||
|
#include <lib/subghz/protocols/nice_flor_s.h>
|
||||||
|
#include <lib/subghz/protocols/somfy_telis.h>
|
||||||
|
|
||||||
struct SubGhzViewTransmitter {
|
struct SubGhzViewTransmitter {
|
||||||
View* view;
|
View* view;
|
||||||
SubGhzViewTransmitterCallback callback;
|
SubGhzViewTransmitterCallback callback;
|
||||||
@@ -15,6 +20,8 @@ typedef struct {
|
|||||||
FuriString* preset_str;
|
FuriString* preset_str;
|
||||||
FuriString* key_str;
|
FuriString* key_str;
|
||||||
uint8_t show_button;
|
uint8_t show_button;
|
||||||
|
FuriString* temp_button_id;
|
||||||
|
bool draw_temp_button;
|
||||||
} SubGhzViewTransmitterModel;
|
} SubGhzViewTransmitterModel;
|
||||||
|
|
||||||
void subghz_view_transmitter_set_callback(
|
void subghz_view_transmitter_set_callback(
|
||||||
@@ -89,6 +96,12 @@ void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* mo
|
|||||||
canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str));
|
canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str));
|
||||||
canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str));
|
canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str));
|
||||||
|
|
||||||
|
if(model->draw_temp_button) {
|
||||||
|
canvas_set_font(canvas, FontBatteryPercent);
|
||||||
|
canvas_draw_str(canvas, 117, 40, furi_string_get_cstr(model->temp_button_id));
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
}
|
||||||
|
|
||||||
if(model->show_button) {
|
if(model->show_button) {
|
||||||
canvas_draw_str(canvas, 58, 62, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int");
|
canvas_draw_str(canvas, 58, 62, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int");
|
||||||
subghz_view_transmitter_button_right(canvas, "Send");
|
subghz_view_transmitter_button_right(canvas, "Send");
|
||||||
@@ -108,7 +121,9 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
|
|||||||
furi_string_reset(model->frequency_str);
|
furi_string_reset(model->frequency_str);
|
||||||
furi_string_reset(model->preset_str);
|
furi_string_reset(model->preset_str);
|
||||||
furi_string_reset(model->key_str);
|
furi_string_reset(model->key_str);
|
||||||
|
furi_string_reset(model->temp_button_id);
|
||||||
model->show_button = 0;
|
model->show_button = 0;
|
||||||
|
model->draw_temp_button = false;
|
||||||
},
|
},
|
||||||
false);
|
false);
|
||||||
return false;
|
return false;
|
||||||
@@ -125,6 +140,14 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
|
|||||||
true);
|
true);
|
||||||
|
|
||||||
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
|
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
|
||||||
|
with_view_model(
|
||||||
|
subghz_transmitter->view,
|
||||||
|
SubGhzViewTransmitterModel * model,
|
||||||
|
{
|
||||||
|
furi_string_reset(model->temp_button_id);
|
||||||
|
model->draw_temp_button = false;
|
||||||
|
},
|
||||||
|
true);
|
||||||
subghz_transmitter->callback(
|
subghz_transmitter->callback(
|
||||||
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
|
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
|
||||||
return true;
|
return true;
|
||||||
@@ -134,6 +157,141 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temp Buttons (UP)
|
||||||
|
if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) {
|
||||||
|
keeloq_set_btn(1);
|
||||||
|
alutech_set_btn(1);
|
||||||
|
nice_flors_set_btn(1);
|
||||||
|
somfy_telis_set_btn(1);
|
||||||
|
with_view_model(
|
||||||
|
subghz_transmitter->view,
|
||||||
|
SubGhzViewTransmitterModel * model,
|
||||||
|
{
|
||||||
|
furi_string_reset(model->temp_button_id);
|
||||||
|
if(keeloq_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(alutech_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(nice_flors_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(
|
||||||
|
model->temp_button_id, "%01X", nice_flors_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(somfy_telis_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(
|
||||||
|
model->temp_button_id, "%01X", somfy_telis_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
subghz_transmitter->callback(
|
||||||
|
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
|
||||||
|
return true;
|
||||||
|
} else if(can_be_sent && event->key == InputKeyUp && event->type == InputTypeRelease) {
|
||||||
|
subghz_transmitter->callback(
|
||||||
|
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Down
|
||||||
|
if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) {
|
||||||
|
keeloq_set_btn(2);
|
||||||
|
alutech_set_btn(2);
|
||||||
|
nice_flors_set_btn(2);
|
||||||
|
somfy_telis_set_btn(2);
|
||||||
|
with_view_model(
|
||||||
|
subghz_transmitter->view,
|
||||||
|
SubGhzViewTransmitterModel * model,
|
||||||
|
{
|
||||||
|
furi_string_reset(model->temp_button_id);
|
||||||
|
if(keeloq_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(alutech_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(nice_flors_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(
|
||||||
|
model->temp_button_id, "%01X", nice_flors_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(somfy_telis_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(
|
||||||
|
model->temp_button_id, "%01X", somfy_telis_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
subghz_transmitter->callback(
|
||||||
|
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
|
||||||
|
return true;
|
||||||
|
} else if(can_be_sent && event->key == InputKeyDown && event->type == InputTypeRelease) {
|
||||||
|
subghz_transmitter->callback(
|
||||||
|
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Left
|
||||||
|
if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) {
|
||||||
|
keeloq_set_btn(3);
|
||||||
|
alutech_set_btn(3);
|
||||||
|
nice_flors_set_btn(3);
|
||||||
|
somfy_telis_set_btn(3);
|
||||||
|
with_view_model(
|
||||||
|
subghz_transmitter->view,
|
||||||
|
SubGhzViewTransmitterModel * model,
|
||||||
|
{
|
||||||
|
furi_string_reset(model->temp_button_id);
|
||||||
|
if(keeloq_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(alutech_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(nice_flors_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(
|
||||||
|
model->temp_button_id, "%01X", nice_flors_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(somfy_telis_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(
|
||||||
|
model->temp_button_id, "%01X", somfy_telis_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
subghz_transmitter->callback(
|
||||||
|
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
|
||||||
|
return true;
|
||||||
|
} else if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypeRelease) {
|
||||||
|
subghz_transmitter->callback(
|
||||||
|
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Right
|
||||||
|
if(can_be_sent && event->key == InputKeyRight && event->type == InputTypePress) {
|
||||||
|
keeloq_set_btn(4);
|
||||||
|
alutech_set_btn(4);
|
||||||
|
with_view_model(
|
||||||
|
subghz_transmitter->view,
|
||||||
|
SubGhzViewTransmitterModel * model,
|
||||||
|
{
|
||||||
|
furi_string_reset(model->temp_button_id);
|
||||||
|
if(keeloq_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
} else if(alutech_get_original_btn() != 0) {
|
||||||
|
furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn());
|
||||||
|
model->draw_temp_button = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
subghz_transmitter->callback(
|
||||||
|
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
|
||||||
|
return true;
|
||||||
|
} else if(can_be_sent && event->key == InputKeyRight && event->type == InputTypeRelease) {
|
||||||
|
subghz_transmitter->callback(
|
||||||
|
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +324,7 @@ SubGhzViewTransmitter* subghz_view_transmitter_alloc() {
|
|||||||
model->frequency_str = furi_string_alloc();
|
model->frequency_str = furi_string_alloc();
|
||||||
model->preset_str = furi_string_alloc();
|
model->preset_str = furi_string_alloc();
|
||||||
model->key_str = furi_string_alloc();
|
model->key_str = furi_string_alloc();
|
||||||
|
model->temp_button_id = furi_string_alloc();
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
return subghz_transmitter;
|
return subghz_transmitter;
|
||||||
@@ -181,6 +340,7 @@ void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter) {
|
|||||||
furi_string_free(model->frequency_str);
|
furi_string_free(model->frequency_str);
|
||||||
furi_string_free(model->preset_str);
|
furi_string_free(model->preset_str);
|
||||||
furi_string_free(model->key_str);
|
furi_string_free(model->key_str);
|
||||||
|
furi_string_free(model->temp_button_id);
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
view_free(subghz_transmitter->view);
|
view_free(subghz_transmitter->view);
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
#include <lib/subghz/types.h>
|
#include <lib/subghz/types.h>
|
||||||
#include <lib/subghz/protocols/keeloq.h>
|
#include <lib/subghz/protocols/keeloq.h>
|
||||||
#include <lib/subghz/protocols/star_line.h>
|
#include <lib/subghz/protocols/star_line.h>
|
||||||
|
#include <lib/subghz/protocols/alutech_at_4n.h>
|
||||||
|
#include <lib/subghz/protocols/nice_flor_s.h>
|
||||||
|
#include <lib/subghz/protocols/somfy_telis.h>
|
||||||
|
|
||||||
#define UNIRFMAP_FOLDER "/ext/subghz/unirf"
|
#define UNIRFMAP_FOLDER "/ext/subghz/unirf"
|
||||||
#define UNIRFMAP_EXTENSION ".txt"
|
#define UNIRFMAP_EXTENSION ".txt"
|
||||||
@@ -481,6 +484,10 @@ void unirfremix_tx_stop(UniRFRemix* app) {
|
|||||||
|
|
||||||
keeloq_reset_mfname();
|
keeloq_reset_mfname();
|
||||||
keeloq_reset_kl_type();
|
keeloq_reset_kl_type();
|
||||||
|
keeloq_reset_original_btn();
|
||||||
|
alutech_reset_original_btn();
|
||||||
|
nice_flors_reset_original_btn();
|
||||||
|
somfy_telis_reset_original_btn();
|
||||||
star_line_reset_mfname();
|
star_line_reset_mfname();
|
||||||
star_line_reset_kl_type();
|
star_line_reset_kl_type();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ void xtreme_app_scene_misc_on_enter(void* context) {
|
|||||||
variable_item_set_current_value_text(item, xtreme_settings->sort_dirs_first ? "ON" : "OFF");
|
variable_item_set_current_value_text(item, xtreme_settings->sort_dirs_first ? "ON" : "OFF");
|
||||||
|
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
var_item_list, "Dark Mode (Exp.)", 2, xtreme_app_scene_misc_dark_mode_changed, app);
|
var_item_list, "Exp. Dark Mode", 2, xtreme_app_scene_misc_dark_mode_changed, app);
|
||||||
variable_item_set_current_value_index(item, xtreme_settings->dark_mode);
|
variable_item_set_current_value_index(item, xtreme_settings->dark_mode);
|
||||||
variable_item_set_current_value_text(item, xtreme_settings->dark_mode ? "ON" : "OFF");
|
variable_item_set_current_value_text(item, xtreme_settings->dark_mode ? "ON" : "OFF");
|
||||||
|
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ XtremeApp* xtreme_app_alloc() {
|
|||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
|
||||||
app->version_tag = furi_string_alloc_printf(
|
app->version_tag = furi_string_alloc_printf(
|
||||||
"%s %s", version_get_gitbranchnum(NULL), version_get_builddate(NULL));
|
"%s %s", version_get_version(NULL), version_get_builddate(NULL));
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,10 +290,10 @@ static void dice_render_callback(Canvas* const canvas, void* ctx) {
|
|||||||
state->diceQty,
|
state->diceQty,
|
||||||
state->diceType[0],
|
state->diceType[0],
|
||||||
state->rollTime[0]);
|
state->rollTime[0]);
|
||||||
if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect)
|
// if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect)
|
||||||
DOLPHIN_DEED(getRandomDeed());
|
// DOLPHIN_DEED(getRandomDeed());
|
||||||
if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect - 1)
|
// if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect - 1)
|
||||||
DOLPHIN_DEED(getRandomDeed());
|
// DOLPHIN_DEED(getRandomDeed());
|
||||||
if(state->diceQty == 1) {
|
if(state->diceQty == 1) {
|
||||||
snprintf(state->strings[1], sizeof(state->strings[1]), "%d", state->diceRoll);
|
snprintf(state->strings[1], sizeof(state->strings[1]), "%d", state->diceRoll);
|
||||||
} else if(state->diceQty == 2) {
|
} else if(state->diceQty == 2) {
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
## (5V -> VCC) / (GND -> GND) / (13|TX -> Trig) / (14|RX -> Echo)
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
// Ported and modified by @xMasterX
|
// Ported and modified by @xMasterX
|
||||||
|
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
#include <furi_hal_power.h>
|
#include <furi_hal_power.h>
|
||||||
#include <furi_hal_console.h>
|
#include <furi_hal_console.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
@@ -26,7 +27,7 @@ typedef struct {
|
|||||||
NotificationApp* notification;
|
NotificationApp* notification;
|
||||||
bool have_5v;
|
bool have_5v;
|
||||||
bool measurement_made;
|
bool measurement_made;
|
||||||
uint32_t echo; // ms
|
uint32_t echo; // us
|
||||||
float distance; // meters
|
float distance; // meters
|
||||||
} PluginState;
|
} PluginState;
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ static void render_callback(Canvas* const canvas, void* ctx) {
|
|||||||
|
|
||||||
FuriString* str_buf;
|
FuriString* str_buf;
|
||||||
str_buf = furi_string_alloc();
|
str_buf = furi_string_alloc();
|
||||||
furi_string_printf(str_buf, "Echo: %ld ms", plugin_state->echo);
|
furi_string_printf(str_buf, "Echo: %ld us", plugin_state->echo);
|
||||||
|
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(
|
||||||
canvas, 8, 38, AlignLeft, AlignTop, furi_string_get_cstr(str_buf));
|
canvas, 8, 38, AlignLeft, AlignTop, furi_string_get_cstr(str_buf));
|
||||||
@@ -110,9 +111,11 @@ static void hc_sr04_state_init(PluginState* const plugin_state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float hc_sr04_ms_to_m(uint32_t ms) {
|
float hc_sr04_us_to_m(uint32_t us) {
|
||||||
const float speed_sound_m_per_s = 343.0f;
|
//speed of sound for 20°C, 50% relative humidity
|
||||||
const float time_s = ms / 1e3f;
|
//331.3 + 20 * 0.606 + 50 * 0.0124 = 0.034404
|
||||||
|
const float speed_sound_m_per_s = 344.04f;
|
||||||
|
const float time_s = us / 1e6f;
|
||||||
const float total_dist = time_s * speed_sound_m_per_s;
|
const float total_dist = time_s * speed_sound_m_per_s;
|
||||||
return total_dist / 2.0f;
|
return total_dist / 2.0f;
|
||||||
}
|
}
|
||||||
@@ -147,10 +150,6 @@ static void hc_sr04_measure(PluginState* const plugin_state) {
|
|||||||
furi_delay_ms(10);
|
furi_delay_ms(10);
|
||||||
furi_hal_gpio_write(&gpio_usart_tx, false);
|
furi_hal_gpio_write(&gpio_usart_tx, false);
|
||||||
|
|
||||||
// TODO change from furi_get_tick(), which returns ms,
|
|
||||||
// to DWT->CYCCNT, which is a more precise counter with
|
|
||||||
// us precision (see furi_hal_cortex_delay_us)
|
|
||||||
|
|
||||||
const uint32_t start = furi_get_tick();
|
const uint32_t start = furi_get_tick();
|
||||||
|
|
||||||
while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx))
|
while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx))
|
||||||
@@ -158,16 +157,17 @@ static void hc_sr04_measure(PluginState* const plugin_state) {
|
|||||||
while(furi_get_tick() - start < timeout_ms && !furi_hal_gpio_read(&gpio_usart_rx))
|
while(furi_get_tick() - start < timeout_ms && !furi_hal_gpio_read(&gpio_usart_rx))
|
||||||
;
|
;
|
||||||
|
|
||||||
const uint32_t pulse_start = furi_get_tick();
|
const uint32_t pulse_start = DWT->CYCCNT;
|
||||||
|
|
||||||
while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx))
|
while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx))
|
||||||
;
|
;
|
||||||
|
const uint32_t pulse_end = DWT->CYCCNT;
|
||||||
|
|
||||||
const uint32_t pulse_end = furi_get_tick();
|
|
||||||
//FURI_CRITICAL_EXIT();
|
//FURI_CRITICAL_EXIT();
|
||||||
|
|
||||||
plugin_state->echo = pulse_end - pulse_start;
|
plugin_state->echo =
|
||||||
plugin_state->distance = hc_sr04_ms_to_m(pulse_end - pulse_start);
|
(pulse_end - pulse_start) / furi_hal_cortex_instructions_per_microsecond();
|
||||||
|
plugin_state->distance = hc_sr04_us_to_m(plugin_state->echo);
|
||||||
plugin_state->measurement_made = true;
|
plugin_state->measurement_made = true;
|
||||||
|
|
||||||
//furi_hal_light_set(LightRed, 0x00);
|
//furi_hal_light_set(LightRed, 0x00);
|
||||||
|
|||||||
@@ -1,191 +0,0 @@
|
|||||||
---
|
|
||||||
Language: Cpp
|
|
||||||
AccessModifierOffset: -4
|
|
||||||
AlignAfterOpenBracket: AlwaysBreak
|
|
||||||
AlignArrayOfStructures: None
|
|
||||||
AlignConsecutiveMacros: None
|
|
||||||
AlignConsecutiveAssignments: None
|
|
||||||
AlignConsecutiveBitFields: None
|
|
||||||
AlignConsecutiveDeclarations: None
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
AlignOperands: Align
|
|
||||||
AlignTrailingComments: false
|
|
||||||
AllowAllArgumentsOnNextLine: true
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
|
||||||
AllowShortEnumsOnASingleLine: true
|
|
||||||
AllowShortBlocksOnASingleLine: Never
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AllowShortFunctionsOnASingleLine: None
|
|
||||||
AllowShortLambdasOnASingleLine: All
|
|
||||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
|
||||||
AllowShortLoopsOnASingleLine: true
|
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
|
||||||
AttributeMacros:
|
|
||||||
- __capability
|
|
||||||
BinPackArguments: false
|
|
||||||
BinPackParameters: false
|
|
||||||
BraceWrapping:
|
|
||||||
AfterCaseLabel: false
|
|
||||||
AfterClass: false
|
|
||||||
AfterControlStatement: Never
|
|
||||||
AfterEnum: false
|
|
||||||
AfterFunction: false
|
|
||||||
AfterNamespace: false
|
|
||||||
AfterObjCDeclaration: false
|
|
||||||
AfterStruct: false
|
|
||||||
AfterUnion: false
|
|
||||||
AfterExternBlock: false
|
|
||||||
BeforeCatch: false
|
|
||||||
BeforeElse: false
|
|
||||||
BeforeLambdaBody: false
|
|
||||||
BeforeWhile: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: true
|
|
||||||
SplitEmptyRecord: true
|
|
||||||
SplitEmptyNamespace: true
|
|
||||||
BreakBeforeBinaryOperators: None
|
|
||||||
BreakBeforeConceptDeclarations: true
|
|
||||||
BreakBeforeBraces: Attach
|
|
||||||
BreakBeforeInheritanceComma: false
|
|
||||||
BreakInheritanceList: BeforeColon
|
|
||||||
BreakBeforeTernaryOperators: false
|
|
||||||
BreakConstructorInitializersBeforeComma: false
|
|
||||||
BreakConstructorInitializers: BeforeComma
|
|
||||||
BreakAfterJavaFieldAnnotations: false
|
|
||||||
BreakStringLiterals: false
|
|
||||||
ColumnLimit: 99
|
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
|
||||||
QualifierAlignment: Leave
|
|
||||||
CompactNamespaces: false
|
|
||||||
ConstructorInitializerIndentWidth: 4
|
|
||||||
ContinuationIndentWidth: 4
|
|
||||||
Cpp11BracedListStyle: true
|
|
||||||
DeriveLineEnding: true
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
DisableFormat: false
|
|
||||||
EmptyLineAfterAccessModifier: Never
|
|
||||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
|
||||||
ExperimentalAutoDetectBinPacking: false
|
|
||||||
PackConstructorInitializers: BinPack
|
|
||||||
BasedOnStyle: ''
|
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
|
||||||
AllowAllConstructorInitializersOnNextLine: true
|
|
||||||
FixNamespaceComments: false
|
|
||||||
ForEachMacros:
|
|
||||||
- foreach
|
|
||||||
- Q_FOREACH
|
|
||||||
- BOOST_FOREACH
|
|
||||||
IfMacros:
|
|
||||||
- KJ_IF_MAYBE
|
|
||||||
IncludeBlocks: Preserve
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '.*'
|
|
||||||
Priority: 1
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
|
||||||
Priority: 3
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
- Regex: '.*'
|
|
||||||
Priority: 1
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
IncludeIsMainRegex: '(Test)?$'
|
|
||||||
IncludeIsMainSourceRegex: ''
|
|
||||||
IndentAccessModifiers: false
|
|
||||||
IndentCaseLabels: false
|
|
||||||
IndentCaseBlocks: false
|
|
||||||
IndentGotoLabels: true
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentExternBlock: AfterExternBlock
|
|
||||||
IndentRequires: false
|
|
||||||
IndentWidth: 4
|
|
||||||
IndentWrappedFunctionNames: true
|
|
||||||
InsertTrailingCommas: None
|
|
||||||
JavaScriptQuotes: Leave
|
|
||||||
JavaScriptWrapImports: true
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
|
||||||
LambdaBodyIndentation: Signature
|
|
||||||
MacroBlockBegin: ''
|
|
||||||
MacroBlockEnd: ''
|
|
||||||
MaxEmptyLinesToKeep: 1
|
|
||||||
NamespaceIndentation: None
|
|
||||||
ObjCBinPackProtocolList: Auto
|
|
||||||
ObjCBlockIndentWidth: 4
|
|
||||||
ObjCBreakBeforeNestedBlockParam: true
|
|
||||||
ObjCSpaceAfterProperty: true
|
|
||||||
ObjCSpaceBeforeProtocolList: true
|
|
||||||
PenaltyBreakAssignment: 10
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 30
|
|
||||||
PenaltyBreakComment: 10
|
|
||||||
PenaltyBreakFirstLessLess: 0
|
|
||||||
PenaltyBreakOpenParenthesis: 0
|
|
||||||
PenaltyBreakString: 10
|
|
||||||
PenaltyBreakTemplateDeclaration: 10
|
|
||||||
PenaltyExcessCharacter: 100
|
|
||||||
PenaltyReturnTypeOnItsOwnLine: 60
|
|
||||||
PenaltyIndentedWhitespace: 0
|
|
||||||
PointerAlignment: Left
|
|
||||||
PPIndentWidth: -1
|
|
||||||
ReferenceAlignment: Pointer
|
|
||||||
ReflowComments: false
|
|
||||||
RemoveBracesLLVM: false
|
|
||||||
SeparateDefinitionBlocks: Leave
|
|
||||||
ShortNamespaceLines: 1
|
|
||||||
SortIncludes: Never
|
|
||||||
SortJavaStaticImport: Before
|
|
||||||
SortUsingDeclarations: false
|
|
||||||
SpaceAfterCStyleCast: false
|
|
||||||
SpaceAfterLogicalNot: false
|
|
||||||
SpaceAfterTemplateKeyword: true
|
|
||||||
SpaceBeforeAssignmentOperators: true
|
|
||||||
SpaceBeforeCaseColon: false
|
|
||||||
SpaceBeforeCpp11BracedList: false
|
|
||||||
SpaceBeforeCtorInitializerColon: true
|
|
||||||
SpaceBeforeInheritanceColon: true
|
|
||||||
SpaceBeforeParens: Never
|
|
||||||
SpaceBeforeParensOptions:
|
|
||||||
AfterControlStatements: false
|
|
||||||
AfterForeachMacros: false
|
|
||||||
AfterFunctionDefinitionName: false
|
|
||||||
AfterFunctionDeclarationName: false
|
|
||||||
AfterIfMacros: false
|
|
||||||
AfterOverloadedOperator: false
|
|
||||||
BeforeNonEmptyParentheses: false
|
|
||||||
SpaceAroundPointerQualifiers: Default
|
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
|
||||||
SpaceInEmptyBlock: false
|
|
||||||
SpaceInEmptyParentheses: false
|
|
||||||
SpacesBeforeTrailingComments: 1
|
|
||||||
SpacesInAngles: Never
|
|
||||||
SpacesInConditionalStatement: false
|
|
||||||
SpacesInContainerLiterals: false
|
|
||||||
SpacesInCStyleCastParentheses: false
|
|
||||||
SpacesInLineCommentPrefix:
|
|
||||||
Minimum: 1
|
|
||||||
Maximum: -1
|
|
||||||
SpacesInParentheses: false
|
|
||||||
SpacesInSquareBrackets: false
|
|
||||||
SpaceBeforeSquareBrackets: false
|
|
||||||
BitFieldColonSpacing: Both
|
|
||||||
Standard: c++03
|
|
||||||
StatementAttributeLikeMacros:
|
|
||||||
- Q_EMIT
|
|
||||||
StatementMacros:
|
|
||||||
- Q_UNUSED
|
|
||||||
- QT_REQUIRE_VERSION
|
|
||||||
TabWidth: 4
|
|
||||||
UseCRLF: false
|
|
||||||
UseTab: Never
|
|
||||||
WhitespaceSensitiveMacros:
|
|
||||||
- STRINGIZE
|
|
||||||
- PP_STRINGIZE
|
|
||||||
- BOOST_PP_STRINGIZE
|
|
||||||
- NS_SWIFT_NAME
|
|
||||||
- CF_SWIFT_NAME
|
|
||||||
...
|
|
||||||
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
# flipperzero-lightmeter
|
# flipperzero-lightmeter
|
||||||
|
|
||||||
[](https://github.com/oleksiikutuzov/flipperzero-lightmeter/actions/workflows/build.yml)
|
[Original link](https://github.com/oleksiikutuzov/flipperzero-lightmeter)
|
||||||
|
|
||||||
|
|
||||||
<img src="images/framed_gui_main.png" width="500px">
|
<img src="images/framed_gui_main.png" width="500px">
|
||||||
|
|
||||||
<img src="images/framed_gui_lux_meter.png" width="500px">
|
|
||||||
|
|
||||||
## Wiring
|
## Wiring
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -15,19 +14,6 @@ SCL -> C0
|
|||||||
SDA -> C1
|
SDA -> C1
|
||||||
```
|
```
|
||||||
|
|
||||||
## Sensor module
|
|
||||||
|
|
||||||
<img src="module/back.jpg" width="500px">
|
|
||||||
|
|
||||||
### If you want to build this module, you'll need (it's quite over-engineered, sorry :D)
|
|
||||||
1. [Module PCB](https://github.com/oleksiikutuzov/flipperzero-lightmeter/blob/main/module/module_v2_gerber.zip)
|
|
||||||
2. [Enclosure](https://github.com/oleksiikutuzov/flipperzero-lightmeter/blob/main/module/module_v2_enclosure.stl)
|
|
||||||
3. 4-pin female header
|
|
||||||
4. 10-pin male header
|
|
||||||
5. 2x M3 threaded inserts (max diameter 5.3 mm, max height 4 mm)
|
|
||||||
6. 2x M3x5 screws
|
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- [ ] Save settings to sd card
|
- [ ] Save settings to sd card
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ App(
|
|||||||
],
|
],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
order=90,
|
order=90,
|
||||||
fap_version=(0, 7),
|
|
||||||
fap_icon="lightmeter.png",
|
fap_icon="lightmeter.png",
|
||||||
fap_category="GPIO",
|
fap_category="GPIO",
|
||||||
fap_private_libs=[
|
fap_private_libs=[
|
||||||
@@ -22,7 +21,4 @@ App(
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
fap_icon_assets="icons",
|
fap_icon_assets="icons",
|
||||||
fap_description="Lightmeter app for photography based on BH1750 sensor",
|
|
||||||
fap_author="Oleksii Kutuzov",
|
|
||||||
fap_weburl="https://github.com/oleksiikutuzov/flipperzero-lightmeter",
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -62,11 +62,11 @@ const float aperture_numbers[] = {
|
|||||||
const float speed_numbers[] = {
|
const float speed_numbers[] = {
|
||||||
[SPEED_8000] = 1.0 / 8000, [SPEED_4000] = 1.0 / 4000, [SPEED_2000] = 1.0 / 2000,
|
[SPEED_8000] = 1.0 / 8000, [SPEED_4000] = 1.0 / 4000, [SPEED_2000] = 1.0 / 2000,
|
||||||
[SPEED_1000] = 1.0 / 1000, [SPEED_500] = 1.0 / 500, [SPEED_250] = 1.0 / 250,
|
[SPEED_1000] = 1.0 / 1000, [SPEED_500] = 1.0 / 500, [SPEED_250] = 1.0 / 250,
|
||||||
[SPEED_125] = 1.0 / 125, [SPEED_60] = 1.0 / 60, [SPEED_30] = 1.0 / 30,
|
[SPEED_125] = 1.0 / 125, [SPEED_60] = 1.0 / 60, [SPEED_48] = 1.0 / 48,
|
||||||
[SPEED_15] = 1.0 / 15, [SPEED_8] = 1.0 / 8, [SPEED_4] = 1.0 / 4,
|
[SPEED_30] = 1.0 / 30, [SPEED_15] = 1.0 / 15, [SPEED_8] = 1.0 / 8,
|
||||||
[SPEED_2] = 1.0 / 2, [SPEED_1S] = 1.0, [SPEED_2S] = 2.0,
|
[SPEED_4] = 1.0 / 4, [SPEED_2] = 1.0 / 2, [SPEED_1S] = 1.0,
|
||||||
[SPEED_4S] = 4.0, [SPEED_8S] = 8.0, [SPEED_15S] = 15.0,
|
[SPEED_2S] = 2.0, [SPEED_4S] = 4.0, [SPEED_8S] = 8.0,
|
||||||
[SPEED_30S] = 30.0,
|
[SPEED_15S] = 15.0, [SPEED_30S] = 30.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MainView {
|
struct MainView {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
BH1750_mode bh1750_mode = BH1750_DEFAULT_MODE; // Current sensor mode
|
BH1750_mode bh1750_mode = BH1750_DEFAULT_MODE; // Current sensor mode
|
||||||
uint8_t bh1750_mt_reg = BH1750_DEFAULT_MTREG; // Current MT register value
|
uint8_t bh1750_mt_reg = BH1750_DEFAULT_MTREG; // Current MT register value
|
||||||
|
uint8_t bh1750_addr = BH1750_ADDRESS;
|
||||||
|
|
||||||
BH1750_STATUS bh1750_init() {
|
BH1750_STATUS bh1750_init() {
|
||||||
if(BH1750_OK == bh1750_reset()) {
|
if(BH1750_OK == bh1750_reset()) {
|
||||||
@@ -25,12 +26,17 @@ BH1750_STATUS bh1750_init() {
|
|||||||
return BH1750_ERROR;
|
return BH1750_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BH1750_STATUS bh1750_init_with_addr(uint8_t addr) {
|
||||||
|
bh1750_addr = (addr << 1);
|
||||||
|
return bh1750_init();
|
||||||
|
}
|
||||||
|
|
||||||
BH1750_STATUS bh1750_reset() {
|
BH1750_STATUS bh1750_reset() {
|
||||||
uint8_t command = 0x07;
|
uint8_t command = 0x07;
|
||||||
bool status;
|
bool status;
|
||||||
|
|
||||||
furi_hal_i2c_acquire(I2C_BUS);
|
furi_hal_i2c_acquire(I2C_BUS);
|
||||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &command, 1, I2C_TIMEOUT);
|
status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &command, 1, I2C_TIMEOUT);
|
||||||
furi_hal_i2c_release(I2C_BUS);
|
furi_hal_i2c_release(I2C_BUS);
|
||||||
|
|
||||||
if(status) {
|
if(status) {
|
||||||
@@ -45,7 +51,7 @@ BH1750_STATUS bh1750_set_power_state(uint8_t PowerOn) {
|
|||||||
bool status;
|
bool status;
|
||||||
|
|
||||||
furi_hal_i2c_acquire(I2C_BUS);
|
furi_hal_i2c_acquire(I2C_BUS);
|
||||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &PowerOn, 1, I2C_TIMEOUT);
|
status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &PowerOn, 1, I2C_TIMEOUT);
|
||||||
furi_hal_i2c_release(I2C_BUS);
|
furi_hal_i2c_release(I2C_BUS);
|
||||||
|
|
||||||
if(status) {
|
if(status) {
|
||||||
@@ -69,7 +75,7 @@ BH1750_STATUS bh1750_set_mode(BH1750_mode mode) {
|
|||||||
bh1750_mode = mode;
|
bh1750_mode = mode;
|
||||||
|
|
||||||
furi_hal_i2c_acquire(I2C_BUS);
|
furi_hal_i2c_acquire(I2C_BUS);
|
||||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &mode, 1, I2C_TIMEOUT);
|
status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &mode, 1, I2C_TIMEOUT);
|
||||||
furi_hal_i2c_release(I2C_BUS);
|
furi_hal_i2c_release(I2C_BUS);
|
||||||
|
|
||||||
if(status) {
|
if(status) {
|
||||||
@@ -93,14 +99,14 @@ BH1750_STATUS bh1750_set_mt_reg(uint8_t mt_reg) {
|
|||||||
tmp[1] = (0x60 | (mt_reg & 0x1F));
|
tmp[1] = (0x60 | (mt_reg & 0x1F));
|
||||||
|
|
||||||
furi_hal_i2c_acquire(I2C_BUS);
|
furi_hal_i2c_acquire(I2C_BUS);
|
||||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &tmp[0], 1, I2C_TIMEOUT);
|
status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &tmp[0], 1, I2C_TIMEOUT);
|
||||||
furi_hal_i2c_release(I2C_BUS);
|
furi_hal_i2c_release(I2C_BUS);
|
||||||
if(!status) {
|
if(!status) {
|
||||||
return BH1750_ERROR;
|
return BH1750_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_hal_i2c_acquire(I2C_BUS);
|
furi_hal_i2c_acquire(I2C_BUS);
|
||||||
status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &tmp[1], 1, I2C_TIMEOUT);
|
status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &tmp[1], 1, I2C_TIMEOUT);
|
||||||
furi_hal_i2c_release(I2C_BUS);
|
furi_hal_i2c_release(I2C_BUS);
|
||||||
if(status) {
|
if(status) {
|
||||||
return BH1750_OK;
|
return BH1750_OK;
|
||||||
@@ -122,7 +128,7 @@ BH1750_STATUS bh1750_read_light(float* result) {
|
|||||||
bool status;
|
bool status;
|
||||||
|
|
||||||
furi_hal_i2c_acquire(I2C_BUS);
|
furi_hal_i2c_acquire(I2C_BUS);
|
||||||
status = furi_hal_i2c_rx(I2C_BUS, BH1750_ADDRESS, rcv, 2, I2C_TIMEOUT);
|
status = furi_hal_i2c_rx(I2C_BUS, bh1750_addr, rcv, 2, I2C_TIMEOUT);
|
||||||
furi_hal_i2c_release(I2C_BUS);
|
furi_hal_i2c_release(I2C_BUS);
|
||||||
|
|
||||||
if(status) {
|
if(status) {
|
||||||
|
|||||||
@@ -49,6 +49,13 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
BH1750_STATUS bh1750_init();
|
BH1750_STATUS bh1750_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Change the I2C device address and then initialize the sensor.
|
||||||
|
*
|
||||||
|
* @return BH1750_STATUS
|
||||||
|
*/
|
||||||
|
BH1750_STATUS bh1750_init_with_addr(uint8_t addr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reset all registers to the default value.
|
* @brief Reset all registers to the default value.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ typedef enum {
|
|||||||
SPEED_250,
|
SPEED_250,
|
||||||
SPEED_125,
|
SPEED_125,
|
||||||
SPEED_60,
|
SPEED_60,
|
||||||
|
SPEED_48,
|
||||||
SPEED_30,
|
SPEED_30,
|
||||||
SPEED_15,
|
SPEED_15,
|
||||||
SPEED_8,
|
SPEED_8,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 2.1 MiB |
@@ -1,5 +1,7 @@
|
|||||||
# Metronome
|
# Metronome
|
||||||
|
|
||||||
|
[Original link](https://github.com/panki27/Metronome)
|
||||||
|
|
||||||
A metronome for the [Flipper Zero](https://flipperzero.one/) device. Goes along perfectly with my [BPM tapper](https://github.com/panki27/bpm-tapper).
|
A metronome for the [Flipper Zero](https://flipperzero.one/) device. Goes along perfectly with my [BPM tapper](https://github.com/panki27/bpm-tapper).
|
||||||
|
|
||||||

|

|
||||||
@@ -17,5 +19,5 @@ A metronome for the [Flipper Zero](https://flipperzero.one/) device. Goes along
|
|||||||
## Compiling
|
## Compiling
|
||||||
|
|
||||||
```
|
```
|
||||||
./fbt fap_metronome
|
./fbt firmware_metronome
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ App(
|
|||||||
"gui",
|
"gui",
|
||||||
],
|
],
|
||||||
fap_icon="metronome_icon.png",
|
fap_icon="metronome_icon.png",
|
||||||
fap_icon_assets="icons",
|
|
||||||
fap_category="Music",
|
fap_category="Music",
|
||||||
|
fap_icon_assets="images",
|
||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
order=20,
|
order=20,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <gui/canvas.h>
|
#include <gui/canvas.h>
|
||||||
#include <gui/icon_i.h>
|
#include <gui/icon_i.h>
|
||||||
#include "Metronome_icons.h"
|
#include <Metronome_icons.h>
|
||||||
|
|
||||||
//lib can only do bottom left/right
|
//lib can only do bottom left/right
|
||||||
void elements_button_top_left(Canvas* canvas, const char* str) {
|
void elements_button_top_left(Canvas* canvas, const char* str) {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 102 B After Width: | Height: | Size: 102 B |
@@ -287,7 +287,6 @@ int32_t metronome_app() {
|
|||||||
metronome_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, &state_mutex);
|
metronome_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, &state_mutex);
|
||||||
|
|
||||||
// Open GUI and register view_port
|
// Open GUI and register view_port
|
||||||
//
|
|
||||||
Gui* gui = furi_record_open("gui");
|
Gui* gui = furi_record_open("gui");
|
||||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||||
|
|
||||||
@@ -326,7 +325,7 @@ int32_t metronome_app() {
|
|||||||
case InputKeyBack:
|
case InputKeyBack:
|
||||||
processing = false;
|
processing = false;
|
||||||
break;
|
break;
|
||||||
case InputKeyMAX:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(event.input.type == InputTypeLong) {
|
} else if(event.input.type == InputTypeLong) {
|
||||||
@@ -348,7 +347,7 @@ int32_t metronome_app() {
|
|||||||
case InputKeyBack:
|
case InputKeyBack:
|
||||||
processing = false;
|
processing = false;
|
||||||
break;
|
break;
|
||||||
case InputKeyMAX:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(event.input.type == InputTypeRepeat) {
|
} else if(event.input.type == InputTypeRepeat) {
|
||||||
@@ -369,7 +368,7 @@ int32_t metronome_app() {
|
|||||||
case InputKeyBack:
|
case InputKeyBack:
|
||||||
processing = false;
|
processing = false;
|
||||||
break;
|
break;
|
||||||
case InputKeyMAX:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
# flipperzero-nrf24
|
|
||||||
|
|
||||||
An [NRF24](https://www.sparkfun.com/datasheets/Components/SMD/nRF24L01Pluss_Preliminary_Product_Specification_v1_0.pdf) driver for the [Flipper Zero](https://flipperzero.one/) device. The NRF24 is a popular line of 2.4GHz radio transceivers from Nordic Semiconductors. This library is not currently complete, but functional.
|
|
||||||
|
|
||||||
## Warning
|
|
||||||
This repo contains two Flipper Zero apps that utilize the NRF24 driver to sniff for NRF24 addresses and perform mousejack attacks. These apps are for **educational purposes** only. Please use this code responsibly and only use these apps on your own equipment.
|
|
||||||
|
|
||||||
## Acknowledgments
|
|
||||||
The NRF24 sniffing technique was discovered and shared by Travis Goodspeed in [his blog](http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html).
|
|
||||||
|
|
||||||
The mousejack vulnerabilities were discovered and reported by Marc Newlin, see [the blog](https://www.bastille.net/research/vulnerabilities/mousejack/technical-details) for technical details.
|
|
||||||
|
|
||||||
Much of the driver code was inspired by [RadioHead's Arduino library](https://www.airspayce.com/mikem/arduino/RadioHead/classRH__NRF24.html).
|
|
||||||
Much of the mousejack code was inspired by the [Jackit project](https://github.com/insecurityofthings/jackit).
|
|
||||||
|
|
||||||
|
|
||||||
## PinOut from from NoComp/Frog
|
|
||||||
<img src="https://media.discordapp.net/attachments/937479784726949900/994495234618687509/unknown.png?width=567&height=634">
|
|
||||||
|
|
||||||
# Mousejack / NRF24 pinout by UberGuidoZ
|
|
||||||
2/A7 on FZ goes to MOSI/6 on nrf24l01<br>
|
|
||||||
3/A6 on FZ goes to MISO/7 on nrf24l01<br>
|
|
||||||
4/A4 on FZ goes to CSN/4 on nrf24l01<br>
|
|
||||||
5/B3 on FZ goes to SCK/5 on nrf24l01<br>
|
|
||||||
6/B2 on FZ goes to CE/3 on nrf24l01<br>
|
|
||||||
8/GND on FZ goes to GND/1 on nrf24l01<br>
|
|
||||||
9/3V3 on FZ goes to VCC/2 on nrf24l01<br>
|
|
||||||
IRQ/8 is left disconnected on nrf24l01
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
If the nRF module is acting a bit flakey, try adding a capacitor to the vcc/gnd lines! I've not tried the Plus model so it may have a bigger need for a cap. Otherwise, I haven't had any major issues. Anything from a 3.3 uF to 10 uF should do. (Watch your positive/negative placement! Negative to ground.) I learned if you wanna get fancy, include a 0.1 uF cap in parallel. The 3.3 uF to 10 uF will respond to slow freq changes while the 0.1 uF will respond to the high freq switching spikes that the larger one cannot. That said, a single 10 uF will likely suffice for the Mousejack attack. ¯\\\_(ツ)_/¯
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Selfmade NRF24 breakoutboard:
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
## Practical hints from einstein2150
|
|
||||||
If you are not successfull with the NRF Sniff Plugin you can try to get the MAC of the device with the crazyradio pa USB dongle. Have a look here: https://github.com/SySS-Research/nrf24-playset
|
|
||||||
|
|
||||||
|
|
||||||
A sample output of the NRF-Research script could be like
|
|
||||||
```
|
|
||||||
[2022-08-05 13:28:56.366] Found nRF24 device with address 38:24:93:C0:07 on channel 75\
|
|
||||||
[2022-08-05 13:28:56.371] Checking communication\
|
|
||||||
[2022-08-05 13:28:59.088] Scan for nRF24 device\
|
|
||||||
[2022-08-05 13:28:59.097] Actively searching for address 07:C0:93:24:38\
|
|
||||||
```
|
|
||||||
|
|
||||||
Be carefull with the byte-order using in mousejacker! The correct byte order is the reverse-byteorder. In my example the reversed one is ```07:C0:93:24:38``` for my Logitech R400 presenter.
|
|
||||||
The next thing which could make trouble is the datarate. In my case the Logitech-device is only responding at 2Mbit. Commands at 1Mbit are not detected.
|
|
||||||
|
|
||||||
Now its time to write all the relevant information in the config file. In my case you are creating a file ```addresses.txt``` in the SD directory of ```/nrfsniff```. The file content corresponding to the results of the research is ```07C0932438,2``` representing the reversed byte order of the MAC and the comma-separated datarate.
|
|
||||||
|
|
||||||
Start the Mouse Jacker plugin and select the prepared ```addresses.txt```. If everything is alright you are starting with your MAC ready for attack:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
If you have troube you can check if a datarate of 1 Mbit will help. Change ```07C0932438,2``` to ```07C0932438,1``` in this case. Another problem in the practical use is electromagnetical noise. In my case the external USB-3.1-Hub creating massive noise in the 2,4 Ghz-Frequency around a distance of 5 cm. Try using a long USB connection-cable for the receiver. In my case the response of the attack raises significant because the signals of the NRF-breakoutboard is no more covered with noise.
|
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ App(
|
|||||||
"dialogs",
|
"dialogs",
|
||||||
],
|
],
|
||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
order=50,
|
order=60,
|
||||||
fap_icon="mouse_10px.png",
|
fap_icon="mouse_10px.png",
|
||||||
fap_category="GPIO",
|
fap_category="GPIO",
|
||||||
fap_icon_assets="images",
|
fap_icon_assets="images",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 576 B |
|
Before Width: | Height: | Size: 299 B |
@@ -184,7 +184,7 @@ static bool process_ducky_file(
|
|||||||
mj_process_ducky_script(
|
mj_process_ducky_script(
|
||||||
nrf24_HANDLE, addr, addr_size, rate, (char*)file_buf, plugin_state);
|
nrf24_HANDLE, addr, addr_size, rate, (char*)file_buf, plugin_state);
|
||||||
FURI_LOG_D(TAG, "finished execution");
|
FURI_LOG_D(TAG, "finished execution");
|
||||||
DOLPHIN_DEED(getRandomDeed());
|
// DOLPHIN_DEED(getRandomDeed());
|
||||||
loaded = true;
|
loaded = true;
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_D(TAG, "load failed. file size: %d", file_size);
|
FURI_LOG_D(TAG, "load failed. file size: %d", file_size);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
static const char ducky_cmd_comment[] = {"REM"};
|
static const char ducky_cmd_comment[] = {"REM"};
|
||||||
static const char ducky_cmd_delay[] = {"DELAY "};
|
static const char ducky_cmd_delay[] = {"DELAY "};
|
||||||
static const char ducky_cmd_string[] = {"STRING "};
|
static const char ducky_cmd_string[] = {"STRING "};
|
||||||
|
static const char ducky_cmd_altstring[] = {"ALTSTRING "};
|
||||||
static const char ducky_cmd_repeat[] = {"REPEAT "};
|
static const char ducky_cmd_repeat[] = {"REPEAT "};
|
||||||
|
|
||||||
static uint8_t LOGITECH_HID_TEMPLATE[] =
|
static uint8_t LOGITECH_HID_TEMPLATE[] =
|
||||||
@@ -11,6 +12,10 @@ static uint8_t LOGITECH_HELLO[] = {0x00, 0x4F, 0x00, 0x04, 0xB0, 0x10, 0x00, 0x0
|
|||||||
static uint8_t LOGITECH_KEEPALIVE[] = {0x00, 0x40, 0x00, 0x55, 0x6B};
|
static uint8_t LOGITECH_KEEPALIVE[] = {0x00, 0x40, 0x00, 0x55, 0x6B};
|
||||||
|
|
||||||
uint8_t prev_hid = 0;
|
uint8_t prev_hid = 0;
|
||||||
|
static bool holding_ctrl = false;
|
||||||
|
static bool holding_shift = false;
|
||||||
|
static bool holding_alt = false;
|
||||||
|
static bool holding_gui = false;
|
||||||
|
|
||||||
#define RT_THRESHOLD 50
|
#define RT_THRESHOLD 50
|
||||||
#define LOGITECH_MIN_CHANNEL 2
|
#define LOGITECH_MIN_CHANNEL 2
|
||||||
@@ -65,7 +70,10 @@ MJDuckyKey mj_ducky_keys[] = {{" ", 44, 0}, {"!", 30, 2}, {"\""
|
|||||||
{"LEFTARROW", 80, 0}, {"RIGHTARROW", 79, 0}, {"PAGEDOWN", 78, 0},
|
{"LEFTARROW", 80, 0}, {"RIGHTARROW", 79, 0}, {"PAGEDOWN", 78, 0},
|
||||||
{"PAUSE", 72, 0}, {"SPACE", 44, 0}, {"UPARROW", 82, 0},
|
{"PAUSE", 72, 0}, {"SPACE", 44, 0}, {"UPARROW", 82, 0},
|
||||||
{"F11", 68, 0}, {"F7", 64, 0}, {"UP", 82, 0},
|
{"F11", 68, 0}, {"F7", 64, 0}, {"UP", 82, 0},
|
||||||
{"LEFT", 80, 0}};
|
{"LEFT", 80, 0}, {"NUM 1", 89, 0}, {"NUM 2", 90, 0},
|
||||||
|
{"NUM 3", 91, 0}, {"NUM 4", 92, 0}, {"NUM 5", 93, 0},
|
||||||
|
{"NUM 6", 94, 0}, {"NUM 7", 95, 0}, {"NUM 8", 96, 0},
|
||||||
|
{"NUM 9", 97, 0}, {"NUM 0", 98, 0}};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static bool mj_ducky_get_number(const char* param, uint32_t* val) {
|
static bool mj_ducky_get_number(const char* param, uint32_t* val) {
|
||||||
@@ -89,7 +97,8 @@ static uint32_t mj_ducky_get_command_len(const char* line) {
|
|||||||
static bool mj_get_ducky_key(char* key, size_t keylen, MJDuckyKey* dk) {
|
static bool mj_get_ducky_key(char* key, size_t keylen, MJDuckyKey* dk) {
|
||||||
//FURI_LOG_D(TAG, "looking up key %s with length %d", key, keylen);
|
//FURI_LOG_D(TAG, "looking up key %s with length %d", key, keylen);
|
||||||
for(uint i = 0; i < sizeof(mj_ducky_keys) / sizeof(MJDuckyKey); i++) {
|
for(uint i = 0; i < sizeof(mj_ducky_keys) / sizeof(MJDuckyKey); i++) {
|
||||||
if(!strncmp(mj_ducky_keys[i].name, key, keylen)) {
|
if(strlen(mj_ducky_keys[i].name) == keylen &&
|
||||||
|
!strncmp(mj_ducky_keys[i].name, key, keylen)) {
|
||||||
memcpy(dk, &mj_ducky_keys[i], sizeof(MJDuckyKey));
|
memcpy(dk, &mj_ducky_keys[i], sizeof(MJDuckyKey));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -152,6 +161,30 @@ static void build_hid_packet(uint8_t mod, uint8_t hid, uint8_t* payload) {
|
|||||||
checksum(payload, LOGITECH_HID_TEMPLATE_SIZE);
|
checksum(payload, LOGITECH_HID_TEMPLATE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void release_key(
|
||||||
|
FuriHalSpiBusHandle* handle,
|
||||||
|
uint8_t* addr,
|
||||||
|
uint8_t addr_size,
|
||||||
|
uint8_t rate,
|
||||||
|
PluginState* plugin_state) {
|
||||||
|
// This function release keys currently pressed, but keep pressing special keys
|
||||||
|
// if holding mod keys variable are set to true
|
||||||
|
|
||||||
|
uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0};
|
||||||
|
build_hid_packet(
|
||||||
|
0 | holding_ctrl | holding_shift << 1 | holding_alt << 2 | holding_gui << 3,
|
||||||
|
0,
|
||||||
|
hid_payload);
|
||||||
|
inject_packet(
|
||||||
|
handle,
|
||||||
|
addr,
|
||||||
|
addr_size,
|
||||||
|
rate,
|
||||||
|
hid_payload,
|
||||||
|
LOGITECH_HID_TEMPLATE_SIZE,
|
||||||
|
plugin_state); // empty hid packet
|
||||||
|
}
|
||||||
|
|
||||||
static void send_hid_packet(
|
static void send_hid_packet(
|
||||||
FuriHalSpiBusHandle* handle,
|
FuriHalSpiBusHandle* handle,
|
||||||
uint8_t* addr,
|
uint8_t* addr,
|
||||||
@@ -161,24 +194,22 @@ static void send_hid_packet(
|
|||||||
uint8_t hid,
|
uint8_t hid,
|
||||||
PluginState* plugin_state) {
|
PluginState* plugin_state) {
|
||||||
uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0};
|
uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0};
|
||||||
build_hid_packet(0, 0, hid_payload);
|
if(hid == prev_hid) release_key(handle, addr, addr_size, rate, plugin_state);
|
||||||
if(hid == prev_hid)
|
|
||||||
inject_packet(
|
|
||||||
handle,
|
|
||||||
addr,
|
|
||||||
addr_size,
|
|
||||||
rate,
|
|
||||||
hid_payload,
|
|
||||||
LOGITECH_HID_TEMPLATE_SIZE,
|
|
||||||
plugin_state); // empty hid packet
|
|
||||||
|
|
||||||
prev_hid = hid;
|
prev_hid = hid;
|
||||||
build_hid_packet(mod, hid, hid_payload);
|
build_hid_packet(
|
||||||
|
mod | holding_ctrl | holding_shift << 1 | holding_alt << 2 | holding_gui << 3,
|
||||||
|
hid,
|
||||||
|
hid_payload);
|
||||||
inject_packet(
|
inject_packet(
|
||||||
handle, addr, addr_size, rate, hid_payload, LOGITECH_HID_TEMPLATE_SIZE, plugin_state);
|
handle, addr, addr_size, rate, hid_payload, LOGITECH_HID_TEMPLATE_SIZE, plugin_state);
|
||||||
furi_delay_ms(12);
|
furi_delay_ms(12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ducky_end_line(const char chr) {
|
||||||
|
return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n'));
|
||||||
|
}
|
||||||
|
|
||||||
// returns false if there was an error processing script line
|
// returns false if there was an error processing script line
|
||||||
static bool mj_process_ducky_line(
|
static bool mj_process_ducky_line(
|
||||||
FuriHalSpiBusHandle* handle,
|
FuriHalSpiBusHandle* handle,
|
||||||
@@ -251,6 +282,32 @@ static bool mj_process_ducky_line(
|
|||||||
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if(strncmp(line_tmp, ducky_cmd_altstring, strlen(ducky_cmd_altstring)) == 0) {
|
||||||
|
// ALTSTRING
|
||||||
|
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
||||||
|
for(size_t i = 0; i < strlen(line_tmp); i++) {
|
||||||
|
if((line_tmp[i] < ' ') || (line_tmp[i] > '~')) {
|
||||||
|
continue; // Skip non-printable chars
|
||||||
|
}
|
||||||
|
|
||||||
|
char alt_code[4];
|
||||||
|
// Getting altcode of the char
|
||||||
|
snprintf(alt_code, 4, "%u", line_tmp[i]);
|
||||||
|
|
||||||
|
uint8_t j = 0;
|
||||||
|
while(!ducky_end_line(alt_code[j])) {
|
||||||
|
char pad_num[5] = {'N', 'U', 'M', ' ', alt_code[j]};
|
||||||
|
if(!mj_get_ducky_key(pad_num, 5, &dk)) return false;
|
||||||
|
holding_alt = true;
|
||||||
|
FURI_LOG_D(TAG, "Sending %s", pad_num);
|
||||||
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
holding_alt = false;
|
||||||
|
release_key(handle, addr, addr_size, rate, plugin_state);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) {
|
} else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) {
|
||||||
// REPEAT
|
// REPEAT
|
||||||
@@ -269,7 +326,9 @@ static bool mj_process_ducky_line(
|
|||||||
} else if(strncmp(line_tmp, "ALT", strlen("ALT")) == 0) {
|
} else if(strncmp(line_tmp, "ALT", strlen("ALT")) == 0) {
|
||||||
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
||||||
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
||||||
send_hid_packet(handle, addr, addr_size, rate, dk.mod | 4, dk.hid, plugin_state);
|
holding_alt = true;
|
||||||
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
|
holding_alt = false;
|
||||||
return true;
|
return true;
|
||||||
} else if(
|
} else if(
|
||||||
strncmp(line_tmp, "GUI", strlen("GUI")) == 0 ||
|
strncmp(line_tmp, "GUI", strlen("GUI")) == 0 ||
|
||||||
@@ -277,33 +336,47 @@ static bool mj_process_ducky_line(
|
|||||||
strncmp(line_tmp, "COMMAND", strlen("COMMAND")) == 0) {
|
strncmp(line_tmp, "COMMAND", strlen("COMMAND")) == 0) {
|
||||||
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
||||||
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
||||||
send_hid_packet(handle, addr, addr_size, rate, dk.mod | 8, dk.hid, plugin_state);
|
holding_gui = true;
|
||||||
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
|
holding_gui = false;
|
||||||
return true;
|
return true;
|
||||||
} else if(
|
} else if(
|
||||||
strncmp(line_tmp, "CTRL-ALT", strlen("CTRL-ALT")) == 0 ||
|
strncmp(line_tmp, "CTRL-ALT", strlen("CTRL-ALT")) == 0 ||
|
||||||
strncmp(line_tmp, "CONTROL-ALT", strlen("CONTROL-ALT")) == 0) {
|
strncmp(line_tmp, "CONTROL-ALT", strlen("CONTROL-ALT")) == 0) {
|
||||||
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
||||||
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
||||||
send_hid_packet(handle, addr, addr_size, rate, dk.mod | 4 | 1, dk.hid, plugin_state);
|
holding_ctrl = true;
|
||||||
|
holding_alt = true;
|
||||||
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
|
holding_ctrl = false;
|
||||||
|
holding_alt = false;
|
||||||
return true;
|
return true;
|
||||||
} else if(
|
} else if(
|
||||||
strncmp(line_tmp, "CTRL-SHIFT", strlen("CTRL-SHIFT")) == 0 ||
|
strncmp(line_tmp, "CTRL-SHIFT", strlen("CTRL-SHIFT")) == 0 ||
|
||||||
strncmp(line_tmp, "CONTROL-SHIFT", strlen("CONTROL-SHIFT")) == 0) {
|
strncmp(line_tmp, "CONTROL-SHIFT", strlen("CONTROL-SHIFT")) == 0) {
|
||||||
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
||||||
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
||||||
send_hid_packet(handle, addr, addr_size, rate, dk.mod | 1 | 2, dk.hid, plugin_state);
|
holding_ctrl = true;
|
||||||
|
holding_shift = true;
|
||||||
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
|
holding_ctrl = false;
|
||||||
|
holding_shift = false;
|
||||||
return true;
|
return true;
|
||||||
} else if(
|
} else if(
|
||||||
strncmp(line_tmp, "CTRL", strlen("CTRL")) == 0 ||
|
strncmp(line_tmp, "CTRL", strlen("CTRL")) == 0 ||
|
||||||
strncmp(line_tmp, "CONTROL", strlen("CONTROL")) == 0) {
|
strncmp(line_tmp, "CONTROL", strlen("CONTROL")) == 0) {
|
||||||
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
||||||
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
||||||
send_hid_packet(handle, addr, addr_size, rate, dk.mod | 1, dk.hid, plugin_state);
|
holding_ctrl = true;
|
||||||
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
|
holding_ctrl = false;
|
||||||
return true;
|
return true;
|
||||||
} else if(strncmp(line_tmp, "SHIFT", strlen("SHIFT")) == 0) {
|
} else if(strncmp(line_tmp, "SHIFT", strlen("SHIFT")) == 0) {
|
||||||
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1];
|
||||||
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false;
|
||||||
send_hid_packet(handle, addr, addr_size, rate, dk.mod | 2, dk.hid, plugin_state);
|
holding_shift = true;
|
||||||
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
|
holding_shift = false;
|
||||||
return true;
|
return true;
|
||||||
} else if(
|
} else if(
|
||||||
strncmp(line_tmp, "ESC", strlen("ESC")) == 0 ||
|
strncmp(line_tmp, "ESC", strlen("ESC")) == 0 ||
|
||||||
@@ -344,6 +417,10 @@ static bool mj_process_ducky_line(
|
|||||||
if(!mj_get_ducky_key("SPACE", 5, &dk)) return false;
|
if(!mj_get_ducky_key("SPACE", 5, &dk)) return false;
|
||||||
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
return true;
|
return true;
|
||||||
|
} else if(strncmp(line_tmp, "TAB", strlen("TAB")) == 0) {
|
||||||
|
if(!mj_get_ducky_key("TAB", 3, &dk)) return false;
|
||||||
|
send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ static void wrap_up(Storage* storage, NotificationApp* notification) {
|
|||||||
hexlify(addr, 5, top_address);
|
hexlify(addr, 5, top_address);
|
||||||
found_count++;
|
found_count++;
|
||||||
save_addr_to_file(storage, addr, 5, notification);
|
save_addr_to_file(storage, addr, 5, notification);
|
||||||
DOLPHIN_DEED(getRandomDeed());
|
// DOLPHIN_DEED(getRandomDeed());
|
||||||
if(confirmed_idx < MAX_CONFIRMED) memcpy(confirmed[confirmed_idx++], addr, 5);
|
if(confirmed_idx < MAX_CONFIRMED) memcpy(confirmed[confirmed_idx++], addr, 5);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
App(
|
App(
|
||||||
appid="Picopass",
|
appid="Picopass",
|
||||||
name="PicoPass Reader",
|
name="PicoPass",
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
targets=["f7"],
|
targets=["f7"],
|
||||||
entry_point="picopass_app",
|
entry_point="picopass_app",
|
||||||
@@ -9,7 +9,7 @@ App(
|
|||||||
"gui",
|
"gui",
|
||||||
],
|
],
|
||||||
stack_size=4 * 1024,
|
stack_size=4 * 1024,
|
||||||
order=175,
|
order=30,
|
||||||
fap_icon="125_10px.png",
|
fap_icon="125_10px.png",
|
||||||
fap_category="Tools",
|
fap_category="Tools",
|
||||||
fap_libs=["mbedtls"],
|
fap_libs=["mbedtls"],
|
||||||
|
|||||||
@@ -137,9 +137,9 @@ void picopass_text_store_clear(Picopass* picopass) {
|
|||||||
memset(picopass->text_store, 0, sizeof(picopass->text_store));
|
memset(picopass->text_store, 0, sizeof(picopass->text_store));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const NotificationSequence picopass_sequence_blink_start_blue = {
|
static const NotificationSequence picopass_sequence_blink_start_cyan = {
|
||||||
&message_blink_start_10,
|
&message_blink_start_10,
|
||||||
&message_blink_set_color_blue,
|
&message_blink_set_color_cyan,
|
||||||
&message_do_not_reset,
|
&message_do_not_reset,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
@@ -150,7 +150,7 @@ static const NotificationSequence picopass_sequence_blink_stop = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void picopass_blink_start(Picopass* picopass) {
|
void picopass_blink_start(Picopass* picopass) {
|
||||||
notification_message(picopass->notifications, &picopass_sequence_blink_start_blue);
|
notification_message(picopass->notifications, &picopass_sequence_blink_start_cyan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void picopass_blink_stop(Picopass* picopass) {
|
void picopass_blink_stop(Picopass* picopass) {
|
||||||
@@ -171,6 +171,16 @@ void picopass_show_loading_popup(void* context, bool show) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool picopass_is_memset(const uint8_t* data, const uint8_t pattern, size_t size) {
|
||||||
|
bool result = size > 0;
|
||||||
|
while(size > 0) {
|
||||||
|
result &= (*data == pattern);
|
||||||
|
data++;
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t picopass_app(void* p) {
|
int32_t picopass_app(void* p) {
|
||||||
UNUSED(p);
|
UNUSED(p);
|
||||||
Picopass* picopass = picopass_alloc();
|
Picopass* picopass = picopass_alloc();
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* r
|
|||||||
|
|
||||||
record->CardNumber = (bot >> 1) & 0xFFFF;
|
record->CardNumber = (bot >> 1) & 0xFFFF;
|
||||||
record->FacilityCode = (bot >> 17) & 0xFF;
|
record->FacilityCode = (bot >> 17) & 0xFF;
|
||||||
FURI_LOG_D(TAG, "FC:%u CN: %u\n", record->FacilityCode, record->CardNumber);
|
FURI_LOG_D(TAG, "FC: %u CN: %u", record->FacilityCode, record->CardNumber);
|
||||||
record->valid = true;
|
record->valid = true;
|
||||||
} else {
|
} else {
|
||||||
record->CardNumber = 0;
|
record->CardNumber = 0;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#define PICOPASS_KD_BLOCK_INDEX 3
|
#define PICOPASS_KD_BLOCK_INDEX 3
|
||||||
#define PICOPASS_KC_BLOCK_INDEX 4
|
#define PICOPASS_KC_BLOCK_INDEX 4
|
||||||
#define PICOPASS_AIA_BLOCK_INDEX 5
|
#define PICOPASS_AIA_BLOCK_INDEX 5
|
||||||
|
#define PICOPASS_PACS_CFG_BLOCK_INDEX 6
|
||||||
|
|
||||||
#define PICOPASS_APP_FOLDER ANY_PATH("picopass")
|
#define PICOPASS_APP_FOLDER ANY_PATH("picopass")
|
||||||
#define PICOPASS_APP_EXTENSION ".picopass"
|
#define PICOPASS_APP_EXTENSION ".picopass"
|
||||||
|
|||||||
@@ -81,3 +81,15 @@ void picopass_blink_start(Picopass* picopass);
|
|||||||
void picopass_blink_stop(Picopass* picopass);
|
void picopass_blink_stop(Picopass* picopass);
|
||||||
|
|
||||||
void picopass_show_loading_popup(void* context, bool show);
|
void picopass_show_loading_popup(void* context, bool show);
|
||||||
|
|
||||||
|
/** Check if memory is set to pattern
|
||||||
|
*
|
||||||
|
* @warning zero size will return false
|
||||||
|
*
|
||||||
|
* @param[in] data Pointer to the byte array
|
||||||
|
* @param[in] pattern The pattern
|
||||||
|
* @param[in] size The byte array size
|
||||||
|
*
|
||||||
|
* @return True if memory is set to pattern, false otherwise
|
||||||
|
*/
|
||||||
|
bool picopass_is_memset(const uint8_t* data, const uint8_t pattern, size_t size);
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
#define TAG "PicopassWorker"
|
#define TAG "PicopassWorker"
|
||||||
|
|
||||||
const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78};
|
const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78};
|
||||||
const uint8_t picopass_factory_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00};
|
const uint8_t picopass_factory_credit_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00};
|
||||||
|
const uint8_t picopass_factory_debit_key[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87};
|
||||||
|
|
||||||
static void picopass_worker_enable_field() {
|
static void picopass_worker_enable_field() {
|
||||||
furi_hal_nfc_ll_txrx_on();
|
furi_hal_nfc_ll_txrx_on();
|
||||||
@@ -197,6 +198,28 @@ static ReturnCode picopass_auth_standard(uint8_t* csn, uint8_t* div_key) {
|
|||||||
return rfalPicoPassPollerCheck(mac, &chkRes);
|
return rfalPicoPassPollerCheck(mac, &chkRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ReturnCode picopass_auth_factory(uint8_t* csn, uint8_t* div_key) {
|
||||||
|
rfalPicoPassReadCheckRes rcRes;
|
||||||
|
rfalPicoPassCheckRes chkRes;
|
||||||
|
|
||||||
|
ReturnCode err;
|
||||||
|
|
||||||
|
uint8_t mac[4] = {0};
|
||||||
|
uint8_t ccnr[12] = {0};
|
||||||
|
|
||||||
|
err = rfalPicoPassPollerReadCheck(&rcRes);
|
||||||
|
if(err != ERR_NONE) {
|
||||||
|
FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
|
||||||
|
|
||||||
|
loclass_diversifyKey(csn, picopass_factory_debit_key, div_key);
|
||||||
|
loclass_opt_doReaderMAC(ccnr, div_key, mac);
|
||||||
|
|
||||||
|
return rfalPicoPassPollerCheck(mac, &chkRes);
|
||||||
|
}
|
||||||
|
|
||||||
static ReturnCode picopass_auth_dict(
|
static ReturnCode picopass_auth_dict(
|
||||||
uint8_t* csn,
|
uint8_t* csn,
|
||||||
PicopassPacs* pacs,
|
PicopassPacs* pacs,
|
||||||
@@ -264,14 +287,23 @@ static ReturnCode picopass_auth_dict(
|
|||||||
ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) {
|
ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) {
|
||||||
ReturnCode err;
|
ReturnCode err;
|
||||||
|
|
||||||
FURI_LOG_E(TAG, "Trying standard legacy key");
|
FURI_LOG_I(TAG, "Trying standard legacy key");
|
||||||
err = picopass_auth_standard(
|
err = picopass_auth_standard(
|
||||||
AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data);
|
AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data);
|
||||||
if(err == ERR_NONE) {
|
if(err == ERR_NONE) {
|
||||||
|
memcpy(pacs->key, picopass_iclass_key, PICOPASS_BLOCK_LEN);
|
||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_E(TAG, "Starting user dictionary attack");
|
FURI_LOG_I(TAG, "Trying factory default key");
|
||||||
|
err = picopass_auth_factory(
|
||||||
|
AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data);
|
||||||
|
if(err == ERR_NONE) {
|
||||||
|
memcpy(pacs->key, picopass_factory_debit_key, PICOPASS_BLOCK_LEN);
|
||||||
|
return ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FURI_LOG_I(TAG, "Starting user dictionary attack");
|
||||||
err = picopass_auth_dict(
|
err = picopass_auth_dict(
|
||||||
AA1[PICOPASS_CSN_BLOCK_INDEX].data,
|
AA1[PICOPASS_CSN_BLOCK_INDEX].data,
|
||||||
pacs,
|
pacs,
|
||||||
@@ -281,7 +313,7 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) {
|
|||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_E(TAG, "Starting in-built dictionary attack");
|
FURI_LOG_I(TAG, "Starting system dictionary attack");
|
||||||
err = picopass_auth_dict(
|
err = picopass_auth_dict(
|
||||||
AA1[PICOPASS_CSN_BLOCK_INDEX].data,
|
AA1[PICOPASS_CSN_BLOCK_INDEX].data,
|
||||||
pacs,
|
pacs,
|
||||||
@@ -406,6 +438,84 @@ ReturnCode picopass_write_card(PicopassBlock* AA1) {
|
|||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnCode picopass_write_block(PicopassPacs* pacs, uint8_t blockNo, uint8_t* newBlock) {
|
||||||
|
rfalPicoPassIdentifyRes idRes;
|
||||||
|
rfalPicoPassSelectRes selRes;
|
||||||
|
rfalPicoPassReadCheckRes rcRes;
|
||||||
|
rfalPicoPassCheckRes chkRes;
|
||||||
|
|
||||||
|
ReturnCode err;
|
||||||
|
|
||||||
|
uint8_t div_key[8] = {0};
|
||||||
|
uint8_t mac[4] = {0};
|
||||||
|
uint8_t ccnr[12] = {0};
|
||||||
|
|
||||||
|
err = rfalPicoPassPollerIdentify(&idRes);
|
||||||
|
if(err != ERR_NONE) {
|
||||||
|
FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
|
||||||
|
if(err != ERR_NONE) {
|
||||||
|
FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rfalPicoPassPollerReadCheck(&rcRes);
|
||||||
|
if(err != ERR_NONE) {
|
||||||
|
FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
|
||||||
|
|
||||||
|
loclass_diversifyKey(selRes.CSN, pacs->key, div_key);
|
||||||
|
loclass_opt_doReaderMAC(ccnr, div_key, mac);
|
||||||
|
|
||||||
|
err = rfalPicoPassPollerCheck(mac, &chkRes);
|
||||||
|
if(err != ERR_NONE) {
|
||||||
|
FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", blockNo);
|
||||||
|
uint8_t data[9] = {
|
||||||
|
blockNo,
|
||||||
|
newBlock[0],
|
||||||
|
newBlock[1],
|
||||||
|
newBlock[2],
|
||||||
|
newBlock[3],
|
||||||
|
newBlock[4],
|
||||||
|
newBlock[5],
|
||||||
|
newBlock[6],
|
||||||
|
newBlock[7]};
|
||||||
|
loclass_doMAC_N(data, sizeof(data), div_key, mac);
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG,
|
||||||
|
"loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
|
||||||
|
blockNo,
|
||||||
|
data[1],
|
||||||
|
data[2],
|
||||||
|
data[3],
|
||||||
|
data[4],
|
||||||
|
data[5],
|
||||||
|
data[6],
|
||||||
|
data[7],
|
||||||
|
data[8],
|
||||||
|
mac[0],
|
||||||
|
mac[1],
|
||||||
|
mac[2],
|
||||||
|
mac[3]);
|
||||||
|
|
||||||
|
err = rfalPicoPassPollerWriteBlock(data[0], data + 1, mac);
|
||||||
|
if(err != ERR_NONE) {
|
||||||
|
FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t picopass_worker_task(void* context) {
|
int32_t picopass_worker_task(void* context) {
|
||||||
PicopassWorker* picopass_worker = context;
|
PicopassWorker* picopass_worker = context;
|
||||||
|
|
||||||
@@ -414,6 +524,8 @@ int32_t picopass_worker_task(void* context) {
|
|||||||
picopass_worker_detect(picopass_worker);
|
picopass_worker_detect(picopass_worker);
|
||||||
} else if(picopass_worker->state == PicopassWorkerStateWrite) {
|
} else if(picopass_worker->state == PicopassWorkerStateWrite) {
|
||||||
picopass_worker_write(picopass_worker);
|
picopass_worker_write(picopass_worker);
|
||||||
|
} else if(picopass_worker->state == PicopassWorkerStateWriteStandardKey) {
|
||||||
|
picopass_worker_write_standard_key(picopass_worker);
|
||||||
}
|
}
|
||||||
picopass_worker_disable_field(ERR_NONE);
|
picopass_worker_disable_field(ERR_NONE);
|
||||||
|
|
||||||
@@ -448,7 +560,7 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Thank you proxmark!
|
// Thank you proxmark!
|
||||||
pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
|
pacs->legacy = picopass_is_memset(AA1[5].data, 0xFF, 8);
|
||||||
pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
|
pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
|
||||||
if(pacs->se_enabled) {
|
if(pacs->se_enabled) {
|
||||||
FURI_LOG_D(TAG, "SE enabled");
|
FURI_LOG_D(TAG, "SE enabled");
|
||||||
@@ -520,3 +632,46 @@ void picopass_worker_write(PicopassWorker* picopass_worker) {
|
|||||||
furi_delay_ms(100);
|
furi_delay_ms(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void picopass_worker_write_standard_key(PicopassWorker* picopass_worker) {
|
||||||
|
PicopassDeviceData* dev_data = picopass_worker->dev_data;
|
||||||
|
PicopassBlock* AA1 = dev_data->AA1;
|
||||||
|
PicopassPacs* pacs = &dev_data->pacs;
|
||||||
|
ReturnCode err;
|
||||||
|
PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
|
||||||
|
|
||||||
|
uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data;
|
||||||
|
uint8_t* configBlock = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data;
|
||||||
|
uint8_t fuses = configBlock[7];
|
||||||
|
uint8_t* oldKey = AA1[PICOPASS_KD_BLOCK_INDEX].data;
|
||||||
|
|
||||||
|
uint8_t newKey[PICOPASS_BLOCK_LEN] = {0};
|
||||||
|
loclass_diversifyKey(csn, picopass_iclass_key, newKey);
|
||||||
|
|
||||||
|
if((fuses & 0x80) == 0x80) {
|
||||||
|
FURI_LOG_D(TAG, "Plain write for personalized mode key change");
|
||||||
|
} else {
|
||||||
|
FURI_LOG_D(TAG, "XOR write for application mode key change");
|
||||||
|
// XOR when in application mode
|
||||||
|
for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
|
||||||
|
newKey[i] ^= oldKey[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(picopass_worker->state == PicopassWorkerStateWriteStandardKey) {
|
||||||
|
if(picopass_detect_card(1000) == ERR_NONE) {
|
||||||
|
err = picopass_write_block(pacs, PICOPASS_KD_BLOCK_INDEX, newKey);
|
||||||
|
if(err != ERR_NONE) {
|
||||||
|
FURI_LOG_E(TAG, "picopass_write_block error %d", err);
|
||||||
|
nextState = PicopassWorkerEventFail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify caller and exit
|
||||||
|
if(picopass_worker->callback) {
|
||||||
|
picopass_worker->callback(nextState, picopass_worker->context);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ typedef enum {
|
|||||||
// Main worker states
|
// Main worker states
|
||||||
PicopassWorkerStateDetect,
|
PicopassWorkerStateDetect,
|
||||||
PicopassWorkerStateWrite,
|
PicopassWorkerStateWrite,
|
||||||
|
PicopassWorkerStateWriteStandardKey,
|
||||||
// Transition
|
// Transition
|
||||||
PicopassWorkerStateStop,
|
PicopassWorkerStateStop,
|
||||||
} PicopassWorkerState;
|
} PicopassWorkerState;
|
||||||
|
|||||||
@@ -31,3 +31,4 @@ int32_t picopass_worker_task(void* context);
|
|||||||
|
|
||||||
void picopass_worker_detect(PicopassWorker* picopass_worker);
|
void picopass_worker_detect(PicopassWorker* picopass_worker);
|
||||||
void picopass_worker_write(PicopassWorker* picopass_worker);
|
void picopass_worker_write(PicopassWorker* picopass_worker);
|
||||||
|
void picopass_worker_write_standard_key(PicopassWorker* picopass_worker);
|
||||||
|
|||||||
@@ -11,3 +11,5 @@ ADD_SCENE(picopass, delete, Delete)
|
|||||||
ADD_SCENE(picopass, delete_success, DeleteSuccess)
|
ADD_SCENE(picopass, delete_success, DeleteSuccess)
|
||||||
ADD_SCENE(picopass, write_card, WriteCard)
|
ADD_SCENE(picopass, write_card, WriteCard)
|
||||||
ADD_SCENE(picopass, write_card_success, WriteCardSuccess)
|
ADD_SCENE(picopass, write_card_success, WriteCardSuccess)
|
||||||
|
ADD_SCENE(picopass, read_factory_success, ReadFactorySuccess)
|
||||||
|
ADD_SCENE(picopass, write_key, WriteKey)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "../picopass_i.h"
|
#include "../picopass_i.h"
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
const uint8_t picopass_factory_key_check[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87};
|
||||||
|
|
||||||
void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context) {
|
void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context) {
|
||||||
UNUSED(event);
|
UNUSED(event);
|
||||||
Picopass* picopass = context;
|
Picopass* picopass = context;
|
||||||
@@ -34,7 +36,14 @@ bool picopass_scene_read_card_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == PicopassCustomEventWorkerExit) {
|
if(event.event == PicopassCustomEventWorkerExit) {
|
||||||
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess);
|
if(memcmp(
|
||||||
|
picopass->dev->dev_data.pacs.key,
|
||||||
|
picopass_factory_key_check,
|
||||||
|
PICOPASS_BLOCK_LEN) == 0) {
|
||||||
|
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadFactorySuccess);
|
||||||
|
} else {
|
||||||
|
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess);
|
||||||
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ void picopass_scene_read_card_success_widget_callback(
|
|||||||
|
|
||||||
void picopass_scene_read_card_success_on_enter(void* context) {
|
void picopass_scene_read_card_success_on_enter(void* context) {
|
||||||
Picopass* picopass = context;
|
Picopass* picopass = context;
|
||||||
|
|
||||||
FuriString* csn_str = furi_string_alloc_set("CSN:");
|
FuriString* csn_str = furi_string_alloc_set("CSN:");
|
||||||
FuriString* credential_str = furi_string_alloc();
|
FuriString* credential_str = furi_string_alloc();
|
||||||
FuriString* wiegand_str = furi_string_alloc();
|
FuriString* wiegand_str = furi_string_alloc();
|
||||||
@@ -30,27 +31,31 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|||||||
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
|
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
|
||||||
Widget* widget = picopass->widget;
|
Widget* widget = picopass->widget;
|
||||||
|
|
||||||
uint8_t csn[PICOPASS_BLOCK_LEN];
|
uint8_t csn[PICOPASS_BLOCK_LEN] = {0};
|
||||||
memcpy(csn, &AA1->data[PICOPASS_CSN_BLOCK_INDEX], PICOPASS_BLOCK_LEN);
|
memcpy(csn, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN);
|
||||||
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
|
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
|
||||||
furi_string_cat_printf(csn_str, " %02X", csn[i]);
|
furi_string_cat_printf(csn_str, "%02X ", csn[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neither of these are valid. Indicates the block was all 0x00 or all 0xff
|
bool no_key = picopass_is_memset(pacs->key, 0x00, PICOPASS_BLOCK_LEN);
|
||||||
if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) {
|
bool empty =
|
||||||
|
picopass_is_memset(AA1[PICOPASS_PACS_CFG_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN);
|
||||||
|
|
||||||
|
if(no_key) {
|
||||||
furi_string_cat_printf(wiegand_str, "Read Failed");
|
furi_string_cat_printf(wiegand_str, "Read Failed");
|
||||||
|
|
||||||
if(pacs->se_enabled) {
|
if(pacs->se_enabled) {
|
||||||
furi_string_cat_printf(credential_str, "SE enabled");
|
furi_string_cat_printf(credential_str, "SE enabled");
|
||||||
}
|
}
|
||||||
|
} else if(empty) {
|
||||||
|
furi_string_cat_printf(wiegand_str, "Empty");
|
||||||
|
} else if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) {
|
||||||
|
// Neither of these are valid. Indicates the block was all 0x00 or all 0xff
|
||||||
|
furi_string_cat_printf(wiegand_str, "Invalid PACS");
|
||||||
|
|
||||||
widget_add_button_element(
|
if(pacs->se_enabled) {
|
||||||
widget,
|
furi_string_cat_printf(credential_str, "SE enabled");
|
||||||
GuiButtonTypeLeft,
|
}
|
||||||
"Retry",
|
|
||||||
picopass_scene_read_card_success_widget_callback,
|
|
||||||
picopass);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
size_t bytesLength = 1 + pacs->record.bitLength / 8;
|
size_t bytesLength = 1 + pacs->record.bitLength / 8;
|
||||||
furi_string_set(credential_str, "");
|
furi_string_set(credential_str, "");
|
||||||
@@ -69,12 +74,18 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|||||||
furi_string_cat_printf(sio_str, "+SIO");
|
furi_string_cat_printf(sio_str, "+SIO");
|
||||||
}
|
}
|
||||||
|
|
||||||
widget_add_button_element(
|
if(pacs->key) {
|
||||||
widget,
|
if(pacs->sio) {
|
||||||
GuiButtonTypeLeft,
|
furi_string_cat_printf(sio_str, " ");
|
||||||
"Retry",
|
}
|
||||||
picopass_scene_read_card_success_widget_callback,
|
furi_string_cat_printf(sio_str, "Key: ");
|
||||||
picopass);
|
|
||||||
|
uint8_t key[PICOPASS_BLOCK_LEN];
|
||||||
|
memcpy(key, &pacs->key, PICOPASS_BLOCK_LEN);
|
||||||
|
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
|
||||||
|
furi_string_cat_printf(sio_str, "%02X", key[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
widget,
|
widget,
|
||||||
@@ -84,6 +95,13 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|||||||
picopass);
|
picopass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
widget,
|
||||||
|
GuiButtonTypeLeft,
|
||||||
|
"Retry",
|
||||||
|
picopass_scene_read_card_success_widget_callback,
|
||||||
|
picopass);
|
||||||
|
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(csn_str));
|
widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(csn_str));
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#include "../picopass_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void picopass_scene_read_factory_success_widget_callback(
|
||||||
|
GuiButtonType result,
|
||||||
|
InputType type,
|
||||||
|
void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Picopass* picopass = context;
|
||||||
|
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(picopass->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void picopass_scene_read_factory_success_on_enter(void* context) {
|
||||||
|
Picopass* picopass = context;
|
||||||
|
FuriString* title = furi_string_alloc_set("Factory Default");
|
||||||
|
FuriString* subtitle = furi_string_alloc_set("");
|
||||||
|
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
|
// Send notification
|
||||||
|
notification_message(picopass->notifications, &sequence_success);
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
Widget* widget = picopass->widget;
|
||||||
|
//PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
|
||||||
|
PicopassBlock* AA1 = picopass->dev->dev_data.AA1;
|
||||||
|
|
||||||
|
uint8_t* configBlock = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data;
|
||||||
|
uint8_t fuses = configBlock[7];
|
||||||
|
|
||||||
|
if((fuses & 0x80) == 0x80) {
|
||||||
|
furi_string_cat_printf(subtitle, "Personalization mode");
|
||||||
|
} else {
|
||||||
|
furi_string_cat_printf(subtitle, "Application mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
widget,
|
||||||
|
GuiButtonTypeCenter,
|
||||||
|
"Write Standard iClass Key",
|
||||||
|
picopass_scene_read_factory_success_widget_callback,
|
||||||
|
picopass);
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(title));
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 64, 20, AlignCenter, AlignCenter, FontPrimary, furi_string_get_cstr(subtitle));
|
||||||
|
|
||||||
|
furi_string_free(title);
|
||||||
|
furi_string_free(subtitle);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool picopass_scene_read_factory_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Picopass* picopass = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
|
consumed = scene_manager_previous_scene(picopass->scene_manager);
|
||||||
|
} else if(event.event == GuiButtonTypeCenter) {
|
||||||
|
scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void picopass_scene_read_factory_success_on_exit(void* context) {
|
||||||
|
Picopass* picopass = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
widget_reset(picopass->widget);
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ void picopass_scene_save_name_on_enter(void* context) {
|
|||||||
} else {
|
} else {
|
||||||
picopass_text_store_set(picopass, picopass->dev->dev_name);
|
picopass_text_store_set(picopass, picopass->dev->dev_name);
|
||||||
}
|
}
|
||||||
text_input_set_header_text(text_input, "Name The Card");
|
text_input_set_header_text(text_input, "Name the card");
|
||||||
text_input_set_result_callback(
|
text_input_set_result_callback(
|
||||||
text_input,
|
text_input,
|
||||||
picopass_scene_save_name_text_input_callback,
|
picopass_scene_save_name_text_input_callback,
|
||||||
|
|||||||
@@ -32,13 +32,18 @@ bool picopass_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexRead) {
|
if(event.event == SubmenuIndexRead) {
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
picopass->scene_manager, PicopassSceneStart, SubmenuIndexRead);
|
||||||
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCard);
|
scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCard);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexSaved) {
|
} else if(event.event == SubmenuIndexSaved) {
|
||||||
|
// Explicitly save state so that the correct item is
|
||||||
|
// reselected if the user cancels loading a file.
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
picopass->scene_manager, PicopassSceneStart, SubmenuIndexSaved);
|
||||||
scene_manager_next_scene(picopass->scene_manager, PicopassSceneFileSelect);
|
scene_manager_next_scene(picopass->scene_manager, PicopassSceneFileSelect);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
scene_manager_set_scene_state(picopass->scene_manager, PicopassSceneStart, event.event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ void picopass_scene_write_card_success_widget_callback(
|
|||||||
void picopass_scene_write_card_success_on_enter(void* context) {
|
void picopass_scene_write_card_success_on_enter(void* context) {
|
||||||
Picopass* picopass = context;
|
Picopass* picopass = context;
|
||||||
Widget* widget = picopass->widget;
|
Widget* widget = picopass->widget;
|
||||||
|
FuriString* str = furi_string_alloc_set("Write Success!");
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
@@ -29,6 +30,18 @@ void picopass_scene_write_card_success_on_enter(void* context) {
|
|||||||
picopass_scene_write_card_success_widget_callback,
|
picopass_scene_write_card_success_widget_callback,
|
||||||
picopass);
|
picopass);
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
widget,
|
||||||
|
GuiButtonTypeRight,
|
||||||
|
"Menu",
|
||||||
|
picopass_scene_write_card_success_widget_callback,
|
||||||
|
picopass);
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(str));
|
||||||
|
|
||||||
|
furi_string_free(str);
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
|
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#include "../picopass_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void picopass_write_key_worker_callback(PicopassWorkerEvent event, void* context) {
|
||||||
|
UNUSED(event);
|
||||||
|
Picopass* picopass = context;
|
||||||
|
view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventWorkerExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void picopass_scene_write_key_on_enter(void* context) {
|
||||||
|
Picopass* picopass = context;
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcSave);
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
Popup* popup = picopass->popup;
|
||||||
|
popup_set_header(popup, "Writing\niClass\nkey", 68, 30, AlignLeft, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||||
|
|
||||||
|
// Start worker
|
||||||
|
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup);
|
||||||
|
picopass_worker_start(
|
||||||
|
picopass->worker,
|
||||||
|
PicopassWorkerStateWriteStandardKey,
|
||||||
|
&picopass->dev->dev_data,
|
||||||
|
picopass_write_key_worker_callback,
|
||||||
|
picopass);
|
||||||
|
|
||||||
|
picopass_blink_start(picopass);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool picopass_scene_write_key_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Picopass* picopass = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == PicopassCustomEventWorkerExit) {
|
||||||
|
scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteCardSuccess);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void picopass_scene_write_key_on_exit(void* context) {
|
||||||
|
Picopass* picopass = context;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
picopass_worker_stop(picopass->worker);
|
||||||
|
// Clear view
|
||||||
|
popup_reset(picopass->popup);
|
||||||
|
|
||||||
|
picopass_blink_stop(picopass);
|
||||||
|
}
|
||||||
@@ -14,7 +14,6 @@ typedef struct {
|
|||||||
const size_t stack_size;
|
const size_t stack_size;
|
||||||
const Icon* icon;
|
const Icon* icon;
|
||||||
const FlipperApplicationFlag flags;
|
const FlipperApplicationFlag flags;
|
||||||
const char* link;
|
|
||||||
} FlipperApplication;
|
} FlipperApplication;
|
||||||
|
|
||||||
typedef void (*FlipperOnStartHook)(void);
|
typedef void (*FlipperOnStartHook)(void);
|
||||||
|
|||||||
@@ -463,7 +463,7 @@ int32_t bt_srv(void* p) {
|
|||||||
Bt* bt = bt_alloc();
|
Bt* bt = bt_alloc();
|
||||||
|
|
||||||
if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
|
if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
|
||||||
FURI_LOG_W(TAG, "Skipped BT init: device in special startup mode");
|
FURI_LOG_W(TAG, "Skipping start in special boot mode");
|
||||||
ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT);
|
ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT);
|
||||||
furi_record_create(RECORD_BT, bt);
|
furi_record_create(RECORD_BT, bt);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ int32_t cli_srv(void* p) {
|
|||||||
if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) {
|
if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) {
|
||||||
cli_session_open(cli, &cli_vcp);
|
cli_session_open(cli, &cli_vcp);
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_W(TAG, "Skipped CLI session open: device in special startup mode");
|
FURI_LOG_W(TAG, "Skipping start in special boot mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|||||||
@@ -12,26 +12,48 @@
|
|||||||
// Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'`
|
// Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'`
|
||||||
#define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d"
|
#define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d"
|
||||||
|
|
||||||
void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) {
|
void cli_command_info_callback(const char* key, const char* value, bool last, void* context) {
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(last);
|
UNUSED(last);
|
||||||
|
UNUSED(context);
|
||||||
printf("%-30s: %s\r\n", key, value);
|
printf("%-30s: %s\r\n", key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/** Info Command
|
||||||
* Device Info Command
|
*
|
||||||
* This command is intended to be used by humans
|
* This command is intended to be used by humans
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* - device - print device info
|
||||||
|
* - power - print power info
|
||||||
|
* - power_debug - print power debug info
|
||||||
|
*
|
||||||
|
* @param cli The cli instance
|
||||||
|
* @param args The arguments
|
||||||
|
* @param context The context
|
||||||
*/
|
*/
|
||||||
void cli_command_device_info(Cli* cli, FuriString* args, void* context) {
|
void cli_command_info(Cli* cli, FuriString* args, void* context) {
|
||||||
UNUSED(cli);
|
UNUSED(cli);
|
||||||
UNUSED(args);
|
|
||||||
furi_hal_info_get(cli_command_device_info_callback, '_', context);
|
if(context) {
|
||||||
|
furi_hal_info_get(cli_command_info_callback, '_', NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!furi_string_cmp(args, "device")) {
|
||||||
|
furi_hal_info_get(cli_command_info_callback, '.', NULL);
|
||||||
|
} else if(!furi_string_cmp(args, "power")) {
|
||||||
|
furi_hal_power_info_get(cli_command_info_callback, '.', NULL);
|
||||||
|
} else if(!furi_string_cmp(args, "power_debug")) {
|
||||||
|
furi_hal_power_debug_get(cli_command_info_callback, NULL);
|
||||||
|
} else {
|
||||||
|
cli_print_usage("info", "<device|power|power_debug>", furi_string_get_cstr(args));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cli_command_help(Cli* cli, FuriString* args, void* context) {
|
void cli_command_help(Cli* cli, FuriString* args, void* context) {
|
||||||
UNUSED(args);
|
UNUSED(args);
|
||||||
UNUSED(context);
|
UNUSED(context);
|
||||||
printf("Commands we have:");
|
printf("Commands available:");
|
||||||
|
|
||||||
// Command count
|
// Command count
|
||||||
const size_t commands_count = CliCommandTree_size(cli->commands);
|
const size_t commands_count = CliCommandTree_size(cli->commands);
|
||||||
@@ -61,9 +83,9 @@ void cli_command_help(Cli* cli, FuriString* args, void* context) {
|
|||||||
|
|
||||||
if(furi_string_size(args) > 0) {
|
if(furi_string_size(args) > 0) {
|
||||||
cli_nl();
|
cli_nl();
|
||||||
printf("Also I have no clue what '");
|
printf("`");
|
||||||
printf("%s", furi_string_get_cstr(args));
|
printf("%s", furi_string_get_cstr(args));
|
||||||
printf("' is.");
|
printf("` command not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,8 +442,9 @@ void cli_command_i2c(Cli* cli, FuriString* args, void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cli_commands_init(Cli* cli) {
|
void cli_commands_init(Cli* cli) {
|
||||||
cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_device_info, NULL);
|
cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_info, (void*)true);
|
||||||
cli_add_command(cli, "device_info", CliCommandFlagParallelSafe, cli_command_device_info, NULL);
|
cli_add_command(cli, "info", CliCommandFlagParallelSafe, cli_command_info, NULL);
|
||||||
|
cli_add_command(cli, "device_info", CliCommandFlagParallelSafe, cli_command_info, (void*)true);
|
||||||
cli_add_command(cli, "src", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
cli_add_command(cli, "src", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
||||||
cli_add_command(cli, "source", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
cli_add_command(cli, "source", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ static StorageAnimation*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lucky_number = furi_hal_random_get() % (whole_weight != 0 ? whole_weight : 1);
|
uint32_t lucky_number = furi_hal_random_get() % whole_weight;
|
||||||
uint32_t weight = 0;
|
uint32_t weight = 0;
|
||||||
|
|
||||||
StorageAnimation* selected = NULL;
|
StorageAnimation* selected = NULL;
|
||||||
|
|||||||
@@ -325,7 +325,7 @@ static bool animation_storage_load_frames(
|
|||||||
FURI_CONST_ASSIGN(icon->width, width);
|
FURI_CONST_ASSIGN(icon->width, width);
|
||||||
icon->frames = malloc(sizeof(const uint8_t*) * icon->frame_count);
|
icon->frames = malloc(sizeof(const uint8_t*) * icon->frame_count);
|
||||||
|
|
||||||
bool frames_ok = true;
|
bool frames_ok = false;
|
||||||
File* file = storage_file_alloc(storage);
|
File* file = storage_file_alloc(storage);
|
||||||
FileInfo file_info;
|
FileInfo file_info;
|
||||||
FuriString* filename;
|
FuriString* filename;
|
||||||
@@ -333,41 +333,34 @@ static bool animation_storage_load_frames(
|
|||||||
size_t max_filesize = ROUND_UP_TO(width, 8) * height + 2;
|
size_t max_filesize = ROUND_UP_TO(width, 8) * height + 2;
|
||||||
|
|
||||||
for(int i = 0; i < icon->frame_count; ++i) {
|
for(int i = 0; i < icon->frame_count; ++i) {
|
||||||
FURI_CONST_ASSIGN_PTR(icon->frames[i], 0);
|
frames_ok = false;
|
||||||
if(frames_ok) {
|
furi_string_printf(filename, "%s/%s/frame_%d.bm", ANIMATION_DIR, name, i);
|
||||||
frames_ok = false;
|
|
||||||
furi_string_printf(filename, "%s/%s/frame_%d.bm", ANIMATION_DIR, name, i);
|
|
||||||
do {
|
|
||||||
if(storage_common_stat(storage, furi_string_get_cstr(filename), &file_info) !=
|
|
||||||
FSE_OK)
|
|
||||||
break;
|
|
||||||
if(file_info.size > max_filesize) {
|
|
||||||
FURI_LOG_E(
|
|
||||||
TAG,
|
|
||||||
"Filesize %lld, max: %d (width %d, height %d)",
|
|
||||||
file_info.size,
|
|
||||||
max_filesize,
|
|
||||||
width,
|
|
||||||
height);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!storage_file_open(
|
|
||||||
file, furi_string_get_cstr(filename), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
|
||||||
FURI_LOG_E(TAG, "Can't open file \'%s\'", furi_string_get_cstr(filename));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
FURI_CONST_ASSIGN_PTR(icon->frames[i], malloc(file_info.size));
|
if(storage_common_stat(storage, furi_string_get_cstr(filename), &file_info) != FSE_OK)
|
||||||
if(storage_file_read(file, (void*)icon->frames[i], file_info.size) !=
|
break;
|
||||||
file_info.size) {
|
if(file_info.size > max_filesize) {
|
||||||
FURI_LOG_E(TAG, "Read failed: \'%s\'", furi_string_get_cstr(filename));
|
FURI_LOG_E(
|
||||||
break;
|
TAG,
|
||||||
} else {
|
"Filesize %lld, max: %d (width %d, height %d)",
|
||||||
frames_ok = true;
|
file_info.size,
|
||||||
}
|
max_filesize,
|
||||||
storage_file_close(file);
|
width,
|
||||||
} while(0);
|
height);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if(!storage_file_open(
|
||||||
|
file, furi_string_get_cstr(filename), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||||
|
FURI_LOG_E(TAG, "Can't open file \'%s\'", furi_string_get_cstr(filename));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FURI_CONST_ASSIGN_PTR(icon->frames[i], malloc(file_info.size));
|
||||||
|
if(storage_file_read(file, (void*)icon->frames[i], file_info.size) != file_info.size) {
|
||||||
|
FURI_LOG_E(TAG, "Read failed: \'%s\'", furi_string_get_cstr(filename));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
storage_file_close(file);
|
||||||
|
frames_ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!frames_ok) {
|
if(!frames_ok) {
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#include "helpers/pin_lock.h"
|
#include "helpers/pin_lock.h"
|
||||||
#include "helpers/slideshow_filename.h"
|
#include "helpers/slideshow_filename.h"
|
||||||
|
|
||||||
|
#define TAG "Desktop"
|
||||||
|
|
||||||
static void desktop_auto_lock_arm(Desktop*);
|
static void desktop_auto_lock_arm(Desktop*);
|
||||||
static void desktop_auto_lock_inhibit(Desktop*);
|
static void desktop_auto_lock_inhibit(Desktop*);
|
||||||
static void desktop_start_auto_lock_timer(Desktop*);
|
static void desktop_start_auto_lock_timer(Desktop*);
|
||||||
@@ -304,43 +306,44 @@ int32_t desktop_srv(void* p) {
|
|||||||
UNUSED(p);
|
UNUSED(p);
|
||||||
|
|
||||||
if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
|
if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
|
||||||
FURI_LOG_W("Desktop", "Desktop load skipped. Device is in special startup mode.");
|
FURI_LOG_W(TAG, "Skipping start in special boot mode");
|
||||||
} else {
|
return 0;
|
||||||
Desktop* desktop = desktop_alloc();
|
|
||||||
|
|
||||||
bool loaded = DESKTOP_SETTINGS_LOAD(&desktop->settings);
|
|
||||||
if(!loaded) {
|
|
||||||
memset(&desktop->settings, 0, sizeof(desktop->settings));
|
|
||||||
DESKTOP_SETTINGS_SAVE(&desktop->settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
|
||||||
|
|
||||||
desktop_pin_lock_init(&desktop->settings);
|
|
||||||
|
|
||||||
if(!desktop_pin_lock_is_locked()) {
|
|
||||||
if(!loader_is_locked(desktop->loader)) {
|
|
||||||
desktop_auto_lock_arm(desktop);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
desktop_lock(desktop);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(desktop_check_file_flag(SLIDESHOW_FS_PATH)) {
|
|
||||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!furi_hal_version_do_i_belong_here()) {
|
|
||||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneHwMismatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(furi_hal_rtc_get_fault_data()) {
|
|
||||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
view_dispatcher_run(desktop->view_dispatcher);
|
|
||||||
desktop_free(desktop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Desktop* desktop = desktop_alloc();
|
||||||
|
|
||||||
|
bool loaded = DESKTOP_SETTINGS_LOAD(&desktop->settings);
|
||||||
|
if(!loaded) {
|
||||||
|
memset(&desktop->settings, 0, sizeof(desktop->settings));
|
||||||
|
DESKTOP_SETTINGS_SAVE(&desktop->settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
||||||
|
|
||||||
|
desktop_pin_lock_init(&desktop->settings);
|
||||||
|
|
||||||
|
if(!desktop_pin_lock_is_locked()) {
|
||||||
|
if(!loader_is_locked(desktop->loader)) {
|
||||||
|
desktop_auto_lock_arm(desktop);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
desktop_lock(desktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(desktop_check_file_flag(SLIDESHOW_FS_PATH)) {
|
||||||
|
scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!furi_hal_version_do_i_belong_here()) {
|
||||||
|
scene_manager_next_scene(desktop->scene_manager, DesktopSceneHwMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(furi_hal_rtc_get_fault_data()) {
|
||||||
|
scene_manager_next_scene(desktop->scene_manager, DesktopSceneFault);
|
||||||
|
}
|
||||||
|
|
||||||
|
view_dispatcher_run(desktop->view_dispatcher);
|
||||||
|
desktop_free(desktop);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include "applications/services/applications.h"
|
#include <applications.h>
|
||||||
#include <assets_icons.h>
|
#include <assets_icons.h>
|
||||||
#include <loader/loader.h>
|
#include <loader/loader.h>
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
|||||||
c2_ver ? c2_ver->StackTypeString : "<none>");
|
c2_ver ? c2_ver->StackTypeString : "<none>");
|
||||||
canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer);
|
canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer);
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), "dev");
|
snprintf(
|
||||||
|
buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), version_get_gitbranch(ver));
|
||||||
canvas_draw_str(canvas, 0, 50 + STATUS_BAR_Y_SHIFT, buffer);
|
canvas_draw_str(canvas, 0, 50 + STATUS_BAR_Y_SHIFT, buffer);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
#include <assets_icons.h>
|
#include <assets_icons.h>
|
||||||
|
|
||||||
#include "../desktop_i.h"
|
#include "../desktop_i.h"
|
||||||
#include "desktop_view_lock_menu.h"
|
#include "desktop_view_lock_menu.h"
|
||||||
#include "xtreme/settings.h"
|
|
||||||
|
|
||||||
#define LOCK_MENU_ITEMS_NB 5
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DesktopLockMenuIndexLock,
|
DesktopLockMenuIndexLock,
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ DesktopMainView* desktop_main_alloc() {
|
|||||||
DesktopMainView* main_view = malloc(sizeof(DesktopMainView));
|
DesktopMainView* main_view = malloc(sizeof(DesktopMainView));
|
||||||
|
|
||||||
main_view->view = view_alloc();
|
main_view->view = view_alloc();
|
||||||
view_allocate_model(main_view->view, ViewModelTypeLockFree, 1);
|
|
||||||
view_set_context(main_view->view, main_view);
|
view_set_context(main_view->view, main_view);
|
||||||
view_set_input_callback(main_view->view, desktop_main_input_callback);
|
view_set_input_callback(main_view->view, desktop_main_input_callback);
|
||||||
|
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) {
|
|||||||
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT);
|
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT);
|
||||||
} else if(event->type == InputTypeRelease) {
|
} else if(event->type == InputTypeRelease) {
|
||||||
furi_timer_stop(instance->timer);
|
furi_timer_stop(instance->timer);
|
||||||
// if(!slideshow_is_one_page(model->slideshow)) {
|
/*if(!slideshow_is_one_page(model->slideshow)) {
|
||||||
// furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG);
|
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG);
|
||||||
// }
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
view_commit_model(instance->view, update_view);
|
view_commit_model(instance->view, update_view);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include "furi_hal_random.h"
|
|
||||||
#include <xtreme/settings.h>
|
#include <xtreme/settings.h>
|
||||||
#define DOLPHIN_LOCK_EVENT_FLAG (0x1)
|
#define DOLPHIN_LOCK_EVENT_FLAG (0x1)
|
||||||
|
|
||||||
@@ -23,18 +22,6 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) {
|
|||||||
dolphin_event_send_async(dolphin, &event);
|
dolphin_event_send_async(dolphin, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
DolphinDeed getRandomDeed() {
|
|
||||||
DolphinDeed returnGrp[14] = {1, 5, 8, 10, 12, 15, 17, 20, 21, 25, 26, 28, 29, 32};
|
|
||||||
static bool rand_generator_inited = false;
|
|
||||||
if(!rand_generator_inited) {
|
|
||||||
srand(furi_get_tick());
|
|
||||||
rand_generator_inited = true;
|
|
||||||
}
|
|
||||||
uint8_t diceRoll = (rand() % COUNT_OF(returnGrp)); // JUST TO GET IT GOING? AND FIX BUG
|
|
||||||
diceRoll = (rand() % COUNT_OF(returnGrp));
|
|
||||||
return returnGrp[diceRoll];
|
|
||||||
}
|
|
||||||
|
|
||||||
DolphinStats dolphin_stats(Dolphin* dolphin) {
|
DolphinStats dolphin_stats(Dolphin* dolphin) {
|
||||||
furi_assert(dolphin);
|
furi_assert(dolphin);
|
||||||
|
|
||||||
@@ -173,6 +160,12 @@ static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin) {
|
|||||||
|
|
||||||
int32_t dolphin_srv(void* p) {
|
int32_t dolphin_srv(void* p) {
|
||||||
UNUSED(p);
|
UNUSED(p);
|
||||||
|
|
||||||
|
if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
|
||||||
|
FURI_LOG_W(TAG, "Skipping start in special boot mode");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Dolphin* dolphin = dolphin_alloc();
|
Dolphin* dolphin = dolphin_alloc();
|
||||||
furi_record_create(RECORD_DOLPHIN, dolphin);
|
furi_record_create(RECORD_DOLPHIN, dolphin);
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,6 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed);
|
|||||||
*/
|
*/
|
||||||
DolphinStats dolphin_stats(Dolphin* dolphin);
|
DolphinStats dolphin_stats(Dolphin* dolphin);
|
||||||
|
|
||||||
/** GET RANDOM 3PT DEED
|
|
||||||
*/
|
|
||||||
DolphinDeed getRandomDeed();
|
|
||||||
|
|
||||||
/** Flush dolphin queue and save state
|
/** Flush dolphin queue and save state
|
||||||
* Thread safe, blocking
|
* Thread safe, blocking
|
||||||
*/
|
*/
|
||||||
|
|||||||