timed-remote

Flipper Zero app for sending delayed IR commands
git clone git://src.adamsgaard.dk/timed-remote # fast
git clone https://src.adamsgaard.dk/timed-remote.git # slow
Log | Files | Refs | README | LICENSE Back to index

scene_timer_config.c (7342B)


      1 #include "../timed_remote.h"
      2 #include "timed_remote_scene.h"
      3 
      4 enum {
      5   TimerConfigIndexMode,
      6   TimerConfigIndexHours,
      7   TimerConfigIndexMinutes,
      8   TimerConfigIndexSeconds,
      9   TimerConfigIndexRepeat,
     10   TimerConfigIndexConfirm,
     11 };
     12 
     13 static void timer_config_mode_change(VariableItem *item) {
     14   TimedRemoteApp *app = variable_item_get_context(item);
     15   uint8_t index = variable_item_get_current_value_index(item);
     16   app->timer_mode = (index == 0) ? TimerModeCountdown : TimerModeScheduled;
     17   variable_item_set_current_value_text(
     18       item, app->timer_mode == TimerModeCountdown ? "Countdown" : "Scheduled");
     19 
     20   /* Disable repeat in scheduled mode */
     21   if (app->timer_mode == TimerModeScheduled) {
     22     app->repeat_count = 0;
     23   }
     24 
     25   /* Trigger rebuild to show/hide repeat options */
     26   view_dispatcher_send_custom_event(app->view_dispatcher,
     27                                     TimedRemoteEventModeChanged);
     28 }
     29 
     30 static void timer_config_hours_change(VariableItem *item) {
     31   TimedRemoteApp *app = variable_item_get_context(item);
     32   uint8_t index = variable_item_get_current_value_index(item);
     33   app->hours = index;
     34   char buf[4];
     35   snprintf(buf, sizeof(buf), "%02d", app->hours);
     36   variable_item_set_current_value_text(item, buf);
     37 }
     38 
     39 static void timer_config_minutes_change(VariableItem *item) {
     40   TimedRemoteApp *app = variable_item_get_context(item);
     41   uint8_t index = variable_item_get_current_value_index(item);
     42   app->minutes = index;
     43   char buf[4];
     44   snprintf(buf, sizeof(buf), "%02d", app->minutes);
     45   variable_item_set_current_value_text(item, buf);
     46 }
     47 
     48 static void timer_config_seconds_change(VariableItem *item) {
     49   TimedRemoteApp *app = variable_item_get_context(item);
     50   uint8_t index = variable_item_get_current_value_index(item);
     51   app->seconds = index;
     52   char buf[4];
     53   snprintf(buf, sizeof(buf), "%02d", app->seconds);
     54   variable_item_set_current_value_text(item, buf);
     55 }
     56 
     57 static void timer_config_repeat_change(VariableItem *item) {
     58   TimedRemoteApp *app = variable_item_get_context(item);
     59   uint8_t index = variable_item_get_current_value_index(item);
     60 
     61   char buf[16];
     62   if (index == 0) {
     63     /* Off */
     64     app->repeat_count = 0;
     65     snprintf(buf, sizeof(buf), "Off");
     66   } else if (index == 1) {
     67     /* Unlimited */
     68     app->repeat_count = 255;
     69     snprintf(buf, sizeof(buf), "Unlimited");
     70   } else {
     71     /* 1, 2, 3, ... 99 */
     72     app->repeat_count = index - 1;
     73     snprintf(buf, sizeof(buf), "%d", app->repeat_count);
     74   }
     75   variable_item_set_current_value_text(item, buf);
     76 }
     77 
     78 static void timer_config_enter_callback(void *context, uint32_t index) {
     79   TimedRemoteApp *app = context;
     80   /* In countdown mode, confirm is at index 5, in scheduled mode it's at index 4 */
     81   uint32_t confirm_index = app->timer_mode == TimerModeCountdown
     82                                ? TimerConfigIndexConfirm
     83                                : (TimerConfigIndexSeconds + 1);
     84   if (index == confirm_index) {
     85     view_dispatcher_send_custom_event(app->view_dispatcher,
     86                                       TimedRemoteEventTimerConfigured);
     87   }
     88 }
     89 
     90 static void build_timer_config_list(TimedRemoteApp *app) {
     91   VariableItem *item;
     92   char buf[16];
     93 
     94   variable_item_list_reset(app->variable_item_list);
     95 
     96   /* Mode: Countdown / Scheduled */
     97   item = variable_item_list_add(app->variable_item_list, "Mode", 2,
     98                                 timer_config_mode_change, app);
     99   variable_item_set_current_value_index(
    100       item, app->timer_mode == TimerModeCountdown ? 0 : 1);
    101   variable_item_set_current_value_text(
    102       item, app->timer_mode == TimerModeCountdown ? "Countdown" : "Scheduled");
    103 
    104   /* Hours: 0-23 */
    105   item = variable_item_list_add(app->variable_item_list, "Hours", 24,
    106                                 timer_config_hours_change, app);
    107   variable_item_set_current_value_index(item, app->hours);
    108   snprintf(buf, sizeof(buf), "%02d", app->hours);
    109   variable_item_set_current_value_text(item, buf);
    110 
    111   /* Minutes: 0-59 */
    112   item = variable_item_list_add(app->variable_item_list, "Minutes", 60,
    113                                 timer_config_minutes_change, app);
    114   variable_item_set_current_value_index(item, app->minutes);
    115   snprintf(buf, sizeof(buf), "%02d", app->minutes);
    116   variable_item_set_current_value_text(item, buf);
    117 
    118   /* Seconds: 0-59 */
    119   item = variable_item_list_add(app->variable_item_list, "Seconds", 60,
    120                                 timer_config_seconds_change, app);
    121   variable_item_set_current_value_index(item, app->seconds);
    122   snprintf(buf, sizeof(buf), "%02d", app->seconds);
    123   variable_item_set_current_value_text(item, buf);
    124 
    125   /* Repeat options - only for countdown mode */
    126   if (app->timer_mode == TimerModeCountdown) {
    127     /* Repeat: Off, Unlimited, 1, 2, 3, ... 99 (total 101 values) */
    128     item = variable_item_list_add(app->variable_item_list, "Repeat", 101,
    129                                   timer_config_repeat_change, app);
    130 
    131     /* Convert repeat_count to index */
    132     uint8_t repeat_index;
    133     if (app->repeat_count == 0) {
    134       repeat_index = 0; /* Off */
    135     } else if (app->repeat_count == 255) {
    136       repeat_index = 1; /* Unlimited */
    137     } else {
    138       repeat_index = app->repeat_count + 1; /* 1-99 */
    139     }
    140     variable_item_set_current_value_index(item, repeat_index);
    141 
    142     /* Set display text */
    143     if (app->repeat_count == 0) {
    144       variable_item_set_current_value_text(item, "Off");
    145     } else if (app->repeat_count == 255) {
    146       variable_item_set_current_value_text(item, "Unlimited");
    147     } else {
    148       snprintf(buf, sizeof(buf), "%d", app->repeat_count);
    149       variable_item_set_current_value_text(item, buf);
    150     }
    151   }
    152 
    153   /* Confirm button */
    154   variable_item_list_add(app->variable_item_list, ">> Start Timer <<", 0, NULL,
    155                          NULL);
    156 
    157   variable_item_list_set_enter_callback(app->variable_item_list,
    158                                         timer_config_enter_callback, app);
    159 }
    160 
    161 void timed_remote_scene_timer_config_on_enter(void *context) {
    162   TimedRemoteApp *app = context;
    163   build_timer_config_list(app);
    164   view_dispatcher_switch_to_view(app->view_dispatcher,
    165                                  TimedRemoteViewVariableItemList);
    166 }
    167 
    168 bool timed_remote_scene_timer_config_on_event(void *context,
    169                                                SceneManagerEvent event) {
    170   TimedRemoteApp *app = context;
    171   bool consumed = false;
    172 
    173   if (event.type == SceneManagerEventTypeCustom) {
    174     if (event.event == TimedRemoteEventModeChanged) {
    175       /* Rebuild the list to show/hide repeat options */
    176       build_timer_config_list(app);
    177       consumed = true;
    178     } else if (event.event == TimedRemoteEventTimerConfigured) {
    179       /* Initialize repeats remaining based on repeat_count encoding */
    180       if (app->repeat_count == 0) {
    181         /* Off - single execution */
    182         app->repeats_remaining = 1;
    183       } else if (app->repeat_count == 255) {
    184         /* Unlimited */
    185         app->repeats_remaining = 255;
    186       } else {
    187         /* Fixed count (1-99): initial + N repeats = N+1 total executions */
    188         app->repeats_remaining = app->repeat_count + 1;
    189       }
    190       scene_manager_next_scene(app->scene_manager,
    191                                TimedRemoteSceneTimerRunning);
    192       consumed = true;
    193     }
    194   }
    195 
    196   return consumed;
    197 }
    198 
    199 void timed_remote_scene_timer_config_on_exit(void *context) {
    200   TimedRemoteApp *app = context;
    201   variable_item_list_reset(app->variable_item_list);
    202 }