Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package iio-sensor-proxy for 
openSUSE:Factory checked in at 2026-03-06 18:16:56
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/iio-sensor-proxy (Old)
 and      /work/SRC/openSUSE:Factory/.iio-sensor-proxy.new.561 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "iio-sensor-proxy"

Fri Mar  6 18:16:56 2026 rev:27 rq:1336654 version:3.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/iio-sensor-proxy/iio-sensor-proxy.changes        
2025-08-12 17:03:46.721270507 +0200
+++ 
/work/SRC/openSUSE:Factory/.iio-sensor-proxy.new.561/iio-sensor-proxy.changes   
    2026-03-06 18:17:03.548336749 +0100
@@ -1,0 +2,13 @@
+Wed Mar  4 09:05:50 UTC 2026 - Bjørn Lie <[email protected]>
+
+- Update to version 3.9:
+  + SSC sensors are now supported through libssc. Light and compass
+    sensor are enabled by default. Accelerometer and proximity
+    remain experimental, but can be enabled through udev rules.
+  + SSC sensor support.
+  + Logging improvements for sensor discovery.
+  + Fix race condition during startup.
+- Pass ssc-support=disabled to meson setup, libssc is not available in
+  any current versions of openSUSE.
+
+-------------------------------------------------------------------

Old:
----
  iio-sensor-proxy-3.8.tar.bz2

New:
----
  iio-sensor-proxy-3.9.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ iio-sensor-proxy.spec ++++++
--- /var/tmp/diff_new_pack.pVcHuA/_old  2026-03-06 18:17:04.060358000 +0100
+++ /var/tmp/diff_new_pack.pVcHuA/_new  2026-03-06 18:17:04.060358000 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package iio-sensor-proxy
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           iio-sensor-proxy
-Version:        3.8
+Version:        3.9
 Release:        0
 Summary:        Proxy for IIO and input subsystems
 License:        GPL-3.0-only
@@ -54,7 +54,9 @@
 %build
 %meson -Dtests=false \
        -Dgtk_doc=true \
-       -Dgeoclue-user=srvGeoClue
+       -Dgeoclue-user=srvGeoClue \
+       -Dssc-support=disabled \
+       %{nil}
 %meson_build
 
 %install

++++++ iio-sensor-proxy-3.8.tar.bz2 -> iio-sensor-proxy-3.9.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/.gitlab-ci.yml 
new/iio-sensor-proxy-3.9/.gitlab-ci.yml
--- old/iio-sensor-proxy-3.8/.gitlab-ci.yml     2025-08-09 13:57:19.000000000 
+0200
+++ new/iio-sensor-proxy-3.9/.gitlab-ci.yml     2026-03-02 20:19:51.000000000 
+0100
@@ -41,6 +41,28 @@
       - "${CI_PROJECT_DIR}/_build/meson-dist"
       - "${CI_PROJECT_DIR}/_build/docs/html/"
 
+build-debian-trixie-libssc:
+  before_script:
+    - apt-get update
+    - apt-get -y install eatmydata
+    - eatmydata apt-get -y install $DEPENDENCIES
+    - eatmydata apt-get -y install python3 python-is-python3 python3-dev 
qrtr-tools libprotobuf-c-dev libprotobuf-dev protobuf-c-compiler 
protobuf-compiler python3-gi libmbim-glib-dev libqmi-glib-dev python3-protobuf 
libqrtr1
+    - git clone "https://codeberg.org/DylanVanAssche/libssc.git";
+    - cd libssc
+    - mkdir _build
+    - meson setup _build
+    - meson compile --verbose -C _build
+    - meson install --no-rebuild -C _build
+    - cd mocking
+    - ./ssc-server &
+    - cd ../..
+  script:
+    - meson -Dssc-support=enabled -Dtests=true -Dgtk_doc=true -Dgtk-tests=true 
_build
+    - meson compile --verbose -C _build
+    - meson install -C _build
+    - meson dist -C _build
+    - meson test --verbose -C _build
+
 pages:
   needs:
     - build-debian-trixie
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/NEWS 
new/iio-sensor-proxy-3.9/NEWS
--- old/iio-sensor-proxy-3.8/NEWS       2025-08-09 13:57:19.000000000 +0200
+++ new/iio-sensor-proxy-3.9/NEWS       2026-03-02 20:19:51.000000000 +0100
@@ -1,3 +1,13 @@
+3.9
+---
+
+SSC sensors are now supported through libssc. Light and compass sensor are 
enabled by default,
+accelerometer and proximity remain experimental, but can be enabled through 
udev rules.
+
+- SSC sensor support.
+- Logging improvements for sensor discovery.
+- Fix race condition during startup.
+
 3.8
 ---
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/data/80-iio-sensor-proxy.rules 
new/iio-sensor-proxy-3.9/data/80-iio-sensor-proxy.rules
--- old/iio-sensor-proxy-3.8/data/80-iio-sensor-proxy.rules     2025-08-09 
13:57:19.000000000 +0200
+++ new/iio-sensor-proxy-3.9/data/80-iio-sensor-proxy.rules     2026-03-02 
20:19:51.000000000 +0100
@@ -18,6 +18,12 @@
 SUBSYSTEM=="iio", TEST=="in_proximity0_raw", 
ENV{IIO_SENSOR_PROXY_TYPE}+="iio-poll-proximity"
 SUBSYSTEM=="input", ENV{ID_INPUT_ACCELEROMETER}=="1", 
ENV{IIO_SENSOR_PROXY_TYPE}+="input-accel"
 
+# Set the sensor type for all the types we recognise for SDSP/ADSP with libssc.
+# Some devices expose the sensors via a separate SDSP while others re-use ADSP.
+# These DSPs expose itself as /dev/fastrpc-* in the misc subsystem.
+SUBSYSTEM=="misc", KERNEL=="fastrpc-adsp*", 
ENV{IIO_SENSOR_PROXY_TYPE}+="ssc-light ssc-compass"
+SUBSYSTEM=="misc", KERNEL=="fastrpc-sdsp*", 
ENV{IIO_SENSOR_PROXY_TYPE}+="ssc-light ssc-compass"
+
 ENV{IIO_SENSOR_PROXY_TYPE}=="", GOTO="iio_sensor_proxy_end"
 
 # We got here because we have a sensor type, which means we need the service
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/iio-sensor-proxy-3.8/data/iio-sensor-proxy.service.in 
new/iio-sensor-proxy-3.9/data/iio-sensor-proxy.service.in
--- old/iio-sensor-proxy-3.8/data/iio-sensor-proxy.service.in   2025-08-09 
13:57:19.000000000 +0200
+++ new/iio-sensor-proxy-3.9/data/iio-sensor-proxy.service.in   2026-03-02 
20:19:51.000000000 +0100
@@ -14,6 +14,6 @@
 ProtectHome=true
 ProtectKernelModules=true
 PrivateTmp=true
