yoga-laptop/docs/Orientation and rotation

yoga-laptop/docs/Orientation and rotation

This is not a production-quality system.  It should be turned into a program
that reads the sensors and produces events on a system bus so that multiple
programs can follow the sensors.

The sensor hub in the Yoga 2 Pro does not behave the same as many other
sensor hubs.  As a result, the sensors are not reliably initialized in 3.12
and may be reliably mis-initialized in 3.13.  I have a patched
hid-sensor-hub.c and hid-sensor-ids.h that appear to fix the problem.  This
patch should get into distributed code in the near future.

NOTE: In most cases you will have to build and install the drivers (in the
drivers directory) for this program to work correctly.

	Orientation Monitor and Screen Rotation

orientation is a stand-alone program that monitors the accelerometer on a
Yoga 2 Pro and rotates the screen and touchscreen (but not the touchpad).
It should work on any laptop that has an IIO-enabled 3D accelerometer in the
screen and uses the HID Hub identifiers for the sensor channels.  The
--touchscreen option will have to be used for laptops that don't have an
ELAN Touchscreen - use xinput to find the name of your touchscreen device.

The program needs the IIO bus drivers and the USB HID sensor hub driver configured
into the kernel (generally these will be loadable modules).  If there is a
directory /sys/bus/iio/devices/iio:device0 then you should be OK.  Fedora 20
has this all set up.

For the program to work best, it needs to manipulate the accelerometer
controls and read accelerometer data without running as root. One way to do
this manually is to be in a group and have the device files  also be in that
group and accessible as necessary, e.g., via  
  sudo chgrp group /sys/bus/iio/devices/iio:device*/scan_elements/in_*_en 
  sudo chmod g+w /sys/bus/iio/devices/iio:device*/scan_elements/in_*_en 
  sudo chgrp group /sys/bus/iio/devices/iio:device*/buffer/*
  sudo chmod g+w /sys/bus/iio/devices/iio:device*/buffer/* 
  sudo chgrp group /sys/bus/iio/devices/iio:device*/trigger/current_trigger
  sudo chmod g+w /sys/bus/iio/devices/iio:device*/trigger/current_trigger
  sudo chgrp group /dev/iio:device*
  sudo chmod g+rw /dev/iio:device*
[What is the best way to do this automatically?  Via udev rules?]
In the absence of something better, `make install` does this for the user's
group, along with installing the program in /usr/bin.

Options are
  --debug=level, -d level 
	produce more and more outut as the argument is increased, default 0
  --count=number, -c number
	runs for only number probes of the accelerometer, default -1
  --name=sensor_name, -n sensor_name
	uses sensor_name for the IIO name of the accelerometer, default accel_3d
  --touchscreen=screen_name, -t screen_name
	uses screen_name for the name of the touchscreen, default ELAN Touchscreen
	set to empty string if you don't have a touchscreen or don't want to rotate it

The program responds to a SIGUSR1 signal by suspending rotations due to
orientation changes until another SIGUSR1 signal is received, except that if
another SIGUSR1 signal is received within a second or two (i.e., the time in
seconds difference is less than two) the second signal performs a manual
left rotation and also suspends automatic rotation.  (A subsequent quick
signal is then interpreted as a regular signal, which turns automatic
rotation on, so three signals in quick succession is not very useful.)

Signals can be easily sent to the orientation program using 
  pkill --signal SIGUSR1 --exact orientation
which can be linked to the rotation lock button o on the side of the
Yoga using the appropriate mechanism in your display manager.

WARNING:  This is not production quality code.  It execs xrandr and xinput.
WARNING:  The distributed iio_utils.h has lots of bugs.
WARNING:  The device appears to get into stuck modes.  To try to unstick
 	  sudo ./unstick X where X is the number of the accelerometer

	Information about the sensor chip in the Lenovo Yoga 2 Pro

The Invensense chip presents eight sensors.  Four of these are supported in
kernel 3.12: an ambient light sensor, an accelerometer, a gyroscope, and a
magnetometer.  The last three sensors are each 3D, producing a 9-axis
position sensor.  There is support for a fifth sensor in kernel 3.13, an
inclinometer, which is probably derived from the accelerometer.  Kernel 3.13
also has some code to support sensitivity, and appears to have some bug
fixes.   There is also a device orientation sensor and a custom sensor that
includes an accelerometer on the base.

Each supported sensor becomes an iio device, possibly with multiple
channels.  The device number (X, below) changes each time.  There is a
function in iio_utils.h for finding out which device number corresponds to
which sensor, cycling through sysfs files to match the name.

Sensor Name	Channels
  als		intensity_both
  accel_3d	accel_x accel_y accel_z
  magn_3d	magn_x magn_y magn_z
  gyro_3d	anglvel_x anglvel_y anglvel_x

Getting data from an iio device involves enabling its channels, enabling the
data-ready device trigger, and turning on the buffer.  (As far as I can
tell, there is only one trigger currently available.)  Only then can data be
read from the device at /dev/iio:deviceX.  The device trigger and the buffer
should be turned off after the program is finished reading data.

To enable the channels of a sensor
  echo 1 | sudo tee /sys/bus/iio/devices/iio:deviceX/scan_elements/in_*_en
It does not appear to be possible to disable a channel

To enable the buffer for a sensor
  echo  | sudo tee /sys/bus/iio/devices/iio:deviceX/buffer/length
  echo 1 | sudo tee /sys/bus/iio/devices/iio:deviceX/buffer/enable
To disable the buffer for a sensor
  echo 0 | sudo tee /sys/bus/iio/devices/iio:deviceX/buffer/enable

To set the data-ready trigger
  cat /sys/bus/iio/devices/triggerX/name | sudo tee /sys/bus/iio/devices/iio:deviceX/trigger/current_trigger
To unset the trigger
  echo "NULL" | sudo tee /sys/bus/iio/devices/iio:deviceX/trigger/current_trigger

The sensors appear to be in one of several states:
1/ stuck - no data is produced and attempts to change the device status produce 
		Device or resource busy
2/ active with hysteresis - data is produced only after a significant change
3/ active with change - data is produced after any change
4/ free-running - data is produced very rapidly
I do not know how they get in these states, nor do I know how to change the state.

To unstick a device (maybe?)
	echo 0 | sudo tee /sys/bus/iio/devices/iio:deviceX/buffer/enable 
	echo NULL | sudo tee /sys/bus/iio/devices/iio:deviceX/trigger/current_trigger 

In 3.12, the light sensor is usually in a mode where it reports only on
changes (but the changes are quantized in steps of 39).  The accelerometer,
magnetometer, and gyroscope are free-running (i.e., the same values can be
output multiple times in a row), although they are sensitive so some value
usually changes each time.  In 3.13 the light sensor is the same, but the
others are in some stuck state.

The eight sensors can be seen in a directory named something like
 HID-SENSOR-200041.0	Ambient Light		als
 HID-SENSOR-200073.0	Accelerometer 3D	accel_3d
 HID-SENSOR-200076.0	Gyrometer 3D  		gyro_3d
 HID-SENSOR-200083.0	Compass 3D		magn_3d
 HID-SENSOR-200086.0	Inclinometer 3D
 HID-SENSOR-20008a.0	Device Orientation, outputting a quaternion
 HID-SENSOR-2000e1.0	Custom, including Accelerometer 3D on the base
 HID-SENSOR-2000e2.0	Generic ??

Sysfs setup (in /sys/bus/iio/devices):

 dev			string		x:y
 name			string		accel_3d	
 uevent			W string	MAJOR=x\nMINOR=y\nDEVNAME=iio:deviceX\nDEVTYPE=iio_device
 in_*_hysteresis	W float		0.000000
 in_*_offset		W int		-3
 in_*sampling_frequency	W float		0.000000
 in_*_scale		W int		0
  enable		W boolean	0|1
  length		W int		128
  in_*_*_en		W boolean	0|-1
  in_*_*_index		int		0|1|2
  in_*_*_type		string		le:s16/32>>0
  current_trigger	W string	accel_3d-devX|...
 power		For run-time power management???
triggerX	The trigger name for iio:deviceX
 name			string		accel_3d-devX|...
 uevent			W string	
 power		For run-time power management???

	Information about rotating the screen and touchscreen

Rotating the screen:
    xrandr -o normal | inverted | left | right

Rotating the touchscreen:
    xinput set-prop 'ELAN Touchscreen' 'Coordinate Transformation Matrix' 1 0 0 0 1 0 0 0 1
    xinput set-prop 'ELAN Touchscreen' 'Coordinate Transformation Matrix' 0 1 0 -1 0 1 0 0 1
    xinput set-prop 'ELAN Touchscreen' 'Coordinate Transformation Matrix' 0 -1 1 1 0 0 0 0 1
    xinput set-prop 'ELAN Touchscreen' 'Coordinate Transformation Matrix' -1 0 1 0 -1 1 0 0 1

Enabling and disabling the touchpad
    xinput enable | disable 'SynPS/2 Synaptics TouchPad'

Another way of modifying the touchscreen (maybe):
    xinput set-prop "ELAN Touchscreen" "Evdev Axes Swap" "0"
    xinput set-prop "ELAN Touchscreen" "Evdev Axis Inversion" 1 1

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s