]> git.neil.brown.name Git - freerunner.git/commitdiff
lock: various updates
authorNeilBrown <neilb@suse.de>
Sun, 6 Feb 2011 09:22:37 +0000 (20:22 +1100)
committerNeilBrown <neilb@suse.de>
Sun, 6 Feb 2011 09:22:37 +0000 (20:22 +1100)
Signed-off-by: NeilBrown <neilb@suse.de>
lock/alerts.doc [new file with mode: 0644]
lock/lock-internalsound.py [new file with mode: 0644]
lock/lock.py

diff --git a/lock/alerts.doc b/lock/alerts.doc
new file mode 100644 (file)
index 0000000..6061ddc
--- /dev/null
@@ -0,0 +1,61 @@
+
+Alerts
+------
+
+'lock' is the intermediary for alerts.
+
+Alerts are registered by creating a file in /var/run/alert/NAME
+
+Providing 'lock' is running, it reads /etc/alert/NAME and performs the
+actions listed.  
+These can be:
+
+  sound:/file/name
+  vibrate:duration,on,off
+  led:name,on,off
+  flash:
+
+Alert sources are:
+
+ SMS - this requires a single alert, no repeats.
+       file should be removed when alert ends.
+ RING - This alert can be actively repeated by changing the file, and
+       can be aborted by removing file.
+
+ ALARM - once only, but can go for longer and get more annoying.
+
+ LOW-BATTERY - single quiet short
+
+If the file still exists when the alert finishes we either
+ - replay the alert if the mtime has changed
+ - delete the file
+
+Other than 'sound' everything has duration, on, off.  They are in millisecs
+Duration defaults to the length of the sound, or 5 seconds if there is no sound
+'on' defaults to 500
+'off' defaults to the same as 'on'
+
+names are:
+  everything in '/sys/class/leds'  (unique substring works)
+  display
+
+
+When the screen is woken up, everything stops.
+If an alert is issued while the screen is awake, it continues until
+some input.
+
+Different modes/personalities are selected by modes files created in
+/var/lib/personality/XXX
+
+When reading the actions for an alert we read
+  alert
+  alert.XXX  for each XXX
+  XXX        for each XXX
+
+settings override, so if 'SILENT' contains 'sound:' then when SILENT mode
+is in effect, no sound is made.
+
+So 'alert' serves as a default if no personality setting has been made.
+
+How does this allow for different tones depending on who the caller is?
+Maybe the alert can be  NAME.GROUP so SMS.friends
diff --git a/lock/lock-internalsound.py b/lock/lock-internalsound.py
new file mode 100644 (file)
index 0000000..3a16605
--- /dev/null
@@ -0,0 +1,430 @@
+#!/usr/bin/env python
+
+# This software is copyright Neil Brown 2009.
+# It is licensed to you under the terms of the
+# GNU General Public License version 2.
+#
+#
+# blank and lock the screen when there is no activity.
+#
+# We detect activity by watching touch screen, power button,
+# aux button
+# After a period with no activity, we drop brightness to 20%
+# and Grab all devices.
+# Any activity at this stage returns us to 100% and no grab
+# Continued inactivity turns display off.  After that, require
+# a button (AUX or Power) to reactivate.
+#
+# If the device seems really idle, we suspend with "apm -s"
+# Other applications can disable this by getting a LOCK_SH
+# lock on /var/run/suspend_disabled
+#
+
+import gobject
+import gtk
+import fcntl
+import os
+import sys
+import struct
+import time
+import suspend
+import dnotify
+import play
+from subprocess import Popen, PIPE
+
+class EvDev:
+    def __init__(self, path, on_event):
+        self.f = os.open(path, os.O_RDWR|os.O_NONBLOCK);
+        self.ev = gobject.io_add_watch(self.f, gobject.IO_IN, self.read)
+        self.on_event = on_event
+        self.grabbed = False
+        self.downlist = []
+    def read(self, x, y):
+        try:
+            str = os.read(self.f, 16)
+        except:
+            return True
+
+        if len(str) != 16:
+            return True
+        (sec,usec,typ,code,value) = struct.unpack_from("IIHHI", str)
+        if typ == 0x01:
+            # KEY event
+            if value == 0:
+                # 'up' - remove from downlist
+                if code in self.downlist:
+                    self.downlist.remove(code)
+            else:
+                # 'down' - add to downlist
+                if code not in self.downlist:
+                    self.downlist.append(code)
+        self.on_event(self.down_count(), typ, code, value)
+        return True
+    def down_count(self):
+        if len(self.downlist) == 0:
+            return 0
+        # double check, we might have missed an 'up' event somehow.
+        try:
+            rv = fcntl.ioctl(self.f, EVIOCGKEY(768/8), (768/8) * " " )
+            l = len(rv)/4
+            ra = struct.unpack('%dI' % l, rv)
+            isup = []
+            for k in self.downlist:
+                by = int(k/8)
+                bt = k % 8
+                if by < l and ((ra[by] >> bt) & 1) == 0:
+                    isup.append[k]
+            for k in isup:
+                self.downlist.remove(k)
+        except:
+            pass
+        return len(self.downlist)
+
+    def grab(self):
+        if self.grabbed:
+            return
+        #print "grab"
+        fcntl.ioctl(self.f, EVIOCGRAB, 1)
+        self.grabbed = True
+    def ungrab(self):
+        if not self.grabbed:
+            return
+        #print "release"
+        fcntl.ioctl(self.f, EVIOCGRAB, 0)
+        self.grabbed = False
+
+FBIOBLANK = 0x4611
+FB_BLANK_UNBLANK = 0
+FB_BLANK_POWERDOWN = 4
+
+EVIOCGRAB = 0x40044590
+def EVIOCGKEY(len):
+    return 0x80004518 + len * 65536
+
+
+class SetAlerts:
+    def __init__(self, alertdir, actiondir):
+        # arrange to respond to alerts.
+        # If a name appears in 'alertdir', respond based
+        # on the content of the name name in 'actiondir'.
+        # Currently that must be a WAV file to be played
+        # If the file disappears, the action must stop instantly
+        # If the file is newer when the action completes, it is
+        # restarted
+        self.alertdir = alertdir
+        self.actiondir = actiondir
+        self.watch = dnotify.dir(alertdir)
+        self.active = {}
+        self.watch.watchall(self.runalert)
+
+    def runalert(self):
+        gobject.idle_add(self.alert)
+        return True
+
+    def alert(self):
+        print 'X'
+        # Only look for new entries here.
+        for n in os.listdir(self.alertdir):
+            if n in self.active:
+                continue
+            if n[0] == '.':
+                continue
+            self.add_alert(n)
+        print 'Y'
+        return False
+
+    def add_alert(self, name):
+        print "adding", name
+        self.active[name] = (None, None, None)
+        w = self.watch.watch(name, lambda x : self.runcheck(x, name))
+        if w.ino == 0:
+            del self.active[name]
+            # already disappeared
+            return
+        a = self.action(name)
+        self.active[name] = (w, a, w.mtime)
+
+    def runcheck(self, w, name):
+        gobject.idle_add(lambda : self.check(w, name))
+        return True
+    def check(self, w, name):
+        if name not in self.active:
+            print "check", name, "not found"
+            return False
+        print "check", name
+        (w2, a, mtime) = self.active[name]
+        if w.ino == 0:
+            if a:
+                a.finished = True
+            del self.active[name]
+            return False
+        if a == None and w.mtime > mtime + 1:
+            # play back had stopped - start it again
+            print "restart play"
+            a = self.action(name)
+            self.active[name] = (w, a, w.mtime)
+        return False
+
+    def action(self, name, a = None):
+        try:
+            fname = os.path.join(self.actiondir, name)
+            if a:
+                a.setfile(fname)
+            else:
+                a = play.Play(fname,
+                              done = lambda : self.action_done(name))
+        except:
+            a = None
+        print "action", name, "retuned", a
+        return a
+
+    def action_done(self, name):
+        print name, "done"
+        if name not in self.active:
+            return
+        (w, a, mtime) = self.active[name]
+        if w.ino == 0:
+            del self.active[name]
+            return
+        if w.mtime <=  mtime + 3:
+            a = None
+        else:
+            print "play again", w.mtime, mtime
+            # play again
+            a = self.action(name, a)
+        self.active[name] = (w, a, w.mtime)
+        
+
+
+class Screen:
+    def __init__(self):
+        self.state = "unknown"
+        f = open("/sys/class/backlight/gta02-bl/max_brightness")
+        self.max = int(f.read())
+        f.close()
+    def bright(self, pcent):
+        b = int(pcent * self.max / 100)
+        f = open("/sys/class/backlight/gta02-bl/brightness","w")
+        f.write("%d\n" % b)
+        f.close()
+    def power(self, ioc):
+        f = open("/dev/fb0", "r+")
+        fcntl.ioctl(f, FBIOBLANK, ioc)
+        f.close()
+    def on(self):
+        if self.state != "on":
+            self.power(FB_BLANK_UNBLANK)
+            self.state = "on"
+        self.bright(100)
+    def dim(self):
+        if self.state != "on":
+            self.power(FB_BLANK_UNBLANK)
+            self.state = "on"
+        self.bright(20)
+    def off(self):
+        self.bright(0)
+        if self.state != "off":
+            self.power(FB_BLANK_POWERDOWN)
+            self.state = "off"
+
+def grab_all():
+    global screen, power, aux
+    screen.grab()
+    power.grab()
+    aux.grab()
+
+def release_all():
+    global screen, power, aux
+    screen.ungrab()
+    power.ungrab()
+    aux.ungrab()
+
+timeout = None
+state = "full"
+dimtime = 15
+enable_suspend = True
+def set_timeout():
+    global timeout
+    global state, enable_suspend
+    global dimtime
+    #print "set timeout for", state
+    if timeout != None:
+        gobject.source_remove(timeout)
+    if state == "full":
+        timeout = gobject.timeout_add(dimtime*1000, set_dim)
+    elif state == "dim":
+        timeout = gobject.timeout_add(10*1000, set_off)
+    elif state == "insta-lock":
+        timeout = gobject.timeout_add(1000, set_off)
+    elif state == "off" and enable_suspend:
+        timeout = gobject.timeout_add(30*1000, set_suspend)
+
+    set_ico_file()
+
+def set_dim():
+    global state
+    global aux, power, screen
+    if aux.down_count() + power.down_count() + screen.down_count() > 0:
+        # button still down
+        set_timeout()
+        return
+    display.dim()
+    grab_all()
+    state = "dim"
+    set_timeout()
+
+def set_off():
+    global state, dimtime
+    display.off()
+    state = "off"
+    set_timeout()
+    dimtime = 15
+
+def read_num(filename, default = 0, sep = None):
+    try:
+        f = open(filename)
+    except:
+        f = [ "%d" % default ]
+    num = default
+    for l in f:
+        l = l.split(sep)[0].strip()
+        try:
+            num = float(l)
+            break
+        except:
+            num = default
+    return num
+
+#Active Internet connections (w/o servers)
+#Proto Recv-Q Send-Q Local Address           Foreign Address         State
+#tcp        0     48 192.168.2.202:22        192.168.2.200:34244     ESTABLISHED
+#tcp        0      0 192.168.2.202:22        192.168.2.200:41473     ESTABLISHED
+def external_tcp():
+    # check for TCP connections to external computers.
+    netstat = Popen(['netstat','-nt'], stdout = PIPE, close_fds = True)
+    for l in netstat.stdout:
+        l = l.strip()
+        f = l.split()
+        if f[0] != "tcp" or f[5] != 'ESTABLISHED':
+            continue
+        a = f[4].split(':')
+        if a[0] != "127.0.0.1":
+            return True
+    return False
+
+def set_suspend():
+    global state, display
+    # Check for lock file
+    try:
+        f = open("/var/run/suspend_disabled", "r+")
+    except:
+        f = None
+    if f:
+        try:
+            fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
+        except:
+            set_timeout()
+            return
+
+    # Check for loadavg > 0.5
+    load = read_num("/proc/loadavg")
+    if load > 0.5:
+        set_timeout()
+        return
+
+    # Check for USB power, at least 500mA
+    current = read_num("/sys/class/i2c-adapter/i2c-0/0-0073/pcf50633-mbc/usb_curlim")
+    if current >= 500:
+        set_timeout()
+        return
+
+    #if external_tcp():
+    #    set_timeout()
+    #    return
+
+    os.system("apm -s")
+    if f:
+        f.close()
+    rr = suspend.resume_reason()
+    if rr == 'PMU power-button-down':
+        wake_all(0)
+        return
+
+    state = "off"
+    set_timeout()
+
+
+def wake_all(down_cnt, *rest):
+    global state, dimtime
+    #print "wake all"
+    display.on()
+    if down_cnt == 0:
+        release_all()
+    if state == "dim" and dimtime < 120:
+        dimtime += 15
+    if state != "disable":
+        state = "full"
+    set_timeout()
+
+def wake_dim(down_cnt, *rest):
+    global state
+    #print "wake_dim"
+    if state == "dim" or state == "full":
+        wake_all(down_cnt)
+
+
+ico_file = None
+def set_ico_file():
+    global state, ico_file, ico
+    if state == "disable":
+        file = "lock-no.png"
+    elif state == "full":
+        if enable_suspend:
+            file = "lock-un.png"
+        else:
+            file = "lock-un-nosusp.png"
+    else:
+        if enable_suspend:
+            file = "lock.png"
+        else:
+            file = "lock-nosusp.png"
+    if file != ico_file:
+        ico.set_from_file("/usr/local/pixmaps/" + file)
+        ico_file = file
+
+last_ping = 0
+prev_ping = 0
+def ping(icon):
+    global state, enable_suspend, last_ping, prev_ping
+    if time.time() - prev_ping < 0.8:
+        grab_all()
+        state = "insta-lock"
+    elif state == "disable":
+        enable_suspend = False
+        state = "full"
+    elif not enable_suspend:
+        enable_suspend = True
+        state = "full"
+    else:
+        state = "disable"
+    prev_ping = last_ping
+    last_ping = time.time()
+    set_timeout()
+
+def main():
+    global display, ico
+    global screen, power, aux
+    aux = EvDev("/dev/input/event4", wake_all)
+    power = EvDev("/dev/input/event0", wake_all)
+    screen = EvDev("/dev/input/event1", wake_dim)
+    alert = SetAlerts("/var/run/alert", "/etc/alert")
+    state = "full"
+    display = Screen()
+    display.on()
+    ico = gtk.StatusIcon()
+    set_timeout()
+    ico.connect("activate", ping)
+
+    gtk.main()
+
+main()
index 9adc658b7081572829f1fc3c866b58b257ccb280..42b22bcf13553573fabbb4dbccdba6d2e0849c27 100644 (file)
@@ -27,6 +27,9 @@ import os
 import sys
 import struct
 import time
