···11+#include <pebble.h>
22+#include <stdlib.h>
33+#include <string.h>
44+#include <stdint.h>
55+66+static Window *s_main_window;
77+static TextLayer *s_time_layer;
88+99+static const char S32_CHAR[] = "234567abcdefghijklmnopqrstuvwxyz";
1010+#define S32_CHAR_LEN (sizeof(S32_CHAR) - 1) // 32
1111+1212+static uint64_t last_timestamp = 0;
1313+1414+// Encodes 'i' into 'buffer' (size 'buffer_len').
1515+// Returns a pointer to the start of the encoded string within the buffer.
1616+// Fills from the end. Result is NOT null-terminated by this function itself.
1717+static char* s32encode_c(uint64_t i, char *buffer, size_t buffer_len) {
1818+ if (buffer_len == 0) return NULL;
1919+2020+ char *ptr = buffer + buffer_len; // Point *past* the end
2121+2222+ // Handle 0 case directly if timestamp/clockid can be 0
2323+ if (i == 0 && ptr > buffer) {
2424+ *(--ptr) = S32_CHAR[0]; // '2'
2525+ return ptr;
2626+ }
2727+2828+ // Encode the number from right to left
2929+ while (i > 0 && ptr > buffer) {
3030+ // Optimize: Use bitwise operations for division/modulo by 32 (2^5)
3131+ uint8_t remainder = i & 31; // i % 32
3232+ i >>= 5; // i / 32
3333+ *(--ptr) = S32_CHAR[remainder]; // Place character and move pointer left
3434+ }
3535+3636+ // If i is still > 0 here, the buffer was too small for the number.
3737+ // This shouldn't happen for timestamp (11 chars) or clockid (2 chars).
3838+3939+ return ptr; // Pointer to the first character written
4040+}
4141+4242+4343+// Creates a TID in tid_buffer (size must be >= 14)
4444+static void createRaw_c(uint64_t timestamp, uint16_t clockid, char *tid_buffer, size_t tid_buffer_len) {
4545+ if (tid_buffer_len < 14) return; // Need space for 13 chars + null terminator
4646+4747+ // --- Timestamp Encoding (11 chars) ---
4848+ char ts_temp_buffer[11];
4949+ char* encoded_ts_start = s32encode_c(timestamp, ts_temp_buffer, sizeof(ts_temp_buffer));
5050+ size_t encoded_ts_len = (ts_temp_buffer + sizeof(ts_temp_buffer)) - encoded_ts_start;
5151+5252+ // Pad beginning with '2'
5353+ memset(tid_buffer, '2', 11);
5454+ // Copy encoded part to the end of the 11-char section
5555+ if (encoded_ts_start && encoded_ts_len > 0) {
5656+ if (encoded_ts_len <= 11) {
5757+ memcpy(tid_buffer + (11 - encoded_ts_len), encoded_ts_start, encoded_ts_len);
5858+ } else {
5959+ // Timestamp too large? Copy last 11 chars.
6060+ memcpy(tid_buffer, encoded_ts_start + (encoded_ts_len - 11), 11);
6161+ }
6262+ }
6363+ // If timestamp was 0, encoded_ts_len is 1 ('2'), correctly placed by the above.
6464+6565+6666+ // --- Hardcoded Clock ID ("22") ---
6767+ // The new logic always appends "22", ignoring the clockid parameter.
6868+ tid_buffer[11] = S32_CHAR[0]; // '2'
6969+ tid_buffer[12] = S32_CHAR[0]; // '2'
7070+7171+ // Null-terminate the final string
7272+ tid_buffer[13] = '\0';
7373+}
7474+7575+// Generates a new TID into tid_buffer (size must be >= 14)
7676+static void now_c(char *tid_buffer, size_t tid_buffer_len) {
7777+ if (tid_buffer_len < 14) return;
7878+7979+ time_t seconds;
8080+ uint16_t milliseconds;
8181+ // Get time with millisecond precision
8282+ time_ms(&seconds, &milliseconds);
8383+8484+ // Convert to microseconds (Pebble resolution)
8585+ uint64_t current_micros = (uint64_t)seconds * 1000000 + (uint64_t)milliseconds * 1000;
8686+8787+ // Ensure monotonicity (at microsecond level)
8888+ if (current_micros <= last_timestamp) {
8989+ current_micros = last_timestamp + 1;
9090+ }
9191+ last_timestamp = current_micros;
9292+9393+ // Create the final TID string
9494+ // Pass 0 for clockid, although it's ignored by the modified createRaw_c
9595+ createRaw_c(current_micros, 0, tid_buffer, tid_buffer_len);
9696+}
9797+9898+9999+// --- Watchface Code ---
100100+101101+static void main_window_load(Window *window) {
102102+ // Get information about the Window
103103+ Layer *window_layer = window_get_root_layer(window);
104104+ GRect bounds = layer_get_bounds(window_layer);
105105+106106+ // Create the TextLayer with specific bounds
107107+ s_time_layer =
108108+ text_layer_create(GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50));
109109+110110+ // Improve the layout to be more like a watchface
111111+ text_layer_set_background_color(s_time_layer, GColorClear);
112112+ text_layer_set_text_color(s_time_layer, GColorBlack);
113113+ // text_layer_set_text(s_time_layer, "00:00");
114114+ text_layer_set_font(s_time_layer,
115115+ fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
116116+ text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);
117117+118118+ // Add it as a child layer to the Window's root layer
119119+ layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
120120+}
121121+122122+static void main_window_unload(Window *window) {
123123+ text_layer_destroy(s_time_layer);
124124+}
125125+126126+static void update_time() {
127127+ static char s_tid_buffer[14]; // Buffer for TID string (13 chars + null)
128128+ now_c(s_tid_buffer, sizeof(s_tid_buffer)); // Generate TID
129129+130130+ // Display this time on the TextLayer
131131+ text_layer_set_text(s_time_layer, s_tid_buffer); // Display TID
132132+}
133133+134134+static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
135135+ update_time();
136136+}
137137+138138+static void init() {
139139+ // Create main Window element and assign to pointer
140140+ s_main_window = window_create();
141141+142142+ // Set handlers to manage the elements inside the Window
143143+ window_set_window_handlers(
144144+ s_main_window,
145145+ (WindowHandlers){.load = main_window_load, .unload = main_window_unload});
146146+147147+ // Show the Window on the watch, with animated=true
148148+ window_stack_push(s_main_window, true);
149149+150150+ // Update the time immediately
151151+ update_time();
152152+153153+ // Register with TickTimerService
154154+ tick_timer_service_subscribe(SECOND_UNIT, tick_handler);
155155+}
156156+157157+static void deinit() { window_destroy(s_main_window); }
158158+159159+int main(void) {
160160+ init();
161161+ app_event_loop();
162162+ deinit();
163163+}
+54
wscript
···11+#
22+# This file is the default set of rules to compile a Pebble application.
33+#
44+# Feel free to customize this to your needs.
55+#
66+import os.path
77+88+top = '.'
99+out = 'build'
1010+1111+1212+def options(ctx):
1313+ ctx.load('pebble_sdk')
1414+1515+1616+def configure(ctx):
1717+ """
1818+ This method is used to configure your build. ctx.load(`pebble_sdk`) automatically configures
1919+ a build for each valid platform in `targetPlatforms`. Platform-specific configuration: add your
2020+ change after calling ctx.load('pebble_sdk') and make sure to set the correct environment first.
2121+ Universal configuration: add your change prior to calling ctx.load('pebble_sdk').
2222+ """
2323+ ctx.load('pebble_sdk')
2424+2525+2626+def build(ctx):
2727+ ctx.load('pebble_sdk')
2828+2929+ build_worker = os.path.exists('worker_src')
3030+ binaries = []
3131+3232+ cached_env = ctx.env
3333+ for platform in ctx.env.TARGET_PLATFORMS:
3434+ ctx.env = ctx.all_envs[platform]
3535+ ctx.set_group(ctx.env.PLATFORM_NAME)
3636+ app_elf = '{}/pebble-app.elf'.format(ctx.env.BUILD_DIR)
3737+ ctx.pbl_build(source=ctx.path.ant_glob('src/c/**/*.c'), target=app_elf, bin_type='app')
3838+3939+ if build_worker:
4040+ worker_elf = '{}/pebble-worker.elf'.format(ctx.env.BUILD_DIR)
4141+ binaries.append({'platform': platform, 'app_elf': app_elf, 'worker_elf': worker_elf})
4242+ ctx.pbl_build(source=ctx.path.ant_glob('worker_src/c/**/*.c'),
4343+ target=worker_elf,
4444+ bin_type='worker')
4545+ else:
4646+ binaries.append({'platform': platform, 'app_elf': app_elf})
4747+ ctx.env = cached_env
4848+4949+ ctx.set_group('bundle')
5050+ ctx.pbl_bundle(binaries=binaries,
5151+ js=ctx.path.ant_glob(['src/pkjs/**/*.js',
5252+ 'src/pkjs/**/*.json',
5353+ 'src/common/**/*.js']),
5454+ js_entry_file='src/pkjs/index.js')