this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add swatch beat time

alice 667b94e3 44521a88

+130 -38
+130 -38
src/c/watchface.c
··· 2 2 #include <stdlib.h> 3 3 #include <string.h> 4 4 #include <stdint.h> 5 + #include <time.h> // Required for time_t 6 + 7 + // --- Constants --- 8 + #define HOUR_LENGTH 3600 // Seconds in an hour 9 + #define DAY_LENGTH 86400 // Seconds in a day (24 * 3600) 5 10 11 + // --- Global Variables --- 6 12 static Window *s_main_window; 7 - static TextLayer *s_time_layer; 13 + static TextLayer *s_beat_layer; // Layer for Swatch Beat Time 14 + static TextLayer *s_tid_layer; // Layer for TID Time (renamed from s_time_layer) 8 15 9 16 static const char S32_CHAR[] = "234567abcdefghijklmnopqrstuvwxyz"; 10 17 #define S32_CHAR_LEN (sizeof(S32_CHAR) - 1) // 32 ··· 73 80 } 74 81 75 82 // Generates a new TID into tid_buffer (size must be >= 14) 76 - static void now_c(char *tid_buffer, size_t tid_buffer_len) { 83 + static void now_c(time_t seconds, uint16_t milliseconds, char *tid_buffer, size_t tid_buffer_len) { 77 84 if (tid_buffer_len < 14) return; 78 85 79 - time_t seconds; 80 - uint16_t milliseconds; 81 - // Get time with millisecond precision 82 - time_ms(&seconds, &milliseconds); 83 - 84 - // Convert to microseconds (Pebble resolution) 85 86 uint64_t current_micros = (uint64_t)seconds * 1000000 + (uint64_t)milliseconds * 1000; 86 87 87 88 // Ensure monotonicity (at microsecond level) ··· 95 96 createRaw_c(current_micros, 0, tid_buffer, tid_buffer_len); 96 97 } 97 98 99 + // --- Swatch .beat Time Code --- 100 + static char s_beat_buffer[7]; // Buffer for Beat time string "@XXX.X\0" 101 + static int last_beat_time = -1; // Cache the last displayed beat time (multiplied by 10) 98 102 99 - // --- Watchface Code --- 103 + /** 104 + * Computes the current .beat time * 10 (0-9999) 105 + * @param current_seconds_utc The current time (UTC seconds since epoch) 106 + * @return The current beat time multiplied by 10. 107 + */ 108 + static int beat(time_t current_seconds_utc) { 109 + // Add one hour for Biel Mean Time (BMT) 110 + time_t now_bmt = current_seconds_utc + HOUR_LENGTH; 111 + // Calculate seconds into the current BMT day (use unsigned for safety) 112 + uint32_t day_now_bmt = now_bmt % DAY_LENGTH; 100 113 101 - static void main_window_load(Window *window) { 102 - // Get information about the Window 103 - Layer *window_layer = window_get_root_layer(window); 104 - GRect bounds = layer_get_bounds(window_layer); 114 + // Calculate beats * 10. 115 + // Cast intermediate multiplication to 64-bit to prevent overflow. 116 + int b = (int)(((uint64_t)day_now_bmt * 10000) / DAY_LENGTH); 105 117 106 - // Create the TextLayer with specific bounds 107 - s_time_layer = 108 - text_layer_create(GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50)); 118 + // Clamp result just in case of edge cases (0 - 9999) 119 + if (b > 9999) b = 9999; 120 + if (b < 0) b = 0; 121 + return b; 122 + } 109 123 110 - // Improve the layout to be more like a watchface 111 - text_layer_set_background_color(s_time_layer, GColorClear); 112 - text_layer_set_text_color(s_time_layer, GColorBlack); 113 - // text_layer_set_text(s_time_layer, "00:00"); 114 - text_layer_set_font(s_time_layer, 115 - fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD)); 116 - text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter); 124 + /** 125 + * Updates the beat time TextLayer if the time has changed. 126 + * @param current_seconds_utc The current time (UTC seconds since epoch) 127 + */ 128 + static void update_beat_time(time_t current_seconds_utc) { 129 + int b = beat(current_seconds_utc); // b is 0-9999 117 130 118 - // Add it as a child layer to the Window's root layer 119 - layer_add_child(window_layer, text_layer_get_layer(s_time_layer)); 120 - } 131 + // Only update the layer if the value has changed 132 + if (b == last_beat_time) { 133 + return; 134 + } 121 135 122 - static void main_window_unload(Window *window) { 123 - text_layer_destroy(s_time_layer); 136 + int beats_integer = b / 10; // 0-999 137 + int beats_fraction = b % 10; // 0-9 138 + 139 + // Format as @XXX.X (e.g., @083.3, @999.9) 140 + snprintf(s_beat_buffer, sizeof(s_beat_buffer), "@%03d.%d", beats_integer, beats_fraction); 141 + 142 + // Update the TextLayer 143 + text_layer_set_text(s_beat_layer, s_beat_buffer); 144 + 145 + // Cache the newly displayed value 146 + last_beat_time = b; 124 147 } 125 148 126 - static void update_time() { 127 - static char s_tid_buffer[14]; // Buffer for TID string (13 chars + null) 128 - now_c(s_tid_buffer, sizeof(s_tid_buffer)); // Generate TID 149 + // --- TID Time Update --- 150 + static char s_tid_buffer[14]; // Buffer for TID string (13 chars + null) 129 151 130 - // Display this time on the TextLayer 131 - text_layer_set_text(s_time_layer, s_tid_buffer); // Display TID 152 + /** 153 + * Updates the TID time TextLayer. 154 + * Uses provided time components for efficiency. 155 + */ 156 + static void update_tid_time(time_t seconds, uint16_t milliseconds) { 157 + // Generate the current TID into the buffer using provided time 158 + now_c(seconds, milliseconds, s_tid_buffer, sizeof(s_tid_buffer)); 159 + 160 + // Display this TID on the TextLayer 161 + // Note: TID changes every microsecond theoretically, 162 + // so we update the text layer every second regardless of visible change. 163 + text_layer_set_text(s_tid_layer, s_tid_buffer); 132 164 } 133 165 166 + 167 + // --- Pebble Window Management --- 168 + 169 + // Handles updates from the TickTimerService 134 170 static void tick_handler(struct tm *tick_time, TimeUnits units_changed) { 135 - update_time(); 171 + // Get time once for both updates 172 + time_t seconds; 173 + uint16_t milliseconds; 174 + time_ms(&seconds, &milliseconds); 175 + 176 + // Update both time displays 177 + update_beat_time(seconds); 178 + update_tid_time(seconds, milliseconds); 179 + } 180 + 181 + static void main_window_load(Window *window) { 182 + Layer *window_layer = window_get_root_layer(window); 183 + GRect bounds = layer_get_bounds(window_layer); 184 + 185 + // Define layout constants (adjust heights based on font sizes) 186 + const int16_t top_margin = 5; 187 + const int16_t bottom_margin = 12; 188 + const int16_t beat_layer_height = 30; // Approx height for FONT_KEY_GOTHIC_28_BOLD 189 + const int16_t tid_layer_height = 30; // Approx height for FONT_KEY_GOTHIC_24_BOLD 190 + 191 + // Calculate Y positions 192 + int16_t beat_y = top_margin; 193 + int16_t tid_y = bounds.size.h - tid_layer_height - bottom_margin; 194 + 195 + // Create Beat Time TextLayer (Top) 196 + s_beat_layer = text_layer_create( 197 + GRect(0, beat_y, bounds.size.w, beat_layer_height)); 198 + text_layer_set_background_color(s_beat_layer, GColorClear); 199 + text_layer_set_text_color(s_beat_layer, GColorBlack); 200 + text_layer_set_text(s_beat_layer, "@--.-"); // Initial placeholder 201 + text_layer_set_font(s_beat_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD)); // Adjust font as needed 202 + text_layer_set_text_alignment(s_beat_layer, GTextAlignmentCenter); 203 + layer_add_child(window_layer, text_layer_get_layer(s_beat_layer)); 204 + 205 + // Create TID TextLayer (Bottom) 206 + s_tid_layer = text_layer_create( 207 + GRect(0, tid_y, bounds.size.w, tid_layer_height)); 208 + text_layer_set_background_color(s_tid_layer, GColorClear); 209 + text_layer_set_text_color(s_tid_layer, GColorBlack); 210 + text_layer_set_text(s_tid_layer, "loading tid..."); // Initial placeholder 211 + text_layer_set_font(s_tid_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD)); // Adjust font as needed 212 + text_layer_set_text_alignment(s_tid_layer, GTextAlignmentCenter); 213 + layer_add_child(window_layer, text_layer_get_layer(s_tid_layer)); 214 + } 215 + 216 + static void main_window_unload(Window *window) { 217 + // Destroy TextLayers 218 + text_layer_destroy(s_beat_layer); 219 + text_layer_destroy(s_tid_layer); // Renamed from s_time_layer 136 220 } 137 221 138 222 static void init() { ··· 147 231 // Show the Window on the watch, with animated=true 148 232 window_stack_push(s_main_window, true); 149 233 150 - // Update the time immediately 151 - update_time(); 234 + // Get initial time and update display immediately 235 + time_t seconds; 236 + uint16_t milliseconds; 237 + time_ms(&seconds, &milliseconds); 238 + update_beat_time(seconds); // Initial beat time 239 + update_tid_time(seconds, milliseconds); // Initial TID time 240 + 152 241 153 - // Register with TickTimerService 242 + // Register with TickTimerService to update every second 154 243 tick_timer_service_subscribe(SECOND_UNIT, tick_handler); 155 244 } 156 245 157 - static void deinit() { window_destroy(s_main_window); } 246 + static void deinit() { 247 + // Destroy Window 248 + window_destroy(s_main_window); 249 + } 158 250 159 251 int main(void) { 160 252 init();