It’s been awhile since my last log post I’ve completed my undergraduate degree and now have moved onto graduate school. I wore this watch throughout my last semester and while working on other projects for my courses I identified a ton of improvements that could be made to make the watch more useable. The improvements were all software related and I’ve finally managed to complete the implementation. The first change is the subject of this log post, the firmware.
The original firmware created for this watch was patchwork at best, I created the original version almost a year ago on one of the early working revision 3 watches and never really improved upon it. When later updates came to the hardware that same firmware kept expanding without a firm direction or plan, as a result expanding the firmware or making changes became increasingly impossible. The newer firmware is a bit more structured lending itself better to future expansion.
Before getting into the actual structure of the firmware its important to note the newer high-level improvements that were implemented:
- -The device now goes into light sleep rather than deep sleep, allowing for almost instant wakeup.
- -The device can now be woken up by the accelerometer
- -Touch handling and page drawing are handled in the structure of the program allowing for easy expansion
- -ESP32 is now acting as a BLE server rather than a client, connections no longer require scanning on the ESP32 side of things (more on the changes that come with this in the next log)
As for the UI it’s been changed significantly, instead of the old blocky aesthetic the newer version is a bit more minimal. Just the time, date, media status, and navigation circle are shown on the home screen. The circle in the bottom right is actually a button, it also animates while the home screen is active.
Tapping the navigation circle brings you to the navigation page.
From here you can access the settings, notifications page, and calendar reader. The home button will take you back to the home page.
The media play button on the home screen shows when there is music playing on Spotify. When tapped it brings up the current song playing and the media controls.
And finally, the calendar viewer. A bit of work went into this one, the calendar displays all the events for the day and spaces boxes on the left side corresponding to their start and end time. The scroll buttons on the right can be used to tap through the calendar events for the day. Overall, I found that the calendar app is one of the things I use the most just to see when my next event for the day is scheduled.
With all that said let’s get into the code structure.
As I said the newer code uses Light sleep instead of deep sleep. Deep sleep is significantly easier to use for this kind of application since it clears all of the variables on boot and thus the code starts from the same spot every time. However Light sleep does not clear the contents of ram, this means that when entering and exiting sleep mode the variables need to be updated to be the desired state and set before sleep. The onWakeup() and DeviceSleep() functions take care of this and prepare the device for operation/sleep. Although there is the enable MOSFET present on the LCD it is no longer used, instead the code initializes the LCDs sleep mode to push it into a low power state. In comparison to the old method of simply removing power from the LCD this is less efficient power-wise, but when the device wakes up there is no longer any need to initialize the LCD which took about (250ms) and resulted in some lag to a wakeup command.
Drawing pages is handled within the loop, there is now a void pointer that is labeled as “currentPage” which gets called every time the loop is iterated. This structure allows for any page to switch to any other page without updating a switch/case statement somewhere in the code. In general pages now use a structure where they have an ‘initialize’ and ‘run’ function. The Initialize function will register the touch areas required by the page and set the values of any variables that need to be used for that page. The ‘run’ function will do the normal drawing of the page.
Touch is also handled a bit more gracefully, there is now a touchArea structure in the code which can be registered to a specific area on the screen along with an action. When the screen is touched an interrupt is triggered which starts a task to check each touch area. This code will automatically trigger the associated function of the touch area when it is pressed, removing the need for the programmer to manually check button presses.
This new structure eases some of the pains of building newer pages and expanding the smartwatch code. A lot of work went into these improvements to the firmware and they’ve increased the general experience of using the watch. The next log will cover the changes to the android companion app which is integral to this project.