Merge branch 'dev' into nfc-parsers

This commit is contained in:
MX
2023-12-21 03:36:32 +03:00
38 changed files with 924 additions and 589 deletions

View File

@@ -27,6 +27,7 @@ static const uint32_t baudrate_list[] = {
460800,
921600,
};
static const char* software_de_re[] = {"None", "4"};
bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) {
GpioApp* app = context;
@@ -84,6 +85,17 @@ static void line_port_cb(VariableItem* item) {
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
}
static void line_software_de_re_cb(VariableItem* item) {
GpioApp* app = variable_item_get_context(item);
furi_assert(app);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, software_de_re[index]);
app->usb_uart_cfg->software_de_re = index;
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
}
static void line_flow_cb(VariableItem* item) {
GpioApp* app = variable_item_get_context(item);
furi_assert(app);
@@ -155,6 +167,11 @@ void gpio_scene_usb_uart_cfg_on_enter(void* context) {
app->var_item_flow = item;
line_ensure_flow_invariant(app);
item = variable_item_list_add(
var_item_list, "DE/RE Pin", COUNT_OF(software_de_re), line_software_de_re_cb, app);
variable_item_set_current_value_index(item, app->usb_uart_cfg->software_de_re);
variable_item_set_current_value_text(item, software_de_re[app->usb_uart_cfg->software_de_re]);
variable_item_list_set_selected_item(
var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUartCfg));

View File

@@ -6,11 +6,16 @@
#include <furi_hal.h>
#include <furi_hal_usb_cdc.h>
//TODO: FL-3276 port to new USART API
#include <stm32wbxx_ll_lpuart.h>
#include <stm32wbxx_ll_usart.h>
#define USB_CDC_PKT_LEN CDC_DATA_SZ
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
#define USB_CDC_BIT_DTR (1 << 0)
#define USB_CDC_BIT_RTS (1 << 1)
#define USB_USART_DE_RE_PIN &gpio_ext_pa4
static const GpioPin* flow_pins[][2] = {
{&gpio_ext_pa7, &gpio_ext_pa6}, // 2, 3
@@ -247,6 +252,17 @@ static int32_t usb_uart_worker(void* context) {
usb_uart->cfg.flow_pins = usb_uart->cfg_new.flow_pins;
events |= WorkerEvtCtrlLineSet;
}
if(usb_uart->cfg.software_de_re != usb_uart->cfg_new.software_de_re) {
usb_uart->cfg.software_de_re = usb_uart->cfg_new.software_de_re;
if(usb_uart->cfg.software_de_re != 0) {
furi_hal_gpio_write(USB_USART_DE_RE_PIN, true);
furi_hal_gpio_init(
USB_USART_DE_RE_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedMedium);
} else {
furi_hal_gpio_init(
USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
}
}
api_lock_unlock(usb_uart->cfg_lock);
}
if(events & WorkerEvtLineCfgSet) {
@@ -260,6 +276,8 @@ static int32_t usb_uart_worker(void* context) {
usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch);
usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch);
furi_hal_gpio_init(USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
if(usb_uart->cfg.flow_pins != 0) {
furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][0], GpioModeAnalog);
furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], GpioModeAnalog);
@@ -298,7 +316,24 @@ static int32_t usb_uart_tx_thread(void* context) {
if(len > 0) {
usb_uart->st.tx_cnt += len;
if(usb_uart->cfg.software_de_re != 0)
furi_hal_gpio_write(USB_USART_DE_RE_PIN, false);
furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, len);
if(usb_uart->cfg.software_de_re != 0) {
//TODO: FL-3276 port to new USART API
if(usb_uart->cfg.uart_ch == FuriHalUartIdUSART1) {
while(!LL_USART_IsActiveFlag_TC(USART1))
;
} else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) {
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
;
}
furi_hal_gpio_write(USB_USART_DE_RE_PIN, true);
}
}
}
}

View File

