John Choi

26 Jan 2015

PebbleWatch

At first, I just wanted to make a binary clock.  I looked around for a bit and it turned out those are actually pretty mainstream.  So I decided to make a Ternary clock!  (This is fitting for a clock because after all, Sumerian time is pretty divisible by 3.)  Here, the horizontal lines represent 0, the vertical line represents 1, and the square represents 2.  I decided to make the lowest bit display on the left and the highest bit on the right, since we naturally read English text from left to right, and doing numbers this way as well makes more sense.  I kind of screwed up with the seconds, so that although it goes up from 0 to 60, it isn’t in perfect sync with the minutes.  I retrospect, developing for the Pebble watch was really annoying on the Android.  I finally figured out why it wasn’t working with my Android phone while it did on my tablet: the Android version was outdated!  (Version needs to be at least 4.2.2)  Anyways,  I think the end result looks kind of like the messaging system the Predator alien has on its wearable wrist device.  Cool stuff.

Here is a sketch:
pebblesketch
Here are some stills:0-40-46
Time:  0 hours, 40 minutes and 46 seconds.

24-10-53
Time: 24 hours, 10 minutes and 53 seconds.

And here is the code:

 
#include 

//windows and layers  
static Window *s_main_window;
static Layer *s_canvas_layer;

//variables to be used
int hours = 0;
int minutes = 0;
int seconds = 0;

//---CLOCK UPDATE STUFF---//
static void update_time() {
  // Get a tm structure
  time_t temp = time(NULL); 
  struct tm *tick_time = localtime(&temp);
  static char buffer[] = "00:00";

  // Write the current hours and minutes into the buffer
  if(clock_is_24h_style() == true) {
    // Use 24 hour format
    strftime(buffer, sizeof("00:00"), "%H:%M", tick_time);
  } else {
    // Use 12 hour format
    strftime(buffer, sizeof("00:00"), "%I:%M", tick_time);
  }
  //update hours and minutes
  hours = (int)(buffer[0]-'0')*10+(int)(buffer[1]-'0');
  minutes= (int)(buffer[3]-'0')*10+(int)(buffer[4]-'0');
  //reset seconds
  if(seconds == 60) {
    seconds = 0;
  } else {
    seconds += 1;
  }
  //mark layer dirty for rerendering
  layer_mark_dirty(s_canvas_layer);
}
static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
  update_time();
}

//---CANVAS STUFF---//
void drawSymbol(int shape, int x, int y, GContext *ctx) {
  //shape:  0 = horizontal line, 1 = vertical line, 2 = square
  graphics_context_set_fill_color(ctx, GColorBlack);
  if(shape == 0) {
    graphics_fill_rect(ctx, GRect(x+6, y+16, 24, 4), 0, GCornerNone);
  } else if(shape == 1) {
    graphics_fill_rect(ctx, GRect(x+16, y+6, 4, 24), 0, GCornerNone);  
  } else if(shape == 2) {
    graphics_fill_rect(ctx, GRect(x+10, y+10, 16, 16), 0, GCornerNone);    
  }
}
//draw the time in ternary:
static void canvas_update_proc(Layer *this_layer, GContext *ctx) {
  //update time
  update_time();
  
  //get ternary hours:
  int thours = hours;
  for(int h = 0; h < 4; h++) {
    drawSymbol(thours%3,h*36,0,ctx);
    thours /= 3;
  }
  //get ternary minutes:
  int tminutes = minutes;
  for(int m = 0; m < 4; m++) {
    drawSymbol(tminutes%3,m*36,36,ctx);
    tminutes /= 3;
  }
  //get ternary seconds:
  int tseconds = seconds;
  for(int s = 0; s < 4; s++) {
    drawSymbol(tseconds%3,s*36,72,ctx);
    tseconds /= 3;
  }
  
}

//---WNDOW STUFF---//
static void main_window_load(Window *window) {
  Layer *window_layer = window_get_root_layer(window);
  GRect window_bounds = layer_get_bounds(window_layer);
  s_canvas_layer = layer_create(GRect(0, 0, window_bounds.size.w, window_bounds.size.h));
  layer_add_child(window_layer, s_canvas_layer);
  layer_set_update_proc(s_canvas_layer, canvas_update_proc);
  
  update_time();
}
static void main_window_unload(Window *window) {
  layer_destroy(s_canvas_layer);
}


//---REQUIRED FUNCTIONS---//
static void init() {
  s_main_window = window_create();
  // Set handlers to manage the elements inside the Window
  window_set_window_handlers(s_main_window, (WindowHandlers) {
    .load = main_window_load,
    .unload = main_window_unload
  });
  // Show the Window on the watch, with animated=true
  window_stack_push(s_main_window, true);
  
  tick_timer_service_subscribe(SECOND_UNIT, tick_handler);
}
static void deinit() {
  // Destroy Window
  window_destroy(s_main_window);
} 
int main(void) {
  init();
  app_event_loop();
  deinit();
}