+import suspend
+import dnotify
+
 from subprocess import Popen, PIPE
 
 class EvDev:
@@ -44,7 +47,7 @@ class EvDev:
 
         if len(str) != 16:
             return True
-        (sec,usec,typ,code,value) = struct.unpack_from("IIHHI", str)
+        (sec,usec,typ,code,value) = struct.unpack_from("IIHHi", str)
         if typ == 0x01:
             # KEY event
             if value == 0:
@@ -54,8 +57,11 @@ class EvDev:
             else:
                 # 'down' - add to downlist
                 if code not in self.downlist:
-                    self.downlist.append(code)
-        self.on_event(self.down_count(), typ, code, value)
+                    # ignore the 'play' butten (headphone insert)
+                    if code != 207:
+                        self.downlist.append(code)
+        moment = sec + float(usec)/1000000
+        self.on_event(self.down_count(), moment, typ, code, value)
         return True
     def down_count(self):
         if len(self.downlist) == 0:
@@ -98,6 +104,123 @@ EVIOCGRAB = 0x40044590
 def EVIOCGKEY(len):
     return 0x80004518 + len * 65536
 
+def sysfs_write(file, val):
+    try:
+        f = open(file, "w")
+        f.write(val)
+        f.close()
+    except:
+        pass
+    
+vib_timer = None
+def set_vibrate(on, off, total):
+    global vib_timer
+    if vib_timer:
+        return
+    vib = "/sys/class/leds/neo1973:vibrator"
+    sysfs_write(vib+"/trigger", "none")
+    sysfs_write(vib+"/trigger", "timer")
+    sysfs_write(vib+"/delay_on", "%d"%on)
+    sysfs_write(vib+"/delay_off", "%d"%off)
+    vib_timer = gobject.timeout_add(total, clear_vibrator)
+def clear_vibrator():
+    global vib_timer
+    if vib_timer:
+        gobject.source_remove(vib_timer)
+    vib_timer = None
+    vib = "/sys/class/leds/neo1973:vibrator"
+    sysfs_write(vib+"/trigger", "none")
+    
+
+class SetAlerts:
+    def __init__(self, alertdir, actiondir):
+        # arrange to respond to alerts.
+        # If a name appears in 'alertdir', respond based
+        # on the content of the same name in 'actiondir'.
+        # Currently that must be a WAV file to be played
+        # If the file disappears, the action must stop instantly
+        # If the file is newer when the action completes, it is
+        # restarted
+        self.alertdir = alertdir
+        self.actiondir = actiondir
+        self.watch = dnotify.dir(alertdir)
+        self.active = {}
+        self.watch.watchall(self.runalert)
+        self.pref = "normal"
+
+    def setpref(self, str):
+        self.pref = str
+
+    def runalert(self):
+        gobject.idle_add(self.alert)
+        return True
+
+    def alert(self):
+        # Only look for new entries here.
+        for n in os.listdir(self.alertdir):
+            if n in self.active:
+                continue
+            if n[0] == '.':
+                continue
+            self.add_alert(n)
+        return False
+
+    def add_alert(self, name):
+        print "adding", name
+        self.active[name] = (None, None, None)
+        w = self.watch.watch(name, lambda x : self.runcheck(x, name))
+        if w.ino == 0:
+            del self.active[name]
+            # already disappeared
+            return
+        a = self.action(name)
+        self.active[name] = (w, a, w.mtime)
+
+    def runcheck(self, w, name):
+        gobject.idle_add(lambda : self.check(w, name))
+        return True
+    def check(self, w, name):
+        if name not in self.active:
+            print "check", name, "not found"
+            return False
+        print "check", name
+        (w2, a, mtime) = self.active[name]
+        if w.ino == 0:
+            if a:
+                self.stop(a)
+            del self.active[name]
+            return False
+        #if a and not os.path.exists(a):
+        #    a = None
+        #if a == None and w.mtime > mtime + 1:
+        #    # play back had stopped - start it again
+        #    print "restart play"
+        a = self.action(name)
+        self.active[name] = (w, a, w.mtime)
+        return False
+
+    def action(self, name):
+        n = '/var/run/sound/14R-ring'+name
+        try:
+            os.symlink(os.path.join(self.actiondir, self.pref, name), n)
+        except:
+            pass
+        set_vibrate(200,400,1800)
+        if display.state != 'on':
+            set_dim()
+        return n
+    def stop(self, name):
+        try:
+            os.unlink(name)
+        except:
+            pass
+
+    def stopall(self):
+        for n in self.active:
+            w, a, w.time = self.active[n]
+            self.stop(a)
+            self.active[n] = (w, None, 0)
+
 class Screen:
     def __init__(self):
         self.state = "unknown"