@@ -11,6 +11,7 @@ typedef struct {
uint8_t flow_pins;
uint8_t baudrate_mode;
uint32_t baudrate;
uint8_t software_de_re;
} UsbUartConfig;
typedef struct {

View File

@@ -54,11 +54,11 @@ static void infrared_progress_view_draw_callback(Canvas* canvas, void* _model) {
float progress_value = (float)model->progress / model->progress_total;
elements_progress_bar(canvas, x + 4, y + 19, width - 7, progress_value);
uint8_t percent_value = 100 * model->progress / model->progress_total;
char percents_string[10] = {0};
snprintf(percents_string, sizeof(percents_string), "%d%%", percent_value);
char number_string[10] = {0};
snprintf(
number_string, sizeof(number_string), "%d/%d", model->progress, model->progress_total);
elements_multiline_text_aligned(
canvas, x + 33, y + 37, AlignCenter, AlignCenter, percents_string);
canvas, x + 33, y + 37, AlignCenter, AlignCenter, number_string);
canvas_draw_icon(canvas, x + 14, y + height - 14, &I_Pin_back_arrow_10x8);
canvas_draw_str(canvas, x + 30, y + height - 6, "= stop");

View File

@@ -1,6 +1,6 @@
#include "mf_user_dict.h"
#include <nfc/helpers/nfc_dict.h>
#include <toolbox/keys_dict.h>
#include <nfc/protocols/mf_classic/mf_classic.h>
#include <furi/furi.h>
@@ -15,22 +15,22 @@ struct MfUserDict {
MfUserDict* mf_user_dict_alloc(size_t max_keys_to_load) {
MfUserDict* instance = malloc(sizeof(MfUserDict));
NfcDict* dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
furi_assert(dict);
size_t dict_keys_num = nfc_dict_get_total_keys(dict);
size_t dict_keys_num = keys_dict_get_total_keys(dict);
instance->keys_num = MIN(max_keys_to_load, dict_keys_num);
if(instance->keys_num > 0) {
instance->keys_arr = malloc(instance->keys_num * sizeof(MfClassicKey));
for(size_t i = 0; i < instance->keys_num; i++) {
bool key_loaded =
nfc_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey));
keys_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey));
furi_assert(key_loaded);
}
}
nfc_dict_free(dict);
keys_dict_free(dict);
return instance;
}
@@ -67,13 +67,13 @@ bool mf_user_dict_delete_key(MfUserDict* instance, uint32_t index) {
furi_assert(index < instance->keys_num);
furi_assert(instance->keys_arr);
NfcDict* dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
furi_assert(dict);
bool key_delete_success =
nfc_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey));
nfc_dict_free(dict);
keys_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey));
keys_dict_free(dict);
if(key_delete_success) {
instance->keys_num--;

View File

@@ -343,7 +343,7 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) {
nfc_supported_cards_load_cache(instance->nfc_supported_cards);
FuriString* load_path = furi_string_alloc();
if(nfc_has_shadow_file_internal(instance, path)) {
if(nfc_has_shadow_file_internal(instance, path)) { //-V1051
nfc_set_shadow_file_path(path, load_path);
} else if(furi_string_end_with(path, NFC_APP_SHADOW_EXTENSION)) {
size_t path_len = furi_string_size(path);

View File

@@ -52,7 +52,7 @@
#include <nfc/nfc_device.h>
#include <nfc/helpers/nfc_data_generator.h>
#include <nfc/helpers/nfc_dict.h>
#include <toolbox/keys_dict.h>
#include <gui/modules/validators.h>
#include <toolbox/path.h>
@@ -80,7 +80,7 @@ typedef enum {
} NfcRpcState;
typedef struct {
NfcDict* dict;
KeysDict* dict;
uint8_t sectors_total;
uint8_t sectors_read;
uint8_t current_sector;

View File

@@ -41,7 +41,8 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
} else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) {
MfClassicKey key = {};
if(nfc_dict_get_next_key(instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) {
if(keys_dict_get_next_key(
instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) {
mfc_event->data->key_request_data.key = key;
mfc_event->data->key_request_data.key_provided = true;
instance->nfc_dict_context.dict_keys_current++;
@@ -60,7 +61,7 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
} else if(mfc_event->type == MfClassicPollerEventTypeNextSector) {
nfc_dict_rewind(instance->nfc_dict_context.dict);
keys_dict_rewind(instance->nfc_dict_context.dict);
instance->nfc_dict_context.dict_keys_current = 0;
instance->nfc_dict_context.current_sector =
mfc_event->data->next_sector_data.current_sector;
@@ -79,7 +80,7 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
} else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStop) {
nfc_dict_rewind(instance->nfc_dict_context.dict);
keys_dict_rewind(instance->nfc_dict_context.dict);
instance->nfc_dict_context.is_key_attack = false;
instance->nfc_dict_context.dict_keys_current = 0;
view_dispatcher_send_custom_event(
@@ -124,15 +125,15 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) {
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack);
if(state == DictAttackStateUserDictInProgress) {
do {
if(!nfc_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) {
if(!keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) {
state = DictAttackStateSystemDictInProgress;
break;
}
instance->nfc_dict_context.dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
if(nfc_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
nfc_dict_free(instance->nfc_dict_context.dict);
instance->nfc_dict_context.dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
keys_dict_free(instance->nfc_dict_context.dict);
state = DictAttackStateSystemDictInProgress;
break;
}
@@ -141,13 +142,13 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) {
} while(false);
}
if(state == DictAttackStateSystemDictInProgress) {
instance->nfc_dict_context.dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey));
instance->nfc_dict_context.dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey));
dict_attack_set_header(instance->dict_attack, "MF Classic System Dictionary");
}
instance->nfc_dict_context.dict_keys_total =
nfc_dict_get_total_keys(instance->nfc_dict_context.dict);
keys_dict_get_total_keys(instance->nfc_dict_context.dict);
dict_attack_set_total_dict_keys(
instance->dict_attack, instance->nfc_dict_context.dict_keys_total);
instance->nfc_dict_context.dict_keys_current = 0;
@@ -185,7 +186,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
if(state == DictAttackStateUserDictInProgress) {
nfc_poller_stop(instance->poller);
nfc_poller_free(instance->poller);
nfc_dict_free(instance->nfc_dict_context.dict);
keys_dict_free(instance->nfc_dict_context.dict);
scene_manager_set_scene_state(
instance->scene_manager,
NfcSceneMfClassicDictAttack,
@@ -215,7 +216,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
if(instance->nfc_dict_context.is_card_present) {
nfc_poller_stop(instance->poller);
nfc_poller_free(instance->poller);
nfc_dict_free(instance->nfc_dict_context.dict);
keys_dict_free(instance->nfc_dict_context.dict);
scene_manager_set_scene_state(
instance->scene_manager,
NfcSceneMfClassicDictAttack,
@@ -253,7 +254,7 @@ void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
scene_manager_set_scene_state(
instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateUserDictInProgress);
nfc_dict_free(instance->nfc_dict_context.dict);
keys_dict_free(instance->nfc_dict_context.dict);
instance->nfc_dict_context.current_sector = 0;
instance->nfc_dict_context.sectors_total = 0;

View File

@@ -14,20 +14,20 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) {
// Load flipper dict keys total
uint32_t flipper_dict_keys_total = 0;
NfcDict* dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey));
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey));
if(dict) {
flipper_dict_keys_total = nfc_dict_get_total_keys(dict);
nfc_dict_free(dict);
flipper_dict_keys_total = keys_dict_get_total_keys(dict);
keys_dict_free(dict);
}
// Load user dict keys total
uint32_t user_dict_keys_total = 0;
dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
if(dict) {
user_dict_keys_total = nfc_dict_get_total_keys(dict);
nfc_dict_free(dict);
user_dict_keys_total = keys_dict_get_total_keys(dict);
keys_dict_free(dict);
}
FuriString* temp_str = furi_string_alloc();

View File

@@ -29,23 +29,23 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) {
// Add key to dict
NfcDict* dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
furi_assert(dict);
MfClassicKey key = {};
memcpy(key.data, instance->byte_input_store, sizeof(MfClassicKey));
if(nfc_dict_is_key_present(dict, key.data, sizeof(MfClassicKey))) {
if(keys_dict_is_key_present(dict, key.data, sizeof(MfClassicKey))) {
scene_manager_next_scene(
instance->scene_manager, NfcSceneMfClassicKeysWarnDuplicate);
} else if(nfc_dict_add_key(dict, key.data, sizeof(MfClassicKey))) {
} else if(keys_dict_add_key(dict, key.data, sizeof(MfClassicKey))) {
scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess);
dolphin_deed(DolphinDeedNfcMfcAdd);
} else {
scene_manager_previous_scene(instance->scene_manager);
}
nfc_dict_free(dict);
keys_dict_free(dict);
consumed = true;
}
}

View File

@@ -27,6 +27,8 @@ typedef enum {
SubmenuIndexGibidi433,
SubmenuIndexNiceMHouse_433_92,
SubmenuIndexJCM_433_92,
SubmenuIndexFAACRCXT_433_92,
SubmenuIndexFAACRCXT_868,
SubmenuIndexNormstahl_433_92,
SubmenuIndexGSN,
SubmenuIndexAprimatic,

View File

@@ -249,7 +249,9 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
subghz_view_receiver_disable_draw_callback(subghz->subghz_receiver);
subghz_history_delete_item(subghz->history, subghz->idx_menu_chosen);
subghz_view_receiver_delete_element_callback(subghz->subghz_receiver);
subghz_view_receiver_delete_item(
subghz->subghz_receiver,
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver));
subghz_view_receiver_enable_draw_callback(subghz->subghz_receiver);
subghz_scene_receiver_update_statusbar(subghz);

View File

@@ -181,6 +181,18 @@ void subghz_scene_set_type_on_enter(void* context) {
SubmenuIndexJCM_433_92,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"KL: FAAC RC,XT 433MHz",
SubmenuIndexFAACRCXT_433_92,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"KL: FAAC RC,XT 868MHz",
SubmenuIndexFAACRCXT_868,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"KL: Nice Mhouse 433MHz",
@@ -744,6 +756,36 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexFAACRCXT_433_92:
generated_protocol = subghz_txrx_gen_keeloq_protocol(
subghz->txrx,
"AM650",
433920000,
(key & 0x0000FFFF) | 0x00100000,
0x2,
0x0003,
"FAAC_RC,XT");
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexFAACRCXT_868:
generated_protocol = subghz_txrx_gen_keeloq_protocol(
subghz->txrx,
"AM650",
868350000,
(key & 0x0000FFFF) | 0x00100000,
0x2,
0x0003,
"FAAC_RC,XT");
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexNormstahl_433_92:
generated_protocol = subghz_txrx_gen_keeloq_protocol(
subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Normstahl");

View File

@@ -1,10 +1,11 @@
#include "subghz_history.h"
#include <lib/subghz/receiver.h>
#include <rpc/rpc.h>
#include <furi.h>
#define SUBGHZ_HISTORY_MAX 55
#define SUBGHZ_HISTORY_FREE_HEAP 20480
#define SUBGHZ_HISTORY_MAX 65530 // uint16_t index max, ram limit below
#define SUBGHZ_HISTORY_FREE_HEAP (10240 * (3 - MIN(rpc_get_sessions_count(instance->rpc), 2U)))
#define TAG "SubGhzHistory"
typedef struct {
@@ -29,6 +30,7 @@ struct SubGhzHistory {
uint8_t code_last_hash_data;
FuriString* tmp_string;
SubGhzHistoryStruct* history;
Rpc* rpc;
};
SubGhzHistory* subghz_history_alloc(void) {
@@ -36,6 +38,7 @@ SubGhzHistory* subghz_history_alloc(void) {
instance->tmp_string = furi_string_alloc();
instance->history = malloc(sizeof(SubGhzHistoryStruct));
SubGhzHistoryItemArray_init(instance->history->data);
instance->rpc = furi_record_open(RECORD_RPC);
return instance;
}
@@ -52,6 +55,7 @@ void subghz_history_free(SubGhzHistory* instance) {
}
SubGhzHistoryItemArray_clear(instance->history->data);
free(instance->history);
furi_record_close(RECORD_RPC);
free(instance);
}
@@ -89,26 +93,19 @@ void subghz_history_reset(SubGhzHistory* instance) {
instance->code_last_hash_data = 0;
}
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id) {
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t idx) {
furi_assert(instance);
SubGhzHistoryItemArray_it_t it;
//SubGhzHistoryItem* target_item = SubGhzHistoryItemArray_get(instance->history->data, item_id);
SubGhzHistoryItemArray_it_last(it, instance->history->data);
while(!SubGhzHistoryItemArray_end_p(it)) {
SubGhzHistoryItem* item = SubGhzHistoryItemArray_ref(it);
if(it->index == (size_t)(item_id)) {
furi_string_free(item->item_str);
furi_string_free(item->preset->name);
free(item->preset);
flipper_format_free(item->flipper_string);
item->type = 0;
SubGhzHistoryItemArray_remove(instance->history->data, it);
}
SubGhzHistoryItemArray_previous(it);
if(idx < SubGhzHistoryItemArray_size(instance->history->data)) {
SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
furi_string_free(item->item_str);
furi_string_free(item->preset->name);
free(item->preset);
flipper_format_free(item->flipper_string);
item->type = 0;
SubGhzHistoryItemArray_remove_v(instance->history->data, idx, idx + 1);
instance->last_index_write--;
}
instance->last_index_write--;
}
uint16_t subghz_history_get_item(SubGhzHistory* instance) {
@@ -150,15 +147,14 @@ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx
bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output) {
furi_assert(instance);
if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) {
if(output != NULL) furi_string_printf(output, " Free heap LOW");
if(output != NULL) furi_string_printf(output, " Memory is FULL");
return true;
}
if(instance->last_index_write == SUBGHZ_HISTORY_MAX) {
if(output != NULL) furi_string_printf(output, " Memory is FULL");
if(output != NULL) furi_string_printf(output, " History is FULL");
return true;
}
if(output != NULL)
furi_string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
if(output != NULL) furi_string_printf(output, "%02u", instance->last_index_write);
return false;
}

View File

@@ -27,7 +27,7 @@ void subghz_history_free(SubGhzHistory* instance);
*/
void subghz_history_reset(SubGhzHistory* instance);
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id);
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t idx);
/** Get frequency to history[idx]
*

View File

@@ -383,7 +383,16 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
#else
canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str));
#endif
canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str));
if(!furi_string_empty(model->history_stat_str)) {
canvas_draw_str_aligned(
canvas,
114,
62,
AlignRight,
AlignBottom,
furi_string_get_cstr(model->history_stat_str));
canvas_draw_icon(canvas, 116, 53, &I_sub1_10px);
}
canvas_set_font(canvas, FontSecondary);
elements_bold_rounded_frame(canvas, 14, 8, 99, 48);
elements_multiline_text(canvas, 65, 26, "To unlock\npress:");
@@ -419,7 +428,16 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
#else
canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str));
#endif
canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str));
if(!furi_string_empty(model->history_stat_str)) {
canvas_draw_str_aligned(
canvas,
114,
62,
AlignRight,
AlignBottom,
furi_string_get_cstr(model->history_stat_str));
canvas_draw_icon(canvas, 116, 53, &I_sub1_10px);
}
} break;
}
}
@@ -655,40 +673,32 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver)
return idx;
}
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver) {
void subghz_view_receiver_delete_item(SubGhzViewReceiver* subghz_receiver, uint16_t idx) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view,
SubGhzViewReceiverModel * model,
{
SubGhzReceiverMenuItemArray_it_t it;
// SubGhzReceiverMenuItem* target_item =
// SubGhzReceiverMenuItemArray_get(model->history->data, model->idx);
SubGhzReceiverMenuItemArray_it_last(it, model->history->data);
while(!SubGhzReceiverMenuItemArray_end_p(it)) {
SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it);
if(idx < SubGhzReceiverMenuItemArray_size(model->history->data)) {
SubGhzReceiverMenuItem* item =
SubGhzReceiverMenuItemArray_get(model->history->data, idx);
furi_string_free(item->item_str);
furi_string_free(item->time);
item->type = 0;
SubGhzReceiverMenuItemArray_remove_v(model->history->data, idx, idx + 1);
if(it->index == (size_t)(model->idx)) {
furi_string_free(item->item_str);
furi_string_free(item->time);
item->type = 0;
SubGhzReceiverMenuItemArray_remove(model->history->data, it);
if(model->history_item == 5) {
if(model->idx >= 2) {
model->idx = model->history_item - 1;
}
}
model->history_item--;
SubGhzReceiverMenuItemArray_previous(it);
}
if(model->history_item == 5) {
if(model->idx >= 2) {
model->idx = model->history_item - 1;
if(model->idx && (model->idx > idx || model->idx == model->history_item)) {
model->idx--;
}
}
model->history_item--;
if(model->idx != 0) {
model->idx--;
}
},
true);
}

View File

@@ -53,7 +53,7 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver);
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx);
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver);
void subghz_view_receiver_delete_item(SubGhzViewReceiver* subghz_receiver, uint16_t idx);
void subghz_view_receiver_enable_draw_callback(SubGhzViewReceiver* subghz_receiver);