Support proximity polling sensors
This commit is contained in:

committed by
Bastien Nocera

parent
9e22ff5d9d
commit
7024b9c45a
@@ -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 \
|
||||
|
@@ -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;
|
||||
|
127
src/drv-iio-poll-proximity.c
Normal file
127
src/drv-iio-poll-proximity.c
Normal 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,
|
||||
};
|
@@ -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 ();
|
||||
}
|
||||
|
@@ -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>
|
||||
|
||||
<!--
|
||||
|
Reference in New Issue
Block a user