File iio-sensor-proxy-base35.patch of Package iio-sensor-proxy
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 6330a0a..b806823 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,6 +16,7 @@ variables:
python3-gobject
python3-dbusmock
python3-psutil
+ python3-packaging
umockdev
workflow:
@@ -27,8 +28,9 @@ build_stable:
before_script:
# Undo delangification present in the Fedora Docker images
- rm -f /etc/rpm/macros.image-language-conf
- - dnf update -y && dnf install -y $DEPENDENCIES
- - dnf reinstall -y glib2
+ - if [ -x /bin/dnf ]; then dnf update -y; else dnf5 update -y; fi
+ - if [ -x /bin/dnf ]; then dnf install -y $DEPENDENCIES; else dnf5 install -y $DEPENDENCIES; fi
+ - if [ -x /bin/dnf ]; then dnf reinstall -y glib2; else dnf5 reinstall -y glib2; fi
script:
- meson -Dtests=true -Dgtk_doc=true -Dgtk-tests=true _build
- ninja -v -C _build
@@ -36,9 +38,22 @@ build_stable:
- ninja -v -C _build uninstall
- ninja -v -C _build dist
- meson test -C _build
+ - ninja -C _build/ iio-sensor-proxy-doc
artifacts:
when: always
- name: "iio-sensor-proxy-${CI_COMMIT_REF_NAME}"
paths:
- "${CI_PROJECT_DIR}/_build/meson-logs"
- "${CI_PROJECT_DIR}/_build/meson-dist"
+ - "${CI_PROJECT_DIR}/_build/docs/html/"
+
+pages:
+ needs:
+ - build_stable
+ script:
+ - find _build/docs/html/
+ - mv _build/docs/html public
+ artifacts:
+ paths:
+ - public
+ only:
+ - master
diff --git a/data/80-iio-sensor-proxy.rules b/data/80-iio-sensor-proxy.rules
index 85d93f9..3b8a149 100644
--- a/data/80-iio-sensor-proxy.rules
+++ b/data/80-iio-sensor-proxy.rules
@@ -10,6 +10,7 @@ SUBSYSTEM=="iio", TEST=="scan_elements/in_accel_x_en", TEST=="scan_elements/in_a
SUBSYSTEM=="iio", TEST=="scan_elements/in_rot_from_north_magnetic_tilt_comp_en", ENV{IIO_SENSOR_PROXY_TYPE}+="iio-buffer-compass"
SUBSYSTEM=="iio", TEST=="in_illuminance_input", ENV{IIO_SENSOR_PROXY_TYPE}+="iio-poll-als"
SUBSYSTEM=="iio", TEST=="in_illuminance0_input", ENV{IIO_SENSOR_PROXY_TYPE}+="iio-poll-als"
+SUBSYSTEM=="iio", TEST=="in_illuminance_clear_raw", ENV{IIO_SENSOR_PROXY_TYPE}+="iio-poll-als"
SUBSYSTEM=="iio", TEST=="in_illuminance_raw", ENV{IIO_SENSOR_PROXY_TYPE}+="iio-poll-als"
SUBSYSTEM=="iio", TEST=="in_intensity_clear_raw", ENV{IIO_SENSOR_PROXY_TYPE}+="iio-poll-als"
SUBSYSTEM=="iio", TEST=="scan_elements/in_intensity_both_en", ENV{IIO_SENSOR_PROXY_TYPE}+="iio-buffer-als"
diff --git a/src/drivers.h b/src/drivers.h
index b760faa..910b2dc 100644
--- a/src/drivers.h
+++ b/src/drivers.h
@@ -6,6 +6,8 @@
* the Free Software Foundation.
*/
+#pragma once
+
#include <glib.h>
#include <gudev/gudev.h>
@@ -17,6 +19,7 @@ typedef enum {
DRIVER_TYPE_LIGHT,
DRIVER_TYPE_COMPASS,
DRIVER_TYPE_PROXIMITY,
+ DRIVER_TYPE_HINGE_ANGLE,
} DriverType;
typedef enum {
@@ -51,11 +54,23 @@ typedef void (*ReadingsUpdateFunc) (SensorDevice *sensor_device,
gpointer readings,
gpointer user_data);
+typedef enum {
+ TABLET_MODE_LAPTOP,
+ TABLET_MODE_TABLET,
+ TABLET_MODE_UNKNOWN,
+} TabletMode;
+
+typedef struct {
+ gdouble angle;
+} HingeAngleReadings;
typedef struct {
const char *driver_name;
DriverType type;
+ gboolean (*get_property) (SensorDevice *device,
+ const char *property,
+ GValue *value);
gboolean (*discover) (GUdevDevice *device);
SensorDevice * (*open) (GUdevDevice *device);
void (*set_polling) (SensorDevice *device,
@@ -65,8 +80,10 @@ typedef struct {
struct SensorDevice {
SensorDriver *drv;
+ GUdevDevice *udev_device;
gpointer priv;
char *name;
+ AccelLocation location;
/* Callback function and data as pass to driver_open() */
ReadingsUpdateFunc callback_func;
@@ -77,25 +94,11 @@ static inline gboolean
driver_discover (SensorDriver *driver,
GUdevDevice *device)
{
- AccelLocation location;
-
g_return_val_if_fail (driver, FALSE);
g_return_val_if_fail (driver->discover, FALSE);
g_return_val_if_fail (device, FALSE);
- if (!driver->discover (device))
- return FALSE;
-
- if (driver->type != DRIVER_TYPE_ACCEL)
- return TRUE;
-
- location = setup_accel_location (device);
- if (location == ACCEL_LOCATION_DISPLAY)
- return TRUE;
-
- g_debug ("Ignoring accelerometer in location '%s'",
- accel_location_to_string (location));
- return FALSE;
+ return driver->discover (device);
}
static inline SensorDevice *
@@ -115,8 +118,15 @@ driver_open (SensorDriver *driver,
if (!sensor_device)
return NULL;
sensor_device->drv = driver;
+ sensor_device->udev_device = g_object_ref (device);
sensor_device->callback_func = callback_func;
sensor_device->user_data = user_data;
+
+ if (driver->type == DRIVER_TYPE_ACCEL)
+ sensor_device->location = setup_accel_location (device);
+ else
+ sensor_device->location = ACCEL_LOCATION_DISPLAY;
+
return sensor_device;
}
@@ -144,11 +154,27 @@ driver_close (SensorDevice *sensor_device)
g_return_if_fail (sensor_device);
driver_set_polling (sensor_device, FALSE);
g_clear_pointer (&sensor_device->name, g_free);
+ g_clear_object (&sensor_device->udev_device);
driver = sensor_device->drv;
g_return_if_fail (driver->close);
driver->close (sensor_device);
}
+static inline gboolean
+driver_get_property (SensorDevice *sensor_device,
+ const char *property,
+ GValue *value)
+{
+ SensorDriver *driver;
+
+ g_return_val_if_fail (sensor_device, FALSE);
+ driver = sensor_device->drv;
+ g_return_val_if_fail (driver, FALSE);
+ g_return_val_if_fail (driver->get_property, FALSE);
+
+ return driver->get_property (sensor_device, property, value);
+}
+
extern SensorDriver iio_buffer_accel;
extern SensorDriver iio_poll_accel;
extern SensorDriver input_accel;
diff --git a/src/drv-iio-buffer-accel.c b/src/drv-iio-buffer-accel.c
index afa898c..311c840 100644
--- a/src/drv-iio-buffer-accel.c
+++ b/src/drv-iio-buffer-accel.c
@@ -198,6 +198,22 @@ iio_buffer_accel_set_polling (SensorDevice *sensor_device,
}
}
+static gboolean
+iio_buffer_accel_get_property (SensorDevice *sensor_device,
+ const char *property,
+ GValue *value)
+{
+ DrvData *drv_data = (DrvData *) sensor_device->priv;
+
+ if (g_strcmp0 (property, "location") == 0) {
+ g_value_init (value, G_TYPE_ENUM);
+ g_value_set_enum (value, drv_data->location);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static SensorDevice *
iio_buffer_accel_open (GUdevDevice *device)
{
@@ -247,6 +263,7 @@ SensorDriver iio_buffer_accel = {
.driver_name = "IIO Buffer accelerometer",
.type = DRIVER_TYPE_ACCEL,
+ .get_property = iio_buffer_accel_get_property,
.discover = iio_buffer_accel_discover,
.open = iio_buffer_accel_open,
.set_polling = iio_buffer_accel_set_polling,
diff --git a/src/drv-iio-poll-accel.c b/src/drv-iio-poll-accel.c
index e8f43f4..0fbced3 100644
--- a/src/drv-iio-poll-accel.c
+++ b/src/drv-iio-poll-accel.c
@@ -94,6 +94,22 @@ iio_poll_accel_set_polling (SensorDevice *sensor_device,
}
}
+static gboolean
+iio_poll_accel_get_property (SensorDevice *sensor_device,
+ const char *property,
+ GValue *value)
+{
+ DrvData *drv_data = (DrvData *) sensor_device->priv;
+
+ if (g_strcmp0 (property, "location") == 0) {
+ g_value_init (value, G_TYPE_ENUM);
+ g_value_set_enum (value, drv_data->location);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static SensorDevice *
iio_poll_accel_open (GUdevDevice *device)
{
@@ -133,6 +149,7 @@ SensorDriver iio_poll_accel = {
.driver_name = "IIO Poll accelerometer",
.type = DRIVER_TYPE_ACCEL,
+ .get_property = iio_poll_accel_get_property,
.discover = iio_poll_accel_discover,
.open = iio_poll_accel_open,
.set_polling = iio_poll_accel_set_polling,
diff --git a/src/drv-iio-poll-light.c b/src/drv-iio-poll-light.c
index f65a7ca..ea88a79 100644
--- a/src/drv-iio-poll-light.c
+++ b/src/drv-iio-poll-light.c
@@ -71,6 +71,7 @@ get_illuminance_channel_path (GUdevDevice *device,
const char *channels[] = {
"in_illuminance",
"in_illuminance0",
+ "in_illuminance_clear",
"in_intensity_clear"
};
char *path = NULL;
diff --git a/src/drv-input-accel.c b/src/drv-input-accel.c
index 48f0973..7a1ddcb 100644
--- a/src/drv-input-accel.c
+++ b/src/drv-input-accel.c
@@ -190,6 +190,23 @@ first_values (gpointer user_data)
return G_SOURCE_REMOVE;
}
+static gboolean
+input_accel_get_property (SensorDevice *sensor_device,
+ const char *property,
+ GValue *value)
+{
+ DrvData *drv_data = (DrvData *) sensor_device->priv;
+
+ if (g_strcmp0 (property, "location") == 0) {
+ g_value_init (value, G_TYPE_ENUM);
+ g_value_set_enum (value, drv_data->location);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
static SensorDevice *
input_accel_open (GUdevDevice *device)
{
@@ -273,6 +290,7 @@ SensorDriver input_accel = {
.driver_name = "Input accelerometer",
.type = DRIVER_TYPE_ACCEL,
+ .get_property = input_accel_get_property,
.discover = input_accel_discover,
.open = input_accel_open,
.set_polling = input_accel_set_polling,
diff --git a/src/iio-buffer-utils.c b/src/iio-buffer-utils.c
index 597e550..d0939d3 100644
--- a/src/iio-buffer-utils.c
+++ b/src/iio-buffer-utils.c
@@ -356,27 +356,38 @@ _write_sysfs_int (const char *filename,
int ret = 0;
g_autoptr(FILE) sysfsfp = NULL;
int test;
- char *temp;
+ g_autofree char *temp = NULL;
+
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;
+ return -errno;
}
+
+ setvbuf(sysfsfp, NULL, _IONBF, 0);
+
if (type)
- fprintf(sysfsfp, "%d %d", val, val2);
+ ret = fprintf(sysfsfp, "%d %d", val, val2);
else
- fprintf(sysfsfp, "%d", val);
+ ret = fprintf(sysfsfp, "%d", val);
+
g_clear_pointer (&sysfsfp, fclose);
+ if (ret < 0) {
+ g_warning ("Could not write to '%s': %s", temp, g_strerror(-ret));
+ return ret;
+ }
+
+ ret = 0;
+
if (verify) {
sysfsfp = fopen(temp, "r");
if (sysfsfp == NULL) {
g_warning ("Could not open for read '%s'", temp);
- ret = -errno;
- goto error_free;
+ return -errno;
}
+
if (fscanf(sysfsfp, "%d", &test) != 1 ||
test != val) {
g_warning ("Possible failure in int write %d to %s",
@@ -384,8 +395,7 @@ _write_sysfs_int (const char *filename,
ret = -1;
}
}
-error_free:
- g_free (temp);
+
return ret;
}
@@ -673,6 +683,9 @@ enable_sensors (GUdevDevice *dev,
gboolean ret = FALSE;
g_autoptr(GError) error = NULL;
+ g_debug ("%s sensors for device '%s'", enable ? "Enabling" : "Disabling",
+ g_udev_device_get_sysfs_path (dev));
+
device_dir = g_build_filename (g_udev_device_get_sysfs_path (dev), "scan_elements", NULL);
dir = g_dir_open (device_dir, 0, &error);
if (!dir) {
@@ -689,7 +702,7 @@ enable_sensors (GUdevDevice *dev,
/* Already enabled? */
path = g_strdup_printf ("scan_elements/%s", name);
- if (g_udev_device_get_sysfs_attr_as_boolean (dev, path)) {
+ if (enable && g_udev_device_get_sysfs_attr_as_boolean (dev, path)) {
g_debug ("Already enabled sensor %s/%s", device_dir, name);
ret = TRUE;
g_free (path);
@@ -699,18 +712,21 @@ enable_sensors (GUdevDevice *dev,
/* Enable */
if (write_sysfs_int (name, device_dir, enable) < 0) {
- g_warning ("Could not enable sensor %s/%s", device_dir, name);
+ g_warning ("Could not write %d to %s/%s",
+ enable, device_dir, name);
continue;
}
ret = TRUE;
- g_debug ("Enabled sensor %s/%s", device_dir, name);
+ g_debug ("%s sensor %s/%s", enable ? "Enabled" : "Disabled",
+ device_dir, name);
}
g_dir_close (dir);
g_free (device_dir);
if (!ret) {
- g_warning ("Failed to enable any sensors for device '%s'",
+ g_warning ("Failed to %s any sensors for device '%s'",
+ enable ? "enable" : "disable",
g_udev_device_get_sysfs_path (dev));
}
@@ -785,13 +801,14 @@ buffer_drv_data_free (BufferDrvData *buffer_data)
if (buffer_data == NULL)
return;
- enable_sensors (buffer_data->device, 0);
- g_clear_object (&buffer_data->device);
-
+ /* A buffer should be disabled before scan elements to avoid a
+ * "Device or resource busy" error */
disable_ring_buffer (buffer_data);
-
g_free (buffer_data->trigger_name);
+ enable_sensors (buffer_data->device, 0);
+ g_clear_object (&buffer_data->device);
+
for (i = 0; i < buffer_data->channels_count; i++)
channel_info_free (buffer_data->channels[i]);
g_free (buffer_data->channels);
diff --git a/src/iio-sensor-proxy.c b/src/iio-sensor-proxy.c
index 836e742..8810e78 100644
--- a/src/iio-sensor-proxy.c
+++ b/src/iio-sensor-proxy.c
@@ -16,7 +16,10 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <math.h>
+#include <linux/uinput.h>
+#include <glib-unix.h>
#include <gio/gio.h>
#include <gudev/gudev.h>
#include <polkit/polkit.h>
@@ -31,7 +34,11 @@
#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_PROXIMITY + 1
+#define NUM_SENSOR_TYPES DRIVER_TYPE_HINGE_ANGLE + 1
+
+
+#define device_type(dev) (dev->drv->type)
+
typedef struct {
GMainLoop *loop;
@@ -39,17 +46,16 @@ typedef struct {
GDBusNodeInfo *introspection_data;
GDBusConnection *connection;
guint name_id;
+ int uinput_fd;
int ret;
PolkitAuthority *auth;
-
- SensorDriver *drivers[NUM_SENSOR_TYPES];
- SensorDevice *devices[NUM_SENSOR_TYPES];
- GUdevDevice *udev_devices[NUM_SENSOR_TYPES];
+ GPtrArray *devices[NUM_SENSOR_TYPES]; /* SensorDevice */
GHashTable *clients[NUM_SENSOR_TYPES]; /* key = D-Bus name, value = watch ID */
/* Accelerometer */
OrientationUp previous_orientation;
+ AccelReadings last_accel_readings[2]; /* For display and base locations */
/* Light */
gdouble previous_level;
@@ -60,6 +66,9 @@ typedef struct {
/* Proximity */
gboolean previous_prox_near;
+
+ gdouble previous_hinge_angle;
+ TabletMode previous_tablet_mode;
} SensorData;
static const SensorDriver * const drivers[] = {
@@ -89,25 +98,114 @@ driver_type_to_str (DriverType type)
return "compass";
case DRIVER_TYPE_PROXIMITY:
return "proximity";
+ case DRIVER_TYPE_HINGE_ANGLE:
+ return "hinge angle";
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]
-#define UDEV_DEVICE_FOR_TYPE(driver_type) data->udev_devices[driver_type]
+static const char *
+tablet_mode_to_str (TabletMode mode)
+{
+ switch (mode) {
+ case TABLET_MODE_LAPTOP:
+ return "laptop";
+ case TABLET_MODE_TABLET:
+ return "tablet";
+ default:
+ return "unknown";
+ }
+}
static void sensor_changes (GUdevClient *client,
gchar *action,
GUdevDevice *device,
SensorData *data);
+/* Return the default device used for given sensor type */
+static SensorDevice *
+find_default_device_for_type (SensorData *data,
+ DriverType driver_type)
+{
+ SensorDevice *sensor_device = NULL;
+
+ /* For accelerometers, use the display accelerometer and ignore base accelerometers */
+ if (driver_type == DRIVER_TYPE_ACCEL) {
+ GValue location_prop = G_VALUE_INIT;
+ guint i;
+
+ for (i = 0; i < data->devices[driver_type]->len; i++) {
+ SensorDevice *sd = g_ptr_array_index (data->devices[driver_type], i);
+ AccelLocation location = ACCEL_LOCATION_DISPLAY;
+
+ if (driver_get_property (sd, "location", &location_prop)) {
+ location = g_value_get_enum (&location_prop);
+ g_value_unset (&location_prop);
+ }
+
+ if (location == ACCEL_LOCATION_DISPLAY) {
+ sensor_device = sd;
+ break;
+ }
+ }
+ } else {
+ /* For other sensors, prefer the first one */
+ sensor_device = data->devices[driver_type]->len ? g_ptr_array_index (data->devices[driver_type], 0) : NULL;
+ }
+
+ g_debug ("Default device for %s: %s",
+ driver_type_to_str (driver_type),
+ sensor_device ? sensor_device->name : "none");
+
+ return sensor_device;
+}
+
+static SensorDevice *
+find_accel_at (SensorData *data, AccelLocation location)
+{
+ guint i;
+
+ for (i = 0; i < data->devices[DRIVER_TYPE_ACCEL]->len; i++) {
+ SensorDevice *sensor_device =
+ g_ptr_array_index (data->devices[DRIVER_TYPE_ACCEL], i);
+
+ if (sensor_device->location == location)
+ return sensor_device;
+ }
+ return NULL;
+}
+
static gboolean
driver_type_exists (SensorData *data,
DriverType driver_type)
{
- return (DRIVER_FOR_TYPE(driver_type) != NULL);
+ return find_default_device_for_type (data, driver_type) != NULL;
+}
+
+static gboolean is_default_device (SensorData *data,
+ SensorDevice *sensor_device)
+{
+ SensorDevice *default_device;
+
+ default_device = find_default_device_for_type (data, device_type (sensor_device));
+
+ return default_device == sensor_device;
+}
+
+static gboolean
+has_hinge_angle_sensor (SensorData *data)
+{
+ SensorDevice *display_accel, *base_accel;
+
+ if (driver_type_exists (data, DRIVER_TYPE_HINGE_ANGLE)) {
+ return TRUE;
+ }
+
+ display_accel = find_accel_at (data, ACCEL_LOCATION_DISPLAY);
+ base_accel = find_accel_at (data, ACCEL_LOCATION_BASE);
+
+ return display_accel && base_accel;
}
static gboolean
@@ -130,24 +228,28 @@ find_sensors (GUdevClient *client,
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)) {
+ SensorDevice *sensor_device;
+
+ if (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->driver_name);
- UDEV_DEVICE_FOR_TYPE(driver->type) = g_object_ref (dev);
- DRIVER_FOR_TYPE(driver->type) = (SensorDriver *) driver;
+
+
+ sensor_device = driver_open (driver, dev,
+ driver_type_to_callback_func (driver->type), data);
+ if (!sensor_device) {
+ g_clear_object (&dev);
+ continue;
+ }
+
+ g_ptr_array_add (data->devices[driver->type], sensor_device);
found = TRUE;
+ break;
}
}
-
- if (driver_type_exists (data, DRIVER_TYPE_ACCEL) &&
- driver_type_exists (data, DRIVER_TYPE_LIGHT) &&
- driver_type_exists (data, DRIVER_TYPE_PROXIMITY) &&
- driver_type_exists (data, DRIVER_TYPE_COMPASS))
- break;
}
g_list_free_full (devices, g_object_unref);
@@ -180,6 +282,9 @@ typedef enum {
PROP_COMPASS_HEADING = 1 << 5,
PROP_HAS_PROXIMITY = 1 << 6,
PROP_PROXIMITY_NEAR = 1 << 7,
+ PROP_HAS_HINGE_ANGLE = 1 << 8,
+ PROP_HINGE_ANGLE = 1 << 9,
+ PROP_TABLET_MODE = 1 << 10,
} PropertiesMask;
#define PROP_ALL (PROP_HAS_ACCELEROMETER | \
@@ -187,9 +292,17 @@ typedef enum {
PROP_HAS_AMBIENT_LIGHT | \
PROP_LIGHT_LEVEL | \
PROP_HAS_PROXIMITY | \
- PROP_PROXIMITY_NEAR)
+ PROP_PROXIMITY_NEAR | \
+ PROP_HAS_HINGE_ANGLE | \
+ PROP_HINGE_ANGLE | \
+ PROP_TABLET_MODE)
#define PROP_ALL_COMPASS (PROP_HAS_COMPASS | \
PROP_COMPASS_HEADING)
+#define PROP_ALL_HAS (PROP_HAS_ACCELEROMETER | \
+ PROP_HAS_AMBIENT_LIGHT | \
+ PROP_HAS_PROXIMITY | \
+ PROP_HAS_COMPASS | \
+ PROP_HAS_HINGE_ANGLE)
static PropertiesMask
mask_for_sensor_type (DriverType sensor_type)
@@ -207,6 +320,10 @@ mask_for_sensor_type (DriverType sensor_type)
case DRIVER_TYPE_PROXIMITY:
return PROP_HAS_PROXIMITY |
PROP_PROXIMITY_NEAR;
+ case DRIVER_TYPE_HINGE_ANGLE:
+ return PROP_HAS_HINGE_ANGLE |
+ PROP_HINGE_ANGLE |
+ PROP_TABLET_MODE;
default:
g_assert_not_reached ();
}
@@ -296,6 +413,48 @@ send_dbus_event_for_client (SensorData *data,
g_variant_new_boolean (data->previous_prox_near));
}
+ if (mask & PROP_HAS_HINGE_ANGLE) {
+ gboolean has_hinge_angle;
+
+ has_hinge_angle = driver_type_exists (data, DRIVER_TYPE_HINGE_ANGLE);
+
+ if (!has_hinge_angle) {
+ gboolean has_display_accel = FALSE, has_base_accel = FALSE;
+ guint i;
+
+ for (i = 0; i < data->devices[DRIVER_TYPE_ACCEL]->len; i++) {
+ SensorDevice *sensor_device =
+ g_ptr_array_index (data->devices[DRIVER_TYPE_ACCEL], i);
+
+ if (sensor_device->location == ACCEL_LOCATION_DISPLAY)
+ has_display_accel = TRUE;
+
+ if (sensor_device->location == ACCEL_LOCATION_BASE)
+ has_base_accel = TRUE;
+ }
+
+ has_hinge_angle = has_display_accel && has_base_accel;
+ }
+
+ g_variant_builder_add (&props_builder, "{sv}", "HasHingeAngle",
+ g_variant_new_boolean (has_hinge_angle));
+
+ /* Send hinge angle information when the device appears */
+ if (has_hinge_angle)
+ mask |= PROP_HINGE_ANGLE | PROP_TABLET_MODE;
+ }
+
+ if (mask & PROP_HINGE_ANGLE) {
+ g_variant_builder_add (&props_builder, "{sv}", "HingeAngle",
+ g_variant_new_double (data->previous_hinge_angle));
+ }
+
+ if (mask & PROP_TABLET_MODE) {
+ g_variant_builder_add (&props_builder, "{sv}", "TabletMode",
+ g_variant_new_string (tablet_mode_to_str (data->previous_tablet_mode)));
+
+ }
+
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));
@@ -355,6 +514,8 @@ send_driver_changed_dbus_event (SensorData *data,
send_dbus_event (data, PROP_HAS_AMBIENT_LIGHT);
else if (driver_type == DRIVER_TYPE_PROXIMITY)
send_dbus_event (data, PROP_HAS_PROXIMITY);
+ else if (driver_type == DRIVER_TYPE_HINGE_ANGLE)
+ send_dbus_event (data, PROP_HAS_HINGE_ANGLE);
else if (driver_type == DRIVER_TYPE_COMPASS)
send_dbus_event (data, PROP_HAS_COMPASS);
else
@@ -364,26 +525,153 @@ send_driver_changed_dbus_event (SensorData *data,
static gboolean
any_sensors_left (SensorData *data)
{
- guint i;
- gboolean exists = FALSE;
+ int i;
- for (i = 0; i < NUM_SENSOR_TYPES; i++) {
- if (driver_type_exists (data, i)) {
- exists = TRUE;
- break;
- }
+ for (i = 0; i < NUM_SENSOR_TYPES; i++)
+ if (data->devices[i]->len > 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+setup_uinput_dev (SensorData *data)
+{
+ struct uinput_setup usetup;
+ int fd;
+ int r;
+
+ fd = open ("/dev/uinput", O_RDWR);
+ if (fd < 0) {
+ g_warning ("Could not open uinput for tablet mode notification: %s",
+ strerror (errno));
+ return FALSE;
}
- return exists;
+ r = ioctl(fd, UI_SET_EVBIT, EV_SW);
+ if (r < 0)
+ goto error;
+
+ r = ioctl(fd, UI_SET_SWBIT, SW_TABLET_MODE);
+ if (r < 0)
+ goto error;
+
+
+ memset (&usetup, 0, sizeof(usetup));
+ snprintf(usetup.name, sizeof(usetup.name), "iio-sensor-proxy");
+ usetup.id.bustype = BUS_VIRTUAL;
+ usetup.id.vendor = 0x00;
+ usetup.id.product = 0x00;
+
+ r = ioctl(fd, UI_DEV_SETUP, &usetup);
+ if (r < 0)
+ goto error;
+
+ r = ioctl(fd, UI_DEV_CREATE);
+ if (r < 0)
+ goto error;
+
+ data->uinput_fd = fd;
+
+ return TRUE;
+
+error:
+ g_warning ("Uinput device setup error: %s", strerror(errno));
+ close (fd);
+
+ return FALSE;
+}
+
+static void
+close_uinput_dev (SensorData *data)
+{
+ if (data->uinput_fd == -1)
+ return;
+
+ ioctl(data->uinput_fd, UI_DEV_DESTROY);
+ close (data->uinput_fd);
+
+ data->uinput_fd = -1;
}
static void
-client_release (SensorData *data,
- const char *sender,
- DriverType driver_type)
+emit_uinput_event (SensorData *data, int type, int code, int val)
+{
+ struct input_event ev;
+
+ g_debug ("Emitting uinput event: %d %d %d", type, code, val);
+
+ if (data->uinput_fd == -1) {
+ g_warning ("Cannot emit uinput event: device is not initialized");
+ return;
+ }
+
+ ev.type = type;
+ ev.code = code;
+ ev.value = val;
+
+ ev.time.tv_sec = 0;
+ ev.time.tv_usec = 0;
+
+ write (data->uinput_fd, &ev, sizeof(ev));
+}
+
+static void
+virt_hinge_angle_sensor_start (SensorData *data)
+{
+ SensorDevice *display_accel, *base_accel;
+ GHashTable *ht;
+
+ display_accel = find_accel_at (data, ACCEL_LOCATION_DISPLAY);
+ base_accel = find_accel_at (data, ACCEL_LOCATION_BASE);
+
+ if (!display_accel || !base_accel) {
+ return;
+ }
+
+ ht = data->clients[DRIVER_TYPE_ACCEL];
+
+ /* If the virtual hinge angle sensor is claimed but no accelerometer
+ * were claimed before, start polling for default (display) accelerometer */
+ if (g_hash_table_size (ht) == 0) {
+ driver_set_polling (display_accel, TRUE);
+ }
+
+ driver_set_polling (base_accel, TRUE);
+}
+
+static void
+virt_hinge_angle_sensor_stop (SensorData *data)
+{
+ SensorDevice *display_accel, *base_accel;
+ GHashTable *ht;
+
+ display_accel = find_accel_at (data, ACCEL_LOCATION_DISPLAY);
+ base_accel = find_accel_at (data, ACCEL_LOCATION_BASE);
+
+ if (!display_accel || !base_accel) {
+ return;
+ }
+
+ ht = data->clients[DRIVER_TYPE_ACCEL];
+
+ /* If the virtual hinge angle sensor was claimed but no accelerometer
+ * were claimed before, stop polling for default (display) accelerometer */
+ if (g_hash_table_size (ht) == 0) {
+ driver_set_polling (display_accel, FALSE);
+ }
+
+ driver_set_polling (base_accel, FALSE);
+}
+
+static void
+client_release (SensorData *data,
+ const char *sender,
+ DriverType driver_type)
{
GHashTable *ht;
guint watch_id;
+ SensorDevice *sensor_device;
ht = data->clients[driver_type];
@@ -395,11 +683,17 @@ client_release (SensorData *data,
g_hash_table_remove (ht, sender);
- if (driver_type_exists (data, driver_type) &&
- g_hash_table_size (ht) == 0) {
- SensorDevice *sensor_device = DEVICE_FOR_TYPE(driver_type);
- driver_set_polling (sensor_device, FALSE);
+ sensor_device = find_default_device_for_type (data, driver_type);
+ if (g_hash_table_size (ht) == 0) {
+ if (sensor_device) {
+ driver_set_polling (sensor_device, FALSE);
+ } else {
+ if (driver_type == DRIVER_TYPE_HINGE_ANGLE) {
+ virt_hinge_angle_sensor_stop (data);
+ }
+ }
}
+
}
static void
@@ -471,10 +765,13 @@ handle_generic_method_call (SensorData *data,
{
GHashTable *ht;
guint watch_id;
+ SensorDevice *sensor_device;
g_debug ("Handling driver refcounting method '%s' for %s device",
method_name, driver_type_to_str (driver_type));
+ sensor_device = find_default_device_for_type (data, driver_type);
+
ht = data->clients[driver_type];
if (g_str_has_prefix (method_name, "Claim")) {
@@ -486,12 +783,17 @@ handle_generic_method_call (SensorData *data,
}
/* No other clients for this sensor? Start it */
- if (driver_type_exists (data, driver_type) &&
- g_hash_table_size (ht) == 0) {
- SensorDevice *sensor_device = DEVICE_FOR_TYPE(driver_type);
- driver_set_polling (sensor_device, TRUE);
+ if (g_hash_table_size (ht) == 0) {
+ if (sensor_device) {
+ driver_set_polling (sensor_device, TRUE);
+ } else {
+ if (driver_type == DRIVER_TYPE_HINGE_ANGLE) {
+ virt_hinge_angle_sensor_start (data);
+ }
+ }
}
+
watch_id = g_bus_watch_name_on_connection (data->connection,
sender,
G_BUS_NAME_WATCHER_FLAGS_NONE,
@@ -531,6 +833,9 @@ handle_method_call (GDBusConnection *connection,
else if (g_strcmp0 (method_name, "ClaimProximity") == 0 ||
g_strcmp0 (method_name, "ReleaseProximity") == 0)
driver_type = DRIVER_TYPE_PROXIMITY;
+ else if (g_strcmp0 (method_name, "ClaimHingeAngle") == 0 ||
+ g_strcmp0 (method_name, "ReleaseHingeAngle") == 0)
+ driver_type = DRIVER_TYPE_HINGE_ANGLE;
else {
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
@@ -577,6 +882,12 @@ handle_get_property (GDBusConnection *connection,
return g_variant_new_boolean (driver_type_exists (data, DRIVER_TYPE_PROXIMITY));
if (g_strcmp0 (property_name, "ProximityNear") == 0)
return g_variant_new_boolean (data->previous_prox_near);
+ if (g_strcmp0 (property_name, "HasHingeAngle") == 0)
+ return g_variant_new_boolean (has_hinge_angle_sensor (data));
+ if (g_strcmp0 (property_name, "HingeAngle") == 0)
+ return g_variant_new_double (data->previous_hinge_angle);
+ if (g_strcmp0 (property_name, "TabletMode") == 0)
+ return g_variant_new_string (tablet_mode_to_str (data->previous_tablet_mode));
return NULL;
}
@@ -629,7 +940,7 @@ handle_compass_get_property (GDBusConnection *connection,
g_assert (data->connection);
if (g_strcmp0 (property_name, "HasCompass") == 0)
- return g_variant_new_boolean (data->drivers[DRIVER_TYPE_COMPASS] != NULL);
+ return g_variant_new_boolean (driver_type_exists (data, DRIVER_TYPE_COMPASS));
if (g_strcmp0 (property_name, "CompassHeading") == 0)
return g_variant_new_double (data->previous_heading);
@@ -695,27 +1006,9 @@ name_acquired_handler (GDBusConnection *connection,
G_CALLBACK (sensor_changes), data);
for (i = 0; i < NUM_SENSOR_TYPES; i++) {
- SensorDevice *sensor_device;
-
data->clients[i] = create_clients_hash_table ();
-
- if (!driver_type_exists (data, i))
- continue;
-
- sensor_device = driver_open (DRIVER_FOR_TYPE(i), UDEV_DEVICE_FOR_TYPE(i),
- driver_type_to_callback_func (data->drivers[i]->type), data);
- if (!sensor_device) {
- DRIVER_FOR_TYPE(i) = NULL;
- g_clear_object (&UDEV_DEVICE_FOR_TYPE(i));
- continue;
- }
-
- DEVICE_FOR_TYPE(i) = sensor_device;
}
- if (!any_sensors_left (data))
- goto bail;
-
send_dbus_event (data, PROP_ALL);
send_dbus_event (data, PROP_ALL_COMPASS);
return;
@@ -756,6 +1049,189 @@ setup_dbus (SensorData *data,
return TRUE;
}
+static TabletMode
+calc_tablet_mode (gdouble hinge_angle)
+{
+ /* If hinge axle is vertical */
+ if (hinge_angle < 0)
+ return TABLET_MODE_UNKNOWN;
+
+ return hinge_angle < 190 ? TABLET_MODE_LAPTOP : TABLET_MODE_TABLET;
+}
+
+static void
+hinge_angle_changed_func (SensorDevice *sensor_device,
+ gpointer readings_data,
+ gpointer user_data)
+{
+ SensorData *data = user_data;
+ HingeAngleReadings *readings = (HingeAngleReadings *) readings_data;
+ TabletMode tablet_mode;
+ PropertiesMask mask = 0;
+
+ g_debug ("Hinge angle sent by driver: %f",
+ readings->angle);
+
+ if (data->previous_hinge_angle != readings->angle) {
+ gdouble tmp;
+
+ tmp = data->previous_hinge_angle;
+ data->previous_hinge_angle = readings->angle;
+
+ mask |= PROP_HINGE_ANGLE;
+ g_debug ("Emitting hinge angle changed: from %.1f to %.1f",
+ tmp, data->previous_hinge_angle);
+ }
+
+ //FIXME: Add hysteresis
+ tablet_mode = calc_tablet_mode (readings->angle);
+ if (data->previous_tablet_mode != tablet_mode) {
+ TabletMode tmp;
+
+ tmp = data->previous_tablet_mode;
+ data->previous_tablet_mode = tablet_mode;
+
+ mask |= PROP_TABLET_MODE;
+ g_debug ("Emitting tablet mode changed: from %s to %s",
+ tablet_mode_to_str (tmp),
+ tablet_mode_to_str (data->previous_tablet_mode));
+
+ emit_uinput_event (data, EV_SW, SW_TABLET_MODE,
+ tablet_mode == TABLET_MODE_TABLET);
+ emit_uinput_event (data, EV_SYN, SYN_REPORT, 0);
+ }
+
+ if (mask) {
+ send_dbus_event (data, mask);
+ }
+}
+
+//FIXME: Use D-Bus GLib API for this
+static gboolean
+lid_is_closed (void)
+{
+ int exit_code;
+
+ exit_code = system ("busctl get-property org.freedesktop.login1 /org/freedesktop/login1 "
+ "org.freedesktop.login1.Manager LidClosed | grep true");
+
+ return !exit_code;
+}
+
+static double
+calc_2d_angle(SensorData *data)
+{
+ double angle_disp = atan2 (data->last_accel_readings[ACCEL_LOCATION_DISPLAY].accel_z,
+ data->last_accel_readings[ACCEL_LOCATION_DISPLAY].accel_y) * 180 / M_PI;
+ double angle_base = atan2 (data->last_accel_readings[ACCEL_LOCATION_BASE].accel_z,
+ data->last_accel_readings[ACCEL_LOCATION_BASE].accel_y) * 180 / M_PI;
+
+ g_debug ("display angle: %.1f, base angle: %.1f", angle_disp, angle_base);
+
+ double hinge_angle = (angle_base - angle_disp);
+
+ if (hinge_angle < 0)
+ hinge_angle += 360;
+
+ hinge_angle = 360 - hinge_angle;
+
+ return hinge_angle;
+}
+
+static double
+calc_3d_angle(SensorData *data)
+{
+ double display_x, display_y, display_z;
+ double base_x, base_y, base_z;
+ double display_norm_x, display_norm_y, display_norm_z;
+ double base_norm_x, base_norm_y, base_norm_z;
+
+ display_x = data->last_accel_readings[ACCEL_LOCATION_DISPLAY].accel_x;
+ display_y = data->last_accel_readings[ACCEL_LOCATION_DISPLAY].accel_y;
+ display_z = data->last_accel_readings[ACCEL_LOCATION_DISPLAY].accel_z;
+ base_x = data->last_accel_readings[ACCEL_LOCATION_BASE].accel_x;
+ base_y = data->last_accel_readings[ACCEL_LOCATION_BASE].accel_y;
+ base_z = data->last_accel_readings[ACCEL_LOCATION_BASE].accel_z;
+
+ double display_length = sqrt (display_x * display_x +
+ display_y * display_y +
+ display_z * display_z);
+ double base_length = sqrt (base_x * base_x +
+ base_y * base_y +
+ base_z * base_z);
+
+ display_norm_x = display_x / display_length;
+ display_norm_y = display_y / display_length;
+ display_norm_z = display_z / display_length;
+
+ base_norm_x = base_x / base_length;
+ base_norm_y = base_y / base_length;
+ base_norm_z = base_z / base_length;
+
+ double hinge_angle = acos (display_norm_x * base_norm_x +
+ display_norm_y * base_norm_y +
+ display_norm_z * base_norm_z)
+ * 180 / M_PI;
+
+ double direction = (display_y * base_z) - (display_z * base_y);
+
+ if (direction > 0)
+ hinge_angle = 360 - hinge_angle;
+
+ return hinge_angle;
+}
+
+static void
+calc_accel_hinge_angle(SensorData *data)
+{
+ HingeAngleReadings hinge_angle_readings;
+ double axle_angle;
+ double hinge_angle, hinge_angle2d, hinge_angle3d;
+ AccelReadings r;
+
+ r = data->last_accel_readings[ACCEL_LOCATION_DISPLAY];
+
+ axle_angle = atan2 (sqrt ((double)r.accel_z * r.accel_z + (double)r.accel_y * r.accel_y), r.accel_x) * 180 / M_PI;
+
+ g_debug ("Hinge axle angle: %.1f degrees (x: %d, y: %d, z: %d)", axle_angle, r.accel_x, r.accel_y, r.accel_z);
+
+ /* We cannot calc hinge angle reliable if hinge axle is almost vertical */
+ if ((axle_angle < 25) || (axle_angle > 155)) {
+ g_debug ("Hinge axle is vertical, cannot calc bending angle");
+ return;
+ }
+
+ hinge_angle2d = calc_2d_angle (data);
+ hinge_angle3d = calc_3d_angle (data);
+
+ g_debug ("2d angle: %.1f", hinge_angle2d);
+ g_debug ("3d angle: %.1f", hinge_angle3d);
+
+ if (hinge_angle3d < 15)
+ hinge_angle = hinge_angle3d;
+ else
+ hinge_angle = hinge_angle2d;
+
+ gboolean lid_closed = lid_is_closed ();
+
+ /*
+ * Handle the corner case: tablet is closed or bended by 360 deg.
+ * the calculated hinge angle may be wrapped around 0/360 deg. here,
+ * check the lid state and normalize
+ */
+ if (lid_closed)
+ hinge_angle = 0;
+ else if (hinge_angle < 15)
+ hinge_angle = 360;
+
+ //FIXME: Add data validations to filter invalid values caused by vibration
+ g_debug ("Hinge angle is %.1f degrees", hinge_angle);
+
+ hinge_angle_readings.angle = hinge_angle;
+
+ hinge_angle_changed_func (NULL, &hinge_angle_readings, data);
+}
+
static void
accel_changed_func (SensorDevice *sensor_device,
gpointer readings_data,
@@ -766,24 +1242,45 @@ accel_changed_func (SensorDevice *sensor_device,
OrientationUp orientation;
//FIXME handle errors
- g_debug ("Accel sent by driver (quirk applied): %d, %d, %d (scale: %lf,%lf,%lf)",
+ g_debug ("Accel (%s) sent by driver (quirk applied): %d, %d, %d (scale: %lf,%lf,%lf)",
+ sensor_device->location == ACCEL_LOCATION_DISPLAY ? "display" : "base",
readings->accel_x, readings->accel_y, readings->accel_z,
readings->scale.x, readings->scale.y, readings->scale.z);
- orientation = orientation_calc (data->previous_orientation,
- readings->accel_x, readings->accel_y, readings->accel_z,
- readings->scale);
+ gboolean accel_hinge_case =
+ (sensor_device->location == ACCEL_LOCATION_BASE) &&
+ !driver_type_exists (data, DRIVER_TYPE_HINGE_ANGLE);
- if (data->previous_orientation != orientation) {
- OrientationUp tmp;
+ if (!is_default_device (data, sensor_device) && !accel_hinge_case) {
+ g_debug ("Skip parsing the readings: %s is not a default device",
+ sensor_device->name);
+ return;
+ }
+
+ memcpy (&data->last_accel_readings[sensor_device->location],
+ readings_data, sizeof (AccelReadings));
+
+ if (sensor_device->location == ACCEL_LOCATION_DISPLAY) {
+ orientation = orientation_calc (data->previous_orientation,
+ readings->accel_x, readings->accel_y, readings->accel_z,
+ readings->scale);
- 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));
+ 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));
+ }
}
+
+ /* Calculate hinge angle based on accelerometers readings if there is no
+ * dedicated hinge angle sensor exists */
+ if (accel_hinge_case)
+ calc_accel_hinge_angle (data);
}
static void
@@ -798,6 +1295,12 @@ light_changed_func (SensorDevice *sensor_device,
g_debug ("Light level sent by driver (quirk applied): %lf (unit: %s)",
readings->level, data->uses_lux ? "lux" : "vendor");
+ if (!is_default_device (data, sensor_device)) {
+ g_debug ("Skip parsing the readings: %s is not a default device",
+ sensor_device->name);
+ return;
+ }
+
if (data->previous_level != readings->level ||
data->uses_lux != readings->uses_lux) {
gdouble tmp;
@@ -825,6 +1328,12 @@ compass_changed_func (SensorDevice *sensor_device,
g_debug ("Heading sent by driver (quirk applied): %lf degrees",
readings->heading);
+ if (!is_default_device (data, sensor_device)) {
+ g_debug ("Skip parsing the readings: %s is not a default device",
+ sensor_device->name);
+ return;
+ }
+
if (data->previous_heading != readings->heading) {
gdouble tmp;
@@ -850,6 +1359,12 @@ proximity_changed_func (SensorDevice *sensor_device,
g_debug ("Proximity sent by driver: %d",
readings->is_near);
+ if (!is_default_device (data, sensor_device)) {
+ g_debug ("Skip parsing the readings: %s is not a default device",
+ sensor_device->name);
+ return;
+ }
+
near = readings->is_near > 0;
if (data->previous_prox_near != near) {
ProximityNear tmp;
@@ -875,15 +1390,41 @@ driver_type_to_callback_func (DriverType type)
return compass_changed_func;
case DRIVER_TYPE_PROXIMITY:
return proximity_changed_func;
+ case DRIVER_TYPE_HINGE_ANGLE:
+ return hinge_angle_changed_func;
default:
g_assert_not_reached ();
}
}
+static SensorData *
+allocate_sensor_data (void)
+{
+ SensorData *data;
+ guint i;
+
+ data = g_new0 (SensorData, 1);
+
+ for (i = 0; i < NUM_SENSOR_TYPES; i++) {
+ data->devices[i] = g_ptr_array_new ();
+ }
+
+ data->uinput_fd = -1;
+
+ data->previous_orientation = ORIENTATION_UNDEFINED;
+ data->previous_tablet_mode = TABLET_MODE_UNKNOWN;
+ data->uses_lux = TRUE;
+ data->previous_level = 0.0;
+ data->previous_heading = 0.0;
+ data->previous_prox_near = FALSE;
+
+ return data;
+}
+
static void
free_sensor_data (SensorData *data)
{
- guint i;
+ guint i, j;
if (data == NULL)
return;
@@ -893,11 +1434,17 @@ free_sensor_data (SensorData *data)
data->name_id = 0;
}
+ close_uinput_dev (data);
+
for (i = 0; i < NUM_SENSOR_TYPES; i++) {
- if (driver_type_exists (data, i))
- driver_close (DEVICE_FOR_TYPE(i));
- g_clear_object (&UDEV_DEVICE_FOR_TYPE(i));
g_clear_pointer (&data->clients[i], g_hash_table_unref);
+
+ for (j = 0; j < data->devices[i]->len; j++) {
+ SensorDevice *dev = g_ptr_array_index (data->devices[i], j);
+ driver_close (dev);
+ }
+
+ g_ptr_array_free (data->devices[i], TRUE);
}
g_clear_object (&data->auth);
@@ -914,33 +1461,41 @@ sensor_changes (GUdevClient *client,
GUdevDevice *device,
SensorData *data)
{
- guint i;
+ guint i, j;
g_debug ("Sensor changes: action = %s, device = %s",
action, g_udev_device_get_sysfs_path (device));
if (g_strcmp0 (action, "remove") == 0) {
+ gboolean found = FALSE;
for (i = 0; i < NUM_SENSOR_TYPES; i++) {
- GUdevDevice *dev = UDEV_DEVICE_FOR_TYPE(i);
+ for (j = 0; j < data->devices[i]->len; j++) {
+ SensorDevice *sensor_device = g_ptr_array_index (data->devices[i], j);
+ GUdevDevice *dev = sensor_device->udev_device;
- 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 (%p) got removed (%s)",
+ driver_type_to_str (i),
+ sensor_device,
+ g_udev_device_get_sysfs_path (dev));
- 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));
+ driver_close (sensor_device);
- g_clear_object (&UDEV_DEVICE_FOR_TYPE(i));
- driver_close (DEVICE_FOR_TYPE(i));
- DEVICE_FOR_TYPE(i) = NULL;
- DRIVER_FOR_TYPE(i) = NULL;
+ g_ptr_array_remove_index (data->devices[i], j);
- g_clear_pointer (&data->clients[i], g_hash_table_unref);
- data->clients[i] = create_clients_hash_table ();
+ if (!find_default_device_for_type (data, i)) {
+ g_clear_pointer (&data->clients[i], g_hash_table_unref);
+ data->clients[i] = create_clients_hash_table ();
+ }
- send_driver_changed_dbus_event (data, i);
+ send_driver_changed_dbus_event (data, i);
+ found = TRUE;
+ break;
+ }
}
+
+ if (found)
+ break;
}
if (!any_sensors_left (data))
@@ -948,10 +1503,9 @@ sensor_changes (GUdevClient *client,
} else if (g_strcmp0 (action, "add") == 0) {
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)) {
- SensorDevice *sensor_device = NULL;
+ if (driver_discover (driver, device)) {
+ SensorDevice *sensor_device = NULL;
g_debug ("Found hotplugged device %s of type %s at %s",
g_udev_device_get_sysfs_path (device),
driver_type_to_str (driver->type),
@@ -963,15 +1517,12 @@ sensor_changes (GUdevClient *client,
if (sensor_device) {
GHashTable *ht;
- UDEV_DEVICE_FOR_TYPE(driver->type) = g_object_ref (device);
- DEVICE_FOR_TYPE(driver->type) = sensor_device;
- DRIVER_FOR_TYPE(driver->type) = (SensorDriver *) driver;
+ g_ptr_array_add (data->devices[driver->type], sensor_device);
send_driver_changed_dbus_event (data, driver->type);
ht = data->clients[driver->type];
if (g_hash_table_size (ht) > 0) {
- SensorDevice *sensor_device = DEVICE_FOR_TYPE(driver->type);
driver_set_polling (sensor_device, TRUE);
}
}
@@ -981,6 +1532,17 @@ sensor_changes (GUdevClient *client,
}
}
+gboolean
+termination_signal_handler (gpointer user_data)
+{
+ SensorData *data = user_data;
+
+ g_debug ("Shutting down");
+ g_main_loop_quit (data->loop);
+
+ return G_SOURCE_REMOVE;
+}
+
int main (int argc, char **argv)
{
SensorData *data;
@@ -1013,15 +1575,19 @@ int main (int argc, char **argv)
g_debug ("Starting iio-sensor-proxy version "VERSION);
}
- data = g_new0 (SensorData, 1);
- data->previous_orientation = ORIENTATION_UNDEFINED;
- data->uses_lux = TRUE;
+ data = allocate_sensor_data ();
+
+ setup_uinput_dev (data);
/* Set up D-Bus */
setup_dbus (data, replace);
data->auth = polkit_authority_get_sync (NULL, NULL);
- data->loop = g_main_loop_new (NULL, TRUE);
+ data->loop = g_main_loop_new (NULL, FALSE);
+
+ g_unix_signal_add (SIGINT, (GSourceFunc) termination_signal_handler, data);
+ g_unix_signal_add (SIGTERM, (GSourceFunc) termination_signal_handler, data);
+
g_main_loop_run (data->loop);
ret = data->ret;
free_sensor_data (data);
diff --git a/src/monitor-sensor.c b/src/monitor-sensor.c
index ea3f9ec..11b5ba3 100644
--- a/src/monitor-sensor.c
+++ b/src/monitor-sensor.c
@@ -18,6 +18,7 @@ static gboolean watch_accel = FALSE;
static gboolean watch_prox = FALSE;
static gboolean watch_compass = FALSE;
static gboolean watch_light = FALSE;
+static gboolean watch_hinge_angle = FALSE;
static void
properties_changed (GDBusProxy *proxy,
@@ -68,6 +69,24 @@ properties_changed (GDBusProxy *proxy,
g_print ("--- Proximity sensor disappeared\n");
g_variant_unref (v);
}
+ if (g_variant_dict_contains (&dict, "HasHingeAngle")) {
+ v = g_dbus_proxy_get_cached_property (iio_proxy, "HasHingeAngle");
+ if (g_variant_get_boolean (v))
+ g_print ("+++ Hinge angle sensor appeared\n");
+ else
+ g_print ("--- Hinge angle sensor disappeared\n");
+ g_variant_unref (v);
+ }
+ if (g_variant_dict_contains (&dict, "HingeAngle")) {
+ v = g_dbus_proxy_get_cached_property (iio_proxy, "HingeAngle");
+ g_print (" Hinge angle changed: %.1f\n", g_variant_get_double (v));
+ g_variant_unref (v);
+ }
+ if (g_variant_dict_contains (&dict, "TabletMode")) {
+ v = g_dbus_proxy_get_cached_property (iio_proxy, "TabletMode");
+ g_print (" Tablet mode changed: %s\n", g_variant_get_string (v, NULL));
+ g_variant_unref (v);
+ }
if (g_variant_dict_contains (&dict, "ProximityNear")) {
v = g_dbus_proxy_get_cached_property (iio_proxy, "ProximityNear");
g_print (" Proximity value changed: %d\n", g_variant_get_boolean (v));
@@ -139,6 +158,19 @@ print_initial_values (void)
g_variant_unref (v);
}
+ if (watch_hinge_angle) {
+ v = g_dbus_proxy_get_cached_property (iio_proxy, "HasHingeAngle");
+ if (g_variant_get_boolean (v)) {
+ g_variant_unref (v);
+ v = g_dbus_proxy_get_cached_property (iio_proxy, "HingeAngle");
+ g_print ("=== Has hinge angle sensor (angle: %.1f)\n",
+ g_variant_get_double (v));
+ } else {
+ g_print ("=== No hinge angle sensor\n");
+ }
+ g_variant_unref (v);
+ }
+
if (!iio_proxy_compass)
return;
@@ -245,6 +277,23 @@ appeared_cb (GDBusConnection *connection,
g_clear_pointer (&ret, g_variant_unref);
}
+ /* Hinge angle sensor */
+ if (watch_hinge_angle) {
+ ret = g_dbus_proxy_call_sync (iio_proxy,
+ "ClaimHingeAngle",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, &error);
+ if (!ret) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Failed to claim hinge angle sensor: %s", error->message);
+ g_main_loop_quit (loop);
+ return;
+ }
+ g_clear_pointer (&ret, g_variant_unref);
+ }
+
/* Compass */
if (watch_compass) {
ret = g_dbus_proxy_call_sync (iio_proxy_compass,
@@ -285,6 +334,7 @@ int main (int argc, char **argv)
gboolean opt_watch_prox = FALSE;
gboolean opt_watch_compass = FALSE;
gboolean opt_watch_light = FALSE;
+ gboolean opt_watch_hinge_angle = FALSE;
gboolean opt_all = FALSE;
const GOptionEntry options[] = {
{ "all", 'a', 0, G_OPTION_ARG_NONE, &opt_all, "Monitor all the sensor changes", NULL },
@@ -292,6 +342,7 @@ int main (int argc, char **argv)
{ "proximity", 0, 0, G_OPTION_ARG_NONE, &opt_watch_prox, "Monitor proximity sensor changes", NULL },
{ "compass", 0, 0, G_OPTION_ARG_NONE, &opt_watch_compass, "Monitor compass changes", NULL },
{ "light", 0, 0, G_OPTION_ARG_NONE, &opt_watch_light, "Monitor light changes changes", NULL },
+ { "hinge", 0, 0, G_OPTION_ARG_NONE, &opt_watch_hinge_angle, "Monitor hinge angle changes", NULL },
{ NULL}
};
int ret = 0;
@@ -315,9 +366,10 @@ int main (int argc, char **argv)
if ((!opt_watch_accel &&
!opt_watch_prox &&
!opt_watch_compass &&
- !opt_watch_light) ||
+ !opt_watch_light &&
+ !opt_watch_hinge_angle) ||
opt_all) {
- opt_watch_accel = opt_watch_prox = opt_watch_light = TRUE;
+ opt_watch_accel = opt_watch_prox = opt_watch_light = opt_watch_hinge_angle = TRUE;
opt_watch_compass = g_strcmp0 (g_get_user_name (), "geoclue") == 0;
}
@@ -325,6 +377,7 @@ int main (int argc, char **argv)
watch_prox = opt_watch_prox;
watch_compass = opt_watch_compass;
watch_light = opt_watch_light;
+ watch_hinge_angle = opt_watch_hinge_angle;
watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
"net.hadess.SensorProxy",
diff --git a/src/net.hadess.SensorProxy.xml b/src/net.hadess.SensorProxy.xml
index 620044a..23cac76 100644
--- a/src/net.hadess.SensorProxy.xml
+++ b/src/net.hadess.SensorProxy.xml
@@ -100,6 +100,11 @@
-->
<property name='ProximityNear' type='b' access='read'/>
+ <property name="HasHingeAngle" type="b" access="read"/>
+ <property name="HingeAngle" type="d" access="read"/>
+ <property name="TabletMode" type="s" access="read"/>
+ <method name="ClaimHingeAngle"/>
+ <method name="ReleaseHingeAngle"/>
<!--
ClaimAccelerometer: