]> git.earman.xyz Git - sensor-watch.git/commitdiff
Allow users to set independent buzzer volume for signal/alarm
authorAlessandro Genova <ales.genova@gmail.com>
Sun, 31 Aug 2025 03:46:34 +0000 (23:46 -0400)
committerAlessandro Genova <ales.genova@gmail.com>
Sat, 3 Jan 2026 01:07:56 +0000 (20:07 -0500)
movement.c
movement.h
movement_config.h
watch-faces/settings/settings_face.c
watch-faces/settings/settings_face.h

index 23eeb401e68d2a41a570a98710f82f3493af602e..1bb0a4bb16f2e3ead1616d08b161e8b26289cbbc 100644 (file)
@@ -157,6 +157,19 @@ static udatetime_t _movement_convert_date_time_to_udate(watch_date_time_t date_t
     };
 }
 
+static watch_buzzer_volume_t _movement_get_buzzer_volume(movement_buzzer_priority_t priority) {
+    switch (priority) {
+        case BUZZER_PRIORITY_BUTTON:
+            return movement_button_volume();
+        case BUZZER_PRIORITY_SIGNAL:
+            return movement_signal_volume();
+        case BUZZER_PRIORITY_ALARM:
+            return movement_alarm_volume();
+        default:
+            return WATCH_BUZZER_VOLUME_LOUD;
+    }
+}
+
 static void _movement_set_top_of_minute_alarm() {
     uint32_t counter = watch_rtc_get_counter();
     uint32_t next_minute_counter;
@@ -512,15 +525,15 @@ void movement_play_note(watch_buzzer_note_t note, uint16_t duration_ms) {
     single_note_sequence[1] = (int8_t)duration;
     single_note_sequence[2] = 0;
 
-    movement_play_sequence(single_note_sequence, 0);
+    movement_play_sequence(single_note_sequence, BUZZER_PRIORITY_BUTTON);
 }
 
 void movement_play_signal(void) {
-    movement_play_sequence(signal_tune, 1);
+    movement_play_sequence(signal_tune, BUZZER_PRIORITY_SIGNAL);
 }
 
 void movement_play_alarm(void) {
-    movement_play_sequence(alarm_tune, 2);
+    movement_play_sequence(alarm_tune, BUZZER_PRIORITY_ALARM);
 }
 
 void movement_play_alarm_beeps(uint8_t rounds, watch_buzzer_note_t alarm_note) {
@@ -550,10 +563,10 @@ void movement_play_alarm_beeps(uint8_t rounds, watch_buzzer_note_t alarm_note) {
 
     custom_alarm_tune[18] = 0;
 
-    movement_play_sequence(custom_alarm_tune, 2);
+    movement_play_sequence(custom_alarm_tune, BUZZER_PRIORITY_ALARM);
 }
 
-void movement_play_sequence(int8_t *note_sequence, uint8_t priority) {
+void movement_play_sequence(int8_t *note_sequence, movement_buzzer_priority_t priority) {
     // Priority is used to ensure that lower priority sequences don't cancel higher priority ones
     // Priotity order: alarm(2) > signal(1) > note(0)
     if (priority < movement_volatile_state.pending_sequence_priority) {
@@ -569,7 +582,7 @@ void movement_play_sequence(int8_t *note_sequence, uint8_t priority) {
         movement_volatile_state.has_pending_sequence = true;
         movement_volatile_state.exit_sleep_mode = true;
     } else {
-        watch_buzzer_play_sequence_with_volume(note_sequence, NULL, movement_button_volume());
+        watch_buzzer_play_sequence_with_volume(note_sequence, NULL, _movement_get_buzzer_volume(priority));
     }
 }
 
@@ -671,6 +684,21 @@ void movement_set_button_volume(watch_buzzer_volume_t value) {
     movement_state.settings.bit.button_volume = value;
 }
 
+watch_buzzer_volume_t movement_signal_volume(void) {
+    return movement_state.signal_volume;
+}
+void movement_set_signal_volume(watch_buzzer_volume_t value) {
+    movement_state.signal_volume = value;
+}
+
+watch_buzzer_volume_t movement_alarm_volume(void) {
+    return movement_state.alarm_volume;
+}
+
+void movement_set_alarm_volume(watch_buzzer_volume_t value) {
+    movement_state.alarm_volume = value;
+}
+
 movement_clock_mode_t movement_clock_mode_24h(void) {
     return movement_state.settings.bit.clock_mode_24h ? MOVEMENT_CLOCK_MODE_24H : MOVEMENT_CLOCK_MODE_12H;
 }
@@ -952,6 +980,8 @@ void app_init(void) {
 
     if (movement_state.accelerometer_motion_threshold == 0) movement_state.accelerometer_motion_threshold = 32;
 
+    movement_state.signal_volume = MOVEMENT_DEFAULT_SIGNAL_VOLUME;
+    movement_state.alarm_volume = MOVEMENT_DEFAULT_ALARM_VOLUME;
     movement_state.light_on = false;
     movement_state.next_available_backup_register = 2;
     _movement_reset_inactivity_countdown();
@@ -1241,7 +1271,7 @@ bool app_loop(void) {
         // If we woke up to play a note sequence, actually play the note sequence we were asked to play while in deep sleep.
         if (movement_volatile_state.has_pending_sequence) {
             movement_volatile_state.has_pending_sequence = false;
-            watch_buzzer_play_sequence_with_volume(_pending_sequence, movement_request_sleep, movement_button_volume());
+            watch_buzzer_play_sequence_with_volume(_pending_sequence, movement_request_sleep, _movement_get_buzzer_volume(movement_volatile_state.pending_sequence_priority));
             // When this sequence is done playing, movement_request_sleep is invoked and the watch will go,
             // back to sleep (unless the user interacts with it in the meantime)
             _pending_sequence = NULL;
index c1ac756f10c116d32641ebceebfb33d5583d7ef9..6e997d4aac3b7191a064326130f44152b8797811 100644 (file)
@@ -145,6 +145,12 @@ typedef enum {
     MINUTE_TIMEOUT,             // Top of the Minute timeout
 } movement_timeout_index_t;
 
+typedef enum {
+    BUZZER_PRIORITY_BUTTON = 0, // Buzzer priority for button beeps (lowest priority).
+    BUZZER_PRIORITY_SIGNAL,     // Buzzer priority for hourly chime (medium priority).
+    BUZZER_PRIORITY_ALARM,      // Buzzer priority for hourly chime (highest priority).
+} movement_buzzer_priority_t;
+
 typedef struct {
     uint8_t event_type;
     uint8_t subsecond;
@@ -286,6 +292,10 @@ typedef struct {
     lis2dw_data_rate_t accelerometer_background_rate;
     // threshold for considering the wearer is in motion
     uint8_t accelerometer_motion_threshold;
+
+    // signal and alarm volumes
+    watch_buzzer_volume_t signal_volume;
+    watch_buzzer_volume_t alarm_volume;
 } movement_state_t;
 
 void movement_move_to_face(uint8_t watch_face_index);
@@ -318,7 +328,7 @@ void movement_play_note(watch_buzzer_note_t note, uint16_t duration_ms);
 void movement_play_signal(void);
 void movement_play_alarm(void);
 void movement_play_alarm_beeps(uint8_t rounds, watch_buzzer_note_t alarm_note);
-void movement_play_sequence(int8_t *note_sequence, uint8_t priority);
+void movement_play_sequence(int8_t *note_sequence, movement_buzzer_priority_t priority);
 
 uint8_t movement_claim_backup_register(void);
 
@@ -343,6 +353,12 @@ void movement_set_button_should_sound(bool value);
 watch_buzzer_volume_t movement_button_volume(void);
 void movement_set_button_volume(watch_buzzer_volume_t value);
 
+watch_buzzer_volume_t movement_signal_volume(void);
+void movement_set_signal_volume(watch_buzzer_volume_t value);
+
+watch_buzzer_volume_t movement_alarm_volume(void);
+void movement_set_alarm_volume(watch_buzzer_volume_t value);
+
 movement_clock_mode_t movement_clock_mode_24h(void);
 void movement_set_clock_mode_24h(movement_clock_mode_t value);
 
index 9633de87883de876d946c72a0fcc1ca3d60c655f..a20cd3c2b892965c84e66cd0facb563ffbf38544 100644 (file)
@@ -69,6 +69,8 @@ const watch_face_t watch_faces[] = {
 #define MOVEMENT_DEFAULT_BUTTON_SOUND true
 
 #define MOVEMENT_DEFAULT_BUTTON_VOLUME WATCH_BUZZER_VOLUME_SOFT
+#define MOVEMENT_DEFAULT_SIGNAL_VOLUME WATCH_BUZZER_VOLUME_LOUD
+#define MOVEMENT_DEFAULT_ALARM_VOLUME WATCH_BUZZER_VOLUME_LOUD
 
 /* Set the timeout before switching back to the main watch face
  * Valid values are:
index 44d70f1b8737717f2cbe21ca25986d2ff8889b16..73bdadc14cec0f6e0c26c6269f2854b69a9c656d 100644 (file)
@@ -77,6 +77,64 @@ static void beep_setting_advance(void) {
     }
 }
 
+static void signal_setting_display(uint8_t subsecond) {
+    watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "SIG", "SI");
+    watch_display_text(WATCH_POSITION_BOTTOM, "SIGNAL");
+    if (subsecond % 2) {
+        if (movement_signal_volume() == WATCH_BUZZER_VOLUME_LOUD) {
+            // H for HIGH
+            watch_display_text(WATCH_POSITION_TOP_RIGHT, " H");
+        }
+        else {
+            // L for LOW
+            watch_display_text(WATCH_POSITION_TOP_RIGHT, " L");
+        }
+    }
+}
+
+static void signal_setting_advance(void) {
+    if (movement_signal_volume() == WATCH_BUZZER_VOLUME_SOFT) {
+        // was soft. make it loud.
+        movement_set_signal_volume(WATCH_BUZZER_VOLUME_LOUD);
+    } else {
+        // was loud. make it soft.
+        movement_set_signal_volume(WATCH_BUZZER_VOLUME_SOFT);
+    }
+
+    signal_setting_display(1);
+    movement_play_signal();
+}
+
+
+static void alarm_setting_display(uint8_t subsecond) {
+    watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "ALM", "AL");
+    watch_display_text(WATCH_POSITION_BOTTOM, "ALARM ");
+    if (subsecond % 2) {
+        if (movement_alarm_volume() == WATCH_BUZZER_VOLUME_LOUD) {
+            // H for HIGH
+            watch_display_text(WATCH_POSITION_TOP_RIGHT, " H");
+        }
+        else {
+            // L for LOW
+            watch_display_text(WATCH_POSITION_TOP_RIGHT, " L");
+        }
+    }
+}
+
+static void alarm_setting_advance(void) {
+    if (movement_alarm_volume() == WATCH_BUZZER_VOLUME_SOFT) {
+        // was soft. make it loud.
+        movement_set_alarm_volume(WATCH_BUZZER_VOLUME_LOUD);
+    } else {
+        // was loud. make it soft.
+        movement_set_alarm_volume(WATCH_BUZZER_VOLUME_SOFT);
+
+    }
+
+    alarm_setting_display(1);
+    movement_play_alarm();
+}
+
 static void timeout_setting_display(uint8_t subsecond) {
     watch_display_text_with_fallback(WATCH_POSITION_TOP, "TMOUt", "TO");
     if (subsecond % 2) {
@@ -235,7 +293,7 @@ void settings_face_setup(uint8_t watch_face_index, void ** context_ptr) {
         settings_state_t *state = (settings_state_t *)*context_ptr;
         int8_t current_setting = 0;
 
-        state->num_settings = 5; // baseline, without LED settings
+        state->num_settings = 7; // baseline, without LED settings
 #ifdef BUILD_GIT_HASH
         state->num_settings++;
 #endif
@@ -256,6 +314,12 @@ void settings_face_setup(uint8_t watch_face_index, void ** context_ptr) {
         state->settings_screens[current_setting].display = beep_setting_display;
         state->settings_screens[current_setting].advance = beep_setting_advance;
         current_setting++;
+        state->settings_screens[current_setting].display = signal_setting_display;
+        state->settings_screens[current_setting].advance = signal_setting_advance;
+        current_setting++;
+        state->settings_screens[current_setting].display = alarm_setting_display;
+        state->settings_screens[current_setting].advance = alarm_setting_advance;
+        current_setting++;
         state->settings_screens[current_setting].display = timeout_setting_display;
         state->settings_screens[current_setting].advance = timeout_setting_advance;
         current_setting++;
index 49e96b98811350fcac4991146aecafb79400ef9a..fd9256ea8b5dedfd3de359f2ab4f6a75f094f05a 100644 (file)
  *      This setting allows you to choose whether the Mode button should emit
  *      a beep when pressed, and if so, how loud it should be. Options are
  *      "Y" for yes and "N" for no.
+ * 
+ *  SI / SIG - Signal beep.
+ *      This setting allows you to choose the hourly chime buzzer volume.
+ * 
+ *  AL / ALM - Alarm beep.
+ *      This setting allows you to choose the hourly chime buzzer volume.
  *
  *  TO / Tmout - Timeout.
  *      Sets the time until screens that time out (like Settings and Time Set)