Support proximity polling sensors

This commit is contained in:
Guido Günther
2019-12-20 18:09:23 +01:00
committed by Bastien Nocera
parent 9e22ff5d9d
commit 7024b9c45a
5 changed files with 251 additions and 4 deletions

View File

@@ -17,6 +17,7 @@ iio_sensor_proxy_SOURCES = \
orientation.h \
drv-iio-buffer-accel.c \
drv-iio-poll-accel.c \
drv-iio-poll-proximity.c \
drv-input-accel.c \
drv-fake-compass.c \
drv-fake-light.c \

View File

@@ -15,6 +15,7 @@ typedef enum {
DRIVER_TYPE_ACCEL,
DRIVER_TYPE_LIGHT,
DRIVER_TYPE_COMPASS,
DRIVER_TYPE_PROXIMITY,
} DriverType;
/* Driver types */
@@ -36,6 +37,16 @@ typedef enum {
DRIVER_TYPE_COMPASS_FAKE
} DriverTypeCompass;
typedef enum {
DRIVER_TYPE_PROXIMITY_IIO,
} DriverTypeProximity;
typedef enum {
PROXIMITY_NEAR_ERROR = -1,
PROXIMITY_NEAR_FALSE = 0,
PROXIMITY_NEAR_TRUE = 1,
} ProximityNear;
typedef struct SensorDriver SensorDriver;
typedef struct {
@@ -54,6 +65,10 @@ typedef struct {
gdouble heading;
} CompassReadings;
typedef struct {
ProximityNear is_near;
} ProximityReadings;
typedef void (*ReadingsUpdateFunc) (SensorDriver *driver,
gpointer readings,
gpointer user_data);
@@ -132,3 +147,4 @@ extern SensorDriver iio_poll_light;
extern SensorDriver hwmon_light;
extern SensorDriver iio_buffer_light;
extern SensorDriver iio_buffer_compass;
extern SensorDriver iio_poll_proximity;

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 2019 Purism SPC
*
* 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 <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
/* FIXME: This needs to come from udev since it's device dependent */
#define NEAR_LEVEL 200
typedef struct DrvData {
guint timeout_id;
ReadingsUpdateFunc callback_func;
gpointer user_data;
GUdevDevice *dev;
const char *name;
} 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_proximity (gpointer user_data)
{
DrvData *data = user_data;
ProximityReadings readings;
gint prox;
/* g_udev_device_get_sysfs_attr_as_int does not update when there's no event */
prox = sysfs_get_int (data->dev, "in_proximity_raw");
readings.is_near = (prox > NEAR_LEVEL) ? TRUE : FALSE;
g_debug ("Proximity read from IIO on '%s': %d, near: %d", data->name, prox, readings.is_near);
drv_data->callback_func (&iio_poll_proximity, (gpointer) &readings, drv_data->user_data);
return G_SOURCE_CONTINUE;
}
static gboolean
iio_poll_proximity_discover (GUdevDevice *device)
{
/* We also handle devices with trigger buffers, but there's no trigger available on the system */
if (g_strcmp0 (g_udev_device_get_property (device, "IIO_SENSOR_PROXY_TYPE"), "iio-poll-proximity") != 0)
return FALSE;
g_debug ("Found IIO poll proximity sensor at %s", g_udev_device_get_sysfs_path (device));
return TRUE;
}
static void
iio_poll_proximity_set_polling (gboolean state)
{
if (drv_data->timeout_id > 0 && state)
return;
if (drv_data->timeout_id == 0 && !state)
return;
g_clear_handle_id (&drv_data->timeout_id, g_source_remove);
if (state) {
drv_data->timeout_id = g_timeout_add (700, poll_proximity, drv_data);
g_source_set_name_by_id (drv_data->timeout_id, "[iio_poll_proximity_set_polling] poll_proximity");
}
}
static gboolean
iio_poll_proximity_open (GUdevDevice *device,
ReadingsUpdateFunc callback_func,
gpointer user_data)
{
iio_fixup_sampling_frequency (device);
drv_data = g_new0 (DrvData, 1);
drv_data->dev = g_object_ref (device);
drv_data->name = g_udev_device_get_sysfs_attr (device, "name");
drv_data->callback_func = callback_func;
drv_data->user_data = user_data;
return TRUE;
}
static void
iio_poll_proximity_close (void)
{
iio_poll_proximity_set_polling (FALSE);
g_clear_object (&drv_data->dev);
g_clear_pointer (&drv_data, g_free);
}
SensorDriver iio_poll_proximity = {
.name = "IIO Poll proximity sensor",
.type = DRIVER_TYPE_PROXIMITY,
.specific_type = DRIVER_TYPE_PROXIMITY_IIO,
.discover = iio_poll_proximity_discover,
.open = iio_poll_proximity_open,
.set_polling = iio_poll_proximity_set_polling,
.close = iio_poll_proximity_close,
};

View File

@@ -29,7 +29,7 @@
#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
#define NUM_SENSOR_TYPES DRIVER_TYPE_PROXIMITY + 1
typedef struct {
GMainLoop *loop;
@@ -52,6 +52,9 @@ typedef struct {
/* Compass */
gdouble previous_heading;
/* Proximity */
gboolean previous_prox_near;
} SensorData;
static const SensorDriver * const drivers[] = {
@@ -63,7 +66,8 @@ static const SensorDriver * const drivers[] = {
&hwmon_light,
&fake_compass,
&fake_light,
&iio_buffer_compass
&iio_buffer_compass,
&iio_poll_proximity,
};
static ReadingsUpdateFunc driver_type_to_callback_func (DriverType type);
@@ -78,6 +82,8 @@ driver_type_to_str (DriverType type)
return "ambient light sensor";
case DRIVER_TYPE_COMPASS:
return "compass";
case DRIVER_TYPE_PROXIMITY:
return "proximity";
default:
g_assert_not_reached ();
}
@@ -133,6 +139,7 @@ find_sensors (GUdevClient *client,
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;
}
@@ -164,13 +171,17 @@ typedef enum {
PROP_HAS_AMBIENT_LIGHT = 1 << 2,
PROP_LIGHT_LEVEL = 1 << 3,
PROP_HAS_COMPASS = 1 << 4,
PROP_COMPASS_HEADING = 1 << 5
PROP_COMPASS_HEADING = 1 << 5,
PROP_HAS_PROXIMITY = 1 << 6,
PROP_PROXIMITY_NEAR = 1 << 7,
} PropertiesMask;
#define PROP_ALL (PROP_HAS_ACCELEROMETER | \
PROP_ACCELEROMETER_ORIENTATION | \
PROP_HAS_AMBIENT_LIGHT | \
PROP_LIGHT_LEVEL)
PROP_LIGHT_LEVEL | \
PROP_HAS_PROXIMITY | \
PROP_PROXIMITY_NEAR)
#define PROP_ALL_COMPASS (PROP_HAS_COMPASS | \
PROP_COMPASS_HEADING)
@@ -245,6 +256,23 @@ send_dbus_event (SensorData *data,
g_variant_new_double (data->previous_heading));
}
if (mask & PROP_HAS_PROXIMITY) {
gboolean has_proximity;
has_proximity = driver_type_exists (data, DRIVER_TYPE_PROXIMITY);
g_variant_builder_add (&props_builder, "{sv}", "HasProximity",
g_variant_new_boolean (has_proximity));
/* Send proximity information when the device appears */
if (has_proximity)
mask |= PROP_PROXIMITY_NEAR;
}
if (mask & PROP_PROXIMITY_NEAR) {
g_variant_builder_add (&props_builder, "{sv}", "ProximityNear",
g_variant_new_boolean (data->previous_prox_near));
}
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));
@@ -265,6 +293,8 @@ send_driver_changed_dbus_event (SensorData *data,
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_PROXIMITY)
send_dbus_event (data, PROP_HAS_PROXIMITY);
else if (driver_type == DRIVER_TYPE_COMPASS)
send_dbus_event (data, PROP_HAS_COMPASS);
else
@@ -402,6 +432,9 @@ handle_method_call (GDBusConnection *connection,
else if (g_strcmp0 (method_name, "ClaimLight") == 0 ||
g_strcmp0 (method_name, "ReleaseLight") == 0)
driver_type = DRIVER_TYPE_LIGHT;
else if (g_strcmp0 (method_name, "ClaimProximity") == 0 ||
g_strcmp0 (method_name, "ReleaseProximity") == 0)
driver_type = DRIVER_TYPE_PROXIMITY;
else {
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
@@ -439,6 +472,10 @@ handle_get_property (GDBusConnection *connection,
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);
if (g_strcmp0 (property_name, "HasProximity") == 0)
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);
return NULL;
}
@@ -684,6 +721,32 @@ compass_changed_func (SensorDriver *driver,
}
}
static void
proximity_changed_func (SensorDriver *driver,
gpointer readings_data,
gpointer user_data)
{
SensorData *data = user_data;
ProximityReadings *readings = (ProximityReadings *) readings_data;
gboolean near;
//FIXME handle errors
g_debug ("Proximity sent by driver: %d",
readings->is_near);
near = readings->is_near > 0;
if (data->previous_prox_near != near) {
ProximityNear tmp;
tmp = data->previous_prox_near;
data->previous_prox_near = near;
send_dbus_event (data, PROP_PROXIMITY_NEAR);
g_debug ("Emitted proximity changed: from %d to %d",
tmp, near);
}
}
static ReadingsUpdateFunc
driver_type_to_callback_func (DriverType type)
{
@@ -694,6 +757,8 @@ driver_type_to_callback_func (DriverType type)
return light_changed_func;
case DRIVER_TYPE_COMPASS:
return compass_changed_func;
case DRIVER_TYPE_PROXIMITY:
return proximity_changed_func;
default:
g_assert_not_reached ();
}

