Allow users to set independent buzzer volume for signal/alarm

This commit is contained in:
Alessandro Genova
2025-08-30 23:46:34 -04:00
parent edd3a5c3b4
commit 3ea2f9c58a
5 changed files with 127 additions and 9 deletions

View 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;

View 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);

View 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:

View 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++;

View File

@ -45,6 +45,12 @@
* 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)
* snap back to the first screen. 60 seconds is a good default for the