src.nth.io/

summaryrefslogtreecommitdiff
path: root/main/state_machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/state_machine.c')
-rw-r--r--main/state_machine.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/main/state_machine.c b/main/state_machine.c
new file mode 100644
index 0000000..22f3f56
--- /dev/null
+++ b/main/state_machine.c
@@ -0,0 +1,89 @@
+#include "state_machine.h"
+
+#include "esp_check.h"
+#include "esp_log.h"
+#include "esp_timer.h"
+
+#include "display.h"
+
+static const char *TAG = "state";
+
+static esp_timer_handle_t s_idle_timer;
+
+static void arm_idle_timer_unlocked(void)
+{
+ viewport_state_lock();
+ uint32_t ms = viewport_state_get()->idle_timeout_ms;
+ viewport_state_unlock();
+ if (ms == 0) return;
+ esp_timer_stop(s_idle_timer);
+ esp_timer_start_once(s_idle_timer, (uint64_t)ms * 1000ULL);
+}
+
+static void disarm_idle_timer(void)
+{
+ esp_timer_stop(s_idle_timer);
+}
+
+static void idle_timer_fired(void *arg)
+{
+ ESP_LOGI(TAG, "idle timer expired — sleeping");
+ state_machine_set(VIEWPORT_STATE_ASLEEP);
+ // TODO M7: state_client_post(VIEWPORT_STATE_ASLEEP); // tell Scrypted
+}
+
+esp_err_t state_machine_init(void)
+{
+ esp_timer_create_args_t args = {
+ .callback = &idle_timer_fired,
+ .name = "viewport_idle",
+ };
+ return esp_timer_create(&args, &s_idle_timer);
+}
+
+esp_err_t state_machine_set(viewport_run_state_t target)
+{
+ if (target != VIEWPORT_STATE_AWAKE && target != VIEWPORT_STATE_ASLEEP)
+ return ESP_ERR_INVALID_ARG;
+
+ viewport_state_lock();
+ viewport_state_t *st = viewport_state_get();
+
+ if (!st->configured) {
+ viewport_state_unlock();
+ return ESP_ERR_INVALID_STATE;
+ }
+ if (st->state == target) {
+ viewport_state_unlock();
+ return ESP_OK; // idempotent no-op
+ }
+ st->state = target;
+ viewport_state_unlock();
+
+ if (target == VIEWPORT_STATE_AWAKE) {
+ if (display_is_up()) display_wake();
+ arm_idle_timer_unlocked();
+ ESP_LOGI(TAG, "AWAKE");
+ } else {
+ disarm_idle_timer();
+ if (display_is_up()) display_sleep();
+ ESP_LOGI(TAG, "ASLEEP");
+ }
+ return ESP_OK;
+}
+
+void state_machine_frame_painted(void)
+{
+ viewport_state_lock();
+ bool awake = (viewport_state_get()->state == VIEWPORT_STATE_AWAKE);
+ viewport_state_unlock();
+ if (awake) arm_idle_timer_unlocked();
+}
+
+viewport_run_state_t state_machine_current(void)
+{
+ viewport_state_lock();
+ viewport_run_state_t s = viewport_state_get()->state;
+ viewport_state_unlock();
+ return s;
+}