View File

@@ -64,6 +64,20 @@
-->
<property name="LightLevel" type="d" access="read"/>
<!--
HasProximity:
Whether a supported proximity sensor is present on the system.
-->
<property name="HasProximity" type="b" access="read"/>
<!--
ProximityNear:
Whether an object is near to the proximity sensor.
-->
<property name='ProximityNear' type='b' access='read'/>
<!--
ClaimAccelerometer:
@@ -117,6 +131,30 @@
calling net.hadess.SensorProxy.ReleaseLight(), crashes or the sensor disappears.
-->
<method name="ReleaseLight"/>
<!--
ClaimProximity:
To start receiving proximity updates from the proxy, the
application must call the net.hadess.SensorProxy.ClaimProximity() method. It can do so
whether a proximity is available or not, updates would then be sent
when such a sensor appears.
Applications should call net.hadess.SensorProxy.ReleaseProximity() when readings are
not required anymore. This prevents the sensor proxy from polling the device, thus
increasing wake-ups and reducing battery life.
-->
<method name="ClaimProximity"/>
<!--
ReleaseProximity:
This should be called as soon as readings are not required anymore. Note
that resources are freed up if a monitoring application exits without
calling net.hadess.SensorProxy.ReleaseProximity(), crashes or the sensor disappears.
-->
<method name="ReleaseProximity"/>
</interface>
<!--