[PATCH] add accelerometer into odeviced subsystem

John Lee john_lee at openmoko.com
Wed Jul 16 14:43:40 CEST 2008


Now accelerometer send signals
on named channel org.freesmartphone.odeviced
path /org/freesmartphone/Device/Accelerometer
interface org.freesmartphone.Device.Accelerometer

signal 'Event' with int x, int y, int z

please review this patch.  thanks!

Signed-off-by: John Lee <john_lee at openmoko.com>
---
 conf/frameworkd.conf                           |    5 +
 framework/subsystems/odeviced/accelerometer.py |  357 ++++++++++++++++++++++++
 2 files changed, 362 insertions(+), 0 deletions(-)
 create mode 100644 framework/subsystems/odeviced/accelerometer.py

diff --git a/conf/frameworkd.conf b/conf/frameworkd.conf
index e105422..c6310b5 100644
--- a/conf/frameworkd.conf
+++ b/conf/frameworkd.conf
@@ -4,6 +4,11 @@
 # set 1 to disable the module
 disable = 0
 
+[input]
+#ignore accelerometers
+ignoreinput = 2,3
+accelerometer_type = gta02
+
 [idlenotifier]
 # set 1 to disable the module
 disable = 0
diff --git a/framework/subsystems/odeviced/accelerometer.py b/framework/subsystems/odeviced/accelerometer.py
new file mode 100644
index 0000000..a5643ac
--- /dev/null
+++ b/framework/subsystems/odeviced/accelerometer.py
@@ -0,0 +1,357 @@
+"""
+Accelerometer class.  It can run in two different modes.  In pull
+mode, it accepts read request then retrieve accelerometer values.  In
+daemon mode, it updates itself as often as possible, notifies the
+observers about value changes and answers request with its current
+state.
+
+(C) 2008 John Lee <john_lee at openmoko.com>
+(C) 2008 Openmoko, Inc.
+GPLv2 or later
+"""
+from __future__ import with_statement
+
+import math
+import os
+import struct
+from threading import RLock
+from time import sleep
+
+class Subject(object):
+    """implementation of the observer pattern.  use _notify to notify all
+    observers about state change.
+    """
+    def __init__(self):
+        self._observers_lock = RLock()
+        self._observers = []
+
+    def attach(self, observer):
+        """attach as an observer
+        """
+        with self._observers_lock:
+            self._observers.append(observer)
+
+    def detach(self, observer):
+        """detach from observers
+        """
+        with self._observers_lock:
+            self._observers.remove(observer)
+
+    def _notify(self, *args, **kwargs):
+        with self._observers_lock:
+            for o in self._observers:
+                o.update(*args, **kwargs)
+
+
+class Accelerometer(Subject):
+    """The base class of all accelerometers.
+    """
+
+    def __new__(cls, *args, **kwargs):
+        cls.sample_rate = property(cls._get_sample_rate, cls._set_sample_rate)
+        obj = object.__new__(cls, *args, **kwargs)
+        return obj
+
+    def __init__(self, device, sample_rate=None):
+        """device: the name of the input
+        sample_rate: how many samples per second
+        """
+        super(Accelerometer, self).__init__()
+        self._statelock = RLock()
+        self._state = (0, -1000, 0)
+        self._open_device(device)
+        self._daemonized = False
+        if sample_rate is not None:
+            self.sample_rate = sample_rate
+
+    def _open_device(self, device):
+        raise NotImplementedError
+
+    def _get_sample_rate(self):
+        """get sample rate
+        """
+        raise NotImplementedError
+
+    def _set_sample_rate(self, sample_rate):
+        """set sample rate
+        """
+        raise NotImplementedError
+
+    def retrieve(self):
+        """read and parse the current values.  could be time
+        consuming.
+        """
+        raise NotImplementedError
+
+    @property
+    def state(self):
+        """return the current state
+        """
+        if self._daemonized:
+            with self._statelock:
+                return self._state
+        else:
+            state = self.retrieve()
+            with self._statelock:
+                self._state = state
+                return self._state
+
+    @property
+    def daemonized(self):
+        """tells the instance is daemonized or not
+        """
+        return self._daemonized
+
+    def daemonize(self):
+        """a infinite loop to update self.state.  will notify
+        observers about state changes.
+        """
+        if self._daemonized:
+            return
+        self._daemonized = True
+        while self._daemonized:
+            state = self.retrieve()
+            with self._statelock:
+                self._state = state
+                self._notify(self._state)
+
+    def stop(self):
+        """stop daemon
+        """
+        self._daemonized = False
+
+
+class MockAccelerometer(Accelerometer):
+    """Mock accelerometer class.
+    >>> g = MockAccelerometer()
+    >>> g.sample_rate
+    100
+    >>> g.sample_rate = 400
+    >>> g.sample_rate
+    400
+    """
+    def __init__(self):
+        super(MockAccelerometer, self).__init__(None)
+        self.sample_rate = 100
+
+    def _open_device(self, device):
+        pass
+
+    def _set_sample_rate(self, sample_rate):
+        self._sample_rate = sample_rate
+
+    def _get_sample_rate(self):
+        return self._sample_rate
+
+    def retrieve(self):
+        sleep(1/self._sample_rate)
+        return (0, -1000, 0)
+
+
+class InputDevAccelerometer(Accelerometer):
+    """Read values from kernel input device
+    """
+
+    # Event types
+    EV_SYN = 0x00
+    EV_KEY = 0x01
+    EV_REL = 0x02
+    EV_ABS = 0x03
+    EV_MSC = 0x04
+    EV_SW = 0x05
+    EV_LED = 0x11
+    EV_SND = 0x12
+    EV_REP = 0x14
+    EV_FF = 0x15
+    EV_PWR = 0x16
+    EV_FF = 0x17
+    EV_MAX = 0x1f
+    EV_CNT = (EV_MAX+1)
+
+    # Relative axes
+    REL_X = 0x00
+    REL_Y = 0x01
+    REL_Z = 0x02
+    REL_RX = 0x03
+    REL_RY = 0x04
+    REL_RZ = 0x05
+    REL_HWHEEL = 0x06
+    REL_DIAL = 0x07
+    REL_WHEEL = 0x08
+    REL_MISC = 0x09
+    REL_MAX = 0x0f
+    REL_CNT = REL_MAX + 1
+
+    input_event_struct = "@llHHi"
+    input_event_size = struct.calcsize(input_event_struct)
+
+    def __init__(self, *args, **kwargs):
+        super(InputDevAccelerometer, self).__init__(*args, **kwargs)
+
+    def _open_device(self, device):
+        self.device_fd = os.open(device, os.O_RDONLY | os.O_SYNC)
+
+    def _unpack(self):
+        """struct input_event {
+	struct timeval time; /* (long, long) */
+	__u16 type;
+	__u16 code;
+	__s32 value;
+        };
+        return (tv_sec, tv_usec, type, code, value)
+        """
+        i = 0
+        while True:
+            try:
+                data = os.read(self.device_fd, InputDevAccelerometer.input_event_size)
+            except OSError:
+                pass # what should i do with this?
+            else:
+                if len(data) >= InputDevAccelerometer.input_event_size:
+                    break;
+            if i > 5:
+                raise Exception()
+        return struct.unpack(InputDevAccelerometer.input_event_struct, data)
+
+    def _unpack_xyz(self):
+        """return a 3 tuple
+        """
+        # wait for EV_SYN
+        while self._unpack()[2] != InputDevAccelerometer.EV_SYN:
+            pass
+        # now return (x, y, z)
+        return (self._unpack()[4], self._unpack()[4], self._unpack()[4])
+
+
+class Gta02Accelerometer(InputDevAccelerometer):
+    """Read values from gta02.  for now we use just one.
+    >>> g = Gta02Accelerometer()
+    >>> g.sample_rate = 400
+    >>> g.sample_rate
+    400
+    >>> g.sample_rate = 100
+    >>> g.sample_rate
+    100
+    """
+
+    INPUT_DEV = '/dev/input/event3'
+    SYS_SAMPLE_RATE = '/sys/devices/platform/spi_s3c24xx_gpio.1/spi0.1/sample_rate'
+
+    def __init__(self, device=None, sample_rate=None):
+        if device == None:
+            device = Gta02Accelerometer.INPUT_DEV
+        super(Gta02Accelerometer, self).__init__(device, sample_rate)
+
+    def _set_sample_rate(self, sample_rate):
+        """possible values: 100, 400
+        """
+        f = open(Gta02Accelerometer.SYS_SAMPLE_RATE, 'w', 0)
+        f.write('%d\n' % sample_rate)
+        f.close()
+
+    def _get_sample_rate(self):
+        f = open(Gta02Accelerometer.SYS_SAMPLE_RATE, 'r', 0)
+        sample_rate = int(f.read())
+        f.close()
+        return sample_rate
+
+    def retrieve(self):
+        return self._unpack_xyz()
+
+
+# shamelessly stole from olv
+def get_xy_theta(u):
+    """get the angle related to (0, -1), clockwise.
+    return 0 < theta < 2pi.
+    >>> get_xy_theta((0, -1000, 0))
+    0.0
+    """
+    uu = u[0] * u[0] + u[1] * u[1]
+    theta = math.acos(-u[1] / math.sqrt(uu))
+    if (u[0] < 0):
+        theta = 2 * math.pi - theta
+    return theta
+
+
+class DumpObserver(object):
+    """Does nothing but print the subject state when notified.
+    """
+
+    def __init__(self, subject):
+        subject.attach(self)
+        self.subject = subject
+
+    def update(self, state):
+        t = get_xy_theta(state)
+        print 'x = %d, y = %d, z = %d, theta = %f pi' % (state + (t / math.pi, ))
+
+
+def dump(accelerometer):
+    DumpObserver(accelerometer)
+    accelerometer.daemonize()
+
+
+def _doctest():
+    try:
+        import doctest
+    except ImportError:
+        return
+    else:
+        doctest.testmod()
+
+
+# stuffs for fso
+import dbus.service
+from helpers import DBUS_INTERFACE_PREFIX, DBUS_PATH_PREFIX
+from gobject import io_add_watch, IO_IN, source_remove, timeout_add, timeout_add_seconds, idle_add
+
+
+class FSOSubsystem(dbus.service.Object):
+
+    DBUS_INTERFACE = DBUS_INTERFACE_PREFIX + ".Accelerometer"
+    DBUS_PATH = DBUS_PATH_PREFIX + "/Accelerometer"
+
+    def __init__(self, accelerometer, bus):
+        self.path = FSOSubsystem.DBUS_PATH
+        self.interface = FSOSubsystem.DBUS_INTERFACE
+        self.accelerometer = accelerometer
+        dbus.service.Object.__init__(self, bus, self.path)
+        if hasattr(accelerometer, 'device_fd'):
+            io_add_watch(accelerometer.device_fd, IO_IN, self.onInputActivity)
+
+    def onInputActivity(self, source, condition):
+        self.Event(*self.accelerometer.retrieve())
+        return True
+
+    @dbus.service.signal(DBUS_INTERFACE, "iii")
+    def Event(self, x, y, z):
+        pass
+
+
+def factory(prefix, controller):
+    device_map = {'gta02': Gta02Accelerometer}
+    config = controller.config
+    try:
+        device_class = device_map[config.get('input', 'accelerometer_type')]
+    except KeyError:
+        device_class = MockAccelerometer
+    return [FSOSubsystem(device_class(), controller.bus), ]
+
+
+def fso_test():
+    from dbus.mainloop.glib import DBusGMainLoop
+    from dbus import SystemBus
+    import sys
+    a = Gta02Accelerometer()
+    b = SystemBus(mainloop=DBusGMainLoop())
+    f = FSOSubsystem(a, b)
+    from gobject import MainLoop
+    try:
+        MainLoop().run()
+    except KeyboardInterrupt:
+        print >>sys.stderr, 'ctrl-c: exiting'
+        sys.exit(0)
+
+
+if __name__ == '__main__':
+    _doctest()
-- 
1.5.5.3




More information about the smartphones-standards mailing list