Python on the Openmoko Neo FreeRunner
I'm Menno Smits <http://freshfoo.com/>
Most of my work has been on the Linux platform but I currently work at Resolver Systems on a product called Resolver One. It's a unique Python development environment with a familiar spreadsheet user interface.
I don't work for Openmoko Inc or represent them in any way. I just own one of their devices and enjoy hacking with it.
I've been developing professionally with Python for about 10 years.
I maintain an open source Pythonic IMAP client library called imapclient.
Openmoko refers to both software & a company
The first phone released publicly by Openmoko Inc was the GTA01. This was only released in small quantities and was aimed mainly at developers.
More hardware specs:
(Oh my!)
Linux kernel for each distro is largely the same
Different goals and maturity
There's many different base software platforms available for the Openmoko. Although each is based largely the same Linux kernel, the software running on top of the kernel varies greatly. Each distro has different focus, completeness and stability.
2008.8 started out as the April Software Update (ASU) but was delayed and so conveniently became the August Software Update. It has now been renamed "2008.8" and was made the official "stable" release on 8/8/2008. It is under active development by Openmoko Inc and open source contributors.
The software that comes with 2008.8 is largely custom written for this distribution but includes some software from 2007.2 and Qtopia.
Some of the hardware features of the phone are controllable using DBus. More on DBus later.
FSO == FreeSmartphone.Org
This is the future
Python plays a big part
FSO aims to provide a clean standard platform for the Openmoko. It's about proving a solid base for others to extend rather than a full distributions with applications. Like 2008.8, it supports a number of GUI toolkits and aims to be toolkit agnostic.
DBus plays an even bigger role with this distribution that it does in 2008.8. The FSO project is working on a standard set of DBus APIs that can interact with most/all of the features of the phone. It is hoped this API will be generic enough to be implemented on other Linux based phones.
This will one day be the standard platform for the Openmoko.
FSO ships with Python and Python plays an integral part of the distribution. The primary test application for FSO is a pure Python application.
Test application for FSO
written in Python
useful for stealing code from when writing PyCon talks :)
Zhone is an application for developers to use when testing FSO. It provides a simple phone interface, interacting with many FSO APIs.
By using one of the more complete distributions (Qtopia, 2008.8) you will have a working phone. That said, the software isn't that reliable yet and some features such as GPRS and Wifi don't have decent GUI interfaces. Battery life isn't that great yet either because power management is still being optimised.
For developers, the phone provides an excellent, highly hackable platform. There are several GUI toolkits and development languages to choose from. The hardware is open, documented and easily accessible. The phone is your oyster.
GTK: all distros except Qtopia
Qt: 2008.8, FSO and Qtopia
There are several GUI toolkits available to Python application on the Openmoko platform. These toolkits aren't specific to Openmoko, they're all available for development on the Linux desktop. Any skills you have with these toolkits translates directly to the Openmoko.
The very popular GTK is available on all distributions except Qtopia.
Qt (from Trolltech) is available on all distros except 2007.2.
EFL is a lesser known GUI toolkit that comes out of the Enlightenment project. It can be used to create Linux GUI apps and is available on Nokia Internet tablets (the Maemo platform). Openmoko Inc has chosen to implement many of the core apps using EFL and have hired the author of Enlightenment and EFL. We will look more at EFL soon.
A sample Python application
A phone number please... ;-)
Throw provides a familiar dialer interface. You enter a phone number and then physically move the phone using a throwing motion. The recipient gets a random Monty Python quote as an SMS.
Several parts
Ecore: async events, timers, IPC + more
Edje: isolate UI from application (similar to WPF)
Written in C, with Python bindings
CSS like syntax
Probably needs a visual tool to be useful for designers
collections { group { name: "main"; parts { part { name: "dialer_box"; type: RECT; description { state: "default" 0.0; rel1 { relative: 0.0 0.26; offset: 0 0; } ... color: 0 0 0 255; } ...
#define GRID_BUTTON(parent, name, xoffset, yoffset, ...) ... ... GRID_BUTTON("dialer_box", "1", 0, 0, 4, 4, "1"); GRID_BUTTON("dialer_box", "2", 1, 0, 4, 4, "2"); ...
Cut down example from throw.edc
import ecore import ecore.evas import edje ee = ecore.evas.SoftwareX11(w=480, h=640) canvas = ee.evas edje_obj = edje.Edje(canvas, file='throw.edj', group='main') edje_obj.size = canvas.size edje_obj.show()
Cut down example from throw.py
edje_obj.signal_callback_add("mouse,clicked,1", "button_*", on_dialer_button_pressed)
button_* from any UI component whose name starts with button_
on_dialer_button_pressed is the Python function to call
ecore.timer_add(0.5, activate_loop) ecore.main_loop_begin()
Value | Bits | Description |
---|---|---|
Time1 | 32 | Seconds |
Time2 | 32 | Microseconds |
Type | 16 | 0: sync; 2: sample |
Code | 16 | for type 2, 0:x 1:y 2:z |
Value | 32 | for type 2, sample |
EVENT_FMT = 'iihhi' EVENT_SIZE = struct.calcsize(EVENT_FMT) x = y = z = None handle = open("/dev/input/event2", 'rb') while True: event = handle.read(EVENT_SIZE) (time1, time2, evType, code, value) = \ struct.unpack(EVENT_FMT, event) if evType == 2: if code == 0: x = value if code == 1: y = value if code == 2: z = value elif evType == 0 and code == 0: t = time1 + (time2 / 1000000.0) if x != None and y != None and z != None: break
This is a simplified version of the code used in Throw. The while loops terminates when a complete XYZ read has been done. As acceleration samples are read via successive event packets they are stored in the variables x, y and z. When a sync packet is seen and all axis values have been set, the loop terminates.
Naive approach
When a number is entered start sampling the accelerometer
Look for high acceleration in X axis
Current APIs send using the SIM
Future APIs will send direct to the GSM network
On FSO, we can do all this using DBus
DBus == "Desktop Bus"
Language & distro agnostic (good Python bindings)
Introspection
Used by most modern Linux distros
On Openmoko is used to talk to phone hardware
bus = dbus.SystemBus(mainloop=e_dbus.DBusEcoreMainLoop()) gsm_device_obj = bus.get_object( 'org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device') gsm_sim_iface = dbus.Interface( gsm_device_obj, 'org.freesmartphone.GSM.SIM')
This is simplified version of what Throw does. To connect to system level services a DBus client connects to the System bus. A Session bus also exists for connection to other programs belonging to the current user but this isn't really used on Openmoko.
Once the bus connection has been made, objects are retrieved using reverse domain style names. In this code GSM device is grabbed.
DBus allows objects to define various Interfaces, identified again by dotted names. Here we connect to the SIM interface of the GSM device, which allows manipulation of the SIM card.
def send(): gsm_sim_iface.StoreMessage( '07123456789', 'hi!', reply_handler=onStored, error_handler=onStoreError, )
DBus objects in Python are proxies to the real objects elsewhere. A method call on an Interface is translated to a low level IPC call to the underlying process providing that object.
Asynchronous callbacks are often used to return results of calls, especially if the call could take some time to execute.
def onStored(message_id): gsm_sim_iface.SendStoredMessage( message_id, reply_handler=onMessageSent, error_handler=onSendError )
Calling the SendStoredMessage DBus method on the SIM interface sends the message. onMessageSent is called if the message was sent successfully. onSendError is called if there was a problem.