Archive

Monthly Archives: June 2013

UPDATE: The section on setting text has been updated to reflect font name change in PebbleKit v1.12

Links to Previous Sections:

Here are links to the previous sections of this tutorial. Read them if you haven’t to get up to speed!

Part #1: Beginner’s Primer to the C Language

Part #2: Applying the Primer to the Pebble SDK

Part #3: Setting Up a Ubuntu Environment for Development

Introduction

This is the section you’ve all been waiting for, I suspect. Here, we’ll examine the key functions and features of a basic watch face source file, and how it all fits together. By the end of this section, you should have assembled your very first watch face!

In summary:

  • Pre-processor statements
  • Static allocation vs. Stack allocation
  • Handler functions
  • Getting the time from the system and 24 hour compatibility
  • Minute ticks vs. seconds ticks
  • The resource map
  • Compiling and installing

Lets begin!

Pre-processor statements

These special statements let you give instructions to the compiler. There are two types I’ll mention here, #include and #define. The former tells the compiler to include extra files that contain functions, data structure types and constant values provided by the Pebble SDK. The latter lets you specify a key word to represent a value (such as a left hand margin) so you can avoid typing that number over and over again.

Another big advantage of using a #defineed variable is that if you use it as (for example) a margin for all features of the watch face and then decide to change that value, you can simply just change the #define statement and not every single instance where it is used. Neat, eh?

Here is how those statements are used for a Pebble watch face:

//Include files from SDK
#include "pebble_os.h"
#include "pebble_app.h"
#include "pebble_fonts.h"

The #define statement is used to define the Universally Unique Identifier, a random number that uniquely defines your watch face. It is used by the Pebble OS to let you overwrite your watch face with a new version.


//Define Universally Unique Identifier
//    88a97cfd-2377-463a-84bd-b85eb4964063
#define UUID { 0x88, 0xa9, 0x7c, 0xfd, 0x23, 0x77, 0x46, 0x3a, 0x84, 0xbd, 0xb8, 0x5e, 0xb4, 0x96, 0x40, 0x63 }

Each watch face MUST have a new one! Here is how you generate a new one in Ubuntu, using the ‘uuidgen’ command:

uuidgen

Static allocation vs. Stack allocation

As you saw in Part #2, if you declare a variable or structure outside ANY function (usually at the top of the file) then it is visible to all parts of the program (it is globally accessible). Once it is declared, that memory is kept safe for later use.

The opposite of this is called ‘stack allocation’ and is much different. With stack allocation, you can imagine a stack of variables in memory like a stack of cards. When you call a function, any declarations you put in there are added to the top of the stack of memory. When the function returns or exits, these variables are freed up to make more memory available, as it is assumed they are only needed for that function. The variable is declared ‘locally’.

So, if you know you want to keep data for later, declare it globally. If you only need it for a single calculation, declare it locally!

For our watch face, we declare the watch face features globally, as well as memory for the string containing the current time (more on how we get that later):


//Declare structures for watch face elements
Window window;
TextLayer timeLayer;

//Declare variable for storing time string
static char hourText[] = "00:00";

Handler functions

In a Pebble watch face, there are certain functions that aren’t called by the programmer (you), but by the system. An example is a function called every time a second ticks by. You can’t know when this is, but the system does (it’s a watch, after all!). What you can do as the programmer is specify what happens in this function, and leave the actual calling of it to the system. It ‘handles’ that scenario for you.

There are many different ‘handler’ functions, but the two main ones I’ll introduce here are the ‘init handler’ and the ‘tick handler’. There are also handlers for buttons, 2-way communication events and animation etc.

The ‘init handler’ is called as soon as you switch to your watch face. Any initialisation of watch face features and structures is placed in here, so it is all done for you in one go when you open the watch face.

Here is the ‘init handler’ for our basic watch face. Try and read what each function call does. Their names should be pretty self explanatory:


