On Friday June 21st, the AGENT SDK v0.1.1 (June 2013, Preview Release) was released. On Thursday June 20th I backed the “AGENT: The World’s Smartest Watch” Kickstarter project. Not being able to wait for the watch to arrive to start coding, I started to play around with Visual Studio 2012, the AGENT Emulator and the Microsoft .NET Micro Framework.
To be honest, I have experience with various flavors of .Net, but I never took the time to explore the .NET Micro Framework. The feeling I got when I started to play with it, was that it felt odd… I have the VAR but no Generics !?! No lambdas, no LINQ..
This is the moment I realized that I was working with a mix of .Net 2.0 style with a slight hint of .net 4.0.
I also had not worked with Bitmaps for a while so I pulled out a stack of paper and started mapping out my screen.
When you have 128px by 128px to work with, you have to ask your self some important questions like “What can I live without?” and “What should be on screen?”
Development for the watch is straight forward. When you create the AGENT Watch Face project, you get a nice program that is able update the display with the current time. The following code was slightly modified to accommodate my tastes.
public class Program { static Bitmap display; static Timer updateClockTimer; private static WatchFaceUpdater wc; public static void Main() { // initialize our display buffer display = new Bitmap(Bitmap.MaxWidth, Bitmap.MaxHeight); wc = new WatchFaceUpdater(display); // display the time immediately UpdateTime(null); // obtain the current time var currentTime = DateTime.Now; // set up timer to refresh time every minute // start timer at beginning of next second var dueTime = new TimeSpan(0, 0, 0, 0, 1000 - currentTime.Millisecond); // update time every second var period = new TimeSpan(0, 0, 0, 1, 0); // start our update timer updateClockTimer = new Timer(UpdateTime, null, dueTime, period); // go to sleep; time updates will happen automatically every minute Thread.Sleep(Timeout.Infinite); } static void UpdateTime(object state) { wc.Update(); } }
Then I set out to create my WatchFaceUpdater. I wanted to encapsulate all my logic within a class that could be instantiated because this will come in handy in future blog posts about Agent development.
The goal of my experiment was to show the current time with the previous time on top and the next time on the bottom. I’m by no means any good with UIs and that is why I usually stick to backend development…
Placing things around took some trial and error, a sheet of paper and a pen! Yes I know… I used paper, but it helped me keep track of x y coordinates when I was placing everything on the screen.
Changing font sizes isn’t implemented in the .NET Micro Framework. In order to display text of different sizes, you will need to export fonts into the TinyFont format and add them as resources to your project. The TinyFont format has the font size embedded in it, so it’s important to name them properly because you might get lost is you have too many sizes.
Jan Kučera has a great tool to help convert Fonts to TinyFonts. In my opinion, it beats using a command line =)
Using this tool I created Cambria16.tinyfnt and Cambria20.tinyfnt and embedded them into my project.
The WatchFaceUpdater calculates the values to display and places them on screen. This call should probably be split up into two classes, one for the bitmap related code and one for the values.
internal class WatchFaceUpdater { private readonly Bitmap display; private DateTime currentTime; private readonly Font fontNinaB; private readonly Font biggerFond; private const int CenterText = 64 - 16; private const int YCenterTopLine = 64 - 12; private const int YCenterLowLine = 64 + 12; private const int XRightBound = 64 + 50; private const int XLeftBound = 64 - 50; internal WatchFaceUpdater(Bitmap display) { this.display = display; fontNinaB = Resources.GetFont(Resources.FontResources.Cambria16); biggerFond = Resources.GetFont(Resources.FontResources.Cambria20); } internal void Update() { currentTime = DateTime.Now; var hours = GetHour(); var minutes = GetMinutes(); var seconds = GetSeconds(); display.Clear(); DrawSeperators(); DrawPreviousValues(hours, minutes, seconds); DrawCurrentTime(hours, minutes, seconds); DrawNestValues(hours, minutes, seconds); display.Flush(); } private void DrawNestValues(int[] hours, int[] minutes, int[] seconds) { var text = hours[2].ToString("D2") + ":" + minutes[2].ToString("D2") + ":" + seconds[2].ToString("D2"); display.DrawText(text, fontNinaB, Color.White, XLeftBound+16, CenterText + 30); } private void DrawCurrentTime(int[] hours, int[] minutes, int[] seconds) { var text = hours[1].ToString("D2") + ":" + minutes[1].ToString("D2") + ":" + seconds[1].ToString("D2"); display.DrawText(text, biggerFond, Color.White, XLeftBound-2, CenterText); } private void DrawPreviousValues(int[] hours, int[] minutes, int[] seconds) { var text = hours[0].ToString("D2") + ":" + minutes[0].ToString("D2") + ":" + seconds[0].ToString("D2"); display.DrawText(text, fontNinaB, Color.White, XLeftBound+16, CenterText - 25); } private void DrawSeperators() { display.DrawLine(Color.White, 1, XLeftBound, YCenterTopLine, XRightBound, YCenterTopLine); display.DrawLine(Color.White, 1, XLeftBound, YCenterLowLine, XRightBound, YCenterLowLine); } internal int[] GetSeconds() { var toDisplay = new[] { currentTime.Subtract(new TimeSpan(0,0,0,1)).Second, currentTime.Second, currentTime.AddSeconds(1).Second, }; return toDisplay; } internal int[] GetMinutes() { var toDisplay = new[] { currentTime.Subtract(new TimeSpan(0,0,0,1)).Minute, currentTime.Minute, currentTime.AddSeconds(1).Minute, }; return toDisplay; } internal int[] GetHour() { var toDisplay = new[] { currentTime.Subtract(new TimeSpan(0,0,0,1)).Hour, currentTime.Hour, currentTime.AddSeconds(1).Hour, }; return toDisplay; } }
The general feeling I get from this first experience with .NET Micro Framework and the AGENT SDK v0.1.1 (June 2013, Preview Release) is that I just can’t wait to get my watch!
The next step in this adventure for me is to find ways to pull information about my Windows Azure Cloud Services and create new services for the AGENT Smartwatch.
The possibilities are endless! Imagine getting notified through your watch that something has gone wrong with your Windows Azure deployments!
Do you have any ideas for the new AGENT Smartwatch?