@@ -130,25 +253,53 @@ class Screen:
             self.state = "off"
 
 def grab_all():
-    global screen, power, aux
+    global screen, power, aux, accel
     screen.grab()
     power.grab()
     aux.grab()
+    accel.grab()
 
 def release_all():
-    global screen, power, aux
+    global screen, power, aux, accel
     screen.ungrab()
     power.ungrab()
     aux.ungrab()
+    accel.ungrab()
+
+# wall-clock might get reset when we wake from suspend, so
+# use a monotonic clock to guard against early blanking.
+import ctypes
+
+CLOCK_MONOTONIC = 1 # not sure about this one, check the headers
+
+class timespec(ctypes.Structure):
+    _fields_ = [
+        ('tv_sec', ctypes.c_long),
+        ('tv_nsec', ctypes.c_long)
+    ]
+
+librt = ctypes.CDLL('librt.so.1')
+clock_gettime = librt.clock_gettime 
+clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]
+
+def get_ticks():
+    t = timespec()
+    clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(t))
+    return t.tv_sec + t.tv_nsec / 1e9
+
+
 
 timeout = None
 state = "full"
 dimtime = 15
 enable_suspend = True
+last_set = 0
 def set_timeout():
     global timeout
     global state, enable_suspend
-    global dimtime
+    global dimtime, last_set
+
+    last_set = get_ticks()
     #print "set timeout for", state
     if timeout != None:
         gobject.source_remove(timeout)
