pax_global_header 0000666 0000000 0000000 00000000064 12554165724 0014525 g ustar 00root root 0000000 0000000 52 comment=4c0b154f7d6e10537bae2c78c6f5035c156e9912
iio-sensor-proxy-1.1/ 0000775 0000000 0000000 00000000000 12554165724 0014634 5 ustar 00root root 0000000 0000000 iio-sensor-proxy-1.1/.gitignore 0000664 0000000 0000000 00000000021 12554165724 0016615 0 ustar 00root root 0000000 0000000 iio-sensor-proxy
iio-sensor-proxy-1.1/AUTHORS 0000664 0000000 0000000 00000000000 12554165724 0015672 0 ustar 00root root 0000000 0000000 iio-sensor-proxy-1.1/ChangeLog 0000664 0000000 0000000 00000000000 12554165724 0016374 0 ustar 00root root 0000000 0000000 iio-sensor-proxy-1.1/Makefile.am 0000664 0000000 0000000 00000000364 12554165724 0016673 0 ustar 00root root 0000000 0000000 SUBDIRS = data src docs
DISTCHECK_CONFIGURE_FLAGS = \
--enable-gtk-doc \
--with-udevrulesdir=$$dc_install_base/$(udevrulesdir) \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
EXTRA_DIST = README.md
iio-sensor-proxy-1.1/NEWS 0000664 0000000 0000000 00000001125 12554165724 0015332 0 ustar 00root root 0000000 0000000 1.1
---
This release adds support for Compasses (only accessible to GeoClue).
- Fix service not starting in a number of cases
- Fix excessive CPU usage monitoring light sensors on Macs
- Support light sensors on some Samsung laptops
- Fix incorrect sensor readings on some devices due to unit scaling
1.0
---
This is the first stable release of iio-sensor-proxy. It now uses a D-Bus API,
and supports accelerometers and ambient light sensors.
0.1
---
This is the first version of iio-sensor-proxy. It supports accelerometers,
proxying IIO sensors, and mimicking input device accelerometers.
iio-sensor-proxy-1.1/README 0000777 0000000 0000000 00000000000 12554165724 0016766 2README.md ustar 00root root 0000000 0000000 iio-sensor-proxy-1.1/README.md 0000664 0000000 0000000 00000003072 12554165724 0016115 0 ustar 00root root 0000000 0000000 iio-sensor-proxy
================
IIO sensors to D-Bus proxy
Installation
------------
```
./configure --prefix=/usr --sysconfdir=/etc
make
make install
```
It requires libgudev and systemd.
Usage
-----
With a new enough version of systemd[1], and a GNOME 3.18 (or newer) based
system, orientation changes will automatically be applied when rotating
the panel.
Note that a number of kernel bugs will prevent it from working correctly on
some machines with the 3.16 kernel (kernel crashes on the Surface Pro, sensor
failing to work after suspend on the Yoga Pro, etc.).
You can verify this by running `udevadm info --export-db` and checking for
an output resembling this one:
```
P: /devices/virtual/input/input15
E: ABS=7
E: DEVPATH=/devices/virtual/input/input15
E: EV=9
E: ID_INPUT=1
E: ID_INPUT_ACCELEROMETER=1
E: ID_INPUT_ACCELEROMETER_ORIENTATION=normal
E: MODALIAS=input:b0006v0001p0002e0000-e0,3,kra0,1,2,mlsfw
E: NAME="IIO Accelerometer Proxy"
E: PRODUCT=6/1/2/0
E: PROP=0
E: SUBSYSTEM=input
E: TAGS=:seat:
E: USEC_INITIALIZED=74243
```
If that doesn't work, please file an issue, make sure any running iio-sensor-proxy has been stopped:
`systemctl stop iio-sensor-proxy.service`
and attach the output of:
`G_MESSAGES_DEBUG=all /usr/sbin/iio-sensor-proxy`
[1]: One including this patch:
http://thread.gmane.org/gmane.comp.sysutils.systemd.devel/32047
Tested on
---------
- Lenovo IdeaPad Yoga 13
- Microsoft Surface Pro 2
- Lenovo Yoga Pro 2
- Onda v975w
- Dell Venue 8 Pro
- Dell Venue 11 Pro (7140)
- Lenovo ThinkPad Twist
- MacBook Pro (8.2)
- Lenovo X1 Carbon 2014 (rev2)
iio-sensor-proxy-1.1/autogen.sh 0000775 0000000 0000000 00000001001 12554165724 0016625 0 ustar 00root root 0000000 0000000 #!/bin/sh
# Run this to generate all the initial makefiles, etc.
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
PKG_NAME="iio-sensor-proxy"
(test -f $srcdir/configure.ac) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level $PKG_NAME directory"
exit 1
}
which gnome-autogen.sh || {
echo "You need to install gnome-common from the GNOME git"
exit 1
}
REQUIRED_PKG_CONFIG_VERSION=0.17.1 REQUIRED_AUTOMAKE_VERSION=1.9 USE_GNOME2_MACROS=1 . gnome-autogen.sh
iio-sensor-proxy-1.1/configure.ac 0000664 0000000 0000000 00000002225 12554165724 0017123 0 ustar 00root root 0000000 0000000 AC_PREREQ(2.59)
AC_INIT([iio-sensor-proxy], [1.1], [hadess@hadess.net])
AM_INIT_AUTOMAKE(1.9 dist-xz no-dist-gzip check-news)
# Enable silent build when available (Automake 1.11)
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
AC_PROG_CC
AC_PROG_MAKE_SET
AC_PROG_INSTALL
AC_PROG_SED
AM_PROG_CC_C_O
GNOME_COMPILE_WARNINGS([maximum])
GTK_DOC_CHECK([1.11],[--flavour no-tmpl])
AC_ARG_WITH([udevrulesdir],
AS_HELP_STRING([--with-udevrulesdir=DIR], [Directory for udev rules]),
[],
[with_udevrulesdir=$($PKG_CONFIG --variable=udevdir udev)"/rules.d"])
AC_SUBST([udevrulesdir], [$with_udevrulesdir])
AC_ARG_WITH([systemdsystemunitdir],
AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
[],
[with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
if test x$with_systemdsystemunitdir != xno; then
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
fi
PKG_CHECK_MODULES(IIO_SENSOR_PROXY, gio-2.0 gudev-1.0)
AC_PATH_PROG([GDBUS_CODEGEN],[gdbus-codegen])
AC_CONFIG_FILES([
Makefile
data/Makefile
src/Makefile
docs/Makefile
docs/version.xml
])
AC_OUTPUT
iio-sensor-proxy-1.1/data/ 0000775 0000000 0000000 00000000000 12554165724 0015545 5 ustar 00root root 0000000 0000000 iio-sensor-proxy-1.1/data/40-iio-sensor-proxy.rules 0000664 0000000 0000000 00000000575 12554165724 0022317 0 ustar 00root root 0000000 0000000 # iio-sensor-proxy
# IIO accelerometer to input proxy
ACTION=="add", SUBSYSTEM=="iio", TAG+="systemd", ENV{SYSTEMD_WANTS}+="iio-sensor-proxy.service"
SUBSYSTEM=="input", ACTION=="add", TAG+="systemd", ENV{ID_INPUT_ACCELEROMETER}=="1", ENV{SYSTEMD_WANTS}+="iio-sensor-proxy.service"
SUBSYSTEM=="hwmon", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="iio-sensor-proxy.service"
iio-sensor-proxy-1.1/data/Makefile.am 0000664 0000000 0000000 00000001002 12554165724 0017572 0 ustar 00root root 0000000 0000000 udevrules_DATA = 40-iio-sensor-proxy.rules
systemdservicedir = $(systemdsystemunitdir)
systemdservice_in_files = iio-sensor-proxy.service.in
systemdservice_DATA = iio-sensor-proxy.service
iio-sensor-proxy.service: iio-sensor-proxy.service.in Makefile
$(AM_V_GEN) $(SED) -e "s|\@sbindir\@|$(sbindir)|" $< > $@
dbusconfdir = $(sysconfdir)/dbus-1/system.d
dbusconf_DATA = net.hadess.SensorProxy.conf
CLEANFILES = iio-sensor-proxy.service
EXTRA_DIST = $(udevrules_DATA) $(dbusconf_DATA) $(systemdservice_in_files)
iio-sensor-proxy-1.1/data/iio-sensor-proxy.service.in 0000664 0000000 0000000 00000000205 12554165724 0022777 0 ustar 00root root 0000000 0000000 [Unit]
Description=IIO Sensor Proxy service
[Service]
Type=dbus
BusName=net.hadess.SensorProxy
ExecStart=@sbindir@/iio-sensor-proxy
iio-sensor-proxy-1.1/data/net.hadess.SensorProxy.conf 0000664 0000000 0000000 00000003041 12554165724 0022760 0 ustar 00root root 0000000 0000000
iio-sensor-proxy-1.1/docs/ 0000775 0000000 0000000 00000000000 12554165724 0015564 5 ustar 00root root 0000000 0000000 iio-sensor-proxy-1.1/docs/Makefile.am 0000664 0000000 0000000 00000002534 12554165724 0017624 0 ustar 00root root 0000000 0000000 NULL =
AUTOMAKE_OPTIONS = 1.7
# The name of the module.
DOC_MODULE=iio-sensor-proxy
# The top-level SGML file.
DOC_MAIN_SGML_FILE=iio-sensor-proxy-docs.xml
# Extra options to supply to gtkdoc-scan
SCAN_OPTIONS=--ignore-headers=config.h --rebuild-sections --rebuild-types
# The directory containing the source code. Relative to $(srcdir)
DOC_SOURCE_DIR=
# Used for dependencies
HFILE_GLOB=
CFILE_GLOB=
# Headers to ignore
IGNORE_HFILES= \
$(NULL)
GTKDOC_LIBS =
# Extra options to supply to gtkdoc-mkdb
MKDB_OPTIONS=--sgml-mode --output-format=xml
# Extra options to supply to gtkdoc-mktmpl
MKTMPL_OPTIONS=
docs-net.hadess.SensorProxy.xml: $(top_srcdir)/src/net.hadess.SensorProxy.xml
$(AM_V_GEN)$(GDBUS_CODEGEN) --generate-docbook=docs $<
# Non-autogenerated SGML files to be included in $(DOC_MAIN_SGML_FILE)
content_files = \
version.xml \
docs-net.hadess.SensorProxy.xml \
$(NULL)
# FIXME
MAINTAINERCLEANFILES = \
*~ \
Makefile.in \
iio-sensor-proxy.types \
iio-sensor-proxy-*.txt \
$(NULL)
if ENABLE_GTK_DOC
include $(top_srcdir)/gtk-doc.make
else
CLEANFILES = $(NULL)
EXTRA_DIST = iio-sensor-proxy-docs.xml
endif
CLEANFILES += \
docs-net.hadess.SensorProxy.xml \
docs-net.hadess.SensorProxy.Compass.xml \
$(NULL)
# Version information for marking the documentation
EXTRA_DIST += version.xml.in
-include $(top_srcdir)/git.mk
iio-sensor-proxy-1.1/docs/iio-sensor-proxy-docs.xml 0000664 0000000 0000000 00000004756 12554165724 0022516 0 ustar 00root root 0000000 0000000
]>
Sensor Proxy Reference Manual
Version &version;
Bastien
Nocera
hadess@hadess.net
2015
Red Hat, Inc.
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free
Documentation License, Version 1.1 or any later
version published by the Free Software Foundation with no
Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. You may obtain a copy of the GNU Free
Documentation License from the Free Software
Foundation by visiting their Web site or by writing
to:
The Free Software Foundation, Inc.,
59 Temple Place - Suite 330,
Boston, MA 02111-1307,
USA
Many of the names used by companies to distinguish their
products and services are claimed as trademarks. Where those
names appear in any GNOME documentation, and those trademarks
are made aware to the members of the GNOME Documentation
Project, the names have been printed in caps or initial caps.
D-Bus API Reference
This part documents the D-Bus interface used to access the
Sensor Proxy service.
Index
License
FIXME: MISSING XINCLUDE CONTENT
iio-sensor-proxy-1.1/docs/version.xml.in 0000664 0000000 0000000 00000000012 12554165724 0020371 0 ustar 00root root 0000000 0000000 @VERSION@
iio-sensor-proxy-1.1/src/ 0000775 0000000 0000000 00000000000 12554165724 0015423 5 ustar 00root root 0000000 0000000 iio-sensor-proxy-1.1/src/Makefile.am 0000664 0000000 0000000 00000003352 12554165724 0017462 0 ustar 00root root 0000000 0000000 BUILT_SOURCES = \
iio-sensor-proxy-resources.c \
iio-sensor-proxy-resources.h
resource_files = $(shell glib-compile-resources --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/iio-sensor-proxy.gresource.xml)
iio-sensor-proxy-resources.c: iio-sensor-proxy.gresource.xml $(resource_files)
$(AM_V_GEN) glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name iio_sensor_proxy $<
iio-sensor-proxy-resources.h: iio-sensor-proxy.gresource.xml $(resource_files)
$(AM_V_GEN) glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name iio_sensor_proxy $<
sbin_PROGRAMS = iio-sensor-proxy
iio_sensor_proxy_SOURCES = \
iio-sensor-proxy.c \
drivers.h \
orientation.c \
orientation.h \
drv-iio-buffer-accel.c \
drv-iio-poll-accel.c \
drv-input-accel.c \
drv-fake-compass.c \
drv-fake-light.c \
drv-iio-poll-light.c \
drv-hwmon-light.c \
drv-iio-buffer-light.c \
drv-iio-buffer-compass.c \
iio-buffer-utils.h \
iio-buffer-utils.c \
$(BUILT_SOURCES)
iio_sensor_proxy_CPPFLAGS = \
$(IIO_SENSOR_PROXY_CFLAGS) \
$(WARN_CFLAGS)
iio_sensor_proxy_LDADD = $(IIO_SENSOR_PROXY_LIBS) -lm
noinst_PROGRAMS = fake-input-accelerometer
fake_input_accelerometer_SOURCES = \
fake-input-accelerometer.c \
uinput.h
fake_input_accelerometer_CPPFLAGS = \
$(IIO_SENSOR_PROXY_CFLAGS) \
$(WARN_CFLAGS)
fake_input_accelerometer_LDADD = $(IIO_SENSOR_PROXY_LIBS)
bin_PROGRAMS = monitor-sensor
monitor_sensor_SOURCES = \
monitor-sensor.c
monitor_sensor_CPPFLAGS = \
$(IIO_SENSOR_PROXY_CFLAGS) \
$(WARN_CFLAGS)
monitor_sensor_LDADD = $(IIO_SENSOR_PROXY_LIBS)
EXTRA_DIST = \
test-orientation.c \
net.hadess.SensorProxy.xml \
iio-sensor-proxy.gresource.xml
iio-sensor-proxy-1.1/src/drivers.h 0000664 0000000 0000000 00000005421 12554165724 0017254 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include
#include
typedef enum {
DRIVER_TYPE_ACCEL,
DRIVER_TYPE_LIGHT,
DRIVER_TYPE_COMPASS,
} DriverType;
/* Driver types */
typedef guint DriverSpecificType;
typedef enum {
DRIVER_TYPE_ACCEL_IIO,
DRIVER_TYPE_ACCEL_INPUT
} DriverAccelType;
typedef enum {
DRIVER_TYPE_LIGHT_IIO,
DRIVER_TYPE_LIGHT_FAKE,
DRIVER_TYPE_LIGHT_HWMON
} DriverLightType;
typedef enum {
DRIVER_TYPE_COMPASS_IIO,
DRIVER_TYPE_COMPASS_FAKE
} DriverTypeCompass;
typedef struct SensorDriver SensorDriver;
typedef struct {
int accel_x;
int accel_y;
int accel_z;
} AccelReadings;
typedef struct {
gdouble level;
gboolean uses_lux;
} LightReadings;
typedef struct {
gdouble heading;
} CompassReadings;
typedef void (*ReadingsUpdateFunc) (SensorDriver *driver,
gpointer readings,
gpointer user_data);
struct SensorDriver {
const char *name;
DriverType type;
DriverSpecificType specific_type;
gboolean (*discover) (GUdevDevice *device);
gboolean (*open) (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data);
void (*set_polling) (gboolean state);
void (*close) (void);
};
static inline gboolean
driver_discover (SensorDriver *driver,
GUdevDevice *device)
{
g_return_val_if_fail (driver, FALSE);
g_return_val_if_fail (driver->discover, FALSE);
g_return_val_if_fail (device, FALSE);
return driver->discover (device);
}
static inline gboolean
driver_open (SensorDriver *driver,
GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
g_return_val_if_fail (driver, FALSE);
g_return_val_if_fail (driver->open, FALSE);
g_return_val_if_fail (device, FALSE);
g_return_val_if_fail (callback_func, FALSE);
return driver->open (device, callback_func, user_data);
}
static inline void
driver_set_polling (SensorDriver *driver,
gboolean state)
{
g_return_if_fail (driver);
if (!driver->set_polling)
return;
driver->set_polling (state);
}
static inline void
driver_close (SensorDriver *driver)
{
g_return_if_fail (driver);
g_return_if_fail (driver->close);
driver->close ();
}
extern SensorDriver iio_buffer_accel;
extern SensorDriver iio_poll_accel;
extern SensorDriver input_accel;
extern SensorDriver fake_compass;
extern SensorDriver fake_light;
extern SensorDriver iio_poll_light;
extern SensorDriver hwmon_light;
extern SensorDriver iio_buffer_light;
extern SensorDriver iio_buffer_compass;
iio-sensor-proxy-1.1/src/drv-fake-compass.c 0000664 0000000 0000000 00000005267 12554165724 0020743 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2015 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include "drivers.h"
#include
#include
#include
#include
#include
#include
typedef struct DrvData {
ReadingsUpdateFunc callback_func;
gpointer user_data;
guint timeout_id;
} DrvData;
static DrvData *drv_data = NULL;
static gboolean
fake_compass_discover (GUdevDevice *device)
{
if (g_getenv ("FAKE_COMPASS") == NULL)
return FALSE;
if (g_strcmp0 (g_udev_device_get_subsystem (device), "input") != 0)
return FALSE;
/* "Lid switch" is a random input device to latch onto */
if (g_strcmp0 (g_udev_device_get_property (device, "NAME"), "\"Lid Switch\"") != 0)
return FALSE;
g_debug ("Found fake compass at %s", g_udev_device_get_sysfs_path (device));
return TRUE;
}
static gboolean
compass_changed (void)
{
static gdouble heading = 0;
CompassReadings readings;
heading += 10;
if (heading >= 360)
heading = 0;
g_debug ("Changed heading to %f", heading);
readings.heading = heading;
drv_data->callback_func (&fake_compass, (gpointer) &readings, drv_data->user_data);
return G_SOURCE_CONTINUE;
}
static gboolean
first_values (gpointer user_data)
{
compass_changed ();
drv_data->timeout_id = g_timeout_add_seconds (1, (GSourceFunc) compass_changed, NULL);
g_source_set_name_by_id (drv_data->timeout_id, "[fake_compass_set_polling] compass_changed");
return G_SOURCE_REMOVE;
}
static gboolean
fake_compass_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
drv_data = g_new0 (DrvData, 1);
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
return TRUE;
}
static void
fake_compass_set_polling (gboolean state)
{
if (drv_data->timeout_id > 0 && state)
return;
if (drv_data->timeout_id == 0 && !state)
return;
if (drv_data->timeout_id) {
g_source_remove (drv_data->timeout_id);
drv_data->timeout_id = 0;
}
if (state) {
drv_data->timeout_id = g_idle_add (first_values, NULL);
g_source_set_name_by_id (drv_data->timeout_id, "[fake_compass_set_polling] first_values");
}
}
static void
fake_compass_close (void)
{
fake_compass_set_polling (FALSE);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver fake_compass = {
.name = "Fake compass",
.type = DRIVER_TYPE_COMPASS,
.specific_type = DRIVER_TYPE_COMPASS_FAKE,
.discover = fake_compass_discover,
.open = fake_compass_open,
.set_polling = fake_compass_set_polling,
.close = fake_compass_close,
};
iio-sensor-proxy-1.1/src/drv-fake-light.c 0000664 0000000 0000000 00000005270 12554165724 0020377 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include "drivers.h"
#include
#include
#include
#include
#include
#include
typedef struct DrvData {
ReadingsUpdateFunc callback_func;
gpointer user_data;
guint timeout_id;
} DrvData;
static DrvData *drv_data = NULL;
static gboolean
fake_light_discover (GUdevDevice *device)
{
if (g_getenv ("FAKE_LIGHT_SENSOR") == NULL)
return FALSE;
if (g_strcmp0 (g_udev_device_get_subsystem (device), "input") != 0)
return FALSE;
/* "Lid switch" is a random input device to latch onto */
if (g_strcmp0 (g_udev_device_get_property (device, "NAME"), "\"Lid Switch\"") == 0)
return FALSE;
g_debug ("Found fake light at %s", g_udev_device_get_sysfs_path (device));
return TRUE;
}
static gboolean
light_changed (void)
{
static gdouble level = -1.0;
LightReadings readings;
/* XXX:
* Might need to do something better here, like
* replicate real readings from a device */
level += 1.0;
readings.level = level;
readings.uses_lux = TRUE;
drv_data->callback_func (&fake_light, (gpointer) &readings, drv_data->user_data);
return G_SOURCE_CONTINUE;
}
static gboolean
first_values (gpointer user_data)
{
light_changed ();
drv_data->timeout_id = g_timeout_add_seconds (1, (GSourceFunc) light_changed, NULL);
g_source_set_name_by_id (drv_data->timeout_id, "[fake_light_set_polling] light_changed");
return G_SOURCE_REMOVE;
}
static gboolean
fake_light_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
drv_data = g_new0 (DrvData, 1);
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
return TRUE;
}
static void
fake_light_set_polling (gboolean state)
{
if (drv_data->timeout_id > 0 && state)
return;
if (drv_data->timeout_id == 0 && !state)
return;
if (drv_data->timeout_id) {
g_source_remove (drv_data->timeout_id);
drv_data->timeout_id = 0;
}
if (state) {
drv_data->timeout_id = g_idle_add (first_values, NULL);
g_source_set_name_by_id (drv_data->timeout_id, "[fake_light_set_polling] first_values");
}
}
static void
fake_light_close (void)
{
fake_light_set_polling (FALSE);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver fake_light = {
.name = "Fake light",
.type = DRIVER_TYPE_LIGHT,
.specific_type = DRIVER_TYPE_LIGHT_FAKE,
.discover = fake_light_discover,
.open = fake_light_open,
.set_polling = fake_light_set_polling,
.close = fake_light_close,
};
iio-sensor-proxy-1.1/src/drv-hwmon-light.c 0000664 0000000 0000000 00000006474 12554165724 0020630 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include "drivers.h"
#include
#include
#include
#include
#include
#define DEFAULT_POLL_TIME 8000
#define MAX_LIGHT_LEVEL 255
typedef struct DrvData {
ReadingsUpdateFunc callback_func;
gpointer user_data;
char *light_path;
guint timeout_id;
} DrvData;
static DrvData *drv_data = NULL;
static gboolean
hwmon_light_discover (GUdevDevice *device)
{
char *light_path;
if (g_strcmp0 (g_udev_device_get_subsystem (device), "platform") != 0)
return FALSE;
if (g_strcmp0 (g_udev_device_get_property (device, "MODALIAS"), "platform:applesmc") != 0)
return FALSE;
light_path = g_build_filename (g_udev_device_get_sysfs_path (device),
"light", NULL);
if (!g_file_test (light_path, G_FILE_TEST_EXISTS)) {
g_free (light_path);
return FALSE;
}
g_free (light_path);
g_debug ("Found HWMon light at %s", g_udev_device_get_sysfs_path (device));
return TRUE;
}
static gboolean
light_changed (void)
{
LightReadings readings;
gdouble level;
char *contents;
GError *error = NULL;
if (g_file_get_contents (drv_data->light_path, &contents, NULL, &error)) {
int light1, light2;
if (sscanf (contents, "(%d,%d)", &light1, &light2) != 2) {
g_warning ("Failed to parse light level: %s", contents);
g_free (contents);
return G_SOURCE_CONTINUE;
}
level = ((float) MAX(light1, light2)) / (float) MAX_LIGHT_LEVEL * 100.0;
g_free (contents);
} else {
g_warning ("Failed to read input level at %s: %s",
drv_data->light_path, error->message);
g_error_free (error);
return G_SOURCE_CONTINUE;
}
readings.level = level;
readings.uses_lux = FALSE;
drv_data->callback_func (&hwmon_light, (gpointer) &readings, drv_data->user_data);
return G_SOURCE_CONTINUE;
}
static gboolean
hwmon_light_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
drv_data = g_new0 (DrvData, 1);
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
drv_data->light_path = g_build_filename (g_udev_device_get_sysfs_path (device),
"light", NULL);
return TRUE;
}
static void
hwmon_light_set_polling (gboolean state)
{
if (drv_data->timeout_id > 0 && state)
return;
if (drv_data->timeout_id == 0 && !state)
return;
if (drv_data->timeout_id) {
g_source_remove (drv_data->timeout_id);
drv_data->timeout_id = 0;
}
if (state) {
drv_data->timeout_id = g_timeout_add (DEFAULT_POLL_TIME, (GSourceFunc) light_changed, NULL);
g_source_set_name_by_id (drv_data->timeout_id, "[hwmon_light_set_polling] light_changed");
/* And send a reading straight away */
light_changed ();
}
}
static void
hwmon_light_close (void)
{
hwmon_light_set_polling (FALSE);
g_clear_pointer (&drv_data->light_path, g_free);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver hwmon_light = {
.name = "Platform HWMon Light",
.type = DRIVER_TYPE_LIGHT,
.specific_type = DRIVER_TYPE_LIGHT_HWMON,
.discover = hwmon_light_discover,
.open = hwmon_light_open,
.set_polling = hwmon_light_set_polling,
.close = hwmon_light_close,
};
iio-sensor-proxy-1.1/src/drv-iio-buffer-accel.c 0000664 0000000 0000000 00000014234 12554165724 0021460 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include "drivers.h"
#include "iio-buffer-utils.h"
#include
#include
#include
#include
/* 1G (9.81m/s²) corresponds to "256"
* value x scale is in m/s² */
#define SCALE_TO_FF(scale) (scale * 256 / 9.81)
typedef struct {
guint timeout_id;
ReadingsUpdateFunc callback_func;
gpointer user_data;
GUdevDevice *dev;
const char *dev_path;
int device_id;
BufferDrvData *buffer_data;
} DrvData;
static DrvData *drv_data = NULL;
static int
process_scan (IIOSensorData data, DrvData *or_data)
{
int i;
int accel_x, accel_y, accel_z;
gdouble scale;
gboolean present_x, present_y, present_z;
AccelReadings readings;
if (data.read_size < 0) {
g_warning ("Couldn't read from device: %s", g_strerror (errno));
return 0;
}
/* Rather than read everything:
* for (i = 0; i < data.read_size / or_data->scan_size; i++)...
* Just read the last one */
i = (data.read_size / or_data->buffer_data->scan_size) - 1;
if (i < 0) {
g_debug ("Not enough data to read (read_size: %d scan_size: %d)", (int) data.read_size, or_data->buffer_data->scan_size);
return 0;
}
process_scan_1(data.data + or_data->buffer_data->scan_size*i, or_data->buffer_data, "in_accel_x", &accel_x, &scale, &present_x);
process_scan_1(data.data + or_data->buffer_data->scan_size*i, or_data->buffer_data, "in_accel_y", &accel_y, &scale, &present_y);
process_scan_1(data.data + or_data->buffer_data->scan_size*i, or_data->buffer_data, "in_accel_z", &accel_z, &scale, &present_z);
g_debug ("Read from IIO: %d, %d, %d", accel_x, accel_y, accel_z);
/* To match the Pegatron accelerometer code
* (see pega_accel_poll() in asus-laptop.c)
* we invert both x, and y values */
accel_x = -accel_x;
accel_y = -accel_y;
//FIXME report errors
readings.accel_x = accel_x * scale;
readings.accel_y = accel_y * scale;
readings.accel_z = accel_z * scale;
or_data->callback_func (&iio_buffer_accel, (gpointer) &readings, or_data->user_data);
return 1;
}
static void
prepare_output (DrvData *or_data,
const char *dev_dir_name,
const char *trigger_name)
{
IIOSensorData data;
int fp, buf_len = 127;
data.data = g_malloc(or_data->buffer_data->scan_size * buf_len);
/* Attempt to open non blocking to access dev */
fp = open (or_data->dev_path, O_RDONLY | O_NONBLOCK);
if (fp == -1) { /* If it isn't there make the node */
g_warning ("Failed to open %s : %s", or_data->dev_path, strerror(errno));
goto bail;
}
/* Actually read the data */
data.read_size = read (fp, data.data, buf_len * or_data->buffer_data->scan_size);
if (data.read_size == -1 && errno == EAGAIN) {
g_debug ("No new data available");
} else {
process_scan(data, or_data);
}
close(fp);
bail:
g_free(data.data);
}
static char *
get_trigger_name (GUdevDevice *device)
{
GList *devices, *l;
GUdevClient *client;
gboolean has_trigger = FALSE;
char *trigger_name;
const gchar * const subsystems[] = { "iio", NULL };
client = g_udev_client_new (subsystems);
devices = g_udev_client_query_by_subsystem (client, "iio");
/* Find the associated trigger */
trigger_name = g_strdup_printf ("accel_3d-dev%s", g_udev_device_get_number (device));
for (l = devices; l != NULL; l = l->next) {
GUdevDevice *dev = l->data;
if (g_strcmp0 (trigger_name, g_udev_device_get_sysfs_attr (dev, "name")) == 0) {
g_debug ("Found associated trigger at %s", g_udev_device_get_sysfs_path (dev));
has_trigger = TRUE;
break;
}
}
g_list_free_full (devices, g_object_unref);
g_clear_object (&client);
if (has_trigger)
return trigger_name;
g_warning ("Could not find trigger name associated with %s",
g_udev_device_get_sysfs_path (device));
g_free (trigger_name);
return NULL;
}
static gboolean
read_orientation (gpointer user_data)
{
DrvData *data = user_data;
prepare_output (data, data->buffer_data->dev_dir_name, data->buffer_data->trigger_name);
return G_SOURCE_CONTINUE;
}
static gboolean
iio_buffer_accel_discover (GUdevDevice *device)
{
if (g_strcmp0 (g_udev_device_get_subsystem (device), "iio") != 0)
return FALSE;
if (g_strcmp0 ("accel_3d", g_udev_device_get_sysfs_attr (device, "name")) != 0)
return FALSE;
g_debug ("Found accel_3d at %s", g_udev_device_get_sysfs_path (device));
return TRUE;
}
static void
iio_buffer_accel_set_polling (gboolean state)
{
if (drv_data->timeout_id > 0 && state)
return;
if (drv_data->timeout_id == 0 && !state)
return;
if (drv_data->timeout_id) {
g_source_remove (drv_data->timeout_id);
drv_data->timeout_id = 0;
}
if (state) {
drv_data->timeout_id = g_timeout_add (700, read_orientation, drv_data);
g_source_set_name_by_id (drv_data->timeout_id, "[iio_buffer_accel_set_polling] read_orientation");
}
}
static gboolean
iio_buffer_accel_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
char *trigger_name;
drv_data = g_new0 (DrvData, 1);
/* Get the trigger name, and build the channels from that */
trigger_name = get_trigger_name (device);
if (!trigger_name) {
g_clear_pointer (&drv_data, g_free);
return FALSE;
}
drv_data->buffer_data = buffer_drv_data_new (device, trigger_name);
g_free (trigger_name);
if (!drv_data->buffer_data) {
g_clear_pointer (&drv_data, g_free);
return FALSE;
}
drv_data->dev = g_object_ref (device);
drv_data->dev_path = g_udev_device_get_device_file (device);
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
return TRUE;
}
static void
iio_buffer_accel_close (void)
{
iio_buffer_accel_set_polling (FALSE);
g_clear_pointer (&drv_data->buffer_data, buffer_drv_data_free);
g_clear_object (&drv_data->dev);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver iio_buffer_accel = {
.name = "IIO Buffer accelerometer",
.type = DRIVER_TYPE_ACCEL,
.specific_type = DRIVER_TYPE_ACCEL_IIO,
.discover = iio_buffer_accel_discover,
.open = iio_buffer_accel_open,
.set_polling = iio_buffer_accel_set_polling,
.close = iio_buffer_accel_close,
};
iio-sensor-proxy-1.1/src/drv-iio-buffer-compass.c 0000664 0000000 0000000 00000013370 12554165724 0022056 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014 Bastien Nocera
* Copyright (c) 2015 Elad Alfassa
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include "drivers.h"
#include "iio-buffer-utils.h"
#include
#include
#include
#include
typedef struct {
guint timeout_id;
ReadingsUpdateFunc callback_func;
gpointer user_data;
GUdevDevice *dev;
const char *dev_path;
int device_id;
BufferDrvData *buffer_data;
} DrvData;
static DrvData *drv_data = NULL;
static int
process_scan (IIOSensorData data, DrvData *or_data)
{
int i;
int raw_heading;
char* channel_name = "in_rot_from_north_magnetic_tilt_comp";
gdouble scale;
gboolean present_level;
CompassReadings readings;
if (data.read_size < 0) {
g_warning ("Couldn't read from device: %s", g_strerror (errno));
return 0;
}
/* Rather than read everything:
* for (i = 0; i < data.read_size / or_data->scan_size; i++)...
* Just read the last one */
i = (data.read_size / or_data->buffer_data->scan_size) - 1;
if (i < 0) {
g_debug ("Not enough data to read (read_size: %d scan_size: %d)", (int) data.read_size, or_data->buffer_data->scan_size);
return 0;
}
process_scan_1 (data.data + or_data->buffer_data->scan_size*i, or_data->buffer_data, channel_name, &raw_heading, &scale, &present_level);
readings.heading = raw_heading * scale;
g_debug ("Read from IIO: %f (%d times %f scale)", readings.heading, raw_heading, scale);
//FIXME report errors
or_data->callback_func (&iio_buffer_compass, (gpointer) &readings, or_data->user_data);
return 1;
}
static void
prepare_output (DrvData *or_data,
const char *dev_dir_name,
const char *trigger_name)
{
IIOSensorData data;
int fp, buf_len = 127;
data.data = g_malloc(or_data->buffer_data->scan_size * buf_len);
/* Attempt to open non blocking to access dev */
fp = open (or_data->dev_path, O_RDONLY | O_NONBLOCK);
if (fp == -1) { /* If it isn't there make the node */
g_warning ("Failed to open %s : %s", or_data->dev_path, strerror(errno));
goto bail;
}
/* Actually read the data */
data.read_size = read (fp, data.data, buf_len * or_data->buffer_data->scan_size);
if (data.read_size == -1 && errno == EAGAIN) {
g_debug ("No new data available");
} else {
process_scan(data, or_data);
}
close(fp);
bail:
g_free(data.data);
}
static char *
get_trigger_name (GUdevDevice *device)
{
GList *devices, *l;
GUdevClient *client;
gboolean has_trigger = FALSE;
char *trigger_name;
const gchar * const subsystems[] = { "iio", NULL };
client = g_udev_client_new (subsystems);
devices = g_udev_client_query_by_subsystem (client, "iio");
/* Find the associated trigger */
trigger_name = g_strdup_printf ("magn_3d-dev%s", g_udev_device_get_number (device));
for (l = devices; l != NULL; l = l->next) {
GUdevDevice *dev = l->data;
if (g_strcmp0 (trigger_name, g_udev_device_get_sysfs_attr (dev, "name")) == 0) {
g_debug ("Found associated trigger at %s", g_udev_device_get_sysfs_path (dev));
has_trigger = TRUE;
break;
}
}
g_list_free_full (devices, g_object_unref);
g_clear_object (&client);
if (has_trigger)
return trigger_name;
g_warning ("Could not find trigger name associated with %s",
g_udev_device_get_sysfs_path (device));
g_free (trigger_name);
return NULL;
}
static gboolean
read_heading (gpointer user_data)
{
DrvData *data = user_data;
prepare_output (data, data->buffer_data->dev_dir_name, data->buffer_data->trigger_name);
return G_SOURCE_CONTINUE;
}
static gboolean
iio_buffer_compass_discover (GUdevDevice *device)
{
if (g_strcmp0 (g_udev_device_get_subsystem (device), "iio") != 0)
return FALSE;
if (g_strcmp0 ("magn_3d", g_udev_device_get_sysfs_attr (device, "name")) != 0)
return FALSE;
g_debug ("Found magn_3d at %s", g_udev_device_get_sysfs_path (device));
return TRUE;
}
static gboolean
iio_buffer_compass_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
char *trigger_name;
drv_data = g_new0 (DrvData, 1);
/* Get the trigger name, and build the channels from that */
trigger_name = get_trigger_name (device);
if (!trigger_name) {
g_clear_pointer (&drv_data, g_free);
return FALSE;
}
drv_data->buffer_data = buffer_drv_data_new (device, trigger_name);
g_free (trigger_name);
if (!drv_data->buffer_data) {
g_clear_pointer (&drv_data, g_free);
return FALSE;
}
drv_data->dev = g_object_ref (device);
drv_data->dev_path = g_udev_device_get_device_file (device);
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
return TRUE;
}
static void
iio_buffer_compass_set_polling (gboolean state)
{
if (drv_data->timeout_id > 0 && state)
return;
if (drv_data->timeout_id == 0 && !state)
return;
if (drv_data->timeout_id) {
g_source_remove (drv_data->timeout_id);
drv_data->timeout_id = 0;
}
if (state) {
drv_data->timeout_id = g_timeout_add (700, read_heading, drv_data);
g_source_set_name_by_id (drv_data->timeout_id, "[iio_buffer_compass_set_polling] read_heading");
}
}
static void
iio_buffer_compass_close (void)
{
iio_buffer_compass_set_polling (FALSE);
g_clear_pointer (&drv_data->buffer_data, buffer_drv_data_free);
g_clear_object (&drv_data->dev);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver iio_buffer_compass = {
.name = "IIO Buffer Compass",
.type = DRIVER_TYPE_COMPASS,
.specific_type = DRIVER_TYPE_COMPASS_IIO,
.discover = iio_buffer_compass_discover,
.open = iio_buffer_compass_open,
.set_polling = iio_buffer_compass_set_polling,
.close = iio_buffer_compass_close,
};
iio-sensor-proxy-1.1/src/drv-iio-buffer-light.c 0000664 0000000 0000000 00000013567 12554165724 0021530 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014 Bastien Nocera
* Copyright (c) 2015 Elad Alfassa
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include "drivers.h"
#include "iio-buffer-utils.h"
#include
#include
#include
#include
typedef struct {
guint timeout_id;
ReadingsUpdateFunc callback_func;
gpointer user_data;
GUdevDevice *dev;
const char *dev_path;
int device_id;
BufferDrvData *buffer_data;
} DrvData;
static DrvData *drv_data = NULL;
static int
process_scan (IIOSensorData data, DrvData *or_data)
{
int i;
int level = 0;
gdouble scale;
gboolean present_level;
LightReadings readings;
if (data.read_size < 0) {
g_warning ("Couldn't read from device: %s", g_strerror (errno));
return 0;
}
/* Rather than read everything:
* for (i = 0; i < data.read_size / or_data->scan_size; i++)...
* Just read the last one */
i = (data.read_size / or_data->buffer_data->scan_size) - 1;
if (i < 0) {
g_debug ("Not enough data to read (read_size: %d scan_size: %d)", (int) data.read_size, or_data->buffer_data->scan_size);
return 0;
}
process_scan_1(data.data + or_data->buffer_data->scan_size*i, or_data->buffer_data, "in_intensity_both", &level, &scale, &present_level);
g_debug ("Read from IIO: %f", level * scale);
readings.level = level;
if (scale)
readings.level *= scale;
/* Even though the IIO kernel API declares in_intensity* values as unitless,
* we use Microsoft's hid-sensors-usages.docx which mentions that Windows 8
* compatible sensor proxies will be using Lux as the unit, and most sensors
* will be Windows 8 compatible */
readings.uses_lux = TRUE;
//FIXME report errors
or_data->callback_func (&iio_buffer_light, (gpointer) &readings, or_data->user_data);
return 1;
}
static void
prepare_output (DrvData *or_data,
const char *dev_dir_name,
const char *trigger_name)
{
IIOSensorData data;
int fp, buf_len = 127;
data.data = g_malloc(or_data->buffer_data->scan_size * buf_len);
/* Attempt to open non blocking to access dev */
fp = open (or_data->dev_path, O_RDONLY | O_NONBLOCK);
if (fp == -1) { /* If it isn't there make the node */
g_warning ("Failed to open %s : %s", or_data->dev_path, strerror(errno));
goto bail;
}
/* Actually read the data */
data.read_size = read (fp, data.data, buf_len * or_data->buffer_data->scan_size);
if (data.read_size == -1 && errno == EAGAIN) {
g_debug ("No new data available");
} else {
process_scan(data, or_data);
}
close(fp);
bail:
g_free(data.data);
}
static char *
get_trigger_name (GUdevDevice *device)
{
GList *devices, *l;
GUdevClient *client;
gboolean has_trigger = FALSE;
char *trigger_name;
const gchar * const subsystems[] = { "iio", NULL };
client = g_udev_client_new (subsystems);
devices = g_udev_client_query_by_subsystem (client, "iio");
/* Find the associated trigger */
trigger_name = g_strdup_printf ("als-dev%s", g_udev_device_get_number (device));
for (l = devices; l != NULL; l = l->next) {
GUdevDevice *dev = l->data;
if (g_strcmp0 (trigger_name, g_udev_device_get_sysfs_attr (dev, "name")) == 0) {
g_debug ("Found associated trigger at %s", g_udev_device_get_sysfs_path (dev));
has_trigger = TRUE;
break;
}
}
g_list_free_full (devices, g_object_unref);
g_clear_object (&client);
if (has_trigger)
return trigger_name;
g_warning ("Could not find trigger name associated with %s",
g_udev_device_get_sysfs_path (device));
g_free (trigger_name);
return NULL;
}
static gboolean
read_light (gpointer user_data)
{
DrvData *data = user_data;
prepare_output (data, data->buffer_data->dev_dir_name, data->buffer_data->trigger_name);
return G_SOURCE_CONTINUE;
}
static gboolean
iio_buffer_light_discover (GUdevDevice *device)
{
if (g_strcmp0 (g_udev_device_get_subsystem (device), "iio") != 0)
return FALSE;
if (g_strcmp0 ("als", g_udev_device_get_sysfs_attr (device, "name")) != 0)
return FALSE;
g_debug ("Found als at %s", g_udev_device_get_sysfs_path (device));
return TRUE;
}
static void
iio_buffer_light_set_polling (gboolean state)
{
if (drv_data->timeout_id > 0 && state)
return;
if (drv_data->timeout_id == 0 && !state)
return;
if (drv_data->timeout_id) {
g_source_remove (drv_data->timeout_id);
drv_data->timeout_id = 0;
}
if (state) {
drv_data->timeout_id = g_timeout_add (700, read_light, drv_data);
g_source_set_name_by_id (drv_data->timeout_id, "[iio_buffer_light_set_polling] read_light");
}
}
static gboolean
iio_buffer_light_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
char *trigger_name;
drv_data = g_new0 (DrvData, 1);
/* Get the trigger name, and build the channels from that */
trigger_name = get_trigger_name (device);
if (!trigger_name) {
g_clear_pointer (&drv_data, g_free);
return FALSE;
}
drv_data->buffer_data = buffer_drv_data_new (device, trigger_name);
g_free (trigger_name);
if (!drv_data->buffer_data) {
g_clear_pointer (&drv_data, g_free);
return FALSE;
}
drv_data->dev = g_object_ref (device);
drv_data->dev_path = g_udev_device_get_device_file (device);
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
return TRUE;
}
static void
iio_buffer_light_close (void)
{
iio_buffer_light_set_polling (FALSE);
g_clear_pointer (&drv_data->buffer_data, buffer_drv_data_free);
g_clear_object (&drv_data->dev);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver iio_buffer_light = {
.name = "IIO Buffer Light sensor",
.type = DRIVER_TYPE_LIGHT,
.specific_type = DRIVER_TYPE_LIGHT_IIO,
.discover = iio_buffer_light_discover,
.open = iio_buffer_light_open,
.set_polling = iio_buffer_light_set_polling,
.close = iio_buffer_light_close,
};
iio-sensor-proxy-1.1/src/drv-iio-poll-accel.c 0000664 0000000 0000000 00000007135 12554165724 0021157 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include "drivers.h"
#include
#include
#include
#include
#include
#include
/* 1G (9.81m/s²) corresponds to "256"
* value x scale is in m/s² */
#define SCALE_TO_FF(scale) (scale * 256 / 9.81)
typedef struct DrvData {
guint timeout_id;
ReadingsUpdateFunc callback_func;
gpointer user_data;
GUdevDevice *dev;
double scale;
} DrvData;
static DrvData *drv_data = NULL;
static int
sysfs_get_int (GUdevDevice *dev,
const char *attribute)
{
int result;
char *contents;
char *filename;
result = 0;
filename = g_build_filename (g_udev_device_get_sysfs_path (dev), attribute, NULL);
if (g_file_get_contents (filename, &contents, NULL, NULL)) {
result = atoi (contents);
g_free (contents);
}
g_free (filename);
return result;
}
static gboolean
poll_orientation (gpointer user_data)
{
DrvData *data = user_data;
int accel_x, accel_y, accel_z;
AccelReadings readings;
accel_x = sysfs_get_int (data->dev, "in_accel_x_raw") * data->scale;
accel_y = sysfs_get_int (data->dev, "in_accel_y_raw") * data->scale;
accel_z = sysfs_get_int (data->dev, "in_accel_z_raw") * data->scale;
//FIXME report errors
if (g_strcmp0 ("i2c-SMO8500:00", g_udev_device_get_sysfs_attr (data->dev, "name")) == 0) {
/* Quirk for i2c-SMO8500:00 device,
* swap x and y */
readings.accel_x = accel_y;
readings.accel_y = accel_x;
readings.accel_z = accel_z;
} else {
readings.accel_x = accel_x;
readings.accel_y = accel_y;
readings.accel_z = accel_z;
}
drv_data->callback_func (&iio_poll_accel, (gpointer) &readings, drv_data->user_data);
return G_SOURCE_CONTINUE;
}
static gboolean
iio_poll_accel_discover (GUdevDevice *device)
{
if (g_strcmp0 (g_udev_device_get_subsystem (device), "iio") != 0)
return FALSE;
if (g_strcmp0 ("i2c-SMO8500:00", g_udev_device_get_sysfs_attr (device, "name")) != 0)
return FALSE;
g_debug ("Found polling accelerometer at %s", g_udev_device_get_sysfs_path (device));
return TRUE;
}
static void
iio_poll_accel_set_polling (gboolean state)
{
if (drv_data->timeout_id > 0 && state)
return;
if (drv_data->timeout_id == 0 && !state)
return;
if (drv_data->timeout_id) {
g_source_remove (drv_data->timeout_id);
drv_data->timeout_id = 0;
}
if (state) {
drv_data->timeout_id = g_timeout_add (700, poll_orientation, drv_data);
g_source_set_name_by_id (drv_data->timeout_id, "[iio_poll_accel_set_polling] poll_orientation");
}
}
static gboolean
iio_poll_accel_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
drv_data = g_new0 (DrvData, 1);
drv_data->dev = g_object_ref (device);
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
drv_data->scale = SCALE_TO_FF(g_udev_device_get_sysfs_attr_as_double (device, "in_accel_scale"));
if (drv_data->scale == 0.0)
drv_data->scale = 1.0;
return TRUE;
}
static void
iio_poll_accel_close (void)
{
iio_poll_accel_set_polling (FALSE);
g_clear_object (&drv_data->dev);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver iio_poll_accel = {
.name = "IIO Poll accelerometer",
.type = DRIVER_TYPE_ACCEL,
.specific_type = DRIVER_TYPE_ACCEL_IIO,
.discover = iio_poll_accel_discover,
.open = iio_poll_accel_open,
.set_polling = iio_poll_accel_set_polling,
.close = iio_poll_accel_close,
};
iio-sensor-proxy-1.1/src/drv-iio-poll-light.c 0000664 0000000 0000000 00000007305 12554165724 0021216 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include "drivers.h"
#include
#include
#include
#include
#include
#define DEFAULT_POLL_TIME 0.8
typedef struct DrvData {
ReadingsUpdateFunc callback_func;
gpointer user_data;
char *input_path;
guint interval;
guint timeout_id;
} DrvData;
static DrvData *drv_data = NULL;
static gboolean
iio_poll_light_discover (GUdevDevice *device)
{
char *path;
gboolean ret;
if (g_strcmp0 (g_udev_device_get_subsystem (device), "iio") != 0)
return FALSE;
path = g_build_filename (g_udev_device_get_sysfs_path (device),
"in_illuminance_input",
NULL);
ret = g_file_test (path, G_FILE_TEST_IS_REGULAR);
g_free (path);
if (ret)
g_debug ("Found IIO poll light at %s", g_udev_device_get_sysfs_path (device));
return ret;
}
static gboolean
light_changed (void)
{
LightReadings readings;
gdouble level;
char *contents;
GError *error = NULL;
if (g_file_get_contents (drv_data->input_path, &contents, NULL, &error)) {
level = g_ascii_strtod (contents, NULL);
g_free (contents);
} else {
g_warning ("Failed to read input level at %s: %s",
drv_data->input_path, error->message);
g_error_free (error);
return G_SOURCE_CONTINUE;
}
readings.level = level;
/* Even though the IIO kernel API declares in_intensity* values as unitless,
* we use Microsoft's hid-sensors-usages.docx which mentions that Windows 8
* compatible sensor proxies will be using Lux as the unit, and most sensors
* will be Windows 8 compatible */
readings.uses_lux = TRUE;
drv_data->callback_func (&iio_poll_light, (gpointer) &readings, drv_data->user_data);
return G_SOURCE_CONTINUE;
}
static guint
get_interval (GUdevDevice *device)
{
gdouble time;
char *path, *contents;
path = g_build_filename (g_udev_device_get_sysfs_path (device),
"in_illuminance_integration_time",
NULL);
if (g_file_get_contents (path, &contents, NULL, NULL)) {
time = g_ascii_strtod (contents, NULL);
g_free (contents);
} else {
time = DEFAULT_POLL_TIME;
}
g_free (path);
return (time * 1000);
}
static void
iio_poll_light_set_polling (gboolean state)
{
if (drv_data->timeout_id > 0 && state)
return;
if (drv_data->timeout_id == 0 && !state)
return;
if (drv_data->timeout_id) {
g_source_remove (drv_data->timeout_id);
drv_data->timeout_id = 0;
}
if (state) {
drv_data->timeout_id = g_timeout_add (drv_data->interval,
(GSourceFunc) light_changed,
NULL);
g_source_set_name_by_id (drv_data->timeout_id, "[iio_poll_light_set_polling] light_changed");
}
}
static gboolean
iio_poll_light_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
drv_data = g_new0 (DrvData, 1);
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
drv_data->interval = get_interval (device);
drv_data->input_path = g_build_filename (g_udev_device_get_sysfs_path (device),
"in_illuminance_input",
NULL);
return TRUE;
}
static void
iio_poll_light_close (void)
{
iio_poll_light_set_polling (FALSE);
g_clear_pointer (&drv_data->input_path, g_free);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver iio_poll_light = {
.name = "IIO Polling Light sensor",
.type = DRIVER_TYPE_LIGHT,
.specific_type = DRIVER_TYPE_LIGHT_IIO,
.discover = iio_poll_light_discover,
.open = iio_poll_light_open,
.set_polling = iio_poll_light_set_polling,
.close = iio_poll_light_close,
};
iio-sensor-proxy-1.1/src/drv-input-accel.c 0000664 0000000 0000000 00000006452 12554165724 0020573 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include "drivers.h"
#include
#include
#include
#include
#include
#include
typedef struct DrvData {
ReadingsUpdateFunc callback_func;
gpointer user_data;
GUdevClient *client;
GUdevDevice *dev, *parent;
const char *dev_path;
} DrvData;
static DrvData *drv_data = NULL;
static gboolean
input_accel_discover (GUdevDevice *device)
{
const char *path;
if (g_strcmp0 (g_udev_device_get_subsystem (device), "input") != 0)
return FALSE;
if (!g_udev_device_get_property_as_boolean (device, "ID_INPUT_ACCELEROMETER"))
return FALSE;
path = g_udev_device_get_device_file (device);
if (!path)
return FALSE;
if (strstr (path, "/event") == NULL)
return FALSE;
g_debug ("Found input accel at %s", g_udev_device_get_sysfs_path (device));
return TRUE;
}
#define READ_AXIS(axis, var) { memzero(&abs_info, sizeof(abs_info)); r = ioctl(fd, EVIOCGABS(axis), &abs_info); if (r < 0) return; var = abs_info.value; }
#define memzero(x,l) (memset((x), 0, (l)))
static void
accelerometer_changed (void)
{
struct input_absinfo abs_info;
int accel_x = 0, accel_y = 0, accel_z = 0;
int fd, r;
AccelReadings readings;
fd = open (drv_data->dev_path, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return;
READ_AXIS(ABS_X, accel_x);
READ_AXIS(ABS_Y, accel_y);
READ_AXIS(ABS_Z, accel_z);
close (fd);
readings.accel_x = accel_x;
readings.accel_y = accel_y;
readings.accel_z = accel_z;
drv_data->callback_func (&input_accel, (gpointer) &readings, drv_data->user_data);
}
static void
uevent_received (GUdevClient *client,
gchar *action,
GUdevDevice *device,
gpointer user_data)
{
if (g_strcmp0 (action, "change") != 0)
return;
if (g_strcmp0 (g_udev_device_get_sysfs_path (device), g_udev_device_get_sysfs_path (drv_data->parent)) != 0)
return;
accelerometer_changed ();
}
static gboolean
first_values (gpointer user_data)
{
accelerometer_changed ();
return G_SOURCE_REMOVE;
}
static gboolean
input_accel_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
const gchar * const subsystems[] = { "input", NULL };
drv_data = g_new0 (DrvData, 1);
drv_data->dev = g_object_ref (device);
drv_data->parent = g_udev_device_get_parent (drv_data->dev);
drv_data->dev_path = g_udev_device_get_device_file (device);
drv_data->client = g_udev_client_new (subsystems);
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
g_signal_connect (drv_data->client, "uevent",
G_CALLBACK (uevent_received), NULL);
g_idle_add (first_values, NULL);
return TRUE;
}
static void
input_accel_close (void)
{
g_clear_object (&drv_data->client);
g_clear_object (&drv_data->dev);
g_clear_object (&drv_data->parent);
g_clear_pointer (&drv_data->dev_path, g_free);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver input_accel = {
.name = "Input accelerometer",
.type = DRIVER_TYPE_ACCEL,
.specific_type = DRIVER_TYPE_ACCEL_INPUT,
.discover = input_accel_discover,
.open = input_accel_open,
.close = input_accel_close,
};
iio-sensor-proxy-1.1/src/fake-input-accelerometer.c 0000664 0000000 0000000 00000014210 12554165724 0022440 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2011, 2014 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "uinput.h"
#define ONEG 256
typedef struct {
GMainLoop *loop;
int uinput;
int accel_x, accel_y, accel_z;
GUdevClient *client;
GUdevDevice *uinput_dev;
struct termios old_tio;
} OrientationData;
static GUdevDevice *
setup_uinput_udev (GUdevClient *client)
{
GList *devices, *l;
GUdevDevice *ret = NULL;
devices = g_udev_client_query_by_subsystem (client, "input");
for (l = devices; l != NULL; l = l->next) {
GUdevDevice *dev = l->data;
if (g_udev_device_get_property_as_boolean (dev, "ID_INPUT_ACCELEROMETER")) {
ret = g_object_ref (dev);
break;
}
}
g_list_free_full (devices, g_object_unref);
return ret;
}
static int
write_sysfs_string (char *filename,
char *basedir,
char *val)
{
int ret = 0;
FILE *sysfsfp;
char *temp;
temp = g_build_filename (basedir, filename, NULL);
sysfsfp = fopen (temp, "w");
if (sysfsfp == NULL) {
ret = -errno;
goto error_free;
}
fprintf(sysfsfp, "%s", val);
fclose(sysfsfp);
error_free:
g_free(temp);
return ret;
}
static gboolean
send_uinput_event (OrientationData *data)
{
struct uinput_event ev;
memset(&ev, 0, sizeof(ev));
ev.type = EV_ABS;
ev.code = ABS_X;
ev.value = data->accel_x;
write (data->uinput, &ev, sizeof(ev));
ev.code = ABS_Y;
ev.value = data->accel_y;
write (data->uinput, &ev, sizeof(ev));
ev.code = ABS_Z;
ev.value = data->accel_z;
write (data->uinput, &ev, sizeof(ev));
memset(&ev, 0, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = EV_SYN;
ev.code = SYN_REPORT;
write (data->uinput, &ev, sizeof(ev));
if (!data->uinput_dev)
data->uinput_dev = setup_uinput_udev (data->client);
if (!data->uinput_dev)
return FALSE;
if (write_sysfs_string ("uevent", (char *) g_udev_device_get_sysfs_path (data->uinput_dev), "change") < 0) {
g_warning ("Failed to write uevent");
return FALSE;
}
return TRUE;
}
static gboolean
setup_uinput (OrientationData *data)
{
struct uinput_dev dev;
int fd;
fd = open("/dev/uinput", O_RDWR);
if (fd < 0) {
g_warning ("Could not open uinput");
return FALSE;
}
memset (&dev, 0, sizeof(dev));
snprintf (dev.name, sizeof (dev.name), "%s", "iio-sensor-proxy test application");
dev.id.bustype = BUS_VIRTUAL;
dev.id.vendor = 0x01; //FIXME
dev.id.product = 0x02;
/* 1G accel is reported as ~256, so clamp to 2G */
dev.absmin[ABS_X] = dev.absmin[ABS_Y] = dev.absmin[ABS_Z] = -512;
dev.absmax[ABS_X] = dev.absmax[ABS_Y] = dev.absmax[ABS_Z] = 512;
if (write (fd, &dev, sizeof(dev)) != sizeof(dev)) {
g_warning ("Error creating uinput device");
goto bail;
}
/* enabling key events */
if (ioctl (fd, UI_SET_EVBIT, EV_ABS) < 0) {
g_warning ("Error enabling uinput absolute events");
goto bail;
}
/* enabling keys */
if (ioctl (fd, UI_SET_ABSBIT, ABS_X) < 0 ||
ioctl (fd, UI_SET_ABSBIT, ABS_Y) < 0 ||
ioctl (fd, UI_SET_ABSBIT, ABS_Z) < 0) {
g_warning ("Couldn't enable uinput axis");
goto bail;
}
/* creating the device */
if (ioctl (fd, UI_DEV_CREATE) < 0) {
g_warning ("Error creating uinput device");
goto bail;
}
data->uinput = fd;
return TRUE;
bail:
close (fd);
return FALSE;
}
static void
keyboard_usage (void)
{
g_print ("Valid keys are: u (up), d (down), l (left), r (right), q/x (quit)\n");
}
static gboolean
check_keyboard (GIOChannel *source,
GIOCondition condition,
OrientationData *data)
{
GIOStatus status;
char buf[1];
status = g_io_channel_read_chars (source, buf, 1, NULL, NULL);
if (status == G_IO_STATUS_ERROR ||
status == G_IO_STATUS_EOF) {
g_main_loop_quit (data->loop);
return FALSE;
}
if (status == G_IO_STATUS_AGAIN)
return TRUE;
switch (buf[0]) {
case 'u':
data->accel_x = 0;
data->accel_y = ONEG;
data->accel_z = 0;
break;
case 'd':
data->accel_x = 0;
data->accel_y = -ONEG;
data->accel_z = 0;
break;
case 'l':
data->accel_x = -ONEG;
data->accel_y = 0;
data->accel_z = 0;
break;
case 'r':
data->accel_x = ONEG;
data->accel_y = 0;
data->accel_z = 0;
break;
case 'q':
case 'x':
g_main_loop_quit (data->loop);
return FALSE;
default:
keyboard_usage ();
return TRUE;
}
send_uinput_event (data);
return TRUE;
}
static gboolean
setup_keyboard (OrientationData *data)
{
GIOChannel *channel;
struct termios new_tio;
tcgetattr(STDIN_FILENO, &data->old_tio);
new_tio = data->old_tio;
new_tio.c_lflag &=(~ICANON & ~ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
channel = g_io_channel_unix_new (STDIN_FILENO);
if (!channel) {
g_warning ("Failed to open stdin");
return FALSE;
}
if (g_io_channel_set_encoding (channel, NULL, NULL) != G_IO_STATUS_NORMAL) {
g_warning ("Failed to set stdin encoding to NULL");
return FALSE;
}
g_io_add_watch (channel, G_IO_IN, (GIOFunc) check_keyboard, data);
return TRUE;
}
static void
free_orientation_data (OrientationData *data)
{
if (data == NULL)
return;
tcsetattr(STDIN_FILENO, TCSANOW, &data->old_tio);
if (data->uinput > 0)
close (data->uinput);
g_clear_object (&data->uinput_dev);
g_clear_object (&data->client);
g_clear_pointer (&data->loop, g_main_loop_unref);
g_free (data);
}
int main (int argc, char **argv)
{
OrientationData *data;
const gchar * const subsystems[] = { "input", NULL };
int ret = 0;
data = g_new0 (OrientationData, 1);
data->client = g_udev_client_new (subsystems);
if (!setup_keyboard (data)) {
g_warning ("Failed to setup keyboard capture");
ret = 1;
goto out;
}
/* Set up uinput */
if (!setup_uinput (data)) {
ret = 1;
goto out;
}
/* Start with the 'normal' orientation */
data->accel_x = 0;
data->accel_y = ONEG;
data->accel_z = 0;
send_uinput_event (data);
keyboard_usage ();
data->loop = g_main_loop_new (NULL, TRUE);
g_main_loop_run (data->loop);
out:
free_orientation_data (data);
return ret;
}
iio-sensor-proxy-1.1/src/iio-buffer-utils.c 0000664 0000000 0000000 00000037455 12554165724 0020772 0 ustar 00root root 0000000 0000000 /*
* Modified from industrialio buffer test code, and Lenovo Yoga (2 Pro) orientation helper
* Copyright (c) 2008 Jonathan Cameron
* Copyright (c) 2014 Peter F. Patel-Schneider
* Copyright (c) 2014 Bastien Nocera
* Copyright (c) 2015 Elad Alfassa
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include "iio-buffer-utils.h"
#include
#include
#include
#include
/**
* iio_channel_info - information about a given channel
* @name: channel name
* @scale: scale factor to be applied for conversion to si units
* @offset: offset to be applied for conversion to si units
* @index: the channel index in the buffer output
* @bytes: number of bytes occupied in buffer output
* @mask: a bit mask for the raw output
* @is_signed: is the raw value stored signed
* @enabled: is this channel enabled
**/
struct iio_channel_info {
char *name;
char *generic_name;
float scale;
float offset;
unsigned index;
unsigned bytes;
unsigned bits_used;
unsigned shift;
guint64 mask;
unsigned be;
unsigned is_signed;
unsigned enabled;
unsigned location;
};
static char *
iioutils_break_up_name (const char *name)
{
char **items, *ret;
guint i;
items = g_strsplit (name, "_", -1);
for (i = 0; items[i] != NULL; i++) {
if (items[i + 1] == NULL) {
g_clear_pointer (&items[i], g_free);
break;
}
}
ret = g_strjoinv ("_", items);
g_strfreev (items);
return ret;
}
/**
* iioutils_get_type() - find and process _type attribute data
* @is_signed: output whether channel is signed
* @bytes: output how many bytes the channel storage occupies
* @mask: output a bit mask for the raw data
* @be: big endian
* @device_dir: the iio device directory
* @name: the channel name
**/
static gboolean
iioutils_get_type (unsigned *is_signed,
unsigned *bytes,
unsigned *bits_used,
unsigned *shift,
guint64 *mask,
unsigned *be,
const char *device_dir,
const char *name,
const char *generic_name)
{
int ret;
char *builtname;
char *filename;
char signchar, endianchar;
unsigned padint;
FILE *sysfsfp;
builtname = g_strdup_printf ("%s_type", name);
filename = g_build_filename (device_dir, "scan_elements", builtname, NULL);
g_free (builtname);
sysfsfp = fopen (filename, "r");
if (sysfsfp == NULL) {
builtname = g_strdup_printf ("%s_type", generic_name);
filename = g_build_filename (device_dir, "scan_elements", builtname, NULL);
g_free (builtname);
sysfsfp = fopen (filename, "r");
if (sysfsfp == NULL) {
g_free (filename);
return FALSE;
}
}
ret = fscanf (sysfsfp,
"%ce:%c%u/%u>>%u",
&endianchar,
&signchar,
bits_used,
&padint, shift);
if (ret < 0) {
g_warning ("Failed to pass scan type description for %s", filename);
fclose (sysfsfp);
g_free (filename);
return FALSE;
}
fclose (sysfsfp);
*be = (endianchar == 'b');
*bytes = padint / 8;
if (*bits_used == 64)
*mask = ~0;
else
*mask = (1 << *bits_used) - 1;
if (signchar == 's')
*is_signed = 1;
else
*is_signed = 0;
g_debug ("Got type for %s: is signed: %d, bytes: %d, bits_used: %d, shift: %d, mask: 0x%" G_GUINT64_FORMAT ", be: %d",
name, *is_signed, *bytes, *bits_used, *shift, *mask, *be);
g_free (filename);
return TRUE;
}
static int
iioutils_get_param_float (float *output,
const char *param_name,
const char *device_dir,
const char *name,
const char *generic_name)
{
FILE *sysfsfp;
char *builtname, *filename;
int ret = 0;
builtname = g_strdup_printf ("%s_%s", name, param_name);
filename = g_build_filename (device_dir, builtname, NULL);
g_free (builtname);
sysfsfp = fopen (filename, "r");
if (sysfsfp) {
fscanf (sysfsfp, "%f", output);
fclose (sysfsfp);
g_free (filename);
return 0;
}
g_free (filename);
builtname = g_strdup_printf ("%s_%s", generic_name, param_name);
filename = g_build_filename (device_dir, builtname, NULL);
g_free (builtname);
sysfsfp = fopen (filename, "r");
if (sysfsfp) {
fscanf (sysfsfp, "%f", output);
fclose (sysfsfp);
} else {
ret = -errno;
g_warning ("Failed to read float from %s", filename);
}
g_free (filename);
return ret;
}
static void
channel_info_free (iio_channel_info *ci)
{
g_free (ci->name);
g_free (ci->generic_name);
g_free (ci);
}
/* build_channel_array() - function to figure out what channels are present */
static iio_channel_info **
build_channel_array (const char *device_dir,
int *counter)
{
GDir *dp;
FILE *sysfsfp;
int ret;
const char *name;
char *scan_el_dir;
GPtrArray *array;
iio_channel_info **ret_array;
int i;
*counter = 0;
scan_el_dir = g_build_filename (device_dir, "scan_elements", NULL);
dp = g_dir_open (scan_el_dir, 0, NULL);
if (dp == NULL) {
ret = -errno;
g_free (scan_el_dir);
return NULL;
}
array = g_ptr_array_new_full (0, (GDestroyNotify) channel_info_free);
while ((name = g_dir_read_name (dp)) != NULL) {
if (g_str_has_suffix (name, "_en")) {
char *filename, *index_name;
iio_channel_info *current;
filename = g_build_filename (scan_el_dir, name, NULL);
sysfsfp = fopen (filename, "r");
if (sysfsfp == NULL) {
g_free (filename);
continue;
}
fscanf (sysfsfp, "%d", &ret);
fclose (sysfsfp);
if (!ret) {
g_free (filename);
continue;
}
g_free (filename);
current = g_new0 (iio_channel_info, 1);
current->scale = 1.0;
current->offset = 0;
current->name = g_strndup (name, strlen(name) - strlen("_en"));
current->generic_name = iioutils_break_up_name (current->name);
if (g_strcmp0(current->generic_name, "in_rot_from_north_magnetic_tilt") == 0) {
current->generic_name = "in_rot";
}
index_name = g_strdup_printf ("%s_index", current->name);
filename = g_build_filename (scan_el_dir, index_name, NULL);
g_free (index_name);
sysfsfp = fopen (filename, "r");
fscanf (sysfsfp, "%u", ¤t->index);
fclose (sysfsfp);
g_free (filename);
/* Find the scale */
ret = iioutils_get_param_float (¤t->scale,
"scale",
device_dir,
current->name,
current->generic_name);
if (ret < 0)
goto error;
ret = iioutils_get_param_float (¤t->offset,
"offset",
device_dir,
current->name,
current->generic_name);
if (ret < 0)
goto error;
ret = iioutils_get_type (¤t->is_signed,
¤t->bytes,
¤t->bits_used,
¤t->shift,
¤t->mask,
¤t->be,
device_dir,
current->name,
current->generic_name);
if (!ret) {
g_warning ("Could not parse name %s, generic name %s",
current->name, current->generic_name);
} else {
g_ptr_array_add (array, current);
}
}
}
g_dir_close (dp);
g_free (scan_el_dir);
*counter = array->len;
ret_array = (iio_channel_info **) g_ptr_array_free (array, FALSE);
for (i = 0; i < *counter; i++) {
iio_channel_info *ci = ret_array[i];
g_debug ("Built channel array for %s: is signed: %d, bytes: %d, bits_used: %d, shift: %d, mask: 0x%" G_GUINT64_FORMAT ", be: %d",
ci->name, ci->is_signed, ci->bytes, ci->bits_used, ci->shift, ci->mask, ci->be);
}
return ret_array;
error:
g_ptr_array_free (array, TRUE);
g_dir_close (dp);
g_free (scan_el_dir);
return NULL;
}
static int
_write_sysfs_int (const char *filename,
const char *basedir,
int val,
int verify,
int type,
int val2)
{
int ret = 0;
FILE *sysfsfp;
int test;
char *temp;
temp = g_build_filename (basedir, filename, NULL);
sysfsfp = fopen(temp, "w");
if (sysfsfp == NULL) {
g_warning ("Could not open for write '%s'", temp);
ret = -errno;
goto error_free;
}
if (type)
fprintf(sysfsfp, "%d %d", val, val2);
else
fprintf(sysfsfp, "%d", val);
fclose(sysfsfp);
if (verify) {
sysfsfp = fopen(temp, "r");
if (sysfsfp == NULL) {
g_warning ("Could not open for read '%s'", temp);
ret = -errno;
goto error_free;
}
fscanf(sysfsfp, "%d", &test);
if (test != val) {
g_warning ("Possible failure in int write %d to %s",
val, temp);
ret = -1;
}
fclose(sysfsfp);
}
error_free:
g_free (temp);
return ret;
}
static int write_sysfs_int(const char *filename, const char *basedir, int val) {
return _write_sysfs_int(filename, basedir, val, 0, 0, 0);
}
static int write_sysfs_int_and_verify(const char *filename, const char *basedir, int val) {
return _write_sysfs_int(filename, basedir, val, 1, 0, 0);
}
static int
_write_sysfs_string (const char *filename,
const char *basedir,
const char *val,
int verify)
{
int ret = 0;
FILE *sysfsfp;
char *temp;
temp = g_build_filename (basedir, filename, NULL);
sysfsfp = fopen (temp, "w");
if (sysfsfp == NULL) {
ret = -errno;
goto error_free;
}
fprintf(sysfsfp, "%s", val);
fclose(sysfsfp);
/* Verify? */
if (!verify)
goto error_free;
sysfsfp = fopen(temp, "r");
if (sysfsfp == NULL) {
ret = -errno;
goto error_free;
}
fscanf(sysfsfp, "%s", temp);
if (strcmp(temp, val) != 0) {
g_warning ("Possible failure in string write of %s Should be %s written to %s\\%s\n",
temp, val, basedir, filename);
ret = -1;
}
fclose(sysfsfp);
error_free:
g_free(temp);
return ret;
}
/**
* write_sysfs_string_and_verify() - string write, readback and verify
* @filename: name of file to write to
* @basedir: the sysfs directory in which the file is to be found
* @val: the string to write
**/
static int write_sysfs_string_and_verify(const char *filename, const char *basedir, const char *val) {
return _write_sysfs_string(filename, basedir, val, 1);
}
static int write_sysfs_string(const char *filename, const char *basedir, const char *val) {
return _write_sysfs_string(filename, basedir, val, 0);
}
/**
* size_from_channelarray() - calculate the storage size of a scan
* @channels: the channel info array
* @num_channels: number of channels
*
* Has the side effect of filling the channels[i].location values used
* in processing the buffer output.
**/
static int
size_from_channelarray (iio_channel_info **channels,
int num_channels)
{
int bytes = 0;
int i = 0;
while (i < num_channels) {
if (bytes % channels[i]->bytes == 0)
channels[i]->location = bytes;
else
channels[i]->location = bytes - bytes % channels[i]->bytes
+ channels[i]->bytes;
bytes = channels[i]->location + channels[i]->bytes;
i++;
}
return bytes;
}
/**
* process_scan_1() - get an integer value for a particular channel
* @data: pointer to the start of the scan
* @buffer_data: Buffer information
* ch_name: name of channel to get
* ch_val: value for the channel
* ch_scale: scale for the channel
* ch_present: whether the channel is present
**/
void
process_scan_1 (char *data,
BufferDrvData *buffer_data,
char *ch_name,
int *ch_val,
gdouble *ch_scale,
gboolean *ch_present)
{
int k;
for (k = 0; k < buffer_data->channels_count; k++) {
if (strcmp (buffer_data->channels[k]->name, ch_name) != 0)
continue;
switch (buffer_data->channels[k]->bytes) {
/* only a few cases implemented so far */
case 4:
if (!buffer_data->channels[k]->is_signed) {
guint32 val = *(guint32 *) (data + buffer_data->channels[k]->location);
val = val >> buffer_data->channels[k]->shift;
if (buffer_data->channels[k]->bits_used < 32) val &= ((guint32) 1 << buffer_data->channels[k]->bits_used) - 1;
*ch_val = (int) val;
*ch_present = TRUE;
} else {
gint32 val = *(gint32 *) (data + buffer_data->channels[k]->location);
val = val >> buffer_data->channels[k]->shift;
if (buffer_data->channels[k]->bits_used < 32) val &= ((guint32) 1 << buffer_data->channels[k]->bits_used) - 1;
val = (gint32) (val << (32 - buffer_data->channels[k]->bits_used)) >> (32 - buffer_data->channels[k]->bits_used);
*ch_val = (int) val;
if (buffer_data->channels[k]->scale)
*ch_scale = buffer_data->channels[k]->scale;
else
*ch_scale = 1.0;
*ch_present = TRUE;
}
break;
case 2:
case 8:
g_error ("Process %d bytes channels not supported yet", buffer_data->channels[k]->bytes);
default:
g_assert_not_reached ();
break;
}
}
if (!*ch_present)
g_warning ("IIO channel '%s' could not be found", ch_name);
}
/**
* enable_sensors: enable all the sensors in a device
* @device_dir: the IIO device directory in sysfs
* @
**/
static gboolean
enable_sensors (GUdevDevice *dev,
int enable)
{
GDir *dir;
char *device_dir;
const char *name;
gboolean ret = TRUE;
device_dir = g_build_filename (g_udev_device_get_sysfs_path (dev), "scan_elements", NULL);
dir = g_dir_open (device_dir, 0, NULL);
if (!dir) {
g_free (device_dir);
return FALSE;
}
while ((name = g_dir_read_name (dir))) {
char *path;
if (g_str_has_suffix (name, "_en") == FALSE)
continue;
/* Already enabled? */
path = g_strdup_printf ("scan_elements/%s", name);
if (g_udev_device_get_sysfs_attr_as_boolean (dev, path)) {
g_free (path);
continue;
}
g_free (path);
/* Enable */
if (write_sysfs_int (name, device_dir, enable) < 0) {
g_warning ("Could not enable sensor %s/%s", device_dir, name);
ret = FALSE;
continue;
}
g_debug ("Enabled sensor %s/%s", device_dir, name);
}
g_dir_close (dir);
g_free (device_dir);
return ret;
}
static gboolean
enable_ring_buffer (BufferDrvData *data)
{
int ret;
/* Setup ring buffer parameters */
ret = write_sysfs_int("buffer/length", data->dev_dir_name, 128);
if (ret < 0)
return FALSE;
/* Enable the buffer */
ret = write_sysfs_int_and_verify("buffer/enable", data->dev_dir_name, 1);
if (ret < 0) {
printf("Unable to enable the buffer %d\n", ret);
return FALSE;
}
return TRUE;
}
static void
disable_ring_buffer (BufferDrvData *data)
{
/* Stop the buffer */
write_sysfs_int ("buffer/enable", data->dev_dir_name, 0);
/* Disconnect the trigger - just write a dummy name. */
write_sysfs_string ("trigger/current_trigger", data->dev_dir_name, "NULL");
}
static gboolean
enable_trigger (BufferDrvData *data)
{
int ret;
/* Set the device trigger to be the data ready trigger */
ret = write_sysfs_string_and_verify("trigger/current_trigger",
data->dev_dir_name, data->trigger_name);
if (ret < 0) {
g_warning ("Failed to write current_trigger file %s", g_strerror(-ret));
return FALSE;
}
return TRUE;
}
static gboolean
build_channels (BufferDrvData *data)
{
/* Parse the files in scan_elements to identify what channels are present */
data->channels = build_channel_array (data->dev_dir_name, &(data->channels_count));
if (data->channels == NULL) {
g_warning ("Problem reading scan element information: %s", data->dev_dir_name);
return FALSE;
}
data->scan_size = size_from_channelarray (data->channels, data->channels_count);
return TRUE;
}
void
buffer_drv_data_free (BufferDrvData *buffer_data)
{
int i;
if (buffer_data == NULL)
return;
enable_sensors (buffer_data->device, 0);
g_clear_object (&buffer_data->device);
disable_ring_buffer (buffer_data);
g_free (buffer_data->trigger_name);
for (i = 0; i < buffer_data->channels_count; i++)
channel_info_free (buffer_data->channels[i]);
g_free (buffer_data->channels);
}
BufferDrvData *
buffer_drv_data_new (GUdevDevice *device,
const char *trigger_name)
{
BufferDrvData *buffer_data;
buffer_data = g_new0 (BufferDrvData, 1);
buffer_data->dev_dir_name = g_udev_device_get_sysfs_path (device);
buffer_data->trigger_name = g_strdup (trigger_name);
buffer_data->device = g_object_ref (device);
if (!enable_sensors (device, 1) ||
!enable_trigger (buffer_data) ||
!enable_ring_buffer (buffer_data) ||
!build_channels (buffer_data)) {
buffer_drv_data_free (buffer_data);
return NULL;
}
return buffer_data;
}
iio-sensor-proxy-1.1/src/iio-buffer-utils.h 0000664 0000000 0000000 00000002454 12554165724 0020766 0 ustar 00root root 0000000 0000000 /*
* Modified from industrialio buffer test code, and Lenovo Yoga (2 Pro) orientation helper
* Copyright (c) 2008 Jonathan Cameron
* Copyright (c) 2014 Peter F. Patel-Schneider
* Copyright (c) 2014 Bastien Nocera
* Copyright (c) 2015 Elad Alfassa
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*/
#include
#include
typedef struct iio_channel_info iio_channel_info;
typedef struct {
GUdevDevice *device;
char *trigger_name;
const char *dev_dir_name;
int channels_count;
iio_channel_info **channels;
int scan_size;
} BufferDrvData;
typedef struct {
ssize_t read_size;
char *data;
} IIOSensorData;
void process_scan_1 (char *data,
BufferDrvData *buffer_data,
char *ch_name,
int *ch_val,
gdouble *ch_scale,
gboolean *ch_present);
void buffer_drv_data_free (BufferDrvData *buffer_data);
BufferDrvData *buffer_drv_data_new (GUdevDevice *device,
const char *trigger_name);
iio-sensor-proxy-1.1/src/iio-sensor-proxy.c 0000664 0000000 0000000 00000053217 12554165724 0021045 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2014-2015 Bastien Nocera
*
* orientation_calc() from the sensorfw package
* Copyright (C) 2009-2010 Nokia Corporation
* Authors:
* Üstün Ergenoglu
* Timo Rongas
* Lihan Guo
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
*/
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include "drivers.h"
#include "orientation.h"
#include "iio-sensor-proxy-resources.h"
#define SENSOR_PROXY_DBUS_NAME "net.hadess.SensorProxy"
#define SENSOR_PROXY_DBUS_PATH "/net/hadess/SensorProxy"
#define SENSOR_PROXY_COMPASS_DBUS_PATH "/net/hadess/SensorProxy/Compass"
#define SENSOR_PROXY_IFACE_NAME SENSOR_PROXY_DBUS_NAME
#define SENSOR_PROXY_COMPASS_IFACE_NAME SENSOR_PROXY_DBUS_NAME ".Compass"
#define NUM_SENSOR_TYPES DRIVER_TYPE_COMPASS + 1
typedef struct {
GMainLoop *loop;
GDBusNodeInfo *introspection_data;
GDBusConnection *connection;
guint name_id;
gboolean init_done;
SensorDriver *drivers[NUM_SENSOR_TYPES];
GUdevDevice *devices[NUM_SENSOR_TYPES];
GHashTable *clients[NUM_SENSOR_TYPES]; /* key = D-Bus name, value = watch ID */
/* Accelerometer */
int accel_x, accel_y, accel_z;
OrientationUp previous_orientation;
/* Light */
gdouble previous_level;
gboolean uses_lux;
/* Compass */
gdouble previous_heading;
} SensorData;
static const SensorDriver * const drivers[] = {
&iio_buffer_accel,
&iio_poll_accel,
&input_accel,
&iio_poll_light,
&iio_buffer_light,
&hwmon_light,
&fake_compass,
&fake_light,
&iio_buffer_compass
};
static ReadingsUpdateFunc driver_type_to_callback_func (DriverType type);
static const char *
driver_type_to_str (DriverType type)
{
switch (type) {
case DRIVER_TYPE_ACCEL:
return "accelerometer";
case DRIVER_TYPE_LIGHT:
return "ambient light sensor";
case DRIVER_TYPE_COMPASS:
return "compass";
default:
g_assert_not_reached ();
}
}
#define DRIVER_FOR_TYPE(driver_type) data->drivers[driver_type]
#define DEVICE_FOR_TYPE(driver_type) data->devices[driver_type]
static gboolean
driver_type_exists (SensorData *data,
DriverType driver_type)
{
return (DRIVER_FOR_TYPE(driver_type) != NULL);
}
static gboolean
find_sensors (GUdevClient *client,
SensorData *data)
{
GList *devices, *input, *platform, *l;
gboolean found = FALSE;
devices = g_udev_client_query_by_subsystem (client, "iio");
input = g_udev_client_query_by_subsystem (client, "input");
platform = g_udev_client_query_by_subsystem (client, "platform");
devices = g_list_concat (devices, input);
devices = g_list_concat (devices, platform);
/* Find the devices */
for (l = devices; l != NULL; l = l->next) {
GUdevDevice *dev = l->data;
guint i;
for (i = 0; i < G_N_ELEMENTS(drivers); i++) {
SensorDriver *driver = (SensorDriver *) drivers[i];
if (!driver_type_exists(data, driver->type) &&
driver_discover (driver, dev)) {
g_debug ("Found device %s of type %s at %s",
g_udev_device_get_sysfs_path (dev),
driver_type_to_str (driver->type),
driver->name);
DEVICE_FOR_TYPE(driver->type) = g_object_ref (dev);
DRIVER_FOR_TYPE(driver->type) = (SensorDriver *) driver;
found = TRUE;
}
}
if (driver_type_exists (data, DRIVER_TYPE_ACCEL) &&
driver_type_exists (data, DRIVER_TYPE_LIGHT) &&
driver_type_exists (data, DRIVER_TYPE_COMPASS))
break;
}
g_list_free_full (devices, g_object_unref);
return found;
}
static void
free_client_watch (gpointer data)
{
guint watch_id = GPOINTER_TO_UINT (data);
if (watch_id == 0)
return;
g_bus_unwatch_name (watch_id);
}
static GHashTable *
create_clients_hash_table (void)
{
return g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, free_client_watch);
}
typedef enum {
PROP_HAS_ACCELEROMETER = 1 << 0,
PROP_ACCELEROMETER_ORIENTATION = 1 << 1,
PROP_HAS_AMBIENT_LIGHT = 1 << 2,
PROP_LIGHT_LEVEL = 1 << 3,
PROP_HAS_COMPASS = 1 << 4,
PROP_COMPASS_HEADING = 1 << 5
} PropertiesMask;
#define PROP_ALL (PROP_HAS_ACCELEROMETER | \
PROP_ACCELEROMETER_ORIENTATION | \
PROP_HAS_AMBIENT_LIGHT | \
PROP_LIGHT_LEVEL)
#define PROP_ALL_COMPASS (PROP_HAS_COMPASS | \
PROP_COMPASS_HEADING)
static void
send_dbus_event (SensorData *data,
PropertiesMask mask)
{
GVariantBuilder props_builder;
GVariant *props_changed = NULL;
g_assert (data->connection);
if (mask == 0)
return;
g_assert ((mask & PROP_ALL) == 0 || (mask & PROP_ALL_COMPASS) == 0);
g_variant_builder_init (&props_builder, G_VARIANT_TYPE ("a{sv}"));
if (mask & PROP_HAS_ACCELEROMETER) {
gboolean has_accel;
has_accel = driver_type_exists (data, DRIVER_TYPE_ACCEL);
g_variant_builder_add (&props_builder, "{sv}", "HasAccelerometer",
g_variant_new_boolean (has_accel));
/* Send the orientation when the device appears */
if (has_accel)
mask |= PROP_ACCELEROMETER_ORIENTATION;
else
data->previous_orientation = ORIENTATION_UNDEFINED;
}
if (mask & PROP_ACCELEROMETER_ORIENTATION) {
g_variant_builder_add (&props_builder, "{sv}", "AccelerometerOrientation",
g_variant_new_string (orientation_to_string (data->previous_orientation)));
}
if (mask & PROP_HAS_AMBIENT_LIGHT) {
gboolean has_als;
has_als = driver_type_exists (data, DRIVER_TYPE_LIGHT);
g_variant_builder_add (&props_builder, "{sv}", "HasAmbientLight",
g_variant_new_boolean (has_als));
/* Send the light level when the device appears */
if (has_als)
mask |= PROP_LIGHT_LEVEL;
}
if (mask & PROP_LIGHT_LEVEL) {
g_variant_builder_add (&props_builder, "{sv}", "LightLevelUnit",
g_variant_new_string (data->uses_lux ? "lux" : "vendor"));
g_variant_builder_add (&props_builder, "{sv}", "LightLevel",
g_variant_new_double (data->previous_level));
}
if (mask & PROP_HAS_COMPASS) {
gboolean has_compass;
has_compass = driver_type_exists (data, DRIVER_TYPE_COMPASS);
g_variant_builder_add (&props_builder, "{sv}", "HasCompass",
g_variant_new_boolean (has_compass));
/* Send the heading when the device appears */
if (has_compass)
mask |= PROP_COMPASS_HEADING;
}
if (mask & PROP_COMPASS_HEADING) {
g_variant_builder_add (&props_builder, "{sv}", "CompassHeading",
g_variant_new_double (data->previous_heading));
}
props_changed = g_variant_new ("(s@a{sv}@as)", (mask & PROP_ALL) ? SENSOR_PROXY_IFACE_NAME : SENSOR_PROXY_COMPASS_IFACE_NAME,
g_variant_builder_end (&props_builder),
g_variant_new_strv (NULL, 0));
g_dbus_connection_emit_signal (data->connection,
NULL,
(mask & PROP_ALL) ? SENSOR_PROXY_DBUS_PATH : SENSOR_PROXY_COMPASS_DBUS_PATH,
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
props_changed, NULL);
}
static void
send_driver_changed_dbus_event (SensorData *data,
DriverType driver_type)
{
if (driver_type == DRIVER_TYPE_ACCEL)
send_dbus_event (data, PROP_HAS_ACCELEROMETER);
else if (driver_type == DRIVER_TYPE_LIGHT)
send_dbus_event (data, PROP_HAS_AMBIENT_LIGHT);
else if (driver_type == DRIVER_TYPE_COMPASS)
send_dbus_event (data, PROP_HAS_COMPASS);
else
g_assert_not_reached ();
}
static gboolean
any_sensors_left (SensorData *data)
{
guint i;
gboolean exists = FALSE;
for (i = 0; i < NUM_SENSOR_TYPES; i++) {
if (driver_type_exists (data, i)) {
exists = TRUE;
break;
}
}
return exists;
}
static void
client_release (SensorData *data,
const char *sender,
DriverType driver_type)
{
GHashTable *ht;
guint watch_id;
ht = data->clients[driver_type];
watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender));
if (watch_id == 0)
return;
g_hash_table_remove (ht, sender);
if (driver_type_exists (data, driver_type) &&
g_hash_table_size (ht) == 0)
driver_set_polling (DRIVER_FOR_TYPE(driver_type), FALSE);
}
static void
client_vanished_cb (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
SensorData *data = user_data;
guint i;
char *sender;
if (name == NULL)
return;
sender = g_strdup (name);
for (i = 0; i < NUM_SENSOR_TYPES; i++) {
GHashTable *ht;
guint watch_id;
ht = data->clients[i];
g_assert (ht);
watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender));
if (watch_id > 0)
client_release (data, sender, i);
}
g_free (sender);
}
static void
handle_generic_method_call (SensorData *data,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
DriverType driver_type)
{
GHashTable *ht;
guint watch_id;
g_debug ("Handling driver refcounting method '%s' for %s device",
method_name, driver_type_to_str (driver_type));
ht = data->clients[driver_type];
if (g_str_has_prefix (method_name, "Claim")) {
watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender));
if (watch_id > 0) {
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
/* No other clients for this sensor? Start it */
if (driver_type_exists (data, driver_type) &&
g_hash_table_size (ht) == 0)
driver_set_polling (DRIVER_FOR_TYPE(driver_type), TRUE);
watch_id = g_bus_watch_name_on_connection (data->connection,
sender,
G_BUS_NAME_WATCHER_FLAGS_NONE,
NULL,
client_vanished_cb,
data,
NULL);
g_hash_table_insert (ht, g_strdup (sender), GUINT_TO_POINTER (watch_id));
g_dbus_method_invocation_return_value (invocation, NULL);
} else if (g_str_has_prefix (method_name, "Release")) {
client_release (data, sender, driver_type);
g_dbus_method_invocation_return_value (invocation, NULL);
}
}
static void
handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
SensorData *data = user_data;
DriverType driver_type;
if (g_strcmp0 (method_name, "ClaimAccelerometer") == 0 ||
g_strcmp0 (method_name, "ReleaseAccelerometer") == 0)
driver_type = DRIVER_TYPE_ACCEL;
else if (g_strcmp0 (method_name, "ClaimLight") == 0 ||
g_strcmp0 (method_name, "ReleaseLight") == 0)
driver_type = DRIVER_TYPE_LIGHT;
else {
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_UNKNOWN_METHOD,
"Method '%s' does not exist on object %s",
method_name, object_path);
return;
}
handle_generic_method_call (data, sender, object_path,
interface_name, method_name,
parameters, invocation, driver_type);
}
static GVariant *
handle_get_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GError **error,
gpointer user_data)
{
SensorData *data = user_data;
g_assert (data->connection);
if (g_strcmp0 (property_name, "HasAccelerometer") == 0)
return g_variant_new_boolean (driver_type_exists (data, DRIVER_TYPE_ACCEL));
if (g_strcmp0 (property_name, "AccelerometerOrientation") == 0)
return g_variant_new_string (orientation_to_string (data->previous_orientation));
if (g_strcmp0 (property_name, "HasAmbientLight") == 0)
return g_variant_new_boolean (driver_type_exists (data, DRIVER_TYPE_LIGHT));
if (g_strcmp0 (property_name, "LightLevelUnit") == 0)
return g_variant_new_string (data->uses_lux ? "lux" : "vendor");
if (g_strcmp0 (property_name, "LightLevel") == 0)
return g_variant_new_double (data->previous_level);
return NULL;
}
static const GDBusInterfaceVTable interface_vtable =
{
handle_method_call,
handle_get_property,
NULL
};
static void
handle_compass_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
SensorData *data = user_data;
if (g_strcmp0 (method_name, "ClaimCompass") != 0 &&
g_strcmp0 (method_name, "ReleaseCompass") != 0) {
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_UNKNOWN_METHOD,
"Method '%s' does not exist on object %s",
method_name, object_path);
return;
}
handle_generic_method_call (data, sender, object_path,
interface_name, method_name,
parameters, invocation, DRIVER_TYPE_COMPASS);
}
static GVariant *
handle_compass_get_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GError **error,
gpointer user_data)
{
SensorData *data = user_data;
g_assert (data->connection);
if (g_strcmp0 (property_name, "HasCompass") == 0)
return g_variant_new_boolean (data->drivers[DRIVER_TYPE_COMPASS] != NULL);
if (g_strcmp0 (property_name, "CompassHeading") == 0)
return g_variant_new_double (data->previous_heading);
return NULL;
}
static const GDBusInterfaceVTable compass_interface_vtable =
{
handle_compass_method_call,
handle_compass_get_property,
NULL
};
static void
name_lost_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_debug ("iio-sensor-proxy is already running, or it cannot own its D-Bus name. Verify installation.");
exit (0);
}
static void
bus_acquired_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
SensorData *data = user_data;
g_dbus_connection_register_object (connection,
SENSOR_PROXY_DBUS_PATH,
data->introspection_data->interfaces[0],
&interface_vtable,
data,
NULL,
NULL);
g_dbus_connection_register_object (connection,
SENSOR_PROXY_COMPASS_DBUS_PATH,
data->introspection_data->interfaces[1],
&compass_interface_vtable,
data,
NULL,
NULL);
data->connection = g_object_ref (connection);
}
static void
name_acquired_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
SensorData *data = user_data;
if (data->init_done) {
send_dbus_event (data, PROP_ALL);
send_dbus_event (data, PROP_ALL_COMPASS);
}
}
static gboolean
setup_dbus (SensorData *data)
{
GBytes *bytes;
bytes = g_resources_lookup_data ("/net/hadess/SensorProxy/net.hadess.SensorProxy.xml",
G_RESOURCE_LOOKUP_FLAGS_NONE,
NULL);
data->introspection_data = g_dbus_node_info_new_for_xml (g_bytes_get_data (bytes, NULL), NULL);
g_bytes_unref (bytes);
g_assert (data->introspection_data != NULL);
data->name_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
SENSOR_PROXY_DBUS_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
bus_acquired_handler,
name_acquired_handler,
name_lost_handler,
data,
NULL);
return TRUE;
}
static void
accel_changed_func (SensorDriver *driver,
gpointer readings_data,
gpointer user_data)
{
SensorData *data = user_data;
AccelReadings *readings = (AccelReadings *) readings_data;
OrientationUp orientation = data->previous_orientation;
//FIXME handle errors
g_debug ("Accel sent by driver (quirk applied): %d, %d, %d", readings->accel_x, readings->accel_y, readings->accel_z);
orientation = orientation_calc (data->previous_orientation, readings->accel_x, readings->accel_y, readings->accel_z);
data->accel_x = readings->accel_x;
data->accel_y = readings->accel_y;
data->accel_z = readings->accel_z;
if (data->previous_orientation != orientation) {
OrientationUp tmp;
tmp = data->previous_orientation;
data->previous_orientation = orientation;
send_dbus_event (data, PROP_ACCELEROMETER_ORIENTATION);
g_debug ("Emitted orientation changed: from %s to %s",
orientation_to_string (tmp),
orientation_to_string (data->previous_orientation));
}
}
static void
light_changed_func (SensorDriver *driver,
gpointer readings_data,
gpointer user_data)
{
SensorData *data = user_data;
LightReadings *readings = (LightReadings *) readings_data;
//FIXME handle errors
g_debug ("Light level sent by driver (quirk applied): %lf (unit: %s)",
readings->level, data->uses_lux ? "lux" : "vendor");
if (data->previous_level != readings->level ||
data->uses_lux != readings->uses_lux) {
gdouble tmp;
tmp = data->previous_level;
data->previous_level = readings->level;
data->uses_lux = readings->uses_lux;
send_dbus_event (data, PROP_LIGHT_LEVEL);
g_debug ("Emitted light changed: from %lf to %lf",
tmp, data->previous_level);
}
}
static void
compass_changed_func (SensorDriver *driver,
gpointer readings_data,
gpointer user_data)
{
SensorData *data = user_data;
CompassReadings *readings = (CompassReadings *) readings_data;
//FIXME handle errors
g_debug ("Heading sent by driver (quirk applied): %lf degrees",
readings->heading);
if (data->previous_heading != readings->heading) {
gdouble tmp;
tmp = data->previous_heading;
data->previous_heading = readings->heading;
send_dbus_event (data, PROP_COMPASS_HEADING);
g_debug ("Emitted heading changed: from %lf to %lf",
tmp, data->previous_heading);
}
}
static ReadingsUpdateFunc
driver_type_to_callback_func (DriverType type)
{
switch (type) {
case DRIVER_TYPE_ACCEL:
return accel_changed_func;
case DRIVER_TYPE_LIGHT:
return light_changed_func;
case DRIVER_TYPE_COMPASS:
return compass_changed_func;
default:
g_assert_not_reached ();
}
}
static void
free_orientation_data (SensorData *data)
{
guint i;
if (data == NULL)
return;
if (data->name_id != 0) {
g_bus_unown_name (data->name_id);
data->name_id = 0;
}
for (i = 0; i < NUM_SENSOR_TYPES; i++) {
if (driver_type_exists (data, i))
driver_close (DRIVER_FOR_TYPE(i));
g_clear_object (&DEVICE_FOR_TYPE(i));
g_clear_pointer (&data->clients[i], g_hash_table_unref);
}
g_clear_pointer (&data->introspection_data, g_dbus_node_info_unref);
g_clear_object (&data->connection);
g_clear_pointer (&data->loop, g_main_loop_unref);
g_free (data);
}
static void
sensor_changes (GUdevClient *client,
gchar *action,
GUdevDevice *device,
SensorData *data)
{
guint i;
if (g_strcmp0 (action, "remove") == 0) {
for (i = 0; i < NUM_SENSOR_TYPES; i++) {
GUdevDevice *dev = DEVICE_FOR_TYPE(i);
if (!dev)
continue;
if (g_strcmp0 (g_udev_device_get_sysfs_path (device), g_udev_device_get_sysfs_path (dev)) == 0) {
g_debug ("Sensor type %s got removed (%s)",
driver_type_to_str (i),
g_udev_device_get_sysfs_path (dev));
g_clear_object (&DEVICE_FOR_TYPE(i));
DRIVER_FOR_TYPE(i) = NULL;
g_clear_pointer (&data->clients[i], g_hash_table_unref);
data->clients[i] = create_clients_hash_table ();
send_driver_changed_dbus_event (data, i);
}
}
if (!any_sensors_left (data))
g_main_loop_quit (data->loop);
} else if (g_strcmp0 (action, "add") == 0) {
guint i;
for (i = 0; i < G_N_ELEMENTS(drivers); i++) {
SensorDriver *driver = (SensorDriver *) drivers[i];
if (!driver_type_exists (data, driver->type) &&
driver_discover (driver, device)) {
g_debug ("Found hotplugged device %s of type %s at %s",
g_udev_device_get_sysfs_path (device),
driver_type_to_str (driver->type),
driver->name);
if (driver_open (driver, device,
driver_type_to_callback_func (driver->type), data)) {
GHashTable *ht;
DEVICE_FOR_TYPE(driver->type) = g_object_ref (device);
DRIVER_FOR_TYPE(driver->type) = (SensorDriver *) driver;
send_driver_changed_dbus_event (data, driver->type);
ht = data->clients[driver->type];
if (g_hash_table_size (ht) > 0)
driver_set_polling (DRIVER_FOR_TYPE(driver->type), TRUE);
}
break;
}
}
}
}
int main (int argc, char **argv)
{
SensorData *data;
GUdevClient *client;
int ret = 0;
const gchar * const subsystems[] = { "iio", "input", "platform", NULL };
guint i;
/* g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); */
data = g_new0 (SensorData, 1);
data->previous_orientation = ORIENTATION_UNDEFINED;
data->uses_lux = TRUE;
/* Set up D-Bus */
setup_dbus (data);
client = g_udev_client_new (subsystems);
if (!find_sensors (client, data)) {
g_debug ("Could not find any supported sensors");
return 0;
}
g_signal_connect (G_OBJECT (client), "uevent",
G_CALLBACK (sensor_changes), data);
for (i = 0; i < NUM_SENSOR_TYPES; i++) {
data->clients[i] = create_clients_hash_table ();
if (!driver_type_exists (data, i))
continue;
if (!driver_open (DRIVER_FOR_TYPE(i), DEVICE_FOR_TYPE(i),
driver_type_to_callback_func (data->drivers[i]->type), data)) {
DRIVER_FOR_TYPE(i) = NULL;
g_clear_object (&DEVICE_FOR_TYPE(i));
}
}
if (!any_sensors_left (data))
goto out;
data->init_done = TRUE;
if (data->connection) {
send_dbus_event (data, PROP_ALL);
send_dbus_event (data, PROP_ALL_COMPASS);
}
data->loop = g_main_loop_new (NULL, TRUE);
g_main_loop_run (data->loop);
out:
free_orientation_data (data);
return ret;
}
iio-sensor-proxy-1.1/src/iio-sensor-proxy.gresource.xml 0000664 0000000 0000000 00000000306 12554165724 0023407 0 ustar 00root root 0000000 0000000
net.hadess.SensorProxy.xml
iio-sensor-proxy-1.1/src/monitor-sensor.c 0000664 0000000 0000000 00000010251 12554165724 0020564 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2015 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
*/
#include
static GMainLoop *loop;
static guint watch_id;
static GDBusProxy *iio_proxy, *iio_proxy_compass;
static void
properties_changed (GDBusProxy *proxy,
GVariant *changed_properties,
GStrv invalidated_properties,
gpointer user_data)
{
GVariant *v;
GVariantDict dict;
g_variant_dict_init (&dict, changed_properties);
if (g_variant_dict_contains (&dict, "HasAccelerometer")) {
v = g_dbus_proxy_get_cached_property (iio_proxy, "HasAccelerometer");
g_message ("Accelerometer %s", g_variant_get_boolean (v) ? "appeared" : "disappeared");
g_variant_unref (v);
}
if (g_variant_dict_contains (&dict, "AccelerometerOrientation")) {
v = g_dbus_proxy_get_cached_property (iio_proxy, "AccelerometerOrientation");
g_message ("Accelerometer orientation changed: %s", g_variant_get_string (v, NULL));
g_variant_unref (v);
}
if (g_variant_dict_contains (&dict, "HasAmbientLight")) {
v = g_dbus_proxy_get_cached_property (iio_proxy, "HasAmbientLight");
g_message ("Light sensor %s", g_variant_get_boolean (v) ? "appeared" : "disappeared");
g_variant_unref (v);
}
if (g_variant_dict_contains (&dict, "LightLevel")) {
GVariant *unit;
v = g_dbus_proxy_get_cached_property (iio_proxy, "LightLevel");
unit = g_dbus_proxy_get_cached_property (iio_proxy, "LightLevelUnit");
g_message ("Light changed: %lf (%s)", g_variant_get_double (v), g_variant_get_string (unit, NULL));
g_variant_unref (v);
g_variant_unref (unit);
}
if (g_variant_dict_contains (&dict, "HasCompass")) {
v = g_dbus_proxy_get_cached_property (iio_proxy_compass, "HasCompass");
g_message ("Compass %s", g_variant_get_boolean (v) ? "appeared" : "disappeared");
g_variant_unref (v);
}
if (g_variant_dict_contains (&dict, "CompassHeading")) {
v = g_dbus_proxy_get_cached_property (iio_proxy_compass, "CompassHeading");
g_message ("Compass heading changed: %lf", g_variant_get_double (v));
g_variant_unref (v);
}
}
static void
appeared_cb (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
GError *error = NULL;
iio_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"net.hadess.SensorProxy",
"/net/hadess/SensorProxy",
"net.hadess.SensorProxy",
NULL, NULL);
g_signal_connect (G_OBJECT (iio_proxy), "g-properties-changed",
G_CALLBACK (properties_changed), NULL);
if (g_strcmp0 (g_get_user_name (), "geoclue") == 0) {
iio_proxy_compass = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"net.hadess.SensorProxy",
"/net/hadess/SensorProxy/Compass",
"net.hadess.SensorProxy.Compass",
NULL, NULL);
g_signal_connect (G_OBJECT (iio_proxy_compass), "g-properties-changed",
G_CALLBACK (properties_changed), NULL);
}
/* Accelerometer */
g_dbus_proxy_call_sync (iio_proxy,
"ClaimAccelerometer",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
g_assert_no_error (error);
/* ALS */
g_dbus_proxy_call_sync (iio_proxy,
"ClaimLight",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
g_assert_no_error (error);
/* Compass */
if (g_strcmp0 (g_get_user_name (), "geoclue") == 0) {
g_dbus_proxy_call_sync (iio_proxy_compass,
"ClaimCompass",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
g_assert_no_error (error);
}
}
static void
vanished_cb (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_clear_object (&iio_proxy);
g_clear_object (&iio_proxy_compass);
}
int main (int argc, char **argv)
{
watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
"net.hadess.SensorProxy",
G_BUS_NAME_WATCHER_FLAGS_NONE,
appeared_cb,
vanished_cb,
NULL, NULL);
loop = g_main_loop_new (NULL, TRUE);
g_main_loop_run (loop);
return 0;
}
iio-sensor-proxy-1.1/src/net.hadess.SensorProxy.xml 0000664 0000000 0000000 00000014176 12554165724 0022524 0 ustar 00root root 0000000 0000000
iio-sensor-proxy-1.1/src/orientation.c 0000664 0000000 0000000 00000005315 12554165724 0020126 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2011, 2014 Bastien Nocera
*
* orientation_calc() from the sensorfw package
* Copyright (C) 2009-2010 Nokia Corporation
* Authors:
* Üstün Ergenoglu
* Timo Rongas
* Lihan Guo
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
*/
#include
#include
#include
#include
#include "orientation.h"
static const char *orientations[] = {
"undefined",
"normal",
"bottom-up",
"left-up",
"right-up",
NULL
};
const char *
orientation_to_string (OrientationUp o)
{
return orientations[o];
}
OrientationUp
string_to_orientation (const char *orientation)
{
int i;
if (orientation == NULL)
return ORIENTATION_UNDEFINED;
for (i = 0; orientations[i] != NULL; i++) {
if (g_str_equal (orientation, orientations[i]))
return i;
}
return ORIENTATION_UNDEFINED;
}
#define RADIANS_TO_DEGREES 180.0/M_PI
#define SAME_AXIS_LIMIT 5
#define THRESHOLD_LANDSCAPE 35
#define THRESHOLD_PORTRAIT 35
OrientationUp
orientation_calc (OrientationUp prev,
int x, int y, int z)
{
int rotation;
OrientationUp ret = prev;
/* Portrait check */
rotation = round(atan((double) x / sqrt(y * y + z * z)) * RADIANS_TO_DEGREES);
if (abs(rotation) > THRESHOLD_PORTRAIT) {
ret = (rotation < 0) ? ORIENTATION_LEFT_UP : ORIENTATION_RIGHT_UP;
/* Some threshold to switching between portrait modes */
if (prev == ORIENTATION_LEFT_UP || prev == ORIENTATION_RIGHT_UP) {
if (abs(rotation) < SAME_AXIS_LIMIT) {
ret = prev;
}
}
} else {
/* Landscape check */
rotation = round(atan((double) y / sqrt(x * x + z * z)) * RADIANS_TO_DEGREES);
if (abs(rotation) > THRESHOLD_LANDSCAPE) {
ret = (rotation < 0) ? ORIENTATION_BOTTOM_UP : ORIENTATION_NORMAL;
/* Some threshold to switching between landscape modes */
if (prev == ORIENTATION_BOTTOM_UP || prev == ORIENTATION_NORMAL) {
if (abs(rotation) < SAME_AXIS_LIMIT) {
ret = prev;
}
}
}
}
return ret;
}
iio-sensor-proxy-1.1/src/orientation.h 0000664 0000000 0000000 00000001747 12554165724 0020140 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2011, 2014 Bastien Nocera
*
* orientation_calc() from the sensorfw package
* Copyright (C) 2009-2010 Nokia Corporation
* Authors:
* Üstün Ergenoglu
* Timo Rongas
* Lihan Guo
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
*/
typedef enum {
ORIENTATION_UNDEFINED,
ORIENTATION_NORMAL,
ORIENTATION_BOTTOM_UP,
ORIENTATION_LEFT_UP,
ORIENTATION_RIGHT_UP
} OrientationUp;
#define ORIENTATION_UP_UP ORIENTATION_NORMAL
const char *orientation_to_string (OrientationUp o);
OrientationUp string_to_orientation (const char *orientation);
OrientationUp orientation_calc (OrientationUp prev,
int x,
int y,
int z);
iio-sensor-proxy-1.1/src/test-orientation.c 0000664 0000000 0000000 00000003263 12554165724 0021103 0 ustar 00root root 0000000 0000000 // gcc -o test-orientation test-orientation.c orientation.c `pkg-config --libs --cflags gtk+-3.0` -lm
#include
#include "orientation.h"
static GtkWidget *scale_x, *scale_y, *scale_z;
static GtkWidget *label;
#define ONEG 256
static void
value_changed (GtkSpinButton *spin_button,
gpointer user_data)
{
int x, y, z;
OrientationUp o;
x = gtk_spin_button_get_value (GTK_SPIN_BUTTON (scale_x));
y = gtk_spin_button_get_value (GTK_SPIN_BUTTON (scale_y));
z = gtk_spin_button_get_value (GTK_SPIN_BUTTON (scale_z));
o = orientation_calc (ORIENTATION_UNDEFINED, x, y, z);
gtk_label_set_text (GTK_LABEL (label), orientation_to_string (o));
}
int main (int argc, char **argv)
{
GtkWidget *window;
GtkWidget *box;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
scale_x = gtk_spin_button_new_with_range (-ONEG, ONEG, 1);
scale_y = gtk_spin_button_new_with_range (-ONEG, ONEG, 1);
scale_z = gtk_spin_button_new_with_range (-ONEG, ONEG, 1);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_container_add (GTK_CONTAINER (box), scale_x);
gtk_container_add (GTK_CONTAINER (box), scale_y);
gtk_container_add (GTK_CONTAINER (box), scale_z);
g_signal_connect (G_OBJECT (scale_x), "value-changed",
G_CALLBACK (value_changed), NULL);
g_signal_connect (G_OBJECT (scale_y), "value-changed",
G_CALLBACK (value_changed), NULL);
g_signal_connect (G_OBJECT (scale_y), "value-changed",
G_CALLBACK (value_changed), NULL);
label = gtk_label_new ("");
gtk_container_add (GTK_CONTAINER (box), label);
value_changed (NULL, NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
iio-sensor-proxy-1.1/src/uinput.h 0000664 0000000 0000000 00000043733 12554165724 0017132 0 ustar 00root root 0000000 0000000 /*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2003-2010 Marcel Holtmann
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __UINPUT_H
#define __UINPUT_H
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
#include
/* Events */
#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
/* Synchronization events */
#define SYN_REPORT 0
#define SYN_CONFIG 1
/*
* Keys and buttons
*
* Most of the keys/buttons are modelled after USB HUT 1.12
* (see http://www.usb.org/developers/hidpage).
* Abbreviations in the comments:
* AC - Application Control
* AL - Application Launch Button
* SC - System Control
*/
#define KEY_RESERVED 0
#define KEY_ESC 1
#define KEY_1 2
#define KEY_2 3
#define KEY_3 4
#define KEY_4 5
#define KEY_5 6
#define KEY_6 7
#define KEY_7 8
#define KEY_8 9
#define KEY_9 10
#define KEY_0 11
#define KEY_MINUS 12
#define KEY_EQUAL 13
#define KEY_BACKSPACE 14
#define KEY_TAB 15
#define KEY_Q 16
#define KEY_W 17
#define KEY_E 18
#define KEY_R 19
#define KEY_T 20
#define KEY_Y 21
#define KEY_U 22
#define KEY_I 23
#define KEY_O 24
#define KEY_P 25
#define KEY_LEFTBRACE 26
#define KEY_RIGHTBRACE 27
#define KEY_ENTER 28
#define KEY_LEFTCTRL 29
#define KEY_A 30
#define KEY_S 31
#define KEY_D 32
#define KEY_F 33
#define KEY_G 34
#define KEY_H 35
#define KEY_J 36
#define KEY_K 37
#define KEY_L 38
#define KEY_SEMICOLON 39
#define KEY_APOSTROPHE 40
#define KEY_GRAVE 41
#define KEY_LEFTSHIFT 42
#define KEY_BACKSLASH 43
#define KEY_Z 44
#define KEY_X 45
#define KEY_C 46
#define KEY_V 47
#define KEY_B 48
#define KEY_N 49
#define KEY_M 50
#define KEY_COMMA 51
#define KEY_DOT 52
#define KEY_SLASH 53
#define KEY_RIGHTSHIFT 54
#define KEY_KPASTERISK 55
#define KEY_LEFTALT 56
#define KEY_SPACE 57
#define KEY_CAPSLOCK 58
#define KEY_F1 59
#define KEY_F2 60
#define KEY_F3 61
#define KEY_F4 62
#define KEY_F5 63
#define KEY_F6 64
#define KEY_F7 65
#define KEY_F8 66
#define KEY_F9 67
#define KEY_F10 68
#define KEY_NUMLOCK 69
#define KEY_SCROLLLOCK 70
#define KEY_KP7 71
#define KEY_KP8 72
#define KEY_KP9 73
#define KEY_KPMINUS 74
#define KEY_KP4 75
#define KEY_KP5 76
#define KEY_KP6 77
#define KEY_KPPLUS 78
#define KEY_KP1 79
#define KEY_KP2 80
#define KEY_KP3 81
#define KEY_KP0 82
#define KEY_KPDOT 83
#define KEY_ZENKAKUHANKAKU 85
#define KEY_102ND 86
#define KEY_F11 87
#define KEY_F12 88
#define KEY_RO 89
#define KEY_KATAKANA 90
#define KEY_HIRAGANA 91
#define KEY_HENKAN 92
#define KEY_KATAKANAHIRAGANA 93
#define KEY_MUHENKAN 94
#define KEY_KPJPCOMMA 95
#define KEY_KPENTER 96
#define KEY_RIGHTCTRL 97
#define KEY_KPSLASH 98
#define KEY_SYSRQ 99
#define KEY_RIGHTALT 100
#define KEY_LINEFEED 101
#define KEY_HOME 102
#define KEY_UP 103
#define KEY_PAGEUP 104
#define KEY_LEFT 105
#define KEY_RIGHT 106
#define KEY_END 107
#define KEY_DOWN 108
#define KEY_PAGEDOWN 109
#define KEY_INSERT 110
#define KEY_DELETE 111
#define KEY_MACRO 112
#define KEY_MUTE 113
#define KEY_VOLUMEDOWN 114
#define KEY_VOLUMEUP 115
#define KEY_POWER 116 /* SC System Power Down */
#define KEY_KPEQUAL 117
#define KEY_KPPLUSMINUS 118
#define KEY_PAUSE 119
#define KEY_KPCOMMA 121
#define KEY_HANGEUL 122
#define KEY_HANGUEL KEY_HANGEUL
#define KEY_HANJA 123
#define KEY_YEN 124
#define KEY_LEFTMETA 125
#define KEY_RIGHTMETA 126
#define KEY_COMPOSE 127
#define KEY_STOP 128 /* AC Stop */
#define KEY_AGAIN 129
#define KEY_PROPS 130 /* AC Properties */
#define KEY_UNDO 131 /* AC Undo */
#define KEY_FRONT 132
#define KEY_COPY 133 /* AC Copy */
#define KEY_OPEN 134 /* AC Open */
#define KEY_PASTE 135 /* AC Paste */
#define KEY_FIND 136 /* AC Search */
#define KEY_CUT 137 /* AC Cut */
#define KEY_HELP 138 /* AL Integrated Help Center */
#define KEY_MENU 139 /* Menu (show menu) */
#define KEY_CALC 140 /* AL Calculator */
#define KEY_SETUP 141
#define KEY_SLEEP 142 /* SC System Sleep */
#define KEY_WAKEUP 143 /* System Wake Up */
#define KEY_FILE 144 /* AL Local Machine Browser */
#define KEY_SENDFILE 145
#define KEY_DELETEFILE 146
#define KEY_XFER 147
#define KEY_PROG1 148
#define KEY_PROG2 149
#define KEY_WWW 150 /* AL Internet Browser */
#define KEY_MSDOS 151
#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */
#define KEY_SCREENLOCK KEY_COFFEE
#define KEY_DIRECTION 153
#define KEY_CYCLEWINDOWS 154
#define KEY_MAIL 155
#define KEY_BOOKMARKS 156 /* AC Bookmarks */
#define KEY_COMPUTER 157
#define KEY_BACK 158 /* AC Back */
#define KEY_FORWARD 159 /* AC Forward */
#define KEY_CLOSECD 160
#define KEY_EJECTCD 161
#define KEY_EJECTCLOSECD 162
#define KEY_NEXTSONG 163
#define KEY_PLAYPAUSE 164
#define KEY_PREVIOUSSONG 165
#define KEY_STOPCD 166
#define KEY_RECORD 167
#define KEY_REWIND 168
#define KEY_PHONE 169 /* Media Select Telephone */
#define KEY_ISO 170
#define KEY_CONFIG 171 /* AL Consumer Control Configuration */
#define KEY_HOMEPAGE 172 /* AC Home */
#define KEY_REFRESH 173 /* AC Refresh */
#define KEY_EXIT 174 /* AC Exit */
#define KEY_MOVE 175
#define KEY_EDIT 176
#define KEY_SCROLLUP 177
#define KEY_SCROLLDOWN 178
#define KEY_KPLEFTPAREN 179
#define KEY_KPRIGHTPAREN 180
#define KEY_NEW 181 /* AC New */
#define KEY_REDO 182 /* AC Redo/Repeat */
#define KEY_F13 183
#define KEY_F14 184
#define KEY_F15 185
#define KEY_F16 186
#define KEY_F17 187
#define KEY_F18 188
#define KEY_F19 189
#define KEY_F20 190
#define KEY_F21 191
#define KEY_F22 192
#define KEY_F23 193
#define KEY_F24 194
#define KEY_PLAYCD 200
#define KEY_PAUSECD 201
#define KEY_PROG3 202
#define KEY_PROG4 203
#define KEY_SUSPEND 205
#define KEY_CLOSE 206 /* AC Close */
#define KEY_PLAY 207
#define KEY_FASTFORWARD 208
#define KEY_BASSBOOST 209
#define KEY_PRINT 210 /* AC Print */
#define KEY_HP 211
#define KEY_CAMERA 212
#define KEY_SOUND 213
#define KEY_QUESTION 214
#define KEY_EMAIL 215
#define KEY_CHAT 216
#define KEY_SEARCH 217
#define KEY_CONNECT 218
#define KEY_FINANCE 219 /* AL Checkbook/Finance */
#define KEY_SPORT 220
#define KEY_SHOP 221
#define KEY_ALTERASE 222
#define KEY_CANCEL 223 /* AC Cancel */
#define KEY_BRIGHTNESSDOWN 224
#define KEY_BRIGHTNESSUP 225
#define KEY_MEDIA 226
#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video
outputs (Monitor/LCD/TV-out/etc) */
#define KEY_KBDILLUMTOGGLE 228
#define KEY_KBDILLUMDOWN 229
#define KEY_KBDILLUMUP 230
#define KEY_SEND 231 /* AC Send */
#define KEY_REPLY 232 /* AC Reply */
#define KEY_FORWARDMAIL 233 /* AC Forward Msg */
#define KEY_SAVE 234 /* AC Save */
#define KEY_DOCUMENTS 235
#define KEY_BATTERY 236
#define KEY_BLUETOOTH 237
#define KEY_WLAN 238
#define KEY_UWB 239
#define KEY_UNKNOWN 240
#define KEY_VIDEO_NEXT 241 /* drive next video source */
#define KEY_VIDEO_PREV 242 /* drive previous video source */
#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */
#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */
#define KEY_DISPLAY_OFF 245 /* display device to off state */
#define KEY_WIMAX 246
/* Range 248 - 255 is reserved for special needs of AT keyboard driver */
#define BTN_MISC 0x100
#define BTN_0 0x100
#define BTN_1 0x101
#define BTN_2 0x102
#define BTN_3 0x103
#define BTN_4 0x104
#define BTN_5 0x105
#define BTN_6 0x106
#define BTN_7 0x107
#define BTN_8 0x108
#define BTN_9 0x109
#define BTN_MOUSE 0x110
#define BTN_LEFT 0x110
#define BTN_RIGHT 0x111
#define BTN_MIDDLE 0x112
#define BTN_SIDE 0x113
#define BTN_EXTRA 0x114
#define BTN_FORWARD 0x115
#define BTN_BACK 0x116
#define BTN_TASK 0x117
#define BTN_JOYSTICK 0x120
#define BTN_TRIGGER 0x120
#define BTN_THUMB 0x121
#define BTN_THUMB2 0x122
#define BTN_TOP 0x123
#define BTN_TOP2 0x124
#define BTN_PINKIE 0x125
#define BTN_BASE 0x126
#define BTN_BASE2 0x127
#define BTN_BASE3 0x128
#define BTN_BASE4 0x129
#define BTN_BASE5 0x12a
#define BTN_BASE6 0x12b
#define BTN_DEAD 0x12f
#define BTN_GAMEPAD 0x130
#define BTN_A 0x130
#define BTN_B 0x131
#define BTN_C 0x132
#define BTN_X 0x133
#define BTN_Y 0x134
#define BTN_Z 0x135
#define BTN_TL 0x136
#define BTN_TR 0x137
#define BTN_TL2 0x138
#define BTN_TR2 0x139
#define BTN_SELECT 0x13a
#define BTN_START 0x13b
#define BTN_MODE 0x13c
#define BTN_THUMBL 0x13d
#define BTN_THUMBR 0x13e
#define BTN_DIGI 0x140
#define BTN_TOOL_PEN 0x140
#define BTN_TOOL_RUBBER 0x141
#define BTN_TOOL_BRUSH 0x142
#define BTN_TOOL_PENCIL 0x143
#define BTN_TOOL_AIRBRUSH 0x144
#define BTN_TOOL_FINGER 0x145
#define BTN_TOOL_MOUSE 0x146
#define BTN_TOOL_LENS 0x147
#define BTN_TOUCH 0x14a
#define BTN_STYLUS 0x14b
#define BTN_STYLUS2 0x14c
#define BTN_TOOL_DOUBLETAP 0x14d
#define BTN_TOOL_TRIPLETAP 0x14e
#define BTN_WHEEL 0x150
#define BTN_GEAR_DOWN 0x150
#define BTN_GEAR_UP 0x151
#define KEY_OK 0x160
#define KEY_SELECT 0x161
#define KEY_GOTO 0x162
#define KEY_CLEAR 0x163
#define KEY_POWER2 0x164
#define KEY_OPTION 0x165
#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */
#define KEY_TIME 0x167
#define KEY_VENDOR 0x168
#define KEY_ARCHIVE 0x169
#define KEY_PROGRAM 0x16a /* Media Select Program Guide */
#define KEY_CHANNEL 0x16b
#define KEY_FAVORITES 0x16c
#define KEY_EPG 0x16d
#define KEY_PVR 0x16e /* Media Select Home */
#define KEY_MHP 0x16f
#define KEY_LANGUAGE 0x170
#define KEY_TITLE 0x171
#define KEY_SUBTITLE 0x172
#define KEY_ANGLE 0x173
#define KEY_ZOOM 0x174
#define KEY_MODE 0x175
#define KEY_KEYBOARD 0x176
#define KEY_SCREEN 0x177
#define KEY_PC 0x178 /* Media Select Computer */
#define KEY_TV 0x179 /* Media Select TV */
#define KEY_TV2 0x17a /* Media Select Cable */
#define KEY_VCR 0x17b /* Media Select VCR */
#define KEY_VCR2 0x17c /* VCR Plus */
#define KEY_SAT 0x17d /* Media Select Satellite */
#define KEY_SAT2 0x17e
#define KEY_CD 0x17f /* Media Select CD */
#define KEY_TAPE 0x180 /* Media Select Tape */
#define KEY_RADIO 0x181
#define KEY_TUNER 0x182 /* Media Select Tuner */
#define KEY_PLAYER 0x183
#define KEY_TEXT 0x184
#define KEY_DVD 0x185 /* Media Select DVD */
#define KEY_AUX 0x186
#define KEY_MP3 0x187
#define KEY_AUDIO 0x188
#define KEY_VIDEO 0x189
#define KEY_DIRECTORY 0x18a
#define KEY_LIST 0x18b
#define KEY_MEMO 0x18c /* Media Select Messages */
#define KEY_CALENDAR 0x18d
#define KEY_RED 0x18e
#define KEY_GREEN 0x18f
#define KEY_YELLOW 0x190
#define KEY_BLUE 0x191
#define KEY_CHANNELUP 0x192 /* Channel Increment */
#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */
#define KEY_FIRST 0x194
#define KEY_LAST 0x195 /* Recall Last */
#define KEY_AB 0x196
#define KEY_NEXT 0x197
#define KEY_RESTART 0x198
#define KEY_SLOW 0x199
#define KEY_SHUFFLE 0x19a
#define KEY_BREAK 0x19b
#define KEY_PREVIOUS 0x19c
#define KEY_DIGITS 0x19d
#define KEY_TEEN 0x19e
#define KEY_TWEN 0x19f
#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */
#define KEY_GAMES 0x1a1 /* Media Select Games */
#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */
#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */
#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */
#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */
#define KEY_EDITOR 0x1a6 /* AL Text Editor */
#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */
#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */
#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */
#define KEY_DATABASE 0x1aa /* AL Database App */
#define KEY_NEWS 0x1ab /* AL Newsreader */
#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */
#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */
#define KEY_LOGOFF 0x1b1 /* AL Logoff */
#define KEY_DOLLAR 0x1b2
#define KEY_EURO 0x1b3
#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */
#define KEY_FRAMEFORWARD 0x1b5
#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */
#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */
#define KEY_DEL_EOL 0x1c0
#define KEY_DEL_EOS 0x1c1
#define KEY_INS_LINE 0x1c2
#define KEY_DEL_LINE 0x1c3
#define KEY_FN 0x1d0
#define KEY_FN_ESC 0x1d1
#define KEY_FN_F1 0x1d2
#define KEY_FN_F2 0x1d3
#define KEY_FN_F3 0x1d4
#define KEY_FN_F4 0x1d5
#define KEY_FN_F5 0x1d6
#define KEY_FN_F6 0x1d7
#define KEY_FN_F7 0x1d8
#define KEY_FN_F8 0x1d9
#define KEY_FN_F9 0x1da
#define KEY_FN_F10 0x1db
#define KEY_FN_F11 0x1dc
#define KEY_FN_F12 0x1dd
#define KEY_FN_1 0x1de
#define KEY_FN_2 0x1df
#define KEY_FN_D 0x1e0
#define KEY_FN_E 0x1e1
#define KEY_FN_F 0x1e2
#define KEY_FN_S 0x1e3
#define KEY_FN_B 0x1e4
#define KEY_BRL_DOT1 0x1f1
#define KEY_BRL_DOT2 0x1f2
#define KEY_BRL_DOT3 0x1f3
#define KEY_BRL_DOT4 0x1f4
#define KEY_BRL_DOT5 0x1f5
#define KEY_BRL_DOT6 0x1f6
#define KEY_BRL_DOT7 0x1f7
#define KEY_BRL_DOT8 0x1f8
#define KEY_BRL_DOT9 0x1f9
#define KEY_BRL_DOT10 0x1fa
/* We avoid low common keys in module aliases so they don't get huge. */
#define KEY_MIN_INTERESTING KEY_MUTE
#define KEY_MAX 0x1ff
#define KEY_CNT (KEY_MAX+1)
/*
* Relative axes
*/
#define REL_X 0x00
#define REL_Y 0x01
#define REL_Z 0x02
#define REL_RX 0x03
#define REL_RY 0x04
#define REL_RZ 0x05
#define REL_HWHEEL 0x06
#define REL_DIAL 0x07
#define REL_WHEEL 0x08
#define REL_MISC 0x09
#define REL_MAX 0x0f
#define REL_CNT (REL_MAX+1)
/*
* Absolute axes
*/
#define ABS_X 0x00
#define ABS_Y 0x01
#define ABS_Z 0x02
#define ABS_RX 0x03
#define ABS_RY 0x04
#define ABS_RZ 0x05
#define ABS_THROTTLE 0x06
#define ABS_RUDDER 0x07
#define ABS_WHEEL 0x08
#define ABS_GAS 0x09
#define ABS_BRAKE 0x0a
#define ABS_HAT0X 0x10
#define ABS_HAT0Y 0x11
#define ABS_HAT1X 0x12
#define ABS_HAT1Y 0x13
#define ABS_HAT2X 0x14
#define ABS_HAT2Y 0x15
#define ABS_HAT3X 0x16
#define ABS_HAT3Y 0x17
#define ABS_PRESSURE 0x18
#define ABS_DISTANCE 0x19
#define ABS_TILT_X 0x1a
#define ABS_TILT_Y 0x1b
#define ABS_TOOL_WIDTH 0x1c
#define ABS_VOLUME 0x20
#define ABS_MISC 0x28
#define ABS_MAX 0x3f
#define ABS_CNT (ABS_MAX+1)
/*
* Switch events
*/
#define SW_LID 0x00 /* set = lid shut */
#define SW_TABLET_MODE 0x01 /* set = tablet mode */
#define SW_HEADPHONE_INSERT 0x02 /* set = inserted */
#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any"
set = radio enabled */
#define SW_RADIO SW_RFKILL_ALL /* deprecated */
#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */
#define SW_DOCK 0x05 /* set = plugged into dock */
#define SW_MAX 0x0f
#define SW_CNT (SW_MAX+1)
/*
* Misc events
*/
#define MSC_SERIAL 0x00
#define MSC_PULSELED 0x01
#define MSC_GESTURE 0x02
#define MSC_RAW 0x03
#define MSC_SCAN 0x04
#define MSC_MAX 0x07
#define MSC_CNT (MSC_MAX+1)
/*
* LEDs
*/
#define LED_NUML 0x00
#define LED_CAPSL 0x01
#define LED_SCROLLL 0x02
#define LED_COMPOSE 0x03
#define LED_KANA 0x04
#define LED_SLEEP 0x05
#define LED_SUSPEND 0x06
#define LED_MUTE 0x07
#define LED_MISC 0x08
#define LED_MAIL 0x09
#define LED_CHARGING 0x0a
#define LED_MAX 0x0f
#define LED_CNT (LED_MAX+1)
/*
* Autorepeat values
*/
#define REP_DELAY 0x00
#define REP_PERIOD 0x01
#define REP_MAX 0x01
/*
* Sounds
*/
#define SND_CLICK 0x00
#define SND_BELL 0x01
#define SND_TONE 0x02
#define SND_MAX 0x07
#define SND_CNT (SND_MAX+1)
/*
* IDs.
*/
#define ID_BUS 0
#define ID_VENDOR 1
#define ID_PRODUCT 2
#define ID_VERSION 3
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
#define BUS_VIRTUAL 0x06
#define BUS_ISA 0x10
#define BUS_I8042 0x11
#define BUS_XTKBD 0x12
#define BUS_RS232 0x13
#define BUS_GAMEPORT 0x14
#define BUS_PARPORT 0x15
#define BUS_AMIGA 0x16
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
#define BUS_ATARI 0x1B
/* User input interface */
#define UINPUT_IOCTL_BASE 'U'
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
#ifndef NBITS
#define NBITS(x) ((((x) - 1) / (sizeof(long) * 8)) + 1)
#endif
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_id {
uint16_t bustype;
uint16_t vendor;
uint16_t product;
uint16_t version;
};
struct uinput_dev {
char name[UINPUT_MAX_NAME_SIZE];
struct uinput_id id;
int ff_effects_max;
int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
};
struct uinput_event {
struct timeval time;
uint16_t type;
uint16_t code;
int32_t value;
};
#ifdef __cplusplus
}
#endif
#endif /* __UINPUT_H */