···11+#include "clock_noonzone.h"
22+#include <pebble.h>
33+#include <time.h> // For time_t, struct tm, gmtime
44+#include <string.h> // For NULL definition (consider stddef.h?)
55+#include <stdio.h> // For snprintf
66+77+// --- Static variables specific to Noon Zone Clock ---
88+static char s_noonzone_buffer[16]; // Buffer for "NAME:MM:SS\0"
99+static int last_noonzone_update_secs = -1;
1010+static int last_utc_hour = -1;
1111+static const char *last_zone_name_ptr = NULL;
1212+1313+// --- Static helper function ---
1414+/**
1515+ * Gets the military timezone name for the longitude where it is currently noon.
1616+ * Includes caching based on UTC hour.
1717+ */
1818+static const char* get_noon_zone_name(int utc_hour) {
1919+ if (utc_hour == last_utc_hour && last_zone_name_ptr != NULL) {
2020+ return last_zone_name_ptr;
2121+ }
2222+2323+ const char *name = "???";
2424+ switch(utc_hour){
2525+ case 12: name="ZULU"; break;
2626+ case 11: name="ALPHA"; break;
2727+ case 10: name="BRAVO"; break;
2828+ case 9: name="CHARLIE"; break;
2929+ case 8: name="DELTA"; break;
3030+ case 7: name="ECHO"; break;
3131+ case 6: name="FOXTROT"; break;
3232+ case 5: name="GOLF"; break;
3333+ case 4: name="HOTEL"; break;
3434+ case 3: name="JULIET"; break;
3535+ case 2: name="KILO"; break;
3636+ case 1: name="LIMA"; break;
3737+ case 0: name="MIKE"; break;
3838+ case 23: name="NOVEMBER"; break;
3939+ case 22: name="OSCAR"; break;
4040+ case 21: name="PAPA"; break;
4141+ case 20: name="QUEBEC"; break;
4242+ case 19: name="ROMEO"; break;
4343+ case 18: name="SIERRA"; break;
4444+ case 17: name="TANGO"; break;
4545+ case 16: name="UNIFORM"; break;
4646+ case 15: name="VICTOR"; break;
4747+ case 14: name="WHISKEY"; break;
4848+ case 13: name="X-RAY"; break;
4949+ // default: name="???"; // Already initialized
5050+ }
5151+ last_utc_hour = utc_hour;
5252+ last_zone_name_ptr = name;
5353+ return name;
5454+}
5555+5656+// --- Pebble UI Interface Functions ---
5757+5858+TextLayer* clock_noonzone_init(GRect bounds, Layer *window_layer) {
5959+ TextLayer* layer = text_layer_create(bounds);
6060+ text_layer_set_background_color(layer, GColorClear);
6161+ text_layer_set_text_color(layer, GColorBlack);
6262+ text_layer_set_text(layer, "ZONE:--:--"); // Initial placeholder
6363+ #define NOONZONE_FONT FONT_KEY_GOTHIC_18_BOLD // Keep font definitions near usage
6464+ text_layer_set_font(layer, fonts_get_system_font(NOONZONE_FONT));
6565+ text_layer_set_text_alignment(layer, GTextAlignmentCenter);
6666+ layer_add_child(window_layer, text_layer_get_layer(layer));
6767+ return layer;
6868+}
6969+7070+void clock_noonzone_deinit(TextLayer *layer) {
7171+ if (layer) {
7272+ text_layer_destroy(layer);
7373+ }
7474+}
7575+7676+void clock_noonzone_update(TextLayer *layer, time_t current_seconds_utc) {
7777+ if (!layer) return;
7878+7979+ // Check cache first to avoid unnecessary calculation/string formatting
8080+ if (current_seconds_utc == last_noonzone_update_secs) {
8181+ return;
8282+ }
8383+8484+ // Perform calculations
8585+ struct tm *utc_tm = gmtime(¤t_seconds_utc);
8686+ if (!utc_tm) {
8787+ text_layer_set_text(layer, "ERR:TIME"); // Show error on layer
8888+ last_noonzone_update_secs = current_seconds_utc; // Cache update time even on error
8989+ return;
9090+ }
9191+9292+ const char *zone_name = get_noon_zone_name(utc_tm->tm_hour);
9393+9494+ // Format string into static buffer
9595+ snprintf(s_noonzone_buffer, sizeof(s_noonzone_buffer),
9696+ "%s:%02d:%02d",
9797+ zone_name,
9898+ utc_tm->tm_min,
9999+ utc_tm->tm_sec);
100100+101101+ text_layer_set_text(layer, s_noonzone_buffer);
102102+ last_noonzone_update_secs = current_seconds_utc;
103103+}
+16
src/c/clock_noonzone.h
···11+#ifndef CLOCK_NOONZONE_H
22+#define CLOCK_NOONZONE_H
33+44+#include <pebble.h>
55+#include <stddef.h> // For size_t
66+77+// Initializes the Noon Zone clock layer
88+TextLayer* clock_noonzone_init(GRect bounds, Layer *window_layer);
99+1010+// Deinitializes the Noon Zone clock layer
1111+void clock_noonzone_deinit(TextLayer *layer);
1212+1313+// Updates the Noon Zone clock layer
1414+void clock_noonzone_update(TextLayer *layer, time_t current_seconds_utc);
1515+1616+#endif // CLOCK_NOONZONE_H
+96
src/c/clock_tid.c
···11+#include "clock_tid.h"
22+#include <pebble.h>
33+#include <string.h> // For memcpy, memset
44+#include <stdint.h> // For uint types
55+#include <stdio.h> // For snprintf
66+77+// --- Static variables specific to TID Clock ---
88+static const char S32_CHAR[] = "234567abcdefghijklmnopqrstuvwxyz";
99+#define S32_CHAR_LEN (sizeof(S32_CHAR) - 1)
1010+static uint64_t last_timestamp = 0;
1111+// Buffer needs to hold 11 (timestamp) + 2 (clock ID) + 1 (null terminator) = 14 chars
1212+static char s_tid_buffer[14]; // Buffer for TID time string "MMMSS\0"
1313+// Remove cache for the old 5-digit display (variable is now unused)
1414+// static int last_tid_time = -1;
1515+1616+// --- Static helper functions ---
1717+1818+static char* s32encode_c(uint64_t i, char *buffer, size_t buffer_len) {
1919+ if (buffer_len == 0) return NULL;
2020+ char *ptr = buffer + buffer_len;
2121+ if (i == 0) {
2222+ if (ptr > buffer) { *(--ptr) = S32_CHAR[0]; return ptr; }
2323+ else { return NULL; }
2424+ }
2525+ while (i > 0 && ptr > buffer) {
2626+ uint8_t remainder = i & 31;
2727+ i >>= 5;
2828+ *(--ptr) = S32_CHAR[remainder];
2929+ }
3030+ return ptr;
3131+}
3232+3333+static void createRaw_c(uint64_t timestamp, char *tid_buffer, size_t tid_buffer_len) {
3434+ if (tid_buffer_len < 14) return;
3535+3636+ char ts_temp_buffer[11];
3737+ char* encoded_ts_start = s32encode_c(timestamp, ts_temp_buffer, sizeof(ts_temp_buffer));
3838+ size_t encoded_ts_len = encoded_ts_start ? (ts_temp_buffer + sizeof(ts_temp_buffer)) - encoded_ts_start : 0;
3939+4040+ memset(tid_buffer, S32_CHAR[0], 11);
4141+ if (encoded_ts_len > 0 && encoded_ts_len <= 11) {
4242+ memcpy(tid_buffer + (11 - encoded_ts_len), encoded_ts_start, encoded_ts_len);
4343+ } else if (encoded_ts_len > 11) {
4444+ memcpy(tid_buffer, encoded_ts_start + (encoded_ts_len - 11), 11);
4545+ }
4646+4747+ tid_buffer[11] = S32_CHAR[0];
4848+ tid_buffer[12] = S32_CHAR[0];
4949+ tid_buffer[13] = '\0';
5050+}
5151+5252+/**
5353+ * Generates a TID string for the given time into the provided buffer.
5454+ * Ensures monotonicity using a static variable internally.
5555+ */
5656+void clock_tid_get_string(char *tid_buffer, size_t tid_buffer_len, time_t seconds, uint16_t milliseconds) {
5757+ if (tid_buffer_len < 14) return; // Ensure buffer is large enough
5858+5959+ uint64_t current_micros = (uint64_t)seconds * 1000000 + (uint64_t)milliseconds * 1000;
6060+6161+ if (current_micros <= last_timestamp) {
6262+ current_micros = last_timestamp + 1;
6363+ }
6464+ last_timestamp = current_micros;
6565+ createRaw_c(current_micros, tid_buffer, tid_buffer_len);
6666+}
6767+6868+// --- Pebble UI Interface Functions ---
6969+7070+TextLayer* clock_tid_init(GRect bounds, Layer *window_layer) {
7171+ TextLayer* layer = text_layer_create(bounds);
7272+ text_layer_set_background_color(layer, GColorClear);
7373+ text_layer_set_text_color(layer, GColorBlack);
7474+ text_layer_set_text(layer, "-----"); // Initial placeholder
7575+ #define TID_FONT FONT_KEY_GOTHIC_18_BOLD // Keep font definitions near usage
7676+ text_layer_set_font(layer, fonts_get_system_font(TID_FONT));
7777+ text_layer_set_text_alignment(layer, GTextAlignmentCenter);
7878+ layer_add_child(window_layer, text_layer_get_layer(layer));
7979+ return layer;
8080+}
8181+8282+void clock_tid_deinit(TextLayer *layer) {
8383+ if (layer) {
8484+ text_layer_destroy(layer);
8585+ }
8686+}
8787+8888+void clock_tid_update(TextLayer *layer, time_t current_seconds_utc, uint16_t current_milliseconds) {
8989+ if (!layer) return;
9090+9191+ // Generate the full TID string into the static buffer
9292+ clock_tid_get_string(s_tid_buffer, sizeof(s_tid_buffer), current_seconds_utc, current_milliseconds);
9393+9494+ // Update the TextLayer
9595+ text_layer_set_text(layer, s_tid_buffer);
9696+}
+17
src/c/clock_tid.h
···11+#ifndef CLOCK_TID_H
22+#define CLOCK_TID_H
33+44+#include <pebble.h>
55+#include <stddef.h> // For size_t
66+#include <stdint.h> // For uint16_t
77+88+// Initializes the TID clock layer
99+TextLayer* clock_tid_init(GRect bounds, Layer *window_layer);
1010+1111+// Deinitializes the TID clock layer
1212+void clock_tid_deinit(TextLayer *layer);
1313+1414+// Updates the TID clock layer
1515+void clock_tid_update(TextLayer *layer, time_t current_seconds_utc, uint16_t current_milliseconds);
1616+1717+#endif // CLOCK_TID_H
+26-439
src/c/watchface.c
···11#include <pebble.h>
22#include <stdlib.h>
33-#include <string.h>
44-#include <stdint.h>
55-#include <time.h> // Required for time_t
66-#include <math.h> // Required for fabsf
77-#include <stdbool.h> // Required for bool type
33+#include <time.h> // Required for time_t, rand(), srand()
8499-// --- Include Generated Timezone Data ---
1010-// This assumes tz_list.c defines TzInfo, tz_list[], and tz_list_count
1111-#include "tz_list.c"
1212-1313-// --- Constants ---
1414-#define HOUR_LENGTH 3600 // Seconds in an hour
1515-#define DAY_LENGTH 86400 // Seconds in a day (24 * 3600)
55+// --- Clock Module Includes ---
66+#include "clock_beat.h"
77+#include "clock_noonzone.h"
88+#include "clock_closest_noon.h"
99+#include "clock_tid.h"
16101717-// --- Global Variables ---
1111+// --- Window and Layer Globals ---
1812static Window *s_main_window;
1913static TextLayer *s_beat_layer; // Layer for Swatch Beat Time
2020-static TextLayer *s_tid_layer; // Layer for TID Time (renamed from s_time_layer)
1414+static TextLayer *s_tid_layer; // Layer for TID Time
2115static TextLayer *s_noonzone_layer; // Layer for Noon Zone Time
2216static TextLayer *s_closest_noon_layer; // Layer for Closest-to-Noon TZ
23172424-static const char S32_CHAR[] = "234567abcdefghijklmnopqrstuvwxyz";
2525-#define S32_CHAR_LEN (sizeof(S32_CHAR) - 1) // 32
2626-2727-static uint64_t last_timestamp = 0;
2828-2929-// Encodes 'i' into 'buffer' (size 'buffer_len').
3030-// Returns a pointer to the start of the encoded string within the buffer.
3131-// Fills from the end. Result is NOT null-terminated by this function itself.
3232-static char* s32encode_c(uint64_t i, char *buffer, size_t buffer_len) {
3333- if (buffer_len == 0) return NULL;
3434-3535- char *ptr = buffer + buffer_len; // Point *past* the end
3636-3737- // Handle 0 case directly if timestamp/clockid can be 0
3838- if (i == 0 && ptr > buffer) {
3939- *(--ptr) = S32_CHAR[0]; // '2'
4040- return ptr;
4141- }
4242-4343- // Encode the number from right to left
4444- while (i > 0 && ptr > buffer) {
4545- // Optimize: Use bitwise operations for division/modulo by 32 (2^5)
4646- uint8_t remainder = i & 31; // i % 32
4747- i >>= 5; // i / 32
4848- *(--ptr) = S32_CHAR[remainder]; // Place character and move pointer left
4949- }
5050-5151- // If i is still > 0 here, the buffer was too small for the number.
5252- // This shouldn't happen for timestamp (11 chars) or clockid (2 chars).
5353-5454- return ptr; // Pointer to the first character written
5555-}
5656-5757-5858-// Creates a TID in tid_buffer (size must be >= 14)
5959-static void createRaw_c(uint64_t timestamp, uint16_t clockid, char *tid_buffer, size_t tid_buffer_len) {
6060- if (tid_buffer_len < 14) return; // Need space for 13 chars + null terminator
6161-6262- // --- Timestamp Encoding (11 chars) ---
6363- char ts_temp_buffer[11];
6464- char* encoded_ts_start = s32encode_c(timestamp, ts_temp_buffer, sizeof(ts_temp_buffer));
6565- size_t encoded_ts_len = (ts_temp_buffer + sizeof(ts_temp_buffer)) - encoded_ts_start;
6666-6767- // Pad beginning with '2'
6868- memset(tid_buffer, '2', 11);
6969- // Copy encoded part to the end of the 11-char section
7070- if (encoded_ts_start && encoded_ts_len > 0) {
7171- if (encoded_ts_len <= 11) {
7272- memcpy(tid_buffer + (11 - encoded_ts_len), encoded_ts_start, encoded_ts_len);
7373- } else {
7474- // Timestamp too large? Copy last 11 chars.
7575- memcpy(tid_buffer, encoded_ts_start + (encoded_ts_len - 11), 11);
7676- }
7777- }
7878- // If timestamp was 0, encoded_ts_len is 1 ('2'), correctly placed by the above.
7979-8080-8181- // --- Hardcoded Clock ID ("22") ---
8282- // The new logic always appends "22", ignoring the clockid parameter.
8383- tid_buffer[11] = S32_CHAR[0]; // '2'
8484- tid_buffer[12] = S32_CHAR[0]; // '2'
8585-8686- // Null-terminate the final string
8787- tid_buffer[13] = '\0';
8888-}
8989-9090-// Generates a new TID into tid_buffer (size must be >= 14)
9191-static void now_c(time_t seconds, uint16_t milliseconds, char *tid_buffer, size_t tid_buffer_len) {
9292- if (tid_buffer_len < 14) return;
9393-9494- uint64_t current_micros = (uint64_t)seconds * 1000000 + (uint64_t)milliseconds * 1000;
9595-9696- // Ensure monotonicity (at microsecond level)
9797- if (current_micros <= last_timestamp) {
9898- current_micros = last_timestamp + 1;
9999- }
100100- last_timestamp = current_micros;
101101-102102- // Create the final TID string
103103- // Pass 0 for clockid, although it's ignored by the modified createRaw_c
104104- createRaw_c(current_micros, 0, tid_buffer, tid_buffer_len);
105105-}
106106-107107-// --- Swatch .beat Time Code ---
108108-static char s_beat_buffer[7]; // Buffer for Beat time string "@XXX.X\0"
109109-static int last_beat_time = -1; // Cache the last displayed beat time (multiplied by 10)
110110-111111-/**
112112- * Computes the current .beat time * 10 (0-9999)
113113- * @param current_seconds_utc The current time (UTC seconds since epoch)
114114- * @return The current beat time multiplied by 10.
115115- */
116116-static int beat(time_t current_seconds_utc) {
117117- // Add one hour for Biel Mean Time (BMT)
118118- time_t now_bmt = current_seconds_utc + HOUR_LENGTH;
119119- // Calculate seconds into the current BMT day (use unsigned for safety)
120120- uint32_t day_now_bmt = now_bmt % DAY_LENGTH;
121121-122122- // Calculate beats * 10.
123123- // Cast intermediate multiplication to 64-bit to prevent overflow.
124124- int b = (int)(((uint64_t)day_now_bmt * 10000) / DAY_LENGTH);
125125-126126- // Clamp result just in case of edge cases (0 - 9999)
127127- if (b > 9999) b = 9999;
128128- return b;
129129-}
130130-131131-/**
132132- * Updates the beat time TextLayer if the time has changed.
133133- * @param current_seconds_utc The current time (UTC seconds since epoch)
134134- */
135135-static void update_beat_time(time_t current_seconds_utc) {
136136- int b = beat(current_seconds_utc); // b is 0-9999
137137-138138- // Only update the layer if the value has changed
139139- if (b == last_beat_time) {
140140- return;
141141- }
142142-143143- int beats_integer = b / 10; // 0-999
144144- int beats_fraction = b % 10; // 0-9
145145-146146- // Format as @XXX.X (e.g., @083.3, @999.9)
147147- snprintf(s_beat_buffer, sizeof(s_beat_buffer), "@%03d.%d", beats_integer, beats_fraction);
148148-149149- // Update the TextLayer
150150- text_layer_set_text(s_beat_layer, s_beat_buffer);
151151-152152- // Cache the newly displayed value
153153- last_beat_time = b;
154154-}
155155-156156-// --- Noon Zone Time Code ---
157157-static char s_noonzone_buffer[16]; // Buffer for "NAME:MM:SS\0"
158158-static int last_noonzone_update_secs = -1; // Cache full secs for update check
159159-static int last_utc_hour = -1; // Cache hour for zone name lookup
160160-static const char *last_zone_name_ptr = NULL; // Cache pointer to zone name string
161161-162162-/**
163163- * Gets the military timezone name for the longitude where it is currently noon,
164164- * based on the provided UTC hour.
165165- * Uses caching to avoid repeated lookups for the same hour.
166166- */
167167-static const char* get_noon_zone_name(int utc_hour) {
168168- // Check cache first
169169- if (utc_hour == last_utc_hour && last_zone_name_ptr != NULL) {
170170- return last_zone_name_ptr;
171171- }
172172-173173- const char *name = "???"; // Default for unexpected hours
174174- switch(utc_hour){
175175- // Cases map UTC hour to the zone where it's noon
176176- case 12: name="ZULU"; break;
177177- case 11: name="ALPHA"; break;
178178- case 10: name="BRAVO"; break;
179179- case 9: name="CHARLIE"; break;
180180- case 8: name="DELTA"; break;
181181- case 7: name="ECHO"; break;
182182- case 6: name="FOXTROT"; break;
183183- case 5: name="GOLF"; break;
184184- case 4: name="HOTEL"; break;
185185- // INDIA is skipped
186186- case 3: name="JULIET"; break;
187187- case 2: name="KILO"; break;
188188- case 1: name="LIMA"; break;
189189- case 0: name="MIKE"; break; // or YANKEE
190190- // Other half of the day (wrapping around)
191191- case 23: name="NOVEMBER"; break;
192192- case 22: name="OSCAR"; break;
193193- case 21: name="PAPA"; break;
194194- case 20: name="QUEBEC"; break;
195195- case 19: name="ROMEO"; break;
196196- case 18: name="SIERRA"; break;
197197- case 17: name="TANGO"; break;
198198- case 16: name="UNIFORM"; break;
199199- case 15: name="VICTOR"; break;
200200- case 14: name="WHISKEY"; break;
201201- case 13: name="X-RAY"; break;
202202- }
203203-204204- // Update cache
205205- last_utc_hour = utc_hour;
206206- last_zone_name_ptr = name;
207207- return name;
208208-}
209209-210210-/**
211211- * Updates the Noon Zone time TextLayer if the time (seconds) has changed.
212212- */
213213-static void update_noonzone_time(time_t current_seconds_utc) {
214214- // Check if the second has changed since the last update
215215- if (current_seconds_utc == last_noonzone_update_secs) {
216216- return;
217217- }
218218-219219- struct tm *utc_tm = gmtime(¤t_seconds_utc);
220220- if (!utc_tm) { // Check if gmtime failed
221221- return;
222222- }
223223-224224- const char *zone_name = get_noon_zone_name(utc_tm->tm_hour);
225225-226226- // Format as NAME:MM:SS
227227- snprintf(s_noonzone_buffer, sizeof(s_noonzone_buffer),
228228- "%s:%02d:%02d",
229229- zone_name,
230230- utc_tm->tm_min,
231231- utc_tm->tm_sec);
232232-233233- text_layer_set_text(s_noonzone_layer, s_noonzone_buffer);
234234-235235- // Cache the time of this update
236236- last_noonzone_update_secs = current_seconds_utc;
237237-}
238238-239239-// --- Closest to Noon Timezone Code ---
240240-#define NOON_SECONDS (12 * 3600L) // Noon in seconds past midnight
241241-static char s_closest_noon_buffer[32]; // Buffer for "City Name:MM:SS\0"
242242-static int last_closest_noon_update_secs = -1; // Cache based on seconds
243243-static int last_closest_candidate_indices[TZ_LIST_COUNT]; // Cache indices of previous winners
244244-static int last_closest_candidate_count = 0; // Cache count of previous winners
245245-static const char* last_chosen_closest_name = NULL; // Cache the specific name pointer displayed
246246-247247-/**
248248- * Comparison function for qsort (integers).
249249- */
250250-static int compare_ints(const void *a, const void *b) {
251251- return (*(int*)a - *(int*)b);
252252-}
253253-254254-/**
255255- * Checks if two arrays of integers (candidate indices) are identical.
256256- * Assumes arrays are sorted beforehand.
257257- */
258258-static bool are_candidate_sets_equal(int* set1, int count1, int* set2, int count2) {
259259- if (count1 != count2) {
260260- return false;
261261- }
262262- // Assumes counts are equal now
263263- for (int i = 0; i < count1; ++i) {
264264- if (set1[i] != set2[i]) {
265265- return false;
266266- }
267267- }
268268- return true;
269269-}
270270-271271-/**
272272- * Updates the Closest-to-Noon timezone TextLayer if the second has changed.
273273- */
274274-static void update_closest_noon_time(time_t current_seconds_utc) {
275275- // --- Caching ---
276276- if (current_seconds_utc == last_closest_noon_update_secs) {
277277- return;
278278- }
279279-280280- // --- Get Current UTC MM:SS ---
281281- struct tm *utc_tm = gmtime(¤t_seconds_utc);
282282- if (!utc_tm) return;
283283- int utc_min = utc_tm->tm_min;
284284- int utc_sec = utc_tm->tm_sec;
285285-286286- // --- Calculate UTC seconds past midnight ---
287287- // Note: tm_yday is 0-365, time_t is secs since epoch. Simpler to use modulo.
288288- uint32_t utc_seconds_today = current_seconds_utc % DAY_LENGTH;
289289-290290- // --- Find Timezone Closest to Noon ---
291291- long min_diff_secs = DAY_LENGTH; // Init with impossibly large difference
292292- int current_candidate_indices[TZ_LIST_COUNT]; // Store indices of current winners
293293- int current_candidate_count = 0;
294294-295295- for (int i = 0; i < TZ_LIST_COUNT; ++i) {
296296- // Calculate offset in seconds (handle float)
297297- long offset_seconds = (long)(tz_list[i].offset_hours * 3600.0f);
298298-299299- // Calculate local time in seconds past midnight (handle wrap around DAY_LENGTH)
300300- long local_seconds_today = (long)utc_seconds_today + offset_seconds;
301301- // Modulo that handles negative results correctly
302302- local_seconds_today = (local_seconds_today % DAY_LENGTH + DAY_LENGTH) % DAY_LENGTH;
303303-304304- // Calculate the shortest difference to noon (around the 24h clock)
305305- long diff1 = labs(local_seconds_today - NOON_SECONDS); // labs for long
306306- long current_min_diff = (diff1 <= DAY_LENGTH / 2) ? diff1 : DAY_LENGTH - diff1;
307307-308308- // --- Update candidate list ---
309309- if (current_min_diff < min_diff_secs) {
310310- // New minimum found
311311- min_diff_secs = current_min_diff;
312312- current_candidate_indices[0] = i;
313313- current_candidate_count = 1;
314314- } else if (current_min_diff == min_diff_secs) {
315315- // Tie found, add to candidates (if space permits - should be fine)
316316- if (current_candidate_count < TZ_LIST_COUNT) { // Safety check
317317- current_candidate_indices[current_candidate_count++] = i;
318318- }
319319- }
320320- }
321321-322322- // --- Select Final Timezone and Name ---
323323- const char *final_name = "???";
324324-325325- // Sort current candidates for comparison
326326- if (current_candidate_count > 1) {
327327- qsort(current_candidate_indices, current_candidate_count, sizeof(int), compare_ints);
328328- }
329329-330330- // Check if the winning set is the same as last time
331331- bool reuse_last_name = false;
332332- if (last_chosen_closest_name != NULL) { // Only reuse if we have a previous name
333333- // Assume last_closest_candidate_indices is already sorted from previous run
334334- if (are_candidate_sets_equal(current_candidate_indices, current_candidate_count,
335335- last_closest_candidate_indices, last_closest_candidate_count)) {
336336- reuse_last_name = true;
337337- final_name = last_chosen_closest_name; // Tentatively reuse
338338- }
339339- }
340340-341341- // If not reusing, or first time, perform selection
342342- if (!reuse_last_name) {
343343- if (current_candidate_count > 0) {
344344- int chosen_list_index;
345345- if (current_candidate_count == 1) {
346346- chosen_list_index = current_candidate_indices[0];
347347- } else {
348348- // Randomly select among tied candidates
349349- chosen_list_index = current_candidate_indices[rand() % current_candidate_count];
350350- }
351351-352352- // Select random name if multiple exist for the chosen offset
353353- const TzInfo *chosen_tz = &tz_list[chosen_list_index];
354354- if (chosen_tz->name_count > 0) {
355355- int name_index = (chosen_tz->name_count == 1) ? 0 : (rand() % chosen_tz->name_count);
356356- if (name_index < chosen_tz->name_count) { // Bounds check
357357- final_name = chosen_tz->names[name_index].name;
358358- }
359359- }
360360-361361- // --- Update Cache for next time ---
362362- last_chosen_closest_name = final_name; // Cache the chosen name pointer
363363- // Copy current candidates to last candidates cache (already sorted)
364364- memcpy(last_closest_candidate_indices, current_candidate_indices, current_candidate_count * sizeof(int));
365365- last_closest_candidate_count = current_candidate_count;
366366-367367- } else {
368368- // Should not happen if tz_list is not empty, but handle defensively
369369- last_chosen_closest_name = NULL; // Reset cache if no candidates found
370370- last_closest_candidate_count = 0;
371371- }
372372- } // end selection block
373373-374374- // --- Format Output and Update Layer ---
375375- // Use the determined final_name (either reused or newly selected)
376376- snprintf(s_closest_noon_buffer, sizeof(s_closest_noon_buffer),
377377- "%s:%02d:%02d", final_name, utc_min, utc_sec);
378378-379379- text_layer_set_text(s_closest_noon_layer, s_closest_noon_buffer);
380380-381381- // Cache the update time
382382- last_closest_noon_update_secs = current_seconds_utc;
383383-}
384384-385385-// --- TID Time Update ---
386386-static char s_tid_buffer[14]; // Buffer for TID string (13 chars + null)
387387-388388-/**
389389- * Updates the TID time TextLayer.
390390- * Uses provided time components for efficiency.
391391- */
392392-static void update_tid_time(time_t seconds, uint16_t milliseconds) {
393393- // Generate the current TID into the buffer using provided time
394394- now_c(seconds, milliseconds, s_tid_buffer, sizeof(s_tid_buffer));
395395-396396- // Display this TID on the TextLayer
397397- // Note: TID changes every microsecond theoretically,
398398- // so we update the text layer every second regardless of visible change.
399399- text_layer_set_text(s_tid_layer, s_tid_buffer);
400400-}
401401-402402-40318// --- Pebble Window Management ---
4041940520// Handles updates from the TickTimerService
···41025 time_ms(&seconds, &milliseconds);
4112641227 // Update both time displays
413413- update_beat_time(seconds);
414414- update_tid_time(seconds, milliseconds);
415415- update_noonzone_time(seconds);
416416- update_closest_noon_time(seconds);
2828+ clock_beat_update(s_beat_layer, seconds);
2929+ clock_tid_update(s_tid_layer, seconds, milliseconds);
3030+ clock_noonzone_update(s_noonzone_layer, seconds);
3131+ clock_closest_noon_update(s_closest_noon_layer, seconds);
41732}
4183341934static void main_window_load(Window *window) {
···44964 int16_t tid_y = current_y;
4506545166 // Create Beat Time TextLayer (Top)
452452- s_beat_layer = text_layer_create(
453453- GRect(0, beat_y, bounds.size.w, beat_h));
454454- text_layer_set_background_color(s_beat_layer, GColorClear);
455455- text_layer_set_text_color(s_beat_layer, GColorBlack);
456456- text_layer_set_text(s_beat_layer, "@--.-"); // Initial placeholder
457457- text_layer_set_font(s_beat_layer, fonts_get_system_font(BEAT_FONT));
458458- text_layer_set_text_alignment(s_beat_layer, GTextAlignmentCenter);
459459- layer_add_child(window_layer, text_layer_get_layer(s_beat_layer));
6767+ s_beat_layer = clock_beat_init(GRect(0, beat_y, bounds.size.w, beat_h), window_layer);
4606846169 // Create Noon Zone Time TextLayer (Middle)
462462- s_noonzone_layer = text_layer_create(
463463- GRect(0, noonzone_y, bounds.size.w, noonzone_h));
464464- text_layer_set_background_color(s_noonzone_layer, GColorClear);
465465- text_layer_set_text_color(s_noonzone_layer, GColorBlack);
466466- text_layer_set_text(s_noonzone_layer, "ZONE:--:--"); // Initial placeholder
467467- text_layer_set_font(s_noonzone_layer, fonts_get_system_font(NOONZONE_FONT));
468468- text_layer_set_text_alignment(s_noonzone_layer, GTextAlignmentCenter);
469469- layer_add_child(window_layer, text_layer_get_layer(s_noonzone_layer));
7070+ s_noonzone_layer = clock_noonzone_init(GRect(0, noonzone_y, bounds.size.w, noonzone_h), window_layer);
4707147172 // Create Closest Noon Time TextLayer (Middle-Bottom)
472472- s_closest_noon_layer = text_layer_create(
473473- GRect(0, closest_y, bounds.size.w, closest_h));
474474- text_layer_set_background_color(s_closest_noon_layer, GColorClear);
475475- text_layer_set_text_color(s_closest_noon_layer, GColorBlack);
476476- text_layer_set_text(s_closest_noon_layer, "City:--:--"); // Initial placeholder
477477- text_layer_set_font(s_closest_noon_layer, fonts_get_system_font(CLOSEST_FONT));
478478- text_layer_set_text_alignment(s_closest_noon_layer, GTextAlignmentCenter);
479479- layer_add_child(window_layer, text_layer_get_layer(s_closest_noon_layer));
7373+ s_closest_noon_layer = clock_closest_noon_init(GRect(0, closest_y, bounds.size.w, closest_h), window_layer);
4807448175 // Create TID TextLayer (Bottom)
482482- s_tid_layer = text_layer_create(
483483- GRect(0, tid_y, bounds.size.w, tid_h));
484484- text_layer_set_background_color(s_tid_layer, GColorClear);
485485- text_layer_set_text_color(s_tid_layer, GColorBlack);
486486- text_layer_set_text(s_tid_layer, "loading tid..."); // Initial placeholder
487487- text_layer_set_font(s_tid_layer, fonts_get_system_font(TID_FONT));
488488- text_layer_set_text_alignment(s_tid_layer, GTextAlignmentCenter);
489489- layer_add_child(window_layer, text_layer_get_layer(s_tid_layer));
7676+ s_tid_layer = clock_tid_init(GRect(0, tid_y, bounds.size.w, tid_h), window_layer);
49077}
4917849279static void main_window_unload(Window *window) {
49380 // Destroy TextLayers
494494- text_layer_destroy(s_beat_layer);
495495- text_layer_destroy(s_tid_layer); // Renamed from s_time_layer
496496- text_layer_destroy(s_noonzone_layer);
497497- text_layer_destroy(s_closest_noon_layer);
8181+ clock_beat_deinit(s_beat_layer);
8282+ clock_noonzone_deinit(s_noonzone_layer);
8383+ clock_closest_noon_deinit(s_closest_noon_layer);
8484+ clock_tid_deinit(s_tid_layer);
49885}
4998650087static void init() {
8888+ // Seed random number generator (used by closest noon clock)
8989+ srand(time(NULL));
9090+50191 // Create main Window element and assign to pointer
50292 s_main_window = window_create();
50393···512102 // Get initial time and update display immediately
513103 time_t seconds;
514104 uint16_t milliseconds;
515515- time_ms(&seconds, &milliseconds);
516516- update_beat_time(seconds); // Initial beat time
517517- update_tid_time(seconds, milliseconds); // Initial TID time
518518- update_noonzone_time(seconds); // Initial noon zone time
519519- update_closest_noon_time(seconds); // Initial closest noon time
520520-105105+ time_ms(&seconds, &milliseconds); // Call only once
106106+ // Initial updates can be skipped if layers show placeholders,
107107+ // tick_handler will update them shortly after load.
521108522109 // Register with TickTimerService to update every second
523110 tick_timer_service_subscribe(SECOND_UNIT, tick_handler);