@@ -156,20 +307,22 @@ def set_timeout():
         timeout = gobject.timeout_add(dimtime*1000, set_dim)
     elif state == "dim":
         timeout = gobject.timeout_add(10*1000, set_off)
-    elif state == "insta-lock":
-        timeout = gobject.timeout_add(1000, set_off)
     elif state == "off" and enable_suspend:
         timeout = gobject.timeout_add(30*1000, set_suspend)
 
     set_ico_file()
 
 def set_dim():
-    global state
+    global state, last_set
     global aux, power, screen
     if aux.down_count() + power.down_count() + screen.down_count() > 0:
         # button still down
         set_timeout()
         return
+    if get_ticks() - last_set < dimtime - 1:
+        # if delay was too quick, try again
+        set_timeout()
+        return
     display.dim()
     grab_all()
     state = "dim"
@@ -177,6 +330,10 @@ def set_dim():
 
 def set_off():
     global state, dimtime
+    global last_set
+    if get_ticks() - last_set < 9.5:
+        set_timeout()
+        return
     display.off()
     state = "off"
     set_timeout()
@@ -218,7 +375,7 @@ def set_suspend():
     global state, display
     # Check for lock file
     try:
-        f = open("/var/run/suspend_disabled", "r+")
+        f = open("/var/run/suspend_disabled", "w+")
     except:
         f = None
     if f:
@@ -226,34 +383,38 @@ def set_suspend():
             fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
         except:
             set_timeout()
+            f.close()
             return
 
     # Check for loadavg > 0.5
-    load = read_num("/proc/loadavg")
-    if load > 0.5:
-        set_timeout()
-        return
+    #load = read_num("/proc/loadavg")
+    #if load > 0.5:
+    #    set_timeout()
+    #    return
 
     # Check for USB power, at least 500mA
+    # If powered and network connection then leave awake.
     current = read_num("/sys/class/i2c-adapter/i2c-0/0-0073/pcf50633-mbc/usb_curlim")
-    if current >= 500:
+    if current >= 500 and external_tcp():
         set_timeout()
         return
 
-    #if external_tcp():
-    #    set_timeout()
-    #    return
-
     os.system("apm -s")
     if f:
         f.close()
-    state = "full"
+    rr = suspend.resume_reason()
+    if rr == 'PMU power-button-down':
+        wake_all(0)
+        return
+
+    state = "off"
     set_timeout()
-    display.on()
+
 
 def wake_all(down_cnt, *rest):
-    global state, dimtime
+    global state, dimtime, alert
     #print "wake all"
+    alert.stopall()
     display.on()
     if down_cnt == 0:
         release_all()
@@ -269,6 +430,63 @@ def wake_dim(down_cnt, *rest):
     if state == "dim" or state == "full":
         wake_all(down_cnt)
 
+EV_SYN = 0
+EV_KEY = 1
+EV_ABS = 3
+ABS_X = 0
+ABS_Y = 1
+ABS_Z = 2
+BTN_X = 307
+BTN_Y = 308
+BTN_Z = 309
+
+shake_cnt = 0
+shake_time = 0
+shake_seen = 0
+invert_timer = 0
+def check_attitude(down_cnt, moment, typ, code, value):
+    global state
+    global shake_cnt, shake_time, shake_seen
+    if moment - shake_time > 0.4:
+        shake_cnt = 0
+    if typ == EV_ABS and abs(value) > 1500:
+        shake_time = moment
+        shake_seen = 1
+    if typ == EV_SYN and shake_seen:
+        shake_cnt += 1
+        shake_seen = 0
+    if typ == EV_ABS and code == ABS_Y and value > 100:
+        shake_cnt = 0
+    if shake_cnt >= 3:
+        shake_cnt = 0
+        #no  wake_all(0)
+        #no return
+
+    if typ == EV_KEY and code <= BTN_Z and code >= BTN_X and value == 1:
+        wake_dim(0)
+
+    global invert_timer
+    if typ == EV_ABS and code == ABS_Y and value > 500:
+        # upside down - need this for 0.6 seconds
+        #print "down", moment
+        if invert_timer == 0:
+            invert_timer = gobject.timeout_add(400, attitude_confirm)
+    elif typ == EV_ABS and code == ABS_Y:
+        #print "up", moment
+        if invert_timer:
+            gobject.source_remove(invert_timer)
+        invert_timer = 0
+
+def attitude_confirm():
+    global invert_timer, state
+    # seem to have been inverted for a while
+    invert_timer = 0
+    if state != "off":
+        display.off()
+        grab_all()
+        state = "off"
+        set_timeout()
+    return False
 
 ico_file = None
 def set_ico_file():
