Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…irmware into mntm-dev
  • Loading branch information
Willy-JL committed Mar 12, 2024
2 parents d947fa7 + 022fccf commit 3ade3f0
Show file tree
Hide file tree
Showing 20 changed files with 294 additions and 251 deletions.
20 changes: 18 additions & 2 deletions applications/debug/unit_tests/datetimelib/datetimelib_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ MU_TEST_SUITE(test_datetime_validate_datetime) {

MU_TEST(test_datetime_timestamp_to_datetime_min) {
uint32_t test_value = 0;
DateTime min_datetime_expected = {0, 0, 0, 1, 1, 1970, 0};
DateTime min_datetime_expected = {0, 0, 0, 1, 1, 1970, 4};

DateTime result = {0};
datetime_timestamp_to_datetime(test_value, &result);
Expand All @@ -122,7 +122,7 @@ MU_TEST(test_datetime_timestamp_to_datetime_min) {

MU_TEST(test_datetime_timestamp_to_datetime_max) {
uint32_t test_value = UINT32_MAX;
DateTime max_datetime_expected = {6, 28, 15, 7, 2, 2106, 0};
DateTime max_datetime_expected = {6, 28, 15, 7, 2, 2106, 7};

DateTime result = {0};
datetime_timestamp_to_datetime(test_value, &result);
Expand All @@ -141,10 +141,26 @@ MU_TEST(test_datetime_timestamp_to_datetime_to_timestamp) {
mu_assert_int_eq(test_value, result);
}

MU_TEST(test_datetime_timestamp_to_datetime_weekday) {
uint32_t test_value = 1709748421; // Wed Mar 06 18:07:01 2024 UTC

DateTime datetime = {0};
datetime_timestamp_to_datetime(test_value, &datetime);

mu_assert_int_eq(datetime.hour, 18);
mu_assert_int_eq(datetime.minute, 7);
mu_assert_int_eq(datetime.second, 1);
mu_assert_int_eq(datetime.day, 6);
mu_assert_int_eq(datetime.month, 3);
mu_assert_int_eq(datetime.weekday, 3);
mu_assert_int_eq(datetime.year, 2024);
}

MU_TEST_SUITE(test_datetime_timestamp_to_datetime_suite) {
MU_RUN_TEST(test_datetime_timestamp_to_datetime_min);
MU_RUN_TEST(test_datetime_timestamp_to_datetime_max);
MU_RUN_TEST(test_datetime_timestamp_to_datetime_to_timestamp);
MU_RUN_TEST(test_datetime_timestamp_to_datetime_weekday);
}

MU_TEST(test_datetime_datetime_to_timestamp_min) {
Expand Down
36 changes: 20 additions & 16 deletions applications/main/infrared/infrared_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

#define TAG "InfraredApp"

#define INFRARED_TX_MIN_INTERVAL_MS 50U
#define INFRARED_TX_MIN_INTERVAL_MS (50U)
#define INFRARED_TASK_STACK_SIZE (2048UL)

static const NotificationSequence*
infrared_notification_sequences[InfraredNotificationMessageCount] = {
Expand Down Expand Up @@ -128,6 +129,8 @@ static void infrared_find_vacant_remote_name(FuriString* name, const char* path)
static InfraredApp* infrared_alloc() {
InfraredApp* infrared = malloc(sizeof(InfraredApp));

infrared->task_thread =
furi_thread_alloc_ex("InfraredTask", INFRARED_TASK_STACK_SIZE, NULL, infrared);
infrared->file_path = furi_string_alloc();
infrared->button_name = furi_string_alloc();

Expand Down Expand Up @@ -213,6 +216,10 @@ static InfraredApp* infrared_alloc() {

static void infrared_free(InfraredApp* infrared) {
furi_assert(infrared);

furi_thread_join(infrared->task_thread);
furi_thread_free(infrared->task_thread);

ViewDispatcher* view_dispatcher = infrared->view_dispatcher;
InfraredAppState* app_state = &infrared->app_state;

Expand Down Expand Up @@ -393,6 +400,18 @@ void infrared_tx_stop(InfraredApp* infrared) {
infrared->app_state.last_transmit_time = furi_get_tick();
}

void infrared_blocking_task_start(InfraredApp* infrared, FuriThreadCallback callback) {
view_stack_add_view(infrared->view_stack, loading_get_view(infrared->loading));
furi_thread_set_callback(infrared->task_thread, callback);
furi_thread_start(infrared->task_thread);
}

bool infrared_blocking_task_finalize(InfraredApp* infrared) {
furi_thread_join(infrared->task_thread);
view_stack_remove_view(infrared->view_stack, loading_get_view(infrared->loading));
return furi_thread_get_return_code(infrared->task_thread);
}

void infrared_text_store_set(InfraredApp* infrared, uint32_t bank, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
Expand All @@ -413,21 +432,6 @@ void infrared_play_notification_message(
notification_message(infrared->notifications, infrared_notification_sequences[message]);
}

void infrared_show_loading_popup(const InfraredApp* infrared, bool show) {
ViewStack* view_stack = infrared->view_stack;
Loading* loading = infrared->loading;

if(show) {
// Raise timer priority so that animations can play
furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
view_stack_add_view(view_stack, loading_get_view(loading));
} else {
view_stack_remove_view(view_stack, loading_get_view(loading));
// Restore default timer priority
furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal);
}
}

void infrared_show_error_message(const InfraredApp* infrared, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
Expand Down
40 changes: 25 additions & 15 deletions applications/main/infrared/infrared_app_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
#include <gui/modules/button_panel.h>
#include <gui/modules/variable_item_list.h>

#include <rpc/rpc_app.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>

#include <notification/notification_messages.h>

#include <infrared_worker.h>
#include <infrared/worker/infrared_worker.h>

#include "infrared_app.h"
#include "infrared_remote.h"
Expand All @@ -38,9 +39,6 @@
#include "views/infrared_debug_view.h"
#include "views/infrared_move_view.h"

#include "rpc/rpc_app.h"
#include <furi_hal_infrared.h>

#define INFRARED_FILE_NAME_SIZE 100
#define INFRARED_TEXT_STORE_NUM 2
#define INFRARED_TEXT_STORE_SIZE 128
Expand Down Expand Up @@ -124,6 +122,7 @@ struct InfraredApp {
Loading* loading; /**< Standard view for informing about long operations. */
InfraredProgressView* progress; /**< Custom view for showing brute force progress. */

FuriThread* task_thread; /**< Pointer to a FuriThread instance for concurrent tasks. */
FuriString* file_path; /**< Full path to the currently loaded file. */
FuriString* button_name; /**< Name of the button requested in RPC mode. */
/** Arbitrary text storage for various inputs. */
Expand Down Expand Up @@ -216,6 +215,28 @@ void infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index);
*/
void infrared_tx_stop(InfraredApp* infrared);

/**
* @brief Start a blocking task in a separate thread.
*
* If a ViewStack is currently on screen, a busy "Hourglass" animation
* will be shown and no input will be accepted until completion.
*
* @param[in,out] infrared pointer to the application instance.
* @param[in] callback pointer to the function to be run in the thread.
*/
void infrared_blocking_task_start(InfraredApp* infrared, FuriThreadCallback callback);

/**
* @brief Wait for a blocking task to finish and receive the result.
*
* Upon the completion of a blocking task, the busy animation will be hidden
* and input will be accepted again.
*
* @param[in,out] infrared pointer to the application instance.
* @return true if the blocking task finished successfully, false otherwise.
*/
bool infrared_blocking_task_finalize(InfraredApp* infrared);

/**
* @brief Set the internal text store with formatted text.
*
Expand Down Expand Up @@ -245,17 +266,6 @@ void infrared_play_notification_message(
const InfraredApp* infrared,
InfraredNotificationMessage message);

/**
* @brief Show a loading pop-up screen.
*
* In order for this to work, a Stack view must be currently active and
* the main view must be added to it.
*
* @param[in] infrared pointer to the application instance.
* @param[in] show whether to show or hide the pop-up.
*/
void infrared_show_loading_popup(const InfraredApp* infrared, bool show);

/**
* @brief Show a formatted error messsage.
*
Expand Down
1 change: 1 addition & 0 deletions applications/main/infrared/infrared_custom_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum InfraredCustomEventType {
InfraredCustomEventTypePopupClosed,
InfraredCustomEventTypeButtonSelected,
InfraredCustomEventTypeBackPressed,
InfraredCustomEventTypeTaskFinished,

InfraredCustomEventTypeRpcLoadFile,
InfraredCustomEventTypeRpcExit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,24 @@ static void infrared_scene_universal_common_hide_popup(InfraredApp* infrared) {
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
}

static int32_t infrared_scene_universal_common_task_callback(void* context) {
InfraredApp* infrared = context;
const bool success = infrared_brute_force_calculate_messages(infrared->brute_force);
view_dispatcher_send_custom_event(
infrared->view_dispatcher,
infrared_custom_event_pack(InfraredCustomEventTypeTaskFinished, 0));

return success;
}

void infrared_scene_universal_common_on_enter(void* context) {
InfraredApp* infrared = context;
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
view_stack_add_view(infrared->view_stack, button_panel_get_view(infrared->button_panel));
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);

// Load universal remote data in background
infrared_blocking_task_start(infrared, infrared_scene_universal_common_task_callback);
}

bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent event) {
Expand All @@ -58,26 +73,34 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e
if(infrared_custom_event_get_type(event.event) == InfraredCustomEventTypeBackPressed) {
infrared_brute_force_stop(brute_force);
infrared_scene_universal_common_hide_popup(infrared);
consumed = true;
}
consumed = true;
}
} else {
if(event.type == SceneManagerEventTypeBack) {
scene_manager_previous_scene(scene_manager);
consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) {
if(infrared_custom_event_get_type(event.event) ==
InfraredCustomEventTypeButtonSelected) {
uint16_t event_type;
int16_t event_value;
infrared_custom_event_unpack(event.event, &event_type, &event_value);

if(event_type == InfraredCustomEventTypeButtonSelected) {
uint32_t record_count;
if(infrared_brute_force_start(
brute_force, infrared_custom_event_get_value(event.event), &record_count)) {
if(infrared_brute_force_start(brute_force, event_value, &record_count)) {
dolphin_deed(DolphinDeedIrSend);
infrared_scene_universal_common_show_popup(infrared, record_count);
} else {
scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases);
}
consumed = true;
} else if(event_type == InfraredCustomEventTypeTaskFinished) {
const bool task_success = infrared_blocking_task_finalize(infrared);

if(!task_success) {
scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases);
}
}
consumed = true;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "../infrared_app_i.h"

#include <furi_hal_infrared.h>

uint8_t value_index_ir;

#define DEB_PINS_COUNT (sizeof(infrared_debug_cfg_variables_text) / sizeof(char* const))
Expand Down
60 changes: 36 additions & 24 deletions applications/main/infrared/scenes/infrared_scene_edit_delete.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,33 @@ static void
view_dispatcher_send_custom_event(infrared->view_dispatcher, result);
}

static int32_t infrared_scene_edit_delete_task_callback(void* context) {
InfraredApp* infrared = context;
InfraredAppState* app_state = &infrared->app_state;
const InfraredEditTarget edit_target = app_state->edit_target;

bool success;
if(edit_target == InfraredEditTargetButton) {
furi_assert(app_state->current_button_index != InfraredButtonIndexNone);
success = infrared_remote_delete_signal(infrared->remote, app_state->current_button_index);
} else if(edit_target == InfraredEditTargetRemote) {
success = infrared_remote_remove(infrared->remote);
} else {
furi_crash();
}

view_dispatcher_send_custom_event(
infrared->view_dispatcher, InfraredCustomEventTypeTaskFinished);

return success;
}

void infrared_scene_edit_delete_on_enter(void* context) {
InfraredApp* infrared = context;
DialogEx* dialog_ex = infrared->dialog_ex;
InfraredRemote* remote = infrared->remote;

const InfraredEditTarget edit_target = infrared->app_state.edit_target;

if(edit_target == InfraredEditTargetButton) {
dialog_ex_set_header(dialog_ex, "Delete Button?", 64, 0, AlignCenter, AlignTop);

Expand Down Expand Up @@ -84,39 +105,30 @@ bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event)
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) {
scene_manager_previous_scene(scene_manager);
consumed = true;
} else if(event.event == DialogExResultRight) {
bool success = false;
InfraredRemote* remote = infrared->remote;
// Delete a button or a remote in a separate thread
infrared_blocking_task_start(infrared, infrared_scene_edit_delete_task_callback);

} else if(event.event == InfraredCustomEventTypeTaskFinished) {
const bool task_success = infrared_blocking_task_finalize(infrared);

InfraredAppState* app_state = &infrared->app_state;
const InfraredEditTarget edit_target = app_state->edit_target;

if(edit_target == InfraredEditTargetButton) {
furi_assert(app_state->current_button_index != InfraredButtonIndexNone);
infrared_show_loading_popup(infrared, true);
success = infrared_remote_delete_signal(remote, app_state->current_button_index);
infrared_show_loading_popup(infrared, false);
app_state->current_button_index = InfraredButtonIndexNone;
} else if(edit_target == InfraredEditTargetRemote) {
success = infrared_remote_remove(remote);
app_state->current_button_index = InfraredButtonIndexNone;
} else {
furi_crash();
}

if(success) {
if(task_success) {
scene_manager_next_scene(scene_manager, InfraredSceneEditDeleteDone);
} else {
infrared_show_error_message(
infrared,
"Failed to\ndelete %s",
edit_target == InfraredEditTargetButton ? "button" : "file");
const char* edit_target_text =
app_state->edit_target == InfraredEditTargetButton ? "button" : "file";
infrared_show_error_message(infrared, "Failed to\ndelete %s", edit_target_text);

const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
scene_manager_search_and_switch_to_previous_scene_one_of(
scene_manager, possible_scenes, COUNT_OF(possible_scenes));
}
consumed = true;

app_state->current_button_index = InfraredButtonIndexNone;
}
consumed = true;
}

return consumed;
Expand Down
Loading

0 comments on commit 3ade3f0

Please sign in to comment.