[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