From c341cc128c8de24a58f67304aa0bba135fb881e4 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 4 May 2023 03:32:53 +0100 Subject: [PATCH 01/14] Bozo moment --- .github/workflow_data/hotfix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflow_data/hotfix.py b/.github/workflow_data/hotfix.py index cb454ae56f..0a5c6793d0 100644 --- a/.github/workflow_data/hotfix.py +++ b/.github/workflow_data/hotfix.py @@ -71,7 +71,7 @@ body = body.replace("", "") insert = body.find("\n [//]: \n") - body = body[:insert] + hotfix + body[:insert] + body = body[:insert] + hotfix + body[insert:] req = requests.patch( release["url"], From d2ca67d261217f445abaf9b3cb0926250d1385a9 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 4 May 2023 07:04:26 +0400 Subject: [PATCH 02/14] [FL-3242] SubGhz: refactoring app (#2554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add SubGhzThresholdRssi * SubGhz: remove direct reading of subghz-txrx-txrx_state * SubGhz: remove direct reading subghz->txrx->hopper_state * SubGhz: remove direct reading subghz->lock * SubGhz: check load type file * SubGhz: remove direct reading subghz->txrx->rx_key_state * SubGhz: remove direct reading subghz->txrx->speaker_state * SubGhz: refactoring subghz_scene_set_type.c * SubGhz: moving "txrx" entity to a separate file * SubGhz: show error tx start * SubGhz: refactoring RPC * SubGhz: value get optimizations * SubGhz: fix name file * SubGhz: add function description * SubGhz: fix double back with a blocked transmission in this region and speacker, when a transmission is blocked in this region * SubGhz: correct spelling * SubGhz: better naming * SubGhz: simplify includes Co-authored-by: SG Co-authored-by: あく --- .../views/weather_station_receiver.c | 6 +- .../main/subghz/helpers/subghz_custom_event.h | 5 +- .../subghz_frequency_analyzer_worker.c | 2 +- .../subghz/helpers/subghz_threshold_rssi.c | 60 ++ .../subghz/helpers/subghz_threshold_rssi.h | 43 ++ .../main/subghz/helpers/subghz_txrx.c | 521 ++++++++++++++++++ .../main/subghz/helpers/subghz_txrx.h | 290 ++++++++++ .../helpers/subghz_txrx_create_potocol_key.c | 164 ++++++ .../helpers/subghz_txrx_create_potocol_key.h | 96 ++++ .../main/subghz/helpers/subghz_txrx_i.h | 27 + .../main/subghz/helpers/subghz_types.h | 7 + .../main/subghz/scenes/subghz_scene_delete.c | 4 +- .../subghz/scenes/subghz_scene_delete_raw.c | 2 +- .../subghz/scenes/subghz_scene_need_saving.c | 18 +- .../subghz/scenes/subghz_scene_read_raw.c | 229 +++----- .../subghz/scenes/subghz_scene_receiver.c | 122 ++-- .../scenes/subghz_scene_receiver_config.c | 133 +++-- .../scenes/subghz_scene_receiver_info.c | 112 ++-- .../subghz/scenes/subghz_scene_region_info.c | 3 +- .../main/subghz/scenes/subghz_scene_rpc.c | 20 +- .../subghz/scenes/subghz_scene_save_name.c | 16 +- .../subghz/scenes/subghz_scene_save_success.c | 4 +- .../main/subghz/scenes/subghz_scene_saved.c | 4 +- .../subghz/scenes/subghz_scene_set_type.c | 255 ++------- .../subghz/scenes/subghz_scene_show_error.c | 11 +- .../main/subghz/scenes/subghz_scene_start.c | 2 +- .../subghz/scenes/subghz_scene_transmitter.c | 46 +- applications/main/subghz/subghz.c | 95 +--- applications/main/subghz/subghz_i.c | 403 +++----------- applications/main/subghz/subghz_i.h | 76 +-- applications/main/subghz/views/receiver.c | 23 +- applications/main/subghz/views/receiver.h | 2 +- .../main/subghz/views/subghz_read_raw.c | 8 +- .../main/subghz/views/subghz_read_raw.h | 2 +- applications/main/subghz/views/transmitter.c | 6 +- applications/main/subghz/views/transmitter.h | 2 +- lib/subghz/environment.c | 2 + 37 files changed, 1704 insertions(+), 1117 deletions(-) create mode 100644 applications/main/subghz/helpers/subghz_threshold_rssi.c create mode 100644 applications/main/subghz/helpers/subghz_threshold_rssi.h create mode 100644 applications/main/subghz/helpers/subghz_txrx.c create mode 100644 applications/main/subghz/helpers/subghz_txrx.h create mode 100644 applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c create mode 100644 applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h create mode 100644 applications/main/subghz/helpers/subghz_txrx_i.h diff --git a/applications/external/weather_station/views/weather_station_receiver.c b/applications/external/weather_station/views/weather_station_receiver.c index f8e2e32889..c4ce1627ec 100644 --- a/applications/external/weather_station/views/weather_station_receiver.c +++ b/applications/external/weather_station/views/weather_station_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { instance->view, WSReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 765c9e251c..285b4a60f9 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -6,14 +6,13 @@ typedef enum { SubGhzCustomEventManagerSetRAW, //SubmenuIndex - SubmenuIndexPricenton, + SubmenuIndexPricenton_433, + SubmenuIndexPricenton_315, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, SubmenuIndexCAME12bit, SubmenuIndexCAME24bit, SubmenuIndexCAMETwee, - SubmenuIndexNeroSketch, - SubmenuIndexNeroRadio, SubmenuIndexGateTX, SubmenuIndexDoorHan_315_00, SubmenuIndexDoorHan_433_92, diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index 5d1a80a395..4a4445faad 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -261,7 +261,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont instance->thread = furi_thread_alloc_ex( "SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance); SubGhz* subghz = context; - instance->setting = subghz->setting; + instance->setting = subghz_txrx_get_setting(subghz->txrx); return instance; } diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.c b/applications/main/subghz/helpers/subghz_threshold_rssi.c new file mode 100644 index 0000000000..04a06bc173 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.c @@ -0,0 +1,60 @@ +#include "subghz_threshold_rssi.h" +#include +#include "../subghz_i.h" + +#define TAG "SubGhzThresholdRssi" +#define THRESHOLD_RSSI_LOW_COUNT 10 + +struct SubGhzThresholdRssi { + float threshold_rssi; + uint8_t threshold_rssi_low_count; +}; + +SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void) { + SubGhzThresholdRssi* instance = malloc(sizeof(SubGhzThresholdRssi)); + instance->threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN; + instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT; + return instance; +} + +void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance) { + furi_assert(instance); + free(instance); +} + +void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi) { + furi_assert(instance); + instance->threshold_rssi = rssi; +} + +float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) { + furi_assert(instance); + return instance->threshold_rssi; +} + +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) { + furi_assert(instance); + float rssi = furi_hal_subghz_get_rssi(); + SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false}; + + if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) { + ret.is_above = true; + } else { + if(rssi < instance->threshold_rssi) { + instance->threshold_rssi_low_count++; + if(instance->threshold_rssi_low_count > THRESHOLD_RSSI_LOW_COUNT) { + instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT; + } + ret.is_above = false; + } else { + instance->threshold_rssi_low_count = 0; + } + + if(instance->threshold_rssi_low_count == THRESHOLD_RSSI_LOW_COUNT) { + ret.is_above = false; + } else { + ret.is_above = true; + } + } + return ret; +} diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.h b/applications/main/subghz/helpers/subghz_threshold_rssi.h new file mode 100644 index 0000000000..e28092acbc --- /dev/null +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +typedef struct { + float rssi; /**< Current RSSI */ + bool is_above; /**< Exceeded threshold level */ +} SubGhzThresholdRssiData; + +typedef struct SubGhzThresholdRssi SubGhzThresholdRssi; + +/** Allocate SubGhzThresholdRssi + * + * @return SubGhzThresholdRssi* + */ +SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void); + +/** Free SubGhzThresholdRssi + * + * @param instance Pointer to a SubGhzThresholdRssi + */ +void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance); + +/** Set threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @param rssi RSSI threshold + */ +void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi); + +/** Get threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @return float RSSI threshold + */ +float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance); + +/** Check threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @return SubGhzThresholdRssiData + */ +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance); diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c new file mode 100644 index 0000000000..1517cb9989 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -0,0 +1,521 @@ +#include "subghz_txrx_i.h" + +#include + +#define TAG "SubGhz" + +SubGhzTxRx* subghz_txrx_alloc() { + SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx)); + instance->setting = subghz_setting_alloc(); + subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user")); + + instance->preset = malloc(sizeof(SubGhzRadioPreset)); + instance->preset->name = furi_string_alloc(); + subghz_txrx_set_preset( + instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0); + + instance->txrx_state = SubGhzTxRxStateSleep; + + subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF); + subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable); + + instance->worker = subghz_worker_alloc(); + instance->fff_data = flipper_format_string_alloc(); + + instance->environment = subghz_environment_alloc(); + instance->is_database_loaded = subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_set_came_atomo_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + subghz_environment_set_nice_flor_s_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/nice_flor_s")); + subghz_environment_set_protocol_registry( + instance->environment, (void*)&subghz_protocol_registry); + instance->receiver = subghz_receiver_alloc_init(instance->environment); + + subghz_worker_set_overrun_callback( + instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); + subghz_worker_set_pair_callback( + instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); + subghz_worker_set_context(instance->worker, instance->receiver); + + return instance; +} + +void subghz_txrx_free(SubGhzTxRx* instance) { + furi_assert(instance); + + subghz_worker_free(instance->worker); + subghz_receiver_free(instance->receiver); + subghz_environment_free(instance->environment); + flipper_format_free(instance->fff_data); + furi_string_free(instance->preset->name); + subghz_setting_free(instance->setting); + free(instance->preset); + free(instance); +} + +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->is_database_loaded; +} + +void subghz_txrx_set_preset( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size) { + furi_assert(instance); + furi_string_set(instance->preset->name, preset_name); + SubGhzRadioPreset* preset = instance->preset; + preset->frequency = frequency; + preset->data = preset_data; + preset->data_size = preset_data_size; +} + +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) { + UNUSED(instance); + const char* preset_name = ""; + if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { + preset_name = "AM270"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { + preset_name = "AM650"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { + preset_name = "FM238"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { + preset_name = "FM476"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { + preset_name = "CUSTOM"; + } else { + FURI_LOG_E(TAG, "Unknown preset"); + } + return preset_name; +} + +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) { + furi_assert(instance); + return *instance->preset; +} + +void subghz_txrx_get_frequency_and_modulation( + SubGhzTxRx* instance, + FuriString* frequency, + FuriString* modulation) { + furi_assert(instance); + SubGhzRadioPreset* preset = instance->preset; + if(frequency != NULL) { + furi_string_printf( + frequency, + "%03ld.%02ld", + preset->frequency / 1000000 % 1000, + preset->frequency / 10000 % 100); + } + if(modulation != NULL) { + furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name)); + } +} + +static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) { + furi_assert(instance); + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(preset_data); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect RX frequency."); + } + furi_assert( + instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep); + + furi_hal_subghz_idle(); + uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_subghz_flush_rx(); + subghz_txrx_speaker_on(instance); + furi_hal_subghz_rx(); + + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker); + subghz_worker_start(instance->worker); + instance->txrx_state = SubGhzTxRxStateRx; + return value; +} + +static void subghz_txrx_idle(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static void subghz_txrx_rx_end(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateRx); + + if(subghz_worker_is_running(instance->worker)) { + subghz_worker_stop(instance->worker); + furi_hal_subghz_stop_async_rx(); + } + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +void subghz_txrx_sleep(SubGhzTxRx* instance) { + furi_assert(instance); + furi_hal_subghz_sleep(); + instance->txrx_state = SubGhzTxRxStateSleep; +} + +static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect TX frequency."); + } + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_write(&gpio_cc1101_g0, false); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + bool ret = furi_hal_subghz_tx(); + if(ret) { + subghz_txrx_speaker_on(instance); + instance->txrx_state = SubGhzTxRxStateTx; + } + + return ret; +} + +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) { + furi_assert(instance); + furi_assert(flipper_format); + + subghz_txrx_stop(instance); + + SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers; + FuriString* temp_str = furi_string_alloc(); + uint32_t repeat = 200; + do { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + ret = SubGhzTxRxStartTxStateOk; + + SubGhzRadioPreset* preset = instance->preset; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str)); + + if(instance->transmitter) { + if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) == + SubGhzProtocolStatusOk) { + if(strcmp(furi_string_get_cstr(preset->name), "") != 0) { + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + instance->setting, furi_string_get_cstr(preset->name))); + if(preset->frequency) { + if(!subghz_txrx_tx(instance, preset->frequency)) { + FURI_LOG_E(TAG, "Only Rx"); + ret = SubGhzTxRxStartTxStateErrorOnlyRx; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + } else { + FURI_LOG_E( + TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name)); + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + if(ret == SubGhzTxRxStartTxStateOk) { + //Start TX + furi_hal_subghz_start_async_tx( + subghz_transmitter_yield, instance->transmitter); + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + if(ret != SubGhzTxRxStartTxStateOk) { + subghz_transmitter_free(instance->transmitter); + if(instance->txrx_state != SubGhzTxRxStateIDLE) { + subghz_txrx_idle(instance); + } + } + + } while(false); + furi_string_free(temp_str); + return ret; +} + +void subghz_txrx_rx_start(SubGhzTxRx* instance) { + furi_assert(instance); + subghz_txrx_stop(instance); + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name))); + subghz_txrx_rx(instance, instance->preset->frequency); +} + +void subghz_txrx_set_need_save_callback( + SubGhzTxRx* instance, + SubGhzTxRxNeedSaveCallback callback, + void* context) { + furi_assert(instance); + instance->need_save_callback = callback; + instance->need_save_context = context; +} + +static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateTx); + //Stop TX + furi_hal_subghz_stop_async_tx(); + subghz_transmitter_stop(instance->transmitter); + subghz_transmitter_free(instance->transmitter); + + //if protocol dynamic then we save the last upload + if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + if(instance->need_save_callback) { + instance->need_save_callback(instance->need_save_context); + } + } + subghz_txrx_idle(instance); + subghz_txrx_speaker_off(instance); + //Todo: Show message + // notification_message(notifications, &sequence_reset_red); +} + +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->fff_data; +} + +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->setting; +} + +void subghz_txrx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->txrx_state) { + case SubGhzTxRxStateTx: + subghz_txrx_tx_stop(instance); + subghz_txrx_speaker_unmute(instance); + break; + case SubGhzTxRxStateRx: + subghz_txrx_rx_end(instance); + subghz_txrx_speaker_mute(instance); + break; + + default: + break; + } +} + +void subghz_txrx_hopper_update(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->hopper_state) { + case SubGhzHopperStateOFF: + case SubGhzHopperStatePause: + return; + case SubGhzHopperStateRSSITimeOut: + if(instance->hopper_timeout != 0) { + instance->hopper_timeout--; + return; + } + break; + default: + break; + } + float rssi = -127.0f; + if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) { + // See RSSI Calculation timings in CC1101 17.3 RSSI + rssi = furi_hal_subghz_get_rssi(); + + // Stay if RSSI is high enough + if(rssi > -90.0f) { + instance->hopper_timeout = 10; + instance->hopper_state = SubGhzHopperStateRSSITimeOut; + return; + } + } else { + instance->hopper_state = SubGhzHopperStateRunnig; + } + // Select next frequency + if(instance->hopper_idx_frequency < + subghz_setting_get_hopper_frequency_count(instance->setting) - 1) { + instance->hopper_idx_frequency++; + } else { + instance->hopper_idx_frequency = 0; + } + + if(instance->txrx_state == SubGhzTxRxStateRx) { + subghz_txrx_rx_end(instance); + }; + if(instance->txrx_state == SubGhzTxRxStateIDLE) { + subghz_receiver_reset(instance->receiver); + instance->preset->frequency = + subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency); + subghz_txrx_rx(instance, instance->preset->frequency); + } +} + +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->hopper_state; +} + +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) { + furi_assert(instance); + instance->hopper_state = state; +} + +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStatePause) { + instance->hopper_state = SubGhzHopperStateRunnig; + } +} + +void subghz_txrx_hopper_pause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStateRunnig) { + instance->hopper_state = SubGhzHopperStatePause; + } +} + +void subghz_txrx_speaker_on(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_acquire(30)) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } else { + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_off(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state != SubGhzSpeakerStateDisable) { + if(furi_hal_speaker_is_mine()) { + furi_hal_subghz_set_async_mirror_pin(NULL); + furi_hal_speaker_release(); + if(instance->speaker_state == SubGhzSpeakerStateShutdown) + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_mute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + } +} + +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } + } +} + +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) { + furi_assert(instance); + instance->speaker_state = state; +} + +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->speaker_state; +} + +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) { + furi_assert(instance); + furi_assert(name_protocol); + bool res = false; + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol); + if(instance->decoder_result) { + res = true; + } + return res; +} + +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->decoder_result; +} + +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) { + furi_assert(instance); + return ( + (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == + SubGhzProtocolFlag_Save); +} + +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) { + furi_assert(instance); + const SubGhzProtocol* protocol = instance->decoder_result->protocol; + if(check_type) { + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic); + } + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize); +} + +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) { + furi_assert(instance); + subghz_receiver_set_filter(instance->receiver, filter); +} + +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context) { + subghz_receiver_set_rx_callback(instance->receiver, callback, context); +} + +void subghz_txrx_set_raw_file_encoder_worker_callback_end( + SubGhzTxRx* instance, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter), + callback, + context); +} diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h new file mode 100644 index 0000000000..0f2daf05d4 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -0,0 +1,290 @@ +#pragma once + +#include "subghz_types.h" + +#include +#include +#include +#include +#include + +typedef struct SubGhzTxRx SubGhzTxRx; + +typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); + +typedef enum { + SubGhzTxRxStartTxStateOk, + SubGhzTxRxStartTxStateErrorOnlyRx, + SubGhzTxRxStartTxStateErrorParserOthers, +} SubGhzTxRxStartTxState; + +/** + * Allocate SubGhzTxRx + * + * @return SubGhzTxRx* pointer to SubGhzTxRx + */ +SubGhzTxRx* subghz_txrx_alloc(); + +/** + * Free SubGhzTxRx + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_free(SubGhzTxRx* instance); + +/** + * Check if the database is loaded + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if the database is loaded + */ +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance); + +/** + * Set preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param preset_data Data of preset + * @param preset_data_size Size of preset data + */ +void subghz_txrx_set_preset( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size); + +/** + * Get name of preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset String of preset + * @return const char* Name of preset + */ +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset); + +/** + * Get of preset + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzRadioPreset Preset + */ +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance); + +/** + * Get string frequency and modulation + * + * @param instance Pointer to a SubGhzTxRx + * @param frequency Pointer to a string frequency + * @param modulation Pointer to a string modulation + */ +void subghz_txrx_get_frequency_and_modulation( + SubGhzTxRx* instance, + FuriString* frequency, + FuriString* modulation); + +/** + * Start TX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + * @param flipper_format Pointer to a FlipperFormat + * @return SubGhzTxRxStartTxState + */ +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format); + +/** + * Start RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_rx_start(SubGhzTxRx* instance); + +/** + * Stop TX/RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_stop(SubGhzTxRx* instance); + +/** + * Set sleep mode CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_sleep(SubGhzTxRx* instance); + +/** + * Update frequency CC1101 in automatic mode (hopper) + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_update(SubGhzTxRx* instance); + +/** + * Get state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzHopperState + */ +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance); + +/** + * Set state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @param state State hopper + */ +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state); + +/** + * Unpause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance); + +/** + * Set pause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_pause(SubGhzTxRx* instance); + +/** + * Speaker on + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_on(SubGhzTxRx* instance); + +/** + * Speaker off + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_off(SubGhzTxRx* instance); + +/** + * Speaker mute + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_mute(SubGhzTxRx* instance); + +/** + * Speaker unmute + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance); + +/** + * Set state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @param state State speaker + */ +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state); + +/** + * Get state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSpeakerState + */ +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance); + +/** + * load decoder by name protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_protocol Name protocol + * @return bool True if the decoder is loaded + */ +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol); + +/** + * Get decoder + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase + */ +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance); + +/** + * Set callback for save data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for save data + * @param context Context for callback + */ +void subghz_txrx_set_need_save_callback( + SubGhzTxRx* instance, + SubGhzTxRxNeedSaveCallback callback, + void* context); + +/** + * Get pointer to a load data key + * + * @param instance Pointer to a SubGhzTxRx + * @return FlipperFormat* + */ +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance); + +/** + * Get pointer to a SugGhzSetting + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSetting* + */ +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance); + +/** + * Is it possible to save this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to save this protocol + */ +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance); + +/** + * Is it possible to send this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to send this protocol + */ +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type); + +/** + * Set filter, what types of decoder to use + * + * @param instance Pointer to a SubGhzTxRx + * @param filter Filter + */ +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter); + +/** + * Set callback for receive data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for receive data + * @param context Context for callback + */ +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context); + +/** + * Set callback for Raw decoder, end of data transfer + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for Raw decoder, end of data transfer + * @param context Context for callback + */ +void subghz_txrx_set_raw_file_encoder_worker_callback_end( + SubGhzTxRx* instance, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context); diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c new file mode 100644 index 0000000000..41e4f7c4ef --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c @@ -0,0 +1,164 @@ +#include "subghz_txrx_i.h" +#include "subghz_txrx_create_potocol_key.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TAG "SubGhzCreateProtocolKey" + +bool subghz_txrx_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit) { + furi_assert(context); + SubGhzTxRx* instance = context; + + bool res = false; + + subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0); + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name); + + if(instance->decoder_result == NULL) { + //TODO: Error + // furi_string_set(error_str, "Protocol not\nfound!"); + // scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub); + FURI_LOG_E(TAG, "Protocol not found!"); + return false; + } + + do { + Stream* fff_data_stream = flipper_format_get_raw_stream(instance->fff_data); + stream_clean(fff_data_stream); + if(subghz_protocol_decoder_base_serialize( + instance->decoder_result, instance->fff_data, instance->preset) != + SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Unable to serialize"); + break; + } + if(!flipper_format_update_uint32(instance->fff_data, "Bit", &bit, 1)) { + FURI_LOG_E(TAG, "Unable to update Bit"); + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; + } + if(!flipper_format_update_hex(instance->fff_data, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + res = true; + } while(false); + return res; +} + +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te) { + furi_assert(instance); + bool ret = false; + if(subghz_txrx_gen_data_protocol(instance, preset_name, frequency, protocol_name, key, bit)) { + if(!flipper_format_update_uint32(instance->fff_data, "TE", (uint32_t*)&te, 1)) { + FURI_LOG_E(TAG, "Unable to update Te"); + } else { + ret = true; + } + } + return ret; +} + +bool subghz_txrx_gen_keelog_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + const char* name_sysmem, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + furi_assert(instance); + + bool ret = false; + serial &= 0x0FFFFFFF; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0); + if(instance->transmitter) { + subghz_protocol_keeloq_create_data( + subghz_transmitter_get_protocol_instance(instance->transmitter), + instance->fff_data, + serial, + btn, + cnt, + name_sysmem, + instance->preset); + ret = true; + } + subghz_transmitter_free(instance->transmitter); + return ret; +} + +bool subghz_txrx_gen_secplus_v2_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt) { + furi_assert(instance); + + bool ret = false; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); + subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0); + if(instance->transmitter) { + subghz_protocol_secplus_v2_create_data( + subghz_transmitter_get_protocol_instance(instance->transmitter), + instance->fff_data, + serial, + btn, + cnt, + instance->preset); + ret = true; + } + return ret; +} + +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency) { + furi_assert(instance); + + bool ret = false; + uint32_t serial = (uint32_t)rand(); + while(!subghz_protocol_secplus_v1_check_fixed(serial)) { + serial = (uint32_t)rand(); + } + if(subghz_txrx_gen_data_protocol( + instance, + name_preset, + frequency, + SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, + (uint64_t)serial << 32 | 0xE6000000, + 42)) { + ret = true; + } + return ret; +} \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h new file mode 100644 index 0000000000..5eed93034f --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h @@ -0,0 +1,96 @@ +#pragma once +#include "subghz_types.h" +#include "subghz_txrx.h" + +/** + * Generate data for protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param protocol_name Name of protocol + * @param key Key + * @param bit Bit + * @return bool True if success + */ +bool subghz_txrx_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit); + +/** + * Generate data for protocol and te + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param protocol_name Name of protocol + * @param key Key + * @param bit Bit + * @param te Te + * @return bool True if success + */ +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te); + +/** + * Generate data Keeloq protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @param name_sysmem Name of Keeloq sysmem + * @param serial Serial number + * @param btn Button + * @param cnt Counter + * @return bool True if success + */ +bool subghz_txrx_gen_keelog_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + const char* name_sysmem, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + +/** + * Generate data SecPlus v2 protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @param serial Serial number + * @param btn Button + * @param cnt Counter + * @return bool True if success + */ +bool subghz_txrx_gen_secplus_v2_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt); + +/** + * Generate data SecPlus v1 protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @return bool True if success + */ +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency); \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_i.h b/applications/main/subghz/helpers/subghz_txrx_i.h new file mode 100644 index 0000000000..bd0ad8b7be --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_i.h @@ -0,0 +1,27 @@ +#pragma once + +#include "subghz_txrx.h" + +struct SubGhzTxRx { + SubGhzWorker* worker; + + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; + SubGhzProtocolDecoderBase* decoder_result; + FlipperFormat* fff_data; + + SubGhzRadioPreset* preset; + SubGhzSetting* setting; + + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; + bool is_database_loaded; + SubGhzHopperState hopper_state; + + SubGhzTxRxState txrx_state; + SubGhzSpeakerState speaker_state; + + SubGhzTxRxNeedSaveCallback need_save_callback; + void* need_save_context; +}; diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 2bd2f6820c..46bf940f46 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -77,3 +77,10 @@ typedef enum { SubGhzViewIdTestCarrier, SubGhzViewIdTestPacket, } SubGhzViewId; + +/** SubGhz load type file */ +typedef enum { + SubGhzLoadTypeFileNoLoad, + SubGhzLoadTypeFileKey, + SubGhzLoadTypeFileRaw, +} SubGhzLoadTypeFile; diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 94814b1432..0d14cd23a3 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -19,7 +19,7 @@ void subghz_scene_delete_on_enter(void* context) { modulation_str = furi_string_alloc(); text = furi_string_alloc(); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); widget_add_string_element( subghz->widget, 78, @@ -37,7 +37,7 @@ void subghz_scene_delete_on_enter(void* context) { AlignTop, FontSecondary, furi_string_get_cstr(modulation_str)); - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); + subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text); widget_add_string_multiline_element( subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text)); diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index fa4fc6f642..8dff442a87 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -33,7 +33,7 @@ void subghz_scene_delete_raw_on_enter(void* context) { widget_add_string_element( subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); widget_add_string_element( subghz->widget, 35, diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index e157246aae..f29f26309c 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -37,27 +37,23 @@ void subghz_scene_need_saving_on_enter(void* context) { bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeBack) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneStay) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.event == SubGhzCustomEventSceneExit) { - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; - subghz_preset_init( - subghz, - "AM650", - subghz_setting_get_default_frequency(subghz->setting), - NULL, - 0); + SubGhzRxKeyState state = subghz_rx_key_state_get(subghz); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + + if(state == SubGhzRxKeyStateExit) { + subghz_set_default_preset(subghz); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } else { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; scene_manager_previous_scene(subghz->scene_manager); } diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 09440b32bb..6e576a8618 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -3,11 +3,9 @@ #include #include #include -#include #define RAW_FILE_NAME "Raw_signal_" #define TAG "SubGhzSceneReadRAW" -#define RAW_THRESHOLD_RSSI_LOW_COUNT 10 bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; @@ -15,12 +13,13 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { FuriString* temp_str; temp_str = furi_string_alloc(); do { - if(!flipper_format_rewind(subghz->txrx->fff_data)) { + FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx); + if(!flipper_format_rewind(fff_data)) { FURI_LOG_E(TAG, "Rewind error"); break; } - if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) { + if(!flipper_format_read_string(fff_data, "File_name", temp_str)) { FURI_LOG_E(TAG, "Missing File_name"); break; } @@ -38,13 +37,10 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); subghz_read_raw_add_data_statusbar( subghz->subghz_read_raw, furi_string_get_cstr(frequency_str), @@ -69,13 +65,13 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); - switch(subghz->txrx->rx_key_state) { + float threshold_rssi = subghz_threshold_rssi_get(subghz->threshold_rssi); + switch(subghz_rx_key_state_get(subghz)) { case SubGhzRxKeyStateBack: subghz_read_raw_set_status( - subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", subghz->txrx->raw_threshold_rssi); + subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", threshold_rssi); break; case SubGhzRxKeyStateRAWLoad: path_extract_filename(subghz->file_path, file_name, true); @@ -83,8 +79,7 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, furi_string_get_cstr(file_name), - subghz->txrx->raw_threshold_rssi); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + threshold_rssi); break; case SubGhzRxKeyStateRAWSave: path_extract_filename(subghz->file_path, file_name, true); @@ -92,66 +87,51 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, furi_string_get_cstr(file_name), - subghz->txrx->raw_threshold_rssi); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + threshold_rssi); break; default: subghz_read_raw_set_status( - subghz->subghz_read_raw, - SubGhzReadRAWStatusStart, - "", - subghz->txrx->raw_threshold_rssi); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "", threshold_rssi); break; } + + if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateBack) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + } furi_string_free(file_name); subghz_scene_read_raw_update_statusbar(subghz); //set callback view raw subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz); - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME); - furi_assert(subghz->txrx->decoder_result); + furi_check(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_RAW_NAME)); //set filter RAW feed - subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW); + subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_RAW); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); } bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; bool consumed = false; + SubGhzProtocolDecoderRAW* decoder_raw = + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx); if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SubGhzCustomEventViewReadRAWBack: - //Stop TX - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } - //Stop RX - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + + subghz_txrx_stop(subghz->txrx); //Stop save file - subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + subghz_protocol_raw_save_to_file_stop(decoder_raw); subghz->state_notifications = SubGhzNotificationStateIDLE; //needed save? - if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) || - (subghz->txrx->rx_key_state == SubGhzRxKeyStateBack)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; + if((subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) || + (subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateBack)) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { //Restore default setting - subghz_preset_init( - subghz, - "AM650", - subghz_setting_get_default_frequency(subghz->setting), - NULL, - 0); + subghz_set_default_preset(subghz); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { if(!scene_manager_search_and_switch_to_previous_scene( @@ -165,16 +145,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWTXRXStop: - //Stop TX - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } - //Stop RX - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateIDLE; consumed = true; break; @@ -187,13 +158,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWErase: - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { if(subghz_scene_read_raw_update_filename(subghz)) { furi_string_set(subghz->file_path_tmp, subghz->file_path); subghz_delete_file(subghz); } } - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); notification_message(subghz->notifications, &sequence_reset_rgb); consumed = true; break; @@ -203,7 +174,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet); - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); consumed = true; } else { @@ -223,33 +194,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { //start send subghz->state_notifications = SubGhzNotificationStateIDLE; - 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)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; - subghz_read_raw_set_status( - subghz->subghz_read_raw, - SubGhzReadRAWStatusIDLE, - "", - subghz->txrx->raw_threshold_rssi); - } else { - if(scene_manager_has_previous_scene( - subghz->scene_manager, SubGhzSceneSaved) || - !scene_manager_has_previous_scene( - subghz->scene_manager, SubGhzSceneStart)) { - DOLPHIN_DEED(DolphinDeedSubGhzSend); - } - // set callback end tx - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - subghz->txrx->transmitter), - subghz_scene_read_raw_callback_end_tx, - subghz); - subghz->state_notifications = SubGhzNotificationStateTx; + if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); + subghz_read_raw_set_status( + subghz->subghz_read_raw, + SubGhzReadRAWStatusIDLE, + "", + subghz_threshold_rssi_get(subghz->threshold_rssi)); + } else { + if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) || + !scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) { + DOLPHIN_DEED(DolphinDeedSubGhzSend); } + // set callback end tx + subghz_txrx_set_raw_file_encoder_worker_callback_end( + subghz->txrx, subghz_scene_read_raw_callback_end_tx, subghz); + subghz->state_notifications = SubGhzNotificationStateTx; } } else { if(!scene_manager_search_and_switch_to_previous_scene( @@ -263,33 +223,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReadRAWSendStop: subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_speaker_unmute(subghz); - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } + subghz_txrx_stop(subghz->txrx); subghz_read_raw_stop_send(subghz->subghz_read_raw); consumed = true; break; case SubGhzCustomEventViewReadRAWIDLE: - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; - - size_t spl_count = subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + subghz_txrx_stop(subghz->txrx); + size_t spl_count = subghz_protocol_raw_get_sample_write(decoder_raw); - subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + subghz_protocol_raw_save_to_file_stop(decoder_raw); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( - subghz->txrx->fff_data, furi_string_get_cstr(temp_str)); + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str)); furi_string_free(temp_str); if(spl_count > 0) { @@ -299,32 +248,21 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); consumed = true; break; case SubGhzCustomEventViewReadRAWREC: - if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { + if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateIDLE) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; - if(subghz_protocol_raw_save_to_file_init( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, - RAW_FILE_NAME, - subghz->txrx->preset)) { + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } + subghz_txrx_rx_start(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } else { furi_string_set(subghz->error_str, "Function requires\nan SD card."); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); @@ -337,7 +275,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW); - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); } else { if(!scene_manager_search_and_switch_to_previous_scene( @@ -356,41 +294,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { switch(subghz->state_notifications) { case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); - subghz_read_raw_update_sample_write( - subghz->subghz_read_raw, - subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result)); - - float rssi = furi_hal_subghz_get_rssi(); - if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); - } else { - if(rssi < subghz->txrx->raw_threshold_rssi) { - subghz->txrx->raw_threshold_rssi_low_count++; - if(subghz->txrx->raw_threshold_rssi_low_count > RAW_THRESHOLD_RSSI_LOW_COUNT) { - subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; - } - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); - } else { - subghz->txrx->raw_threshold_rssi_low_count = 0; - } - - if(subghz->txrx->raw_threshold_rssi_low_count == RAW_THRESHOLD_RSSI_LOW_COUNT) { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true); - subghz_speaker_mute(subghz); - } else { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); - subghz_speaker_unmute(subghz); - } - } + subghz_read_raw_update_sample_write( + subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write(decoder_raw)); + SubGhzThresholdRssiData ret_rssi = + subghz_threshold_get_rssi_data(subghz->threshold_rssi); + subghz_read_raw_add_data_rssi( + subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above); + subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above); break; case SubGhzNotificationStateTx: notification_message(subghz->notifications, &sequence_blink_magenta_10); @@ -407,13 +319,10 @@ void subghz_scene_read_raw_on_exit(void* context) { SubGhz* subghz = context; //Stop CC1101 - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateIDLE; notification_message(subghz->notifications, &sequence_reset_rgb); //filter restoration - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 93c369092e..dcc22b91cc 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -35,16 +35,12 @@ static const NotificationSequence subghs_sequence_rx_locked = { static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); - if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* history_stat_str = furi_string_alloc(); + if(!subghz_history_get_text_space_left(subghz->history, history_stat_str)) { + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); subghz_view_receiver_add_data_statusbar( subghz->subghz_receiver, @@ -74,80 +70,68 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + SubGhzHistory* history = subghz->history; + FuriString* str_buff = furi_string_alloc(); + + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); - if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { + if(subghz_history_add_to_history(history, decoder_base, &preset)) { furi_string_reset(str_buff); subghz->state_notifications = SubGhzNotificationStateRxDone; - - subghz_history_get_text_item_menu( - subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); + uint16_t item_history = subghz_history_get_item(history); + subghz_history_get_text_item_menu(history, str_buff, item_history - 1); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(str_buff), - subghz_history_get_type_protocol( - subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); + subghz_history_get_type_protocol(history, item_history - 1)); subghz_scene_receiver_update_statusbar(subghz); } subghz_receiver_reset(receiver); furi_string_free(str_buff); - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; + SubGhzHistory* history = subghz->history; FuriString* str_buff; str_buff = furi_string_alloc(); - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { - subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); - subghz_history_reset(subghz->txrx->history); - subghz->txrx->rx_key_state = SubGhzRxKeyStateStart; + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) { + subghz_set_default_preset(subghz); + subghz_history_reset(history); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } - subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); + subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz_is_locked(subghz)); //Load history to receiver subghz_view_receiver_exit(subghz->subghz_receiver); - for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { + for(uint8_t i = 0; i < subghz_history_get_item(history); i++) { furi_string_reset(str_buff); - subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); + subghz_history_get_text_item_menu(history, str_buff, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(str_buff), - subghz_history_get_type_protocol(subghz->txrx->history, i)); - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_history_get_type_protocol(history, i)); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } furi_string_free(str_buff); subghz_scene_receiver_update_statusbar(subghz); subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); - subghz_receiver_set_rx_callback( - subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); + subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz); subghz->state_notifications = SubGhzNotificationStateRx; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - }; - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); + subghz_txrx_rx_start(subghz->txrx); + subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); //to use a universal decoder, we are looking for a link to it - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_BIN_RAW_NAME); - furi_assert(subghz->txrx->decoder_result); + furi_check( + subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_BIN_RAW_NAME)); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); } @@ -160,41 +144,31 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReceiverBack: // Stop CC1101 Rx subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; - subghz->txrx->idx_menu_chosen = 0; - subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); - - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; + subghz_txrx_stop(subghz->txrx); + subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + subghz->idx_menu_chosen = 0; + subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz); + + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; - subghz_preset_init( - subghz, - "AM650", - subghz_setting_get_default_frequency(subghz->setting), - NULL, - 0); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + subghz_set_default_preset(subghz); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } consumed = true; break; case SubGhzCustomEventViewReceiverOK: - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); consumed = true; break; case SubGhzCustomEventViewReceiverConfig: subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); consumed = true; break; @@ -203,30 +177,30 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case SubGhzCustomEventViewReceiverUnlock: - subghz->lock = SubGhzLockOff; + subghz_unlock(subghz); consumed = true; break; default: break; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz); + if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_txrx_hopper_update(subghz->txrx); subghz_scene_receiver_update_statusbar(subghz); } - //get RSSI - float rssi = furi_hal_subghz_get_rssi(); - subghz_receiver_rssi(subghz->subghz_receiver, rssi); + SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi); + + subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi); subghz_protocol_decoder_bin_raw_data_input_rssi( - (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, rssi); + (SubGhzProtocolDecoderBinRAW*)subghz_txrx_get_decoder(subghz->txrx), ret_rssi.rssi); switch(subghz->state_notifications) { case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); break; case SubGhzNotificationStateRxDone: - if(subghz->lock != SubGhzLockOn) { + if(!subghz_is_locked(subghz)) { notification_message(subghz->notifications, &subghs_sequence_rx); } else { notification_message(subghz->notifications, &subghs_sequence_rx_locked); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 895e433428..55a8f6b44a 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -72,13 +72,15 @@ const uint32_t bin_raw_value[BIN_RAW_COUNT] = { uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { furi_assert(context); SubGhz* subghz = context; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->setting); i++) { - if(value == subghz_setting_get_frequency(subghz->setting, i)) { + for(uint8_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) { + if(value == subghz_setting_get_frequency(setting, i)) { index = i; break; } else { - index = subghz_setting_get_frequency_default_index(subghz->setting); + index = subghz_setting_get_frequency_default_index(setting); } } return index; @@ -87,13 +89,15 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* context) { furi_assert(context); SubGhz* subghz = context; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) { - if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), preset_name)) { + for(uint8_t i = 0; i < subghz_setting_get_preset_count(setting); i++) { + if(!strcmp(subghz_setting_get_preset_name(setting, i), preset_name)) { index = i; break; } else { - // index = subghz_setting_get_frequency_default_index(subghz->setting); + // index = subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx)); } } return index; @@ -122,70 +126,84 @@ uint8_t subghz_scene_receiver_config_hopper_value_index( static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); - if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { + if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) { char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_frequency(setting, index); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->setting, index) / 1000000, - (subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000); + frequency / 1000000, + (frequency % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); - subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index); + subghz_txrx_set_preset( + subghz->txrx, + furi_string_get_cstr(preset.name), + frequency, + preset.data, + preset.data_size); } else { variable_item_set_current_value_index( - item, subghz_setting_get_frequency_default_index(subghz->setting)); + item, subghz_setting_get_frequency_default_index(setting)); } } static void subghz_scene_receiver_config_set_preset(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text( - item, subghz_setting_get_preset_name(subghz->setting, index)); - subghz_preset_init( - subghz, - subghz_setting_get_preset_name(subghz->setting, index), - subghz->txrx->preset->frequency, - subghz_setting_get_preset_data(subghz->setting, index), - subghz_setting_get_preset_data_size(subghz->setting, index)); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + + variable_item_set_current_value_text(item, subghz_setting_get_preset_name(setting, index)); + + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + subghz_txrx_set_preset( + subghz->txrx, + subghz_setting_get_preset_name(setting, index), + preset.frequency, + subghz_setting_get_preset_data(setting, index), + subghz_setting_get_preset_data_size(setting, index)); } static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + VariableItem* frequency_item = (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig); variable_item_set_current_value_text(item, hopping_text[index]); if(hopping_value[index] == SubGhzHopperStateOFF) { char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_default_frequency(setting); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_default_frequency(subghz->setting) / 1000000, - (subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000); - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - text_buf); - subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting); + frequency / 1000000, + (frequency % 1000000) / 10000); + variable_item_set_current_value_text(frequency_item, text_buf); + + subghz_txrx_set_preset( + subghz->txrx, + furi_string_get_cstr(preset.name), + frequency, + preset.data, + preset.data_size); variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); + frequency_item, subghz_setting_get_frequency_default_index(setting)); } else { - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - " -----"); + variable_item_set_current_value_text(frequency_item, " -----"); variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); + frequency_item, subghz_setting_get_frequency_default_index(setting)); } - subghz->txrx->hopper_state = hopping_value[index]; + subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[index]); } static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { @@ -193,7 +211,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, speaker_text[index]); - subghz->txrx->speaker_state = speaker_value[index]; + subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]); } static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { @@ -201,8 +219,8 @@ static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, bin_raw_text[index]); - subghz->txrx->filter = bin_raw_value[index]; - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); + subghz->filter = bin_raw_value[index]; + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); } static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { @@ -210,7 +228,7 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]); - subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index]; + subghz_threshold_rssi_set(subghz->threshold_rssi, raw_theshold_rssi_value[index]); } static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { @@ -226,25 +244,27 @@ void subghz_scene_receiver_config_on_enter(void* context) { SubGhz* subghz = context; VariableItem* item; uint8_t value_index; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); item = variable_item_list_add( subghz->variable_item_list, "Frequency:", - subghz_setting_get_frequency_count(subghz->setting), + subghz_setting_get_frequency_count(setting), subghz_scene_receiver_config_set_frequency, subghz); - value_index = - subghz_scene_receiver_config_next_frequency(subghz->txrx->preset->frequency, subghz); + value_index = subghz_scene_receiver_config_next_frequency(preset.frequency, subghz); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item); variable_item_set_current_value_index(item, value_index); char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_frequency(setting, value_index); snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->setting, value_index) / 1000000, - (subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000); + frequency / 1000000, + (frequency % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != @@ -256,7 +276,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_hopping_running, subghz); value_index = subghz_scene_receiver_config_hopper_value_index( - subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); + subghz_txrx_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, hopping_text[value_index]); } @@ -264,14 +284,14 @@ void subghz_scene_receiver_config_on_enter(void* context) { item = variable_item_list_add( subghz->variable_item_list, "Modulation:", - subghz_setting_get_preset_count(subghz->setting), + subghz_setting_get_preset_count(setting), subghz_scene_receiver_config_set_preset, subghz); - value_index = subghz_scene_receiver_config_next_preset( - furi_string_get_cstr(subghz->txrx->preset->name), subghz); + value_index = + subghz_scene_receiver_config_next_preset(furi_string_get_cstr(preset.name), subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text( - item, subghz_setting_get_preset_name(subghz->setting, value_index)); + item, subghz_setting_get_preset_name(setting, value_index)); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerSet) { @@ -281,7 +301,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { BIN_RAW_COUNT, subghz_scene_receiver_config_set_bin_raw, subghz); - value_index = value_index_uint32(subghz->txrx->filter, bin_raw_value, BIN_RAW_COUNT); + value_index = value_index_uint32(subghz->filter, bin_raw_value, BIN_RAW_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, bin_raw_text[value_index]); } @@ -292,7 +312,8 @@ void subghz_scene_receiver_config_on_enter(void* context) { SPEAKER_COUNT, subghz_scene_receiver_config_set_speaker, subghz); - value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT); + value_index = value_index_uint32( + subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, speaker_text[value_index]); @@ -313,7 +334,9 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_raw_threshold_rssi, subghz); value_index = value_index_float( - subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); + subghz_threshold_rssi_get(subghz->threshold_rssi), + raw_theshold_rssi_value, + RAW_THRESHOLD_RSSI_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]); } @@ -326,7 +349,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneSettingLock) { - subghz->lock = SubGhzLockOn; + subghz_lock(subghz); scene_manager_previous_scene(subghz->scene_manager); consumed = true; } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 152334ad63..9b57165e76 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -19,20 +19,19 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v static bool subghz_scene_receiver_info_update_parser(void* context) { SubGhz* subghz = context; - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, - subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); - if(subghz->txrx->decoder_result) { + if(subghz_txrx_load_decoder_by_name_protocol( + subghz->txrx, + subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) { //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, - subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); + subghz_txrx_get_decoder(subghz->txrx), + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen)); SubGhzRadioPreset* preset = - subghz_history_get_radio_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen); - subghz_preset_init( - subghz, + subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen); + subghz_txrx_set_preset( + subghz->txrx, furi_string_get_cstr(preset->name), preset->frequency, preset->data, @@ -47,15 +46,11 @@ void subghz_scene_receiver_info_on_enter(void* context) { SubGhz* subghz = context; if(subghz_scene_receiver_info_update_parser(subghz)) { - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); widget_add_string_element( subghz->widget, 78, @@ -73,7 +68,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { AlignTop, FontSecondary, furi_string_get_cstr(modulation_str)); - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); + subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text); widget_add_string_multiline_element( subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text)); @@ -81,8 +76,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { furi_string_free(modulation_str); furi_string_free(text); - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == - SubGhzProtocolFlag_Save) { + if(subghz_txrx_protocol_is_serializable(subghz->txrx)) { widget_add_button_element( subghz->widget, GuiButtonTypeRight, @@ -90,10 +84,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { subghz_scene_receiver_info_callback, subghz); } - if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) && - subghz->txrx->decoder_result->protocol->encoder->deserialize && - subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic) { + if(subghz_txrx_protocol_is_transmittable(subghz->txrx, true)) { widget_add_button_element( subghz->widget, GuiButtonTypeCenter, @@ -114,82 +105,49 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) { - //CC1101 Stop RX -> Start TX - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz->txrx->hopper_state = SubGhzHopperStatePause; - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - } if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE || - subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { - if(!subghz_tx_start( - subghz, - subghz_history_get_raw_data( - subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } - subghz->state_notifications = SubGhzNotificationStateRx; - } else { - subghz->state_notifications = SubGhzNotificationStateTx; - } + //CC1101 Stop RX -> Start TX + subghz_txrx_hopper_pause(subghz->txrx); + if(!subghz_tx_start( + subghz, + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { + subghz_txrx_rx_start(subghz->txrx); + subghz_txrx_hopper_unpause(subghz->txrx); + subghz->state_notifications = SubGhzNotificationStateRx; + } else { + subghz->state_notifications = SubGhzNotificationStateTx; } return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) { //CC1101 Stop Tx -> Start RX subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } + + subghz_txrx_rx_start(subghz->txrx); + + subghz_txrx_hopper_unpause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) { //CC1101 Stop RX -> Save subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - } + subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + + subghz_txrx_stop(subghz->txrx); if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == - SubGhzProtocolFlag_Save) { + if(subghz_txrx_protocol_is_serializable(subghz->txrx)) { subghz_file_name_clear(subghz); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); } return true; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz); + if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_txrx_hopper_update(subghz->txrx); } switch(subghz->state_notifications) { case SubGhzNotificationStateTx: diff --git a/applications/main/subghz/scenes/subghz_scene_region_info.c b/applications/main/subghz/scenes/subghz_scene_region_info.c index 82486314d9..b98394af07 100644 --- a/applications/main/subghz/scenes/subghz_scene_region_info.c +++ b/applications/main/subghz/scenes/subghz_scene_region_info.c @@ -5,8 +5,7 @@ void subghz_scene_region_info_on_enter(void* context) { SubGhz* subghz = context; const FuriHalRegion* const region = furi_hal_region_get(); - FuriString* buffer; - buffer = furi_string_alloc(); + FuriString* buffer = furi_string_alloc(); if(region) { furi_string_cat_printf(buffer, "Region: %s, bands:\n", region->country_code); for(uint16_t i = 0; i < region->bands_count; ++i) { diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index a1c0e41fd6..aa6f132d76 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -3,6 +3,7 @@ typedef enum { SubGhzRpcStateIdle, SubGhzRpcStateLoaded, + SubGhzRpcStateTx, } SubGhzRpcState; void subghz_scene_rpc_on_enter(void* context) { @@ -38,9 +39,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { view_dispatcher_stop(subghz->view_dispatcher); } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; - if((subghz->txrx->txrx_state == SubGhzTxRxStateSleep) && - (state == SubGhzRpcStateLoaded)) { - result = subghz_tx_start(subghz, subghz->txrx->fff_data); + if((state == SubGhzRpcStateLoaded)) { + result = subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + state = SubGhzRpcStateTx; if(result) subghz_blink_start(subghz); } if(!result) { @@ -52,10 +53,10 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result); } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { bool result = false; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + if(state == SubGhzRpcStateTx) { + subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); - subghz_tx_stop(subghz); - subghz_sleep(subghz); + state = SubGhzRpcStateIdle; result = true; } rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result); @@ -93,10 +94,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { void subghz_scene_rpc_on_exit(void* context) { SubGhz* subghz = context; - - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); + SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc); + if(state != SubGhzRpcStateIdle) { + subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index 255ba228bc..2a292a1ef3 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -35,10 +35,8 @@ void subghz_scene_save_name_on_enter(void* context) { TextInput* text_input = subghz->text_input; bool dev_name_empty = false; - FuriString* file_name; - FuriString* dir_name; - file_name = furi_string_alloc(); - dir_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* dir_name = furi_string_alloc(); if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; @@ -69,7 +67,7 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_scene_save_name_text_input_callback, subghz, subghz->file_name_tmp, - MAX_TEXT_INPUT_LEN, // buffer size + MAX_TEXT_INPUT_LEN, dev_name_empty); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( @@ -106,7 +104,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhzCustomEventManagerNoSet) { subghz_save_protocol_to_file( subghz, - subghz->txrx->fff_data, + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, @@ -115,8 +113,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { } else { subghz_save_protocol_to_file( subghz, - subghz_history_get_raw_data( - subghz->txrx->history, subghz->txrx->idx_menu_chosen), + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen), furi_string_get_cstr(subghz->file_path)); } } @@ -124,7 +121,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerNoSet) { subghz_protocol_raw_gen_fff_data( - subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); + subghz_txrx_get_fff_data(subghz->txrx), + furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); } else { diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index 2977975f7f..40ade5a535 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -26,10 +26,10 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) if(event.event == SubGhzCustomEventSceneSaveSuccess) { if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReceiver)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWSave); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReadRAW)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); diff --git a/applications/main/subghz/scenes/subghz_scene_saved.c b/applications/main/subghz/scenes/subghz_scene_saved.c index 62ade3508e..8b198e3395 100644 --- a/applications/main/subghz/scenes/subghz_scene_saved.c +++ b/applications/main/subghz/scenes/subghz_scene_saved.c @@ -4,8 +4,8 @@ void subghz_scene_saved_on_enter(void* context) { SubGhz* subghz = context; if(subghz_load_protocol_from_file(subghz)) { - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 2134377e3a..32e0d65884 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -1,63 +1,10 @@ #include "../subghz_i.h" -#include -#include -#include +#include "../helpers/subghz_txrx_create_potocol_key.h" #include -#include -#include #include #define TAG "SubGhzSetType" -bool subghz_scene_set_type_submenu_gen_data_protocol( - void* context, - const char* protocol_name, - uint64_t key, - uint32_t bit, - uint32_t frequency, - const char* preset_name) { - furi_assert(context); - SubGhz* subghz = context; - - bool res = false; - - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - subghz->txrx->decoder_result = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name); - - if(subghz->txrx->decoder_result == NULL) { - furi_string_set(subghz->error_str, "Protocol not\nfound!"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); - return false; - } - - do { - Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); - stream_clean(fff_data_stream); - if(subghz_protocol_decoder_base_serialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Unable to serialize"); - break; - } - if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) { - FURI_LOG_E(TAG, "Unable to update Bit"); - break; - } - - uint8_t key_data[sizeof(uint64_t)] = {0}; - for(size_t i = 0; i < sizeof(uint64_t); i++) { - key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; - } - if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Unable to update Key"); - break; - } - res = true; - } while(false); - return res; -} - void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) { SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, index); @@ -69,7 +16,13 @@ void subghz_scene_set_type_on_enter(void* context) { submenu_add_item( subghz->submenu, "Princeton_433", - SubmenuIndexPricenton, + SubmenuIndexPricenton_433, + subghz_scene_set_type_submenu_callback, + subghz); + submenu_add_item( + subghz->submenu, + "Princeton_315", + SubmenuIndexPricenton_315, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( @@ -108,10 +61,6 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexCAMETwee, subghz_scene_set_type_submenu_callback, subghz); - // submenu_add_item( - // subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz); - // submenu_add_item( - // subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( subghz->submenu, "Gate TX_433", @@ -172,94 +121,59 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { bool generated_protocol = false; if(event.type == SceneManagerEventTypeCustom) { - //ToDo Fix - uint32_t key = subghz_random_serial(); + uint32_t key = (uint32_t)rand(); switch(event.event) { - case SubmenuIndexPricenton: + case SubmenuIndexPricenton_433: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 433920000, "AM650")) { - uint32_t te = 400; - flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1); - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol_and_te( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); + break; + case SubmenuIndexPricenton_315: + key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 + generated_protocol = subghz_txrx_gen_data_protocol_and_te( + subghz->txrx, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); break; case SubmenuIndexNiceFlo12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12); break; case SubmenuIndexNiceFlo24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24); break; case SubmenuIndexCAME12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 12, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); break; case SubmenuIndexCAME24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); break; case SubmenuIndexLinear_300_00: key = (key & 0x3FF); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10, 300000000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10); break; case SubmenuIndexCAMETwee: key = (key & 0x0FFFFFF0); key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54, 433920000, "AM650")) { - generated_protocol = true; - } + + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54); break; - // case SubmenuIndexNeroSketch: - // /* code */ - // break; - // case SubmenuIndexNeroRadio: - // /* code */ - // break; case SubmenuIndexGateTX: key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?) uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); break; case SubmenuIndexDoorHan_433_92: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_keeloq_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key & 0x0FFFFFFF, - 0x2, - 0x0003, - "DoorHan", - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_keelog_protocol( + subghz->txrx, "AM650", 433920000, "DoorHan", key, 0x2, 0x0003); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -267,23 +181,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDoorHan_315_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init(subghz, "AM650", 315000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_keeloq_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key & 0x0FFFFFFF, - 0x2, - 0x0003, - "DoorHan", - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_keelog_protocol( + subghz->txrx, "AM650", 315000000, "DoorHan", key, 0x2, 0x0003); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -291,86 +190,24 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexLiftMaster_315_00: - while(!subghz_protocol_secplus_v1_check_fixed(key)) { - key = subghz_random_serial(); - } - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)key << 32 | 0xE6000000, - 42, - 315000000, - "AM650")) { - generated_protocol = true; - } + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000); break; case SubmenuIndexLiftMaster_390_00: - while(!subghz_protocol_secplus_v1_check_fixed(key)) { - key = subghz_random_serial(); - } - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)key << 32 | 0xE6000000, - 42, - 390000000, - "AM650")) { - generated_protocol = true; - } + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000); break; case SubmenuIndexSecPlus_v2_310_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 310000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 310000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_315_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 315000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 315000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_390_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 390000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 390000000, key, 0x68, 0xE500000); break; default: return false; diff --git a/applications/main/subghz/scenes/subghz_scene_show_error.c b/applications/main/subghz/scenes/subghz_scene_show_error.c index eadfb21146..d52eca9b6c 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error.c @@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) { bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; + SubGhzCustomEvent scene_state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError); if(event.type == SceneManagerEventTypeBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { return false; } else { scene_manager_search_and_switch_to_previous_scene( @@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneShowErrorOk) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } return true; } else if(event.event == SubGhzCustomEventSceneShowErrorBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { //exit app if(!scene_manager_previous_scene(subghz->scene_manager)) { scene_manager_stop(subghz->scene_manager); diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index a50f73a810..a41e4b06f4 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -70,7 +70,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexReadRAW) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); return true; } else if(event.event == SubmenuIndexRead) { diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 712e50071c..1c193c1794 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -11,32 +11,24 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; - if(subghz->txrx->decoder_result) { - FuriString* key_str; - FuriString* frequency_str; - FuriString* modulation_str; + SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx); - key_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - uint8_t show_button = 0; + if(decoder) { + FuriString* key_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); if(subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str); + decoder, subghz_txrx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) { + subghz_protocol_decoder_base_get_string(decoder, key_str); - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) { - show_button = 1; - } - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); subghz_view_transmitter_add_data_to_show( subghz->subghz_transmitter, furi_string_get_cstr(key_str), furi_string_get_cstr(frequency_str), furi_string_get_cstr(modulation_str), - show_button); + subghz_txrx_protocol_is_transmittable(subghz->txrx, false)); ret = true; } furi_string_free(frequency_str); @@ -65,24 +57,16 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - 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)) { - subghz->state_notifications = SubGhzNotificationStateTx; - subghz_scene_transmitter_update_data_show(subghz); - DOLPHIN_DEED(DolphinDeedSubGhzSend); - } + + if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { + subghz->state_notifications = SubGhzNotificationStateTx; + subghz_scene_transmitter_update_data_show(subghz); + DOLPHIN_DEED(DolphinDeedSubGhzSend); } return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } + subghz_txrx_stop(subghz->txrx); return true; } else if(event.event == SubGhzCustomEventViewTransmitterBack) { subghz->state_notifications = SubGhzNotificationStateIDLE; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 25233fe21c..09963584af 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -1,9 +1,6 @@ /* Abandon hope, all ye who enter here. */ -#include "subghz/types.h" #include "subghz_i.h" -#include -#include bool subghz_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -49,16 +46,6 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context) } } -void subghz_blink_start(SubGhz* instance) { - furi_assert(instance); - notification_message(instance->notifications, &sequence_blink_start_magenta); -} - -void subghz_blink_stop(SubGhz* instance) { - furi_assert(instance); - notification_message(instance->notifications, &sequence_blink_stop); -} - SubGhz* subghz_alloc() { SubGhz* subghz = malloc(sizeof(SubGhz)); @@ -163,45 +150,18 @@ SubGhz* subghz_alloc() { SubGhzViewIdStatic, subghz_test_static_get_view(subghz->subghz_test_static)); - //init setting - subghz->setting = subghz_setting_alloc(); - subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user")); - - //init Worker & Protocol & History & KeyBoard - subghz->lock = SubGhzLockOff; - subghz->txrx = malloc(sizeof(SubGhzTxRx)); - subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset)); - subghz->txrx->preset->name = furi_string_alloc(); - subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); - - subghz->txrx->txrx_state = SubGhzTxRxStateSleep; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; - subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN; - subghz->txrx->history = subghz_history_alloc(); - subghz->txrx->worker = subghz_worker_alloc(); - subghz->txrx->fff_data = flipper_format_string_alloc(); - - subghz->txrx->environment = subghz_environment_alloc(); - subghz_environment_set_came_atomo_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/came_atomo")); - subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n")); - subghz_environment_set_nice_flor_s_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/nice_flor_s")); - subghz_environment_set_protocol_registry( - subghz->txrx->environment, (void*)&subghz_protocol_registry); - subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment); - subghz->txrx->filter = SubGhzProtocolFlag_Decodable; - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); - - subghz_worker_set_overrun_callback( - subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); - subghz_worker_set_pair_callback( - subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); - subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver); + //init threshold rssi + subghz->threshold_rssi = subghz_threshold_rssi_alloc(); + + subghz_unlock(subghz); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + subghz->history = subghz_history_alloc(); + subghz->filter = SubGhzProtocolFlag_Decodable; + + //init TxRx & History & KeyBoard + subghz->txrx = subghz_txrx_alloc(); + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); + subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz); //Init Error_str subghz->error_str = furi_string_alloc(); @@ -219,7 +179,9 @@ void subghz_free(SubGhz* subghz) { subghz->rpc_ctx = NULL; } - subghz_speaker_off(subghz); + subghz_txrx_speaker_off(subghz->txrx); + subghz_txrx_stop(subghz->txrx); + subghz_txrx_sleep(subghz->txrx); // Packet Test view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); @@ -282,18 +244,14 @@ void subghz_free(SubGhz* subghz) { furi_record_close(RECORD_GUI); subghz->gui = NULL; - //setting - subghz_setting_free(subghz->setting); + // threshold rssi + subghz_threshold_rssi_free(subghz->threshold_rssi); //Worker & Protocol & History - subghz_receiver_free(subghz->txrx->receiver); - subghz_environment_free(subghz->txrx->environment); - subghz_worker_free(subghz->txrx->worker); - flipper_format_free(subghz->txrx->fff_data); - subghz_history_free(subghz->txrx->history); - furi_string_free(subghz->txrx->preset->name); - free(subghz->txrx->preset); - free(subghz->txrx); + subghz_history_free(subghz->history); + + //TxRx + subghz_txrx_free(subghz->txrx); //Error string furi_string_free(subghz->error_str); @@ -319,11 +277,6 @@ int32_t subghz_app(void* p) { return 1; } - //Load database - bool load_database = subghz_environment_load_keystore( - subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore( - subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); // Check argument and run corresponding scene if(p && strlen(p)) { uint32_t rpc_ctx = 0; @@ -340,9 +293,9 @@ int32_t subghz_app(void* p) { if(subghz_key_load(subghz, p, true)) { furi_string_set(subghz->file_path, (const char*)p); - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { + if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { //Load Raw TX - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { //Load transmitter TX @@ -358,7 +311,7 @@ int32_t subghz_app(void* p) { view_dispatcher_attach_to_gui( subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER); - if(load_database) { + if(subghz_txrx_is_database_loaded(subghz->txrx)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } else { scene_manager_set_scene_state( diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 18d87c76b5..8036ed5f7a 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -18,214 +18,42 @@ #define TAG "SubGhz" -void subghz_preset_init( - void* context, - const char* preset_name, - uint32_t frequency, - uint8_t* preset_data, - size_t preset_data_size) { - furi_assert(context); - SubGhz* subghz = context; - furi_string_set(subghz->txrx->preset->name, preset_name); - subghz->txrx->preset->frequency = frequency; - subghz->txrx->preset->data = preset_data; - subghz->txrx->preset->data_size = preset_data_size; -} - -bool subghz_set_preset(SubGhz* subghz, const char* preset) { - if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { - furi_string_set(subghz->txrx->preset->name, "AM270"); - } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { - furi_string_set(subghz->txrx->preset->name, "AM650"); - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { - furi_string_set(subghz->txrx->preset->name, "FM238"); - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { - furi_string_set(subghz->txrx->preset->name, "FM476"); - } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { - furi_string_set(subghz->txrx->preset->name, "CUSTOM"); - } else { - FURI_LOG_E(TAG, "Unknown preset"); - return false; - } - return true; -} - -void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation) { +void subghz_set_default_preset(SubGhz* subghz) { furi_assert(subghz); - if(frequency != NULL) { - furi_string_printf( - frequency, - "%03ld.%02ld", - subghz->txrx->preset->frequency / 1000000 % 1000, - subghz->txrx->preset->frequency / 10000 % 100); - } - if(modulation != NULL) { - furi_string_printf(modulation, "%.2s", furi_string_get_cstr(subghz->txrx->preset->name)); - } + subghz_txrx_set_preset( + subghz->txrx, + "AM650", + subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)), + NULL, + 0); } -void subghz_begin(SubGhz* subghz, uint8_t* preset_data) { +void subghz_blink_start(SubGhz* subghz) { furi_assert(subghz); - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(preset_data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; + notification_message(subghz->notifications, &sequence_blink_stop); + notification_message(subghz->notifications, &sequence_blink_start_magenta); } -uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) { +void subghz_blink_stop(SubGhz* subghz) { furi_assert(subghz); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect RX frequency."); - } - furi_assert( - subghz->txrx->txrx_state != SubGhzTxRxStateRx && - subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - - furi_hal_subghz_idle(); - uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - furi_hal_subghz_flush_rx(); - subghz_speaker_on(subghz); - furi_hal_subghz_rx(); - - furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker); - subghz_worker_start(subghz->txrx->worker); - subghz->txrx->txrx_state = SubGhzTxRxStateRx; - return value; -} - -static bool subghz_tx(SubGhz* subghz, uint32_t frequency) { - furi_assert(subghz); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect TX frequency."); - } - furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_write(&gpio_cc1101_g0, false); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - bool ret = furi_hal_subghz_tx(); - if(ret) { - subghz_speaker_on(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateTx; - } - return ret; -} - -void subghz_idle(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - subghz_speaker_off(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; -} - -void subghz_rx_end(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx); - - if(subghz_worker_is_running(subghz->txrx->worker)) { - subghz_worker_stop(subghz->txrx->worker); - furi_hal_subghz_stop_async_rx(); - } - furi_hal_subghz_idle(); - subghz_speaker_off(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; -} - -void subghz_sleep(SubGhz* subghz) { - furi_assert(subghz); - furi_hal_subghz_sleep(); - subghz->txrx->txrx_state = SubGhzTxRxStateSleep; + notification_message(subghz->notifications, &sequence_blink_stop); } bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { - furi_assert(subghz); - - bool ret = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); - uint32_t repeat = 200; - do { - if(!flipper_format_rewind(flipper_format)) { - FURI_LOG_E(TAG, "Rewind error"); - break; - } - if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - break; - } - if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, furi_string_get_cstr(temp_str)); - - if(subghz->txrx->transmitter) { - if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format) == - SubGhzProtocolStatusOk) { - if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - } else { - FURI_LOG_E( - TAG, - "Unknown name preset \" %s \"", - furi_string_get_cstr(subghz->txrx->preset->name)); - subghz_begin( - subghz, subghz_setting_get_preset_data_by_name(subghz->setting, "AM650")); - } - if(subghz->txrx->preset->frequency) { - ret = subghz_tx(subghz, subghz->txrx->preset->frequency); - } else { - ret = subghz_tx(subghz, 433920000); - } - if(ret) { - //Start TX - furi_hal_subghz_start_async_tx( - subghz_transmitter_yield, subghz->txrx->transmitter); - } else { - subghz_dialog_message_show_only_rx(subghz); - } - } else { - dialog_message_show_storage_error( - subghz->dialogs, "Error in protocol\nparameters\ndescription"); - } - } - if(!ret) { - subghz_transmitter_free(subghz->txrx->transmitter); - if(subghz->txrx->txrx_state != SubGhzTxRxStateSleep) { - subghz_idle(subghz); - } - } - - } while(false); - furi_string_free(temp_str); - return ret; -} + switch(subghz_txrx_tx_start(subghz->txrx, flipper_format)) { + case SubGhzTxRxStartTxStateErrorParserOthers: + dialog_message_show_storage_error( + subghz->dialogs, "Error in protocol\nparameters\ndescription"); + break; + case SubGhzTxRxStartTxStateErrorOnlyRx: + subghz_dialog_message_show_only_rx(subghz); + break; -void subghz_tx_stop(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx); - //Stop TX - furi_hal_subghz_stop_async_tx(); - subghz_transmitter_stop(subghz->txrx->transmitter); - subghz_transmitter_free(subghz->txrx->transmitter); - - //if protocol dynamic then we save the last upload - if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) && - (subghz_path_is_file(subghz->file_path))) { - subghz_save_protocol_to_file( - subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); + default: + return true; + break; } - subghz_idle(subghz); - subghz_speaker_off(subghz); - notification_message(subghz->notifications, &sequence_reset_red); + return false; } void subghz_dialog_message_show_only_rx(SubGhz* subghz) { @@ -254,11 +82,11 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); + Stream* fff_data_stream = + flipper_format_get_raw_stream(subghz_txrx_get_fff_data(subghz->txrx)); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; do { @@ -281,6 +109,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } + //Load frequency if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { FURI_LOG_E(TAG, "Missing Frequency"); break; @@ -291,58 +120,61 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } - subghz->txrx->preset->frequency = temp_data32; - + //Load preset if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { FURI_LOG_E(TAG, "Missing Preset"); break; } - if(!subghz_set_preset(subghz, furi_string_get_cstr(temp_str))) { + furi_string_set_str( + temp_str, subghz_txrx_get_preset_name(subghz->txrx, furi_string_get_cstr(temp_str))); + if(!strcmp(furi_string_get_cstr(temp_str), "")) { break; } + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); - if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { + if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) { //Todo add Custom_preset_module //delete preset if it already exists - subghz_setting_delete_custom_preset( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)); + subghz_setting_delete_custom_preset(setting, furi_string_get_cstr(temp_str)); //load custom preset from file if(!subghz_setting_load_custom_preset( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name), - fff_data_file)) { + setting, furi_string_get_cstr(temp_str), fff_data_file)) { FURI_LOG_E(TAG, "Missing Custom preset"); break; } } - size_t preset_index = subghz_setting_get_inx_preset_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)); - subghz_preset_init( - subghz, - furi_string_get_cstr(subghz->txrx->preset->name), - subghz->txrx->preset->frequency, - subghz_setting_get_preset_data(subghz->setting, preset_index), - subghz_setting_get_preset_data_size(subghz->setting, preset_index)); - + size_t preset_index = + subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str)); + subghz_txrx_set_preset( + subghz->txrx, + furi_string_get_cstr(temp_str), + temp_data32, + subghz_setting_get_preset_data(setting, preset_index), + subghz_setting_get_preset_data_size(setting, preset_index)); + + //Load protocol if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { FURI_LOG_E(TAG, "Missing Protocol"); break; } + + FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx); if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { //if RAW - subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, file_path); + subghz->load_type_file = SubGhzLoadTypeFileRaw; + subghz_protocol_raw_gen_fff_data(fff_data, file_path); } else { + subghz->load_type_file = SubGhzLoadTypeFileKey; stream_copy_full( flipper_format_get_raw_stream(fff_data_file), - flipper_format_get_raw_stream(subghz->txrx->fff_data)); + flipper_format_get_raw_stream(fff_data)); } - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, furi_string_get_cstr(temp_str)); - if(subghz->txrx->decoder_result) { + if(subghz_txrx_load_decoder_by_name_protocol( + subghz->txrx, furi_string_get_cstr(temp_str))) { SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data); + subghz_txrx_get_decoder(subghz->txrx), fff_data); if(status != SubGhzProtocolStatusOk) { load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr; break; @@ -381,17 +213,18 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } } +SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz) { + furi_assert(subghz); + return subghz->load_type_file; +} + bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* temp_str; - FuriString* file_name; - FuriString* file_path; - - temp_str = furi_string_alloc(); - file_name = furi_string_alloc(); - file_path = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); bool res = false; @@ -438,8 +271,7 @@ bool subghz_save_protocol_to_file( Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; - FuriString* file_dir; - file_dir = furi_string_alloc(); + FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { @@ -467,11 +299,21 @@ bool subghz_save_protocol_to_file( return saved; } +void subghz_save_to_file(void* context) { + furi_assert(context); + SubGhz* subghz = context; + if(subghz_path_is_file(subghz->file_path)) { + subghz_save_protocol_to_file( + subghz, + subghz_txrx_get_fff_data(subghz->txrx), + furi_string_get_cstr(subghz->file_path)); + } +} + bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); - FuriString* file_path; - file_path = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); @@ -551,92 +393,27 @@ bool subghz_path_is_file(FuriString* path) { return furi_string_end_with(path, SUBGHZ_APP_EXTENSION); } -uint32_t subghz_random_serial(void) { - return (uint32_t)rand(); -} - -void subghz_hopper_update(SubGhz* subghz) { +void subghz_lock(SubGhz* subghz) { furi_assert(subghz); - - switch(subghz->txrx->hopper_state) { - case SubGhzHopperStateOFF: - case SubGhzHopperStatePause: - return; - case SubGhzHopperStateRSSITimeOut: - if(subghz->txrx->hopper_timeout != 0) { - subghz->txrx->hopper_timeout--; - return; - } - break; - default: - break; - } - float rssi = -127.0f; - if(subghz->txrx->hopper_state != SubGhzHopperStateRSSITimeOut) { - // See RSSI Calculation timings in CC1101 17.3 RSSI - rssi = furi_hal_subghz_get_rssi(); - - // Stay if RSSI is high enough - if(rssi > -90.0f) { - subghz->txrx->hopper_timeout = 10; - subghz->txrx->hopper_state = SubGhzHopperStateRSSITimeOut; - return; - } - } else { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } - // Select next frequency - if(subghz->txrx->hopper_idx_frequency < - subghz_setting_get_hopper_frequency_count(subghz->setting) - 1) { - subghz->txrx->hopper_idx_frequency++; - } else { - subghz->txrx->hopper_idx_frequency = 0; - } - - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - }; - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_receiver_reset(subghz->txrx->receiver); - subghz->txrx->preset->frequency = subghz_setting_get_hopper_frequency( - subghz->setting, subghz->txrx->hopper_idx_frequency); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } + subghz->lock = SubGhzLockOn; } -void subghz_speaker_on(SubGhz* subghz) { - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_acquire(30)) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); - } else { - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - } - } +void subghz_unlock(SubGhz* subghz) { + furi_assert(subghz); + subghz->lock = SubGhzLockOff; } -void subghz_speaker_off(SubGhz* subghz) { - if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) { - if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); - furi_hal_speaker_release(); - if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown) - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - } - } +bool subghz_is_locked(SubGhz* subghz) { + furi_assert(subghz); + return (subghz->lock == SubGhzLockOn); } -void subghz_speaker_mute(SubGhz* subghz) { - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); - } - } +void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state) { + furi_assert(subghz); + subghz->rx_key_state = state; } -void subghz_speaker_unmute(SubGhz* subghz) { - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); - } - } +SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz) { + furi_assert(subghz); + return subghz->rx_key_state; } diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 65480c6fd0..fc3404c07e 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -25,10 +25,6 @@ #include #include -#include -#include -#include -#include #include "subghz_history.h" @@ -37,33 +33,11 @@ #include "rpc/rpc_app.h" -#define SUBGHZ_MAX_LEN_NAME 64 - -struct SubGhzTxRx { - SubGhzWorker* worker; - - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; - SubGhzTransmitter* transmitter; - SubGhzProtocolFlag filter; - SubGhzProtocolDecoderBase* decoder_result; - FlipperFormat* fff_data; - - SubGhzRadioPreset* preset; - SubGhzHistory* history; - uint16_t idx_menu_chosen; - SubGhzTxRxState txrx_state; - SubGhzHopperState hopper_state; - SubGhzSpeakerState speaker_state; - uint8_t hopper_timeout; - uint8_t hopper_idx_frequency; - SubGhzRxKeyState rx_key_state; +#include "helpers/subghz_threshold_rssi.h" - float raw_threshold_rssi; - uint8_t raw_threshold_rssi_low_count; -}; +#include "helpers/subghz_txrx.h" -typedef struct SubGhzTxRx SubGhzTxRx; +#define SUBGHZ_MAX_LEN_NAME 64 struct SubGhz { Gui* gui; @@ -93,47 +67,43 @@ struct SubGhz { SubGhzTestStatic* subghz_test_static; SubGhzTestCarrier* subghz_test_carrier; SubGhzTestPacket* subghz_test_packet; + + SubGhzProtocolFlag filter; FuriString* error_str; - SubGhzSetting* setting; SubGhzLock lock; - + SubGhzThresholdRssi* threshold_rssi; + SubGhzRxKeyState rx_key_state; + SubGhzHistory* history; + uint16_t idx_menu_chosen; + SubGhzLoadTypeFile load_type_file; void* rpc_ctx; }; -void subghz_preset_init( - void* context, - const char* preset_name, - uint32_t frequency, - uint8_t* preset_data, - size_t preset_data_size); -bool subghz_set_preset(SubGhz* subghz, const char* preset); -void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation); -void subghz_begin(SubGhz* subghz, uint8_t* preset_data); -uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); -void subghz_rx_end(SubGhz* subghz); -void subghz_sleep(SubGhz* subghz); - -void subghz_blink_start(SubGhz* instance); -void subghz_blink_stop(SubGhz* instance); +void subghz_set_default_preset(SubGhz* subghz); +void subghz_blink_start(SubGhz* subghz); +void subghz_blink_stop(SubGhz* subghz); bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); -void subghz_tx_stop(SubGhz* subghz); void subghz_dialog_message_show_only_rx(SubGhz* subghz); + bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog); bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len); bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, const char* dev_file_name); +void subghz_save_to_file(void* context); bool subghz_load_protocol_from_file(SubGhz* subghz); bool subghz_rename_file(SubGhz* subghz); bool subghz_file_available(SubGhz* subghz); bool subghz_delete_file(SubGhz* subghz); void subghz_file_name_clear(SubGhz* subghz); bool subghz_path_is_file(FuriString* path); -uint32_t subghz_random_serial(void); -void subghz_hopper_update(SubGhz* subghz); -void subghz_speaker_on(SubGhz* subghz); -void subghz_speaker_off(SubGhz* subghz); -void subghz_speaker_mute(SubGhz* subghz); -void subghz_speaker_unmute(SubGhz* subghz); +SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz); + +void subghz_lock(SubGhz* subghz); +void subghz_unlock(SubGhz* subghz); +bool subghz_is_locked(SubGhz* subghz); + +void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state); +SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index acc39e2581..f84ddfed08 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -44,7 +44,7 @@ typedef enum { } SubGhzViewReceiverBarShow; struct SubGhzViewReceiver { - SubGhzLock lock; + bool lock; uint8_t lock_count; FuriTimer* timer; View* view; @@ -70,20 +70,21 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { instance->view, SubGhzViewReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); } -void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) { +void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool lock) { furi_assert(subghz_receiver); subghz_receiver->lock_count = 0; - if(lock == SubGhzLockOn) { - subghz_receiver->lock = lock; + + if(lock == true) { + subghz_receiver->lock = true; with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -280,7 +281,7 @@ static void subghz_view_receiver_timer_callback(void* context) { subghz_receiver->callback( SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context); } else { - subghz_receiver->lock = SubGhzLockOff; + subghz_receiver->lock = false; subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context); } subghz_receiver->lock_count = 0; @@ -290,7 +291,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { furi_assert(context); SubGhzViewReceiver* subghz_receiver = context; - if(subghz_receiver->lock == SubGhzLockOn) { + if(subghz_receiver->lock == true) { with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -310,7 +311,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { SubGhzViewReceiverModel * model, { model->bar_show = SubGhzViewReceiverBarShowUnlock; }, true); - //subghz_receiver->lock = SubGhzLockOff; + //subghz_receiver->lock = false; furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650)); } @@ -394,7 +395,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { // View allocation and configuration subghz_receiver->view = view_alloc(); - subghz_receiver->lock = SubGhzLockOff; + subghz_receiver->lock = false; subghz_receiver->lock_count = 0; view_allocate_model( subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel)); diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index 9b12ccfee8..5119105e93 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -10,7 +10,7 @@ typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* contex void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi); -void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard); +void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool keyboard); void subghz_view_receiver_set_callback( SubGhzViewReceiver* subghz_receiver, diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index 87c8a30828..2ff598b605 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -60,10 +60,10 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool tra furi_assert(instance); uint8_t u_rssi = 0; - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { u_rssi = 0; } else { - u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); } with_view_model( @@ -261,9 +261,9 @@ void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* mod uint8_t x = 118; uint8_t y = 48; - if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) { + if(model->raw_threshold_rssi > SUBGHZ_RAW_THRESHOLD_MIN) { uint8_t x = 118; - y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); uint8_t width = 3; for(uint8_t i = 0; i < x; i += width * 2) { diff --git a/applications/main/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h index bc87119239..31aa9db6fd 100644 --- a/applications/main/subghz/views/subghz_read_raw.h +++ b/applications/main/subghz/views/subghz_read_raw.h @@ -3,7 +3,7 @@ #include #include "../helpers/subghz_custom_event.h" -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct SubGhzReadRAW SubGhzReadRAW; diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 4a13460a37..86dc17a38f 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -14,7 +14,7 @@ typedef struct { FuriString* frequency_str; FuriString* preset_str; FuriString* key_str; - uint8_t show_button; + bool show_button; } SubGhzViewTransmitterModel; void subghz_view_transmitter_set_callback( @@ -32,7 +32,7 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button) { + bool show_button) { furi_assert(subghz_transmitter); with_view_model( subghz_transmitter->view, @@ -104,7 +104,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_reset(model->frequency_str); furi_string_reset(model->preset_str); furi_string_reset(model->key_str); - model->show_button = 0; + model->show_button = false; }, false); return false; diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 64bcbd1afa..06aae7c6bf 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -23,4 +23,4 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button); + bool show_button); diff --git a/lib/subghz/environment.c b/lib/subghz/environment.c index b39b259d41..5ded243c41 100644 --- a/lib/subghz/environment.c +++ b/lib/subghz/environment.c @@ -16,6 +16,7 @@ SubGhzEnvironment* subghz_environment_alloc() { instance->protocol_registry = NULL; instance->came_atomo_rainbow_table_file_name = NULL; instance->nice_flor_s_rainbow_table_file_name = NULL; + instance->alutech_at_4n_rainbow_table_file_name = NULL; return instance; } @@ -26,6 +27,7 @@ void subghz_environment_free(SubGhzEnvironment* instance) { instance->protocol_registry = NULL; instance->came_atomo_rainbow_table_file_name = NULL; instance->nice_flor_s_rainbow_table_file_name = NULL; + instance->alutech_at_4n_rainbow_table_file_name = NULL; subghz_keystore_free(instance->keystore); free(instance); From a7d1ec03e878c062ba07132474720d0d54d26b97 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 3 May 2023 20:48:13 -0700 Subject: [PATCH 03/14] [FL-3270] Loader refactoring, part 1 (#2593) * Loader: menu part * Settings: remove unused loader api * Desktop: get loader from record_open * CLI: remove unneeded loader api * gitignore: ignore .old files * Loader: now really a service * Loader: working service prototype * Loader: cli, system start hooks * CI/CD: make happy * Loader: autorun * Loader: lock and unlock * Loader: rearrange code * Gui, module menu: fix memleak * Updater test: add timeout * added update timeouts and max run duration * Github: revert updater test workflow changes * Loader: less missleading message in info cli command Co-authored-by: doomwastaken Co-authored-by: Aleksandr Kutuzov --- .gitignore | 1 + applications/services/cli/cli_commands.c | 2 - .../desktop/scenes/desktop_scene_main.c | 8 +- applications/services/gui/modules/menu.c | 2 + applications/services/loader/application.fam | 9 + applications/services/loader/loader.c | 553 +++++++----------- applications/services/loader/loader.h | 13 +- applications/services/loader/loader_cli.c | 117 ++++ applications/services/loader/loader_i.h | 79 ++- applications/services/loader/loader_menu.c | 187 ++++++ applications/services/loader/loader_menu.h | 30 + .../settings/system/system_settings.c | 3 - firmware/targets/f18/api_symbols.csv | 7 +- firmware/targets/f7/api_symbols.csv | 7 +- 14 files changed, 615 insertions(+), 403 deletions(-) create mode 100644 applications/services/loader/loader_cli.c create mode 100644 applications/services/loader/loader_menu.c create mode 100644 applications/services/loader/loader_menu.h diff --git a/.gitignore b/.gitignore index 89e129acea..bf17a94e28 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp *.swo *.gdb_history +*.old # LSP diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 0f042f6c48..3f94deebcf 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -220,11 +220,9 @@ void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) { UNUSED(context); if(!furi_string_cmp(args, "0")) { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug disabled."); } else if(!furi_string_cmp(args, "1")) { furi_hal_rtc_set_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug enabled."); } else { cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args)); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 4d1fa49505..053ac56f1e 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -106,10 +106,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case DesktopMainEventOpenMenu: - loader_show_menu(); + case DesktopMainEventOpenMenu: { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_show_menu(loader); + furi_record_close(RECORD_LOADER); consumed = true; - break; + } break; case DesktopMainEventOpenLockMenu: scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); diff --git a/applications/services/gui/modules/menu.c b/applications/services/gui/modules/menu.c index 3e3b6c2e48..afae8b8fa2 100644 --- a/applications/services/gui/modules/menu.c +++ b/applications/services/gui/modules/menu.c @@ -154,6 +154,8 @@ Menu* menu_alloc() { void menu_free(Menu* menu) { furi_assert(menu); menu_reset(menu); + with_view_model( + menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false); view_free(menu->view); free(menu); } diff --git a/applications/services/loader/application.fam b/applications/services/loader/application.fam index 49f3c41488..f4d006e076 100644 --- a/applications/services/loader/application.fam +++ b/applications/services/loader/application.fam @@ -5,6 +5,7 @@ App( entry_point="loader_srv", cdefines=["SRV_LOADER"], requires=["gui"], + provides=["loader_start"], stack_size=2 * 1024, order=90, sdk_headers=[ @@ -12,3 +13,11 @@ App( "firmware_api/firmware_api.h", ], ) + +App( + appid="loader_start", + apptype=FlipperAppType.STARTUP, + entry_point="loader_on_system_start", + requires=["loader"], + order=90, +) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index f83d47d63d..be16e5091f 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,76 +1,114 @@ -#include "applications.h" -#include -#include "loader/loader.h" +#include "loader.h" #include "loader_i.h" +#include "loader_menu.h" +#include +#include + +#define TAG "Loader" +#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF +// api + +LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { + LoaderMessage message; + LoaderMessageLoaderStatusResult result; + + message.type = LoaderMessageTypeStartByName; + message.start.name = name; + message.start.args = args; + message.api_lock = api_lock_alloc_locked(); + message.status_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -#define TAG "LoaderSrv" - -#define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) -#define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU) - -static Loader* loader_instance = NULL; +bool loader_lock(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeLock; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -static bool - loader_start_application(const FlipperApplication* application, const char* arguments) { - loader_instance->application = application; +void loader_unlock(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeUnlock; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - furi_assert(loader_instance->application_arguments == NULL); - if(arguments && strlen(arguments) > 0) { - loader_instance->application_arguments = strdup(arguments); - } +bool loader_is_locked(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeIsLocked; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} - FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); +void loader_show_menu(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowMenu; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); - if(mode > FuriHalRtcHeapTrackModeNone) { - furi_thread_enable_heap_trace(loader_instance->application_thread); - } else { - furi_thread_disable_heap_trace(loader_instance->application_thread); - } +FuriPubSub* loader_get_pubsub(Loader* loader) { + furi_assert(loader); + // it's safe to return pubsub without locking + // because it's never freed and loader is never exited + // also the loader instance cannot be obtained until the pubsub is created + return loader->pubsub; +} - furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name); - furi_thread_set_appid( - loader_instance->application_thread, loader_instance->application->appid); - furi_thread_set_stack_size( - loader_instance->application_thread, loader_instance->application->stack_size); - furi_thread_set_context( - loader_instance->application_thread, loader_instance->application_arguments); - furi_thread_set_callback( - loader_instance->application_thread, loader_instance->application->app); +// callbacks - furi_thread_start(loader_instance->application_thread); +static void loader_menu_closed_callback(void* context) { + Loader* loader = context; + LoaderMessage message; + message.type = LoaderMessageTypeMenuClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - return true; +static void loader_menu_click_callback(const char* name, void* context) { + Loader* loader = context; + loader_start(loader, name, NULL); } -static void loader_menu_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const FlipperApplication* application = _ctx; +static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { + furi_assert(context); - furi_assert(application->app); - furi_assert(application->name); + Loader* loader = context; + LoaderEvent event; - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; - } + if(thread_state == FuriThreadStateRunning) { + event.type = LoaderEventTypeApplicationStarted; + furi_pubsub_publish(loader->pubsub, &event); + } else if(thread_state == FuriThreadStateStopped) { + LoaderMessage message; + message.type = LoaderMessageTypeAppClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); - loader_start_application(application, NULL); + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); + } } -static void loader_submenu_callback(void* context, uint32_t index) { - UNUSED(index); - uint32_t view_id = (uint32_t)context; - view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); -} +// implementation -static void loader_cli_print_usage() { - printf("Usage:\r\n"); - printf("loader \r\n"); - printf("Cmd list:\r\n"); - printf("\tlist\t - List available applications\r\n"); - printf("\topen \t - Open application by name\r\n"); - printf("\tinfo\t - Show loader state\r\n"); +static Loader* loader_alloc() { + Loader* loader = malloc(sizeof(Loader)); + loader->pubsub = furi_pubsub_alloc(); + loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); + loader->loader_menu = NULL; + loader->app.args = NULL; + loader->app.name = NULL; + loader->app.thread = NULL; + loader->app.insomniac = false; + return loader; } static FlipperApplication const* loader_find_application_by_name_in_list( @@ -85,7 +123,7 @@ static FlipperApplication const* loader_find_application_by_name_in_list( return NULL; } -const FlipperApplication* loader_find_application_by_name(const char* name) { +static const FlipperApplication* loader_find_application_by_name(const char* name) { const FlipperApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { @@ -100,346 +138,167 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { return application; } -static void loader_cli_open(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - if(loader_is_locked(instance)) { - if(instance->application) { - furi_assert(instance->application->name); - printf("Can't start, %s application is running", instance->application->name); - } else { - printf("Can't start, furi application is running"); - } - return; - } - - FuriString* application_name; - application_name = furi_string_alloc(); - - do { - if(!args_read_probably_quoted_string_and_trim(args, application_name)) { - printf("No application provided\r\n"); - break; - } +static void + loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); - const FlipperApplication* application = - loader_find_application_by_name(furi_string_get_cstr(application_name)); - if(!application) { - printf("%s doesn't exists\r\n", furi_string_get_cstr(application_name)); - break; - } + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); + } - furi_string_trim(args); - if(!loader_start_application(application, furi_string_get_cstr(args))) { - printf("Can't start, furi application is running"); - return; - } else { - // We must to increment lock counter to keep balance - // TODO: rewrite whole thing, it's complex as hell - FURI_CRITICAL_ENTER(); - instance->lock_count++; - FURI_CRITICAL_EXIT(); - } - } while(false); + // store name + furi_assert(loader->app.name == NULL); + loader->app.name = strdup(app->name); - furi_string_free(application_name); -} + // setup app thread + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); -static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - UNUSED(instance); - printf("Applications:\r\n"); - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - printf("\t%s\r\n", FLIPPER_APPS[i].name); + // setup heap trace + FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); + if(mode > FuriHalRtcHeapTrackModeNone) { + furi_thread_enable_heap_trace(loader->app.thread); + } else { + furi_thread_disable_heap_trace(loader->app.thread); } -} -static void loader_cli_info(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - if(!loader_is_locked(instance)) { - printf("No application is running\r\n"); + // setup insomnia + if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + furi_hal_power_insomnia_enter(); + loader->app.insomniac = true; } else { - printf("Running application: "); - if(instance->application) { - furi_assert(instance->application->name); - printf("%s\r\n", instance->application->name); - } else { - printf("unknown\r\n"); - } + loader->app.insomniac = false; } -} -static void loader_cli(Cli* cli, FuriString* args, void* _ctx) { - furi_assert(_ctx); - Loader* instance = _ctx; + // setup app thread callbacks + furi_thread_set_state_context(loader->app.thread, loader); + furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); - FuriString* cmd; - cmd = furi_string_alloc(); - - do { - if(!args_read_string_and_trim(args, cmd)) { - loader_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(cmd, "list") == 0) { - loader_cli_list(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "open") == 0) { - loader_cli_open(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "info") == 0) { - loader_cli_info(cli, args, instance); - break; - } - - loader_cli_print_usage(); - } while(false); - - furi_string_free(cmd); + // start app thread + furi_thread_start(loader->app.thread); } -LoaderStatus loader_start(Loader* instance, const char* name, const char* args) { - UNUSED(instance); - furi_assert(name); +// process messages - const FlipperApplication* application = loader_find_application_by_name(name); - - if(!application) { - FURI_LOG_E(TAG, "Can't find application with name %s", name); - return LoaderStatusErrorUnknownApp; +static void loader_do_menu_show(Loader* loader) { + if(!loader->loader_menu) { + loader->loader_menu = loader_menu_alloc(); + loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); + loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); + loader_menu_start(loader->loader_menu); } - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return LoaderStatusErrorAppStarted; - } - - if(!loader_start_application(application, args)) { - return LoaderStatusErrorInternal; - } - - return LoaderStatusOk; } -bool loader_lock(Loader* instance) { - FURI_CRITICAL_ENTER(); - bool result = false; - if(instance->lock_count == 0) { - instance->lock_count++; - result = true; +static void loader_do_menu_closed(Loader* loader) { + if(loader->loader_menu) { + loader_menu_stop(loader->loader_menu); + loader_menu_free(loader->loader_menu); + loader->loader_menu = NULL; } - FURI_CRITICAL_EXIT(); - return result; } -void loader_unlock(Loader* instance) { - FURI_CRITICAL_ENTER(); - if(instance->lock_count > 0) instance->lock_count--; - FURI_CRITICAL_EXIT(); +static bool loader_do_is_locked(Loader* loader) { + return loader->app.thread != NULL; } -bool loader_is_locked(const Loader* instance) { - return instance->lock_count > 0; -} - -static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - - Loader* instance = context; - LoaderEvent event; - - if(thread_state == FuriThreadStateRunning) { - event.type = LoaderEventTypeApplicationStarted; - furi_pubsub_publish(loader_instance->pubsub, &event); - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_enter(); - } - } else if(thread_state == FuriThreadStateStopped) { - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); - - if(loader_instance->application_arguments) { - free(loader_instance->application_arguments); - loader_instance->application_arguments = NULL; - } - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_exit(); - } - loader_unlock(instance); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader_instance->pubsub, &event); +static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { + if(loader_do_is_locked(loader)) { + return LoaderStatusErrorAppStarted; } -} -static uint32_t loader_hide_menu(void* context) { - UNUSED(context); - return VIEW_NONE; -} + const FlipperApplication* app = loader_find_application_by_name(name); -static uint32_t loader_back_to_primary_menu(void* context) { - furi_assert(context); - Submenu* submenu = context; - submenu_set_selected_item(submenu, 0); - return LoaderMenuViewPrimary; -} + if(!app) { + return LoaderStatusErrorUnknownApp; + } -static Loader* loader_alloc() { - Loader* instance = malloc(sizeof(Loader)); - - instance->application_thread = furi_thread_alloc(); - - furi_thread_set_state_context(instance->application_thread, instance); - furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback); - - instance->pubsub = furi_pubsub_alloc(); - -#ifdef SRV_CLI - instance->cli = furi_record_open(RECORD_CLI); - cli_add_command( - instance->cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, instance); -#else - UNUSED(loader_cli); -#endif - - instance->loader_thread = furi_thread_get_current_id(); - - // Gui - instance->gui = furi_record_open(RECORD_GUI); - instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - // Primary menu - instance->primary_menu = menu_alloc(); - view_set_previous_callback(menu_get_view(instance->primary_menu), loader_hide_menu); - view_dispatcher_add_view( - instance->view_dispatcher, LoaderMenuViewPrimary, menu_get_view(instance->primary_menu)); - // Settings menu - instance->settings_menu = submenu_alloc(); - view_set_context(submenu_get_view(instance->settings_menu), instance->settings_menu); - view_set_previous_callback( - submenu_get_view(instance->settings_menu), loader_back_to_primary_menu); - view_dispatcher_add_view( - instance->view_dispatcher, - LoaderMenuViewSettings, - submenu_get_view(instance->settings_menu)); - - view_dispatcher_enable_queue(instance->view_dispatcher); - - return instance; + loader_start_internal_app(loader, app, args); + return LoaderStatusOk; } -static void loader_free(Loader* instance) { - furi_assert(instance); - - if(instance->cli) { - furi_record_close(RECORD_CLI); +static bool loader_do_lock(Loader* loader) { + if(loader->app.thread) { + return false; } - furi_pubsub_free(instance->pubsub); - - furi_thread_free(instance->application_thread); - - menu_free(loader_instance->primary_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary); - submenu_free(loader_instance->settings_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_free(loader_instance->view_dispatcher); - - furi_record_close(RECORD_GUI); + loader->app.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE; + return true; +} - free(instance); - instance = NULL; +static void loader_do_unlock(Loader* loader) { + furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + loader->app.thread = NULL; } -static void loader_build_menu() { - FURI_LOG_I(TAG, "Building main menu"); - size_t i; - for(i = 0; i < FLIPPER_APPS_COUNT; i++) { - menu_add_item( - loader_instance->primary_menu, - FLIPPER_APPS[i].name, - FLIPPER_APPS[i].icon, - i, - loader_menu_callback, - (void*)&FLIPPER_APPS[i]); +static void loader_do_app_closed(Loader* loader) { + furi_assert(loader->app.thread); + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + if(loader->app.args) { + free(loader->app.args); + loader->app.args = NULL; } - menu_add_item( - loader_instance->primary_menu, - "Settings", - &A_Settings_14, - i++, - loader_submenu_callback, - (void*)LoaderMenuViewSettings); -} -static void loader_build_submenu() { - FURI_LOG_I(TAG, "Building settings menu"); - for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { - submenu_add_item( - loader_instance->settings_menu, - FLIPPER_SETTINGS_APPS[i].name, - i, - loader_menu_callback, - (void*)&FLIPPER_SETTINGS_APPS[i]); + if(loader->app.insomniac) { + furi_hal_power_insomnia_exit(); } -} -void loader_show_menu() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); -} + free(loader->app.name); + loader->app.name = NULL; -void loader_update_menu() { - menu_reset(loader_instance->primary_menu); - loader_build_menu(); + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; } +// app + int32_t loader_srv(void* p) { UNUSED(p); + Loader* loader = loader_alloc(); + furi_record_create(RECORD_LOADER, loader); + FURI_LOG_I(TAG, "Executing system start hooks"); for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { FLIPPER_ON_SYSTEM_START[i](); } - FURI_LOG_I(TAG, "Starting"); - loader_instance = loader_alloc(); - - loader_build_menu(); - loader_build_submenu(); - - FURI_LOG_I(TAG, "Started"); - - furi_record_create(RECORD_LOADER, loader_instance); - if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); } - while(1) { - uint32_t flags = - furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); - if(flags & LOADER_THREAD_FLAG_SHOW_MENU) { - menu_set_selected_item(loader_instance->primary_menu, 0); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_run(loader_instance->view_dispatcher); + LoaderMessage message; + while(true) { + if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { + switch(message.type) { + case LoaderMessageTypeStartByName: + message.status_value->value = + loader_do_start_by_name(loader, message.start.name, message.start.args); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeShowMenu: + loader_do_menu_show(loader); + break; + case LoaderMessageTypeMenuClosed: + loader_do_menu_closed(loader); + break; + case LoaderMessageTypeIsLocked: + message.bool_value->value = loader_do_is_locked(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeAppClosed: + loader_do_app_closed(loader); + break; + case LoaderMessageTypeLock: + message.bool_value->value = loader_do_lock(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeUnlock: + loader_do_unlock(loader); + } } } - furi_record_destroy(RECORD_LOADER); - loader_free(loader_instance); - return 0; -} - -FuriPubSub* loader_get_pubsub(Loader* instance) { - return instance->pubsub; -} +} \ No newline at end of file diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index 8dbc4fc358..e3a691b768 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,7 +1,5 @@ #pragma once - -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -43,17 +41,14 @@ bool loader_lock(Loader* instance); void loader_unlock(Loader* instance); /** Get loader lock status */ -bool loader_is_locked(const Loader* instance); - -/** Show primary loader */ -void loader_show_menu(); +bool loader_is_locked(Loader* instance); /** Show primary loader */ -void loader_update_menu(); +void loader_show_menu(Loader* instance); /** Show primary loader */ FuriPubSub* loader_get_pubsub(Loader* instance); #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c new file mode 100644 index 0000000000..2d46022157 --- /dev/null +++ b/applications/services/loader/loader_cli.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include "loader.h" + +static void loader_cli_print_usage() { + printf("Usage:\r\n"); + printf("loader \r\n"); + printf("Cmd list:\r\n"); + printf("\tlist\t - List available applications\r\n"); + printf("\topen \t - Open application by name\r\n"); + printf("\tinfo\t - Show loader state\r\n"); +} + +static void loader_cli_list() { + printf("Applications:\r\n"); + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_APPS[i].name); + } + printf("Settings:\r\n"); + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name); + } +} + +static void loader_cli_info(Loader* loader) { + if(!loader_is_locked(loader)) { + printf("No application is running\r\n"); + } else { + // TODO: print application name ??? + printf("Application is running\r\n"); + } +} + +static void loader_cli_open(FuriString* args, Loader* loader) { + FuriString* app_name = furi_string_alloc(); + + do { + if(!args_read_probably_quoted_string_and_trim(args, app_name)) { + printf("No application provided\r\n"); + break; + } + furi_string_trim(args); + + const char* args_str = furi_string_get_cstr(args); + if(strlen(args_str) == 0) { + args_str = NULL; + } + + const char* app_name_str = furi_string_get_cstr(app_name); + + LoaderStatus status = loader_start(loader, app_name_str, args_str); + + switch(status) { + case LoaderStatusOk: + break; + case LoaderStatusErrorAppStarted: + printf("Can't start, application is running"); + break; + case LoaderStatusErrorUnknownApp: + printf("%s doesn't exists\r\n", app_name_str); + break; + case LoaderStatusErrorInternal: + printf("Internal error\r\n"); + break; + } + } while(false); + + furi_string_free(app_name); +} + +static void loader_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + UNUSED(context); + Loader* loader = furi_record_open(RECORD_LOADER); + + FuriString* cmd; + cmd = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, cmd)) { + loader_cli_print_usage(); + break; + } + + if(furi_string_cmp_str(cmd, "list") == 0) { + loader_cli_list(); + break; + } + + if(furi_string_cmp_str(cmd, "open") == 0) { + loader_cli_open(args, loader); + break; + } + + if(furi_string_cmp_str(cmd, "info") == 0) { + loader_cli_info(loader); + break; + } + + loader_cli_print_usage(); + } while(false); + + furi_string_free(cmd); + furi_record_close(RECORD_LOADER); +} + +void loader_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(loader_cli); +#endif +} \ No newline at end of file diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 00028cd6b1..2e3f10dad0 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,39 +1,56 @@ -#include "loader.h" - +#pragma once #include -#include -#include -#include -#include - -#include - -#include -#include +#include +#include "loader.h" +#include "loader_menu.h" -#include -#include +typedef struct { + char* args; + char* name; + FuriThread* thread; + bool insomniac; +} LoaderAppData; struct Loader { - FuriThreadId loader_thread; - - const FlipperApplication* application; - FuriThread* application_thread; - char* application_arguments; - - Cli* cli; - Gui* gui; - - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - volatile uint8_t lock_count; - FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderMenu* loader_menu; + LoaderAppData app; }; typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; + LoaderMessageTypeStartByName, + LoaderMessageTypeAppClosed, + LoaderMessageTypeShowMenu, + LoaderMessageTypeMenuClosed, + LoaderMessageTypeLock, + LoaderMessageTypeUnlock, + LoaderMessageTypeIsLocked, +} LoaderMessageType; + +typedef struct { + const char* name; + const char* args; +} LoaderMessageStartByName; + +typedef struct { + LoaderStatus value; +} LoaderMessageLoaderStatusResult; + +typedef struct { + bool value; +} LoaderMessageBoolResult; + +typedef struct { + FuriApiLock api_lock; + LoaderMessageType type; + + union { + LoaderMessageStartByName start; + }; + + union { + LoaderMessageLoaderStatusResult* status_value; + LoaderMessageBoolResult* bool_value; + }; +} LoaderMessage; diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c new file mode 100644 index 0000000000..ec853661fb --- /dev/null +++ b/applications/services/loader/loader_menu.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +#include "loader_menu.h" + +#define TAG "LoaderMenu" + +struct LoaderMenu { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; + + void (*closed_callback)(void*); + void* closed_callback_context; + + void (*click_callback)(const char*, void*); + void* click_callback_context; + + FuriThread* thread; +}; + +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +static int32_t loader_menu_thread(void* p); + +LoaderMenu* loader_menu_alloc() { + LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); + loader_menu->gui = furi_record_open(RECORD_GUI); + loader_menu->view_dispatcher = view_dispatcher_alloc(); + loader_menu->primary_menu = menu_alloc(); + loader_menu->settings_menu = submenu_alloc(); + loader_menu->thread = NULL; + return loader_menu; +} + +void loader_menu_free(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + // check if thread is running + furi_assert(!loader_menu->thread); + + submenu_free(loader_menu->settings_menu); + menu_free(loader_menu->primary_menu); + view_dispatcher_free(loader_menu->view_dispatcher); + furi_record_close(RECORD_GUI); + free(loader_menu); +} + +void loader_menu_start(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(!loader_menu->thread); + loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); + furi_thread_start(loader_menu->thread); +} + +void loader_menu_stop(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(loader_menu->thread); + view_dispatcher_stop(loader_menu->view_dispatcher); + furi_thread_join(loader_menu->thread); + furi_thread_free(loader_menu->thread); + loader_menu->thread = NULL; +} + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context) { + loader_menu->closed_callback = callback; + loader_menu->closed_callback_context = context; +} + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context) { + loader_menu->click_callback = callback; + loader_menu->click_callback_context = context; +} + +static void loader_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_settings_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_SETTINGS_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_switch_to_settings(void* context, uint32_t index) { + UNUSED(index); + LoaderMenu* loader_menu = context; + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); +} + +static uint32_t loader_menu_switch_to_primary(void* context) { + UNUSED(context); + return LoaderMenuViewPrimary; +} + +static uint32_t loader_menu_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +static void loader_menu_build_menu(LoaderMenu* loader_menu) { + size_t i; + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_menu->primary_menu, + FLIPPER_APPS[i].name, + FLIPPER_APPS[i].icon, + i, + loader_menu_callback, + (void*)loader_menu); + } + menu_add_item( + loader_menu->primary_menu, + "Settings", + &A_Settings_14, + i++, + loader_menu_switch_to_settings, + loader_menu); +}; + +static void loader_menu_build_submenu(LoaderMenu* loader_menu) { + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + submenu_add_item( + loader_menu->settings_menu, + FLIPPER_SETTINGS_APPS[i].name, + i, + loader_menu_settings_menu_callback, + loader_menu); + } +} + +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + loader_menu_build_menu(loader_menu); + loader_menu_build_submenu(loader_menu); + + view_dispatcher_attach_to_gui( + loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + + // Primary menu + View* primary_view = menu_get_view(loader_menu->primary_menu); + view_set_context(primary_view, loader_menu->primary_menu); + view_set_previous_callback(primary_view, loader_menu_exit); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + + // Settings menu + View* settings_view = submenu_get_view(loader_menu->settings_menu); + view_set_context(settings_view, loader_menu->settings_menu); + view_set_previous_callback(settings_view, loader_menu_switch_to_primary); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + + view_dispatcher_enable_queue(loader_menu->view_dispatcher); + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + + // run view dispatcher + view_dispatcher_run(loader_menu->view_dispatcher); + + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + + if(loader_menu->closed_callback) { + loader_menu->closed_callback(loader_menu->closed_callback_context); + } + + return 0; +} \ No newline at end of file diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h new file mode 100644 index 0000000000..7405b87be7 --- /dev/null +++ b/applications/services/loader/loader_menu.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderMenu LoaderMenu; + +LoaderMenu* loader_menu_alloc(); + +void loader_menu_free(LoaderMenu* loader_menu); + +void loader_menu_start(LoaderMenu* loader_menu); + +void loader_menu_stop(LoaderMenu* loader_menu); + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context); + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 597710a53f..dd3c0dc6bd 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -43,7 +43,6 @@ static void debug_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); } - loader_update_menu(); } const char* const heap_trace_mode_text[] = { @@ -137,8 +136,6 @@ static void hand_orient_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient); } - - loader_update_menu(); } const char* const sleep_method[] = { diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f84bf074e1..bc6844d350 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1375,12 +1375,11 @@ Function,-,ldiv,ldiv_t,"long, long" Function,-,llabs,long long,long long Function,-,lldiv,lldiv_t,"long long, long long" Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index c176b2d7e1..1c8424fe8c 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1795,12 +1795,11 @@ Function,-,llround,long long int,double Function,-,llroundf,long long int,float Function,-,llroundl,long long int,long double Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* From ac05387803b7f0c71594959b1c060fb765a58d29 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 3 May 2023 20:48:13 -0700 Subject: [PATCH 04/14] [FL-3270] Loader refactoring, part 1 (#2593) * Loader: menu part * Settings: remove unused loader api * Desktop: get loader from record_open * CLI: remove unneeded loader api * gitignore: ignore .old files * Loader: now really a service * Loader: working service prototype * Loader: cli, system start hooks * CI/CD: make happy * Loader: autorun * Loader: lock and unlock * Loader: rearrange code * Gui, module menu: fix memleak * Updater test: add timeout * added update timeouts and max run duration * Github: revert updater test workflow changes * Loader: less missleading message in info cli command Co-authored-by: doomwastaken Co-authored-by: Aleksandr Kutuzov --- .gitignore | 1 + applications/services/cli/cli_commands.c | 2 - .../desktop/scenes/desktop_scene_main.c | 8 +- applications/services/loader/application.fam | 9 + applications/services/loader/loader.c | 553 +++++++----------- applications/services/loader/loader.h | 13 +- applications/services/loader/loader_cli.c | 117 ++++ applications/services/loader/loader_i.h | 79 ++- applications/services/loader/loader_menu.c | 187 ++++++ applications/services/loader/loader_menu.h | 30 + .../settings/system/system_settings.c | 3 - firmware/targets/f18/api_symbols.csv | 7 +- firmware/targets/f7/api_symbols.csv | 7 +- 13 files changed, 613 insertions(+), 403 deletions(-) create mode 100644 applications/services/loader/loader_cli.c create mode 100644 applications/services/loader/loader_menu.c create mode 100644 applications/services/loader/loader_menu.h diff --git a/.gitignore b/.gitignore index eacfec1e49..f199a48beb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp *.swo *.gdb_history +*.old # LSP diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 4e3e1104ae..a6b23c9422 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -230,11 +230,9 @@ void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) { UNUSED(context); if(!furi_string_cmp(args, "0")) { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug disabled."); } else if(!furi_string_cmp(args, "1")) { furi_hal_rtc_set_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug enabled."); } else { cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args)); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index fd04ff917e..9109ef309f 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -90,10 +90,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case DesktopMainEventOpenMenu: - loader_show_menu(); + case DesktopMainEventOpenMenu: { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_show_menu(loader); + furi_record_close(RECORD_LOADER); consumed = true; - break; + } break; case DesktopMainEventOpenLockMenu: scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); diff --git a/applications/services/loader/application.fam b/applications/services/loader/application.fam index 49f3c41488..f4d006e076 100644 --- a/applications/services/loader/application.fam +++ b/applications/services/loader/application.fam @@ -5,6 +5,7 @@ App( entry_point="loader_srv", cdefines=["SRV_LOADER"], requires=["gui"], + provides=["loader_start"], stack_size=2 * 1024, order=90, sdk_headers=[ @@ -12,3 +13,11 @@ App( "firmware_api/firmware_api.h", ], ) + +App( + appid="loader_start", + apptype=FlipperAppType.STARTUP, + entry_point="loader_on_system_start", + requires=["loader"], + order=90, +) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index f83d47d63d..be16e5091f 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,76 +1,114 @@ -#include "applications.h" -#include -#include "loader/loader.h" +#include "loader.h" #include "loader_i.h" +#include "loader_menu.h" +#include +#include + +#define TAG "Loader" +#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF +// api + +LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { + LoaderMessage message; + LoaderMessageLoaderStatusResult result; + + message.type = LoaderMessageTypeStartByName; + message.start.name = name; + message.start.args = args; + message.api_lock = api_lock_alloc_locked(); + message.status_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -#define TAG "LoaderSrv" - -#define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) -#define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU) - -static Loader* loader_instance = NULL; +bool loader_lock(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeLock; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -static bool - loader_start_application(const FlipperApplication* application, const char* arguments) { - loader_instance->application = application; +void loader_unlock(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeUnlock; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - furi_assert(loader_instance->application_arguments == NULL); - if(arguments && strlen(arguments) > 0) { - loader_instance->application_arguments = strdup(arguments); - } +bool loader_is_locked(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeIsLocked; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} - FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); +void loader_show_menu(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowMenu; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); - if(mode > FuriHalRtcHeapTrackModeNone) { - furi_thread_enable_heap_trace(loader_instance->application_thread); - } else { - furi_thread_disable_heap_trace(loader_instance->application_thread); - } +FuriPubSub* loader_get_pubsub(Loader* loader) { + furi_assert(loader); + // it's safe to return pubsub without locking + // because it's never freed and loader is never exited + // also the loader instance cannot be obtained until the pubsub is created + return loader->pubsub; +} - furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name); - furi_thread_set_appid( - loader_instance->application_thread, loader_instance->application->appid); - furi_thread_set_stack_size( - loader_instance->application_thread, loader_instance->application->stack_size); - furi_thread_set_context( - loader_instance->application_thread, loader_instance->application_arguments); - furi_thread_set_callback( - loader_instance->application_thread, loader_instance->application->app); +// callbacks - furi_thread_start(loader_instance->application_thread); +static void loader_menu_closed_callback(void* context) { + Loader* loader = context; + LoaderMessage message; + message.type = LoaderMessageTypeMenuClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - return true; +static void loader_menu_click_callback(const char* name, void* context) { + Loader* loader = context; + loader_start(loader, name, NULL); } -static void loader_menu_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const FlipperApplication* application = _ctx; +static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { + furi_assert(context); - furi_assert(application->app); - furi_assert(application->name); + Loader* loader = context; + LoaderEvent event; - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; - } + if(thread_state == FuriThreadStateRunning) { + event.type = LoaderEventTypeApplicationStarted; + furi_pubsub_publish(loader->pubsub, &event); + } else if(thread_state == FuriThreadStateStopped) { + LoaderMessage message; + message.type = LoaderMessageTypeAppClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); - loader_start_application(application, NULL); + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); + } } -static void loader_submenu_callback(void* context, uint32_t index) { - UNUSED(index); - uint32_t view_id = (uint32_t)context; - view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); -} +// implementation -static void loader_cli_print_usage() { - printf("Usage:\r\n"); - printf("loader \r\n"); - printf("Cmd list:\r\n"); - printf("\tlist\t - List available applications\r\n"); - printf("\topen \t - Open application by name\r\n"); - printf("\tinfo\t - Show loader state\r\n"); +static Loader* loader_alloc() { + Loader* loader = malloc(sizeof(Loader)); + loader->pubsub = furi_pubsub_alloc(); + loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); + loader->loader_menu = NULL; + loader->app.args = NULL; + loader->app.name = NULL; + loader->app.thread = NULL; + loader->app.insomniac = false; + return loader; } static FlipperApplication const* loader_find_application_by_name_in_list( @@ -85,7 +123,7 @@ static FlipperApplication const* loader_find_application_by_name_in_list( return NULL; } -const FlipperApplication* loader_find_application_by_name(const char* name) { +static const FlipperApplication* loader_find_application_by_name(const char* name) { const FlipperApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { @@ -100,346 +138,167 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { return application; } -static void loader_cli_open(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - if(loader_is_locked(instance)) { - if(instance->application) { - furi_assert(instance->application->name); - printf("Can't start, %s application is running", instance->application->name); - } else { - printf("Can't start, furi application is running"); - } - return; - } - - FuriString* application_name; - application_name = furi_string_alloc(); - - do { - if(!args_read_probably_quoted_string_and_trim(args, application_name)) { - printf("No application provided\r\n"); - break; - } +static void + loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); - const FlipperApplication* application = - loader_find_application_by_name(furi_string_get_cstr(application_name)); - if(!application) { - printf("%s doesn't exists\r\n", furi_string_get_cstr(application_name)); - break; - } + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); + } - furi_string_trim(args); - if(!loader_start_application(application, furi_string_get_cstr(args))) { - printf("Can't start, furi application is running"); - return; - } else { - // We must to increment lock counter to keep balance - // TODO: rewrite whole thing, it's complex as hell - FURI_CRITICAL_ENTER(); - instance->lock_count++; - FURI_CRITICAL_EXIT(); - } - } while(false); + // store name + furi_assert(loader->app.name == NULL); + loader->app.name = strdup(app->name); - furi_string_free(application_name); -} + // setup app thread + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); -static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - UNUSED(instance); - printf("Applications:\r\n"); - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - printf("\t%s\r\n", FLIPPER_APPS[i].name); + // setup heap trace + FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); + if(mode > FuriHalRtcHeapTrackModeNone) { + furi_thread_enable_heap_trace(loader->app.thread); + } else { + furi_thread_disable_heap_trace(loader->app.thread); } -} -static void loader_cli_info(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - if(!loader_is_locked(instance)) { - printf("No application is running\r\n"); + // setup insomnia + if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + furi_hal_power_insomnia_enter(); + loader->app.insomniac = true; } else { - printf("Running application: "); - if(instance->application) { - furi_assert(instance->application->name); - printf("%s\r\n", instance->application->name); - } else { - printf("unknown\r\n"); - } + loader->app.insomniac = false; } -} -static void loader_cli(Cli* cli, FuriString* args, void* _ctx) { - furi_assert(_ctx); - Loader* instance = _ctx; + // setup app thread callbacks + furi_thread_set_state_context(loader->app.thread, loader); + furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); - FuriString* cmd; - cmd = furi_string_alloc(); - - do { - if(!args_read_string_and_trim(args, cmd)) { - loader_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(cmd, "list") == 0) { - loader_cli_list(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "open") == 0) { - loader_cli_open(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "info") == 0) { - loader_cli_info(cli, args, instance); - break; - } - - loader_cli_print_usage(); - } while(false); - - furi_string_free(cmd); + // start app thread + furi_thread_start(loader->app.thread); } -LoaderStatus loader_start(Loader* instance, const char* name, const char* args) { - UNUSED(instance); - furi_assert(name); +// process messages - const FlipperApplication* application = loader_find_application_by_name(name); - - if(!application) { - FURI_LOG_E(TAG, "Can't find application with name %s", name); - return LoaderStatusErrorUnknownApp; +static void loader_do_menu_show(Loader* loader) { + if(!loader->loader_menu) { + loader->loader_menu = loader_menu_alloc(); + loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); + loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); + loader_menu_start(loader->loader_menu); } - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return LoaderStatusErrorAppStarted; - } - - if(!loader_start_application(application, args)) { - return LoaderStatusErrorInternal; - } - - return LoaderStatusOk; } -bool loader_lock(Loader* instance) { - FURI_CRITICAL_ENTER(); - bool result = false; - if(instance->lock_count == 0) { - instance->lock_count++; - result = true; +static void loader_do_menu_closed(Loader* loader) { + if(loader->loader_menu) { + loader_menu_stop(loader->loader_menu); + loader_menu_free(loader->loader_menu); + loader->loader_menu = NULL; } - FURI_CRITICAL_EXIT(); - return result; } -void loader_unlock(Loader* instance) { - FURI_CRITICAL_ENTER(); - if(instance->lock_count > 0) instance->lock_count--; - FURI_CRITICAL_EXIT(); +static bool loader_do_is_locked(Loader* loader) { + return loader->app.thread != NULL; } -bool loader_is_locked(const Loader* instance) { - return instance->lock_count > 0; -} - -static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - - Loader* instance = context; - LoaderEvent event; - - if(thread_state == FuriThreadStateRunning) { - event.type = LoaderEventTypeApplicationStarted; - furi_pubsub_publish(loader_instance->pubsub, &event); - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_enter(); - } - } else if(thread_state == FuriThreadStateStopped) { - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); - - if(loader_instance->application_arguments) { - free(loader_instance->application_arguments); - loader_instance->application_arguments = NULL; - } - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_exit(); - } - loader_unlock(instance); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader_instance->pubsub, &event); +static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { + if(loader_do_is_locked(loader)) { + return LoaderStatusErrorAppStarted; } -} -static uint32_t loader_hide_menu(void* context) { - UNUSED(context); - return VIEW_NONE; -} + const FlipperApplication* app = loader_find_application_by_name(name); -static uint32_t loader_back_to_primary_menu(void* context) { - furi_assert(context); - Submenu* submenu = context; - submenu_set_selected_item(submenu, 0); - return LoaderMenuViewPrimary; -} + if(!app) { + return LoaderStatusErrorUnknownApp; + } -static Loader* loader_alloc() { - Loader* instance = malloc(sizeof(Loader)); - - instance->application_thread = furi_thread_alloc(); - - furi_thread_set_state_context(instance->application_thread, instance); - furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback); - - instance->pubsub = furi_pubsub_alloc(); - -#ifdef SRV_CLI - instance->cli = furi_record_open(RECORD_CLI); - cli_add_command( - instance->cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, instance); -#else - UNUSED(loader_cli); -#endif - - instance->loader_thread = furi_thread_get_current_id(); - - // Gui - instance->gui = furi_record_open(RECORD_GUI); - instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - // Primary menu - instance->primary_menu = menu_alloc(); - view_set_previous_callback(menu_get_view(instance->primary_menu), loader_hide_menu); - view_dispatcher_add_view( - instance->view_dispatcher, LoaderMenuViewPrimary, menu_get_view(instance->primary_menu)); - // Settings menu - instance->settings_menu = submenu_alloc(); - view_set_context(submenu_get_view(instance->settings_menu), instance->settings_menu); - view_set_previous_callback( - submenu_get_view(instance->settings_menu), loader_back_to_primary_menu); - view_dispatcher_add_view( - instance->view_dispatcher, - LoaderMenuViewSettings, - submenu_get_view(instance->settings_menu)); - - view_dispatcher_enable_queue(instance->view_dispatcher); - - return instance; + loader_start_internal_app(loader, app, args); + return LoaderStatusOk; } -static void loader_free(Loader* instance) { - furi_assert(instance); - - if(instance->cli) { - furi_record_close(RECORD_CLI); +static bool loader_do_lock(Loader* loader) { + if(loader->app.thread) { + return false; } - furi_pubsub_free(instance->pubsub); - - furi_thread_free(instance->application_thread); - - menu_free(loader_instance->primary_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary); - submenu_free(loader_instance->settings_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_free(loader_instance->view_dispatcher); - - furi_record_close(RECORD_GUI); + loader->app.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE; + return true; +} - free(instance); - instance = NULL; +static void loader_do_unlock(Loader* loader) { + furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + loader->app.thread = NULL; } -static void loader_build_menu() { - FURI_LOG_I(TAG, "Building main menu"); - size_t i; - for(i = 0; i < FLIPPER_APPS_COUNT; i++) { - menu_add_item( - loader_instance->primary_menu, - FLIPPER_APPS[i].name, - FLIPPER_APPS[i].icon, - i, - loader_menu_callback, - (void*)&FLIPPER_APPS[i]); +static void loader_do_app_closed(Loader* loader) { + furi_assert(loader->app.thread); + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + if(loader->app.args) { + free(loader->app.args); + loader->app.args = NULL; } - menu_add_item( - loader_instance->primary_menu, - "Settings", - &A_Settings_14, - i++, - loader_submenu_callback, - (void*)LoaderMenuViewSettings); -} -static void loader_build_submenu() { - FURI_LOG_I(TAG, "Building settings menu"); - for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { - submenu_add_item( - loader_instance->settings_menu, - FLIPPER_SETTINGS_APPS[i].name, - i, - loader_menu_callback, - (void*)&FLIPPER_SETTINGS_APPS[i]); + if(loader->app.insomniac) { + furi_hal_power_insomnia_exit(); } -} -void loader_show_menu() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); -} + free(loader->app.name); + loader->app.name = NULL; -void loader_update_menu() { - menu_reset(loader_instance->primary_menu); - loader_build_menu(); + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; } +// app + int32_t loader_srv(void* p) { UNUSED(p); + Loader* loader = loader_alloc(); + furi_record_create(RECORD_LOADER, loader); + FURI_LOG_I(TAG, "Executing system start hooks"); for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { FLIPPER_ON_SYSTEM_START[i](); } - FURI_LOG_I(TAG, "Starting"); - loader_instance = loader_alloc(); - - loader_build_menu(); - loader_build_submenu(); - - FURI_LOG_I(TAG, "Started"); - - furi_record_create(RECORD_LOADER, loader_instance); - if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); } - while(1) { - uint32_t flags = - furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); - if(flags & LOADER_THREAD_FLAG_SHOW_MENU) { - menu_set_selected_item(loader_instance->primary_menu, 0); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_run(loader_instance->view_dispatcher); + LoaderMessage message; + while(true) { + if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { + switch(message.type) { + case LoaderMessageTypeStartByName: + message.status_value->value = + loader_do_start_by_name(loader, message.start.name, message.start.args); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeShowMenu: + loader_do_menu_show(loader); + break; + case LoaderMessageTypeMenuClosed: + loader_do_menu_closed(loader); + break; + case LoaderMessageTypeIsLocked: + message.bool_value->value = loader_do_is_locked(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeAppClosed: + loader_do_app_closed(loader); + break; + case LoaderMessageTypeLock: + message.bool_value->value = loader_do_lock(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeUnlock: + loader_do_unlock(loader); + } } } - furi_record_destroy(RECORD_LOADER); - loader_free(loader_instance); - return 0; -} - -FuriPubSub* loader_get_pubsub(Loader* instance) { - return instance->pubsub; -} +} \ No newline at end of file diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index 8dbc4fc358..e3a691b768 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,7 +1,5 @@ #pragma once - -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -43,17 +41,14 @@ bool loader_lock(Loader* instance); void loader_unlock(Loader* instance); /** Get loader lock status */ -bool loader_is_locked(const Loader* instance); - -/** Show primary loader */ -void loader_show_menu(); +bool loader_is_locked(Loader* instance); /** Show primary loader */ -void loader_update_menu(); +void loader_show_menu(Loader* instance); /** Show primary loader */ FuriPubSub* loader_get_pubsub(Loader* instance); #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c new file mode 100644 index 0000000000..2d46022157 --- /dev/null +++ b/applications/services/loader/loader_cli.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include "loader.h" + +static void loader_cli_print_usage() { + printf("Usage:\r\n"); + printf("loader \r\n"); + printf("Cmd list:\r\n"); + printf("\tlist\t - List available applications\r\n"); + printf("\topen \t - Open application by name\r\n"); + printf("\tinfo\t - Show loader state\r\n"); +} + +static void loader_cli_list() { + printf("Applications:\r\n"); + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_APPS[i].name); + } + printf("Settings:\r\n"); + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name); + } +} + +static void loader_cli_info(Loader* loader) { + if(!loader_is_locked(loader)) { + printf("No application is running\r\n"); + } else { + // TODO: print application name ??? + printf("Application is running\r\n"); + } +} + +static void loader_cli_open(FuriString* args, Loader* loader) { + FuriString* app_name = furi_string_alloc(); + + do { + if(!args_read_probably_quoted_string_and_trim(args, app_name)) { + printf("No application provided\r\n"); + break; + } + furi_string_trim(args); + + const char* args_str = furi_string_get_cstr(args); + if(strlen(args_str) == 0) { + args_str = NULL; + } + + const char* app_name_str = furi_string_get_cstr(app_name); + + LoaderStatus status = loader_start(loader, app_name_str, args_str); + + switch(status) { + case LoaderStatusOk: + break; + case LoaderStatusErrorAppStarted: + printf("Can't start, application is running"); + break; + case LoaderStatusErrorUnknownApp: + printf("%s doesn't exists\r\n", app_name_str); + break; + case LoaderStatusErrorInternal: + printf("Internal error\r\n"); + break; + } + } while(false); + + furi_string_free(app_name); +} + +static void loader_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + UNUSED(context); + Loader* loader = furi_record_open(RECORD_LOADER); + + FuriString* cmd; + cmd = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, cmd)) { + loader_cli_print_usage(); + break; + } + + if(furi_string_cmp_str(cmd, "list") == 0) { + loader_cli_list(); + break; + } + + if(furi_string_cmp_str(cmd, "open") == 0) { + loader_cli_open(args, loader); + break; + } + + if(furi_string_cmp_str(cmd, "info") == 0) { + loader_cli_info(loader); + break; + } + + loader_cli_print_usage(); + } while(false); + + furi_string_free(cmd); + furi_record_close(RECORD_LOADER); +} + +void loader_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(loader_cli); +#endif +} \ No newline at end of file diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 00028cd6b1..2e3f10dad0 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,39 +1,56 @@ -#include "loader.h" - +#pragma once #include -#include -#include -#include -#include - -#include - -#include -#include +#include +#include "loader.h" +#include "loader_menu.h" -#include -#include +typedef struct { + char* args; + char* name; + FuriThread* thread; + bool insomniac; +} LoaderAppData; struct Loader { - FuriThreadId loader_thread; - - const FlipperApplication* application; - FuriThread* application_thread; - char* application_arguments; - - Cli* cli; - Gui* gui; - - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - volatile uint8_t lock_count; - FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderMenu* loader_menu; + LoaderAppData app; }; typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; + LoaderMessageTypeStartByName, + LoaderMessageTypeAppClosed, + LoaderMessageTypeShowMenu, + LoaderMessageTypeMenuClosed, + LoaderMessageTypeLock, + LoaderMessageTypeUnlock, + LoaderMessageTypeIsLocked, +} LoaderMessageType; + +typedef struct { + const char* name; + const char* args; +} LoaderMessageStartByName; + +typedef struct { + LoaderStatus value; +} LoaderMessageLoaderStatusResult; + +typedef struct { + bool value; +} LoaderMessageBoolResult; + +typedef struct { + FuriApiLock api_lock; + LoaderMessageType type; + + union { + LoaderMessageStartByName start; + }; + + union { + LoaderMessageLoaderStatusResult* status_value; + LoaderMessageBoolResult* bool_value; + }; +} LoaderMessage; diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c new file mode 100644 index 0000000000..ec853661fb --- /dev/null +++ b/applications/services/loader/loader_menu.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +#include "loader_menu.h" + +#define TAG "LoaderMenu" + +struct LoaderMenu { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; + + void (*closed_callback)(void*); + void* closed_callback_context; + + void (*click_callback)(const char*, void*); + void* click_callback_context; + + FuriThread* thread; +}; + +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +static int32_t loader_menu_thread(void* p); + +LoaderMenu* loader_menu_alloc() { + LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); + loader_menu->gui = furi_record_open(RECORD_GUI); + loader_menu->view_dispatcher = view_dispatcher_alloc(); + loader_menu->primary_menu = menu_alloc(); + loader_menu->settings_menu = submenu_alloc(); + loader_menu->thread = NULL; + return loader_menu; +} + +void loader_menu_free(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + // check if thread is running + furi_assert(!loader_menu->thread); + + submenu_free(loader_menu->settings_menu); + menu_free(loader_menu->primary_menu); + view_dispatcher_free(loader_menu->view_dispatcher); + furi_record_close(RECORD_GUI); + free(loader_menu); +} + +void loader_menu_start(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(!loader_menu->thread); + loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); + furi_thread_start(loader_menu->thread); +} + +void loader_menu_stop(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(loader_menu->thread); + view_dispatcher_stop(loader_menu->view_dispatcher); + furi_thread_join(loader_menu->thread); + furi_thread_free(loader_menu->thread); + loader_menu->thread = NULL; +} + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context) { + loader_menu->closed_callback = callback; + loader_menu->closed_callback_context = context; +} + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context) { + loader_menu->click_callback = callback; + loader_menu->click_callback_context = context; +} + +static void loader_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_settings_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_SETTINGS_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_switch_to_settings(void* context, uint32_t index) { + UNUSED(index); + LoaderMenu* loader_menu = context; + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); +} + +static uint32_t loader_menu_switch_to_primary(void* context) { + UNUSED(context); + return LoaderMenuViewPrimary; +} + +static uint32_t loader_menu_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +static void loader_menu_build_menu(LoaderMenu* loader_menu) { + size_t i; + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_menu->primary_menu, + FLIPPER_APPS[i].name, + FLIPPER_APPS[i].icon, + i, + loader_menu_callback, + (void*)loader_menu); + } + menu_add_item( + loader_menu->primary_menu, + "Settings", + &A_Settings_14, + i++, + loader_menu_switch_to_settings, + loader_menu); +}; + +static void loader_menu_build_submenu(LoaderMenu* loader_menu) { + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + submenu_add_item( + loader_menu->settings_menu, + FLIPPER_SETTINGS_APPS[i].name, + i, + loader_menu_settings_menu_callback, + loader_menu); + } +} + +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + loader_menu_build_menu(loader_menu); + loader_menu_build_submenu(loader_menu); + + view_dispatcher_attach_to_gui( + loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + + // Primary menu + View* primary_view = menu_get_view(loader_menu->primary_menu); + view_set_context(primary_view, loader_menu->primary_menu); + view_set_previous_callback(primary_view, loader_menu_exit); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + + // Settings menu + View* settings_view = submenu_get_view(loader_menu->settings_menu); + view_set_context(settings_view, loader_menu->settings_menu); + view_set_previous_callback(settings_view, loader_menu_switch_to_primary); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + + view_dispatcher_enable_queue(loader_menu->view_dispatcher); + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + + // run view dispatcher + view_dispatcher_run(loader_menu->view_dispatcher); + + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + + if(loader_menu->closed_callback) { + loader_menu->closed_callback(loader_menu->closed_callback_context); + } + + return 0; +} \ No newline at end of file diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h new file mode 100644 index 0000000000..7405b87be7 --- /dev/null +++ b/applications/services/loader/loader_menu.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderMenu LoaderMenu; + +LoaderMenu* loader_menu_alloc(); + +void loader_menu_free(LoaderMenu* loader_menu); + +void loader_menu_start(LoaderMenu* loader_menu); + +void loader_menu_stop(LoaderMenu* loader_menu); + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context); + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 8cbe62da87..5ab9cc6f0d 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -43,7 +43,6 @@ static void debug_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); } - loader_update_menu(); } const char* const heap_trace_mode_text[] = { @@ -137,8 +136,6 @@ static void hand_orient_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient); } - - loader_update_menu(); } const char* const sleep_method[] = { diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f84bf074e1..bc6844d350 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1375,12 +1375,11 @@ Function,-,ldiv,ldiv_t,"long, long" Function,-,llabs,long long,long long Function,-,lldiv,lldiv_t,"long long, long long" Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 9c0cca01ab..a4d1b87a63 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1839,12 +1839,11 @@ Function,-,llround,long long int,double Function,-,llroundf,long long int,float Function,-,llroundl,long long int,long double Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* From 1f0c2c12666df847586cd347580930964ace0f46 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 02:09:21 +0300 Subject: [PATCH 05/14] SubGhz refactor merge pt 0 --- .../pocsag_pager/views/pocsag_pager_receiver.c | 6 +++--- .../weather_station/views/weather_station_receiver.c | 6 +++--- .../main/subghz/scenes/subghz_scene_show_error.c | 11 +++++------ .../main/subghz/scenes/subghz_scene_transmitter.c | 4 ++-- applications/main/subghz/views/transmitter.c | 6 +++--- applications/main/subghz/views/transmitter.h | 2 +- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c index 532f41984b..64939a9564 100644 --- a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c +++ b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -69,10 +69,10 @@ void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi) { instance->view, PCSGReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/external/weather_station/views/weather_station_receiver.c b/applications/external/weather_station/views/weather_station_receiver.c index 62f1adad02..e994e7830e 100644 --- a/applications/external/weather_station/views/weather_station_receiver.c +++ b/applications/external/weather_station/views/weather_station_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { instance->view, WSReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/scenes/subghz_scene_show_error.c b/applications/main/subghz/scenes/subghz_scene_show_error.c index 107189cae7..4544260ef6 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error.c @@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) { bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; + SubGhzCustomEvent scene_state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError); if(event.type == SceneManagerEventTypeBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { return false; } else { scene_manager_search_and_switch_to_previous_scene( @@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneShowErrorOk) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } return true; } else if(event.event == SubGhzCustomEventSceneShowErrorBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { //exit app if(!scene_manager_previous_scene(subghz->scene_manager)) { scene_manager_stop(subghz->scene_manager); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index ab9155fb7d..f20d039cb9 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -23,7 +23,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { key_str = furi_string_alloc(); frequency_str = furi_string_alloc(); modulation_str = furi_string_alloc(); - uint8_t show_button = 0; + bool show_button = false; if(subghz_protocol_decoder_base_deserialize( subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { @@ -31,7 +31,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) { - show_button = 1; + show_button = true; } subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 2bec77690e..5ae1a6e2c3 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -16,7 +16,7 @@ typedef struct { FuriString* frequency_str; FuriString* preset_str; FuriString* key_str; - uint8_t show_button; + bool show_button; FuriString* temp_button_id; bool draw_temp_button; } SubGhzViewTransmitterModel; @@ -36,7 +36,7 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button) { + bool show_button) { furi_assert(subghz_transmitter); with_view_model( subghz_transmitter->view, @@ -119,7 +119,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_reset(model->preset_str); furi_string_reset(model->key_str); furi_string_reset(model->temp_button_id); - model->show_button = 0; + model->show_button = false; model->draw_temp_button = false; }, false); diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 64bcbd1afa..06aae7c6bf 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -23,4 +23,4 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button); + bool show_button); From c36b788b2db733bfa96c3b2bdbad347feb90f81f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 03:17:53 +0300 Subject: [PATCH 06/14] Use COUNT_OF in mouse jiggler --- applications/external/hid_app/views/hid_mouse_jiggler.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/applications/external/hid_app/views/hid_mouse_jiggler.c b/applications/external/hid_app/views/hid_mouse_jiggler.c index 120d5bc34c..09c14c6688 100644 --- a/applications/external/hid_app/views/hid_mouse_jiggler.c +++ b/applications/external/hid_app/views/hid_mouse_jiggler.c @@ -6,8 +6,6 @@ #define TAG "HidMouseJiggler" -#define LENGTH(x) (int)(sizeof(x) / sizeof((x)[0])) - struct HidMouseJiggler { View* view; Hid* hid; @@ -44,7 +42,7 @@ static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { elements_multiline_text(canvas, AlignLeft, 26, "Interval (ms):"); canvas_set_font(canvas, FontSecondary); if(model->interval_idx != 0) canvas_draw_icon(canvas, 74, 19, &I_ButtonLeft_4x7); - if(model->interval_idx != LENGTH(intervals) - 1) + if(model->interval_idx != (int)COUNT_OF(intervals) - 1) canvas_draw_icon(canvas, 80, 19, &I_ButtonRight_4x7); FuriString* interval_str = furi_string_alloc_printf("%d", intervals[model->interval_idx]); elements_multiline_text(canvas, 91, 26, furi_string_get_cstr(interval_str)); @@ -116,7 +114,7 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { consumed = true; } if(event->type == InputTypePress && event->key == InputKeyRight && !model->running && - model->interval_idx < LENGTH(intervals) - 1) { + model->interval_idx < (int)COUNT_OF(intervals) - 1) { model->interval_idx++; consumed = true; } From b0b9e507e7b794e769866432cc07b1aa3faeeb42 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 03:51:16 +0300 Subject: [PATCH 07/14] SubGHz combine FuriString allocs --- .../subghz/scenes/subghz_scene_decode_raw.c | 28 +++++---------- .../main/subghz/scenes/subghz_scene_delete.c | 10 ++---- .../subghz/scenes/subghz_scene_delete_raw.c | 7 ++-- .../subghz/scenes/subghz_scene_read_raw.c | 16 +++------ .../subghz/scenes/subghz_scene_receiver.c | 24 +++++-------- .../scenes/subghz_scene_receiver_info.c | 10 ++---- .../main/subghz/scenes/subghz_scene_rpc.c | 3 +- .../subghz/scenes/subghz_scene_save_name.c | 8 ++--- .../subghz/scenes/subghz_scene_transmitter.c | 9 ++--- applications/main/subghz/subghz_cli.c | 36 +++++++------------ applications/main/subghz/subghz_history.c | 3 +- applications/main/subghz/subghz_i.c | 22 ++++-------- applications/main/subghz/views/receiver.c | 3 +- 13 files changed, 59 insertions(+), 120 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 5ac4fcccd5..b9f2d236bf 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -24,14 +24,10 @@ static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); @@ -62,11 +58,9 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -90,8 +84,7 @@ static void subghz_scene_add_to_history_callback( } bool subghz_scene_decode_raw_start(SubGhz* subghz) { - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); bool success = false; do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { @@ -148,8 +141,7 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { } // Update progress info - FuriString* progress_str; - progress_str = furi_string_alloc(); + FuriString* progress_str = furi_string_alloc(); subghz_file_encoder_worker_get_text_progress( subghz->decode_raw_file_worker_encoder, progress_str); @@ -164,10 +156,8 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { void subghz_scene_decode_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 94814b1432..4cad14bbf0 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -11,13 +11,9 @@ void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* co void subghz_scene_delete_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index fa4fc6f642..ee7983dfd3 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -15,11 +15,8 @@ void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void void subghz_scene_delete_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); char delete_str[SUBGHZ_MAX_LEN_NAME + 16]; FuriString* file_name; diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 0c692e000d..6a881cba44 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -12,8 +12,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; //set the path to read the file - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { FURI_LOG_E(TAG, "Rewind error"); @@ -38,11 +37,8 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME subghz_get_frequency_modulation(subghz, frequency_str, NULL); @@ -74,8 +70,7 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); switch(subghz->txrx->rx_key_state) { case SubGhzRxKeyStateBack: @@ -293,8 +288,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index b17a0700b4..fd8d9b70ec 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -39,14 +39,10 @@ const NotificationSequence subghz_sequence_rx_locked = { static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME if(subghz_history_get_last_index(subghz->txrx->history) > 0) { @@ -90,12 +86,12 @@ static void subghz_scene_add_to_history_callback( SubGhzProtocolDecoderBase* decoder_base, void* context) { furi_assert(context); + SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -122,10 +118,8 @@ static void subghz_scene_add_to_history_callback( void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 58e4287850..a108132c0d 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -49,13 +49,9 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { if(subghz_scene_receiver_info_update_parser(subghz)) { - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 9172f67c2c..8140f69a23 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -72,8 +72,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateLoaded); furi_string_set(subghz->file_path, arg); result = true; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); path_extract_filename(subghz->file_path, file_name, true); snprintf( diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index d3f5474beb..2bb13f1844 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -51,10 +51,8 @@ void subghz_scene_save_name_on_enter(void* context) { TextInput* text_input = subghz->text_input; bool dev_name_empty = false; - FuriString* file_name; - FuriString* dir_name; - file_name = furi_string_alloc(); - dir_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* dir_name = furi_string_alloc(); if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; @@ -109,7 +107,7 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_scene_save_name_text_input_callback, subghz, subghz->file_name_tmp, - MAX_TEXT_INPUT_LEN, // buffer size + MAX_TEXT_INPUT_LEN, dev_name_empty); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index f20d039cb9..d1fafd8ff8 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -16,13 +16,10 @@ bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; if(subghz->txrx->decoder_result) { - FuriString* key_str; - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* key_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - key_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); bool show_button = false; if(subghz_protocol_decoder_base_deserialize( diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index c047a32b3e..f30578fb28 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -215,8 +215,7 @@ static void subghz_cli_command_rx_callback( SubGhzCliCommandRx* instance = context; instance->packet_count++; - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_protocol_decoder_base_get_string(decoder_base, text); subghz_receiver_reset(receiver); printf("%s", furi_string_get_cstr(text)); @@ -384,14 +383,12 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { } void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { UNUSED(context); - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); furi_string_set(file_name, ANY_PATH("subghz/test.sub")); Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; bool check_file = false; @@ -526,10 +523,8 @@ static void subghz_cli_command_encrypt_keeloq(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); SubGhzKeystore* keystore = subghz_keystore_alloc(); @@ -569,10 +564,8 @@ static void subghz_cli_command_encrypt_raw(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); do { if(!args_read_string_and_trim(args, source)) { @@ -645,14 +638,10 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { size_t message_max_len = 64; uint8_t message[64] = {0}; - FuriString* input; - input = furi_string_alloc(); - FuriString* name; - name = furi_string_alloc(); - FuriString* output; - output = furi_string_alloc(); - FuriString* sysmsg; - sysmsg = furi_string_alloc(); + FuriString* input = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + FuriString* output = furi_string_alloc(); + FuriString* sysmsg = furi_string_alloc(); bool exit = false; SubGhzChatEvent chat_event; @@ -785,8 +774,7 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { } static void subghz_cli_command(Cli* cli, FuriString* args, void* context) { - FuriString* cmd; - cmd = furi_string_alloc(); + FuriString* cmd = furi_string_alloc(); do { if(!args_read_string_and_trim(args, cmd)) { diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index 3c018ec8bb..396e284210 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -197,8 +197,7 @@ bool subghz_history_add_to_history( instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base); instance->last_update_timestamp = furi_get_tick(); - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data); item->preset = malloc(sizeof(SubGhzRadioPreset)); item->type = decoder_base->protocol->type; diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index dd01602133..77eba42fbb 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -145,8 +145,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { furi_assert(subghz); bool ret = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t repeat = 200; do { if(!flipper_format_rewind(flipper_format)) { @@ -254,8 +253,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; do { @@ -393,13 +391,9 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* temp_str; - FuriString* file_name; - FuriString* file_path; - - temp_str = furi_string_alloc(); - file_name = furi_string_alloc(); - file_path = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); bool res = false; @@ -446,8 +440,7 @@ bool subghz_save_protocol_to_file( Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; - FuriString* file_dir; - file_dir = furi_string_alloc(); + FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { @@ -478,8 +471,7 @@ bool subghz_save_protocol_to_file( bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); - FuriString* file_path; - file_path = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index d48ff8b967..811a466988 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -239,8 +239,7 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { } bool scrollbar = model->history_item > 4; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* str_buff = furi_string_alloc(); SubGhzReceiverMenuItem* item_menu; From 914129a0d90a75952662f4c717d1d98ffe90fccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Fri, 5 May 2023 21:40:55 +0900 Subject: [PATCH 08/14] [FL-3289] Various Furi/FuriHal bug fixes and improvements (#2637) * Furi: properly handle thread free before TCB scrapping, add furi_free - more invasive version of free to memmgr. FuriHal: add DWT comparator api to cortex. Updater, RPC: refactor various thread shanenigans. Code cleanup. * Rollback free macros and related changes --- applications/services/loader/loader.c | 1 + applications/services/rpc/rpc.c | 48 +++++++------ .../services/storage/storage_external_api.c | 1 + .../services/storage/storages/storage_ext.c | 1 + .../power_settings_app/views/battery_info.c | 4 +- applications/system/updater/cli/updater_cli.c | 26 ++----- .../updater/util/update_task_worker_flasher.c | 6 +- firmware/targets/f18/api_symbols.csv | 7 +- firmware/targets/f7/api_symbols.csv | 7 +- .../targets/f7/furi_hal/furi_hal_cortex.c | 72 ++++++++++++++++++- .../furi_hal_include/furi_hal_cortex.h | 47 ++++++++++++ furi/core/thread.c | 28 ++++---- furi/core/thread.h | 8 +-- furi/core/timer.c | 10 +++ furi/core/timer.h | 4 ++ 15 files changed, 202 insertions(+), 68 deletions(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index be16e5091f..f385efdf95 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -248,6 +248,7 @@ static void loader_do_app_closed(Loader* loader) { free(loader->app.name); loader->app.name = NULL; + furi_thread_join(loader->app.thread); furi_thread_free(loader->app.thread); loader->app.thread = NULL; } diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 5b09e9b517..a759a12a9c 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -326,31 +326,35 @@ static int32_t rpc_session_worker(void* context) { return 0; } -static void rpc_session_free_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - +static void rpc_session_thread_pending_callback(void* context, uint32_t arg) { + UNUSED(arg); RpcSession* session = (RpcSession*)context; - if(thread_state == FuriThreadStateStopped) { - for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { - if(rpc_systems[i].free) { - rpc_systems[i].free(session->system_contexts[i]); - } - } - free(session->system_contexts); - free(session->decoded_message); - RpcHandlerDict_clear(session->handlers); - furi_stream_buffer_free(session->stream); - - furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); - if(session->terminated_callback) { - session->terminated_callback(session->context); + for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { + if(rpc_systems[i].free) { + (rpc_systems[i].free)(session->system_contexts[i]); } - furi_mutex_release(session->callbacks_mutex); + } + free(session->system_contexts); + free(session->decoded_message); + RpcHandlerDict_clear(session->handlers); + furi_stream_buffer_free(session->stream); - furi_mutex_free(session->callbacks_mutex); - furi_thread_free(session->thread); - free(session); + furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); + if(session->terminated_callback) { + session->terminated_callback(session->context); + } + furi_mutex_release(session->callbacks_mutex); + + furi_mutex_free(session->callbacks_mutex); + furi_thread_join(session->thread); + furi_thread_free(session->thread); + free(session); +} + +static void rpc_session_thread_state_callback(FuriThreadState thread_state, void* context) { + if(thread_state == FuriThreadStateStopped) { + furi_timer_pending_callback(rpc_session_thread_pending_callback, context, 0); } } @@ -385,7 +389,7 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); furi_thread_set_state_context(session->thread, session); - furi_thread_set_state_callback(session->thread, rpc_session_free_callback); + furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback); furi_thread_start(session->thread); diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index ffc3da4bc4..bf474bc9d0 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -803,6 +803,7 @@ void storage_file_free(File* file) { } FuriPubSub* storage_get_pubsub(Storage* storage) { + furi_assert(storage); return storage->pubsub; } diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index d802d6e9f6..15a355dc25 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -337,6 +337,7 @@ static bool storage_ext_file_close(void* ctx, File* file) { file->internal_error_id = f_close(file_data); file->error_id = storage_ext_parse_error(file->internal_error_id); free(file_data); + storage_set_storage_file_data(file, NULL, storage); return (file->error_id == FSE_OK); } diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index 0956cae4f5..d56dfc6285 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -53,7 +53,9 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { (uint32_t)(data->vbus_voltage), (uint32_t)(data->vbus_voltage * 10) % 10, current); - } else if(current < 0) { + } else if(current < -5) { + // Often gauge reports anything in the range 1~5ma as 5ma + // That brings confusion, so we'll treat it as Napping snprintf( emote, sizeof(emote), diff --git a/applications/system/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c index 2bf6dab26e..659c431f70 100644 --- a/applications/system/updater/cli/updater_cli.c +++ b/applications/system/updater/cli/updater_cli.c @@ -85,22 +85,10 @@ static void updater_cli_ep(Cli* cli, FuriString* args, void* context) { updater_cli_help(args); } -static int32_t updater_spawner_thread_worker(void* arg) { +static void updater_start_app(void* context, uint32_t arg) { + UNUSED(context); UNUSED(arg); - Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "UpdaterApp", NULL); - furi_record_close(RECORD_LOADER); - return 0; -} -static void updater_spawner_thread_cleanup(FuriThreadState state, void* context) { - FuriThread* thread = context; - if(state == FuriThreadStateStopped) { - furi_thread_free(thread); - } -} - -static void updater_start_app() { FuriHalRtcBootMode mode = furi_hal_rtc_get_boot_mode(); if((mode != FuriHalRtcBootModePreUpdate) && (mode != FuriHalRtcBootModePostUpdate)) { return; @@ -110,11 +98,9 @@ static void updater_start_app() { * inside loader process, at startup. * So, accessing its record would cause a deadlock */ - FuriThread* thread = - furi_thread_alloc_ex("UpdateAppSpawner", 768, updater_spawner_thread_worker, NULL); - furi_thread_set_state_callback(thread, updater_spawner_thread_cleanup); - furi_thread_set_state_context(thread, thread); - furi_thread_start(thread); + Loader* loader = furi_record_open(RECORD_LOADER); + loader_start(loader, "UpdaterApp", NULL); + furi_record_close(RECORD_LOADER); } void updater_on_system_start() { @@ -126,7 +112,7 @@ void updater_on_system_start() { UNUSED(updater_cli_ep); #endif #ifndef FURI_RAM_EXEC - updater_start_app(); + furi_timer_pending_callback(updater_start_app, NULL, 0); #else UNUSED(updater_start_app); #endif diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index 63024ced9c..5d24774646 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -346,7 +346,11 @@ int32_t update_task_worker_flash_writer(void* context) { furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); // Format LFS before restoring backup on next boot furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); - +#ifdef FURI_NDEBUG + // Production + furi_hal_rtc_set_log_level(FuriLogLevelDefault); + furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); +#endif update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); success = true; } while(false); diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index bc6844d350..f83f6405be 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,24.0,, +Version,+,26.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -892,6 +892,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1278,7 +1280,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1287,6 +1289,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1c8424fe8c..8a4e06303f 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,24.0,, +Version,+,26.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1073,6 +1073,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1562,7 +1564,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1571,6 +1573,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" diff --git a/firmware/targets/f7/furi_hal/furi_hal_cortex.c b/firmware/targets/f7/furi_hal/furi_hal_cortex.c index d0bce50381..3fbe384e3c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_cortex.c +++ b/firmware/targets/f7/furi_hal/furi_hal_cortex.c @@ -1,11 +1,12 @@ #include +#include #include #define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000) void furi_hal_cortex_init_early() { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + CoreDebug->DEMCR |= (CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk); DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CYCCNT = 0U; @@ -38,4 +39,71 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer) { void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer) { while(!furi_hal_cortex_timer_is_expired(cortex_timer)) ; -} \ No newline at end of file +} + +// Duck ST +#undef COMP0 +#undef COMP1 +#undef COMP2 +#undef COMP3 + +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size) { + uint32_t function_reg = (uint32_t)function | ((uint32_t)size << 10); + + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = value; + (DWT->MASK0) = mask; + (DWT->FUNCTION0) = function_reg; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = value; + (DWT->MASK1) = mask; + (DWT->FUNCTION1) = function_reg; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = value; + (DWT->MASK2) = mask; + (DWT->FUNCTION2) = function_reg; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = value; + (DWT->MASK3) = mask; + (DWT->FUNCTION3) = function_reg; + break; + default: + furi_crash("Invalid parameter"); + } +} + +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp) { + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = 0; + (DWT->MASK0) = 0; + (DWT->FUNCTION0) = 0; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = 0; + (DWT->MASK1) = 0; + (DWT->FUNCTION1) = 0; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = 0; + (DWT->MASK2) = 0; + (DWT->FUNCTION2) = 0; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = 0; + (DWT->MASK3) = 0; + (DWT->FUNCTION3) = 0; + break; + default: + furi_crash("Invalid parameter"); + } +} diff --git a/firmware/targets/furi_hal_include/furi_hal_cortex.h b/firmware/targets/furi_hal_include/furi_hal_cortex.h index 91596ffe3f..ebabbabfd8 100644 --- a/firmware/targets/furi_hal_include/furi_hal_cortex.h +++ b/firmware/targets/furi_hal_include/furi_hal_cortex.h @@ -56,6 +56,53 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer); */ void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer); +typedef enum { + FuriHalCortexComp0, + FuriHalCortexComp1, + FuriHalCortexComp2, + FuriHalCortexComp3, +} FuriHalCortexComp; + +typedef enum { + FuriHalCortexCompSizeWord = 0b10, + FuriHalCortexCompSizeHalfWord = 0b01, + FuriHalCortexCompSizeByte = 0b00, +} FuriHalCortexCompSize; + +typedef enum { + FuriHalCortexCompFunctionPC = 0b100, + FuriHalCortexCompFunctionRead = 0b101, + FuriHalCortexCompFunctionWrite = 0b110, + FuriHalCortexCompFunctionReadWrite = 0b110, +} FuriHalCortexCompFunction; + +/** Enable DWT comparator + * + * Allows to programmatically set instruction/data breakpoints. + * + * More details on how it works can be found in armv7m official documentation: + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/The-DWT-comparators + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Comparator-Function-registers--DWT-FUNCTIONn + * + * @param[in] comp The Comparator + * @param[in] function The Comparator Function to use + * @param[in] value The value + * @param[in] mask The mask + * @param[in] size The size + */ +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size); + +/** Reset DWT comparator + * + * @param[in] comp The Comparator + */ +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp); + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index d78070d61d..facbcb4117 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -164,10 +164,13 @@ FuriThread* furi_thread_alloc_ex( void furi_thread_free(FuriThread* thread) { furi_assert(thread); + + // Ensure that use join before free furi_assert(thread->state == FuriThreadStateStopped); + furi_assert(thread->task_handle == NULL); - if(thread->name) free((void*)thread->name); - if(thread->appid) free((void*)thread->appid); + if(thread->name) free(thread->name); + if(thread->appid) free(thread->appid); furi_string_free(thread->output.buffer); free(thread); @@ -176,14 +179,14 @@ void furi_thread_free(FuriThread* thread) { void furi_thread_set_name(FuriThread* thread, const char* name) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->name) free((void*)thread->name); + if(thread->name) free(thread->name); thread->name = name ? strdup(name) : NULL; } void furi_thread_set_appid(FuriThread* thread, const char* appid) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->appid) free((void*)thread->appid); + if(thread->appid) free(thread->appid); thread->appid = appid ? strdup(appid) : NULL; } @@ -276,7 +279,7 @@ void furi_thread_cleanup_tcb_event(TaskHandle_t task) { if(thread) { // clear thread local storage vTaskSetThreadLocalStoragePointer(task, 0, NULL); - + furi_assert(thread->task_handle == task); thread->task_handle = NULL; } } @@ -332,7 +335,6 @@ FuriThreadId furi_thread_get_current_id() { FuriThread* furi_thread_get_current() { FuriThread* thread = pvTaskGetThreadLocalStoragePointer(NULL, 0); - furi_assert(thread != NULL); return thread; } @@ -579,24 +581,22 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) { return 0; } -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); __furi_thread_stdout_flush(thread); thread->output.write_callback = callback; - - return true; } FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); return thread->output.write_callback; } size_t furi_thread_stdout_write(const char* data, size_t size) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); if(size == 0 || data == NULL) { return __furi_thread_stdout_flush(thread); } else { @@ -619,7 +619,9 @@ size_t furi_thread_stdout_write(const char* data, size_t size) { } int32_t furi_thread_stdout_flush() { - return __furi_thread_stdout_flush(furi_thread_get_current()); + FuriThread* thread = furi_thread_get_current(); + furi_assert(thread); + return __furi_thread_stdout_flush(thread); } void furi_thread_suspend(FuriThreadId thread_id) { diff --git a/furi/core/thread.h b/furi/core/thread.h index b11a225b58..022894ee8f 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -233,7 +233,7 @@ FuriThreadId furi_thread_get_current_id(); /** Get FuriThread instance for current thread * - * @return FuriThread* + * @return pointer to FuriThread or NULL if this thread doesn't belongs to Furi */ FuriThread* furi_thread_get_current(); @@ -288,12 +288,10 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(); /** Set STDOUT callback for thread - * + * * @param callback callback or NULL to clear - * - * @return true on success, otherwise fail */ -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); /** Write data to buffered STDOUT * diff --git a/furi/core/timer.c b/furi/core/timer.c index 4b6ccecba5..7743ffe701 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -124,3 +124,13 @@ uint32_t furi_timer_is_running(FuriTimer* instance) { /* Return 0: not running, 1: running */ return (uint32_t)xTimerIsTimerActive(hTimer); } + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg) { + BaseType_t ret = pdFAIL; + if(furi_kernel_is_irq_or_masked()) { + ret = xTimerPendFunctionCallFromISR(callback, context, arg, NULL); + } else { + ret = xTimerPendFunctionCall(callback, context, arg, FuriWaitForever); + } + furi_check(ret == pdPASS); +} \ No newline at end of file diff --git a/furi/core/timer.h b/furi/core/timer.h index e79c1868d9..3f43de5fd9 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -56,6 +56,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance); */ uint32_t furi_timer_is_running(FuriTimer* instance); +typedef void (*FuriTimerPendigCallback)(void* context, uint32_t arg); + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg); + #ifdef __cplusplus } #endif From 7ddde7e6ca333e63f6ec3073cadfa0f9ee6c8f83 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 16:09:06 +0300 Subject: [PATCH 09/14] Fuzzers remove excessive free's thanks to @Willy-JL --- applications/external/flipfrid/flipfrid.c | 3 --- applications/external/ibtn_fuzzer/ibtnfuzzer.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/applications/external/flipfrid/flipfrid.c b/applications/external/flipfrid/flipfrid.c index 4608bab165..1cf7be8652 100644 --- a/applications/external/flipfrid/flipfrid.c +++ b/applications/external/flipfrid/flipfrid.c @@ -118,9 +118,6 @@ void flipfrid_free(FlipFridState* flipfrid) { furi_string_free(flipfrid->main_menu_proto_items[i]); } - free(flipfrid->data); - free(flipfrid->payload); - // The rest free(flipfrid); } diff --git a/applications/external/ibtn_fuzzer/ibtnfuzzer.c b/applications/external/ibtn_fuzzer/ibtnfuzzer.c index d385a22d26..825a555607 100644 --- a/applications/external/ibtn_fuzzer/ibtnfuzzer.c +++ b/applications/external/ibtn_fuzzer/ibtnfuzzer.c @@ -120,9 +120,6 @@ void ibtnfuzzer_free(iBtnFuzzerState* ibtnfuzzer) { furi_string_free(ibtnfuzzer->main_menu_proto_items[i]); } - free(ibtnfuzzer->data); - free(ibtnfuzzer->payload); - // The rest free(ibtnfuzzer); } From 1feb876a32efa8c2de59e4c218312e8a1533c160 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 17:58:58 +0300 Subject: [PATCH 10/14] update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37c6260e04..459a9d6c28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,14 @@ ### New changes +* If you have copied any apps manually into `apps` folder - remove `apps` folder or that specific apps you copied on your microSD before installing this release to avoid issues! +* Plugins: RFID and iButton Fuzzer remove excessive free's (thanks @Willy-JL) +* Plugins: Use COUNT_OF in mouse jiggler * Plugins: Added Numpad keyboard to HID app (by @clipboard1 | PR #452) +* About: Don't show 00 on about screens +* SubGHz: Combine FuriString allocs and other small changes * Infrared: Updated universal remote assets (by @amec0e | PR #454) * Update slideshow: Replace QR code with good old link +* OFW: Various Furi/FuriHal bug fixes and improvements -> **Breaking API change, api was changed from 24.x to 26.x** +* OFW: Loader refactoring, part 1 -> **Breaking API change, api was changed from 23.x to 24.x** **(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** * OFW: Dolphin builder in ufbt; minor ufbt/fbt improvements * OFW: Added API version to device info * OFW: Gui: relax some asserts in view From 49df6a89b597e8dfd065ffe5339c10ffd0c8d579 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Fri, 5 May 2023 23:24:38 +0100 Subject: [PATCH 11/14] Temp fix for mobile app pairing --- firmware/targets/f7/furi_hal/furi_hal_version.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_version.c b/firmware/targets/f7/furi_hal/furi_hal_version.c index 6075604601..43a48d1366 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_version.c +++ b/firmware/targets/f7/furi_hal/furi_hal_version.c @@ -124,7 +124,11 @@ static void furi_hal_version_set_name(const char* name) { } uint32_t company_id = LL_FLASH_GetSTCompanyID(); - uint32_t device_id = LL_FLASH_GetDeviceID(); + // uint32_t device_id = LL_FLASH_GetDeviceID(); + // Somehow some new flippers return 0x27 instead of 0x26 + // Mobile apps expects it to return 0x26 (and clearly STM too) + // Temporarely hardcoded until cause / fix is found + uint32_t device_id = 0x26; furi_hal_version.ble_mac[0] = (uint8_t)(udn & 0x000000FF); furi_hal_version.ble_mac[1] = (uint8_t)((udn & 0x0000FF00) >> 8); furi_hal_version.ble_mac[2] = (uint8_t)((udn & 0x00FF0000) >> 16); From 8fa7d16c5f976c607af7386b9b0ee217ec8c9089 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sat, 6 May 2023 01:43:09 +0100 Subject: [PATCH 12/14] Merge branch 'ul-dev' into xfw-dev --- .gitignore | 1 + .../hid_app/views/hid_mouse_jiggler.c | 6 +- .../views/pocsag_pager_receiver.c | 6 +- .../views/weather_station_receiver.c | 6 +- .../subghz/scenes/subghz_scene_decode_raw.c | 28 +- .../main/subghz/scenes/subghz_scene_delete.c | 10 +- .../subghz/scenes/subghz_scene_delete_raw.c | 7 +- .../subghz/scenes/subghz_scene_read_raw.c | 16 +- .../subghz/scenes/subghz_scene_receiver.c | 24 +- .../scenes/subghz_scene_receiver_info.c | 10 +- .../main/subghz/scenes/subghz_scene_rpc.c | 3 +- .../subghz/scenes/subghz_scene_save_name.c | 8 +- .../subghz/scenes/subghz_scene_show_error.c | 11 +- .../subghz/scenes/subghz_scene_transmitter.c | 13 +- applications/main/subghz/subghz_cli.c | 36 +- applications/main/subghz/subghz_history.c | 3 +- applications/main/subghz/subghz_i.c | 22 +- applications/main/subghz/views/receiver.c | 3 +- applications/main/subghz/views/transmitter.c | 4 +- applications/main/subghz/views/transmitter.h | 4 +- applications/services/cli/cli_commands.c | 2 - .../desktop/scenes/desktop_scene_lock_menu.c | 3 +- .../desktop/scenes/desktop_scene_main.c | 8 +- applications/services/loader/application.fam | 9 + applications/services/loader/loader.c | 677 ++++++------------ applications/services/loader/loader.h | 13 +- applications/services/loader/loader_cli.c | 117 +++ applications/services/loader/loader_i.h | 80 ++- applications/services/loader/loader_menu.c | 256 +++++++ applications/services/loader/loader_menu.h | 30 + applications/services/rpc/rpc.c | 48 +- .../services/storage/storage_external_api.c | 1 + .../services/storage/storages/storage_ext.c | 1 + applications/settings/about/about.c | 4 +- .../power_settings_app/views/battery_info.c | 4 +- .../settings/system/system_settings.c | 1 - applications/system/updater/cli/updater_cli.c | 26 +- .../updater/util/update_task_worker_flasher.c | 6 +- firmware/targets/f18/api_symbols.csv | 12 +- firmware/targets/f7/api_symbols.csv | 14 +- .../targets/f7/furi_hal/furi_hal_cortex.c | 72 +- .../furi_hal_include/furi_hal_cortex.h | 47 ++ furi/core/thread.c | 28 +- furi/core/thread.h | 8 +- furi/core/timer.c | 10 + furi/core/timer.h | 4 + 46 files changed, 994 insertions(+), 708 deletions(-) create mode 100644 applications/services/loader/loader_cli.c create mode 100644 applications/services/loader/loader_menu.c create mode 100644 applications/services/loader/loader_menu.h diff --git a/.gitignore b/.gitignore index d6a2dc470a..48b5ed8b0b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp *.swo *.gdb_history +*.old # LSP diff --git a/applications/external/hid_app/views/hid_mouse_jiggler.c b/applications/external/hid_app/views/hid_mouse_jiggler.c index 120d5bc34c..09c14c6688 100644 --- a/applications/external/hid_app/views/hid_mouse_jiggler.c +++ b/applications/external/hid_app/views/hid_mouse_jiggler.c @@ -6,8 +6,6 @@ #define TAG "HidMouseJiggler" -#define LENGTH(x) (int)(sizeof(x) / sizeof((x)[0])) - struct HidMouseJiggler { View* view; Hid* hid; @@ -44,7 +42,7 @@ static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { elements_multiline_text(canvas, AlignLeft, 26, "Interval (ms):"); canvas_set_font(canvas, FontSecondary); if(model->interval_idx != 0) canvas_draw_icon(canvas, 74, 19, &I_ButtonLeft_4x7); - if(model->interval_idx != LENGTH(intervals) - 1) + if(model->interval_idx != (int)COUNT_OF(intervals) - 1) canvas_draw_icon(canvas, 80, 19, &I_ButtonRight_4x7); FuriString* interval_str = furi_string_alloc_printf("%d", intervals[model->interval_idx]); elements_multiline_text(canvas, 91, 26, furi_string_get_cstr(interval_str)); @@ -116,7 +114,7 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { consumed = true; } if(event->type == InputTypePress && event->key == InputKeyRight && !model->running && - model->interval_idx < LENGTH(intervals) - 1) { + model->interval_idx < (int)COUNT_OF(intervals) - 1) { model->interval_idx++; consumed = true; } diff --git a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c index 532f41984b..64939a9564 100644 --- a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c +++ b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -69,10 +69,10 @@ void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi) { instance->view, PCSGReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/external/weather_station/views/weather_station_receiver.c b/applications/external/weather_station/views/weather_station_receiver.c index 62f1adad02..e994e7830e 100644 --- a/applications/external/weather_station/views/weather_station_receiver.c +++ b/applications/external/weather_station/views/weather_station_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { instance->view, WSReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 5ac4fcccd5..b9f2d236bf 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -24,14 +24,10 @@ static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); @@ -62,11 +58,9 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -90,8 +84,7 @@ static void subghz_scene_add_to_history_callback( } bool subghz_scene_decode_raw_start(SubGhz* subghz) { - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); bool success = false; do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { @@ -148,8 +141,7 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { } // Update progress info - FuriString* progress_str; - progress_str = furi_string_alloc(); + FuriString* progress_str = furi_string_alloc(); subghz_file_encoder_worker_get_text_progress( subghz->decode_raw_file_worker_encoder, progress_str); @@ -164,10 +156,8 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { void subghz_scene_decode_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 94814b1432..4cad14bbf0 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -11,13 +11,9 @@ void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* co void subghz_scene_delete_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index fa4fc6f642..ee7983dfd3 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -15,11 +15,8 @@ void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void void subghz_scene_delete_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); char delete_str[SUBGHZ_MAX_LEN_NAME + 16]; FuriString* file_name; diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index db2cf47631..e3eb5bdd1c 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -12,8 +12,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; //set the path to read the file - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { FURI_LOG_E(TAG, "Rewind error"); @@ -38,11 +37,8 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME subghz_get_frequency_modulation(subghz, frequency_str, NULL); @@ -74,8 +70,7 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); switch(subghz->txrx->rx_key_state) { case SubGhzRxKeyStateBack: @@ -313,8 +308,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index b17a0700b4..fd8d9b70ec 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -39,14 +39,10 @@ const NotificationSequence subghz_sequence_rx_locked = { static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME if(subghz_history_get_last_index(subghz->txrx->history) > 0) { @@ -90,12 +86,12 @@ static void subghz_scene_add_to_history_callback( SubGhzProtocolDecoderBase* decoder_base, void* context) { furi_assert(context); + SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -122,10 +118,8 @@ static void subghz_scene_add_to_history_callback( void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 58e4287850..a108132c0d 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -49,13 +49,9 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { if(subghz_scene_receiver_info_update_parser(subghz)) { - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 82ab184d1d..13379490b2 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -73,8 +73,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateLoaded); furi_string_set(subghz->file_path, arg); result = true; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); path_extract_filename(subghz->file_path, file_name, true); snprintf( diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index d3f5474beb..2bb13f1844 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -51,10 +51,8 @@ void subghz_scene_save_name_on_enter(void* context) { TextInput* text_input = subghz->text_input; bool dev_name_empty = false; - FuriString* file_name; - FuriString* dir_name; - file_name = furi_string_alloc(); - dir_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* dir_name = furi_string_alloc(); if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; @@ -109,7 +107,7 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_scene_save_name_text_input_callback, subghz, subghz->file_name_tmp, - MAX_TEXT_INPUT_LEN, // buffer size + MAX_TEXT_INPUT_LEN, dev_name_empty); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( diff --git a/applications/main/subghz/scenes/subghz_scene_show_error.c b/applications/main/subghz/scenes/subghz_scene_show_error.c index 107189cae7..4544260ef6 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error.c @@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) { bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; + SubGhzCustomEvent scene_state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError); if(event.type == SceneManagerEventTypeBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { return false; } else { scene_manager_search_and_switch_to_previous_scene( @@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneShowErrorOk) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } return true; } else if(event.event == SubGhzCustomEventSceneShowErrorBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { //exit app if(!scene_manager_previous_scene(subghz->scene_manager)) { scene_manager_stop(subghz->scene_manager); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 78b26688f8..77601c08af 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -17,14 +17,11 @@ bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; if(subghz->txrx->decoder_result) { - FuriString* key_str; - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* key_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - key_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - uint8_t show_button = 0; + bool show_button = false; if(subghz_protocol_decoder_base_deserialize( subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { @@ -32,7 +29,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) { - show_button = 1; + show_button = true; } subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index be7143643b..815857cc9a 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -215,8 +215,7 @@ static void subghz_cli_command_rx_callback( SubGhzCliCommandRx* instance = context; instance->packet_count++; - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_protocol_decoder_base_get_string(decoder_base, text); subghz_receiver_reset(receiver); printf("%s", furi_string_get_cstr(text)); @@ -384,14 +383,12 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { } void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { UNUSED(context); - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); furi_string_set(file_name, ANY_PATH("subghz/test.sub")); Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; bool check_file = false; @@ -526,10 +523,8 @@ static void subghz_cli_command_encrypt_keeloq(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); SubGhzKeystore* keystore = subghz_keystore_alloc(); @@ -569,10 +564,8 @@ static void subghz_cli_command_encrypt_raw(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); do { if(!args_read_string_and_trim(args, source)) { @@ -646,14 +639,10 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args, void* context) { size_t message_max_len = 64; uint8_t message[64] = {0}; - FuriString* input; - input = furi_string_alloc(); - FuriString* name; - name = furi_string_alloc(); - FuriString* output; - output = furi_string_alloc(); - FuriString* sysmsg; - sysmsg = furi_string_alloc(); + FuriString* input = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + FuriString* output = furi_string_alloc(); + FuriString* sysmsg = furi_string_alloc(); bool exit = false; SubGhzChatEvent chat_event; @@ -786,8 +775,7 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args, void* context) { } static void subghz_cli_command(Cli* cli, FuriString* args, void* context) { - FuriString* cmd; - cmd = furi_string_alloc(); + FuriString* cmd = furi_string_alloc(); do { if(!args_read_string_and_trim(args, cmd)) { diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index 3c018ec8bb..396e284210 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -197,8 +197,7 @@ bool subghz_history_add_to_history( instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base); instance->last_update_timestamp = furi_get_tick(); - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data); item->preset = malloc(sizeof(SubGhzRadioPreset)); item->type = decoder_base->protocol->type; diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index cbef8fe972..d21bdac418 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -145,8 +145,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { furi_assert(subghz); bool ret = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t repeat = 200; do { if(!flipper_format_rewind(flipper_format)) { @@ -254,8 +253,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; do { @@ -393,13 +391,9 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* temp_str; - FuriString* file_name; - FuriString* file_path; - - temp_str = furi_string_alloc(); - file_name = furi_string_alloc(); - file_path = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); bool res = false; @@ -446,8 +440,7 @@ bool subghz_save_protocol_to_file( Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; - FuriString* file_dir; - file_dir = furi_string_alloc(); + FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { @@ -478,8 +471,7 @@ bool subghz_save_protocol_to_file( bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); - FuriString* file_path; - file_path = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 0d38503dab..bcc7181f06 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -241,8 +241,7 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { } bool scrollbar = model->history_item > 4; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* str_buff = furi_string_alloc(); SubGhzReceiverMenuItem* item_menu; diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 5667cd59fc..48184cf390 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -21,7 +21,7 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button) { + bool show_button) { furi_assert(subghz_transmitter); with_view_model( subghz_transmitter->view, @@ -104,7 +104,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_reset(model->preset_str); furi_string_reset(model->key_str); furi_string_reset(model->temp_button_id); - model->show_button = 0; + model->show_button = false; model->draw_temp_button = false; }, false); diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 1ae51afbde..e121c87463 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -7,7 +7,7 @@ typedef struct { FuriString* frequency_str; FuriString* preset_str; FuriString* key_str; - uint8_t show_button; + bool show_button; FuriString* temp_button_id; bool draw_temp_button; } SubGhzViewTransmitterModel; @@ -36,4 +36,4 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button); + bool show_button); diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index a652d0f0c5..fc71aa31f1 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -230,11 +230,9 @@ void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) { UNUSED(context); if(!furi_string_cmp(args, "0")) { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug disabled."); } else if(!furi_string_cmp(args, "1")) { furi_hal_rtc_set_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug enabled."); } else { cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args)); diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index e68d280765..346283d1b7 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -80,7 +80,8 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { switch(event.event) { case DesktopLockMenuEventSettings: desktop_scene_lock_menu_save_settings(desktop); - loader_show_settings(); + loader_show_settings(furi_record_open(RECORD_LOADER)); + furi_record_close(RECORD_LOADER); consumed = true; break; case DesktopLockMenuEventLock: diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 8be63bfe36..1bb194302a 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -90,10 +90,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case DesktopMainEventOpenMenu: - loader_show_menu(); + case DesktopMainEventOpenMenu: { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_show_menu(loader); + furi_record_close(RECORD_LOADER); consumed = true; - break; + } break; case DesktopMainEventOpenLockMenu: scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); diff --git a/applications/services/loader/application.fam b/applications/services/loader/application.fam index 49f3c41488..f4d006e076 100644 --- a/applications/services/loader/application.fam +++ b/applications/services/loader/application.fam @@ -5,6 +5,7 @@ App( entry_point="loader_srv", cdefines=["SRV_LOADER"], requires=["gui"], + provides=["loader_start"], stack_size=2 * 1024, order=90, sdk_headers=[ @@ -12,3 +13,11 @@ App( "firmware_api/firmware_api.h", ], ) + +App( + appid="loader_start", + apptype=FlipperAppType.STARTUP, + entry_point="loader_on_system_start", + requires=["loader"], + order=90, +) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 808c8e18e5..b9f47dcddd 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,76 +1,139 @@ -#include "applications.h" -#include -#include -#include "loader/loader.h" +#include "loader.h" #include "loader_i.h" -#include "applications/main/fap_loader/fap_loader_app.h" -#include -#include -#include -#include -#include -#include +#include "loader_menu.h" +#include +#include + +#define TAG "Loader" +#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF +// api + +LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { + LoaderMessage message; + LoaderMessageLoaderStatusResult result; + + message.type = LoaderMessageTypeStartByName; + message.start.name = name; + message.start.args = args; + message.api_lock = api_lock_alloc_locked(); + message.status_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -#define TAG "LoaderSrv" +bool loader_lock(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeLock; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -#define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) -#define LOADER_THREAD_FLAG_SHOW_SETTINGS (1 << 1) -#define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU | LOADER_THREAD_FLAG_SHOW_SETTINGS) +void loader_unlock(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeUnlock; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} -static Loader* loader_instance = NULL; +bool loader_is_locked(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeIsLocked; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} -static FlipperApplication const* loader_find_application_by_name_in_list( - const char* name, - const FlipperApplication* list, - const uint32_t n_apps) { - for(size_t i = 0; i < n_apps; i++) { - if(strcmp(name, list[i].name) == 0) { - return &list[i]; - } - } - return NULL; +void loader_show_menu(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowMenu; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); } -static bool - loader_start_application(const FlipperApplication* application, const char* arguments) { - if(application->app == NULL) { - arguments = application->appid; - application = loader_find_application_by_name_in_list( - FAP_LOADER_APP_NAME, FLIPPER_APPS, FLIPPER_APPS_COUNT); - } - loader_instance->application = application; +void loader_show_settings(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowSettings; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +FuriPubSub* loader_get_pubsub(Loader* loader) { + furi_assert(loader); + // it's safe to return pubsub without locking + // because it's never freed and loader is never exited + // also the loader instance cannot be obtained until the pubsub is created + return loader->pubsub; +} + +// callbacks - furi_assert(loader_instance->application_arguments == NULL); - if(arguments && strlen(arguments) > 0) { - loader_instance->application_arguments = strdup(arguments); - FURI_LOG_I(TAG, "Starting: %s, args: %s", loader_instance->application->name, arguments); +static void loader_menu_closed_callback(void* context) { + Loader* loader = context; + LoaderMessage message; + message.type = LoaderMessageTypeMenuClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +static void loader_menu_click_callback(const char* name, bool external, void* context) { + Loader* loader = context; + if(external) { + loader_start(loader, FAP_LOADER_APP_NAME, name); } else { - FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); + loader_start(loader, name, NULL); } +} - FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); - if(mode > FuriHalRtcHeapTrackModeNone) { - furi_thread_enable_heap_trace(loader_instance->application_thread); - } else { - furi_thread_disable_heap_trace(loader_instance->application_thread); +static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { + furi_assert(context); + + Loader* loader = context; + LoaderEvent event; + + if(thread_state == FuriThreadStateRunning) { + event.type = LoaderEventTypeApplicationStarted; + furi_pubsub_publish(loader->pubsub, &event); + } else if(thread_state == FuriThreadStateStopped) { + LoaderMessage message; + message.type = LoaderMessageTypeAppClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); } +} - furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name); - furi_thread_set_appid( - loader_instance->application_thread, loader_instance->application->appid); - furi_thread_set_stack_size( - loader_instance->application_thread, loader_instance->application->stack_size); - furi_thread_set_context( - loader_instance->application_thread, loader_instance->application_arguments); - furi_thread_set_callback( - loader_instance->application_thread, loader_instance->application->app); +// implementation - furi_thread_start(loader_instance->application_thread); +static Loader* loader_alloc() { + Loader* loader = malloc(sizeof(Loader)); + loader->pubsub = furi_pubsub_alloc(); + loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); + loader->loader_menu = NULL; + loader->app.args = NULL; + loader->app.name = NULL; + loader->app.thread = NULL; + loader->app.insomniac = false; + return loader; +} - return true; +static FlipperApplication const* loader_find_application_by_name_in_list( + const char* name, + const FlipperApplication* list, + const uint32_t n_apps) { + for(size_t i = 0; i < n_apps; i++) { + if(strcmp(name, list[i].name) == 0) { + return &list[i]; + } + } + return NULL; } -const FlipperApplication* loader_find_application_by_name(const char* name) { +static const FlipperApplication* loader_find_application_by_name(const char* name) { const FlipperApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { @@ -85,449 +148,177 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { return application; } -static void loader_menu_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const FlipperApplication* application = _ctx; - - furi_assert(application->app); - furi_assert(application->name); - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; - } - - loader_start_application(application, NULL); -} - -static void loader_external_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const char* path = _ctx; - const FlipperApplication* app = loader_find_application_by_name_in_list( - FAP_LOADER_APP_NAME, FLIPPER_APPS, FLIPPER_APPS_COUNT); +static void + loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); - furi_assert(path); - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; + if(app->app == NULL) { + args = app->appid; + app = loader_find_application_by_name_in_list( + FAP_LOADER_APP_NAME, FLIPPER_APPS, FLIPPER_APPS_COUNT); } - loader_start_application(app, path); -} - -static void loader_submenu_callback(void* context, uint32_t index) { - UNUSED(index); - uint32_t view_id = (uint32_t)context; - view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); -} - -static void loader_cli_print_usage() { - printf("Usage:\r\n"); - printf("loader \r\n"); - printf("Cmd list:\r\n"); - printf("\tlist\t - List available applications\r\n"); - printf("\topen \t - Open application by name\r\n"); - printf("\tinfo\t - Show loader state\r\n"); -} - -static void loader_cli_open(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - if(loader_is_locked(instance)) { - if(instance->application) { - furi_assert(instance->application->name); - printf("Can't start, %s application is running", instance->application->name); - } else { - printf("Can't start, furi application is running"); - } - return; + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); } - FuriString* application_name; - application_name = furi_string_alloc(); + // store name + furi_assert(loader->app.name == NULL); + loader->app.name = strdup(app->name); - do { - if(!args_read_probably_quoted_string_and_trim(args, application_name)) { - printf("No application provided\r\n"); - break; - } - - const FlipperApplication* application = - loader_find_application_by_name(furi_string_get_cstr(application_name)); - if(!application) { - printf("%s doesn't exists\r\n", furi_string_get_cstr(application_name)); - break; - } - - furi_string_trim(args); - if(!loader_start_application(application, furi_string_get_cstr(args))) { - printf("Can't start, furi application is running"); - return; - } else { - // We must to increment lock counter to keep balance - // TODO: rewrite whole thing, it's complex as hell - FURI_CRITICAL_ENTER(); - instance->lock_count++; - FURI_CRITICAL_EXIT(); - } - } while(false); + // setup app thread + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); - furi_string_free(application_name); -} - -static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - UNUSED(instance); - printf("Applications:\r\n"); - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - printf("\t%s\r\n", FLIPPER_APPS[i].name); + // setup heap trace + FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); + if(mode > FuriHalRtcHeapTrackModeNone) { + furi_thread_enable_heap_trace(loader->app.thread); + } else { + furi_thread_disable_heap_trace(loader->app.thread); } -} -static void loader_cli_info(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - if(!loader_is_locked(instance)) { - printf("No application is running\r\n"); + // setup insomnia + if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + furi_hal_power_insomnia_enter(); + loader->app.insomniac = true; } else { - printf("Running application: "); - if(instance->application) { - furi_assert(instance->application->name); - printf("%s\r\n", instance->application->name); - } else { - printf("unknown\r\n"); - } + loader->app.insomniac = false; } -} - -static void loader_cli(Cli* cli, FuriString* args, void* _ctx) { - furi_assert(_ctx); - Loader* instance = _ctx; - FuriString* cmd; - cmd = furi_string_alloc(); + // setup app thread callbacks + furi_thread_set_state_context(loader->app.thread, loader); + furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); - do { - if(!args_read_string_and_trim(args, cmd)) { - loader_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(cmd, "list") == 0) { - loader_cli_list(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "open") == 0) { - loader_cli_open(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "info") == 0) { - loader_cli_info(cli, args, instance); - break; - } - - loader_cli_print_usage(); - } while(false); - - furi_string_free(cmd); + // start app thread + furi_thread_start(loader->app.thread); } -LoaderStatus loader_start(Loader* instance, const char* name, const char* args) { - UNUSED(instance); - furi_assert(name); - - const FlipperApplication* application = loader_find_application_by_name(name); - - if(!application) { - FURI_LOG_E(TAG, "Can't find application with name %s", name); - return LoaderStatusErrorUnknownApp; - } - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return LoaderStatusErrorAppStarted; - } +// process messages - if(!loader_start_application(application, args)) { - return LoaderStatusErrorInternal; +static void loader_do_menu_show(Loader* loader, bool settings) { + if(!loader->loader_menu) { + loader->loader_menu = loader_menu_alloc(); + loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); + loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); + loader_menu_start(loader->loader_menu, settings); } - - return LoaderStatusOk; } -bool loader_lock(Loader* instance) { - FURI_CRITICAL_ENTER(); - bool result = false; - if(instance->lock_count == 0) { - instance->lock_count++; - result = true; +static void loader_do_menu_closed(Loader* loader) { + if(loader->loader_menu) { + loader_menu_stop(loader->loader_menu); + loader_menu_free(loader->loader_menu); + loader->loader_menu = NULL; } - FURI_CRITICAL_EXIT(); - return result; } -void loader_unlock(Loader* instance) { - FURI_CRITICAL_ENTER(); - if(instance->lock_count > 0) instance->lock_count--; - FURI_CRITICAL_EXIT(); +static bool loader_do_is_locked(Loader* loader) { + return loader->app.thread != NULL; } -bool loader_is_locked(const Loader* instance) { - return instance->lock_count > 0; -} - -static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - - Loader* instance = context; - LoaderEvent event; - - if(thread_state == FuriThreadStateRunning) { - event.type = LoaderEventTypeApplicationStarted; - furi_pubsub_publish(loader_instance->pubsub, &event); - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_enter(); - } - } else if(thread_state == FuriThreadStateStopped) { - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); - - if(loader_instance->application_arguments) { - free(loader_instance->application_arguments); - loader_instance->application_arguments = NULL; - } - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_exit(); - } - loader_unlock(instance); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader_instance->pubsub, &event); +static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { + if(loader_do_is_locked(loader)) { + return LoaderStatusErrorAppStarted; } -} - -static uint32_t loader_hide_menu(void* context) { - UNUSED(context); - return VIEW_NONE; -} -static uint32_t loader_back_to_primary_menu(void* context) { - furi_assert(context); - Submenu* submenu = context; - submenu_set_selected_item(submenu, 0); - return LoaderMenuViewPrimary; -} + const FlipperApplication* app = loader_find_application_by_name(name); -static Loader* loader_alloc() { - Loader* instance = malloc(sizeof(Loader)); - - instance->application_thread = furi_thread_alloc(); - - furi_thread_set_state_context(instance->application_thread, instance); - furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback); - - instance->pubsub = furi_pubsub_alloc(); - -#ifdef SRV_CLI - instance->cli = furi_record_open(RECORD_CLI); - cli_add_command( - instance->cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, instance); -#else - UNUSED(loader_cli); -#endif - - instance->loader_thread = furi_thread_get_current_id(); - - // Gui - instance->gui = furi_record_open(RECORD_GUI); - instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - // Primary menu - instance->primary_menu = menu_alloc(); - view_set_previous_callback(menu_get_view(instance->primary_menu), loader_hide_menu); - view_dispatcher_add_view( - instance->view_dispatcher, LoaderMenuViewPrimary, menu_get_view(instance->primary_menu)); - // Settings menu - instance->settings_menu = submenu_alloc(); - view_set_context(submenu_get_view(instance->settings_menu), instance->settings_menu); - view_set_previous_callback( - submenu_get_view(instance->settings_menu), loader_back_to_primary_menu); - view_dispatcher_add_view( - instance->view_dispatcher, - LoaderMenuViewSettings, - submenu_get_view(instance->settings_menu)); - - view_dispatcher_enable_queue(instance->view_dispatcher); - - return instance; -} - -static void loader_free(Loader* instance) { - furi_assert(instance); - - if(instance->cli) { - furi_record_close(RECORD_CLI); + if(!app) { + return LoaderStatusErrorUnknownApp; } - furi_pubsub_free(instance->pubsub); - - furi_thread_free(instance->application_thread); - - menu_free(loader_instance->primary_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary); - submenu_free(loader_instance->settings_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_free(loader_instance->view_dispatcher); - - furi_record_close(RECORD_GUI); - - free(instance); - instance = NULL; + loader_start_internal_app(loader, app, args); + return LoaderStatusOk; } -bool loader_load_fap_meta(Storage* storage, FuriString* path, FuriString* name, const Icon** icon) { - *icon = NULL; - uint8_t* icon_buf = malloc(CUSTOM_ICON_MAX_SIZE); - if(!fap_loader_load_name_and_icon(path, storage, &icon_buf, name)) { - free(icon_buf); - icon_buf = NULL; +static bool loader_do_lock(Loader* loader) { + if(loader->app.thread) { return false; } - *icon = malloc(sizeof(Icon)); - FURI_CONST_ASSIGN((*icon)->frame_count, 1); - FURI_CONST_ASSIGN((*icon)->frame_rate, 0); - FURI_CONST_ASSIGN((*icon)->width, 10); - FURI_CONST_ASSIGN((*icon)->height, 10); - FURI_CONST_ASSIGN_PTR((*icon)->frames, malloc(sizeof(const uint8_t*))); - FURI_CONST_ASSIGN_PTR((*icon)->frames[0], icon_buf); + + loader->app.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE; return true; } -static void loader_build_menu() { - FURI_LOG_I(TAG, "Building main menu"); - size_t i; - for(i = 0; i < FLIPPER_APPS_COUNT; i++) { - menu_add_item( - loader_instance->primary_menu, - FLIPPER_APPS[i].name, - FLIPPER_APPS[i].icon, - i, - loader_menu_callback, - (void*)&FLIPPER_APPS[i]); - } - menu_add_item( - loader_instance->primary_menu, - "Settings", - &A_Settings_14, - i++, - loader_submenu_callback, - (void*)LoaderMenuViewSettings); - - Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* path = furi_string_alloc(); - FuriString* name = furi_string_alloc(); - Stream* stream = file_stream_alloc(storage); - if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - while(stream_read_line(stream, path)) { - furi_string_replace_all(path, "\r", ""); - furi_string_replace_all(path, "\n", ""); - const Icon* icon; - if(!loader_load_fap_meta(storage, path, name, &icon)) continue; - menu_add_item( - loader_instance->primary_menu, - strdup(furi_string_get_cstr(name)), - icon, - i++, - loader_external_callback, - (void*)strdup(furi_string_get_cstr(path))); - } - } - file_stream_close(stream); - stream_free(stream); - furi_string_free(name); - furi_string_free(path); - furi_record_close(RECORD_STORAGE); +static void loader_do_unlock(Loader* loader) { + furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + loader->app.thread = NULL; } -static void loader_build_submenu() { - FURI_LOG_I(TAG, "Building settings menu"); - for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { - submenu_add_item( - loader_instance->settings_menu, - FLIPPER_SETTINGS_APPS[i].name, - i, - loader_menu_callback, - (void*)&FLIPPER_SETTINGS_APPS[i]); +static void loader_do_app_closed(Loader* loader) { + furi_assert(loader->app.thread); + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + if(loader->app.args) { + free(loader->app.args); + loader->app.args = NULL; } -} -void loader_show_menu() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); -} + if(loader->app.insomniac) { + furi_hal_power_insomnia_exit(); + } -void loader_show_settings() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_SETTINGS); -} + free(loader->app.name); + loader->app.name = NULL; -void loader_update_menu() { - menu_reset(loader_instance->primary_menu); - loader_build_menu(); + furi_thread_join(loader->app.thread); + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; } +// app + int32_t loader_srv(void* p) { UNUSED(p); + Loader* loader = loader_alloc(); + furi_record_create(RECORD_LOADER, loader); + FURI_LOG_I(TAG, "Executing system start hooks"); for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { FLIPPER_ON_SYSTEM_START[i](); } - FURI_LOG_I(TAG, "Starting"); - loader_instance = loader_alloc(); - - loader_build_menu(); - loader_build_submenu(); - - FURI_LOG_I(TAG, "Started"); - - furi_record_create(RECORD_LOADER, loader_instance); - if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); } - while(1) { - uint32_t flags = - furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); - if(flags & LOADER_THREAD_FLAG_SHOW_MENU) { - menu_set_selected_item(loader_instance->primary_menu, 0); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_run(loader_instance->view_dispatcher); - } else if(flags & LOADER_THREAD_FLAG_SHOW_SETTINGS) { - submenu_set_selected_item(loader_instance->settings_menu, 0); - view_set_previous_callback( - submenu_get_view(loader_instance->settings_menu), loader_hide_menu); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_run(loader_instance->view_dispatcher); - view_set_previous_callback( - submenu_get_view(loader_instance->settings_menu), loader_back_to_primary_menu); + LoaderMessage message; + while(true) { + if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { + switch(message.type) { + case LoaderMessageTypeStartByName: + message.status_value->value = + loader_do_start_by_name(loader, message.start.name, message.start.args); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeShowMenu: + loader_do_menu_show(loader, false); + break; + case LoaderMessageTypeShowSettings: + loader_do_menu_show(loader, true); + break; + case LoaderMessageTypeMenuClosed: + loader_do_menu_closed(loader); + break; + case LoaderMessageTypeIsLocked: + message.bool_value->value = loader_do_is_locked(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeAppClosed: + loader_do_app_closed(loader); + break; + case LoaderMessageTypeLock: + message.bool_value->value = loader_do_lock(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeUnlock: + loader_do_unlock(loader); + } } } - furi_record_destroy(RECORD_LOADER); - loader_free(loader_instance); - return 0; } - -FuriPubSub* loader_get_pubsub(Loader* instance) { - return instance->pubsub; -} diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index 58516b3394..e8f1fd64e8 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,7 +1,5 @@ #pragma once - -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -45,16 +43,13 @@ bool loader_lock(Loader* instance); void loader_unlock(Loader* instance); /** Get loader lock status */ -bool loader_is_locked(const Loader* instance); +bool loader_is_locked(Loader* instance); /** Show primary loader */ -void loader_show_menu(); +void loader_show_menu(Loader* instance); /** Show settings menu */ -void loader_show_settings(); - -/** Show primary loader */ -void loader_update_menu(); +void loader_show_settings(Loader* loader); /** Show primary loader */ FuriPubSub* loader_get_pubsub(Loader* instance); diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c new file mode 100644 index 0000000000..2d46022157 --- /dev/null +++ b/applications/services/loader/loader_cli.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include "loader.h" + +static void loader_cli_print_usage() { + printf("Usage:\r\n"); + printf("loader \r\n"); + printf("Cmd list:\r\n"); + printf("\tlist\t - List available applications\r\n"); + printf("\topen \t - Open application by name\r\n"); + printf("\tinfo\t - Show loader state\r\n"); +} + +static void loader_cli_list() { + printf("Applications:\r\n"); + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_APPS[i].name); + } + printf("Settings:\r\n"); + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name); + } +} + +static void loader_cli_info(Loader* loader) { + if(!loader_is_locked(loader)) { + printf("No application is running\r\n"); + } else { + // TODO: print application name ??? + printf("Application is running\r\n"); + } +} + +static void loader_cli_open(FuriString* args, Loader* loader) { + FuriString* app_name = furi_string_alloc(); + + do { + if(!args_read_probably_quoted_string_and_trim(args, app_name)) { + printf("No application provided\r\n"); + break; + } + furi_string_trim(args); + + const char* args_str = furi_string_get_cstr(args); + if(strlen(args_str) == 0) { + args_str = NULL; + } + + const char* app_name_str = furi_string_get_cstr(app_name); + + LoaderStatus status = loader_start(loader, app_name_str, args_str); + + switch(status) { + case LoaderStatusOk: + break; + case LoaderStatusErrorAppStarted: + printf("Can't start, application is running"); + break; + case LoaderStatusErrorUnknownApp: + printf("%s doesn't exists\r\n", app_name_str); + break; + case LoaderStatusErrorInternal: + printf("Internal error\r\n"); + break; + } + } while(false); + + furi_string_free(app_name); +} + +static void loader_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + UNUSED(context); + Loader* loader = furi_record_open(RECORD_LOADER); + + FuriString* cmd; + cmd = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, cmd)) { + loader_cli_print_usage(); + break; + } + + if(furi_string_cmp_str(cmd, "list") == 0) { + loader_cli_list(); + break; + } + + if(furi_string_cmp_str(cmd, "open") == 0) { + loader_cli_open(args, loader); + break; + } + + if(furi_string_cmp_str(cmd, "info") == 0) { + loader_cli_info(loader); + break; + } + + loader_cli_print_usage(); + } while(false); + + furi_string_free(cmd); + furi_record_close(RECORD_LOADER); +} + +void loader_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(loader_cli); +#endif +} \ No newline at end of file diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 00028cd6b1..4a1477a7b2 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,39 +1,57 @@ -#include "loader.h" - +#pragma once #include -#include -#include -#include -#include - -#include - -#include -#include +#include +#include "loader.h" +#include "loader_menu.h" -#include -#include +typedef struct { + char* args; + char* name; + FuriThread* thread; + bool insomniac; +} LoaderAppData; struct Loader { - FuriThreadId loader_thread; - - const FlipperApplication* application; - FuriThread* application_thread; - char* application_arguments; - - Cli* cli; - Gui* gui; - - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - volatile uint8_t lock_count; - FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderMenu* loader_menu; + LoaderAppData app; }; typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; + LoaderMessageTypeStartByName, + LoaderMessageTypeAppClosed, + LoaderMessageTypeShowMenu, + LoaderMessageTypeMenuClosed, + LoaderMessageTypeLock, + LoaderMessageTypeUnlock, + LoaderMessageTypeIsLocked, + LoaderMessageTypeShowSettings, +} LoaderMessageType; + +typedef struct { + const char* name; + const char* args; +} LoaderMessageStartByName; + +typedef struct { + LoaderStatus value; +} LoaderMessageLoaderStatusResult; + +typedef struct { + bool value; +} LoaderMessageBoolResult; + +typedef struct { + FuriApiLock api_lock; + LoaderMessageType type; + + union { + LoaderMessageStartByName start; + }; + + union { + LoaderMessageLoaderStatusResult* status_value; + LoaderMessageBoolResult* bool_value; + }; +} LoaderMessage; diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c new file mode 100644 index 0000000000..1391394e51 --- /dev/null +++ b/applications/services/loader/loader_menu.c @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "applications/main/fap_loader/fap_loader_app.h" +#include + +#include "loader_menu.h" + +#define TAG "LoaderMenu" + +struct LoaderMenu { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; + bool settings; + + void (*closed_callback)(void*); + void* closed_callback_context; + + void (*click_callback)(const char*, bool, void*); + void* click_callback_context; + + FuriThread* thread; +}; + +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +static int32_t loader_menu_thread(void* p); + +LoaderMenu* loader_menu_alloc() { + LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); + loader_menu->gui = furi_record_open(RECORD_GUI); + loader_menu->view_dispatcher = view_dispatcher_alloc(); + loader_menu->primary_menu = menu_alloc(); + loader_menu->settings_menu = submenu_alloc(); + loader_menu->thread = NULL; + return loader_menu; +} + +void loader_menu_free(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + // check if thread is running + furi_assert(!loader_menu->thread); + + submenu_free(loader_menu->settings_menu); + menu_free(loader_menu->primary_menu); + view_dispatcher_free(loader_menu->view_dispatcher); + furi_record_close(RECORD_GUI); + free(loader_menu); +} + +void loader_menu_start(LoaderMenu* loader_menu, bool settings) { + furi_assert(loader_menu); + furi_assert(!loader_menu->thread); + loader_menu->settings = settings; + loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); + furi_thread_start(loader_menu->thread); +} + +void loader_menu_stop(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(loader_menu->thread); + view_dispatcher_stop(loader_menu->view_dispatcher); + furi_thread_join(loader_menu->thread); + furi_thread_free(loader_menu->thread); + loader_menu->thread = NULL; +} + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context) { + loader_menu->closed_callback = callback; + loader_menu->closed_callback_context = context; +} + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, bool, void*), + void* context) { + loader_menu->click_callback = callback; + loader_menu->click_callback_context = context; +} + +static void loader_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, false, loader_menu->click_callback_context); + } +} + +static void loader_menu_external_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* path = (const char*)index; + if(loader_menu->click_callback) { + loader_menu->click_callback(path, true, loader_menu->click_callback_context); + } +} + +static void loader_menu_settings_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_SETTINGS_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, false, loader_menu->click_callback_context); + } +} + +static void loader_menu_switch_to_settings(void* context, uint32_t index) { + UNUSED(index); + LoaderMenu* loader_menu = context; + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); +} + +static uint32_t loader_menu_switch_to_primary(void* context) { + UNUSED(context); + return LoaderMenuViewPrimary; +} + +static uint32_t loader_menu_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +bool loader_menu_load_fap_meta( + Storage* storage, + FuriString* path, + FuriString* name, + const Icon** icon) { + *icon = NULL; + uint8_t* icon_buf = malloc(CUSTOM_ICON_MAX_SIZE); + if(!fap_loader_load_name_and_icon(path, storage, &icon_buf, name)) { + free(icon_buf); + icon_buf = NULL; + return false; + } + *icon = malloc(sizeof(Icon)); + FURI_CONST_ASSIGN((*icon)->frame_count, 1); + FURI_CONST_ASSIGN((*icon)->frame_rate, 0); + FURI_CONST_ASSIGN((*icon)->width, 10); + FURI_CONST_ASSIGN((*icon)->height, 10); + FURI_CONST_ASSIGN_PTR((*icon)->frames, malloc(sizeof(const uint8_t*))); + FURI_CONST_ASSIGN_PTR((*icon)->frames[0], icon_buf); + return true; +} + +static void loader_menu_build_menu(LoaderMenu* loader_menu) { + size_t i; + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_menu->primary_menu, + FLIPPER_APPS[i].name, + FLIPPER_APPS[i].icon, + i, + loader_menu_callback, + (void*)loader_menu); + } + menu_add_item( + loader_menu->primary_menu, + "Settings", + &A_Settings_14, + i++, + loader_menu_switch_to_settings, + loader_menu); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* path = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + Stream* stream = file_stream_alloc(storage); + if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + while(stream_read_line(stream, path)) { + furi_string_replace_all(path, "\r", ""); + furi_string_replace_all(path, "\n", ""); + const Icon* icon; + if(!loader_menu_load_fap_meta(storage, path, name, &icon)) continue; + menu_add_item( + loader_menu->primary_menu, + strdup(furi_string_get_cstr(name)), + icon, + (uint32_t)strdup(furi_string_get_cstr(path)), + loader_menu_external_callback, + (void*)loader_menu); + } + } + file_stream_close(stream); + stream_free(stream); + furi_string_free(name); + furi_string_free(path); + furi_record_close(RECORD_STORAGE); +}; + +static void loader_menu_build_submenu(LoaderMenu* loader_menu) { + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + submenu_add_item( + loader_menu->settings_menu, + FLIPPER_SETTINGS_APPS[i].name, + i, + loader_menu_settings_menu_callback, + loader_menu); + } +} + +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + if(!loader_menu->settings) loader_menu_build_menu(loader_menu); + loader_menu_build_submenu(loader_menu); + + view_dispatcher_attach_to_gui( + loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + + // Primary menu + if(!loader_menu->settings) { + View* primary_view = menu_get_view(loader_menu->primary_menu); + view_set_context(primary_view, loader_menu->primary_menu); + view_set_previous_callback(primary_view, loader_menu_exit); + view_dispatcher_add_view( + loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + } + + // Settings menu + View* settings_view = submenu_get_view(loader_menu->settings_menu); + view_set_context(settings_view, loader_menu->settings_menu); + view_set_previous_callback( + settings_view, loader_menu->settings ? loader_menu_exit : loader_menu_switch_to_primary); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + + view_dispatcher_enable_queue(loader_menu->view_dispatcher); + view_dispatcher_switch_to_view( + loader_menu->view_dispatcher, + loader_menu->settings ? LoaderMenuViewSettings : LoaderMenuViewPrimary); + + // run view dispatcher + view_dispatcher_run(loader_menu->view_dispatcher); + + if(!loader_menu->settings) + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + + if(loader_menu->closed_callback) { + loader_menu->closed_callback(loader_menu->closed_callback_context); + } + + return 0; +} diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h new file mode 100644 index 0000000000..db39834da5 --- /dev/null +++ b/applications/services/loader/loader_menu.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderMenu LoaderMenu; + +LoaderMenu* loader_menu_alloc(); + +void loader_menu_free(LoaderMenu* loader_menu); + +void loader_menu_start(LoaderMenu* loader_menu, bool settings); + +void loader_menu_stop(LoaderMenu* loader_menu); + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context); + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, bool, void*), + void* context); + +#ifdef __cplusplus +} +#endif diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 62428d79d9..879754fd5b 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -326,31 +326,35 @@ static int32_t rpc_session_worker(void* context) { return 0; } -static void rpc_session_free_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - +static void rpc_session_thread_pending_callback(void* context, uint32_t arg) { + UNUSED(arg); RpcSession* session = (RpcSession*)context; - if(thread_state == FuriThreadStateStopped) { - for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { - if(rpc_systems[i].free) { - rpc_systems[i].free(session->system_contexts[i]); - } - } - free(session->system_contexts); - free(session->decoded_message); - RpcHandlerDict_clear(session->handlers); - furi_stream_buffer_free(session->stream); - - furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); - if(session->terminated_callback) { - session->terminated_callback(session->context); + for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { + if(rpc_systems[i].free) { + (rpc_systems[i].free)(session->system_contexts[i]); } - furi_mutex_release(session->callbacks_mutex); + } + free(session->system_contexts); + free(session->decoded_message); + RpcHandlerDict_clear(session->handlers); + furi_stream_buffer_free(session->stream); - furi_mutex_free(session->callbacks_mutex); - furi_thread_free(session->thread); - free(session); + furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); + if(session->terminated_callback) { + session->terminated_callback(session->context); + } + furi_mutex_release(session->callbacks_mutex); + + furi_mutex_free(session->callbacks_mutex); + furi_thread_join(session->thread); + furi_thread_free(session->thread); + free(session); +} + +static void rpc_session_thread_state_callback(FuriThreadState thread_state, void* context) { + if(thread_state == FuriThreadStateStopped) { + furi_timer_pending_callback(rpc_session_thread_pending_callback, context, 0); } } @@ -385,7 +389,7 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); furi_thread_set_state_context(session->thread, session); - furi_thread_set_state_callback(session->thread, rpc_session_free_callback); + furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback); furi_thread_start(session->thread); diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index ffc3da4bc4..bf474bc9d0 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -803,6 +803,7 @@ void storage_file_free(File* file) { } FuriPubSub* storage_get_pubsub(Storage* storage) { + furi_assert(storage); return storage->pubsub; } diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index d802d6e9f6..15a355dc25 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -337,6 +337,7 @@ static bool storage_ext_file_close(void* ctx, File* file) { file->internal_error_id = f_close(file_data); file->error_id = storage_ext_parse_error(file->internal_error_id); free(file_data); + storage_set_storage_file_data(file, NULL, storage); return (file->error_id == FSE_OK); } diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 2f61ceb2c7..fd6be16858 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -212,7 +212,9 @@ static void draw_battery(Canvas* canvas, PowerInfo* info, int x, int y) { (uint32_t)(info->voltage_vbus), (uint32_t)(info->voltage_vbus * 10) % 10, current); - } else if(current < 0) { + } else if(current < -5) { + // Often gauge reports anything in the range 1~5ma as 5ma + // That brings confusion, so we'll treat it as Napping snprintf(header, sizeof(header), "%s", "Consumption is"); snprintf( value, diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index 828c518d67..9ffb0d22b8 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -53,7 +53,9 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { (uint32_t)(data->vbus_voltage), (uint32_t)(data->vbus_voltage * 10) % 10, current); - } else if(current < 0) { + } else if(current < -5) { + // Often gauge reports anything in the range 1~5ma as 5ma + // That brings confusion, so we'll treat it as Napping snprintf( emote, sizeof(emote), diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 655541be55..68a8950041 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -43,7 +43,6 @@ static void debug_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); } - loader_update_menu(); } const char* const heap_trace_mode_text[] = { diff --git a/applications/system/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c index 2bf6dab26e..659c431f70 100644 --- a/applications/system/updater/cli/updater_cli.c +++ b/applications/system/updater/cli/updater_cli.c @@ -85,22 +85,10 @@ static void updater_cli_ep(Cli* cli, FuriString* args, void* context) { updater_cli_help(args); } -static int32_t updater_spawner_thread_worker(void* arg) { +static void updater_start_app(void* context, uint32_t arg) { + UNUSED(context); UNUSED(arg); - Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "UpdaterApp", NULL); - furi_record_close(RECORD_LOADER); - return 0; -} -static void updater_spawner_thread_cleanup(FuriThreadState state, void* context) { - FuriThread* thread = context; - if(state == FuriThreadStateStopped) { - furi_thread_free(thread); - } -} - -static void updater_start_app() { FuriHalRtcBootMode mode = furi_hal_rtc_get_boot_mode(); if((mode != FuriHalRtcBootModePreUpdate) && (mode != FuriHalRtcBootModePostUpdate)) { return; @@ -110,11 +98,9 @@ static void updater_start_app() { * inside loader process, at startup. * So, accessing its record would cause a deadlock */ - FuriThread* thread = - furi_thread_alloc_ex("UpdateAppSpawner", 768, updater_spawner_thread_worker, NULL); - furi_thread_set_state_callback(thread, updater_spawner_thread_cleanup); - furi_thread_set_state_context(thread, thread); - furi_thread_start(thread); + Loader* loader = furi_record_open(RECORD_LOADER); + loader_start(loader, "UpdaterApp", NULL); + furi_record_close(RECORD_LOADER); } void updater_on_system_start() { @@ -126,7 +112,7 @@ void updater_on_system_start() { UNUSED(updater_cli_ep); #endif #ifndef FURI_RAM_EXEC - updater_start_app(); + furi_timer_pending_callback(updater_start_app, NULL, 0); #else UNUSED(updater_start_app); #endif diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index 63024ced9c..5d24774646 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -346,7 +346,11 @@ int32_t update_task_worker_flash_writer(void* context) { furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); // Format LFS before restoring backup on next boot furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); - +#ifdef FURI_NDEBUG + // Production + furi_hal_rtc_set_log_level(FuriLogLevelDefault); + furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); +#endif update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); success = true; } while(false); diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f2622c340f..a0ae040a5d 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,26.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -892,6 +892,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1278,7 +1280,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1287,6 +1289,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" @@ -1376,12 +1379,11 @@ Function,-,ldiv,ldiv_t,"long, long" Function,-,llabs,long long,long long Function,-,lldiv,lldiv_t,"long long, long long" Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 7878e5c682..ba82545e37 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.0,, +Version,+,26.0,, Header,+,applications/main/fap_loader/fap_loader_app.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -1171,6 +1171,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1683,7 +1685,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1692,6 +1694,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" @@ -1921,13 +1924,12 @@ Function,-,llround,long long int,double Function,-,llroundf,long long int,float Function,-,llroundl,long long int,long double Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, -Function,+,loader_show_settings,void, +Function,+,loader_show_menu,void,Loader* +Function,+,loader_show_settings,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/furi_hal/furi_hal_cortex.c b/firmware/targets/f7/furi_hal/furi_hal_cortex.c index d0bce50381..3fbe384e3c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_cortex.c +++ b/firmware/targets/f7/furi_hal/furi_hal_cortex.c @@ -1,11 +1,12 @@ #include +#include #include #define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000) void furi_hal_cortex_init_early() { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + CoreDebug->DEMCR |= (CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk); DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CYCCNT = 0U; @@ -38,4 +39,71 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer) { void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer) { while(!furi_hal_cortex_timer_is_expired(cortex_timer)) ; -} \ No newline at end of file +} + +// Duck ST +#undef COMP0 +#undef COMP1 +#undef COMP2 +#undef COMP3 + +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size) { + uint32_t function_reg = (uint32_t)function | ((uint32_t)size << 10); + + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = value; + (DWT->MASK0) = mask; + (DWT->FUNCTION0) = function_reg; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = value; + (DWT->MASK1) = mask; + (DWT->FUNCTION1) = function_reg; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = value; + (DWT->MASK2) = mask; + (DWT->FUNCTION2) = function_reg; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = value; + (DWT->MASK3) = mask; + (DWT->FUNCTION3) = function_reg; + break; + default: + furi_crash("Invalid parameter"); + } +} + +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp) { + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = 0; + (DWT->MASK0) = 0; + (DWT->FUNCTION0) = 0; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = 0; + (DWT->MASK1) = 0; + (DWT->FUNCTION1) = 0; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = 0; + (DWT->MASK2) = 0; + (DWT->FUNCTION2) = 0; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = 0; + (DWT->MASK3) = 0; + (DWT->FUNCTION3) = 0; + break; + default: + furi_crash("Invalid parameter"); + } +} diff --git a/firmware/targets/furi_hal_include/furi_hal_cortex.h b/firmware/targets/furi_hal_include/furi_hal_cortex.h index 91596ffe3f..ebabbabfd8 100644 --- a/firmware/targets/furi_hal_include/furi_hal_cortex.h +++ b/firmware/targets/furi_hal_include/furi_hal_cortex.h @@ -56,6 +56,53 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer); */ void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer); +typedef enum { + FuriHalCortexComp0, + FuriHalCortexComp1, + FuriHalCortexComp2, + FuriHalCortexComp3, +} FuriHalCortexComp; + +typedef enum { + FuriHalCortexCompSizeWord = 0b10, + FuriHalCortexCompSizeHalfWord = 0b01, + FuriHalCortexCompSizeByte = 0b00, +} FuriHalCortexCompSize; + +typedef enum { + FuriHalCortexCompFunctionPC = 0b100, + FuriHalCortexCompFunctionRead = 0b101, + FuriHalCortexCompFunctionWrite = 0b110, + FuriHalCortexCompFunctionReadWrite = 0b110, +} FuriHalCortexCompFunction; + +/** Enable DWT comparator + * + * Allows to programmatically set instruction/data breakpoints. + * + * More details on how it works can be found in armv7m official documentation: + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/The-DWT-comparators + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Comparator-Function-registers--DWT-FUNCTIONn + * + * @param[in] comp The Comparator + * @param[in] function The Comparator Function to use + * @param[in] value The value + * @param[in] mask The mask + * @param[in] size The size + */ +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size); + +/** Reset DWT comparator + * + * @param[in] comp The Comparator + */ +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp); + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index d78070d61d..facbcb4117 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -164,10 +164,13 @@ FuriThread* furi_thread_alloc_ex( void furi_thread_free(FuriThread* thread) { furi_assert(thread); + + // Ensure that use join before free furi_assert(thread->state == FuriThreadStateStopped); + furi_assert(thread->task_handle == NULL); - if(thread->name) free((void*)thread->name); - if(thread->appid) free((void*)thread->appid); + if(thread->name) free(thread->name); + if(thread->appid) free(thread->appid); furi_string_free(thread->output.buffer); free(thread); @@ -176,14 +179,14 @@ void furi_thread_free(FuriThread* thread) { void furi_thread_set_name(FuriThread* thread, const char* name) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->name) free((void*)thread->name); + if(thread->name) free(thread->name); thread->name = name ? strdup(name) : NULL; } void furi_thread_set_appid(FuriThread* thread, const char* appid) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->appid) free((void*)thread->appid); + if(thread->appid) free(thread->appid); thread->appid = appid ? strdup(appid) : NULL; } @@ -276,7 +279,7 @@ void furi_thread_cleanup_tcb_event(TaskHandle_t task) { if(thread) { // clear thread local storage vTaskSetThreadLocalStoragePointer(task, 0, NULL); - + furi_assert(thread->task_handle == task); thread->task_handle = NULL; } } @@ -332,7 +335,6 @@ FuriThreadId furi_thread_get_current_id() { FuriThread* furi_thread_get_current() { FuriThread* thread = pvTaskGetThreadLocalStoragePointer(NULL, 0); - furi_assert(thread != NULL); return thread; } @@ -579,24 +581,22 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) { return 0; } -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); __furi_thread_stdout_flush(thread); thread->output.write_callback = callback; - - return true; } FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); return thread->output.write_callback; } size_t furi_thread_stdout_write(const char* data, size_t size) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); if(size == 0 || data == NULL) { return __furi_thread_stdout_flush(thread); } else { @@ -619,7 +619,9 @@ size_t furi_thread_stdout_write(const char* data, size_t size) { } int32_t furi_thread_stdout_flush() { - return __furi_thread_stdout_flush(furi_thread_get_current()); + FuriThread* thread = furi_thread_get_current(); + furi_assert(thread); + return __furi_thread_stdout_flush(thread); } void furi_thread_suspend(FuriThreadId thread_id) { diff --git a/furi/core/thread.h b/furi/core/thread.h index b11a225b58..022894ee8f 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -233,7 +233,7 @@ FuriThreadId furi_thread_get_current_id(); /** Get FuriThread instance for current thread * - * @return FuriThread* + * @return pointer to FuriThread or NULL if this thread doesn't belongs to Furi */ FuriThread* furi_thread_get_current(); @@ -288,12 +288,10 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(); /** Set STDOUT callback for thread - * + * * @param callback callback or NULL to clear - * - * @return true on success, otherwise fail */ -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); /** Write data to buffered STDOUT * diff --git a/furi/core/timer.c b/furi/core/timer.c index 4b6ccecba5..7743ffe701 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -124,3 +124,13 @@ uint32_t furi_timer_is_running(FuriTimer* instance) { /* Return 0: not running, 1: running */ return (uint32_t)xTimerIsTimerActive(hTimer); } + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg) { + BaseType_t ret = pdFAIL; + if(furi_kernel_is_irq_or_masked()) { + ret = xTimerPendFunctionCallFromISR(callback, context, arg, NULL); + } else { + ret = xTimerPendFunctionCall(callback, context, arg, FuriWaitForever); + } + furi_check(ret == pdPASS); +} \ No newline at end of file diff --git a/furi/core/timer.h b/furi/core/timer.h index e79c1868d9..3f43de5fd9 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -56,6 +56,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance); */ uint32_t furi_timer_is_running(FuriTimer* instance); +typedef void (*FuriTimerPendigCallback)(void* context, uint32_t arg); + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg); + #ifdef __cplusplus } #endif From 24dd4336c4973e95ab0eabbf8954c2ec43463deb Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sat, 6 May 2023 02:53:21 +0100 Subject: [PATCH 13/14] Dont reload ext main apps data on each menu open --- applications/services/loader/loader.c | 54 +++++++++++++++- applications/services/loader/loader.h | 1 + .../services/loader/loader_extmainapp.h | 12 ++++ applications/services/loader/loader_i.h | 1 + applications/services/loader/loader_menu.c | 64 ++++--------------- applications/services/loader/loader_menu.h | 3 +- 6 files changed, 82 insertions(+), 53 deletions(-) create mode 100644 applications/services/loader/loader_extmainapp.h diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index b9f47dcddd..12651eba74 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -3,6 +3,11 @@ #include "loader_menu.h" #include #include +#include +#include +#include +#include "applications/main/fap_loader/fap_loader_app.h" +#include #define TAG "Loader" #define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF @@ -107,6 +112,28 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con } } +bool loader_menu_load_fap_meta( + Storage* storage, + FuriString* path, + FuriString* name, + const Icon** icon) { + *icon = NULL; + uint8_t* icon_buf = malloc(CUSTOM_ICON_MAX_SIZE); + if(!fap_loader_load_name_and_icon(path, storage, &icon_buf, name)) { + free(icon_buf); + icon_buf = NULL; + return false; + } + *icon = malloc(sizeof(Icon)); + FURI_CONST_ASSIGN((*icon)->frame_count, 1); + FURI_CONST_ASSIGN((*icon)->frame_rate, 0); + FURI_CONST_ASSIGN((*icon)->width, 10); + FURI_CONST_ASSIGN((*icon)->height, 10); + FURI_CONST_ASSIGN_PTR((*icon)->frames, malloc(sizeof(const uint8_t*))); + FURI_CONST_ASSIGN_PTR((*icon)->frames[0], icon_buf); + return true; +} + // implementation static Loader* loader_alloc() { @@ -118,6 +145,31 @@ static Loader* loader_alloc() { loader->app.name = NULL; loader->app.thread = NULL; loader->app.insomniac = false; + + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* path = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + Stream* stream = file_stream_alloc(storage); + ExtMainAppList_init(loader->ext_main_apps); + if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + while(stream_read_line(stream, path)) { + furi_string_replace_all(path, "\r", ""); + furi_string_replace_all(path, "\n", ""); + const Icon* icon; + if(!loader_menu_load_fap_meta(storage, path, name, &icon)) continue; + ExtMainAppList_push_back( + loader->ext_main_apps, + (ExtMainApp){ + .name = strdup(furi_string_get_cstr(name)), + .path = strdup(furi_string_get_cstr(path)), + .icon = icon}); + } + } + file_stream_close(stream); + stream_free(stream); + furi_string_free(name); + furi_string_free(path); + furi_record_close(RECORD_STORAGE); return loader; } @@ -204,7 +256,7 @@ static void loader_do_menu_show(Loader* loader, bool settings) { loader->loader_menu = loader_menu_alloc(); loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); - loader_menu_start(loader->loader_menu, settings); + loader_menu_start(loader->loader_menu, settings, &loader->ext_main_apps); } } diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index e8f1fd64e8..b31bb1bdd6 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,5 +1,6 @@ #pragma once #include +#include "loader_extmainapp.h" #ifdef __cplusplus extern "C" { diff --git a/applications/services/loader/loader_extmainapp.h b/applications/services/loader/loader_extmainapp.h new file mode 100644 index 0000000000..2e10b16a3d --- /dev/null +++ b/applications/services/loader/loader_extmainapp.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +typedef struct { + const char* name; + const char* path; + const Icon* icon; +} ExtMainApp; + +LIST_DEF(ExtMainAppList, ExtMainApp, M_POD_OPLIST) diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 4a1477a7b2..6887b4b509 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -16,6 +16,7 @@ struct Loader { FuriMessageQueue* queue; LoaderMenu* loader_menu; LoaderAppData app; + ExtMainAppList_t ext_main_apps; }; typedef enum { diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c index 1391394e51..c4e14038c5 100644 --- a/applications/services/loader/loader_menu.c +++ b/applications/services/loader/loader_menu.c @@ -4,11 +4,6 @@ #include #include #include -#include -#include -#include -#include "applications/main/fap_loader/fap_loader_app.h" -#include #include "loader_menu.h" @@ -19,7 +14,9 @@ struct LoaderMenu { ViewDispatcher* view_dispatcher; Menu* primary_menu; Submenu* settings_menu; + bool settings; + ExtMainAppList_t* ext_main_apps; void (*closed_callback)(void*); void* closed_callback_context; @@ -59,10 +56,11 @@ void loader_menu_free(LoaderMenu* loader_menu) { free(loader_menu); } -void loader_menu_start(LoaderMenu* loader_menu, bool settings) { +void loader_menu_start(LoaderMenu* loader_menu, bool settings, ExtMainAppList_t* ext_main_apps) { furi_assert(loader_menu); furi_assert(!loader_menu->thread); loader_menu->settings = settings; + loader_menu->ext_main_apps = ext_main_apps; loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); furi_thread_start(loader_menu->thread); } @@ -132,28 +130,6 @@ static uint32_t loader_menu_exit(void* context) { return VIEW_NONE; } -bool loader_menu_load_fap_meta( - Storage* storage, - FuriString* path, - FuriString* name, - const Icon** icon) { - *icon = NULL; - uint8_t* icon_buf = malloc(CUSTOM_ICON_MAX_SIZE); - if(!fap_loader_load_name_and_icon(path, storage, &icon_buf, name)) { - free(icon_buf); - icon_buf = NULL; - return false; - } - *icon = malloc(sizeof(Icon)); - FURI_CONST_ASSIGN((*icon)->frame_count, 1); - FURI_CONST_ASSIGN((*icon)->frame_rate, 0); - FURI_CONST_ASSIGN((*icon)->width, 10); - FURI_CONST_ASSIGN((*icon)->height, 10); - FURI_CONST_ASSIGN_PTR((*icon)->frames, malloc(sizeof(const uint8_t*))); - FURI_CONST_ASSIGN_PTR((*icon)->frames[0], icon_buf); - return true; -} - static void loader_menu_build_menu(LoaderMenu* loader_menu) { size_t i; for(i = 0; i < FLIPPER_APPS_COUNT; i++) { @@ -173,30 +149,16 @@ static void loader_menu_build_menu(LoaderMenu* loader_menu) { loader_menu_switch_to_settings, loader_menu); - Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* path = furi_string_alloc(); - FuriString* name = furi_string_alloc(); - Stream* stream = file_stream_alloc(storage); - if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - while(stream_read_line(stream, path)) { - furi_string_replace_all(path, "\r", ""); - furi_string_replace_all(path, "\n", ""); - const Icon* icon; - if(!loader_menu_load_fap_meta(storage, path, name, &icon)) continue; - menu_add_item( - loader_menu->primary_menu, - strdup(furi_string_get_cstr(name)), - icon, - (uint32_t)strdup(furi_string_get_cstr(path)), - loader_menu_external_callback, - (void*)loader_menu); - } + for(i = 0; i < ExtMainAppList_size(*loader_menu->ext_main_apps); i++) { + const ExtMainApp* app = ExtMainAppList_get(*loader_menu->ext_main_apps, i); + menu_add_item( + loader_menu->primary_menu, + app->name, + app->icon, + (uint32_t)app->path, + loader_menu_external_callback, + (void*)loader_menu); } - file_stream_close(stream); - stream_free(stream); - furi_string_free(name); - furi_string_free(path); - furi_record_close(RECORD_STORAGE); }; static void loader_menu_build_submenu(LoaderMenu* loader_menu) { diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h index db39834da5..f4188b7335 100644 --- a/applications/services/loader/loader_menu.h +++ b/applications/services/loader/loader_menu.h @@ -1,5 +1,6 @@ #pragma once #include +#include "loader_extmainapp.h" #ifdef __cplusplus extern "C" { @@ -11,7 +12,7 @@ LoaderMenu* loader_menu_alloc(); void loader_menu_free(LoaderMenu* loader_menu); -void loader_menu_start(LoaderMenu* loader_menu, bool settings); +void loader_menu_start(LoaderMenu* loader_menu, bool settings, ExtMainAppList_t* ext_main_apps); void loader_menu_stop(LoaderMenu* loader_menu); From 1db6d4dbe82f7fc40a68e4e8dad5f0341d6e8ad8 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sat, 6 May 2023 18:34:39 +0100 Subject: [PATCH 14/14] Bump v46 --- fbt_options.py | 2 +- scripts/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fbt_options.py b/fbt_options.py index 3fdcc6e30d..27503cbd66 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -14,7 +14,7 @@ # Suffix to add to files when building distribution # If OS environment has DIST_SUFFIX set, it will be used instead -DIST_SUFFIX = "XFW-0045_04052023" +DIST_SUFFIX = "XFW-0046_06052023" # Coprocessor firmware COPRO_OB_DATA = "scripts/ob.data" diff --git a/scripts/version.py b/scripts/version.py index 9e543ac9c2..7d3643765f 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -1,5 +1,5 @@ #!/usb/bin/env python3 -VERSION = "XFW-0045" +VERSION = "XFW-0046" import json import os