-RestrictAddressFamilies=AF_UNIX AF_LOCAL AF_NETLINK
+RestrictAddressFamilies=AF_UNIX AF_LOCAL AF_NETLINK AF_QIPCRTR
 MemoryDenyWriteExecute=true
 RestrictRealtime=true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/data/meson.build 
new/iio-sensor-proxy-3.9/data/meson.build
--- old/iio-sensor-proxy-3.8/data/meson.build   2025-08-09 13:57:19.000000000 
+0200
+++ new/iio-sensor-proxy-3.9/data/meson.build   2026-03-02 20:19:51.000000000 
+0100
@@ -1,3 +1,7 @@
+rules = files(
+  '80-iio-sensor-proxy.rules'
+)
+
 install_data(
   '80-iio-sensor-proxy.rules',
   install_dir: udev_rules_dir
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/meson.build 
new/iio-sensor-proxy-3.9/meson.build
--- old/iio-sensor-proxy-3.8/meson.build        2025-08-09 13:57:19.000000000 
+0200
+++ new/iio-sensor-proxy-3.9/meson.build        2026-03-02 20:19:51.000000000 
+0100
@@ -1,5 +1,5 @@
 project('iio-sensor-proxy', [ 'c' ],
-        version: '3.8',
+        version: '3.9',
         license: 'GPLv3+',
         default_options: [
           'buildtype=debugoptimized',
@@ -46,6 +46,7 @@
 gudev_dep = dependency('gudev-1.0', version: '>= 237')
 polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.91')
 polkit_policy_directory = 
polkit_gobject_dep.get_pkgconfig_variable('policydir')
+libssc_dep = dependency('libssc', version: '>=0.2.1', required: 
get_option('ssc-support'))
 
 xmllint = find_program('xmllint', required: false)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/meson_options.txt 
new/iio-sensor-proxy-3.9/meson_options.txt
--- old/iio-sensor-proxy-3.8/meson_options.txt  2025-08-09 13:57:19.000000000 
+0200
+++ new/iio-sensor-proxy-3.9/meson_options.txt  2026-03-02 20:19:51.000000000 
+0100
@@ -18,6 +18,10 @@
        description: 'The USER (existing) as which geoclue service is running',
        type: 'string',
        value: 'geoclue')
+option('ssc-support',
+       description: 'Enable Qualcomm SSC support',
+       type: 'feature',
+       value: 'auto')
 option('gtk_doc',
        type: 'boolean',
        value: false,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/src/drivers.h 
new/iio-sensor-proxy-3.9/src/drivers.h
--- old/iio-sensor-proxy-3.8/src/drivers.h      2025-08-09 13:57:19.000000000 
+0200
+++ new/iio-sensor-proxy-3.9/src/drivers.h      2026-03-02 20:19:51.000000000 
+0100
@@ -161,4 +161,11 @@
 extern SensorDriver iio_poll_proximity;
 extern SensorDriver input_proximity;
 
+#ifdef HAS_LIBSSC
+extern SensorDriver ssc_proximity;
+extern SensorDriver ssc_light;
+extern SensorDriver ssc_accel;
+extern SensorDriver ssc_compass;
+#endif
+
 gboolean drv_check_udev_sensor_type (GUdevDevice *device, const gchar *match, 
const char *name);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/src/drv-input-proximity.c 
new/iio-sensor-proxy-3.9/src/drv-input-proximity.c
--- old/iio-sensor-proxy-3.8/src/drv-input-proximity.c  2025-08-09 
13:57:19.000000000 +0200
+++ new/iio-sensor-proxy-3.9/src/drv-input-proximity.c  2026-03-02 
20:19:51.000000000 +0100
@@ -73,31 +73,39 @@
        gboolean ret = FALSE;
        g_autofree gchar *contents = NULL;
        g_autofree gchar *native_path = NULL;
-       g_autofree gchar *path;
+       g_autofree gchar *path = NULL;
        g_autoptr(GError) error = NULL;
        gint num_bits;
 
-       /* check if the input device has switch capabilities */
+       /* only process devices on the input subsystem */
+       if (g_strcmp0 (g_udev_device_get_subsystem (device), "input") != 0)
+               return FALSE;
+
+       /* ignore devices which do not report any switch capabilities */
        native_path = g_strdup (g_udev_device_get_sysfs_path (device));
        path = g_build_filename (native_path, "../capabilities/sw", NULL);
        if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
-               g_warning_once ("Not a switch [%s]", path);
                return FALSE;
        }
 
        ret = g_file_get_contents (path, &contents, NULL, &error);
+       /* for completeness, report read failures */
        if (!ret) {
-               g_warning_once ("Failed to read contents of [%s]: %s",
+               g_warning ("Failed to read contents of [%s]: %s",
                        path, error->message);
                return FALSE;
        }
 
-       /* convert attributes of input device into a bitmask */
+       /* confirm that the device has a usable switch */
        num_bits = input_str_to_bitmask (contents, bitmask, sizeof (bitmask));
-       if ((num_bits == 0) || (num_bits >= SW_CNT)) {
-               g_warning_once ("Invalid bitmask entry for %s", native_path);
+       if (num_bits == 0) {
+               g_debug ("%s is not a valid switch", native_path);
+        } else if (num_bits >= SW_CNT) {
+               g_debug ("%s reports an invalid number of switches. Was 
iio-sensor-proxy compiled with kernel headers not matching the running kernel?",
+                       native_path);
                return FALSE;
        }
+
        return TRUE;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/src/drv-ssc-accel.c 
new/iio-sensor-proxy-3.9/src/drv-ssc-accel.c
--- old/iio-sensor-proxy-3.8/src/drv-ssc-accel.c        1970-01-01 
01:00:00.000000000 +0100
+++ new/iio-sensor-proxy-3.9/src/drv-ssc-accel.c        2026-03-02 
20:19:51.000000000 +0100
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2023-2025 Dylan Van Assche
+ *
+ * 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 "accel-mount-matrix.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gio/gio.h>
+#include <libssc-sensor.h>
+#include <libssc-sensor-accelerometer.h>
+
+typedef struct DrvData {
+       SSCSensorAccelerometer *sensor;
+       gulong measurement_id;
+       AccelVec3 *mount_matrix;
+       AccelLocation location;
+       AccelScale scale;
+} DrvData;
+
+static gboolean
+ssc_accelerometer_discover (GUdevDevice *device)
+{
+       g_autoptr(SSCSensorAccelerometer) sensor = NULL;
+
+       /* Verify presence of FastRPC device */
+       if (!drv_check_udev_sensor_type (device, "ssc-accel", NULL))
+               return FALSE;
+
+       /* Open and close SSC accelerometer for discovering */
+       sensor = ssc_sensor_accelerometer_new_sync (NULL, NULL);
+       if (!sensor)
+               return FALSE;
+
+       if (!ssc_sensor_accelerometer_close_sync (sensor, NULL, NULL))
+               return FALSE;
+
+       g_debug ("Found SSC accelerometer at %s", g_udev_device_get_sysfs_path 
(device));
+       return TRUE;
+}
+
+static void
+measurement_cb (SSCSensorAccelerometer *sensor, gfloat accel_x, gfloat 
accel_y, gfloat accel_z, gpointer user_data)
+{
+       SensorDevice *sensor_device = user_data;
+       DrvData *drv_data = (DrvData *) sensor_device->priv;
+       AccelReadings readings;
+       AccelVec3 tmp;
+
+       tmp.x = accel_x;
+       tmp.y = accel_y;
+       tmp.z = accel_z;
+
+       if (!apply_mount_matrix (drv_data->mount_matrix, &tmp))
+               g_warning ("Could not apply mount matrix");
+
+       readings.accel_x = tmp.x;
+       readings.accel_y = tmp.y;
+       readings.accel_z = tmp.z;
+       copy_accel_scale (&readings.scale, drv_data->scale);
+
+       sensor_device->callback_func (sensor_device, (gpointer) &readings, 
sensor_device->user_data);
+}
+
+static SensorDevice *
+ssc_accelerometer_open (GUdevDevice *device)
+{
+       g_autoptr(GError) error = NULL;
+       SensorDevice *sensor_device;
+       DrvData *drv_data;
+
+       sensor_device = g_new0 (SensorDevice, 1);
+       sensor_device->priv = g_new0 (DrvData, 1);
+
+       drv_data = (DrvData *) sensor_device->priv;
+       drv_data->sensor = ssc_sensor_accelerometer_new_sync (NULL, &error);
+       if (!drv_data->sensor)
+               g_warning ("Creating SSC accelerometer sensor failed: %s", 
error->message);
+       else
+               g_object_get (drv_data->sensor,
+                             SSC_SENSOR_NAME, &sensor_device->name,
+                             NULL);
+
+       /* Setup accel attributes */
+       drv_data->mount_matrix = setup_mount_matrix (device);
+       drv_data->location = setup_accel_location (device);
+       set_accel_scale (&drv_data->scale, 1.0);
+
+       return sensor_device;
+}
+
+static void
+ssc_accelerometer_set_polling (SensorDevice *sensor_device, gboolean state)
+{
+       DrvData *drv_data = (DrvData *) sensor_device->priv;
+       g_autoptr(GError) error = NULL;
+       if (state) {
+               if (drv_data->measurement_id)
+                       return;
+
+               /* Start listening for measurements */
+               drv_data->measurement_id = g_signal_connect (drv_data->sensor,
+                                                            "measurement",
+                                                            G_CALLBACK 
(measurement_cb),
+                                                            sensor_device);
+               /* Enable sensor */
+               if (!ssc_sensor_accelerometer_open_sync (drv_data->sensor, 
NULL, &error)) {
+                       g_warning ("Opening SSC accelerometer sensor failed: 
%s", error->message);
+                       return;
+               }
+       } else {
+               if (!drv_data->measurement_id)
+                       return;
+
+               /* Stop listening for measurements */
+               g_clear_signal_handler (&drv_data->measurement_id, 
drv_data->sensor);
+
+               /* Disable sensor */
+               if (!ssc_sensor_accelerometer_close_sync (drv_data->sensor, 
NULL, &error))
+                       g_warning ("Closing SSC accelerometer sensor failed: 
%s", error->message);
+       }
+}
+
+static void
+ssc_accelerometer_close (SensorDevice *sensor_device)
+{
+       g_autoptr(GError) error = NULL;
+       DrvData *drv_data = (DrvData *) sensor_device->priv;
+
+       g_clear_object (&drv_data->sensor);
+       g_clear_pointer (&drv_data->mount_matrix, g_free);
+       g_clear_pointer (&sensor_device->priv, g_free);
+       g_free (sensor_device);
+}
+
+SensorDriver ssc_accel = {
+       .driver_name = "SSC accelerometer sensor",
+       .type = DRIVER_TYPE_ACCEL,
+
+       .discover = ssc_accelerometer_discover,
+       .open = ssc_accelerometer_open,
+       .set_polling = ssc_accelerometer_set_polling,
+       .close = ssc_accelerometer_close,
+};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/src/drv-ssc-compass.c 
new/iio-sensor-proxy-3.9/src/drv-ssc-compass.c
--- old/iio-sensor-proxy-3.8/src/drv-ssc-compass.c      1970-01-01 
01:00:00.000000000 +0100
+++ new/iio-sensor-proxy-3.9/src/drv-ssc-compass.c      2026-03-02 
20:19:51.000000000 +0100
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2023-2025 Dylan Van Assche
+ *
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gio/gio.h>
+#include <libssc-sensor.h>
+#include <libssc-sensor-compass.h>
+
+typedef struct DrvData {
+       SSCSensorCompass *sensor;
+       gulong measurement_id;
+} DrvData;
+
+static gboolean
+ssc_compass_discover (GUdevDevice *device)
+{
+       g_autoptr(SSCSensorCompass) sensor = NULL;
+
+       /* Verify presence of FastRPC device */
+       if (!drv_check_udev_sensor_type (device, "ssc-compass", NULL))
+               return FALSE;
+
+       /* Open and close SSC compass for discovering */
+       sensor = ssc_sensor_compass_new_sync (NULL, NULL);
+       if (!sensor)
+               return FALSE;
+
+       if (!ssc_sensor_compass_close_sync (sensor, NULL, NULL))
+               return FALSE;
+
+       g_debug ("Found SSC compass at %s", g_udev_device_get_sysfs_path 
(device));
+       return TRUE;
+}
+
+static void
+measurement_cb (SSCSensorCompass *sensor, gfloat azimuth, gpointer user_data)
+{
+       SensorDevice *sensor_device = user_data;
+       CompassReadings readings;
+
+       readings.heading = azimuth;
+
+       sensor_device->callback_func (sensor_device, (gpointer) &readings, 
sensor_device->user_data);
+}
+
+static SensorDevice *
+ssc_compass_open (GUdevDevice *device)
+{
+       g_autoptr(GError) error = NULL;
+       SensorDevice *sensor_device;
+       DrvData *drv_data;
+
+       sensor_device = g_new0 (SensorDevice, 1);
+       sensor_device->priv = g_new0 (DrvData, 1);
+
+       drv_data = (DrvData *) sensor_device->priv;
+       drv_data->sensor = ssc_sensor_compass_new_sync (NULL, &error);
+       if (!drv_data->sensor)
+               g_warning ("Creating SSC compass sensor failed: %s", 
error->message);
+       else {
+         g_object_get (drv_data->sensor,
+                       SSC_SENSOR_NAME, &sensor_device->name,
+                       NULL);
+       }
+
+       return sensor_device;
+}
+
+static void
+ssc_compass_set_polling (SensorDevice *sensor_device, gboolean state)
+{
+       DrvData *drv_data = (DrvData *) sensor_device->priv;
+       g_autoptr(GError) error = NULL;
+
+       if (state) {
+               if (drv_data->measurement_id)
+                       return;
+               /* Start listening for measurements */
+               drv_data->measurement_id = g_signal_connect (drv_data->sensor,
+                                                            "measurement",
+                                                            G_CALLBACK 
(measurement_cb),
+                                                            sensor_device);
+
+               /* Enable sensor */
+               if (!ssc_sensor_compass_open_sync (drv_data->sensor, NULL, 
&error))
+                       g_warning ("Opening SSC compass sensor failed: %s", 
error->message);
+       } else {
+               if (!drv_data->measurement_id)
+                       return;
+
+               /* Stop listening for measurements */
+               g_clear_signal_handler (&drv_data->measurement_id, 
drv_data->sensor);
+
+               /* Disable sensor */
+               if (!ssc_sensor_compass_close_sync (drv_data->sensor, NULL, 
&error))
+                       g_warning ("Closing SSC compass sensor failed: %s", 
error->message);
+       }
+}
+
+static void
+ssc_compass_close (SensorDevice *sensor_device)
+{
+       DrvData *drv_data = (DrvData *) sensor_device->priv;
+
+       g_clear_object (&drv_data->sensor);
+       g_clear_pointer (&sensor_device->name, g_free);
+       g_clear_pointer (&sensor_device->priv, g_free);
+       g_free (sensor_device);
+}
+
+SensorDriver ssc_compass = {
+       .driver_name = "SSC compass sensor",
+       .type = DRIVER_TYPE_COMPASS,
+
+       .discover = ssc_compass_discover,
+       .open = ssc_compass_open,
+       .set_polling = ssc_compass_set_polling,
+       .close = ssc_compass_close,
+};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/src/drv-ssc-light.c 
new/iio-sensor-proxy-3.9/src/drv-ssc-light.c
--- old/iio-sensor-proxy-3.8/src/drv-ssc-light.c        1970-01-01 
01:00:00.000000000 +0100
+++ new/iio-sensor-proxy-3.9/src/drv-ssc-light.c        2026-03-02 
20:19:51.000000000 +0100
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2023-2025 Dylan Van Assche
+ *
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gio/gio.h>
+#include <libssc-sensor.h>
+#include <libssc-sensor-light.h>
+
+typedef struct DrvData {
+       SSCSensorLight *sensor;
+       gulong measurement_id;
+} DrvData;
+
+static gboolean
+ssc_light_discover (GUdevDevice *device)
+{
+       g_autoptr(SSCSensorLight) sensor = NULL;
+
+       /* Verify presence of FastRPC device */
+       if (!drv_check_udev_sensor_type (device, "ssc-light", NULL))
+               return FALSE;
+
+       /* Open and close SSC light sensor for discovering */
+       sensor = ssc_sensor_light_new_sync (NULL, NULL);
+       if (!sensor)
+               return FALSE;
+
+       if (!ssc_sensor_light_close_sync (sensor, NULL, NULL))
+               return FALSE;
+
+       g_debug ("Found SSC light at %s", g_udev_device_get_sysfs_path 
(device));
+       return TRUE;
+}
+
+static void
+measurement_cb (SSCSensorLight *sensor, gfloat intensity, gpointer user_data)
+{
+       SensorDevice *sensor_device = user_data;
+       LightReadings readings;
+
+       readings.level = intensity;
+       readings.uses_lux = TRUE;
+       sensor_device->callback_func (sensor_device, (gpointer) &readings, 
sensor_device->user_data);
+}
+
+static SensorDevice *
+ssc_light_open (GUdevDevice *device)
+{
+       g_autoptr(GError) error = NULL;
+       SensorDevice *sensor_device;
+       DrvData *drv_data;
+
+       sensor_device = g_new0 (SensorDevice, 1);
+       sensor_device->priv = g_new0 (DrvData, 1);
+
+       drv_data = (DrvData *) sensor_device->priv;
+       drv_data->sensor = ssc_sensor_light_new_sync (NULL, &error);
+       if (!drv_data->sensor)
+               g_warning ("Creating SSC light sensor failed: %s", 
error->message);
+       else
+               g_object_get (drv_data->sensor,
+                             SSC_SENSOR_NAME, &sensor_device->name,
+                             NULL);
+
+       return sensor_device;
+}
+
+static void
+ssc_light_set_polling (SensorDevice *sensor_device, gboolean state)
+{
+       DrvData *drv_data = (DrvData *) sensor_device->priv;
+       g_autoptr (GError) error = NULL;
+       if (state) {
+               if (drv_data->measurement_id)
+                       return;
+               /* Start listening for measurements */
+               drv_data->measurement_id = g_signal_connect (drv_data->sensor,
+                                                            "measurement",
+                                                            G_CALLBACK 
(measurement_cb),
+                                                            sensor_device);
+               /* Enable sensor */
+               if (!ssc_sensor_light_open_sync (drv_data->sensor, NULL, 
&error))
+                       g_warning ("Opening SSC light sensor failed: %s", 
error->message);
+       } else {
+               if (!drv_data->measurement_id)
+                       return;
+
+               /* Stop listening for measurements */
+               g_clear_signal_handler (&drv_data->measurement_id, 
drv_data->sensor);
+
+               /* Disable sensor */
+               if (!ssc_sensor_light_close_sync (drv_data->sensor, NULL, 
&error))
+                       g_warning ("Closing SSC light sensor failed: %s", 
error->message);
+       }
+}
+
+static void
+ssc_light_close (SensorDevice *sensor_device)
+{
+       g_autoptr(GError) error = NULL;
+       DrvData *drv_data = (DrvData *) sensor_device->priv;
+
+       g_clear_object (&drv_data->sensor);
+       g_clear_pointer (&sensor_device->priv, g_free);
+       g_free (sensor_device);
+}
+
+SensorDriver ssc_light = {
+       .driver_name = "SSC light sensor",
+       .type = DRIVER_TYPE_LIGHT,
+
+       .discover = ssc_light_discover,
+       .open = ssc_light_open,
+       .set_polling = ssc_light_set_polling,
+       .close = ssc_light_close,
+};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/src/drv-ssc-proximity.c 
new/iio-sensor-proxy-3.9/src/drv-ssc-proximity.c
--- old/iio-sensor-proxy-3.8/src/drv-ssc-proximity.c    1970-01-01 
01:00:00.000000000 +0100
+++ new/iio-sensor-proxy-3.9/src/drv-ssc-proximity.c    2026-03-02 
20:19:51.000000000 +0100
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2023-2025 Dylan Van Assche
+ *
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gio/gio.h>
+#include <libssc-sensor.h>
+#include <libssc-sensor-proximity.h>
+
+typedef struct DrvData {
+       SSCSensorProximity *sensor;
+       gulong measurement_id;
+} DrvData;
+
+static gboolean
+ssc_proximity_discover (GUdevDevice *device)
+{
+       SSCSensorProximity *sensor = NULL;
+
+       /* Verify presence of FastRPC device */
+       if (!drv_check_udev_sensor_type (device, "ssc-proximity", NULL))
+               return FALSE;
+
+       /* Open and close SSC proximity sensor for discovering */
+       sensor = ssc_sensor_proximity_new_sync (NULL, NULL);
+       if (!sensor)
+               return FALSE;
+
+       if (!ssc_sensor_proximity_close_sync (sensor, NULL, NULL)) {
+               g_clear_object (&sensor);
+               return FALSE;
+       }
+
+       g_clear_object (&sensor);
+
+       g_debug ("Found SSC proximity at %s", g_udev_device_get_sysfs_path 
(device));
+       return TRUE;
+}
+
+static void
+measurement_cb (SSCSensorProximity *sensor, gboolean near, gpointer user_data)
+{
+       SensorDevice *sensor_device = user_data;
+       ProximityReadings readings;
+
+       readings.is_near = near ? PROXIMITY_NEAR_TRUE : PROXIMITY_NEAR_FALSE;
+       sensor_device->callback_func (sensor_device, (gpointer) &readings, 
sensor_device->user_data);
+}
+
+static SensorDevice *
+ssc_proximity_open (GUdevDevice *device)
+{
+       g_autoptr(GError) error = NULL;
+       SensorDevice *sensor_device;
+       DrvData *drv_data;
+
+       sensor_device = g_new0 (SensorDevice, 1);
+       sensor_device->priv = g_new0 (DrvData, 1);
+       drv_data = (DrvData *) sensor_device->priv;
+       drv_data->sensor = ssc_sensor_proximity_new_sync (NULL, &error);
+       if (!drv_data->sensor)
+               g_warning ("Creating SSC proximity sensor failed: %s", 
error->message);
+       else
+               g_object_get (drv_data->sensor,
+                             SSC_SENSOR_NAME, &sensor_device->name,
+                             NULL);
+
+       return sensor_device;
+}
+
+static void
+ssc_proximity_set_polling (SensorDevice *sensor_device, gboolean state)
+{
+       DrvData *drv_data = (DrvData *) sensor_device->priv;
+       g_autoptr(GError) error = NULL;
+       if (state) {
+               if (drv_data->measurement_id)
+                       return;
+               /* Start listening for measurements */
+               drv_data->measurement_id = g_signal_connect (drv_data->sensor,
+                                                            "measurement",
+                                                            G_CALLBACK 
(measurement_cb),
+                                                            sensor_device);
+
+               /* Enable sensor */
+               if (!ssc_sensor_proximity_open_sync (drv_data->sensor, NULL, 
&error)) {
+                       g_warning ("Opening SSC proximity sensor failed: %s", 
error ? error->message : "UNKNOWN");
+                       return;
+               }
+       } else {
+               if (!drv_data->measurement_id)
+                       return;
+               /* Stop listening for measurements */
+               g_clear_signal_handler (&drv_data->measurement_id, 
drv_data->sensor);
+               /* Disable sensor */
+               if (!ssc_sensor_proximity_close_sync (drv_data->sensor, NULL, 
&error))
+                       g_warning ("Closing SSC proximity sensor failed: %s", 
error->message);
+       }
+}
+
+static void
+ssc_proximity_close (SensorDevice *sensor_device)
+{
+       DrvData *drv_data = (DrvData *) sensor_device->priv;
+
+       g_clear_object (&drv_data->sensor);
+       g_clear_pointer (&sensor_device->priv, g_free);
+       g_free (sensor_device);
+}
+
+SensorDriver ssc_proximity = {
+       .driver_name = "SSC proximity sensor",
+       .type = DRIVER_TYPE_PROXIMITY,
+
+       .discover = ssc_proximity_discover,
+       .open = ssc_proximity_open,
+       .set_polling = ssc_proximity_set_polling,
+       .close = ssc_proximity_close,
+};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/src/iio-sensor-proxy.c 
new/iio-sensor-proxy-3.9/src/iio-sensor-proxy.c
--- old/iio-sensor-proxy-3.8/src/iio-sensor-proxy.c     2025-08-09 
13:57:19.000000000 +0200
+++ new/iio-sensor-proxy-3.9/src/iio-sensor-proxy.c     2026-03-02 
20:19:51.000000000 +0100
@@ -79,6 +79,12 @@
        &iio_buffer_compass,
        &iio_poll_proximity,
        &input_proximity,
+#ifdef HAS_LIBSSC
+       &ssc_proximity,
+       &ssc_light,
+       &ssc_accel,
+       &ssc_compass,
+#endif
 };
 
 static ReadingsUpdateFunc driver_type_to_callback_func (DriverType type);
@@ -128,6 +134,11 @@
        platform = g_udev_client_query_by_subsystem (client, "platform");
        devices = g_list_concat (devices, input);
        devices = g_list_concat (devices, platform);
+#ifdef HAS_LIBSSC
+       GList *fastrpc;
+       fastrpc = g_udev_client_query_by_subsystem (client, "misc");
+       devices = g_list_concat (devices, fastrpc);
+#endif
 
        /* Find the devices */
        for (l = devices; l != NULL; l = l->next) {
@@ -701,6 +712,16 @@
                      gpointer         user_data)
 {
        SensorData *data = user_data;
+       const gchar * const subsystems[] = {
+               "iio",
+               "input",
+               "platform",
+#ifdef HAS_LIBSSC
+               "misc",
+#endif
+               NULL
+    };
+       guint i;
 
        g_dbus_connection_register_object (connection,
                                           SENSOR_PROXY_DBUS_PATH,
@@ -718,6 +739,12 @@
                                           NULL,
                                           NULL);
 
+       /* Initialize DBus clients hash table before DBus is fully exposed */
+       data->client = g_udev_client_new (subsystems);
+
+       for (guint i = 0; i < NUM_SENSOR_TYPES; i++)
+               data->clients[i] = create_clients_hash_table ();
+
        data->connection = g_object_ref (connection);
 }
 
@@ -727,10 +754,8 @@
                       gpointer         user_data)
 {
        SensorData *data = user_data;
-       const gchar * const subsystems[] = { "iio", "input", "platform", NULL };
        guint i;
 
-       data->client = g_udev_client_new (subsystems);
        if (!find_sensors (data->client, data))
                goto bail;
 
@@ -740,7 +765,6 @@
        for (i = 0; i < NUM_SENSOR_TYPES; i++) {
                SensorDevice *sensor_device;
 
-               data->clients[i] = create_clients_hash_table ();
                data->sensor_startup_dbus_invocations_delayed[i] = 
g_ptr_array_new ();
 
                if (!driver_type_exists (data, i))
@@ -766,7 +790,7 @@
 
 bail:
        data->ret = 0;
-       g_debug ("No sensors or missing kernel drivers for the sensors");
+       g_message ("No sensors or missing kernel drivers for the sensors. 
Exiting");
        g_main_loop_quit (data->loop);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/src/meson.build 
new/iio-sensor-proxy-3.9/src/meson.build
--- old/iio-sensor-proxy-3.8/src/meson.build    2025-08-09 13:57:19.000000000 
+0200
+++ new/iio-sensor-proxy-3.9/src/meson.build    2026-03-02 20:19:51.000000000 
+0100
@@ -1,5 +1,8 @@
 config_h = configuration_data()
 config_h.set_quoted('VERSION', meson.project_version())
+if get_option('ssc-support').enabled()
+  config_h.set_quoted('HAS_LIBSSC', '1')
+endif
 config_h_files = configure_file(
   output: 'config.h',
   configuration: config_h
@@ -7,6 +10,10 @@
 
 deps = [ gio_dep, gudev_dep, mathlib_dep, polkit_gobject_dep ]
 
+if get_option('ssc-support').enabled()
+  deps = deps + [ libssc_dep ]
+endif
+
 resources = gnome.compile_resources(
     'iio-sensor-proxy-resources', 'iio-sensor-proxy.gresource.xml',
     c_name: 'iio_sensor_proxy',
@@ -38,6 +45,15 @@
   config_h_files,
 ]
 
+if get_option('ssc-support').enabled()
+  sources = sources + [
+    'drv-ssc-proximity.c',
+    'drv-ssc-light.c',
+    'drv-ssc-accel.c',
+    'drv-ssc-compass.c',
+  ]
+endif
+
 executable('iio-sensor-proxy',
   sources,
   dependencies: deps,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/tests/integration-test.py 
new/iio-sensor-proxy-3.9/tests/integration-test.py
--- old/iio-sensor-proxy-3.8/tests/integration-test.py  2025-08-09 
13:57:19.000000000 +0200
+++ new/iio-sensor-proxy-3.9/tests/integration-test.py  2026-03-02 
20:19:51.000000000 +0100
@@ -56,6 +56,7 @@
     def setUpClass(cls):
         # run from local build tree if we are in one, otherwise use system 
instance
         builddir = os.getenv('top_builddir', '.')
+        print(os.path.join(builddir, 'src', 'iio-sensor-proxy'))
         if os.access(os.path.join(builddir, 'src', 'iio-sensor-proxy'), 
os.X_OK):
             cls.daemon_path = os.path.join(builddir, 'src', 'iio-sensor-proxy')
             cls.monitor_sensor_path = os.path.join(builddir, 'src', 
'monitor-sensor')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/tests/meson.build 
new/iio-sensor-proxy-3.9/tests/meson.build
--- old/iio-sensor-proxy-3.8/tests/meson.build  2025-08-09 13:57:19.000000000 
+0200
+++ new/iio-sensor-proxy-3.9/tests/meson.build  2026-03-02 20:19:51.000000000 
+0100
@@ -16,3 +16,17 @@
          env: envs,
         )
 endforeach
+
+if get_option('ssc-support').enabled()
+    r = run_command(unittest_inspector, files('ssc-test.py'), check: true)
+    unit_tests = r.stdout().strip().split('\n')
+    foreach ut: unit_tests
+        ut_args = files('ssc-test.py')
+        ut_args += ut
+        test(ut,
+             python3,
+             args: ut_args,
+             env: envs,
+            )
+    endforeach
+endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iio-sensor-proxy-3.8/tests/ssc-test.py 
new/iio-sensor-proxy-3.9/tests/ssc-test.py
--- old/iio-sensor-proxy-3.8/tests/ssc-test.py  1970-01-01 01:00:00.000000000 
+0100
+++ new/iio-sensor-proxy-3.9/tests/ssc-test.py  2026-03-02 20:19:51.000000000 
+0100
@@ -0,0 +1,375 @@
+#!/usr/bin/python3
+
+# iio-sensor-proxy integration test suite
+#
+# Run in built tree to test local built binaries, or from anywhere else to test
+# system installed binaries.
+#
+# Copyright: (C) 2011 Martin Pitt <[email protected]>
+# (C) 2021 Bastien Nocera <[email protected]>
+#
+# 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.
+
+import os
+import sys
+import dbus
+import dbusmock
+import gi
+import tempfile
+import psutil
+import subprocess
+import unittest
+import locale
+import time
+
+try:
+    from gi.repository import GLib
+    from gi.repository import Gio
+except ImportError as e:
+    sys.stderr.write('PyGobject not available for Python 3, or missing GI 
typelibs: %s\n' % str(e))
+    sys.exit(1)
+
+try:
+    gi.require_version('UMockdev', '1.0')
+    from gi.repository import UMockdev
+except ImportError:
+    sys.stderr.write('umockdev not available 
(https://github.com/martinpitt/umockdev)\n')
+    sys.exit(1)
+
+
+SP = 'net.hadess.SensorProxy'
+SP_PATH = '/net/hadess/SensorProxy'
+SP_COMPASS = 'net.hadess.SensorProxy.Compass'
+SP_COMPASS_PATH = '/net/hadess/SensorProxy/Compass'
+
+class Tests(dbusmock.DBusTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        # run from local build tree if we are in one, otherwise use system 
instance
+        builddir = os.getenv('top_builddir', '.')
+        print(os.path.join(builddir, 'src', 'iio-sensor-proxy'))
+        if os.access(os.path.join(builddir, 'src', 'iio-sensor-proxy'), 
os.X_OK):
+            cls.daemon_path = os.path.join(builddir, 'src', 'iio-sensor-proxy')
+            cls.monitor_sensor_path = os.path.join(builddir, 'src', 
'monitor-sensor')
+            print('Testing binaries from local build tree (%s)' % 
cls.daemon_path)
+        elif os.environ.get('UNDER_JHBUILD', False):
+            jhbuild_prefix = os.environ['JHBUILD_PREFIX']
+            cls.daemon_path = os.path.join(jhbuild_prefix, 'libexec', 
'iio-sensor-proxy')
+            cls.monitor_sensor_path = os.path.join(jhbuild_prefix, 'bin', 
'monitor-sensor')
+            print('Testing binaries from JHBuild (%s)' % cls.daemon_path)
+        else:
+            cls.daemon_path = None
+            with open('/usr/lib/systemd/system/iio-sensor-proxy.service') as f:
+                for line in f:
+                    if line.startswith('ExecStart='):
+                        cls.daemon_path = line.split('=', 1)[1].strip()
+                        break
+            assert cls.daemon_path, 'could not determine daemon path from 
systemd .service file'
+            cls.monitor_sensor_path = '/usr/bin/monitor-sensor'
+            print('Testing installed system binary (%s)' % cls.daemon_path)
+
+        # fail on CRITICALs on client and server side
+        GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_WARNING |
+                                  GLib.LogLevelFlags.LEVEL_ERROR |
+                                  GLib.LogLevelFlags.LEVEL_CRITICAL)
+        os.environ['G_DEBUG'] = 'fatal_warnings'
+
+        # set up a fake system D-BUS
+        cls.test_bus = Gio.TestDBus.new(Gio.TestDBusFlags.NONE)
+        cls.test_bus.up()
+        try:
+            del os.environ['DBUS_SESSION_BUS_ADDRESS']
+        except KeyError:
+            pass
+        os.environ['DBUS_SYSTEM_BUS_ADDRESS'] = cls.test_bus.get_bus_address()
+
+        cls.dbus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
+        cls.dbus_con = cls.get_dbus(True)
+
+        # Some test outputs require the daemon to run under the fr locale:
+        # so check if that's available
+        try:
+            old_loc = locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8')
+            locale.setlocale(locale.LC_ALL, old_loc)
+           # We need to make sure the decimal point is correct as on musl libc 
the above
+           # succeeds yet the tests just fail due to the output being in 
unexpected format
+            cls.has_fr = locale.localeconv()["decimal_point"] == ","
+        except:
+            cls.has_fr = False
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.test_bus.down()
+        dbusmock.DBusTestCase.tearDownClass()
+
+    def setUp(self):
+        '''Set up a local umockdev testbed.
+
+        The testbed is initially empty.
+        '''
+        self.testbed = UMockdev.Testbed.new()
+        self.polkitd, obj_polkit = self.spawn_server_template(
+            'polkitd', {}, stdout=subprocess.PIPE)
+        obj_polkit.SetAllowed(['net.hadess.SensorProxy.claim-sensor'])
+
+        self.proxy = None
+        self.log = None
+        self.daemon = None
+
+    def run(self, result=None):
+        super(Tests, self).run(result)
+        if result and len(result.errors) + len(result.failures) > 0 and 
self.log:
+            with open(self.log.name) as f:
+                sys.stderr.write('\n-------------- daemon log: 
----------------\n')
+                sys.stderr.write(f.read())
+                sys.stderr.write('------------------------------\n')
+
+    def tearDown(self):
+        del self.testbed
+        self.stop_daemon()
+
+        if self.polkitd:
+            try:
+                self.polkitd.kill()
+            except OSError:
+                pass
+            self.polkitd.wait()
+        self.polkitd = None
+
+    #
+    # Daemon control and D-BUS I/O
+    #
+
+    def start_daemon(self, env = None, wrapper = None):
+        '''Start daemon and create DBus proxy.
+
+        When done, this sets self.proxy as the Gio.DBusProxy for 
power-profiles-daemon.
+        '''
+        if not env:
+            env = os.environ.copy()
+        env['G_DEBUG'] = 'fatal-criticals'
+        env['G_MESSAGES_DEBUG'] = 'all'
+        env['UMOCKDEV_DEBUG'] = 'all'
+        # note: Python doesn't propagate the setenv from Testbed.new(), so we
+        # have to do that ourselves
+        env['UMOCKDEV_DIR'] = self.testbed.get_root_dir()
+        self.log = tempfile.NamedTemporaryFile()
+        timeout_multiplier = 1
+        if wrapper:
+            daemon_path = wrapper + [ self.daemon_path ]
+        else:
+            daemon_path = [ self.daemon_path ]
+        if os.getenv('VALGRIND') != None:
+            daemon_path = ['valgrind'] + daemon_path + ['-v']
+            timeout_multiplier = 10
+        else:
+            daemon_path = daemon_path + ['-v']
+
+        self.daemon = subprocess.Popen(daemon_path,
+                                       env=env, stdout=self.log,
+                                       stderr=subprocess.STDOUT)
+
+        # wait until the daemon gets online
+        timeout = 100 * timeout_multiplier
+        while timeout > 0:
+            time.sleep(0.1)
+            timeout -= 1
+            try:
+                self.get_dbus_property('HasAccelerometer')
+                break
+            except GLib.GError:
+                pass
+        else:
+            self.fail('daemon did not start in 10 seconds')
+
+        self.proxy = Gio.DBusProxy.new_sync(
+            self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, SP,
+            SP_PATH, SP, None)
+
+        self.assertEqual(self.daemon.poll(), None, 'daemon crashed')
+
+    def stop_daemon(self):
+        '''Stop the daemon if it is running.'''
+
+        if self.daemon:
+            try:
+                for child in 
psutil.Process(self.daemon.pid).children(recursive=True):
+                    child.kill()
+                self.daemon.kill()
+            except OSError:
+                pass
+            self.daemon.wait()
+        self.daemon = None
+        self.proxy = None
+
+    def get_dbus_property(self, name):
+        '''Get property value from daemon D-Bus interface.'''
+
+        proxy = Gio.DBusProxy.new_sync(
+            self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, SP,
+            SP_PATH, 'org.freedesktop.DBus.Properties', None)
+        return proxy.Get('(ss)', SP, name)
+
+    def get_compass_dbus_property(self, name):
+        '''Get property value from daemon compass D-Bus interface.'''
+
+        proxy = Gio.DBusProxy.new_sync(
+            self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, SP,
+            SP_COMPASS_PATH, 'org.freedesktop.DBus.Properties', None)
+        return proxy.Get('(ss)', SP_COMPASS, name)
+
+    def have_text_in_log(self, text):
+        return self.count_text_in_log(text) > 0
+
+    def count_text_in_log(self, text):
+        with open(self.log.name) as f:
+            return f.read().count(text)
+
+    def read_sysfs_attr(self, device, attribute):
+        with open(os.path.join(self.testbed.get_root_dir() + device, 
attribute), 'rb') as f:
+            return f.read()
+        return None
+
+    def read_file(self, path):
+        with open(path, 'rb') as f:
+            return f.read()
+        return None
+
+    def assertEventually(self, condition, message=None, timeout=50):
+        '''Assert that condition function eventually returns True.
+
+        Timeout is in deciseconds, defaulting to 50 (5 seconds). message is
+        printed on failure.
+        '''
+        while timeout >= 0:
+            context = GLib.MainContext.default()
+            while context.iteration(False):
+                pass
+            if condition():
+                break
+            timeout -= 1
+            time.sleep(0.1)
+        else:
+            self.fail(message or 'timed out waiting for ' + str(condition))
+
+    #
+    # Actual test cases
+    #
+
+    @unittest.skip('Proximity SSC sensor is currently disabled via udev by 
default.')
+    def test_ssc_proximity(self):
+        '''SSC proximity'''
+        prox = self.testbed.add_device('misc', 'ssc-proximity', None,
+            ['name', 'SSC Test Proximity Sensor'],
+            ['NAME', '"SSC Proximity Sensor"',
+             'DEVNAME', '/dev/fastrpc-sdsp',
+             'IIO_SENSOR_PROXY_TYPE', 'ssc-proximity']
+        )
+        self.start_daemon()
+        self.assertEqual(self.get_dbus_property('HasAmbientLight'), False)
+        self.assertEqual(self.get_dbus_property('HasAccelerometer'), False)
+        self.assertEqual(self.get_dbus_property('HasProximity'), True)
+        self.assertEqual(self.get_compass_dbus_property('HasCompass'), False)
+
+        # Default values
+        self.assertEqual(self.get_dbus_property('ProximityNear'), False)
+
+        self.proxy.ClaimProximity()
+        self.assertEqual(self.get_dbus_property('ProximityNear'), True)
+        self.assertEventually(lambda: self.get_dbus_property('ProximityNear') 
== False)
+        self.assertEventually(lambda: self.get_dbus_property('ProximityNear') 
== True)
+
+        self.stop_daemon()
+
+    @unittest.skip('Accelerometer SSC sensor is currently disabled via udev by 
default.')
+    def test_ssc_accel(self):
+        '''SSC accelerometer'''
+        prox = self.testbed.add_device('misc', 'ssc-accel', None,
+            ['name', 'SSC Test Accelerometer Sensor'],
+            ['NAME', '"SSC Accelerometer Sensor"',
+             'DEVNAME', '/dev/fastrpc-sdsp',
+             'IIO_SENSOR_PROXY_TYPE', 'ssc-accel']
+        )
+        self.start_daemon()
+        self.assertEqual(self.get_dbus_property('HasAmbientLight'), False)
+        self.assertEqual(self.get_dbus_property('HasAccelerometer'), True)
+        self.assertEqual(self.get_dbus_property('HasProximity'), False)
+        self.assertEqual(self.get_compass_dbus_property('HasCompass'), False)
+
+        self.assertEqual(self.get_dbus_property('AccelerometerOrientation'), 
'undefined')
+
+        self.proxy.ClaimAccelerometer()
+        self.assertEqual(self.get_dbus_property('AccelerometerOrientation'), 
'left-up')
+
+        self.stop_daemon()
+
+    def test_ssc_light(self):
+        '''SSC light'''
+        prox = self.testbed.add_device('misc', 'ssc-light', None,
+            ['name', 'SSC Test Light Sensor'],
+            ['NAME', '"SSC Light Sensor"',
+             'DEVNAME', '/dev/fastrpc-sdsp',
+             'IIO_SENSOR_PROXY_TYPE', 'ssc-light']
+        )
+        self.start_daemon()
+        self.assertEqual(self.get_dbus_property('HasAmbientLight'), True)
+        self.assertEqual(self.get_dbus_property('HasAccelerometer'), False)
+        self.assertEqual(self.get_dbus_property('HasProximity'), False)
+        self.assertEqual(self.get_compass_dbus_property('HasCompass'), False)
+
+        # Default values
+        self.assertEqual(self.get_dbus_property('LightLevelUnit'), 'lux')
+        self.assertEqual(self.get_dbus_property('LightLevel'), 0)
+
+        self.proxy.ClaimLight()
+        self.assertEventually(lambda: self.get_dbus_property('LightLevel') == 
7)
+        self.assertEqual(self.get_dbus_property('LightLevelUnit'), 'lux')
+
+        self.stop_daemon()
+
+    def test_ssc_compass(self):
+        '''SSC compass'''
+        prox = self.testbed.add_device('misc', 'ssc-compass', None,
+            ['name', 'SSC Test Compass Sensor'],
+            ['NAME', '"SSC Compass Sensor"',
+             'DEVNAME', '/dev/fastrpc-sdsp',
+             'IIO_SENSOR_PROXY_TYPE', 'ssc-compass']
+        )
+        self.start_daemon()
+        self.assertEqual(self.get_dbus_property('HasAmbientLight'), False)
+        self.assertEqual(self.get_dbus_property('HasAccelerometer'), False)
+        self.assertEqual(self.get_dbus_property('HasProximity'), False)
+        self.assertEqual(self.get_compass_dbus_property('HasCompass'), True)
+        
self.assertEqual(int(self.get_compass_dbus_property('CompassHeading')), 0)
+
+        self.stop_daemon()
+
+    #
+    # Helper methods
+    #
+
+    @classmethod
+    def _props_to_str(cls, properties):
+        '''Convert a properties dictionary to uevent text representation.'''
+
+        prop_str = ''
+        if properties:
+            for k, v in properties.items():
+                prop_str += '%s=%s\n' % (k, v)
+        return prop_str
+
+if __name__ == '__main__':
+    # run ourselves under umockdev
+    if 'umockdev' not in os.environ.get('LD_PRELOAD', ''):
+        os.execvp('umockdev-wrapper', ['umockdev-wrapper'] + sys.argv)
+
+    unittest.main()

Reply via email to