1hz Watch Faces - Q&A

I'm not sure if many folks have been trying the new "always active" watch faces in 2.3.x, but the 2.3.0.beta1 has been out for a month or so now. It's probably getting close to the 2.3.1 SDK release, and thought I'd start a Q&A for the feature, and start with some of what I've picked up in adapting a number of watch faces to use 1hz.

I'll be calling this feature "1hz", as that's what it really is - being able to change the screen on a watch face every second.
The most common thing will likely being the ability to display seconds all the time. One thing I'll note right off, is while you can update the screen every second, the underlying data still changes at the rate it did before, so if you use 1hz for the HR, you won't see the HR change every second.

A few basics.

  • 1hz is only available on some watches. The f5, f5s, f5x, 935, and Q5, but if you support a bunch of different watches, you can easily have it on some and not others.
  • 1hz happens by way of a new onPartialUpdate() for watch faces. onUpdate() is just like it was in the past, and when you are allowed to do a 1hz update, onPartialUpdated() is called. You don't have to change a thing in your code if you don't want to use 1hz.
  • onPartialUpdate() is VERY strict as to how long it can run. You have a "power budget", and the rule is that each minute, the average run time each second can't be greater than 30 milliseconds. This is the tricky part! :)



I started with the Analog Sample in the SDK, which does show what to do, but has some things you don't need to do for digital watch faces - there's no second hand passing over a bunch of different places on the screen with a digital one. The time is in a fixed spot on the screen in most cases.



Anyway's, the first thing I did was cut back to the basics of what was needed for a digital WF. I'll attached a project with a very basic 1hz watch face, but first a few notes about it.

  • vs1hzapp.mc shows how to use the delegate for the power exceeded deligate on watches that have 1hz, and still run on watches that don't do 1hz.
  • vs1hzview.mc I tried to comment as to where to do things, where not to do things, but took a simple approach where I don't just update the seconds at 1hz, I actually do hh:mm:ss. In real code, you likely have a separate space for seconds, and your setClip() will be adjusted for that. I just wanted to get the ball rolling here :). Also, note onEnterSleep() and the code there for 1hz...
  • In onPartialUpdate(), I have a comment about a simple change to make the watch face exceed the power budget, so you can see how that works



Ask questions, suggest other ideas, whatever. That's what this thread is for!

So here's the project! (it might be a bit different than the original one that was lost in the forum update) :

VS1hz-old.zip



NOTE: I should have mentioned this before, but you want to use a 2.3.x SDK for this project!



  • Thanks Jim, that's a great video. I'm doing most of that. Pre-calc layout, don't load resources, aggressive setClips, etc.

    When debugging via the WF Diagnostics, I see;
    • "execution" time is about 3ms,
    • "graphics" time is about 0.7ms, while
    • "display" time is about 26ms (as I'm updating just over 50% the display).


    I've got the average down to 29.7ms :)

    I have noticed that it runs in the simulator for over an hour without tripping onPowerBudgetExceeded(). However, on a real fr935 device, I see my power budget being tripped within 10 minutes. So, that's interesting! Maybe I'm cutting it too close?

    Anyone else see or experience this?
  • Here's how big the clipping regions are. It's relatively big!

  • I have noticed that it runs in the simulator for over an hour without tripping onPowerBudgetExceeded(). However, on a real fr935 device, I see my power budget being tripped within 10 minutes. So, that's interesting! Maybe I'm cutting it too close?

    Anyone else see or experience this?


    I did have another ticket for this, but it didn't quite make it to the top of my queue before a bunch of other things got prioritized above it. This really shouldn't be happening since the budget calculations should be getting done the same way on device and in the sim. I'll see if I can prod the case again.


    In your gif, I see a couple of cases where it looks like the clip on the cat is not following the top and bottom of the bounding box quite as well as it could.

    Also, since all the regions will be summed to the smallest box that fits everything, you might get some good performance benefits just from scooting that top star down a bit closer to the cat. The one that flies through is good because it won't add to the budget at all. Maybe add another one that goes through lower in the main range too, so the high one is less frequent. (Maybe those are also just a bit random, and the animation just happens to show those two.) In any case, try to tighten them in to the center a bit more and it should drop your average a bit.
  • Thanks Brian, that's all great advice. That minimum bounding box is a real killer. Adding another star to reduce the bounding box size over the average might be a good idea.

    The old code is on GitHub. Once I get the average down, I'll update the repo and others can feel free to play with the source.
  • So, I managed to get within the 30ms time budget. Has been running for 12hrs without issue on the 935 :)

    Source code is up on Github for those interested in seeing how I implemented 1hz in this watchface...
    https://github.com/sunpazed/garmin-nyan-cat

    Also, version 1.7 is now in the store.
  • Average execution time: 236.602005
    Allowed execution time: 30.000000

    Seems like I have much more work to do ;)
  • Haha!

    Check out the source. Honestly, it's horrible now. Had to pre-calc quite a bit. Shaving 1ms here and there :)
  • What I do not understand is why time diagnostic time varies based on clip distance from each other vs. clipped area. I made some modifications to Jim's example (see attached pictures and programs) and when clips are near each other time was 19ms and when distance further away 28 ms, even clip area is exactly same. Is this bug or intended functionality?

    Edit: Attached are added zipped program files related to above mentioned examples (VS1hz.zip is 28ms and VS1hz2.zip is 19ms)community.garmin.com/.../1238189.png


  • CIQ calculates the "minimum bounding box". It's not just based on the size of the clipping regions, but rather the smallest box that encloses the clipping regions. If you have one clipping region in the top left, and another in the bottom right, then the minimum bounding box is the entire screen.

    This explains why the timing is increased in your example.
  • ^Thanks ftrimboli for explanation. In practice it means that I may need to change layout of the watch face to be able to reach under 30 ms budget. Another interesting issue is that even simulator says you are under 30 ms, in real watch it is not. I guess both of my examples above will fail in real watch, but I need to wait test results as I am having fenix 3HR myself that do not support 1Hz mode.

    EDIT: in practice it seems in simulator that one big clip box is better than two smaller clip boxes. Related to examples above I tried 19ms example with one big box and managed to shave 0,8 ms away still (total 18,5ms). Picture attached