Hdaps ess

From ThinkWiki
Revision as of 23:02, 17 September 2008 by Damajor (Talk | contribs) (HDAPS Enhanced Smack Script)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

ess.py stands for Enhanced Smack Script.

It is an improved version of the smacks scripts you can find here.

Features:

  • stabilization for both axis,
  • you can disable an axis if needed,
  • invert axis flag,
  • almost everything tunable,
  • different log levels for debug messages.

At best you should be able to map 8 commands, even if it is possible I was not able to do so.

Unfortunately it is not a copy and paste script, you have to tune some parameters and to add the commands you want to execute. Usually you only have to adjust the short term thresholds.

I am sure it is far to be exempt of any bug so do not hesitate to fix the wrong things.

The default thresholds should work on quiet environment.

I commented the dbus commands I used with KDE so you can activate them easily.

Good luck ;)

--Damajor 00:02, 18 September 2008 (CEST)

Code:

#!/usr/bin/env python

import sys, re, time, math
#import dbus
import os

# hdaps input file
POS_FILE = '/sys/devices/platform/hdaps/position'
# regex to gather hdaps values
POS_RX = re.compile('^\((-?\d+),(-?\d+)\)$')

# invert x and y axis (True or False)
INVERT_AXIS = False

# interval to pause between hdaps reads
INTERVAL = 0.01

# length of the short term buffer (same value will be used for x and y buffers)
ST_LENGTH = 20
# short term standard deviation threshold for x
ST_X_STDDEV_THRESHOLD = 1
# short term standard deviation threshold for y
ST_Y_STDDEV_THRESHOLD = 1
# short term threshold for x (0 to disable x axis knocks)
ST_X_THRESHOLD = 2
# short term threshold for y (0 to disable y axis knocks)
ST_Y_THRESHOLD = 2

# length of the long term buffer (same value will be used for x and y buffers)
LT_LENGTH = 6
# long term standard deviation threshold for x
LT_X_STDDEV_THRESHOLD = 2
# long term standard deviation threshold for y
LT_Y_STDDEV_THRESHOLD = 2

# Debug (0 to 4) 0=no output
DEBUG = 1

# END OF CONFIG SECTION

# dbus init
#bus = dbus.SessionBus()
#kwin = bus.get_object('org.kde.kwin','/KWin')

def switch_to_workspace_at_right():
  os.system('/full/path/cdb.py wall next_key')
#  kwin.nextDesktop()

def switch_to_workspace_at_left():
  os.system('/full/path/cdb.py wall prev_key')
#  kwin.previousDesktop()

def launch_x_left():
  debug("X-Left",1)
#  switch_to_workspace_at_left()
def launch_x_right():
  debug("X-Right",1)
#  switch_to_workspace_at_right()
def launch_y_front():
  debug("Y-Front",1)
def launch_y_back():
  debug("Y-Back",1)
def launch_x_left_y_front():
  debug("X-Left Y-Front",1)
#  switch_to_workspace_at_left()
def launch_x_left_y_back():
  debug("X-Left Y-Back",1)
#  switch_to_workspace_at_left()
def launch_x_right_y_front():
  debug("X-Right Y-Front",1)
#  switch_to_workspace_at_right()
def launch_x_right_y_back():
  debug("X-Right Y-Back",1)
#  switch_to_workspace_at_right()

def get_pos():
  pos = open(POS_FILE).read()
  match = POS_RX.match(pos)
  return (int(match.groups()[0]), int(match.groups()[1]))

def loop():
  st_x = []
  st_y = []
  st_x_idx = 0
  st_y_idx = 0
  
  lt_x = []
  lt_y = []
  lt_x_idx = 0
  lt_y_idx = 0
  
  lt_x_stable = False
  lt_y_stable = False
  
  for i in range(ST_LENGTH):
    st_x.append(0)
  for i in range(ST_LENGTH):
    st_y.append(0)
  for i in range(LT_LENGTH):
    lt_x.append(0)
  for i in range(LT_LENGTH):
    lt_y.append(0)

  while True:
    if INVERT_AXIS:
      y, x = get_pos()
    else:
      x, y = get_pos()
    
    st_x[st_x_idx] = x
    st_y[st_y_idx] = y
    
    if (stddev(lt_x) < LT_X_STDDEV_THRESHOLD) and (stddev(lt_y) < LT_Y_STDDEV_THRESHOLD):
      if (lt_x_stable == False) or (lt_y_stable == False):
	debug("Stable",1)
	lt_x_stable = True
	lt_y_stable = True

      # Split short term buffer into older and newer values
      old_x = []
      old_y = []
      new_x = []
      new_y = []
      for i in range(ST_LENGTH / 2):
	old_x.append(st_x[(st_x_idx + i + 1) % ST_LENGTH])
	old_y.append(st_y[(st_y_idx + i + 1) % ST_LENGTH])
	new_x.append(st_x[(st_x_idx + i + 1 + (ST_LENGTH / 2)) % ST_LENGTH])
	new_y.append(st_y[(st_y_idx + i + 1 + (ST_LENGTH / 2)) % ST_LENGTH])
      
      # Add some older stable data to new array, to make sure it's gone
      # back to the same stable state rather than a new one
      for i in range((ST_LENGTH / 2) + 1, ST_LENGTH):
	new_x.append(lt_x[(lt_x_idx + i) % LT_LENGTH])
	new_y.append(lt_y[(lt_y_idx + i) % LT_LENGTH])

      if (stddev(new_x) < ST_X_STDDEV_THRESHOLD) and (stddev(new_y) < ST_Y_STDDEV_THRESHOLD):
	st_x_mean = mean(st_x)
	st_y_mean = mean(st_y)
	debug("Max x: " + str(max(old_x)) + " > " + str(st_x_mean + ST_X_THRESHOLD) + \
	      " Min x: " + str(min(old_x)) + " < " + str(st_x_mean - ST_X_THRESHOLD) + \
	      " SD x: " + str(stddev(new_x)) + " < " + str(ST_X_STDDEV_THRESHOLD),4)
	debug("Max y: " + str(max(old_y)) + " < " + str(st_y_mean + ST_Y_THRESHOLD) + \
	      " Min y: " + str(min(old_y)) + " > " + str(st_y_mean - ST_Y_THRESHOLD) + \
	      " SD y: " + str(stddev(new_y)) + " < " + str(ST_Y_STDDEV_THRESHOLD),4)
	max_x_idx = -1
	max_y_idx = -1
	min_x_idx = -1
	min_y_idx = -1

	# Heartbeat
	for i in range(len(old_y)):
	  if (ST_X_THRESHOLD != 0):
	    if (old_x[i] > st_x_mean + ST_X_THRESHOLD):
	      max_x_idx = i;
	    if (old_x[i] < st_x_mean - ST_X_THRESHOLD):
	      min_x_idx = i;
	  if (ST_Y_THRESHOLD != 0):
	    if (old_y[i] > st_y_mean + ST_Y_THRESHOLD):
	      max_y_idx = i;
	    if (old_y[i] < st_y_mean - ST_Y_THRESHOLD):
	      min_y_idx = i;

	# Check knock directions and launch associated commands
	if ((max_x_idx != -1) and (min_x_idx != -1)) or ((max_y_idx != -1) and (min_y_idx != -1)):
	  if (max_x_idx == min_x_idx) and (max_y_idx >= min_y_idx):
	    debug("Smack! X-Disabled or stable x=" + str(old_x[max_x_idx]) + "/" + str(old_x[min_x_idx]) + \
		  " Y-Front y=" + str(old_y[max_y_idx]) + "/" + str(old_y[min_y_idx]),2)
	    launch_y_front()
	  if (max_x_idx == min_x_idx) and (max_y_idx <= min_y_idx):
	    debug("Smack! X-Disabled or stable x=" + str(old_x[max_x_idx]) + "/" + str(old_x[min_x_idx]) + \
		  " Y-Back y=" + str(old_y[max_y_idx]) + "/" + str(old_y[min_y_idx]),2)
	    launch_y_back()
	  if (max_x_idx >= min_x_idx) and (max_y_idx == min_y_idx):
	    debug("Smack! X-Right x=" + str(old_x[max_x_idx]) + "/" + str(old_x[min_x_idx]) + \
		  " Y-Disabled or stable y=" + str(old_y[max_y_idx]) + "/" + str(old_y[min_y_idx]),2)
	    launch_x_right()
	  if (max_x_idx < min_x_idx) and (max_y_idx == min_y_idx):
	    debug("Smack! X-Left x=" + str(old_x[max_x_idx]) + "/" + str(old_x[min_x_idx]) + \
		  " Y-Disabled or stable y=" + str(old_y[max_y_idx]) + "/" + str(old_y[min_y_idx]),2)
	    launch_x_left()
	  if (max_x_idx > min_x_idx) and (max_y_idx > min_y_idx):
	    debug("Smack! X-Right x=" + str(old_x[max_x_idx]) + "/" + str(old_x[min_x_idx]) + \
		  " Y-Front y=" + str(old_y[max_y_idx]) + "/" + str(old_y[min_y_idx]),2)
	    launch_x_right_y_front()
	  if (max_x_idx < min_x_idx) and (max_y_idx < min_y_idx):
	    debug("Smack! X-Left x=" + str(old_x[max_x_idx]) + "/" + str(old_x[min_x_idx]) + \
		  " Y-Back y=" + str(old_y[max_y_idx]) + "/" + str(old_y[min_y_idx]),2)
	    launch_x_left_y_back()
	  if (max_x_idx < min_x_idx) and (max_y_idx > min_y_idx):
	    debug("Smack! X-Left x=" + str(old_x[max_x_idx]) + "/" + str(old_x[min_x_idx]) + \
		  " Y-Front y=" + str(old_y[max_y_idx]) + "/" + str(old_y[min_y_idx]),2)
	    launch_x_left_y_front()
	  if (max_x_idx > min_x_idx) and (max_y_idx < min_y_idx):
	    debug("Smack! X-Right x=" + str(old_x[max_x_idx]) + "/" + str(old_x[min_x_idx]) + \
		  " Y-Back y=" + str(old_y[max_y_idx]) + "/" + str(old_y[min_y_idx]),2)
	    launch_x_right_y_back()

	  # No further smacks for a while; bias long-term stddev
	  #lt_x[(lt_x_idx + LT_LENGTH - 1) % LT_LENGTH] = 10000000;
	  lt_y[(lt_y_idx + LT_LENGTH - 1) % LT_LENGTH] = 10000000;
    else:
      if (lt_x_stable == True) or (lt_y_stable == True):
        debug("Unstable",1)
	lt_x_stable = False
	lt_y_stable = False

    st_x_idx = st_x_idx + 1
    st_x_idx %= ST_LENGTH
    st_y_idx = st_y_idx + 1
    st_y_idx %= ST_LENGTH

    if st_x_idx == 0:
      lt_x[lt_x_idx] = st_x[st_x_idx]
      lt_x_idx = lt_x_idx + 1
      lt_x_idx %= LT_LENGTH
      debug("X Stability stddev: " + str(stddev(lt_x)),3)
    if st_y_idx == 0:
      lt_y[lt_y_idx] = st_y[st_y_idx]
      lt_y_idx = lt_y_idx + 1
      lt_y_idx %= LT_LENGTH
      debug("Y Stability stddev: " + str(stddev(lt_y)),3)

    time.sleep(INTERVAL)

def debug(param, level):
  # show the message depending on the DEBUG level
  if level <= DEBUG:
    print param

def mean(values):
  # average of the values
  return sum(values) / float(len(values))

def stddev(values):
  # standard deviation of the values
  meanval = mean(values)
  return math.sqrt(sum([(x - meanval)**2 for x in values]) / (len(values)-1))

def main():
  try:
    loop()
  except KeyboardInterrupt:
    pass

if __name__ == '__main__':
  main()