Fix encoder pin order and enhance work timer structure with improved state management and validation

This commit is contained in:
TS Design Works 2025-05-16 07:16:34 -04:00
parent d13b6fd64b
commit cc50f2cd92
2 changed files with 204 additions and 251 deletions

View File

@ -26,7 +26,7 @@
"encoder": { "encoder": {
"enabled": true, "enabled": true,
"rotary": [ "rotary": [
{"pin_a": "GP0", "pin_b": "GP1", "resolution": 4} {"pin_a": "GP1", "pin_b": "GP0", "resolution": 4}
] ]
}, },
"features": { "features": {

View File

@ -31,32 +31,28 @@ typedef struct {
uint8_t pulse_active: 1; // Flag to track if any pulse is currently active uint8_t pulse_active: 1; // Flag to track if any pulse is currently active
} work_timer_flags_t; } work_timer_flags_t;
// Work timer state structure // Simplified work timer state structure
typedef struct { typedef struct {
work_timer_flags_t flags; work_timer_flags_t flags;
work_timer_type_t timer_type; work_timer_type_t timer_type;
uint32_t start_time; uint32_t start_time; // When timer was started
uint32_t elapsed_time; // Work time (excluding breaks) uint32_t end_time; // When timer should end (calculated)
uint32_t pause_time; uint32_t pause_time; // When pause started (if paused)
uint32_t break_start_time; // When current break started uint32_t break_start_time; // When current break started
uint32_t total_break_time; // Total accumulated break time uint32_t mid_break_time; // When mid-break should occur
uint32_t timer_duration; // Total work time duration (excludes breaks) uint32_t mid_break_duration; // How long the mid-break should last
uint32_t mid_break_start; // When in workday the break occurs bool has_lunch_break; // Whether this timer has a lunch break
uint32_t mid_break_duration;
bool has_lunch_break;
} work_timer_t; } work_timer_t;
// Global work timer state // Global work timer state with simplified initialization
static work_timer_t work_timer = { static work_timer_t work_timer = {
.flags = {0}, .flags = {0},
.timer_type = TIMER_TYPE_8HR, .timer_type = TIMER_TYPE_8HR,
.start_time = 0, .start_time = 0,
.elapsed_time = 0, .end_time = 0,
.pause_time = 0, .pause_time = 0,
.break_start_time = 0, .break_start_time = 0,
.total_break_time = 0, .mid_break_time = 0,
.timer_duration = TIMER_8HR_DURATION,
.mid_break_start = TIMER_8HR_DURATION / 2, // Default halfway point
.mid_break_duration = LUNCH_BREAK_DURATION, .mid_break_duration = LUNCH_BREAK_DURATION,
.has_lunch_break = true .has_lunch_break = true
}; };
@ -67,7 +63,6 @@ static const rgb_color_t WORK_TIMER_MID_COLOR = {WORK_TIMER_MID_R, WORK_TIMER_MI
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_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_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}; static const rgb_color_t WORK_TIMER_WARNING_COLOR = {WORK_TIMER_WARNING_R, WORK_TIMER_WARNING_G, WORK_TIMER_WARNING_B};
static const rgb_color_t WORK_TIMER_BREAK_WARNING_COLOR = {WORK_TIMER_WARNING_R, WORK_TIMER_WARNING_G, WORK_TIMER_WARNING_B};
// Function prototypes for internal functions // Function prototypes for internal functions
static void configure_timer_for_type(work_timer_type_t timer_type); static void configure_timer_for_type(work_timer_type_t timer_type);
@ -84,57 +79,56 @@ static void configure_timer_for_type(work_timer_type_t timer_type) {
switch (timer_type) { switch (timer_type) {
case TIMER_TYPE_30MIN: case TIMER_TYPE_30MIN:
work_timer.timer_duration = TIMER_30MIN_DURATION; work_timer.mid_break_time = TIMER_30MIN_DURATION / 2;
work_timer.mid_break_start = TIMER_30MIN_DURATION / 2;
work_timer.mid_break_duration = MID_BREAK_30MIN_DURATION; work_timer.mid_break_duration = MID_BREAK_30MIN_DURATION;
work_timer.has_lunch_break = false; work_timer.has_lunch_break = false;
work_timer.end_time = work_timer.start_time + TIMER_30MIN_DURATION;
break; break;
case TIMER_TYPE_1HR: case TIMER_TYPE_1HR:
work_timer.timer_duration = TIMER_1HR_DURATION; work_timer.mid_break_time = TIMER_1HR_DURATION / 2;
work_timer.mid_break_start = TIMER_1HR_DURATION / 2;
work_timer.mid_break_duration = MID_BREAK_1HR_DURATION; work_timer.mid_break_duration = MID_BREAK_1HR_DURATION;
work_timer.has_lunch_break = false; work_timer.has_lunch_break = false;
work_timer.end_time = work_timer.start_time + TIMER_1HR_DURATION;
break; break;
case TIMER_TYPE_4HR: case TIMER_TYPE_4HR:
work_timer.timer_duration = TIMER_4HR_DURATION; work_timer.mid_break_time = TIMER_4HR_DURATION / 2;
work_timer.mid_break_start = TIMER_4HR_DURATION / 2;
work_timer.mid_break_duration = MID_BREAK_4HR_DURATION; work_timer.mid_break_duration = MID_BREAK_4HR_DURATION;
work_timer.has_lunch_break = false; work_timer.has_lunch_break = false;
work_timer.end_time = work_timer.start_time + TIMER_4HR_DURATION;
break; break;
case TIMER_TYPE_8HR: case TIMER_TYPE_8HR:
work_timer.timer_duration = TIMER_8HR_DURATION; work_timer.mid_break_time = TIMER_8HR_DURATION / 2;
work_timer.mid_break_start = TIMER_8HR_DURATION / 2;
work_timer.mid_break_duration = LUNCH_BREAK_DURATION; work_timer.mid_break_duration = LUNCH_BREAK_DURATION;
work_timer.has_lunch_break = true; work_timer.has_lunch_break = true;
work_timer.end_time = work_timer.start_time + TIMER_8HR_DURATION;
break; break;
case TIMER_TYPE_10HR: case TIMER_TYPE_10HR:
work_timer.timer_duration = TIMER_10HR_DURATION; work_timer.mid_break_time = TIMER_10HR_DURATION / 2;
work_timer.mid_break_start = TIMER_10HR_DURATION / 2;
work_timer.mid_break_duration = LUNCH_BREAK_DURATION; work_timer.mid_break_duration = LUNCH_BREAK_DURATION;
work_timer.has_lunch_break = true; work_timer.has_lunch_break = true;
work_timer.end_time = work_timer.start_time + TIMER_10HR_DURATION;
break; break;
default: default:
// Default to 8HR if something goes wrong // Default to 8HR if something goes wrong
work_timer.timer_duration = TIMER_8HR_DURATION; work_timer.mid_break_time = TIMER_8HR_DURATION / 2;
work_timer.mid_break_start = TIMER_8HR_DURATION / 2;
work_timer.mid_break_duration = LUNCH_BREAK_DURATION; work_timer.mid_break_duration = LUNCH_BREAK_DURATION;
work_timer.has_lunch_break = true; work_timer.has_lunch_break = true;
work_timer.end_time = work_timer.start_time + TIMER_8HR_DURATION;
break; break;
} }
} }
/** /**
* Save the work timer state to EEPROM * Save the work timer state to EEPROM
* Modern QMK using block-based EEPROM operations for RP2040
*/ */
static void save_work_timer_state(void) { static void save_work_timer_state(void) {
// Create a buffer to store all our data // Create a buffer to store all our data
uint8_t buffer[19] = {0}; // 19 bytes total uint8_t buffer[24] = {0}; // Increased from 21 to 24 bytes to have enough space
// Set the active flag // Set the active flag
buffer[0] = work_timer.flags.active; buffer[0] = work_timer.flags.active;
@ -144,21 +138,25 @@ static void save_work_timer_state(void) {
// Save start time (4 bytes) // Save start time (4 bytes)
memcpy(&buffer[1], &work_timer.start_time, sizeof(uint32_t)); memcpy(&buffer[1], &work_timer.start_time, sizeof(uint32_t));
// Save elapsed time (4 bytes) // Save end time (4 bytes)
memcpy(&buffer[5], &work_timer.elapsed_time, sizeof(uint32_t)); memcpy(&buffer[5], &work_timer.end_time, sizeof(uint32_t));
// Save total break time (4 bytes)
memcpy(&buffer[9], &work_timer.total_break_time, sizeof(uint32_t));
// Save timer type (1 byte) // Save timer type (1 byte)
buffer[13] = (uint8_t)work_timer.timer_type; 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) // Save break state (1 byte)
buffer[14] = (work_timer.flags.lunch_break ? 1 : 0) | buffer[15] = (work_timer.flags.lunch_break ? 1 : 0) |
(work_timer.flags.mid_break ? 2 : 0); (work_timer.flags.mid_break ? 2 : 0);
// Save break start time (4 bytes) // Save break start time (4 bytes)
memcpy(&buffer[15], &work_timer.break_start_time, sizeof(uint32_t)); 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 all data at once to EEPROM
@ -167,11 +165,10 @@ static void save_work_timer_state(void) {
/** /**
* Load the work timer state from EEPROM * Load the work timer state from EEPROM
* Modern QMK using block-based EEPROM operations for RP2040
*/ */
static void load_work_timer_state(void) { static void load_work_timer_state(void) {
// Create a buffer to read all our data // Create a buffer to read all our data
uint8_t buffer[19] = {0}; // 19 bytes total uint8_t buffer[24] = {0}; // Increased from 21 to 24 bytes to match save function
// Read all data at once from EEPROM // Read all data at once from EEPROM
eeprom_read_block(buffer, (const void *)EEPROM_WORK_TIMER_ACTIVE, sizeof(buffer)); eeprom_read_block(buffer, (const void *)EEPROM_WORK_TIMER_ACTIVE, sizeof(buffer));
@ -182,86 +179,61 @@ static void load_work_timer_state(void) {
// Only process the rest if timer was active // Only process the rest if timer was active
if (work_timer.flags.active) { if (work_timer.flags.active) {
// Load timer type // Load timer type
work_timer_type_t saved_type = (work_timer_type_t)buffer[13]; work_timer_type_t saved_type = (work_timer_type_t)buffer[9];
// Apply configuration for this timer type
configure_timer_for_type(saved_type);
// Get start time (4 bytes) // Get start time (4 bytes)
memcpy(&work_timer.start_time, &buffer[1], sizeof(uint32_t)); memcpy(&work_timer.start_time, &buffer[1], sizeof(uint32_t));
// Get the elapsed work time (4 bytes) // Get end time (4 bytes)
memcpy(&work_timer.elapsed_time, &buffer[5], sizeof(uint32_t)); memcpy(&work_timer.end_time, &buffer[5], sizeof(uint32_t));
// Get the total break time (4 bytes) // Get pause state and time (5 bytes)
memcpy(&work_timer.total_break_time, &buffer[9], sizeof(uint32_t)); work_timer.flags.paused = buffer[10];
memcpy(&work_timer.pause_time, &buffer[11], sizeof(uint32_t));
// Get break state (1 byte) // Get break state (1 byte)
uint8_t break_state = buffer[14]; uint8_t break_state = buffer[15];
work_timer.flags.lunch_break = (break_state & 1) > 0; work_timer.flags.lunch_break = (break_state & 1) > 0;
work_timer.flags.mid_break = (break_state & 2) > 0; work_timer.flags.mid_break = (break_state & 2) > 0;
// Get break start time (4 bytes) // Get break start time (4 bytes)
memcpy(&work_timer.break_start_time, &buffer[15], sizeof(uint32_t)); memcpy(&work_timer.break_start_time, &buffer[16], sizeof(uint32_t));
// If in a break, adjust break_start_time to account for time powered off // 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) { if (work_timer.flags.lunch_break || work_timer.flags.mid_break) {
uint32_t current_time = timer_read32(); uint32_t current_time = timer_read32();
uint32_t time_off = current_time - work_timer.break_start_time; uint32_t time_off = current_time - work_timer.break_start_time;
// If we've been off for less than the break duration, continue the break // If we've been powered off longer than the break duration, end the break
if (work_timer.flags.lunch_break && if (time_off > work_timer.mid_break_duration) {
time_off < work_timer.mid_break_duration) {
// Stay in lunch break, adjust break_start_time
work_timer.break_start_time = current_time - time_off;
}
else if (work_timer.flags.mid_break &&
time_off < work_timer.mid_break_duration) {
// Stay in mid-break, adjust break_start_time
work_timer.break_start_time = current_time - time_off;
}
else {
// Break would have ended while powered off
work_timer.flags.lunch_break = 0; work_timer.flags.lunch_break = 0;
work_timer.flags.mid_break = 0; work_timer.flags.mid_break = 0;
// Add the remaining break time to total_break_time
// This is approximate but better than nothing
if (time_off < work_timer.mid_break_duration) {
work_timer.total_break_time += work_timer.mid_break_duration;
}
} }
} }
// Calculate elapsed wall time (including time powered off) // Validate timer values
uint32_t current_time = timer_read32(); uint32_t current_time = timer_read32();
uint32_t wall_time_elapsed = current_time - work_timer.start_time;
// Adjust start time to account for time powered off, preserving elapsed_time // If end time is in the past, timer is done
work_timer.start_time = current_time - wall_time_elapsed; if (work_timer.end_time <= current_time && !work_timer.flags.paused) {
// Validate time values - if unreasonable, reset
if (work_timer.elapsed_time > work_timer.timer_duration) {
work_timer.flags.active = 0; work_timer.flags.active = 0;
save_work_timer_state(); save_work_timer_state();
} }
// Check for end warning state // Check for end warning state (within 5 minutes of end)
if (work_timer.elapsed_time >= (work_timer.timer_duration - BREAK_WARNING_TIME)) { if (!work_timer.flags.paused &&
current_time >= (work_timer.end_time - BREAK_WARNING_TIME)) {
work_timer.flags.end_warning_shown = 1; work_timer.flags.end_warning_shown = 1;
} }
// Update pulse active state // Update pulse active state
update_pulse_active_state(); update_pulse_active_state();
// Additional validation - ensure break state is consistent
if (work_timer.flags.lunch_break || work_timer.flags.mid_break) {
// If in a break state but break_start_time is invalid, reset break state
if (work_timer.break_start_time == 0) {
work_timer.flags.lunch_break = 0;
work_timer.flags.mid_break = 0;
}
}
} }
} }
@ -342,32 +314,46 @@ static void update_pulse_active_state(void) {
return; return;
} }
uint32_t current_time = timer_read32();
// Check if any pulse condition is active // Check if any pulse condition is active
bool lunch_warning = false; bool lunch_warning = false;
bool lunch_end_warning = false; bool lunch_end_warning = false;
bool mid_point_warning = false; bool mid_point_warning = false;
bool end_warning = false; bool end_warning = false;
// For timers with lunch breaks // Mid-break (lunch) timing logic
if (work_timer.has_lunch_break) { 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 break warning (before lunch)
lunch_warning = !work_timer.flags.lunch_break && lunch_warning = !work_timer.flags.lunch_break &&
(work_timer.elapsed_time >= (work_timer.mid_break_start - BREAK_WARNING_TIME) && (time_to_mid_break > 0 && time_to_mid_break < BREAK_WARNING_TIME);
work_timer.elapsed_time < work_timer.mid_break_start);
// Lunch end warning (before end of lunch) // Lunch end warning (before end of lunch)
lunch_end_warning = work_timer.flags.lunch_break && lunch_end_warning = work_timer.flags.lunch_break &&
(timer_elapsed32(work_timer.break_start_time) >= (work_timer.mid_break_duration - BREAK_WARNING_TIME)); (timer_elapsed32(work_timer.break_start_time) >=
} else { (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 break warning for shorter timers
mid_point_warning = !work_timer.flags.mid_break && mid_point_warning = !work_timer.flags.mid_break &&
(work_timer.elapsed_time >= (work_timer.mid_break_start - BREAK_WARNING_TIME) && (time_to_mid_break > 0 && time_to_mid_break < BREAK_WARNING_TIME);
work_timer.elapsed_time < work_timer.mid_break_start);
} }
// End timer warning (5 minutes before end) // End timer warning (5 minutes before end)
end_warning = (work_timer.elapsed_time >= (work_timer.timer_duration - BREAK_WARNING_TIME) && end_warning = (current_time >= (work_timer.end_time - BREAK_WARNING_TIME) &&
work_timer.elapsed_time < work_timer.timer_duration); current_time < work_timer.end_time);
// Set pulse active if any of these conditions are true // Set pulse active if any of these conditions are true
work_timer.flags.pulse_active = ( work_timer.flags.pulse_active = (
@ -379,8 +365,6 @@ static void update_pulse_active_state(void) {
mid_point_warning || // Mid-point warning for shorter timers mid_point_warning || // Mid-point warning for shorter timers
end_warning // End warning for all timers end_warning // End warning for all timers
); );
// Removed wake functionality - no need to wake RGB matrix
} }
/** /**
@ -396,15 +380,15 @@ void toggle_work_timer(void) {
work_timer.flags.lunch_warning_shown = 0; work_timer.flags.lunch_warning_shown = 0;
work_timer.flags.mid_break_warning_shown = 0; work_timer.flags.mid_break_warning_shown = 0;
work_timer.flags.end_warning_shown = 0; work_timer.flags.end_warning_shown = 0;
work_timer.flags.pulse_active = 0; // Clear pulse active flag work_timer.flags.pulse_active = 0;
// Save complete clean state to EEPROM // Save clean state to EEPROM
save_work_timer_state(); save_work_timer_state();
// Force immediate RGB refresh to restore normal LED state // Force immediate RGB refresh
rgb_matrix_mode_noeeprom(rgb_matrix_get_mode()); rgb_matrix_mode_noeeprom(rgb_matrix_get_mode());
} else { } else {
// If timer is inactive, activate it with current settings // If timer is inactive, start a new timer
work_timer.flags.active = 1; work_timer.flags.active = 1;
work_timer.flags.paused = 0; work_timer.flags.paused = 0;
work_timer.flags.lunch_break = 0; work_timer.flags.lunch_break = 0;
@ -414,12 +398,26 @@ void toggle_work_timer(void) {
work_timer.flags.end_warning_shown = 0; work_timer.flags.end_warning_shown = 0;
work_timer.flags.pulse_active = 0; work_timer.flags.pulse_active = 0;
// Reset all time tracking variables // Set timer start and calculate end time
work_timer.start_time = timer_read32(); work_timer.start_time = timer_read32();
work_timer.elapsed_time = 0;
work_timer.pause_time = 0;
work_timer.break_start_time = 0; work_timer.break_start_time = 0;
work_timer.total_break_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(); save_work_timer_state();
} }
@ -438,9 +436,6 @@ void work_timer_init(void) {
* Start a specific timer type * Start a specific timer type
*/ */
void start_timer(work_timer_type_t timer_type) { void start_timer(work_timer_type_t timer_type) {
// Configure timer parameters based on type
configure_timer_for_type(timer_type);
// Reset timer state // Reset timer state
work_timer.flags.active = 1; work_timer.flags.active = 1;
work_timer.flags.paused = 0; work_timer.flags.paused = 0;
@ -452,10 +447,11 @@ void start_timer(work_timer_type_t timer_type) {
work_timer.flags.pulse_active = 0; work_timer.flags.pulse_active = 0;
work_timer.start_time = timer_read32(); work_timer.start_time = timer_read32();
work_timer.elapsed_time = 0;
work_timer.pause_time = 0;
work_timer.break_start_time = 0; work_timer.break_start_time = 0;
work_timer.total_break_time = 0;
// Configure timer parameters based on type
work_timer.timer_type = timer_type;
configure_timer_for_type(timer_type);
save_work_timer_state(); save_work_timer_state();
@ -475,9 +471,17 @@ void toggle_pause_work_timer(void) {
work_timer.pause_time = timer_read32(); work_timer.pause_time = timer_read32();
save_work_timer_state(); save_work_timer_state();
} else { } else {
// Resume the timer, adjust start time to account for pause duration // Resume the timer - extend all time values by pause duration
uint32_t pause_duration = timer_read32() - work_timer.pause_time; uint32_t current_time = timer_read32();
work_timer.start_time += pause_duration; uint32_t pause_duration = current_time - work_timer.pause_time;
// Extend end time by pause duration
work_timer.end_time += 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 in a break, adjust break start time too
if (work_timer.flags.lunch_break || work_timer.flags.mid_break) { if (work_timer.flags.lunch_break || work_timer.flags.mid_break) {
@ -488,7 +492,6 @@ void toggle_pause_work_timer(void) {
save_work_timer_state(); save_work_timer_state();
} }
// Update pulse state after changing pause status
update_pulse_active_state(); update_pulse_active_state();
} }
@ -498,141 +501,103 @@ void toggle_pause_work_timer(void) {
void update_work_timer(void) { void update_work_timer(void) {
if (!work_timer.flags.active || work_timer.flags.paused) return; if (!work_timer.flags.active || work_timer.flags.paused) return;
// Current time
uint32_t current_time = timer_read32(); uint32_t current_time = timer_read32();
// Calculate work time (wall time minus breaks)
uint32_t work_time;
if (work_timer.flags.lunch_break || work_timer.flags.mid_break) {
// If in a break, calculate work time as:
// (time since start - total break time - current break elapsed time)
uint32_t current_break_elapsed = timer_elapsed32(work_timer.break_start_time);
work_time = (current_time - work_timer.start_time) - work_timer.total_break_time - current_break_elapsed;
} else {
// Not in a break, work time is wall time minus total break time
work_time = (current_time - work_timer.start_time) - work_timer.total_break_time;
}
// Store the calculated work time
work_timer.elapsed_time = work_time;
// Process different timer states based on timer type // Process different timer states based on timer type
if (work_timer.has_lunch_break) { if (work_timer.has_lunch_break) {
// Handle lunch break state transitions // Handle lunch break state transitions
if (!work_timer.flags.lunch_break) { if (!work_timer.flags.lunch_break) {
// Check if it's time to start lunch // Check if it's time to start lunch
if (!work_timer.flags.lunch_warning_shown && if (!work_timer.flags.lunch_warning_shown &&
work_time >= (work_timer.mid_break_start - BREAK_WARNING_TIME) && current_time >= (work_timer.mid_break_time - BREAK_WARNING_TIME) &&
work_time < work_timer.mid_break_start) { current_time < work_timer.mid_break_time) {
// Pre-lunch warning (red pulse before lunch) // Pre-lunch warning
work_timer.flags.lunch_warning_shown = 1; work_timer.flags.lunch_warning_shown = 1;
} }
else if (work_time >= work_timer.mid_break_start) { else if (current_time >= work_timer.mid_break_time) {
// Start lunch break // Start lunch break
work_timer.flags.lunch_break = 1; work_timer.flags.lunch_break = 1;
work_timer.break_start_time = current_time; work_timer.break_start_time = current_time;
work_timer.flags.lunch_warning_shown = 0; // Reset for lunch end warning work_timer.flags.lunch_warning_shown = 0; // Reset for lunch end warning
// Save state when entering lunch break // Don't need to extend end time yet - will do that when break ends
save_work_timer_state(); save_work_timer_state();
} }
} }
else { else {
// First validate break_start_time before any other processing // Currently in lunch break
if (work_timer.break_start_time == 0) { uint32_t break_elapsed = timer_elapsed32(work_timer.break_start_time);
// Invalid break start time, force end break
// 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_break = 0;
work_timer.flags.lunch_warning_shown = 0; work_timer.flags.lunch_warning_shown = 0;
// Extend end time by break duration
work_timer.end_time += break_elapsed;
save_work_timer_state(); save_work_timer_state();
// Skip the rest of the break processing
}
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 (red pulse before end of lunch)
work_timer.flags.lunch_warning_shown = 1;
}
// End lunch break after specified duration (plus a small 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;
// Add actual break duration to total break time
work_timer.total_break_time += break_elapsed;
save_work_timer_state();
}
} }
} }
} }
else { else {
// For shorter timers without lunch breaks (30MIN, 1HR, 4HR) // Handle mid-break state transitions for shorter timers
// Handle mid-break state transitions
if (!work_timer.flags.mid_break) { if (!work_timer.flags.mid_break) {
// Check if it's time to start mid-break // Check if it's time to start mid-break
if (!work_timer.flags.mid_break_warning_shown && if (!work_timer.flags.mid_break_warning_shown &&
work_time >= (work_timer.mid_break_start - BREAK_WARNING_TIME) && current_time >= (work_timer.mid_break_time - BREAK_WARNING_TIME) &&
work_time < work_timer.mid_break_start) { current_time < work_timer.mid_break_time) {
// Mid-break warning // Mid-break warning
work_timer.flags.mid_break_warning_shown = 1; work_timer.flags.mid_break_warning_shown = 1;
} }
else if (work_time >= work_timer.mid_break_start) { else if (current_time >= work_timer.mid_break_time) {
// Start mid-break // Start mid-break
work_timer.flags.mid_break = 1; work_timer.flags.mid_break = 1;
work_timer.break_start_time = current_time; work_timer.break_start_time = current_time;
work_timer.flags.mid_break_warning_shown = 0;
save_work_timer_state(); save_work_timer_state();
} }
} }
else { else {
// First validate break_start_time before any other processing // Currently in mid-break
if (work_timer.break_start_time == 0) { uint32_t break_elapsed = timer_elapsed32(work_timer.break_start_time);
// Invalid break start time, force end break
// 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 = 0;
work_timer.flags.mid_break_warning_shown = 0; work_timer.flags.mid_break_warning_shown = 0;
save_work_timer_state();
// Skip the rest of the break processing
}
else {
// Currently in mid-break
uint32_t break_elapsed = timer_elapsed32(work_timer.break_start_time);
// End mid-break after specified duration (plus a small grace period) // Extend end time by break duration
if (break_elapsed >= (work_timer.mid_break_duration + 5000)) { work_timer.end_time += break_elapsed;
// End mid-break
work_timer.flags.mid_break = 0; save_work_timer_state();
work_timer.flags.mid_break_warning_shown = 0;
// Add actual break duration to total break time
work_timer.total_break_time += break_elapsed;
save_work_timer_state();
}
} }
} }
} }
// Check for end of day warning (5 min before end) // Check for end of day warning
if (!work_timer.flags.end_warning_shown && if (!work_timer.flags.end_warning_shown &&
work_time >= (work_timer.timer_duration - BREAK_WARNING_TIME)) { current_time >= (work_timer.end_time - BREAK_WARNING_TIME)) {
work_timer.flags.end_warning_shown = 1; work_timer.flags.end_warning_shown = 1;
} }
// Auto-stop after timer duration // Auto-stop after timer ends
if (work_time >= work_timer.timer_duration) { if (current_time >= work_timer.end_time) {
work_timer.flags.active = 0; work_timer.flags.active = 0;
work_timer.flags.lunch_break = 0; work_timer.flags.lunch_break = 0;
work_timer.flags.mid_break = 0; work_timer.flags.mid_break = 0;
save_work_timer_state(); save_work_timer_state();
} }
// Update the pulse active state
update_pulse_active_state(); update_pulse_active_state();
} }
@ -659,83 +624,71 @@ void handle_work_timer(void) {
static bool was_active = false; static bool was_active = false;
if (!work_timer.flags.active) { if (!work_timer.flags.active) {
// If the timer was just deactivated, force a complete RGB refresh // If the timer was just deactivated, force RGB refresh
if (was_active) { if (was_active) {
rgb_matrix_mode_noeeprom(rgb_matrix_get_mode()); rgb_matrix_mode_noeeprom(rgb_matrix_get_mode());
was_active = false; was_active = false;
} }
// Instead of explicitly turning off LEDs, let the RGB system handle them
return; return;
} }
was_active = true; was_active = true;
// Enhanced validation checks for break states - run on every visual update // Get current RGB matrix brightness
// to catch and correct any inconsistent timer states
if (work_timer.flags.lunch_break || work_timer.flags.mid_break) {
uint32_t break_elapsed = timer_elapsed32(work_timer.break_start_time);
uint32_t max_break_time = work_timer.mid_break_duration * 2; // Extra safety margin
// If break has been active much longer than expected (2x duration), force end it
if (break_elapsed > max_break_time) {
// Force break to end - this is an emergency failsafe
if (work_timer.flags.lunch_break) {
work_timer.flags.lunch_break = 0;
work_timer.flags.lunch_warning_shown = 0;
}
if (work_timer.flags.mid_break) {
work_timer.flags.mid_break = 0;
work_timer.flags.mid_break_warning_shown = 0;
}
// Add the actual break duration to total break time
work_timer.total_break_time += work_timer.mid_break_duration;
save_work_timer_state();
// Return early to let next frame handle normal display
return;
}
}
// Get current RGB matrix brightness value (0-255)
uint8_t rgb_brightness = rgb_matrix_get_val(); uint8_t rgb_brightness = rgb_matrix_get_val();
float brightness_factor = (float)rgb_brightness / 255.0f; float brightness_factor = (float)rgb_brightness / 255.0f;
// Simplified: No need to modify brightness - use whatever the system has
// Number of LEDs in the progress bar // Number of LEDs in the progress bar
const uint8_t num_leds = WORK_TIMER_LED_END - WORK_TIMER_LED_START + 1; const uint8_t num_leds = WORK_TIMER_LED_END - WORK_TIMER_LED_START + 1;
// Calculate overall progress (0.0 - 1.0) // Calculate overall progress (0.0 - 1.0)
float overall_progress = (float)work_timer.elapsed_time / (float)work_timer.timer_duration; 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);
} 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);
}
if (overall_progress > 1.0f) overall_progress = 1.0f; if (overall_progress > 1.0f) overall_progress = 1.0f;
// Create a pulsing effect by varying brightness based on timer // Create pulsing effect
uint8_t pulse_brightness = abs((timer_read() / 4) % 510 - 255); uint8_t pulse_brightness = abs((timer_read() / 4) % 510 - 255);
float pulse_ratio = (float)pulse_brightness / 255.0f; float pulse_ratio = (float)pulse_brightness / 255.0f;
// Check for various timer states // Check for various timer states
bool lunch_warning = false; bool lunch_warning = false;
bool lunch_end_warning = false; bool lunch_end_warning = false;
bool mid_break_warning = false;
bool end_warning = false;
// For timers with lunch breaks (8HR and 10HR) // For timers with lunch breaks
if (work_timer.has_lunch_break) { if (work_timer.has_lunch_break) {
// Pre-lunch warning (red pulse) // Pre-lunch warning (red pulse)
lunch_warning = !work_timer.flags.lunch_break && lunch_warning = !work_timer.flags.lunch_break &&
(work_timer.elapsed_time >= (work_timer.mid_break_start - BREAK_WARNING_TIME) && (current_time >= (work_timer.mid_break_time - BREAK_WARNING_TIME) &&
work_timer.elapsed_time < work_timer.mid_break_start); current_time < work_timer.mid_break_time);
// Lunch-end warning (red pulse) - Add validation for break_start_time // Lunch-end warning (red pulse)
lunch_end_warning = work_timer.flags.lunch_break && lunch_end_warning = work_timer.flags.lunch_break &&
work_timer.break_start_time != 0 && work_timer.break_start_time != 0 &&
(timer_elapsed32(work_timer.break_start_time) >= (work_timer.mid_break_duration - BREAK_WARNING_TIME)); (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 // Choose appropriate display based on current state
if (lunch_warning || lunch_end_warning) { if (lunch_warning || lunch_end_warning) {
// Pre/Post lunch red warning pulse // Pre/Post lunch red warning pulse
rgb_color_t pulse_color = WORK_TIMER_BREAK_WARNING_COLOR; rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR;
// Apply pulsing effect to all progress bar LEDs // Apply pulsing effect to all progress bar LEDs
for (uint8_t i = 0; i < num_leds; i++) { for (uint8_t i = 0; i < num_leds; i++) {
@ -746,7 +699,7 @@ void handle_work_timer(void) {
} }
} }
else if (work_timer.flags.lunch_break && work_timer.break_start_time != 0) { else if (work_timer.flags.lunch_break && work_timer.break_start_time != 0) {
// During lunch break - blue pulse, only if break_start_time is valid // During lunch break - blue pulse
rgb_color_t pulse_color = WORK_TIMER_LUNCH_COLOR; rgb_color_t pulse_color = WORK_TIMER_LUNCH_COLOR;
// Use a slower pulse for regular lunch break // Use a slower pulse for regular lunch break
@ -761,7 +714,7 @@ void handle_work_timer(void) {
(uint8_t)((float)pulse_color.b * lunch_pulse_ratio * brightness_factor)); (uint8_t)((float)pulse_color.b * lunch_pulse_ratio * brightness_factor));
} }
} }
else if (work_timer.flags.end_warning_shown) { else if (work_timer.flags.end_warning_shown || end_warning) {
// End of day warning - red pulse // End of day warning - red pulse
rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR; rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR;
@ -780,14 +733,17 @@ void handle_work_timer(void) {
} }
// For timers without lunch breaks (30MIN, 1HR, 4HR) // For timers without lunch breaks (30MIN, 1HR, 4HR)
else { else {
bool mid_break_warning = !work_timer.flags.mid_break && mid_break_warning = !work_timer.flags.mid_break &&
(work_timer.elapsed_time >= (work_timer.mid_break_start - BREAK_WARNING_TIME) && (current_time >= (work_timer.mid_break_time - BREAK_WARNING_TIME) &&
work_timer.elapsed_time < work_timer.mid_break_start); 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 // Choose appropriate display based on current state
if (mid_break_warning) { if (mid_break_warning) {
// Mid-break warning - red pulse // Mid-break warning - red pulse
rgb_color_t pulse_color = WORK_TIMER_BREAK_WARNING_COLOR; rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR;
// Apply pulsing effect to all progress bar LEDs // Apply pulsing effect to all progress bar LEDs
for (uint8_t i = 0; i < num_leds; i++) { for (uint8_t i = 0; i < num_leds; i++) {
@ -797,7 +753,7 @@ void handle_work_timer(void) {
(uint8_t)((float)pulse_color.b * pulse_ratio * brightness_factor)); (uint8_t)((float)pulse_color.b * pulse_ratio * brightness_factor));
} }
} }
// Mid-break active - only show if break_start_time is valid // Mid-break active
else if (work_timer.flags.mid_break && work_timer.break_start_time != 0) { else if (work_timer.flags.mid_break && work_timer.break_start_time != 0) {
// Mid-break active - blue pulse // Mid-break active - blue pulse
rgb_color_t pulse_color = WORK_TIMER_LUNCH_COLOR; rgb_color_t pulse_color = WORK_TIMER_LUNCH_COLOR;
@ -814,7 +770,7 @@ void handle_work_timer(void) {
(uint8_t)((float)pulse_color.b * mid_pulse_ratio * brightness_factor)); (uint8_t)((float)pulse_color.b * mid_pulse_ratio * brightness_factor));
} }
} }
else if (work_timer.flags.end_warning_shown) { else if (work_timer.flags.end_warning_shown || end_warning) {
// End of timer warning - red pulse // End of timer warning - red pulse
rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR; rgb_color_t pulse_color = WORK_TIMER_WARNING_COLOR;
@ -839,7 +795,4 @@ void handle_work_timer(void) {
void work_timer_task(void) { void work_timer_task(void) {
// Update work timer state // Update work timer state
update_work_timer(); update_work_timer();
// Add explicit call to refresh RGB matrix if needed
// This might help ensure F1-F12 get proper colors after timer state changes
} }