diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 5746efbed..5ac4fcccd 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -62,26 +62,31 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* item_name; + FuriString* item_time; + 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(str_buff); + furi_string_reset(item_name); + furi_string_reset(item_time); subghz->state_notifications = SubGhzNotificationStateRxDone; - subghz_history_get_text_item_menu( - subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); + subghz_history_get_text_item_menu(subghz->txrx->history, item_name, idx); + subghz_history_get_time_item_menu(subghz->txrx->history, item_time, idx); 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)); + furi_string_get_cstr(item_name), + furi_string_get_cstr(item_time), + subghz_history_get_type_protocol(subghz->txrx->history, idx)); subghz_scene_receiver_update_statusbar(subghz); } subghz_receiver_reset(receiver); - furi_string_free(str_buff); + furi_string_free(item_name); + furi_string_free(item_time); } bool subghz_scene_decode_raw_start(SubGhz* subghz) { @@ -159,8 +164,10 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { void subghz_scene_decode_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* item_name; + FuriString* item_time; + item_name = furi_string_alloc(); + item_time = furi_string_alloc(); subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); @@ -183,14 +190,18 @@ void subghz_scene_decode_raw_on_enter(void* context) { //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++) { - furi_string_reset(str_buff); - subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); + furi_string_reset(item_name); + furi_string_reset(item_time); + subghz_history_get_text_item_menu(subghz->txrx->history, item_name, i); + subghz_history_get_time_item_menu(subghz->txrx->history, item_time, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, - furi_string_get_cstr(str_buff), + furi_string_get_cstr(item_name), + furi_string_get_cstr(item_time), subghz_history_get_type_protocol(subghz->txrx->history, i)); } - furi_string_free(str_buff); + furi_string_free(item_name); + furi_string_free(item_time); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 5276bc4a8..b17a0700b 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -91,34 +91,41 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* item_name; + FuriString* item_time; + 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(str_buff); + furi_string_reset(item_name); + furi_string_reset(item_time); subghz->state_notifications = SubGhzNotificationStateRxDone; - subghz_history_get_text_item_menu( - subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); + subghz_history_get_text_item_menu(subghz->txrx->history, item_name, idx); + subghz_history_get_time_item_menu(subghz->txrx->history, item_time, idx); 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)); + furi_string_get_cstr(item_name), + furi_string_get_cstr(item_time), + subghz_history_get_type_protocol(subghz->txrx->history, idx)); subghz_scene_receiver_update_statusbar(subghz); } subghz_receiver_reset(receiver); - furi_string_free(str_buff); + furi_string_free(item_name); + furi_string_free(item_time); subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; } void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* item_name; + FuriString* item_time; + item_name = furi_string_alloc(); + item_time = furi_string_alloc(); if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); @@ -132,15 +139,19 @@ void subghz_scene_receiver_on_enter(void* context) { //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++) { - furi_string_reset(str_buff); - subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); + furi_string_reset(item_name); + furi_string_reset(item_time); + subghz_history_get_text_item_menu(subghz->txrx->history, item_name, i); + subghz_history_get_time_item_menu(subghz->txrx->history, item_time, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, - furi_string_get_cstr(str_buff), + furi_string_get_cstr(item_name), + furi_string_get_cstr(item_time), subghz_history_get_type_protocol(subghz->txrx->history, i)); subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; } - furi_string_free(str_buff); + furi_string_free(item_name); + furi_string_free(item_time); subghz_scene_receiver_update_statusbar(subghz); subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index bb6d00a17..51d5ada7d 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -161,10 +161,14 @@ uint16_t subghz_history_get_last_index(SubGhzHistory* instance) { return instance->last_index_write; } void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx) { + SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); + furi_string_set(output, item->item_str); +} + +void subghz_history_get_time_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx) { SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); FuriHalRtcDateTime* t = &item->datetime; furi_string_printf(output, "%.2d:%.2d:%.2d ", t->hour, t->minute, t->second); - furi_string_cat(output, item->item_str); } bool subghz_history_add_to_history( diff --git a/applications/main/subghz/subghz_history.h b/applications/main/subghz/subghz_history.h index 1f2f8d246..1b27d52ad 100644 --- a/applications/main/subghz/subghz_history.h +++ b/applications/main/subghz/subghz_history.h @@ -78,6 +78,14 @@ const char* subghz_history_get_protocol_name(SubGhzHistory* instance, uint16_t i */ void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx); +/** Get time item menu to history[idx] + * + * @param instance - SubGhzHistory instance + * @param output - FuriString* output + * @param idx - record index + */ +void subghz_history_get_time_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx); + /** Get string the remaining number of records to history * * @param instance - SubGhzHistory instance diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 8dbb22b86..33a3c79d1 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -14,8 +14,12 @@ #define SUBGHZ_RAW_THRESHOLD_MIN -90.0f +#define SCROLL_INTERVAL (333) +#define SCROLL_DELAY (2) + typedef struct { FuriString* item_str; + FuriString* time; uint8_t type; } SubGhzReceiverMenuItem; @@ -51,6 +55,7 @@ struct SubGhzViewReceiver { View* view; SubGhzViewReceiverCallback callback; void* context; + FuriTimer* scroll_timer; }; typedef struct { @@ -65,6 +70,7 @@ typedef struct { SubGhzViewReceiverBarShow bar_show; SubGhzViewReceiverMode mode; uint8_t u_rssi; + size_t scroll_counter; } SubGhzViewReceiverModel; void subghz_view_receiver_set_mode( @@ -144,6 +150,7 @@ static void subghz_view_receiver_update_offset(SubGhzViewReceiver* subghz_receiv void subghz_view_receiver_add_item_to_menu( SubGhzViewReceiver* subghz_receiver, const char* name, + const char* time, uint8_t type) { furi_assert(subghz_receiver); with_view_model( @@ -152,6 +159,7 @@ void subghz_view_receiver_add_item_to_menu( { SubGhzReceiverMenuItem* item_menu = SubGhzReceiverMenuItemArray_push_raw(model->history->data); + item_menu->time = furi_string_alloc_set(time); item_menu->item_str = furi_string_alloc_set(name); item_menu->type = type; if((model->idx == model->history_item - 1)) { @@ -240,14 +248,29 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0); item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx); furi_string_set(str_buff, item_menu->item_str); - elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 7 : MAX_LEN_PX); + size_t scroll_counter = model->scroll_counter; if(model->idx == idx) { subghz_view_receiver_draw_frame(canvas, i, scrollbar); + if(scroll_counter < SCROLL_DELAY) { + // Show time of signal one moment + furi_string_set(str_buff, item_menu->time); + scroll_counter = 0; + } else { + scroll_counter -= SCROLL_DELAY; + } } else { canvas_set_color(canvas, ColorBlack); + scroll_counter = 0; } canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]); - canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buff)); + elements_scrollable_text_line( + canvas, + 15, + 9 + i * FRAME_HEIGHT, + (scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX), + str_buff, + scroll_counter, + (model->idx != idx)); furi_string_reset(str_buff); } if(scrollbar) { @@ -353,6 +376,13 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { } } +static void subghz_view_receiver_scroll_timer_callback(void* context) { + furi_assert(context); + SubGhzViewReceiver* subghz_receiver = context; + with_view_model( + subghz_receiver->view, SubGhzViewReceiverModel * model, { model->scroll_counter++; }, true); +} + static void subghz_view_receiver_timer_callback(void* context) { furi_assert(context); SubGhzViewReceiver* subghz_receiver = context; @@ -412,6 +442,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { SubGhzViewReceiverModel * model, { if(model->idx != 0) model->idx--; + model->scroll_counter = 0; }, true); } else if( @@ -423,6 +454,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { { if((model->history_item != 0) && (model->idx != model->history_item - 1)) model->idx++; + model->scroll_counter = 0; }, true); } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { @@ -442,6 +474,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { 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); } @@ -475,6 +508,13 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { void subghz_view_receiver_enter(void* context) { furi_assert(context); + SubGhzViewReceiver* subghz_receiver = context; + with_view_model( + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->scroll_counter = 0; }, + true); + furi_timer_start(subghz_receiver->scroll_timer, SCROLL_INTERVAL); } void subghz_view_receiver_exit(void* context) { @@ -491,6 +531,7 @@ void subghz_view_receiver_exit(void* context) { for M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { furi_string_free(item_menu->item_str); + furi_string_free(item_menu->time); item_menu->type = 0; } SubGhzReceiverMenuItemArray_reset(model->history->data); @@ -500,6 +541,7 @@ void subghz_view_receiver_exit(void* context) { }, false); furi_timer_stop(subghz_receiver->timer); + furi_timer_stop(subghz_receiver->scroll_timer); } SubGhzViewReceiver* subghz_view_receiver_alloc() { @@ -518,6 +560,9 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { view_set_enter_callback(subghz_receiver->view, subghz_view_receiver_enter); view_set_exit_callback(subghz_receiver->view, subghz_view_receiver_exit); + subghz_receiver->scroll_timer = furi_timer_alloc( + subghz_view_receiver_scroll_timer_callback, FuriTimerTypePeriodic, subghz_receiver); + with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -539,6 +584,8 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) { furi_assert(subghz_receiver); + furi_timer_free(subghz_receiver->scroll_timer); + with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -550,6 +597,7 @@ void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) { for M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { furi_string_free(item_menu->item_str); + furi_string_free(item_menu->time); item_menu->type = 0; } SubGhzReceiverMenuItemArray_clear(model->history->data); diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index ad8c31eda..f5ec86b4b 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -40,6 +40,7 @@ void subghz_view_receiver_add_data_progress( void subghz_view_receiver_add_item_to_menu( SubGhzViewReceiver* subghz_receiver, const char* name, + const char* time, uint8_t type); uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver);