1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 04:34:43 +04:00

[FL-3949] Universal IR signal selection (#4085)

* feat: universal ir signal selection
* fix: f18, format specifiers
* update labels with suggestions from the ui team

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Anna Antonenko
2025-02-20 03:58:55 +04:00
committed by GitHub
parent 93b0277938
commit 0f240c4dbc
17 changed files with 376 additions and 108 deletions

View File

@@ -2,26 +2,61 @@
#include <stdlib.h>
#include <m-dict.h>
#include <m-array.h>
#include <flipper_format/flipper_format.h>
#include "infrared_signal.h"
ARRAY_DEF(SignalPositionArray, size_t, M_DEFAULT_OPLIST);
typedef struct {
uint32_t index;
uint32_t count;
size_t index;
SignalPositionArray_t signals;
} InfraredBruteForceRecord;
static inline void ir_bf_record_init(InfraredBruteForceRecord* record) {
record->index = 0;
SignalPositionArray_init(record->signals);
}
#define IR_BF_RECORD_INIT(r) (ir_bf_record_init(&(r)))
static inline void
ir_bf_record_init_set(InfraredBruteForceRecord* dest, const InfraredBruteForceRecord* src) {
dest->index = src->index;
SignalPositionArray_init_set(dest->signals, src->signals);
}
#define IR_BF_RECORD_INIT_SET(d, s) (ir_bf_record_init_set(&(d), &(s)))
static inline void
ir_bf_record_set(InfraredBruteForceRecord* dest, const InfraredBruteForceRecord* src) {
dest->index = src->index;
SignalPositionArray_set(dest->signals, src->signals);
}
#define IR_BF_RECORD_SET(d, s) (ir_bf_record_set(&(d), &(s)))
static inline void ir_bf_record_clear(InfraredBruteForceRecord* record) {
SignalPositionArray_clear(record->signals);
}
#define IR_BF_RECORD_CLEAR(r) (ir_bf_record_clear(&(r)))
#define IR_BF_RECORD_OPLIST \
(INIT(IR_BF_RECORD_INIT), \
INIT_SET(IR_BF_RECORD_INIT_SET), \
SET(IR_BF_RECORD_SET), \
CLEAR(IR_BF_RECORD_CLEAR))
DICT_DEF2(
InfraredBruteForceRecordDict,
FuriString*,
FURI_STRING_OPLIST,
InfraredBruteForceRecord,
M_POD_OPLIST);
IR_BF_RECORD_OPLIST);
struct InfraredBruteForce {
FlipperFormat* ff;
const char* db_filename;
FuriString* current_record_name;
InfraredBruteForceRecord current_record;
InfraredSignal* current_signal;
InfraredBruteForceRecordDict_t records;
bool is_started;
@@ -39,6 +74,7 @@ InfraredBruteForce* infrared_brute_force_alloc(void) {
}
void infrared_brute_force_free(InfraredBruteForce* brute_force) {
furi_check(brute_force);
furi_assert(!brute_force->is_started);
InfraredBruteForceRecordDict_clear(brute_force->records);
furi_string_free(brute_force->current_record_name);
@@ -46,11 +82,13 @@ void infrared_brute_force_free(InfraredBruteForce* brute_force) {
}
void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename) {
furi_check(brute_force);
furi_assert(!brute_force->is_started);
brute_force->db_filename = db_filename;
}
InfraredErrorCode infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
furi_check(brute_force);
furi_assert(!brute_force->is_started);
furi_assert(brute_force->db_filename);
InfraredErrorCode error = InfraredErrorCodeNone;
@@ -66,19 +104,19 @@ InfraredErrorCode infrared_brute_force_calculate_messages(InfraredBruteForce* br
break;
}
bool signals_valid = false;
size_t signal_start = flipper_format_tell(ff);
bool signal_valid = false;
while(infrared_signal_read_name(ff, signal_name) == InfraredErrorCodeNone) {
error = infrared_signal_read_body(signal, ff);
signals_valid = (!INFRARED_ERROR_PRESENT(error)) && infrared_signal_is_valid(signal);
if(!signals_valid) break;
signal_valid = (!INFRARED_ERROR_PRESENT(error)) && infrared_signal_is_valid(signal);
if(!signal_valid) break;
InfraredBruteForceRecord* record =
InfraredBruteForceRecordDict_get(brute_force->records, signal_name);
if(record) { //-V547
++(record->count);
}
furi_assert(record);
SignalPositionArray_push_back(record->signals, signal_start);
}
if(!signals_valid) break;
if(!signal_valid) break;
} while(false);
infrared_signal_free(signal);
@@ -93,6 +131,7 @@ bool infrared_brute_force_start(
InfraredBruteForce* brute_force,
uint32_t index,
uint32_t* record_count) {
furi_check(brute_force);
furi_assert(!brute_force->is_started);
bool success = false;
*record_count = 0;
@@ -103,9 +142,10 @@ bool infrared_brute_force_start(
InfraredBruteForceRecordDict_next(it)) {
const InfraredBruteForceRecordDict_itref_t* record = InfraredBruteForceRecordDict_cref(it);
if(record->value.index == index) {
*record_count = record->value.count;
*record_count = SignalPositionArray_size(record->value.signals);
if(*record_count) {
furi_string_set(brute_force->current_record_name, record->key);
brute_force->current_record = record->value;
}
break;
}
@@ -124,10 +164,12 @@ bool infrared_brute_force_start(
}
bool infrared_brute_force_is_started(const InfraredBruteForce* brute_force) {
furi_check(brute_force);
return brute_force->is_started;
}
void infrared_brute_force_stop(InfraredBruteForce* brute_force) {
furi_check(brute_force);
furi_assert(brute_force->is_started);
furi_string_reset(brute_force->current_record_name);
infrared_signal_free(brute_force->current_signal);
@@ -138,25 +180,32 @@ void infrared_brute_force_stop(InfraredBruteForce* brute_force) {
furi_record_close(RECORD_STORAGE);
}
bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) {
bool infrared_brute_force_send(InfraredBruteForce* brute_force, uint32_t signal_index) {
furi_check(brute_force);
furi_assert(brute_force->is_started);
const bool success = infrared_signal_search_by_name_and_read(
brute_force->current_signal,
brute_force->ff,
furi_string_get_cstr(brute_force->current_record_name)) ==
InfraredErrorCodeNone;
if(success) {
infrared_signal_transmit(brute_force->current_signal);
}
return success;
if(signal_index >= SignalPositionArray_size(brute_force->current_record.signals)) return false;
size_t signal_start =
*SignalPositionArray_cget(brute_force->current_record.signals, signal_index);
if(!flipper_format_seek(brute_force->ff, signal_start, FlipperFormatOffsetFromStart))
return false;
if(INFRARED_ERROR_PRESENT(
infrared_signal_read_body(brute_force->current_signal, brute_force->ff)))
return false;
infrared_signal_transmit(brute_force->current_signal);
return true;
}
void infrared_brute_force_add_record(
InfraredBruteForce* brute_force,
uint32_t index,
const char* name) {
InfraredBruteForceRecord value = {.index = index, .count = 0};
InfraredBruteForceRecord value;
ir_bf_record_init(&value);
value.index = index;
FuriString* key;
key = furi_string_alloc_set(name);
InfraredBruteForceRecordDict_set_at(brute_force->records, key, value);

View File

@@ -78,18 +78,16 @@ bool infrared_brute_force_is_started(const InfraredBruteForce* brute_force);
void infrared_brute_force_stop(InfraredBruteForce* brute_force);
/**
* @brief Send the next signal from the chosen category.
*
* This function is called repeatedly until no more signals are left
* in the chosen signal category.
*
* @warning Transmission must be started first by calling infrared_brute_force_start()
* before calling this function.
*
* @param[in,out] brute_force pointer to the instance to be used.
* @returns true if the next signal existed and could be transmitted, false otherwise.
* @brief Send an arbitrary signal from the chosen category.
*
* @param[in] brute_force pointer to the instance
* @param signal_index the index of the signal within the category, must be
* between 0 and `record_count` as told by
* `infrared_brute_force_start`
*
* @returns true on success, false otherwise
*/
bool infrared_brute_force_send_next(InfraredBruteForce* brute_force);
bool infrared_brute_force_send(InfraredBruteForce* brute_force, uint32_t signal_index);
/**
* @brief Add a signal category to an InfraredBruteForce instance's dictionary.

View File

@@ -475,25 +475,24 @@ static void
break;
}
uint32_t record_count;
uint32_t signal_count, current_signal = 0;
bool running = infrared_brute_force_start(
brute_force, INFRARED_BRUTE_FORCE_DUMMY_INDEX, &record_count);
brute_force, INFRARED_BRUTE_FORCE_DUMMY_INDEX, &signal_count);
if(record_count <= 0) {
if(signal_count <= 0) {
printf("Invalid signal name.\r\n");
break;
}
printf("Sending %lu signal(s)...\r\n", record_count);
printf("Sending %lu signal(s)...\r\n", signal_count);
printf("Press Ctrl-C to stop.\r\n");
int records_sent = 0;
while(running) {
running = infrared_brute_force_send_next(brute_force);
running = infrared_brute_force_send(brute_force, current_signal);
if(cli_cmd_interrupt_received(cli)) break;
printf("\r%d%% complete.", (int)((float)records_sent++ / (float)record_count * 100));
printf("\r%d%% complete.", (int)((float)current_signal++ / (float)signal_count * 100));
fflush(stdout);
}

View File

@@ -3,7 +3,7 @@
#include <stdint.h>
#include <stddef.h>
enum InfraredCustomEventType {
typedef enum {
// Reserve first 100 events for button types and indexes, starting from 0
InfraredCustomEventTypeReserved = 100,
InfraredCustomEventTypeMenuSelected,
@@ -13,7 +13,7 @@ enum InfraredCustomEventType {
InfraredCustomEventTypeTextEditDone,
InfraredCustomEventTypePopupClosed,
InfraredCustomEventTypeButtonSelected,
InfraredCustomEventTypeBackPressed,
InfraredCustomEventTypePopupInput,
InfraredCustomEventTypeTaskFinished,
InfraredCustomEventTypeRpcLoadFile,
@@ -27,7 +27,7 @@ enum InfraredCustomEventType {
InfraredCustomEventTypeGpioTxPinChanged,
InfraredCustomEventTypeGpioOtgChanged,
};
} InfraredCustomEventType;
#pragma pack(push, 1)
typedef union {

View File

@@ -2,15 +2,28 @@
#include <dolphin/dolphin.h>
#pragma pack(push, 1)
typedef union {
uint32_t packed_value;
struct {
bool is_paused;
uint8_t padding;
uint16_t signal_index;
};
} InfraredSceneState;
#pragma pack(pop)
void infrared_scene_universal_common_item_callback(void* context, uint32_t index) {
InfraredApp* infrared = context;
uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeButtonSelected, index);
view_dispatcher_send_custom_event(infrared->view_dispatcher, event);
}
static void infrared_scene_universal_common_progress_back_callback(void* context) {
static void infrared_scene_universal_common_progress_input_callback(
void* context,
InfraredProgressViewInput input) {
InfraredApp* infrared = context;
uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeBackPressed, -1);
uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypePopupInput, input);
view_dispatcher_send_custom_event(infrared->view_dispatcher, event);
}
@@ -19,8 +32,8 @@ static void
ViewStack* view_stack = infrared->view_stack;
InfraredProgressView* progress = infrared->progress;
infrared_progress_view_set_progress_total(progress, record_count);
infrared_progress_view_set_back_callback(
progress, infrared_scene_universal_common_progress_back_callback, infrared);
infrared_progress_view_set_input_callback(
progress, infrared_scene_universal_common_progress_input_callback, infrared);
view_stack_add_view(view_stack, infrared_progress_view_get_view(progress));
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
}
@@ -51,29 +64,111 @@ void infrared_scene_universal_common_on_enter(void* context) {
infrared_blocking_task_start(infrared, infrared_scene_universal_common_task_callback);
}
static void infrared_scene_universal_common_handle_popup_input(
InfraredApp* infrared,
InfraredProgressViewInput input) {
InfraredBruteForce* brute_force = infrared->brute_force;
SceneManager* scene_manager = infrared->scene_manager;
uint32_t scene_id = scene_manager_get_current_scene(infrared->scene_manager);
switch(input) {
case InfraredProgressViewInputStop: {
infrared_brute_force_stop(brute_force);
infrared_scene_universal_common_hide_popup(infrared);
break;
}
case InfraredProgressViewInputPause: {
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
infrared_progress_view_set_paused(infrared->progress, true);
InfraredSceneState scene_state = {
.packed_value = scene_manager_get_scene_state(scene_manager, scene_id)};
scene_state.is_paused = true;
if(scene_state.signal_index)
scene_state.signal_index--; // when running, the state stores the next index
scene_manager_set_scene_state(scene_manager, scene_id, scene_state.packed_value);
break;
}
case InfraredProgressViewInputResume: {
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
infrared_progress_view_set_paused(infrared->progress, false);
InfraredSceneState scene_state = {
.packed_value = scene_manager_get_scene_state(scene_manager, scene_id)};
scene_state.is_paused = false;
scene_manager_set_scene_state(scene_manager, scene_id, scene_state.packed_value);
break;
}
case InfraredProgressViewInputNextSignal: {
InfraredSceneState scene_state = {
.packed_value = scene_manager_get_scene_state(scene_manager, scene_id)};
scene_state.signal_index++;
if(infrared_progress_view_set_progress(infrared->progress, scene_state.signal_index + 1))
scene_manager_set_scene_state(scene_manager, scene_id, scene_state.packed_value);
break;
}
case InfraredProgressViewInputPreviousSignal: {
InfraredSceneState scene_state = {
.packed_value = scene_manager_get_scene_state(scene_manager, scene_id)};
if(scene_state.signal_index) {
scene_state.signal_index--;
if(infrared_progress_view_set_progress(
infrared->progress, scene_state.signal_index + 1))
scene_manager_set_scene_state(scene_manager, scene_id, scene_state.packed_value);
}
break;
}
case InfraredProgressViewInputSendSingle: {
InfraredSceneState scene_state = {
.packed_value = scene_manager_get_scene_state(scene_manager, scene_id)};
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
infrared_brute_force_send(infrared->brute_force, scene_state.signal_index);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
break;
}
default:
furi_crash();
}
}
bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent event) {
InfraredApp* infrared = context;
SceneManager* scene_manager = infrared->scene_manager;
InfraredBruteForce* brute_force = infrared->brute_force;
uint32_t scene_id = scene_manager_get_current_scene(infrared->scene_manager);
bool consumed = false;
if(infrared_brute_force_is_started(brute_force)) {
if(event.type == SceneManagerEventTypeTick) {
bool success = infrared_brute_force_send_next(brute_force);
if(success) {
success = infrared_progress_view_increase_progress(infrared->progress);
InfraredSceneState scene_state = {
.packed_value = scene_manager_get_scene_state(scene_manager, scene_id)};
if(!scene_state.is_paused) {
bool success = infrared_brute_force_send(brute_force, scene_state.signal_index);
if(success) {
success = infrared_progress_view_set_progress(
infrared->progress, scene_state.signal_index + 1);
scene_state.signal_index++;
scene_manager_set_scene_state(
scene_manager, scene_id, scene_state.packed_value);
}
if(!success) {
infrared_brute_force_stop(brute_force);
infrared_scene_universal_common_hide_popup(infrared);
}
consumed = true;
}
if(!success) {
infrared_brute_force_stop(brute_force);
infrared_scene_universal_common_hide_popup(infrared);
}
consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) {
if(infrared_custom_event_get_type(event.event) == InfraredCustomEventTypeBackPressed) {
infrared_brute_force_stop(brute_force);
infrared_scene_universal_common_hide_popup(infrared);
uint16_t event_type;
int16_t event_value;
infrared_custom_event_unpack(event.event, &event_type, &event_value);
if(event_type == InfraredCustomEventTypePopupInput) {
infrared_scene_universal_common_handle_popup_input(infrared, event_value);
consumed = true;
}
consumed = true;
}
} else {
if(event.type == SceneManagerEventTypeBack) {
@@ -87,6 +182,7 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e
if(event_type == InfraredCustomEventTypeButtonSelected) {
uint32_t record_count;
if(infrared_brute_force_start(brute_force, event_value, &record_count)) {
scene_manager_set_scene_state(infrared->scene_manager, scene_id, 0);
dolphin_deed(DolphinDeedIrSend);
infrared_scene_universal_common_show_popup(infrared, record_count);
} else {

View File

@@ -118,7 +118,7 @@ void infrared_scene_universal_ac_on_enter(void* context) {
button_panel_add_icon(button_panel, 0, 60, &I_cool_30x51);
button_panel_add_icon(button_panel, 34, 60, &I_heat_30x51);
button_panel_add_label(button_panel, 4, 10, FontPrimary, "AC remote");
button_panel_add_label(button_panel, 24, 10, FontPrimary, "AC");
infrared_scene_universal_common_on_enter(context);
}

View File

@@ -114,7 +114,7 @@ void infrared_scene_universal_audio_on_enter(void* context) {
context);
infrared_brute_force_add_record(brute_force, i++, "Vol_up");
button_panel_add_label(button_panel, 1, 10, FontPrimary, "Mus. remote");
button_panel_add_label(button_panel, 1, 10, FontPrimary, "Audio player");
button_panel_add_icon(button_panel, 34, 56, &I_vol_ac_text_30x30);
infrared_scene_universal_common_on_enter(context);

View File

@@ -63,7 +63,7 @@ void infrared_scene_universal_projector_on_enter(void* context) {
context);
infrared_brute_force_add_record(brute_force, i++, "Vol_dn");
button_panel_add_label(button_panel, 3, 11, FontPrimary, "Proj. remote");
button_panel_add_label(button_panel, 10, 11, FontPrimary, "Projector");
button_panel_add_icon(button_panel, 17, 72, &I_vol_ac_text_30x30);
infrared_scene_universal_common_on_enter(context);

View File

@@ -91,7 +91,7 @@ void infrared_scene_universal_tv_on_enter(void* context) {
context);
infrared_brute_force_add_record(brute_force, i++, "Ch_prev");
button_panel_add_label(button_panel, 5, 10, FontPrimary, "TV remote");
button_panel_add_label(button_panel, 25, 10, FontPrimary, "TV");
infrared_scene_universal_common_on_enter(context);
}

View File

@@ -14,54 +14,80 @@
struct InfraredProgressView {
View* view;
InfraredProgressViewBackCallback back_callback;
InfraredProgressViewInputCallback input_callback;
void* context;
};
typedef struct {
size_t progress;
size_t progress_total;
bool is_paused;
} InfraredProgressViewModel;
bool infrared_progress_view_increase_progress(InfraredProgressView* progress) {
furi_assert(progress);
bool result = false;
InfraredProgressViewModel* model = view_get_model(progress->view);
if(model->progress < model->progress_total) {
++model->progress;
result = model->progress < model->progress_total;
}
view_commit_model(progress->view, true);
return result;
}
static void infrared_progress_view_draw_callback(Canvas* canvas, void* _model) {
InfraredProgressViewModel* model = (InfraredProgressViewModel*)_model;
uint8_t x = 0;
uint8_t y = 36;
uint8_t y = 25;
uint8_t width = 63;
uint8_t height = 59;
uint8_t height = 81;
elements_bold_rounded_frame(canvas, x, y, width, height);
canvas_set_font(canvas, FontSecondary);
elements_multiline_text_aligned(
canvas, x + 34, y + 9, AlignCenter, AlignCenter, "Sending ...");
canvas,
x + 32,
y + 9,
AlignCenter,
AlignCenter,
model->is_paused ? "Paused" : "Sending...");
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 progress_string[16] = {0};
if(model->is_paused) {
snprintf(
progress_string,
sizeof(progress_string),
"%zu/%zu",
model->progress,
model->progress_total);
} else {
uint8_t percent_value = 100 * model->progress / model->progress_total;
snprintf(progress_string, sizeof(progress_string), "%d%%", percent_value);
}
elements_multiline_text_aligned(
canvas, x + 33, y + 37, AlignCenter, AlignCenter, percents_string);
canvas, x + 33, y + 37, AlignCenter, AlignCenter, progress_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");
uint8_t buttons_x = x + (model->is_paused ? 10 : 14);
uint8_t buttons_y = y + (model->is_paused ? 46 : 50);
canvas_draw_icon(canvas, buttons_x + 0, buttons_y + 0, &I_Pin_back_arrow_10x8);
canvas_draw_str(canvas, buttons_x + 14, buttons_y + 8, model->is_paused ? "resume" : "stop");
canvas_draw_icon(canvas, buttons_x + 1, buttons_y + 10, &I_Ok_btn_9x9);
canvas_draw_str(canvas, buttons_x + 14, buttons_y + 17, model->is_paused ? "send 1" : "pause");
if(model->is_paused) {
canvas_draw_icon(canvas, buttons_x + 2, buttons_y + 21, &I_ButtonLeftSmall_3x5);
canvas_draw_icon(canvas, buttons_x + 7, buttons_y + 21, &I_ButtonRightSmall_3x5);
canvas_draw_str(canvas, buttons_x + 14, buttons_y + 26, "select");
}
}
bool infrared_progress_view_set_progress(InfraredProgressView* instance, uint16_t progress) {
bool result;
with_view_model(
instance->view,
InfraredProgressViewModel * model,
{
result = progress <= model->progress_total;
if(result) model->progress = progress;
},
true);
return result;
}
void infrared_progress_view_set_progress_total(
@@ -74,14 +100,40 @@ void infrared_progress_view_set_progress_total(
view_commit_model(progress->view, false);
}
void infrared_progress_view_set_paused(InfraredProgressView* instance, bool is_paused) {
with_view_model(
instance->view, InfraredProgressViewModel * model, { model->is_paused = is_paused; }, true);
}
bool infrared_progress_view_input_callback(InputEvent* event, void* context) {
InfraredProgressView* instance = context;
if(event->type != InputTypeShort && event->type != InputTypeRepeat) return false;
if(!instance->input_callback) return false;
if((event->type == InputTypeShort) && (event->key == InputKeyBack)) {
if(instance->back_callback) {
instance->back_callback(instance->context);
}
}
with_view_model(
instance->view,
InfraredProgressViewModel * model,
{
if(model->is_paused) {
if(event->key == InputKeyLeft)
instance->input_callback(
instance->context, InfraredProgressViewInputPreviousSignal);
else if(event->key == InputKeyRight)
instance->input_callback(
instance->context, InfraredProgressViewInputNextSignal);
else if(event->key == InputKeyOk)
instance->input_callback(
instance->context, InfraredProgressViewInputSendSingle);
else if(event->key == InputKeyBack)
instance->input_callback(instance->context, InfraredProgressViewInputResume);
} else {
if(event->key == InputKeyOk)
instance->input_callback(instance->context, InfraredProgressViewInputPause);
else if(event->key == InputKeyBack)
instance->input_callback(instance->context, InfraredProgressViewInputStop);
}
},
false);
return true;
}
@@ -106,12 +158,12 @@ void infrared_progress_view_free(InfraredProgressView* progress) {
free(progress);
}
void infrared_progress_view_set_back_callback(
void infrared_progress_view_set_input_callback(
InfraredProgressView* instance,
InfraredProgressViewBackCallback callback,
InfraredProgressViewInputCallback callback,
void* context) {
furi_assert(instance);
instance->back_callback = callback;
instance->input_callback = callback;
instance->context = context;
}

View File

@@ -10,11 +10,20 @@
extern "C" {
#endif
/** Anonumous instance */
/** Anonymous instance */
typedef struct InfraredProgressView InfraredProgressView;
/** Callback for back button handling */
typedef void (*InfraredProgressViewBackCallback)(void*);
typedef enum {
InfraredProgressViewInputStop,
InfraredProgressViewInputPause,
InfraredProgressViewInputResume,
InfraredProgressViewInputPreviousSignal,
InfraredProgressViewInputNextSignal,
InfraredProgressViewInputSendSingle,
} InfraredProgressViewInput;
/** Callback for input handling */
typedef void (*InfraredProgressViewInputCallback)(void* context, InfraredProgressViewInput event);
/** Allocate and initialize Infrared view
*
@@ -35,13 +44,12 @@ void infrared_progress_view_free(InfraredProgressView* instance);
*/
View* infrared_progress_view_get_view(InfraredProgressView* instance);
/** Increase progress on progress view module
/** Set progress of progress view module
*
* @param instance view module
* @retval true - value is incremented and maximum is reached,
* false - value is incremented and maximum is not reached
* @param progress progress value
*/
bool infrared_progress_view_increase_progress(InfraredProgressView* instance);
bool infrared_progress_view_set_progress(InfraredProgressView* instance, uint16_t progress);
/** Set maximum progress value
*
@@ -52,15 +60,22 @@ void infrared_progress_view_set_progress_total(
InfraredProgressView* instance,
uint16_t progress_max);
/** Set back button callback
/** Selects the variant of the View
*
* @param instance view instance
* @param is_paused the "paused" variant is displayed if true; the "sending" one if false
*/
void infrared_progress_view_set_paused(InfraredProgressView* instance, bool is_paused);
/** Set input callback
*
* @param instance - view module
* @param callback - callback to call for back button
* @param callback - callback to call for input
* @param context - context to pass to callback
*/
void infrared_progress_view_set_back_callback(
void infrared_progress_view_set_input_callback(
InfraredProgressView* instance,
InfraredProgressViewBackCallback callback,
InfraredProgressViewInputCallback callback,
void* context);
#ifdef __cplusplus

View File

@@ -230,6 +230,11 @@ bool scene_manager_search_and_switch_to_another_scene(
}
}
uint32_t scene_manager_get_current_scene(SceneManager* scene_manager) {
furi_check(scene_manager);
return *SceneManagerIdStack_back(scene_manager->scene_id_stack);
}
void scene_manager_stop(SceneManager* scene_manager) {
furi_check(scene_manager);

View File

@@ -170,6 +170,14 @@ bool scene_manager_search_and_switch_to_another_scene(
SceneManager* scene_manager,
uint32_t scene_id);
/** Get id of current scene
*
* @param scene_manager SceneManager instance
*
* @return Scene ID
*/
uint32_t scene_manager_get_current_scene(SceneManager* scene_manager);
/** Exit from current scene
*
* @param scene_manager SceneManager instance

View File

@@ -8,6 +8,11 @@
#include "flipper_format_stream.h"
#include "flipper_format_stream_i.h"
// permits direct casting between `FlipperFormatOffset` and `StreamOffset`
static_assert((size_t)FlipperFormatOffsetFromCurrent == (size_t)StreamOffsetFromCurrent);
static_assert((size_t)FlipperFormatOffsetFromStart == (size_t)StreamOffsetFromStart);
static_assert((size_t)FlipperFormatOffsetFromEnd == (size_t)StreamOffsetFromEnd);
/********************************** Private **********************************/
struct FlipperFormat {
Stream* stream;
@@ -127,6 +132,17 @@ bool flipper_format_rewind(FlipperFormat* flipper_format) {
return stream_rewind(flipper_format->stream);
}
size_t flipper_format_tell(FlipperFormat* flipper_format) {
furi_check(flipper_format);
return stream_tell(flipper_format->stream);
}
bool flipper_format_seek(FlipperFormat* flipper_format, int32_t offset, FlipperFormatOffset anchor) {
furi_check(flipper_format);
// direct usage of `anchor` made valid by `static_assert`s at the top of this file
return stream_seek(flipper_format->stream, offset, (StreamOffset)anchor);
}
bool flipper_format_seek_to_end(FlipperFormat* flipper_format) {
furi_check(flipper_format);
return stream_seek(flipper_format->stream, 0, StreamOffsetFromEnd);

View File

@@ -94,6 +94,12 @@ extern "C" {
typedef struct FlipperFormat FlipperFormat;
typedef enum {
FlipperFormatOffsetFromCurrent,
FlipperFormatOffsetFromStart,
FlipperFormatOffsetFromEnd,
} FlipperFormatOffset;
/** Allocate FlipperFormat as string.
*
* @return FlipperFormat* pointer to a FlipperFormat instance
@@ -216,6 +222,24 @@ void flipper_format_set_strict_mode(FlipperFormat* flipper_format, bool strict_m
*/
bool flipper_format_rewind(FlipperFormat* flipper_format);
/** Get the RW pointer position
*
* @param flipper_format Pointer to a FlipperFormat instance
*
* @return RW pointer position
*/
size_t flipper_format_tell(FlipperFormat* flipper_format);
/** Set the RW pointer position to an arbitrary value
*
* @param flipper_format Pointer to a FlipperFormat instance
* @param offset Offset relative to the anchor point
* @param anchor Anchor point (e.g. start of file)
*
* @return True on success
*/
bool flipper_format_seek(FlipperFormat* flipper_format, int32_t offset, FlipperFormatOffset anchor);
/** Move the RW pointer at the end. Can be useful if you want to add some data
* after reading.
*

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,80.1,,
Version,+,80.2,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Header,+,applications/services/cli/cli.h,,
@@ -1038,6 +1038,7 @@ Function,+,flipper_format_read_int32,_Bool,"FlipperFormat*, const char*, int32_t
Function,+,flipper_format_read_string,_Bool,"FlipperFormat*, const char*, FuriString*"
Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32_t*, const uint16_t"
Function,+,flipper_format_rewind,_Bool,FlipperFormat*
Function,+,flipper_format_seek,_Bool,"FlipperFormat*, int32_t, FlipperFormatOffset"
Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat*
Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool"
Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool"
@@ -1046,6 +1047,7 @@ Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, Fl
Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*"
Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*"
Function,+,flipper_format_string_alloc,FlipperFormat*,
Function,+,flipper_format_tell,size_t,FlipperFormat*
Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t"
Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t"
Function,+,flipper_format_update_hex,_Bool,"FlipperFormat*, const char*, const uint8_t*, const uint16_t"
@@ -2468,6 +2470,7 @@ Function,-,scalbnl,long double,"long double, int"
Function,-,scanf,int,"const char*, ..."
Function,+,scene_manager_alloc,SceneManager*,"const SceneManagerHandlers*, void*"
Function,+,scene_manager_free,void,SceneManager*
Function,+,scene_manager_get_current_scene,uint32_t,SceneManager*
Function,+,scene_manager_get_scene_state,uint32_t,"const SceneManager*, uint32_t"
Function,+,scene_manager_handle_back_event,_Bool,SceneManager*
Function,+,scene_manager_handle_custom_event,_Bool,"SceneManager*, uint32_t"
1 entry status name type params
2 Version + 80.1 80.2
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/bt/bt_service/bt_keys_storage.h
5 Header + applications/services/cli/cli.h
1038 Function + flipper_format_read_string _Bool FlipperFormat*, const char*, FuriString*
1039 Function + flipper_format_read_uint32 _Bool FlipperFormat*, const char*, uint32_t*, const uint16_t
1040 Function + flipper_format_rewind _Bool FlipperFormat*
1041 Function + flipper_format_seek _Bool FlipperFormat*, int32_t, FlipperFormatOffset
1042 Function + flipper_format_seek_to_end _Bool FlipperFormat*
1043 Function + flipper_format_set_strict_mode void FlipperFormat*, _Bool
1044 Function + flipper_format_stream_delete_key_and_write _Bool Stream*, FlipperStreamWriteData*, _Bool
1047 Function + flipper_format_stream_write_comment_cstr _Bool Stream*, const char*
1048 Function + flipper_format_stream_write_value_line _Bool Stream*, FlipperStreamWriteData*
1049 Function + flipper_format_string_alloc FlipperFormat*
1050 Function + flipper_format_tell size_t FlipperFormat*
1051 Function + flipper_format_update_bool _Bool FlipperFormat*, const char*, const _Bool*, const uint16_t
1052 Function + flipper_format_update_float _Bool FlipperFormat*, const char*, const float*, const uint16_t
1053 Function + flipper_format_update_hex _Bool FlipperFormat*, const char*, const uint8_t*, const uint16_t
2470 Function - scanf int const char*, ...
2471 Function + scene_manager_alloc SceneManager* const SceneManagerHandlers*, void*
2472 Function + scene_manager_free void SceneManager*
2473 Function + scene_manager_get_current_scene uint32_t SceneManager*
2474 Function + scene_manager_get_scene_state uint32_t const SceneManager*, uint32_t
2475 Function + scene_manager_handle_back_event _Bool SceneManager*
2476 Function + scene_manager_handle_custom_event _Bool SceneManager*, uint32_t

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,80.1,,
Version,+,80.2,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
@@ -1149,6 +1149,7 @@ Function,+,flipper_format_read_int32,_Bool,"FlipperFormat*, const char*, int32_t
Function,+,flipper_format_read_string,_Bool,"FlipperFormat*, const char*, FuriString*"
Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32_t*, const uint16_t"
Function,+,flipper_format_rewind,_Bool,FlipperFormat*
Function,+,flipper_format_seek,_Bool,"FlipperFormat*, int32_t, FlipperFormatOffset"
Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat*
Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool"
Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool"
@@ -1157,6 +1158,7 @@ Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, Fl
Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*"
Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*"
Function,+,flipper_format_string_alloc,FlipperFormat*,
Function,+,flipper_format_tell,size_t,FlipperFormat*
Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t"
Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t"
Function,+,flipper_format_update_hex,_Bool,"FlipperFormat*, const char*, const uint8_t*, const uint16_t"
@@ -3105,6 +3107,7 @@ Function,-,scalbnl,long double,"long double, int"
Function,-,scanf,int,"const char*, ..."
Function,+,scene_manager_alloc,SceneManager*,"const SceneManagerHandlers*, void*"
Function,+,scene_manager_free,void,SceneManager*
Function,+,scene_manager_get_current_scene,uint32_t,SceneManager*
Function,+,scene_manager_get_scene_state,uint32_t,"const SceneManager*, uint32_t"
Function,+,scene_manager_handle_back_event,_Bool,SceneManager*
Function,+,scene_manager_handle_custom_event,_Bool,"SceneManager*, uint32_t"
1 entry status name type params
2 Version + 80.1 80.2
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/bt/bt_service/bt_keys_storage.h
1149 Function + flipper_format_read_string _Bool FlipperFormat*, const char*, FuriString*
1150 Function + flipper_format_read_uint32 _Bool FlipperFormat*, const char*, uint32_t*, const uint16_t
1151 Function + flipper_format_rewind _Bool FlipperFormat*
1152 Function + flipper_format_seek _Bool FlipperFormat*, int32_t, FlipperFormatOffset
1153 Function + flipper_format_seek_to_end _Bool FlipperFormat*
1154 Function + flipper_format_set_strict_mode void FlipperFormat*, _Bool
1155 Function + flipper_format_stream_delete_key_and_write _Bool Stream*, FlipperStreamWriteData*, _Bool
1158 Function + flipper_format_stream_write_comment_cstr _Bool Stream*, const char*
1159 Function + flipper_format_stream_write_value_line _Bool Stream*, FlipperStreamWriteData*
1160 Function + flipper_format_string_alloc FlipperFormat*
1161 Function + flipper_format_tell size_t FlipperFormat*
1162 Function + flipper_format_update_bool _Bool FlipperFormat*, const char*, const _Bool*, const uint16_t
1163 Function + flipper_format_update_float _Bool FlipperFormat*, const char*, const float*, const uint16_t
1164 Function + flipper_format_update_hex _Bool FlipperFormat*, const char*, const uint8_t*, const uint16_t
3107 Function - scanf int const char*, ...
3108 Function + scene_manager_alloc SceneManager* const SceneManagerHandlers*, void*
3109 Function + scene_manager_free void SceneManager*
3110 Function + scene_manager_get_current_scene uint32_t SceneManager*
3111 Function + scene_manager_get_scene_state uint32_t const SceneManager*, uint32_t
3112 Function + scene_manager_handle_back_event _Bool SceneManager*
3113 Function + scene_manager_handle_custom_event _Bool SceneManager*, uint32_t