So a common request is to add the ability to send a menu to the phone and have the phone draw it and send back the users selection. My first attempt at this is shown below.
To use it send a Message type "GeneralPurposeWatchMsg" with option set at 0x43. The length set to max and the first byte of the string is the Length of the original string in characters. The rest of the payload is a Huffman encoded space separated list of strings. These represents the menu items to display. The huffman encoding uses a fixed tree based on the frequency of characters in the English language. This allows us to send all the text in one message and hopefully keep latency to a minimum. I haven't got around to writing the java to encode the string but I have written a python script that generates the bye sequence needed for a given string which you can then place in a payload and send. For example to menu shown above (Ignore the bad layout that will be fixed!) the strings would be "toggle next back volup voldown". this string is 30 characters long so too long to fit in our payload but once encoded takes up just 20 characters.
On selection the watch sends back a GeneralPurposePhoneMsg with the type set to 0x43and the index of the menu item selected as the first byte of payload.
It's possible that menus with more items more like a list view would be required and up and down could be used to select items. This would be more useful for browsing music on the phone or other larger datasets.
I'll maybe have a go at this tomorrow.
Garthy.com
Wednesday 5 October 2011
Tuesday 4 October 2011
Metawatch Music Controls in Firmware
Metawatch kinda has music controls but they can be kinda flaky. With my menu system in my modified firmware it was very easy to add. First I needed to send music messages to the watch but as you can't define your own messages i chose to use "GeneralPurposePhoneMsg" with an option of 0x42. The first byte in the payload would be the action. I used the constants already defined in MediaControl class.
I then added a Music menu to my firmware which took all of 10 minutes. This has none of the problems with the phone defined shortcuts overriding items. I'm in the middle of a refactor of the firmware and plan to have multiple home screens like the android launcher with the music controls being one.
All this code can be seen in these two commits:-
https://github.com/garthy/MetaWatch-WDS11x-IAR/commit/acae64ff3b50c028415405f4a9faf54691400a5f
https://github.com/garthy/MWM-for-Android/commit/89574c66b9a231b8886b33a0d8a6f24d8834b27b
I then added a Music menu to my firmware which took all of 10 minutes. This has none of the problems with the phone defined shortcuts overriding items. I'm in the middle of a refactor of the firmware and plan to have multiple home screens like the android launcher with the music controls being one.
All this code can be seen in these two commits:-
https://github.com/garthy/MetaWatch-WDS11x-IAR/commit/acae64ff3b50c028415405f4a9faf54691400a5f
https://github.com/garthy/MWM-for-Android/commit/89574c66b9a231b8886b33a0d8a6f24d8834b27b
Thursday 29 September 2011
Metawatch Menus
The top menu
The Bluetooth Menu
and the clock settings menu
This change took 2 minutes. Not sure how long it would have taken with the old system.
I changed The code
MENU_START(menu1)
MENU_DYNAMIC_ICON_ACTION(bluetooth_get_discoverability_icon, bluetooth_toggle_discoverability, 0) // no update as the spp callback does the refresh
MENU_DYNAMIC_ICON_ACTION(LinkAlarmIcon, ToggleLinkAlarmEnable, MENU_FLAG_UPDATE)
MENU_STATIC_ICON_ACTION(pLedIcon, 0, 0)
MENU_DYNAMIC_ICON_ACTION(bluetooth_get_status_icon, bluetooth_toggle_bluetooth, 0) // no update as the spp callback does the refresh
MENU_END
MENU_START(menu2)
MENU_MSG_BUTTON(SoftwareResetMsg, NO_MSG_OPTIONS, pResetButtonIcon, BUTTON_STATE_PRESSED, MENU_FLAG_UPDATE)
MENU_DYNAMIC_ICON_ACTION(bluetooth_get_secure_smiple_pairing_icon, bluetooth_toggle_secure_smiple_pairing, MENU_FLAG_UPDATE)
MENU_STATIC_ICON_ACTION(pLedIcon, 0, 0)
MENU_STATIC_ICON_ACTION(pRstPinIcon, ToggleRstPin, MENU_FLAG_UPDATE)
MENU_END
MENU_START(menu3)
MENU_STATIC_ICON_ACTION(pNormalDisplayMenuIcon,ToggleIdleBufferInvert, MENU_FLAG_UPDATE)
MENU_DYNAMIC_ICON_ACTION(SecondsIcon, ToggleSecondsHandler, MENU_FLAG_UPDATE)
MENU_STATIC_ICON_ACTION(pLedIcon, 0, 0)
MENU_DYNAMIC_ICON_ACTION(TimeFormatIcon, ToggleTimeFormat, MENU_FLAG_UPDATE)
MENU_END
To
MENU_START(bluetooth)
MENU_DYNAMIC_ICON_ACTION(bluetooth_get_discoverability_icon, bluetooth_toggle_discoverability, 0) // no update as the spp callback does the refresh
MENU_DYNAMIC_ICON_ACTION(bluetooth_get_secure_smiple_pairing_icon, bluetooth_toggle_secure_smiple_pairing, MENU_FLAG_UPDATE)
MENU_STATIC_ICON_ACTION(pLedIcon, 0, 0)
MENU_DYNAMIC_ICON_ACTION(bluetooth_get_status_icon, bluetooth_toggle_bluetooth, 0) // no update as the spp callback does the refresh
MENU_END
MENU_START(clock)
MENU_DYNAMIC_ICON_ACTION(SecondsIcon, ToggleSecondsHandler, MENU_FLAG_UPDATE)
MENU_DYNAMIC_ICON_ACTION(DateFormatIcon, ToggleDateFormat, MENU_FLAG_UPDATE)
MENU_STATIC_ICON_ACTION(pLedIcon, 0, 0)
MENU_DYNAMIC_ICON_ACTION(TimeFormatIcon, ToggleTimeFormat, MENU_FLAG_UPDATE)
MENU_END
MENU_DEF(dev2)
MENU_START_WITH_NEXT(dev, dev2)
MENU_STATIC_ICON_ACTION(pNormalDisplayMenuIcon,ToggleIdleBufferInvert, MENU_FLAG_UPDATE)
MENU_MSG_BUTTON(SoftwareResetMsg, NO_MSG_OPTIONS, pResetButtonIcon, BUTTON_STATE_PRESSED, MENU_FLAG_UPDATE)
MENU_DYNAMIC_ICON_ACTION(LinkAlarmIcon, ToggleLinkAlarmEnable, MENU_FLAG_UPDATE)
MENU_STATIC_ICON_ACTION(pLedIcon, 0, 0)
MENU_END
MENU_START_WITH_NEXT(dev2, dev)
MENU_STATIC_ICON_ACTION(pNormalDisplayMenuIcon,ToggleIdleBufferInvert, MENU_FLAG_UPDATE)
MENU_FLAG_UPDATE)
MENU_DYNAMIC_ICON_ACTION(LinkAlarmIcon, ToggleLinkAlarmEnable, MENU_FLAG_UPDATE)
MENU_STATIC_ICON_ACTION(pLedIcon, 0, 0)
MENU_STATIC_ICON_ACTION(pRstPinIcon, ToggleRstPin, MENU_FLAG_UPDATE)
MENU_END
MENU_START(TopLevel)
MENU_SUB(bluetooth, pBluetooth, MENU_FLAG_UPDATE)
MENU_SUB(clock, pClockSettings, MENU_FLAG_UPDATE)
MENU_STATIC_ICON_ACTION(pLedIcon, 0, 0)
MENU_SUB(dev, pDevSettings, MENU_FLAG_UPDATE)
MENU_END
Metawatch Firmware Hacking
So I got a new watch.....
And I do what anyone does when they get a new piece of technology....
Improve it! First I fixed it so the date and time were shown in the correct format.
You can move left and right. But I need to rethink the design and how it fits with the watch architecture. I'd like to split out all the idle screens to separate pluggable entities from the code that handles the LCD. This would make it easer to swap functionality in and out. I'm having to think about how a app can take control from the watch safely and fast. All this source is available on git hub. https://github.com/garthy/MetaWatch-WDS11x-IAR/
Then added a menu item to allow configuring of this.
Now adding this menu item was quite tricky. The code does lots of message passing and has a custom message for each item. I decided to rewrite the menuing system and made life alot easier(in my opinion)[1], I've since added items for the Day/Month ordering (Although why anyone would want to change this is beyond me ;-) ) and am currently trying out sub menu organisation. The new system makes it very easy to reorder the menus. I've stuck with the current menu design but may experiment with others and possibly add dynamic menus that can be added by applications on the phone (A common request)
Then of course I moved onto the next stage. Writing "Space invaders" for it. (Less encumbered than Xtris) This is the screen.
You can move left and right. But I need to rethink the design and how it fits with the watch architecture. I'd like to split out all the idle screens to separate pluggable entities from the code that handles the LCD. This would make it easer to swap functionality in and out. I'm having to think about how a app can take control from the watch safely and fast. All this source is available on git hub. https://github.com/garthy/MetaWatch-WDS11x-IAR/
Friday 26 March 2010
Mignonette game SDK
Tomorrow I'm going to be going to a Mitch Altman workshop "How To Make Cool Things With Microcontrollers"[1] and I was looking at the choices of things to make and noticed the "Mignonette Game kit". It has a SDK of sorts and a few games had been written for it so I though this would be a cool choice. Being unable to find an emulator I decided to port the game SDK to SDL[3] so I could run the games on a wide variaty of platforms that SDL supports.
After a little work I present you with the miggl game SDK. This compiles on Windows and Linux and supports the graphics and sound APIs. I've restructured them a bit and hacked around with the code to abstract it and it now has less hardware specific things exposed. Most of the common code is in libmiggl.c and then the platform specific code is in miggl-$(TARGET).c.
The current targets are SDL and ARDUINO although it should be noted that although the ARDUINO target compiles I've never tested the code generated as I don't have the hardware yet.
I've also written a game called invaders that is a space invaders clone which I havn't finished yet. It seems to work fine under SDL but It'll be interesting to see if it runs on the arduino.
I'm just working on getting my mercurial repo public but if you'd like to have a look in the mean time you can download from here.
[1] - http://bristol.hackspace.org.uk/journal/2010/02/how-to-make-cool-things-with-microcontrollers/
[2] - http://www.mignonette-game.com
[3] - http://www.libsdl.org
After a little work I present you with the miggl game SDK. This compiles on Windows and Linux and supports the graphics and sound APIs. I've restructured them a bit and hacked around with the code to abstract it and it now has less hardware specific things exposed. Most of the common code is in libmiggl.c and then the platform specific code is in miggl-$(TARGET).c.
The current targets are SDL and ARDUINO although it should be noted that although the ARDUINO target compiles I've never tested the code generated as I don't have the hardware yet.
I've also written a game called invaders that is a space invaders clone which I havn't finished yet. It seems to work fine under SDL but It'll be interesting to see if it runs on the arduino.
I'm just working on getting my mercurial repo public but if you'd like to have a look in the mean time you can download from here.
[1] - http://bristol.hackspace.org.uk/journal/2010/02/how-to-make-cool-things-with-microcontrollers/
[2] - http://www.mignonette-game.com
[3] - http://www.libsdl.org
Saturday 6 March 2010
Google Appengine upload_data to restore keys via bulkloader is broken (Using local SDK)
I've logged an issue. 2925
I've been trying to save and restore my dataset including keys using the bulkloader as docuemnted. There are a few undocumented things that are not mentioned and quite important. First is how to save your model keys. If we had the following model
Then the following is defined to export the model
Notice the '__key__' Field. This saves the key in the csv for that model.
The following should load the model back in with the key, updating it if the model already exists.
Notice the special field key. This is Used in the Model.__init__ constructor in file "google/appengine/ext/db/__init__.py" Line 655 to recreate the Key from the string. This is created in bulkloader.py line 1260.
This key is then used when _populate_entity "google/appengine/ext/db/__init__.py" is called from bulkload at line 1264
_populate_entity then fills out the 'id' field with using the id() call on the key. The Issue with this is that key.id() returns a long
The Entity is then Created but line 422 of file "google/appengine/api/datastore.py" checks to see if the id is an int but it's a long so the creation fails. Can the id be a long?
My solution is to cast the return from "self._key.id()" at "google/appengine/ext/db/__init__.py" line 823 to an int.
This then fixs stuff nicly.
I've been trying to save and restore my dataset including keys using the bulkloader as docuemnted. There are a few undocumented things that are not mentioned and quite important. First is how to save your model keys. If we had the following model
class TestModel(BaseModel):
name = db.StringProperty(required=True)
Then the following is defined to export the model
class TestModelExporter(bulkloader.Exporter):
def __init__(self):
bulkloader.Exporter.__init__(self, 'TestModel',
[('__key__', str, None),
('name', str, None),
])
Notice the '__key__' Field. This saves the key in the csv for that model.
The following should load the model back in with the key, updating it if the model already exists.
class TestModelLoader(bulkloader.Loader):
def __init__(self):
bulkloader.Loader.__init__(self, 'TestModel',
[('key', lambda x: x.decode('utf-8')),
('name', lambda x: x.decode('utf-8')),
])
Notice the special field key. This is Used in the Model.__init__ constructor in file "google/appengine/ext/db/__init__.py" Line 655 to recreate the Key from the string. This is created in bulkloader.py line 1260.
This key is then used when _populate_entity "google/appengine/ext/db/__init__.py" is called from bulkload at line 1264
_populate_entity then fills out the 'id' field with using the id() call on the key. The Issue with this is that key.id() returns a long
The Entity is then Created but line 422 of file "google/appengine/api/datastore.py" checks to see if the id is an int but it's a long so the creation fails. Can the id be a long?
My solution is to cast the return from "self._key.id()" at "google/appengine/ext/db/__init__.py" line 823 to an int.
This then fixs stuff nicly.
Subscribe to:
Posts (Atom)