/**
* Watch face initialisation handle function
*/
void handle_init(AppContextRef ctx) {
(void)ctx;    //This is not needed. Convert to void (nothing)

//Initialise window
window_init(&window, "Window Name");
window_stack_push(&window, true);
window_set_background_color(&window, GColorBlack);

//Initialise TextLayers
text_layer_init(&timeLayer, GRect(30, 30, 150, 50));
text_layer_set_background_color(&timeLayer, GColorClear);
text_layer_set_text_color(&timeLayer, GColorWhite);
text_layer_set_font(&timeLayer,
fonts_get_system_font(FONT_KEY_BITHAM_30_BLACK));
text_layer_set_text_alignment(&timeLayer, GTextAlignmentLeft);

//Add to window
layer_add_child(&window.layer, &timeLayer.layer);

//Set initial time so display isn't blank
PblTm time;
get_time(&time);
setTime(&time);
}

The ‘tick handler’ is a function called when the watch face ‘ticks’, either every minute or every second. For saving power and helping keep the watch asleep as much as possible, it is wise to use a minute tick handler. If you want a more active watch face, use a second tick handler. We will start with a second tick handler in our basic watch face:


/**
* Handle function called every second
*/
void handle_second_tick(AppContextRef ctx, PebbleTickEvent *t) {
(void)ctx;

PblTm time;    //Structure to store time info
get_time(&time);    //Fill the structure with current time

int seconds = time.tm_sec;    //Get the current number of seconds

if(seconds == 0)
setTime(t->tick_time);    //Change the time on the 'zero seconds' mark
}

So that the system can call these handler functions, we specify them in a function called ‘pbl_main’. The exact details of how this function is laid out is not covered here, but how each handler is registered is done the same way, and can be seen in other examples. Here is the ‘pbl_main’ function for our basic watch face:


/**
* Main Pebble app loop
*/
void pbl_main(void *params) {
PebbleAppHandlers handlers = {
.init_handler = &handle_init,    //Register initialisation function

.tick_info = {
.tick_handler = &handle_second_tick,    //Register tick function
.tick_units = SECOND_UNIT    //Specify to call every minute
}
};
app_event_loop(params, &handlers);    //Continue from there!
}

This brings up an important point: The functions specified by the Pebble SDK MUST be named how they are specified in the examples and the API documentation. There is no flexibility here.

However, the handler functions can be called whatever you like (as long as they are C legal) , but when you register them you must supply the exact same name.

Getting the time (And 24 hour compatibility)

