Python on the Openmoko Neo FreeRunner

Openmoko Case

Who is this guy?

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.

What is Openmoko?

Openmoko.org

What is the Neo FreeRunner?

Openmoko Case

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:

How Open is It?

Software Distributions

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.

2007.2

2007.2 screenshot

Qtopia

Qtopia screenshot

2008.8 (ASU)

2008.8 screenshot

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

FSO screenshot

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.

FSO: Zhone

Zhone screenshot

Zhone is an application for developers to use when testing FSO. It provides a simple phone interface, interacting with many FSO APIs.

SHR

Debian

Debian screenshot

Can I Use the Phone Today?

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.

What about the iPhone?

Apple

Where Python Fits In

Python UI Development

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.

Introducing "Throw" (1)

Throw screenshot

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.

Introducing "Throw" (2)

EFL

Edje

Developing with Edje

Edje workflow

.edc files

.edc Example (1)

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;
        }
  ...

.edc Example (2)

#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

Loading edj files from Code

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

Attaching to Signals

edje_obj.signal_callback_add("mouse,clicked,1", "button_*",
                             on_dialer_button_pressed)

Starting EFL Based Apps

ecore.timer_add(0.5, activate_loop)
ecore.main_loop_begin()

The Accelerometers

Accelerometer Packets

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

Accelerometers in Python

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.

Detecting a "throw"

Sending an SMS

Catching the DBus

DBus Setup From Python

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.

Storing a Message to the SIM

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.

Sending a Stored Message

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.

That's it