@@ -293,10 +511,7 @@ last_ping = 0
 prev_ping = 0
 def ping(icon):
     global state, enable_suspend, last_ping, prev_ping
-    if time.time() - prev_ping < 0.8:
-        grab_all()
-        state = "insta-lock"
-    elif state == "disable":
+    if state == "disable":
         enable_suspend = False
         state = "full"
     elif not enable_suspend:
@@ -308,12 +523,24 @@ def ping(icon):
     last_ping = time.time()
     set_timeout()
 
+def setfile(name, val):
+    f = open(name, 'w')
+    f.write(val)
+    f.close()
+
 def main():
     global display, ico
-    global screen, power, aux
+    global screen, power, aux, accel
+    global alert
     aux = EvDev("/dev/input/event4", wake_all)
     power = EvDev("/dev/input/event0", wake_all)
     screen = EvDev("/dev/input/event1", wake_dim)
+
+    alert = SetAlerts("/var/run/alert", "/etc/alert")
+    setfile('/sys/bus/spi/devices/spi3.1/threshold', '500')
+    setfile('/sys/bus/spi/devices/spi3.1/sample_rate','0')
+    setfile('/sys/bus/spi/devices/spi3.1/taps', '7000 5')
+    accel = EvDev("/dev/input/event3", check_attitude)
     state = "full"
     display = Screen()
     display.on()