Refactor work timer structure for improved state management and simplify color definitions. Remove unused warning color definitions and clarify break warning time comment.

This commit is contained in:
TS Design Works 2025-05-17 15:25:55 -04:00
parent cc50f2cd92
commit 7f49c0408f
2 changed files with 214 additions and 624 deletions

View File

@ -19,237 +19,159 @@
#include "rgb_effects/rgb_effects.h"
#include "timer.h"
// Bitpacked flags to save memory
// Simple work timer structure
typedef struct {
uint8_t active: 1;
uint8_t paused: 1;
uint8_t lunch_break: 1;
uint8_t mid_break: 1;
uint8_t lunch_warning_shown: 1;
uint8_t mid_break_warning_shown: 1;
uint8_t end_warning_shown: 1;
uint8_t pulse_active: 1; // Flag to track if any pulse is currently active
} work_timer_flags_t;
// Basic state
bool active; // Is the timer running?
bool paused; // Is the timer paused?
work_timer_type_t type; // Timer type (30min, 1hr, etc.)
// Simplified work timer state structure
typedef struct {
work_timer_flags_t flags;
work_timer_type_t timer_type;
uint32_t start_time; // When timer was started
uint32_t end_time; // When timer should end (calculated)
uint32_t pause_time; // When pause started (if paused)
uint32_t break_start_time; // When current break started
uint32_t mid_break_time; // When mid-break should occur
uint32_t mid_break_duration; // How long the mid-break should last
bool has_lunch_break; // Whether this timer has a lunch break
// Time tracking
uint32_t start_time; // When this timer started
uint32_t end_time; // When this timer should end
uint32_t pause_time; // When timer was paused (if paused)
uint32_t break_time; // Break duration for this timer
// Midpoint break tracking
uint32_t mid_point; // Time value at midpoint (when break starts)
uint32_t mid_point_end; // Time value when break ends
} work_timer_t;
// Global work timer state with simplified initialization
static work_timer_t work_timer = {
.flags = {0},
.timer_type = TIMER_TYPE_8HR,
.start_time = 0,
.end_time = 0,
.pause_time = 0,
.break_start_time = 0,
.mid_break_time = 0,
.mid_break_duration = LUNCH_BREAK_DURATION,
.has_lunch_break = true
};
// Global timer state
static work_timer_t timer = {0};
// Predefined RGB colors for timer states
static const rgb_color_t WORK_TIMER_START_COLOR = {WORK_TIMER_START_R, WORK_TIMER_START_G, WORK_TIMER_START_B};
static const rgb_color_t WORK_TIMER_MID_COLOR = {WORK_TIMER_MID_R, WORK_TIMER_MID_G, WORK_TIMER_MID_B};
static const rgb_color_t WORK_TIMER_END_COLOR = {WORK_TIMER_END_R, WORK_TIMER_END_G, WORK_TIMER_END_B};
static const rgb_color_t WORK_TIMER_LUNCH_COLOR = {WORK_TIMER_LUNCH_R, WORK_TIMER_LUNCH_G, WORK_TIMER_LUNCH_B};
static const rgb_color_t WORK_TIMER_WARNING_COLOR = {WORK_TIMER_WARNING_R, WORK_TIMER_WARNING_G, WORK_TIMER_WARNING_B};
// Timer colors
static const rgb_color_t TIMER_START_COLOR = {WORK_TIMER_START_R, WORK_TIMER_START_G, WORK_TIMER_START_B};
static const rgb_color_t TIMER_MID_COLOR = {WORK_TIMER_MID_R, WORK_TIMER_MID_G, WORK_TIMER_MID_B};
static const rgb_color_t TIMER_END_COLOR = {WORK_TIMER_END_R, WORK_TIMER_END_G, WORK_TIMER_END_B};
static const rgb_color_t TIMER_BREAK_COLOR = {WORK_TIMER_LUNCH_R, WORK_TIMER_LUNCH_G, WORK_TIMER_LUNCH_B};
// Function prototypes for internal functions
static void configure_timer_for_type(work_timer_type_t timer_type);
static void display_progress_bar(uint8_t num_leds, float overall_progress, float brightness_factor);
static void save_work_timer_state(void);
static void load_work_timer_state(void);
static void update_pulse_active_state(void);
// Function declarations
static void save_timer_state(void);
static void load_timer_state(void);
static void display_progress_bar(uint8_t num_leds, float progress, float brightness);
/**
* Configure timer parameters based on timer type
* Configure a timer with the specified type
*/
static void configure_timer_for_type(work_timer_type_t timer_type) {
work_timer.timer_type = timer_type;
static void configure_timer(work_timer_type_t type) {
timer.type = type;
switch (timer_type) {
// Set break duration based on timer type
switch (type) {
case TIMER_TYPE_30MIN:
work_timer.mid_break_time = TIMER_30MIN_DURATION / 2;
work_timer.mid_break_duration = MID_BREAK_30MIN_DURATION;
work_timer.has_lunch_break = false;
work_timer.end_time = work_timer.start_time + TIMER_30MIN_DURATION;
timer.break_time = MID_BREAK_30MIN_DURATION;
break;
case TIMER_TYPE_1HR:
work_timer.mid_break_time = TIMER_1HR_DURATION / 2;
work_timer.mid_break_duration = MID_BREAK_1HR_DURATION;
work_timer.has_lunch_break = false;
work_timer.end_time = work_timer.start_time + TIMER_1HR_DURATION;
timer.break_time = MID_BREAK_1HR_DURATION;
break;
case TIMER_TYPE_4HR:
work_timer.mid_break_time = TIMER_4HR_DURATION / 2;
work_timer.mid_break_duration = MID_BREAK_4HR_DURATION;
work_timer.has_lunch_break = false;
work_timer.end_time = work_timer.start_time + TIMER_4HR_DURATION;
timer.break_time = MID_BREAK_4HR_DURATION;
break;
case TIMER_TYPE_8HR:
work_timer.mid_break_time = TIMER_8HR_DURATION / 2;
work_timer.mid_break_duration = LUNCH_BREAK_DURATION;
work_timer.has_lunch_break = true;
work_timer.end_time = work_timer.start_time + TIMER_8HR_DURATION;
timer.break_time = LUNCH_BREAK_DURATION;
break;
case TIMER_TYPE_10HR:
work_timer.mid_break_time = TIMER_10HR_DURATION / 2;
work_timer.mid_break_duration = LUNCH_BREAK_DURATION;
work_timer.has_lunch_break = true;
work_timer.end_time = work_timer.start_time + TIMER_10HR_DURATION;
timer.break_time = LUNCH_BREAK_DURATION;
break;
default:
// Default to 8HR if something goes wrong
work_timer.mid_break_time = TIMER_8HR_DURATION / 2;
work_timer.mid_break_duration = LUNCH_BREAK_DURATION;
work_timer.has_lunch_break = true;
work_timer.end_time = work_timer.start_time + TIMER_8HR_DURATION;
timer.break_time = LUNCH_BREAK_DURATION;
break;
}
// Calculate timer duration (excluding break)
uint32_t work_duration = 0;
switch (type) {
case TIMER_TYPE_30MIN: work_duration = TIMER_30MIN_DURATION; break;
case TIMER_TYPE_1HR: work_duration = TIMER_1HR_DURATION; break;
case TIMER_TYPE_4HR: work_duration = TIMER_4HR_DURATION; break;
case TIMER_TYPE_8HR: work_duration = TIMER_8HR_DURATION; break;
case TIMER_TYPE_10HR: work_duration = TIMER_10HR_DURATION; break;
default: work_duration = TIMER_8HR_DURATION; break;
}
// Calculate end time and midpoint
timer.end_time = timer.start_time + work_duration;
timer.mid_point = timer.start_time + (work_duration / 2);
timer.mid_point_end = timer.mid_point + timer.break_time;
}
/**
* Save the work timer state to EEPROM
* Save timer state to EEPROM
*/
static void save_work_timer_state(void) {
// Create a buffer to store all our data
uint8_t buffer[24] = {0}; // Increased from 21 to 24 bytes to have enough space
static void save_timer_state(void) {
uint8_t buffer[24] = {0};
// Set the active flag
buffer[0] = work_timer.flags.active;
// Basic state
buffer[0] = timer.active ? 1 : 0;
buffer[1] = timer.paused ? 1 : 0;
buffer[2] = (uint8_t)timer.type;
// Only save time info if timer is active
if (work_timer.flags.active) {
// Save start time (4 bytes)
memcpy(&buffer[1], &work_timer.start_time, sizeof(uint32_t));
// Time values
memcpy(&buffer[3], &timer.start_time, sizeof(uint32_t));
memcpy(&buffer[7], &timer.end_time, sizeof(uint32_t));
memcpy(&buffer[11], &timer.pause_time, sizeof(uint32_t));
memcpy(&buffer[15], &timer.break_time, sizeof(uint32_t));
memcpy(&buffer[19], &timer.mid_point, sizeof(uint32_t));
// Save end time (4 bytes)
memcpy(&buffer[5], &work_timer.end_time, sizeof(uint32_t));
// Save timer type (1 byte)
buffer[9] = (uint8_t)work_timer.timer_type;
// Save pause state and time (5 bytes)
buffer[10] = work_timer.flags.paused;
memcpy(&buffer[11], &work_timer.pause_time, sizeof(uint32_t));
// Save break state (1 byte)
buffer[15] = (work_timer.flags.lunch_break ? 1 : 0) |
(work_timer.flags.mid_break ? 2 : 0);
// Save break start time (4 bytes)
memcpy(&buffer[16], &work_timer.break_start_time, sizeof(uint32_t));
// Save mid-break time (4 bytes) - fixed buffer position
memcpy(&buffer[20], &work_timer.mid_break_time, sizeof(uint32_t));
}
// Write all data at once to EEPROM
// Write to EEPROM
eeprom_update_block(buffer, (void *)EEPROM_WORK_TIMER_ACTIVE, sizeof(buffer));
}
/**
* Load the work timer state from EEPROM
* Load timer state from EEPROM
*/
static void load_work_timer_state(void) {
// Create a buffer to read all our data
uint8_t buffer[24] = {0}; // Increased from 21 to 24 bytes to match save function
static void load_timer_state(void) {
uint8_t buffer[24] = {0};
// Read all data at once from EEPROM
// Read from EEPROM
eeprom_read_block(buffer, (const void *)EEPROM_WORK_TIMER_ACTIVE, sizeof(buffer));
// Get the active flag
work_timer.flags.active = buffer[0];
// Basic state
timer.active = buffer[0] ? true : false;
timer.paused = buffer[1] ? true : false;
timer.type = (work_timer_type_t)buffer[2];
// Only process the rest if timer was active
if (work_timer.flags.active) {
// Load timer type
work_timer_type_t saved_type = (work_timer_type_t)buffer[9];
// Time values
memcpy(&timer.start_time, &buffer[3], sizeof(uint32_t));
memcpy(&timer.end_time, &buffer[7], sizeof(uint32_t));
memcpy(&timer.pause_time, &buffer[11], sizeof(uint32_t));
memcpy(&timer.break_time, &buffer[15], sizeof(uint32_t));
memcpy(&timer.mid_point, &buffer[19], sizeof(uint32_t));
// Get start time (4 bytes)
memcpy(&work_timer.start_time, &buffer[1], sizeof(uint32_t));
// Calculate mid_point_end from loaded values
if (timer.active) {
timer.mid_point_end = timer.mid_point + timer.break_time;
// Get end time (4 bytes)
memcpy(&work_timer.end_time, &buffer[5], sizeof(uint32_t));
// Get pause state and time (5 bytes)
work_timer.flags.paused = buffer[10];
memcpy(&work_timer.pause_time, &buffer[11], sizeof(uint32_t));
// Get break state (1 byte)
uint8_t break_state = buffer[15];
work_timer.flags.lunch_break = (break_state & 1) > 0;
work_timer.flags.mid_break = (break_state & 2) > 0;
// Get break start time (4 bytes)
memcpy(&work_timer.break_start_time, &buffer[16], sizeof(uint32_t));
// Get mid-break time (4 bytes) - fixed buffer position
memcpy(&work_timer.mid_break_time, &buffer[20], sizeof(uint32_t));
// Apply configuration for this timer type (durations, etc.)
configure_timer_for_type(saved_type);
// If currently in a break, we need to adjust for time passed since poweroff
if (work_timer.flags.lunch_break || work_timer.flags.mid_break) {
// Verify timer is still valid
if (!timer.paused) {
uint32_t current_time = timer_read32();
uint32_t time_off = current_time - work_timer.break_start_time;
// If we've been powered off longer than the break duration, end the break
if (time_off > work_timer.mid_break_duration) {
work_timer.flags.lunch_break = 0;
work_timer.flags.mid_break = 0;
if (current_time > timer.end_time) {
timer.active = false;
save_timer_state();
}
}
// Validate timer values
uint32_t current_time = timer_read32();
// If end time is in the past, timer is done
if (work_timer.end_time <= current_time && !work_timer.flags.paused) {
work_timer.flags.active = 0;
save_work_timer_state();
}
// Check for end warning state (within 5 minutes of end)
if (!work_timer.flags.paused &&
current_time >= (work_timer.end_time - BREAK_WARNING_TIME)) {
work_timer.flags.end_warning_shown = 1;
}
// Update pulse active state
update_pulse_active_state();
}
}
/**
* Display progress bar with gradient colors
*/
static void display_progress_bar(uint8_t num_leds, float overall_progress, float brightness_factor) {
// Calculate hour segments and LED positions
static void display_progress_bar(uint8_t num_leds, float progress, float brightness) {
// Progress is a value from 0.0 to 1.0
float hours_per_led = 1.0f / (float)num_leds;
// Determine how many LEDs should be fully lit
uint8_t leds_lit = (uint8_t)(overall_progress / hours_per_led);
// Determine how many LEDs should be lit
uint8_t leds_lit = (uint8_t)(progress / hours_per_led);
if (leds_lit > num_leds) leds_lit = num_leds;
// Calculate progress within the current LED
float current_led_progress = (overall_progress - (leds_lit * hours_per_led)) / hours_per_led;
// Calculate progress for the partially-lit LED
float current_led_progress = (progress - (leds_lit * hours_per_led)) / hours_per_led;
// Set colors for each LED in the progress bar
for (uint8_t i = 0; i < num_leds; i++) {
@ -257,46 +179,41 @@ static void display_progress_bar(uint8_t num_leds, float overall_progress, float
if (i < leds_lit) {
// Fully lit LED - calculate gradient color based on position
float led_position = (float)i / (float)(num_leds - 1);
float position = (float)i / (float)(num_leds - 1);
// Adjust transition points - more green-to-orange (first 80% of bar),
// and less orange-to-red (last 20% of bar)
if (led_position < 0.3f) {
// Scale to 0.0 - 1.0 for green-to-orange part (now 80% of the bar)
float adjusted_progress = led_position / 0.3f;
color = calculate_gradient_color(WORK_TIMER_START_COLOR, WORK_TIMER_MID_COLOR, adjusted_progress);
}
else {
float adjusted_progress = (led_position - 0.3f) / 0.7f; // Scale to 0.0 - 1.0 for last 20%
color = calculate_gradient_color(WORK_TIMER_MID_COLOR, WORK_TIMER_END_COLOR, adjusted_progress);
// Use green to orange gradient for most of bar, orange to red at end
if (position < 0.7f) {
// First 70% is green to orange
float adj_progress = position / 0.7f;
color = calculate_gradient_color(TIMER_START_COLOR, TIMER_MID_COLOR, adj_progress);
} else {
// Last 30% is orange to red
float adj_progress = (position - 0.7f) / 0.3f;
color = calculate_gradient_color(TIMER_MID_COLOR, TIMER_END_COLOR, adj_progress);
}
// Apply overall RGB brightness factor
color.r = (uint8_t)((float)color.r * brightness_factor);
color.g = (uint8_t)((float)color.g * brightness_factor);
color.b = (uint8_t)((float)color.b * brightness_factor);
// Apply brightness
color.r = (uint8_t)((float)color.r * brightness);
color.g = (uint8_t)((float)color.g * brightness);
color.b = (uint8_t)((float)color.b * brightness);
}
else if (i == leds_lit && current_led_progress > 0.0f) {
// Current LED - partially lit based on progress
float led_position = (float)i / (float)(num_leds - 1);
// Partially lit LED
float position = (float)i / (float)(num_leds - 1);
rgb_color_t full_color;
// Adjust transition points - more green-to-orange, less orange-to-red
if (led_position < 0.3f) {
// Scale to 0.0 - 1.0 for green-to-orange part
float adjusted_progress = led_position / 0.3f;
full_color = calculate_gradient_color(WORK_TIMER_START_COLOR, WORK_TIMER_MID_COLOR, adjusted_progress);
}
// Last 30% is orange-to-red gradient
else {
float adjusted_progress = (led_position - 0.3f) / 0.7f; // Scale to 0.0 - 1.0 for last 20%
full_color = calculate_gradient_color(WORK_TIMER_MID_COLOR, WORK_TIMER_END_COLOR, adjusted_progress);
if (position < 0.7f) {
float adj_progress = position / 0.7f;
full_color = calculate_gradient_color(TIMER_START_COLOR, TIMER_MID_COLOR, adj_progress);
} else {
float adj_progress = (position - 0.7f) / 0.3f;
full_color = calculate_gradient_color(TIMER_MID_COLOR, TIMER_END_COLOR, adj_progress);
}
// Dim the color based on progress within this LED and overall brightness
color.r = (uint8_t)((float)full_color.r * current_led_progress * brightness_factor);
color.g = (uint8_t)((float)full_color.g * current_led_progress * brightness_factor);
color.b = (uint8_t)((float)full_color.b * current_led_progress * brightness_factor);
// Dim by progress and brightness
color.r = (uint8_t)((float)full_color.r * current_led_progress * brightness);
color.g = (uint8_t)((float)full_color.g * current_led_progress * brightness);
color.b = (uint8_t)((float)full_color.b * current_led_progress * brightness);
}
// Set the LED color
@ -305,326 +222,114 @@ static void display_progress_bar(uint8_t num_leds, float overall_progress, float
}
/**
* Update the pulse active state
* This determines if any pulse effect is currently active
* Initialize the work timer
*/
static void update_pulse_active_state(void) {
if (!work_timer.flags.active || work_timer.flags.paused) {
work_timer.flags.pulse_active = false;
return;
}
uint32_t current_time = timer_read32();
// Check if any pulse condition is active
bool lunch_warning = false;
bool lunch_end_warning = false;
bool mid_point_warning = false;
bool end_warning = false;
// Mid-break (lunch) timing logic
if (work_timer.has_lunch_break) {
// Time until mid-break (lunch)
uint32_t time_to_mid_break = 0;
if (current_time < work_timer.mid_break_time) {
time_to_mid_break = work_timer.mid_break_time - current_time;
}
// Lunch break warning (before lunch)
lunch_warning = !work_timer.flags.lunch_break &&
(time_to_mid_break > 0 && time_to_mid_break < BREAK_WARNING_TIME);
// Lunch end warning (before end of lunch)
lunch_end_warning = work_timer.flags.lunch_break &&
(timer_elapsed32(work_timer.break_start_time) >=
(work_timer.mid_break_duration - BREAK_WARNING_TIME));
}
else {
// Simple mid-break logic
uint32_t time_to_mid_break = 0;
if (current_time < work_timer.mid_break_time) {
time_to_mid_break = work_timer.mid_break_time - current_time;
}
// Mid-point break warning for shorter timers
mid_point_warning = !work_timer.flags.mid_break &&
(time_to_mid_break > 0 && time_to_mid_break < BREAK_WARNING_TIME);
}
// End timer warning (5 minutes before end)
end_warning = (current_time >= (work_timer.end_time - BREAK_WARNING_TIME) &&
current_time < work_timer.end_time);
// Set pulse active if any of these conditions are true
work_timer.flags.pulse_active = (
work_timer.flags.mid_break || // Mid-point break pulse
work_timer.flags.lunch_break || // Lunch break
work_timer.flags.end_warning_shown || // End warning
lunch_warning || // Pre-lunch warning
lunch_end_warning || // End of lunch warning
mid_point_warning || // Mid-point warning for shorter timers
end_warning // End warning for all timers
);
void work_timer_init(void) {
load_timer_state();
}
/**
* Toggle the work timer on/off
*/
void toggle_work_timer(void) {
if (work_timer.flags.active) {
// If timer is active, stop it and reset all state flags
work_timer.flags.active = 0;
work_timer.flags.paused = 0;
work_timer.flags.lunch_break = 0;
work_timer.flags.mid_break = 0;
work_timer.flags.lunch_warning_shown = 0;
work_timer.flags.mid_break_warning_shown = 0;
work_timer.flags.end_warning_shown = 0;
work_timer.flags.pulse_active = 0;
if (timer.active) {
// Turn off timer
timer.active = false;
timer.paused = false;
// Save clean state to EEPROM
save_work_timer_state();
save_timer_state();
// Force immediate RGB refresh
// Force RGB refresh
rgb_matrix_mode_noeeprom(rgb_matrix_get_mode());
} else {
// If timer is inactive, start a new timer
work_timer.flags.active = 1;
work_timer.flags.paused = 0;
work_timer.flags.lunch_break = 0;
work_timer.flags.mid_break = 0;
work_timer.flags.lunch_warning_shown = 0;
work_timer.flags.mid_break_warning_shown = 0;
work_timer.flags.end_warning_shown = 0;
work_timer.flags.pulse_active = 0;
// Start a new timer
timer.active = true;
timer.paused = false;
timer.start_time = timer_read32();
timer.pause_time = 0;
// Set timer start and calculate end time
work_timer.start_time = timer_read32();
work_timer.break_start_time = 0;
// Set up mid-break time based on current time
uint32_t duration = 0;
switch (work_timer.timer_type) {
case TIMER_TYPE_30MIN: duration = TIMER_30MIN_DURATION; break;
case TIMER_TYPE_1HR: duration = TIMER_1HR_DURATION; break;
case TIMER_TYPE_4HR: duration = TIMER_4HR_DURATION; break;
case TIMER_TYPE_8HR: duration = TIMER_8HR_DURATION; break;
case TIMER_TYPE_10HR: duration = TIMER_10HR_DURATION; break;
default: duration = TIMER_8HR_DURATION; break;
}
// Set mid-break time (halfway through timer)
work_timer.mid_break_time = work_timer.start_time + (duration / 2);
// Set end time
work_timer.end_time = work_timer.start_time + duration;
save_work_timer_state();
// Configure for current timer type
configure_timer(timer.type);
save_timer_state();
}
update_pulse_active_state();
}
/**
* Initialize the work timer - load state from EEPROM
*/
void work_timer_init(void) {
load_work_timer_state();
}
/**
* Start a specific timer type
*/
void start_timer(work_timer_type_t timer_type) {
// Reset timer state
work_timer.flags.active = 1;
work_timer.flags.paused = 0;
work_timer.flags.lunch_break = 0;
work_timer.flags.mid_break = 0;
work_timer.flags.lunch_warning_shown = 0;
work_timer.flags.mid_break_warning_shown = 0;
work_timer.flags.end_warning_shown = 0;
work_timer.flags.pulse_active = 0;
void start_timer(work_timer_type_t type) {
// Start fresh
timer.active = true;
timer.paused = false;
timer.start_time = timer_read32();
timer.pause_time = 0;
work_timer.start_time = timer_read32();
work_timer.break_start_time = 0;
// Configure timer parameters based on type
work_timer.timer_type = timer_type;
configure_timer_for_type(timer_type);
save_work_timer_state();
// Update pulse state immediately after starting timer
update_pulse_active_state();
// Configure based on type
configure_timer(type);
save_timer_state();
}
/**
* Pause or resume the work timer
* Pause or resume the timer
*/
void toggle_pause_work_timer(void) {
if (!work_timer.flags.active) return;
if (!timer.active) return;
if (!work_timer.flags.paused) {
// Pause the timer
work_timer.flags.paused = 1;
work_timer.pause_time = timer_read32();
save_work_timer_state();
} else {
// Resume the timer - extend all time values by pause duration
if (timer.paused) {
// Resume - calculate time paused and adjust timers
uint32_t current_time = timer_read32();
uint32_t pause_duration = current_time - work_timer.pause_time;
uint32_t pause_duration = current_time - timer.pause_time;
// Extend end time by pause duration
work_timer.end_time += pause_duration;
// Extend all time points by pause duration
timer.end_time += pause_duration;
timer.mid_point += pause_duration;
timer.mid_point_end += pause_duration;
// If mid-break hasn't happened yet, extend that too
if (current_time < work_timer.mid_break_time) {
work_timer.mid_break_time += pause_duration;
}
// If in a break, adjust break start time too
if (work_timer.flags.lunch_break || work_timer.flags.mid_break) {
work_timer.break_start_time += pause_duration;
}
work_timer.flags.paused = 0;
save_work_timer_state();
timer.paused = false;
} else {
// Pause
timer.pause_time = timer_read32();
timer.paused = true;
}
update_pulse_active_state();
save_timer_state();
}
/**
* Update the work timer state
* Check if the blue pulse effect should be active
*/
void update_work_timer(void) {
if (!work_timer.flags.active || work_timer.flags.paused) return;
bool is_timer_pulse_active(void) {
if (!timer.active || timer.paused) return false;
uint32_t current_time = timer_read32();
// Process different timer states based on timer type
if (work_timer.has_lunch_break) {
// Handle lunch break state transitions
if (!work_timer.flags.lunch_break) {
// Check if it's time to start lunch
if (!work_timer.flags.lunch_warning_shown &&
current_time >= (work_timer.mid_break_time - BREAK_WARNING_TIME) &&
current_time < work_timer.mid_break_time) {
// Pre-lunch warning
work_timer.flags.lunch_warning_shown = 1;
}
else if (current_time >= work_timer.mid_break_time) {
// Start lunch break
work_timer.flags.lunch_break = 1;
work_timer.break_start_time = current_time;
work_timer.flags.lunch_warning_shown = 0; // Reset for lunch end warning
// Don't need to extend end time yet - will do that when break ends
save_work_timer_state();
}
}
else {
// Currently in lunch break
uint32_t break_elapsed = timer_elapsed32(work_timer.break_start_time);
// Check for lunch end warning
if (!work_timer.flags.lunch_warning_shown &&
break_elapsed >= (work_timer.mid_break_duration - BREAK_WARNING_TIME)) {
// Pre-end warning
work_timer.flags.lunch_warning_shown = 1;
}
// End lunch break after duration (plus grace period)
if (break_elapsed >= (work_timer.mid_break_duration + 5000)) {
// End lunch break
work_timer.flags.lunch_break = 0;
work_timer.flags.lunch_warning_shown = 0;
// Extend end time by break duration
work_timer.end_time += break_elapsed;
save_work_timer_state();
}
}
}
else {
// Handle mid-break state transitions for shorter timers
if (!work_timer.flags.mid_break) {
// Check if it's time to start mid-break
if (!work_timer.flags.mid_break_warning_shown &&
current_time >= (work_timer.mid_break_time - BREAK_WARNING_TIME) &&
current_time < work_timer.mid_break_time) {
// Mid-break warning
work_timer.flags.mid_break_warning_shown = 1;
}
else if (current_time >= work_timer.mid_break_time) {
// Start mid-break
work_timer.flags.mid_break = 1;
work_timer.break_start_time = current_time;
work_timer.flags.mid_break_warning_shown = 0;
save_work_timer_state();
}
}
else {
// Currently in mid-break
uint32_t break_elapsed = timer_elapsed32(work_timer.break_start_time);
// End mid-break after duration (plus grace period)
if (break_elapsed >= (work_timer.mid_break_duration + 5000)) {
// End mid-break
work_timer.flags.mid_break = 0;
work_timer.flags.mid_break_warning_shown = 0;
// Extend end time by break duration
work_timer.end_time += break_elapsed;
save_work_timer_state();
}
}
}
// Check for end of day warning
if (!work_timer.flags.end_warning_shown &&
current_time >= (work_timer.end_time - BREAK_WARNING_TIME)) {
work_timer.flags.end_warning_shown = 1;
}
// Auto-stop after timer ends
if (current_time >= work_timer.end_time) {
work_timer.flags.active = 0;
work_timer.flags.lunch_break = 0;
work_timer.flags.mid_break = 0;
save_work_timer_state();
}
update_pulse_active_state();
// Only return true when we're in the mid-point break window
return (current_time >= timer.mid_point && current_time < timer.mid_point_end);
}
/**
* Check if any timer pulse is currently active
* Used for easier state checking
*
* @return true if any timer pulse effect is active, false otherwise
* Update timer state
*/
bool is_timer_pulse_active(void) {
// If timer is not active or is paused, no pulse is active
if (!work_timer.flags.active || work_timer.flags.paused) {
return false;
}
void update_work_timer(void) {
if (!timer.active || timer.paused) return;
// Return the pulse_active flag directly from the work timer state
return work_timer.flags.pulse_active;
uint32_t current_time = timer_read32();
// Check if timer has ended
if (current_time >= timer.end_time) {
timer.active = false;
save_timer_state();
rgb_matrix_mode_noeeprom(rgb_matrix_get_mode());
}
}
/**
* Handle the work timer visualization on LEDs
* Handle work timer visualization
*/
void handle_work_timer(void) {
static bool was_active = false;
if (!work_timer.flags.active) {
// If the timer was just deactivated, force RGB refresh
if (!timer.active) {
if (was_active) {
rgb_matrix_mode_noeeprom(rgb_matrix_get_mode());
was_active = false;
@ -634,165 +339,55 @@ void handle_work_timer(void) {
was_active = true;
// Get current RGB matrix brightness
// Get current time and brightness
uint32_t current_time = timer_read32();
uint8_t rgb_brightness = rgb_matrix_get_val();
float brightness_factor = (float)rgb_brightness / 255.0f;
// Number of LEDs in the progress bar
const uint8_t num_leds = WORK_TIMER_LED_END - WORK_TIMER_LED_START + 1;
// Calculate overall progress (0.0 - 1.0)
uint32_t current_time = timer_read32();
float overall_progress;
// Simple progress calculation based on total time range
if (work_timer.flags.paused) {
// When paused, use the pause time for calculation
overall_progress = (float)(work_timer.pause_time - work_timer.start_time) /
(float)(work_timer.end_time - work_timer.start_time);
// Calculate progress based on active timer duration
float progress;
if (timer.paused) {
// When paused, use pause time for progress calculation
progress = (float)(timer.pause_time - timer.start_time) /
(float)(timer.end_time - timer.start_time);
} else {
// Normal operation - current progress through timer
overall_progress = (float)(current_time - work_timer.start_time) /
(float)(work_timer.end_time - work_timer.start_time);
// When active, use current time for progress calculation
progress = (float)(current_time - timer.start_time) /
(float)(timer.end_time - timer.start_time);
}
if (overall_progress > 1.0f) overall_progress = 1.0f;
// Clamp progress to valid range
if (progress > 1.0f) progress = 1.0f;
if (progress < 0.0f) progress = 0.0f;
// Create pulsing effect
uint8_t pulse_brightness = abs((timer_read() / 4) % 510 - 255);
float pulse_ratio = (float)pulse_brightness / 255.0f;
// Check if we're in the break window (midpoint of the timer)
if (!timer.paused && current_time >= timer.mid_point && current_time < timer.mid_point_end) {
// In break time - show blue pulse
rgb_color_t color = TIMER_BREAK_COLOR;
// Check for various timer states
bool lunch_warning = false;
bool lunch_end_warning = false;
bool mid_break_warning = false;
bool end_warning = false;
// Slow pulse for break time
uint8_t break_pulse = timer_read() / 10;
float break_intensity = (float)(abs(break_pulse % 510 - 255)) / 255.0f;
// For timers with lunch breaks
if (work_timer.has_lunch_break) {
// Pre-lunch warning (red pulse)
lunch_warning = !work_timer.flags.lunch_break &&
(current_time >= (work_timer.mid_break_time - BREAK_WARNING_TIME) &&
current_time < work_timer.mid_break_time);
// Lunch-end warning (red pulse)
lunch_end_warning = work_timer.flags.lunch_break &&
work_timer.break_start_time != 0 &&
(timer_elapsed32(work_timer.break_start_time) >=
(work_timer.mid_break_duration - BREAK_WARNING_TIME));
// End warning
end_warning = current_time >= (work_timer.end_time - BREAK_WARNING_TIME) &&
current_time < work_timer.end_time;
// Choose appropriate display based on current state
if (lunch_warning || lunch_end_warning) {
// Pre/Post lunch red warning pulse
rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR;
// Apply pulsing effect to all progress bar LEDs
for (uint8_t i = 0; i < num_leds; i++) {
rgb_matrix_set_color(WORK_TIMER_LED_START + i,
(uint8_t)((float)pulse_color.r * pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.g * pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.b * pulse_ratio * brightness_factor));
}
}
else if (work_timer.flags.lunch_break && work_timer.break_start_time != 0) {
// During lunch break - blue pulse
rgb_color_t pulse_color = WORK_TIMER_LUNCH_COLOR;
// Use a slower pulse for regular lunch break
uint8_t lunch_pulse = abs((timer_read() / 10) % 510 - 255);
float lunch_pulse_ratio = (float)lunch_pulse / 255.0f;
// Apply lunch break color to all progress bar LEDs
for (uint8_t i = 0; i < num_leds; i++) {
rgb_matrix_set_color(WORK_TIMER_LED_START + i,
(uint8_t)((float)pulse_color.r * lunch_pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.g * lunch_pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.b * lunch_pulse_ratio * brightness_factor));
}
}
else if (work_timer.flags.end_warning_shown || end_warning) {
// End of day warning - red pulse
rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR;
// Apply pulsing effect to all progress bar LEDs
for (uint8_t i = 0; i < num_leds; i++) {
rgb_matrix_set_color(WORK_TIMER_LED_START + i,
(uint8_t)((float)pulse_color.r * pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.g * pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.b * pulse_ratio * brightness_factor));
}
}
else {
// Normal progress bar display
display_progress_bar(num_leds, overall_progress, brightness_factor);
}
}
// For timers without lunch breaks (30MIN, 1HR, 4HR)
else {
mid_break_warning = !work_timer.flags.mid_break &&
(current_time >= (work_timer.mid_break_time - BREAK_WARNING_TIME) &&
current_time < work_timer.mid_break_time);
end_warning = current_time >= (work_timer.end_time - BREAK_WARNING_TIME) &&
current_time < work_timer.end_time;
// Choose appropriate display based on current state
if (mid_break_warning) {
// Mid-break warning - red pulse
rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR;
// Apply pulsing effect to all progress bar LEDs
for (uint8_t i = 0; i < num_leds; i++) {
rgb_matrix_set_color(WORK_TIMER_LED_START + i,
(uint8_t)((float)pulse_color.r * pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.g * pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.b * pulse_ratio * brightness_factor));
}
}
// Mid-break active
else if (work_timer.flags.mid_break && work_timer.break_start_time != 0) {
// Mid-break active - blue pulse
rgb_color_t pulse_color = WORK_TIMER_LUNCH_COLOR;
// Use a faster pulse for mid-break reminder
uint8_t mid_pulse = abs((timer_read() / 3) % 510 - 255);
float mid_pulse_ratio = (float)mid_pulse / 255.0f;
// Apply pulsing effect to all progress bar LEDs
for (uint8_t i = 0; i < num_leds; i++) {
rgb_matrix_set_color(WORK_TIMER_LED_START + i,
(uint8_t)((float)pulse_color.r * mid_pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.g * mid_pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.b * mid_pulse_ratio * brightness_factor));
}
}
else if (work_timer.flags.end_warning_shown || end_warning) {
// End of timer warning - red pulse
rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR;
// Apply pulsing effect to all progress bar LEDs
for (uint8_t i = 0; i < num_leds; i++) {
rgb_matrix_set_color(WORK_TIMER_LED_START + i,
(uint8_t)((float)pulse_color.r * pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.g * pulse_ratio * brightness_factor),
(uint8_t)((float)pulse_color.b * pulse_ratio * brightness_factor));
}
}
else {
// Normal progress bar display
display_progress_bar(num_leds, overall_progress, brightness_factor);
// Apply blue pulse to all LEDs in progress bar
for (uint8_t i = 0; i < num_leds; i++) {
rgb_matrix_set_color(WORK_TIMER_LED_START + i,
(uint8_t)((float)color.r * break_intensity * brightness_factor),
(uint8_t)((float)color.g * break_intensity * brightness_factor),
(uint8_t)((float)color.b * break_intensity * brightness_factor));
}
} else {
// Normal progress display
display_progress_bar(num_leds, progress, brightness_factor);
}
}
/**
* Work timer task - can be called periodically
* Periodic timer task
*/
void work_timer_task(void) {
// Update work timer state
update_work_timer();
}

View File

@ -58,11 +58,6 @@ typedef enum {
#define WORK_TIMER_LUNCH_G 0
#define WORK_TIMER_LUNCH_B 255
// Warning color (red)
#define WORK_TIMER_WARNING_R 255
#define WORK_TIMER_WARNING_G 0
#define WORK_TIMER_WARNING_B 0
// Standard timer durations (in milliseconds)
// IMPORTANT: These represent actual working time (excluding breaks)
#define TIMER_30MIN_DURATION 1800000 // 30 minutes
@ -72,7 +67,7 @@ typedef enum {
#define TIMER_10HR_DURATION 36000000 // 10 hours (real world 11 hours with lunch)
// Break durations
#define BREAK_WARNING_TIME 60000 // 60 seconds
#define BREAK_WARNING_TIME 60000 // 60 seconds (kept for calculations but not used for warnings)
#define MID_BREAK_30MIN_DURATION 30000 // 30 seconds
#define MID_BREAK_1HR_DURATION 45000 // 45 seconds
#define MID_BREAK_4HR_DURATION 60000 // 60 seconds