The one thing a watch face file must do is tell the time! To do this, there is a function supplied by the Pebble SDK called ‘string_format_time’, which uses:

  • A string you’ve declared to store the time as a string
  • The size of the string (luckily there is a function supplied called ‘sizeof’
  • The format of the time you want (According to the rules specified here)
  • The source of the time, which is a PblTm structure.

Here is an example here, in conjunction with another function that tells you what the user’s Settings preference is, which returns type bool (true or false), so you can use it in the if else style with ease:


/**
* Function to set the time and date features on the TextLayers
*/
void setTime(PblTm *t) {

//If user selects '24hr' in Settings on the watch
if(clock_is_24h_style())
string_format_time(hourText, sizeof(hourText), "%H:%M", t);
else
string_format_time(hourText, sizeof(hourText), "%I:%M", t);

//Set the TextLayer text
text_layer_set_text(&timeLayer, hourText);
}

Minute ticks vs. seconds ticks

As I mentioned earlier, battery life can be saved by working with the watch’s ‘aggressive sleep’ philosophy. By only calling the tick handler every minute, the watch can spend a good deal more of it’s time asleep in a low power state. Here is how the tick handler would look after changing to a minute tick basis:


/**
* Handle function called every minute
*/
void handle_minute_tick(AppContextRef ctx, PebbleTickEvent *t) {
(void)ctx;

PblTm time;    //Structure to store time info
get_time(&time);    //Fill the structure with current time
setTime(t->tick_time);    //Change time on 'zero seconds' mark
}

Notice the differences with the image previous, which showed the second tick handler. It is simpler to implement. However, with the second handler, you can open the possibility of animations happening at different point.

For example, in one of my watch faces ‘Split Horizon‘ (shameless plug!) there is animation happening to tell the user how far thorough the minute they are with markers that slide into view showing 15, 30, 45 and 60 seconds past the minute. These are allowed through a second handler with if(seconds == 15) etc conditional statements.

Once again, the handle function name can be changed, so long as the name used in ‘pbl_main’ is kept in sync:


/**
* Main Pebble app loop
*/
void pbl_main(void *params) {
PebbleAppHandlers handlers = {
.init_handler = &handle_init,    //Register initialisation function

.tick_info = {
.tick_handler = &handle_minute_tick,    //Register tick function
.tick_units = MINUTE_UNIT    //Specify to call every minute
}
};
app_event_loop(params, &handlers);    //Continue from there!
}

Notice the ‘.tick_units’ field is different now, to reflect the new tick basis.

Extra bits and pieces

There are a couple extra pieces each watch face file needs.

The first is the PBL_APP_INFO function call which contains information such as watch face name, author, version number, icons etc:


//Set app info
PBL_APP_INFO(UUID, "First Watch Face", "Chris Lewis", 0, 1, DEFAULT_MENU_ICON, APP_INFO_WATCH_FACE);

//UUID, app name, author, minor version, major version,
//use default icon, tell compiler this is a face

The second is the Resource Map. This is a file that is like a catalogue of all the resources you used in your watch face, such as custom images and fonts. Since there are none of those things in this basic example, it can be left as the dummy file supplied with the SDK examples, and included in the link to the finished project files at the end of this post.

Compiling and installing

Here comes the fun bit: feeding your watch face source file into the compiler and receiving the install file to upload to your watch. If you’ve followed Step 1 and Step 2 in the API install instructions from Part 3 on Ubuntu then you should know how to do this, but here is brief summary if you have forgotten (‘<path to PebbleKit>’ should be replaced with that path):

  1. Set up the new project folder to include all the requisite links to the sdk using the following Terminal commands: cd ~/<path to the folder above your project folder> and then ~/<path to PebbleKit>/Pebble/tools/create_pebble_project.py --symlink-only ~/<path to PebbleKit>/Pebble/sdk <newprojectfolder>
  2. Go to the new project folder with cd <newprojectfolder>
  3. Configure and build with ./waf configure build

The output file will be found in <project folder>/build and has the extension ‘.pbw’.

On cloudpebble.net, this can all be done by selecting ‘compilation’ and then ‘run build’.

Copy this to your Dropbox, or use the python script from the Pebble SDK (instructions in the API documentation) or any other method of navigating to it on your phone (such as copying to SD card and a file manager), and the Pebble App will do the rest!

Conclusion

So, hopefully you’ll have all the information you need to build your first Pebble watch face. Tweak the values in the example code segments to see their effect (such as layer GRect co-ordinates and GColors), or tweak some other examples from the SDK and the Web.

HERE IS A LINK TO THE COMPLETE EXAMPLE PROJECT!

Next time

Next section I’ll show you how to use your own fonts, display bitmap images and do simple animations.

Announcement

For the next ten days, I’ll won’t be able to write. I’m glad I’ve managed to get Parts 1 to 4 done so you can do the complete basic journey, but be assured that while I’m away I’ll be making copious notes on the next Parts! I’d be very grateful if you could bear with me! If I find time I’ll try and check back here and answer any questions that have arisen.

Best of luck!

Advertisements

Links to Previous Sections:

Here are links to the previous sections of this tutorial. Read them if you haven’t to get up to speed!

Part #1: Beginner’s Primer to the C Language

Part #2: Applying the Primer to the Pebble SDK

Introduction

In this section of the tutorial I’ll do an almost click by click run-through of how to set up a Virtual Machine running Ubuntu Linux for developing watch faces and apps. This will be without any screenshots because it’s a very linear ‘click next to continue’ sort of process. If you get stuck, there are numerous guides that are Google-able to achieve this goal.

The reason this is done is because the software tools and compilers used are only supported on Linux, and not Windows.

Again, if you would rather prefer not to do this you can use cloudpebble.net to write the .c files and compile them, but it’s always interesting to see a new facet of computing that you might not have done otherwise. It can also be said that this method of building watch faces and apps grants you more control, but it’s up to  you.

An advantage of using cloudpebble instead of installing your own Virtual Machine is that if you wanted only to modify an existing watch face and study the effects, that is a simpler option. You can focus on writing watch face code and compilation. For example, you can make a small modification to an existing watch face to save bothering the developer, but in most case I’d hope they would be happy to help, unless they were inundated with requests!

Important Downloads

Before you start, make sure you download both these files. You’ll need them!

  1. VirtualBox
  2. A DVD image file for Ubuntu OS. I’d recommend 12.04 LTS. Pick the architecture version that is applicable. If you’re unsure, select 32-bit. If you want to donate, that’s great, but you don’t have to. On the next page choose ‘not now, take me to the download’ to go straight there.

Setting Up the Virtual Machine

  1. Install and open VirtualBox. Click ‘New’ at the top left corner.
  2. Enter a name for your Virtual Machine and select ‘Type’ as ‘Linux’ and ‘Version’ as ‘Ubuntu’ or ‘Ubuntu 64’, depending on your preference earlier.
  3. Choose a memory size. I’d recommend between 1 GB and 2 GB. (1024 MB – 2048 MB to be more precise)
  4. Choose ‘Create a virtual hard drive now’.
  5. Choose the ‘VDI’ type.
  6. Select ‘Dynamically allocated’. An explanation of the difference is given.
  7. Name your virtual hard drive and set the capacity. I’d recommend 8 GB if you have that much available, but Ubuntu itself recommends at least 4.5 GB. You’ll need extra space for installing the Pebble SDK and tools.
  8. You should now be back at the main VirtualBox window you started in. Click ‘Start’.
  9. When asked for the instal medium, click the ‘folder with green arrow’ icon on the right of the dialogue and navigate to the Ubuntu .iso you downloaded earlier.
  10. Press ‘Start’ and wait for the ‘Welcome’ window.

Setting up Ubuntu

  1. Select your preferred language on the left pane and then choose ‘Install Ubuntu’.
  2. If you prefer, select the box for ‘Download updates while installing’. This will ensure the standard parts of Linux that the SDK may rely on are up-to-date, and I’d strongly recommend it. Press ‘Continue’.
  3. Select ‘Erase Disk and Install Ubuntu’. This is fine, as the whole machine is running on a virtual hard disk, which is merely a single file on your host OS. Your computer is safe!
  4. Press ‘Continue’, then ‘Install now’.
  5. Wait for the installation to complete and answer the additional locale questions. This should take no more than ten minutes. (I remember waiting almost two hours for Windows XP to install back in the day).
  6. Click ‘Restart Now’ when asked, then press ENTER when asked. There is no CD to eject.

Set Up Toolchain

Now you need to install the software tools and dependencies the SDK requires to work.

I would go though it in detail here, but there really is only one correct way of doing it and that method is documented in fine detail over on the official Pebble Developer site. Make sure you follow the instructions to the letter and make sure you resolve any problems you encounter before you try and proceed any further, or you’ll be wasting your time!

I’d say that only Step 1 and Step 2 on the left hand side are essential right now, then you will be ready for the next section of my tutorial, but if you’re interested, a little extra reading is great.

Next Time

In the next section there will be a detailed look at the key features of a basic watch face source file, and you’ll end up with your first custom built watch face!

Best of luck! Remember there are already lots of answered questions and solutions to common problems over on the Pebble SDK Install and SDK Help forums.

Introduction:

The aim of this second section of the tutorial series is to show examples of how the primer theory from the last section appears in the real world application we’re all looking at – the PebbleKit SDK. But first there is one more data storage convention in C we need to look at. But before that, a quick recap.

Recap:

  • A watch face file is a C file (*.c) and is compiled by the compilers supplied with the Pebble SDK.
  • Statements (or lines of code) are executed one after another, except where diverted by program flow statements such as if and else.
  • Variables are where data is stored. Examples are types such as integers, strings and floating points.
  • Functions perform repeated tasks on data supplied as the arguments. Sometimes the resulting values are returned, and used in assignments.

If any of these things are completely foreign to you, please go back and read the last section!

Structures

In C, structures are a data type similar to int or float, but contain many different values and can be created for a specific purpose by the user or in this case the SDK developers. You can think of them as a collection of variables that come under one heading, or an Object, if you’re coming from an Object Oriented Programming background.

image 1

The individual variables inside the structure can be accessed individually but are all declared at the same time by a single structure declaration. Let’s make this a little clearer with an example. Suppose we used a structure to define the aspects of a car.

image 2

The reason that structures are included here are that they are especially important in relation to the Pebble SDK, and so form our first real examples. Luckily we don’t have to access the individual variables inside a structure very often.

The final point on structures is that the key word typedef can be used to define your structure as it’s own data type, and so avoid having to type struct before any declaration. Here’s an example:

image 2.5

More Common Types To Know

In developing a watch face, there are a few more types of data constants to know (these are used as easy ways of specifying aspects of the watch face). The first example is the GColor (Graphics Color). These are defined in order to be used to set the colours of parts of Layers. Their listing in the API documentation lets you know which ones are available. You’ll see how they fit in when we start to use them later.

Another common type you’ll be using a lot is the GRect. This allows you to specify the dimensions of a rectangle for use in setting Layer frames, or starting and finishing positions for animations etc. It is crucial to enabling you to set where items appear on the watch face and how big they are.

Here are two real examples of these types in use:

image 2.6

If you see the API documentation for GRect, it is actually a structure consisting of a GPoint for the origin and a GSize for the width and height. I hope you can guess what those two new ones do!

Structures in the PebbleSDK

A large number of structures are used in the SDK to represent various elements that go into a watch face or app. An example is the Layer structure. The variables stored inside this structure are items such as it’s geometry and the Window it is situated in. In the SDK reference material it looks like this.

At a distance, the most basic watch face possible is just a collection of structures representing user interface elements and functions that manipulate these structures through their pointers (easier than returning an entire struct!)

The first two I’ll introduce are Window and TextLayer. These are defined using typedef, so the key word struct is not needed when you use them.

The Window structure represents the ‘fullscreen window’ that IS your watch face. When you add an element such as a TextLayer to the Window, it is displayed in that Window. In order to be accessible to all parts of the watch face program, they are declared ‘globally’. This just means outside any function, and so visible to them all, like so:

image 3

So, the Window is the main place for all the parts of the watch face, and the TextLayer is a Layer that displays text to the user. Before either of these can be used, we must call functions provided by the SDK to set them up or ‘initialise’ them. The image below illustrates this process:

image 4

Notice throughout the process the Window structure the pointers are operating on is specified using a pointer to the structure, rather than the structure itself. This is done thought the ‘&’ symbol, used to specify the structure’s pointer.

Once this is done, we can initialise and add a TextLayer to the Window for displaying our demo text.

image 5

It is important to note that the order in which Layers are added to a Window matters. Much like the new Window is added to the top of the ‘stack’ of windows, the most recent’y added Layer will be at the front, on top of everything else. If the background colour is specified as GColorClear, this is rarely an issue, but there could be times when this feature can be taken advantage of.

Conclusion

So that’s how the data types, functions and structures manifest themselves in creating a basic watch face. I hope I’ve made it clear enough, but if not, feel free to ask a question.

Next Time

In the next section I’ll show a brief overview of how to setup a Ubuntu environment for building watch faces, if you prefer that to the cloud based solution mentioned in the first section.

After that, I’ll walk through a basic first watch face!

Introduction

After using the Pebble Watch Face SDK (aka PebbleKit) to create a number of my own watch faces, and considering that being able to do so as an owner of one of these marvellous devices is one of it’s main unique selling points, I’d like to use this position to help others get their foot on the ladder in terms of getting started creating their own watch faces.

This first part of the tutorial will focus on conveying the basics of the C language, which is the language of choice for writing watch faces, so that hopefully a non-programmer can pick them up and start using them to write a watch face.

At the moment, there are two viable environments for writing a watch face that I’m aware of. If you know your way around a Linux OS, such as Ubuntu at a basic level, you can follow the steps provided by the Pebble Team to set up all the tools you’ll need to write, compile and install your new watch face. The alternative method is to write the code and upload resources (images, fonts etc) to cloudpebble.net, a site that does all this for you, if you don’t want to work with Ubuntu.

In either case, the program code is entered in to a file with the extension ‘.c’, instead of ‘.jpg’ or ‘.txt’ for example. This file is then used by a piece of software supplied by Pebble in the SDK called a ‘compiler’ that processes your program code and produces a watch install package as a ‘.pbw’, ready for sharing and uploading, to your watch or the web.

Variables

The C programming language is one of the most widely used and flexible around, because it can be  adapted for almost any purpose (including Pebble Smartwatches!) and allows low level control of whatever hardware it’s implemented on.

Like almost any language, C consists of variables, functions and structures. A variable can be thought of as a container for a piece of information, and comes in many types depending on what sort of information you want it to hold. For example, if you want to store a number, such as the number of minutes past the hour, you would use an int. This stands for integer, which is just another name for a number.

If you wanted to store a number with a decimal point, you can use a float type. The decimal point is here called a floating point

Another type is a string of characters, called (you guessed it) a ‘string’, but it’s representation in C is slightly more complex. You can think of the string “Hello, world!” as a collection of individual characters. Due to the low level nature of C, this is stored in a character array. You can think of an array as just such a collection. In C, an array is declared by the number of ‘slots’ in the array after it’s name, or can be left empty if the size is known by what you initially store in it.

Here are a couple of examples:

Image 1

Using these types of variable, most kinds of data can be stored.

Functions

Functions can be thought of as tasks that be started at any time. They’re a good way of grouping statements (another word for a line of code or command) to act on data that you’re going to be doing frequently. As a very basic example, imagine you wanted to add one to an integer. When your code is running, you don’t know what that number will be, but you know where it will be coming from. It could be a literal value, or the result of a function call, so it needs to be supplied to the function.

A function declaration has three main parts:

  1. The return type, which is the type of data the function will supply us with when we call it to run.
  2. The name of the function
  3. The variables we supply to the function for it to work on. These are called arguments. There can be as many arguments as you need.

You can see these parts shown in the ‘pseudo-function’ below:

Image 2

For all intents and purposes, a function must be declared in the file BEFORE it is used.

For our example of adding one to a number, there are two ways of doing it. The first is by specifying the integer as the function argument, and this is known as ‘pass by value’. The value is copied from the call argument into the variable supplied in the function declaration ready to be used however you want. So, here is our example. See if you can follow the train of thought.

Image 3

The value we use is ‘number’ and is supplied to the function in the call ‘addOne(number)’ by putting it in the brackets. The value then ‘appears’ in the function declaration as ‘input’, where it is incremented by one, before being returned by the function.

Here’s the clever bit: As the function returns an integer type, we can assign it into the integer ‘result’! It can be said that the function itself represents the integer type it returns.

I hope you can follow that. If not, look back through the last example image and follow the flow of the value of ‘number’.

Pointers

Imagine a variable came with a tag, like a label on an item at a Lost Property Office. The tag or label would describe what was attached. For example, a lost wallet with a ten pounds inside might have a label attached saying “Lost wallet”. By following the string from the label to the wallet, you could then look inside and find the value held within. Another example is Baggage Reclaim at the airport. To find the luggage that belongs to you, you look for the label and flight number you’ve been given, which leads you to the correct bags.

Image 3.5

It is in this way that C can reference variables by their location, but not necessarily by the actual instance of that variable. This type of ‘pass by reference’ is called a pointer, and is just a number of the memory location of where the variable is actually stored. This is especially useful for strings, where in C a string is often supplied to a function by a pointer to the location of the first slot in the string’s character array. The rest of the string can then by read simply by incrementing the pointer to point to the next slot, and so on. An example of the addOne function discussed in the previous section using a pointer to the ‘number’ and not the actual value itself is shown below. Note the need for no return type!

Image 4

Program flow

Especially relevant in the realm of watch faces that change depending on the time, is the control of how the program that is the watch face executes. You might only want an animation to fire on the turn of the hour, for example. Another example is that the watch face will show “14:30” if the user selects ‘Time Display 24h’ in the watch settings, and “2:30” if they select ‘Time Display 12h’. Thankfully, the SDK lets you facilitate this preference in your watch face program using a combination of program flow and a function supplied by the SDK.

The two key statements for controlling program flow are almost self explanatory: if and else. Much like a function call, whatever condition is placed in the brackets after an if decides whether the code following is executed. An example of these types of conditional statements is shown below:

Image 5

So, if the value of ‘number’ is exactly 5, the top segment of code is executed, but if not, then the lower segment is executed.

As a sneak preview of the next section of this tutorial ‘Applying the Primer to the Pebble SDK’, see if you can decipher what this code segment does…

Image 6

Thanks for reading! Please ask any questions you have and I’ll do my best to answer them!

Stay tuned for the next section of the tutorial!

I’ve had another watch face idea! And it’s almost completely implemented. This time around, any digit about to change gets ‘beamed up’ by an InverterLayer, changed, then replaced a moment later. Before I go into the interesting specifics, here’s a preview image (although rather crudely created):

mockupI’ll post it for download on mypebblefaces when I feel its ready, but its pretty close now, and there is an interesting characteristic to a watch face of this nature that I’d like to discuss.

The rough logic for the ‘digit changing’ code goes like this:

1. Any digit about to change has the ‘beam comes down, digit goes up’ animations applied to it.

2. Those digits are changed to the new ones at seconds == 0 time

3. Those new digits are then replaced with the ‘digit comes down, beam goes up’  animations.

Now, in order to make sure only those digits that ARE about to change actually have the animation applied to them, we need to predict which ones are about to change. This is because the condition ‘new digit does not equal old digit’ (12:39 changing to 12:40) for example, can only be known once the new minute has elapsed at the seconds == 0 time. But by this time, the changed digit specific ‘hide’ animations are supposed to already have taken place! Hence the need for digit change prediction a second before, at seconds == 59 time.

To do this, we look at each digit and the conditions under which each one will change. For example, for the ‘2’ digit in ’13:29′, which I call ‘minutes tens’, the condition is that the ‘minutes units’ digit will be ‘9’. Thus, this is incremented behind the scenes to trigger the correct ‘hide’ animations before the time change has actually taken place. When the minute changes, the new time overwrites this little ‘hack’ and so synchrony is never lost to the user.

Similar conditions exist for the other two left hand digits. For the ‘hours minutes’, the condition is that  the ‘minutes tens’ digit is ‘5’ and the ‘minutes units’ digit is ‘9’ (12:59 for example).

Finally, for the left hand most digit, ‘hours tens’, the condition is a little more complex. There are three times at which this digit changes.

  1. At 09:59, it changes to a ‘1’ in 10:00.
  2. At 19:59, it changes to a ‘2’ in 20:00.
  3. At 23:59, it changes to a ‘0’ in 00:00.

By using this simple prediction algorithm on the second tick before any animation is due to take place, the watch face code knows which digits will change before the time change has even taken place!

I’ll need to think about how this can be generalised even further for 12-hour time, so that will be included in the eventual release, hopefully very soon!

Until next time.

Here’s a preview of something interesting I’ve been working on. All I’ll say right now (until I have more to show) is that is uses my newest multi-threaded, TCP enabled Java 2D game engine, and it’s like having a model railway on your PC. And after swapping a few BufferedImages for Bitmaps, possibly in your pocket!

Preview1Summary of features so far:

  • Sixteen types of placeable track (straight, curves, crossrails, points)
  • A depot with GUI that enables creation of services from the top left
  • Intelligent navigation of all track and points, including stop signals
  • Text file saving/loading of complete maps, except services.

More details soon!