diff --git a/CHANGELOG.md b/CHANGELOG.md index acaef9411..faa145a8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,11 @@ - NFC: - Added 6 new Mifare Classic keys from Bulgaria Hotel (#216 by @z3r0l1nk) - OFW: Rename 'Detect Reader' to 'Extract MF Keys' (by @bettse) +- Sub-GHz: + - UL: Frequency analyzer fixes and improvements (by @xMasterX): + - Enforce int module (like in OFW) usage due to lack of required hardware on external boards (PathIsolate (+rf switch for multiple paths)) and incorrect usage and/or understanding the purpose of frequency analyzer app by users, it should be used only to get frequency of the remote placed around 1-10cm around flipper's left corner + - Fix possible GSM mobile towers signal interference by limiting upper frequency to 920mhz max + - Fix duplicated frequency lists and use user config for nearest frequency selector too - Infrared: - OFW: IR button operation fails now shows more informative messages (by @RebornedBrain) - OFW: Add Airwell AW-HKD012-N91 to univeral AC remote (by @valeraOlexienko) @@ -56,7 +61,9 @@ - OFW: Fix detection of GProx II cards and false detection of other cards (by @Astrrra) - OFW: Fix Guard GProxII False Positive and 36-bit Parsing (by @zinongli) - OFW: GProxII Fix Writing and Rendering Conflict (by @zinongli) -- Desktop: Fallback Poweroff prompt when power settings is unavailable (by @Willy-JL) +- Desktop: + - Fallback Poweroff prompt when power settings is unavailable (by @Willy-JL) + - OFW: Autolock fixes (by @portasynthinca3) - Storage: - Fallback SD format prompt when storage settings is unavailable (by @Willy-JL) - OFW: Fix folder rename fails (by @portasynthinca3) diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index 00ce0fb04..3894f022f 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -132,11 +132,8 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { uint32_t current_frequency = subghz_setting_get_frequency(instance->setting, i); // if(furi_hal_subghz_is_frequency_valid(current_frequency) && if(subghz_devices_is_frequency_valid(radio_device, current_frequency) && - (current_frequency != 467750000) && (current_frequency != 464000000) && - !((instance->ext_radio) && - ((current_frequency == 390000000) || (current_frequency == 312000000) || - (current_frequency == 312100000) || (current_frequency == 312200000) || - (current_frequency == 440175000)))) { + (((current_frequency != 467750000) && (current_frequency != 464000000)) && + (current_frequency <= 920000000))) { furi_hal_spi_acquire(spi_bus); cc1101_switch_to_idle(spi_bus); frequency = cc1101_set_frequency(spi_bus, current_frequency); @@ -323,18 +320,21 @@ void subghz_frequency_analyzer_worker_start( furi_assert(instance); furi_assert(!instance->worker_running); + /* SubGhzRadioDeviceType radio_type = subghz_txrx_radio_device_get(txrx); if(radio_type == SubGhzRadioDeviceTypeExternalCC1101) { instance->spi_bus = &furi_hal_spi_bus_handle_external; instance->ext_radio = true; } else if(radio_type == SubGhzRadioDeviceTypeInternal) { - instance->spi_bus = &furi_hal_spi_bus_handle_subghz; - instance->ext_radio = false; + */ + instance->spi_bus = &furi_hal_spi_bus_handle_subghz; + /* + instance->ext_radio = false; } else { - furi_crash("Unsuported external module"); + furi_crash("Wrong subghz radio type"); } - + */ instance->radio_device = subghz_devices_get_by_name(subghz_txrx_radio_device_get_name(txrx)); instance->worker_running = true; @@ -365,3 +365,33 @@ void subghz_frequency_analyzer_worker_set_trigger_level( float subghz_frequency_analyzer_worker_get_trigger_level(SubGhzFrequencyAnalyzerWorker* instance) { return instance->trigger_level; } + +uint32_t subghz_frequency_analyzer_get_nearest_frequency( + SubGhzFrequencyAnalyzerWorker* instance, + uint32_t input) { + uint32_t prev_freq = 0; + uint32_t result = 0; + uint32_t current; + + for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) { + current = subghz_setting_get_frequency(instance->setting, i); + if(current == 0) { + continue; + } + if(current == input) { + result = current; + break; + } + if(current > input && prev_freq < input) { + if(current - input < input - prev_freq) { + result = current; + } else { + result = prev_freq; + } + break; + } + prev_freq = current; + } + + return result; +} diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h index 1b21c39e9..6533571d5 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h @@ -78,3 +78,8 @@ void subghz_frequency_analyzer_worker_set_trigger_level( * @return RSSI trigger level */ float subghz_frequency_analyzer_worker_get_trigger_level(SubGhzFrequencyAnalyzerWorker* instance); + +// Round up the frequency +uint32_t subghz_frequency_analyzer_get_nearest_frequency( + SubGhzFrequencyAnalyzerWorker* instance, + uint32_t input); diff --git a/applications/main/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c index fde3a1f61..2ce2dfbbf 100644 --- a/applications/main/subghz/views/subghz_frequency_analyzer.c +++ b/applications/main/subghz/views/subghz_frequency_analyzer.c @@ -20,71 +20,6 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #endif -static const uint32_t subghz_frequency_list[] = { - /* 300 - 348 */ - 300000000, - 302757000, - 303875000, - 303900000, - 304250000, - 307000000, - 307500000, - 307800000, - 309000000, - 310000000, - 312000000, - 312100000, - 312200000, - 313000000, - 313850000, - 314000000, - 314350000, - 314980000, - 315000000, - 318000000, - 330000000, - 345000000, - 348000000, - 350000000, - - /* 387 - 464 */ - 387000000, - 390000000, - 418000000, - 430000000, - 430500000, - 431000000, - 431500000, - 433075000, /* LPD433 first */ - 433220000, - 433420000, - 433657070, - 433889000, - 433920000, /* LPD433 mid */ - 434075000, - 434176948, - 434190000, - 434390000, - 434420000, - 434620000, - 434775000, /* LPD433 last channels */ - 438900000, - 440175000, - 464000000, - 467750000, - - /* 779 - 928 */ - 779000000, - 868350000, - 868400000, - 868800000, - 868950000, - 906400000, - 915000000, - 925000000, - 928000000, -}; - typedef enum { SubGhzFrequencyAnalyzerStatusIDLE, } SubGhzFrequencyAnalyzerStatus; @@ -225,7 +160,7 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 0, 7, model->is_ext_radio ? "Ext" : "Int"); + //canvas_draw_str(canvas, 0, 7, model->is_ext_radio ? "Ext" : "Int"); canvas_draw_str(canvas, 20, 7, "Frequency Analyzer"); // RSSI @@ -278,34 +213,6 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel elements_button_right(canvas, "+T"); } -uint32_t subghz_frequency_find_correct(uint32_t input) { - uint32_t prev_freq = 0; - uint32_t result = 0; - uint32_t current; - - for(size_t i = 0; i < ARRAY_SIZE(subghz_frequency_list) - 1; i++) { - current = subghz_frequency_list[i]; - if(current == 0) { - continue; - } - if(current == input) { - result = current; - break; - } - if(current > input && prev_freq < input) { - if(current - input < input - prev_freq) { - result = current; - } else { - result = prev_freq; - } - break; - } - prev_freq = current; - } - - return result; -} - bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { furi_assert(context); SubGhzFrequencyAnalyzer* instance = (SubGhzFrequencyAnalyzer*)context; @@ -364,7 +271,8 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { } else if( (model->show_frame && model->signal) || (!model->show_frame && model->signal)) { - frequency_candidate = subghz_frequency_find_correct(model->frequency); + frequency_candidate = subghz_frequency_analyzer_get_nearest_frequency( + instance->worker, model->frequency); } frequency_candidate = frequency_candidate == 0 || @@ -372,7 +280,8 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { instance->txrx, frequency_candidate) || prev_freq_to_save == frequency_candidate ? 0 : - subghz_frequency_find_correct(frequency_candidate); + subghz_frequency_analyzer_get_nearest_frequency( + instance->worker, frequency_candidate); if(frequency_candidate > 0 && frequency_candidate != model->frequency_to_save) { model->frequency_to_save = frequency_candidate; updated = true; @@ -445,7 +354,8 @@ void subghz_frequency_analyzer_pair_callback( SubGhzFrequencyAnalyzerModel * model, { bool in_array = false; - uint32_t normal_frequency = subghz_frequency_find_correct(model->frequency); + uint32_t normal_frequency = subghz_frequency_analyzer_get_nearest_frequency( + instance->worker, model->frequency); for(size_t i = 0; i < MAX_HISTORY; i++) { if(model->history_frequency[i] == normal_frequency) { in_array = true; diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index cdabaaa05..a74710284 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -2,6 +2,10 @@ #include #include #include +#include +#include +#include +#include #define TAG "CliVcp" @@ -43,6 +47,13 @@ typedef struct { FuriHalUsbInterface* usb_if_prev; uint8_t data_buffer[USB_CDC_PKT_LEN]; + + // CLI icon + Gui* gui; + ViewPort* view_port; + + // Autolocking inhibition + Desktop* desktop; } CliVcp; static int32_t vcp_worker(void* context); @@ -64,6 +75,13 @@ static CliVcp* vcp = NULL; static const uint8_t ascii_soh = 0x01; static const uint8_t ascii_eot = 0x04; +static void cli_vcp_icon_draw_callback(Canvas* canvas, void* context) { + furi_assert(canvas); + furi_assert(context); + const Icon* icon = context; + canvas_draw_icon(canvas, 0, 0, icon); +} + static void cli_vcp_init(void) { if(vcp == NULL) { vcp = malloc(sizeof(CliVcp)); @@ -103,6 +121,15 @@ static int32_t vcp_worker(void* context) { FURI_LOG_D(TAG, "Start"); vcp->running = true; + // GUI icon + vcp->desktop = furi_record_open(RECORD_DESKTOP); + const Icon* icon = &I_Console_active_8x8; + vcp->gui = furi_record_open(RECORD_GUI); + vcp->view_port = view_port_alloc(); + view_port_set_width(vcp->view_port, icon_get_width(icon)); + // casting const away. we know that we cast it right back in the callback + view_port_draw_callback_set(vcp->view_port, cli_vcp_icon_draw_callback, (void*)icon); + while(1) { uint32_t flags = furi_thread_flags_wait(VCP_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); @@ -115,6 +142,8 @@ static int32_t vcp_worker(void* context) { if(vcp->connected == false) { vcp->connected = true; furi_stream_buffer_send(vcp->rx_stream, &ascii_soh, 1, FuriWaitForever); + gui_add_view_port(vcp->gui, vcp->view_port, GuiLayerStatusBarLeft); + desktop_api_add_external_inhibitor(vcp->desktop); } } @@ -126,6 +155,8 @@ static int32_t vcp_worker(void* context) { vcp->connected = false; furi_stream_buffer_receive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0); furi_stream_buffer_send(vcp->rx_stream, &ascii_eot, 1, FuriWaitForever); + gui_remove_view_port(vcp->gui, vcp->view_port); + desktop_api_remove_external_inhibitor(vcp->desktop); } } @@ -190,6 +221,10 @@ static int32_t vcp_worker(void* context) { } if(flags & VcpEvtStop) { + if(vcp->connected) { + gui_remove_view_port(vcp->gui, vcp->view_port); + desktop_api_remove_external_inhibitor(vcp->desktop); + } vcp->connected = false; vcp->running = false; furi_hal_cdc_set_callbacks(VCP_IF_NUM, NULL, NULL); @@ -203,6 +238,11 @@ static int32_t vcp_worker(void* context) { break; } } + + view_port_free(vcp->view_port); + furi_record_close(RECORD_DESKTOP); + furi_record_close(RECORD_GUI); + FURI_LOG_D(TAG, "End"); return 0; } diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index d618f14df..02834a901 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -20,6 +20,8 @@ static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); static void desktop_apply_settings(Desktop*); +static void desktop_auto_lock_add_inhibitor(Desktop* desktop); +static void desktop_auto_lock_remove_inhibitor(Desktop* desktop); static void desktop_loader_callback(const void* message, void* context) { furi_assert(context); @@ -125,16 +127,22 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { animation_manager_unload_and_stall_animation(desktop->animation_manager); } - desktop_auto_lock_inhibit(desktop); + desktop_auto_lock_add_inhibitor(desktop); desktop->app_running = true; furi_semaphore_release(desktop->animation_semaphore); } else if(event == DesktopGlobalAfterAppFinished) { animation_manager_load_and_continue_animation(desktop->animation_manager); - desktop_auto_lock_arm(desktop); + desktop_auto_lock_remove_inhibitor(desktop); desktop->app_running = false; + } else if(event == DesktopGlobalAddExternalInhibitor) { + desktop_auto_lock_add_inhibitor(desktop); + + } else if(event == DesktopGlobalRemoveExternalInhibitor) { + desktop_auto_lock_remove_inhibitor(desktop); + } else if(event == DesktopGlobalAutoLock) { if(!desktop->app_running && !desktop->locked) { desktop_lock(desktop, desktop->settings.auto_lock_with_pin); @@ -205,6 +213,24 @@ static void desktop_auto_lock_arm(Desktop* desktop) { } } +static void desktop_auto_lock_add_inhibitor(Desktop* desktop) { + furi_check(furi_semaphore_release(desktop->auto_lock_inhibitors) == FuriStatusOk); + FURI_LOG_D( + TAG, + "%lu autolock inhibitors (+1)", + furi_semaphore_get_count(desktop->auto_lock_inhibitors)); + desktop_auto_lock_inhibit(desktop); +} + +static void desktop_auto_lock_remove_inhibitor(Desktop* desktop) { + furi_check(furi_semaphore_acquire(desktop->auto_lock_inhibitors, 0) == FuriStatusOk); + uint32_t inhibitors = furi_semaphore_get_count(desktop->auto_lock_inhibitors); + FURI_LOG_D(TAG, "%lu autolock inhibitors (-1)", inhibitors); + if(inhibitors == 0) { + desktop_auto_lock_arm(desktop); + } +} + static void desktop_auto_lock_inhibit(Desktop* desktop) { desktop_stop_auto_lock_timer(desktop); if(desktop->input_events_subscription) { @@ -361,6 +387,7 @@ static Desktop* desktop_alloc(void) { desktop->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS); desktop->ascii_events_pubsub = furi_record_open(RECORD_ASCII_EVENTS); + desktop->auto_lock_inhibitors = furi_semaphore_alloc(UINT32_MAX, 0); desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); @@ -519,6 +546,18 @@ void desktop_api_set_settings(Desktop* instance, const DesktopSettings* settings view_dispatcher_send_custom_event(instance->view_dispatcher, DesktopGlobalSaveSettings); } +void desktop_api_add_external_inhibitor(Desktop* instance) { + furi_assert(instance); + view_dispatcher_send_custom_event( + instance->view_dispatcher, DesktopGlobalAddExternalInhibitor); +} + +void desktop_api_remove_external_inhibitor(Desktop* instance) { + furi_assert(instance); + view_dispatcher_send_custom_event( + instance->view_dispatcher, DesktopGlobalRemoveExternalInhibitor); +} + /* * Application thread */ diff --git a/applications/services/desktop/desktop.h b/applications/services/desktop/desktop.h index e83bc3ee4..4f1556f7c 100644 --- a/applications/services/desktop/desktop.h +++ b/applications/services/desktop/desktop.h @@ -21,3 +21,17 @@ FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance); void desktop_api_get_settings(Desktop* instance, DesktopSettings* settings); void desktop_api_set_settings(Desktop* instance, const DesktopSettings* settings); + +/** + * @brief Adds 1 to the count of active external autolock inhibitors + * + * Autolocking will not get triggered while there's at least 1 inhibitor + */ +void desktop_api_add_external_inhibitor(Desktop* instance); + +/** + * @brief Removes 1 from the count of active external autolock inhibitors + * + * Autolocking will not get triggered while there's at least 1 inhibitor + */ +void desktop_api_remove_external_inhibitor(Desktop* instance); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index 10badcc07..46b35054c 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -74,6 +74,7 @@ struct Desktop { FuriPubSub* input_events_pubsub; FuriPubSubSubscription* input_events_subscription; + FuriSemaphore* auto_lock_inhibitors; FuriTimer* auto_lock_timer; FuriTimer* update_clock_timer; diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index 3f2896912..cbacb8545 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -58,6 +58,8 @@ typedef enum { DesktopGlobalApiUnlock, DesktopGlobalSaveSettings, DesktopGlobalReloadSettings, + DesktopGlobalAddExternalInhibitor, + DesktopGlobalRemoveExternalInhibitor, DesktopMainEventLockKeypad, DesktopLockedEventOpenPowerOff, diff --git a/assets/icons/StatusBar/Console_active_8x8.png b/assets/icons/StatusBar/Console_active_8x8.png new file mode 100644 index 000000000..f2230a374 Binary files /dev/null and b/assets/icons/StatusBar/Console_active_8x8.png differ diff --git a/documentation/SubGHzSettings.md b/documentation/SubGHzSettings.md index 770c3b84e..5454ede00 100644 --- a/documentation/SubGHzSettings.md +++ b/documentation/SubGHzSettings.md @@ -42,6 +42,8 @@ if you need your custom one, make sure it doesn't listed here 314980000, 315000000, 318000000, + 320000000, + 320150000, 330000000, 345000000, 348000000, diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index be09c511e..63e034d61 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -32,6 +32,8 @@ static const uint32_t subghz_frequency_list[] = { 314980000, 315000000, 318000000, + 320000000, + 320150000, 330000000, 345000000, 348000000, diff --git a/scripts/serial_cli.py b/scripts/serial_cli.py index 8e35d57fa..a48647bd5 100644 --- a/scripts/serial_cli.py +++ b/scripts/serial_cli.py @@ -13,7 +13,9 @@ def main(): parser.add_argument("-p", "--port", help="CDC Port", default="auto") args = parser.parse_args() if not (port := resolve_port(logger, args.port)): - logger.error("Is Flipper connected via USB and not in DFU mode?") + logger.error( + "Is Flipper connected via USB, currently unlocked and not in DFU mode?" + ) return 1 subprocess.call( [ diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index f71e6d341..70fbad27a 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -3911,6 +3911,7 @@ Variable,+,I_Circles_47x47,const Icon, Variable,+,I_Clock_18x18,const Icon, Variable,+,I_Connect_me_62x31,const Icon, Variable,+,I_Connected_62x31,const Icon, +Variable,+,I_Console_active_8x8,const Icon, Variable,+,I_Cos_9x7,const Icon, Variable,+,I_DFU_128x50,const Icon, Variable,+,I_DolphinDone_80x58,const Icon,