Skip to content
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
/**
* @file mce-sensorfw.c
*
* Mode Control Entity - Interprocess communication with sensord
*
* <p>
*
* Copyright (C) 2013-2014 Jolla Ltd.
*
* <p>
*
* @author Simo Piiroinen <simo.piiroinen@jollamobile.com>
*
* mce is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* mce 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mce. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mce-sensorfw.h"
#include "mce.h"
#include "mce-log.h"
#include "mce-dbus.h"
#include "libwakelock.h"
#include <linux/input.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <inttypes.h>
/* ========================================================================= *
*
* Internal Layering - Top-Down
*
* ========================================================================= *
*
* SENSORFW_MODULE:
* - implements internal mce interface defined in mce-sensorfw.h
*
* SENSORFW_SERVICE:
* - state machine that tracks availablity of sensord on system bus
* - availalibility changes trigger activity in SENSORFW_PLUGIN
*
* SENSORFW_PLUGIN:
* - state machine that takes care of sensord plugin loading ipc
* - one instance / sensor
* - finishing plugin loading triggers activity in SENSORFW_SESSION
*
* SENSORFW_SESSION:
* - state machine that takes care of data session start ipc
* - one instance / sensor
* - acquiring a session id triggers activity in SENSORFW_CONNECTION
*
* SENSORFW_CONNECTION:
* - state machine that takes care of data connection with sensord
* - one instance / sensor
* - establishing a connection triggers activity in SENSORFW_OVERRIDE
* and SENSORFW_REPORTING
*
* SENSORFW_OVERRIDE:
* - state machine that takes care of standby override ipc
* - one instance / sensor
*
*
* SENSORFW_REPORTING:
* - state machine that takes care of sensor start/stop ipc
* - one instance / sensor
* - value changes reported via sensor specific SENSORFW_BACKEND
*
* SENSORFW_BACKEND:
* - contains all sensor specific constants and logic
*
* SENSORFW_NOTIFY:
* - manages cached sensor state
* - provides default values used when sensord is not available
* - feeds sensor data to upper level logic when state changes
* and/or listening callbacks are registered
*
* Error handling:
* - The layer where error occurred makes transition to ERROR state
* and all layers below that are reset to IDLE state and sensor
* states are reverted to sensord-is-not-available defaults.
* - The failed operation is reattempted after brief delay until it
* succeeds
* - Sensord restart might still be needed for full recovery.
*
* State transitions:
* - state transition diagram can be generated from mce-sensorfw.dot
* via installing graphviz package and running from command line
* dot -Tpng mce-sensorfw.dot -o mce-sensorfw.png
*
* ========================================================================= *
*
* Rough Data/Control Flow Diagram - Error Handling and EVDEV Input Excluded
*
* ========================================================================= *
*
* .--------------------. .--------------------.
* | MCE INIT/EXIT | | MCE SENSOR LOGIC |
* `--------------------' `--------------------'
* | |
* | init/quit enable/disable |
* | |
* v v
* .--------------------------------------------------------.
* | SENSORFW_MODULE |
* `--------------------------------------------------------'
* | | |
* | start | probe/reset enable/disable |
* | | |
* | v v
* | .---------------------------------------------------.
* | | SENSORFW_SERVICE |
* | `---------------------------------------------------'
* | | | | |
* | | start | load/reset set/unset | |
* | | | | | start/stop
* | | v | |
* | | .------------------------------. | |
* | | | SENSORFW_PLUGIN | | |
* | | `------------------------------' | |
* | | | | |
* | | | start/reset | |
* | | | | |
* | | v | |
* | | .------------------------------. | |
* | | | SENSORFW_SESSION | | |
* | | `------------------------------' | |
* | | | | |
* | | | connect/reset | |
* | | | | |
* | | v | |
* | | .------------------------------. | |
* | | | SENSORFW_CONNECTION | | |
* | | `------------------------------' | |
* | | | | | |
* | | | rethink/reset | | |
* | | | | | |
* | | | rethink/reset | | |
* | | | | | |
* | | | v v |
* | | | .--------------------------------. |
* | | | | SENSORFW_OVERRIDE | |
* | | | `--------------------------------' |
* | | v v
* | | .--------------------------------------------.
* | | | SENSORFW_REPORTING |
* | | `--------------------------------------------'
* | | |
* | | | initial/change/reset
* | | |
* | | v
* | | .--------------------------------------------.
* | | | SENSORFW_BACKEND |
* | | `--------------------------------------------'
* v v |
* .--------------------. | sensor state
* | SENSORFW_EXCEPTION | |
* `--------------------' |
* | |
* active | |
* v v
* .--------------------------------------------.
* | SENSORFW_NOTIFY |
* `--------------------------------------------'
* |
* | sensor state
* |
* v
* .--------------------------------------------.
* | MCE SENSOR LOGIC |
* `--------------------------------------------'
*
* ========================================================================= */
/** ID numbers for sensors supported by mce-sensorfwd module
*/
typedef enum
{
SFW_SENSOR_ID_PS,
SFW_SENSOR_ID_ALS,
SFW_SENSOR_ID_ORIENT,
SFW_SENSOR_ID_ACCELEROMETER,
SFW_SENSOR_ID_COMPASS,
SFW_SENSOR_ID_GYROSCOPE,
SFW_SENSOR_ID_LID,
SFW_SENSOR_ID_HUMIDITY,
SFW_SENSOR_ID_MAGNETOMETER,
SFW_SENSOR_ID_PRESSURE,
SFW_SENSOR_ID_ROTATION,
SFW_SENSOR_ID_STEPCOUNTER,
SFW_SENSOR_ID_TAP,
SFW_SENSOR_ID_TEMPERATURE,
SFW_SENSOR_ID_COUNT
} sensor_id_t;
static bool
sensor_id_available(sensor_id_t id)
{
bool available = true;
switch( id ) {
case SFW_SENSOR_ID_PS:
case SFW_SENSOR_ID_ALS:
case SFW_SENSOR_ID_ORIENT:
break;
default:
available = mce_in_sensortest_mode();
break;
}
return available;
}
/* ========================================================================= *
* D-BUS CONSTANTS FOR D-BUS DAEMON
* ========================================================================= */
/** org.freedesktop.DBus.NameOwnerChanged D-Bus signal */
#define DBUS_SIGNAL_NAME_OWNER_CHANGED "NameOwnerChanged"
#define DBUS_METHOD_GET_NAME_OWNER "GetNameOwner"
/* ========================================================================= *
* D-BUS CONSTANTS FOR SENSORD SERVICE
* ========================================================================= */
/** How long to wait before retrying failed sensorfw dbus requests */
#define SENSORFW_RETRY_DELAY_MS 10000
/** D-Bus name of the sensord service */
#define SENSORFW_SERVICE "com.nokia.SensorService"
// ----------------------------------------------------------------
/** D-Bus object path for sensord sensor manager */
#define SENSORFW_MANAGER_OBJECT "/SensorManager"
/** D-Bus interface used by sensor manager */
#define SENSORFW_MANAGER_INTEFCACE "local.SensorManager"
/** D-Bus method for loading sensor plugin */
#define SENSORFW_MANAGER_METHOD_LOAD_PLUGIN "loadPlugin"
/** D-Bus method for starting sensor session */
#define SENSORFW_MANAGER_METHOD_START_SESSION "requestSensor"
// ----------------------------------------------------------------
/* D-Bus interfaces for accessing sensor specific data
*
* Note: Sensorfwd uses separate interface for each sensor. */
#define SFW_SENSOR_INTERFACE_PS "local.ProximitySensor"
#define SFW_SENSOR_INTERFACE_ALS "local.ALSSensor"
#define SFW_SENSOR_INTERFACE_ORIENT "local.OrientationSensor"
#define SFW_SENSOR_INTERFACE_ACCELEROMETER "local.AccelerometerSensor"
#define SFW_SENSOR_INTERFACE_COMPASS "local.CompassSensor"
#define SFW_SENSOR_INTERFACE_GYROSCOPE "local.GyroscopeSensor"
#define SFW_SENSOR_INTERFACE_LID "local.LidSensor"
#define SFW_SENSOR_INTERFACE_HUMIDITY "local.HumiditySensor"
#define SFW_SENSOR_INTERFACE_MAGNETOMETER "local.MagnetometerSensor"
#define SFW_SENSOR_INTERFACE_PRESSURE "local.PressureSensor"
#define SFW_SENSOR_INTERFACE_ROTATION "local.RotationSensor"
#define SFW_SENSOR_INTERFACE_STEPCOUNTER "local.StepcounterSensor"
#define SFW_SENSOR_INTERFACE_TAP "local.TapSensor"
#define SFW_SENSOR_INTERFACE_TEMPERATURE "local.TemperatureSensor"
/** D-Bus method for enabling sensor
*
* @Note All sensor specific interfaces have start method.
*/
#define SFW_SENSOR_METHOD_START "start"
/** D-Bus method for disabling sensor
*
* @Note All sensor specific interfaces have stop method.
*/
#define SFW_SENSOR_METHOD_STOP "stop"
/** D-Bus method for changing sensor standby override
*
* @Note All sensor specific interfaces have have this method,
* but unless it is actually explicitly implemented, a
* virtual dummy method call handler gets invoked and
* it will just return "false".
*/
#define SFW_SENSOR_METHOD_SET_OVERRIDE "setStandbyOverride"
/* D-Bus methods for getting current sensor value
*
* The method name and returned data varies from one sensor to
* another, and in some cases there is no "current state" to
* query (such as tap detection sensor which emits events).
*/
#define SFW_SENSOR_METHOD_READ_PS "proximity"
#define SFW_SENSOR_METHOD_READ_ALS "lux"
#define SFW_SENSOR_METHOD_READ_ORIENT "orientation"
#define SFW_SENSOR_METHOD_READ_ACCELEROMETER "xyz"
#define SFW_SENSOR_METHOD_READ_COMPASS "value" // or "declinationvalue"?
#define SFW_SENSOR_METHOD_READ_GYROSCOPE "value"
#define SFW_SENSOR_METHOD_READ_LID "closed"
#define SFW_SENSOR_METHOD_READ_HUMIDITY "relativeHumidity"
#define SFW_SENSOR_METHOD_READ_MAGNETOMETER "magneticField"
#define SFW_SENSOR_METHOD_READ_PRESSURE "pressure"
#define SFW_SENSOR_METHOD_READ_ROTATION "rotation"
#define SFW_SENSOR_METHOD_READ_STEPCOUNTER "steps"
#define SFW_SENSOR_METHOD_READ_TAP NULL // event, not state
#define SFW_SENSOR_METHOD_READ_TEMPERATURE "temperature"
// ----------------------------------------------------------------
/** Connect path to sensord data unix domain socket */
#define SENSORFW_DATA_SOCKET "/run/sensord.sock"
// ----------------------------------------------------------------
/* Sensor names used by senseofwd */
#define SFW_SENSOR_NAME_PS "proximitysensor"
#define SFW_SENSOR_NAME_ALS "alssensor"
#define SFW_SENSOR_NAME_ORIENT "orientationsensor"
#define SFW_SENSOR_NAME_ACCELEROMETER "accelerometersensor"
#define SFW_SENSOR_NAME_COMPASS "compasssensor"
#define SFW_SENSOR_NAME_GYROSCOPE "gyroscopesensor"
#define SFW_SENSOR_NAME_LID "lidsensor"
#define SFW_SENSOR_NAME_HUMIDITY "humiditysensor"
#define SFW_SENSOR_NAME_MAGNETOMETER "magnetometersensor"
#define SFW_SENSOR_NAME_PRESSURE "pressuresensor"
#define SFW_SENSOR_NAME_ROTATION "rotationsensor"
#define SFW_SENSOR_NAME_STEPCOUNTER "stepcountersensor"
#define SFW_SENSOR_NAME_TAP "tapsensor"
#define SFW_SENSOR_NAME_TEMPERATURE "temperaturesensor"
// ----------------------------------------------------------------
/* ========================================================================= *
* FORWARD_DECLARATIONS
* ========================================================================= */
typedef struct sfw_service_t sfw_service_t;
typedef struct sfw_plugin_t sfw_plugin_t;
typedef struct sfw_session_t sfw_session_t;
typedef struct sfw_connection_t sfw_connection_t;
typedef struct sfw_override_t sfw_override_t;
typedef struct sfw_reporting_t sfw_reporting_t;
typedef struct sfw_backend_t sfw_backend_t;
typedef struct sfw_sample_als_t sfw_sample_als_t;
typedef struct sfw_sample_ps_t sfw_sample_ps_t;
typedef struct sfw_sample_orient_t sfw_sample_orient_t;
typedef struct sfw_sample_accelerometer_t sfw_sample_accelerometer_t;
typedef struct sfw_sample_compass_t sfw_sample_compass_t;
typedef struct sfw_sample_gyroscope_t sfw_sample_gyroscope_t;
typedef struct sfw_sample_lid_t sfw_sample_lid_t;
typedef struct sfw_sample_humidity_t sfw_sample_humidity_t;
typedef struct sfw_sample_magnetometer_t sfw_sample_magnetometer_t;
typedef struct sfw_sample_pressure_t sfw_sample_pressure_t;
typedef struct sfw_sample_rotation_t sfw_sample_rotation_t;
typedef struct sfw_sample_stepcounter_t sfw_sample_stepcounter_t;
typedef struct sfw_sample_tap_t sfw_sample_tap_t;
typedef struct sfw_sample_temperature_t sfw_sample_temperature_t;
/* ========================================================================= *
* SENSORFW_NOTIFY
* ========================================================================= */
/** Proximity state to use when sensor can't be enabled
*
* This must be "uncovered" so that absense of or failures within
* sensord do not make the device unusable due to proximity values
* blocking display power up and touch input.
*/
#define SFW_NOTIFY_DEFAULT_PS false
/** Proximity state to use when waiting for sensord startup
*
* This must be "covered" so that we do not prematurely unblock
* touch input / allow display power up during bootup and during
* sensord restarts.
*/
#define SFW_NOTIFY_EXCEPTION_PS true
/** Ambient light level [lux] to use when sensor can't be enabled */
#define SFW_NOTIFY_DEFAULT_ALS 400
/** Orientation state to use when sensor can't be enabled */
#define SFW_NOTIFY_DEFAULT_ORIENT MCE_ORIENTATION_UNDEFINED
/** Dummy sensor value to use when re-sending cached state data */
#define SFW_NOTIFY_DUMMY 0
typedef enum
{
/** Cached sensor state should be reset to default value */
NOTIFY_RESET,
/** Cached sensor state should be restored from last-known value */
NOTIFY_RESTORE,
/** Cached sensor state should be sent again */
NOTIFY_REPEAT,
/** Sensor state was received from evdev source */
NOTIFY_EVDEV,
/** Sensor state was received from sensord */
NOTIFY_SENSORD,
/** Flush cached state */
NOTIFY_FORGET,
NOTIFY_NUMTYPES
} sfw_notify_t;
static const char *sfw_notify_name (sfw_notify_t type);
static gboolean sfw_name_owner_changed_cb (DBusMessage *const msg);
/* ========================================================================= *
* SENSORD_DATA_TYPES
* ========================================================================= */
/** ALS data block as sensord sends them */
struct sfw_sample_als_t
{
/** microseconds, monotonic */
uint64_t als_timestamp;
/** amount of light [lux] */
uint32_t als_value;
};
static const char *sfw_sample_als_repr(const sfw_sample_als_t *self);
/** PS data block as sensord sends them */
struct sfw_sample_ps_t
{
/** microseconds, monotonic */
uint64_t ps_timestamp;
/** distance of blocking object [cm] */
uint32_t ps_value;
/** sensor covered [bool]
*
* This should be the size of a C++ bool on the same platform.
* Unfortunately there's no way to find out in a C program
*/
uint8_t ps_withinProximity;
};
static const char *sfw_sample_ps_repr(const sfw_sample_ps_t *self);
/** Orientation data block as sensord sends them */
struct sfw_sample_orient_t
{
/* microseconds, monotonic */
uint64_t orient_timestamp;
/* orientation [enum orientation_state_t] */
int32_t orient_state;
};
static const char *sfw_sample_orient_repr(const sfw_sample_orient_t *self);
typedef enum sfw_lid_type_t
{
SFW_LID_TYPE_UNKNOWN = -1, // UnknownLid
SFW_LID_TYPE_FRONT = 0, // FrontLid
SFW_LID_TYPE_BACK = 1, // BackLid
} sfw_lid_type_t;
static const char *sfw_lid_type_repr(sfw_lid_type_t type);
typedef enum sfw_tap_direction_t
{
/** Left or right side tapped */
SFW_TAP_DIRECTION_X = 0,
/** Top or down side tapped */
SFW_TAP_DIRECTION_Y = 1,
/** Face or bottom tapped */
SFW_TAP_DIRECTION_Z = 2,
/** Tapped from left to right */
SFW_TAP_DIRECTION_LEFT_RIGHT = 3,
/** Tapped from right to left */
SFW_TAP_DIRECTION_RIGHT_LEFT = 4,
/** Tapped from top to bottom */
SFW_TAP_DIRECTION_TOP_BOTTOM = 5,
/** Tapped from bottom to top */
SFW_TAP_DIRECTION_BOTTOM_TOP = 6,
/** Tapped from face to back */
SFW_TAP_DIRECTION_FACE_BACK = 7,
/** Tapped from back to face */
SFW_TAP_DIRECTION_BACK_FACE = 8,
} sfw_tap_direction_t;
static const char *sfw_tap_direction_repr(sfw_tap_direction_t direction);
typedef enum sfw_tap_type_t
{
/** placeholder */
SFW_TAP_TYPE_NONE = -1,
/** Double tap. */
SFW_TAP_TYPE_DOUBLE_TAP = 0,
/**< Single tap. */
SFW_TAP_TYPE_SINGLE_TAP = 1,
} sfw_tap_type_t;
static const char * sfw_tap_type_repr(sfw_tap_type_t type);
typedef struct sfw_xyz_t
{
int32_t x,y,z;
} sfw_xyz_t;
struct sfw_sample_accelerometer_t
{
/** microseconds, monotonic */
uint64_t accelerometer_timestamp;
/** amount of TBD */
sfw_xyz_t accelerometer_xyz;
};
static const char *sfw_sample_accelerometer_repr(const sfw_sample_accelerometer_t *self);
struct sfw_sample_compass_t
{
/** microseconds, monotonic */
uint64_t compass_timestamp;
/** Angle to north which may be declination corrected or not. This is the value apps should use */
int32_t compass_degrees;
/** Angle to north without declination correction */
int32_t compass_raw_degrees;
/** Declination corrected angle to north */
int32_t compass_corrected_degrees;
/** Magnetometer calibration level. Higher value means better calibration. */
int32_t compass_level;
};
static const char *sfw_sample_compass_repr(const sfw_sample_compass_t *self);
struct sfw_sample_gyroscope_t
{
/** microseconds, monotonic */
uint64_t gyroscope_timestamp;
/** amount of TBD */
sfw_xyz_t gyroscope_xyz;
};
static const char *sfw_sample_gyroscope_repr(const sfw_sample_gyroscope_t *self);
struct sfw_sample_lid_t
{
/** microseconds, monotonic */
uint64_t lid_timestamp;
/** amount of TBD */
int32_t lid_type; // sfw_lid_type_t
uint32_t lid_value;
};
static const char *sfw_sample_lid_repr(const sfw_sample_lid_t *self);
struct sfw_sample_humidity_t
{
/** microseconds, monotonic */
uint64_t humidity_timestamp;
/** amount of TBD */
uint32_t humidity_value;
};
static const char *sfw_sample_humidity_repr(const sfw_sample_humidity_t *self);
struct sfw_sample_magnetometer_t
{
/** microseconds, monotonic */
uint64_t magnetometer_timestamp;
/** X coordinate value */
int32_t magnetometer_x;
/** Y coordinate value */
int32_t magnetometer_y;
/** Z coordinate value */
int32_t magnetometer_z;
/** raw X coordinate value */
int32_t magnetometer_rx;
/** raw Y coordinate value */
int32_t magnetometer_ry;
/** raw Z coordinate value */
int32_t magnetometer_rz;
/** Magnetometer calibration level. Higher value means better calibration. */
int32_t magnetometer_level;
};
static const char *sfw_sample_magnetometer_repr(const sfw_sample_magnetometer_t *self);
struct sfw_sample_pressure_t
{
/** microseconds, monotonic */
uint64_t pressure_timestamp;
/** amount of TBD */
uint32_t pressure_value;
};
static const char *sfw_sample_pressure_repr(const sfw_sample_pressure_t *self);
struct sfw_sample_rotation_t
{
/** microseconds, monotonic */
uint64_t rotation_timestamp;
/** amount of TBD */
sfw_xyz_t rotation_xyz;
};
static const char *sfw_sample_rotation_repr(const sfw_sample_rotation_t *self);
struct sfw_sample_stepcounter_t
{
/** microseconds, monotonic */
uint64_t stepcounter_timestamp;
/** amount of TBD */
uint32_t stepcounter_value;
};
static const char *sfw_sample_stepcounter_repr(const sfw_sample_stepcounter_t *self);
struct sfw_sample_tap_t
{
/** microseconds, monotonic */
uint64_t tap_timestamp;
/** amount of TBD */
uint32_t tap_direction; // sfw_tap_direction_t
int32_t tap_type; // sfw_tap_type_t
};
static const char *sfw_sample_tap_repr(const sfw_sample_tap_t *self);
struct sfw_sample_temperature_t
{
/** microseconds, monotonic */
uint64_t temperature_timestamp;
/** amount of TBD */
uint32_t temperature_value;
};
static const char *sfw_sample_temperature_repr(const sfw_sample_temperature_t *self);
/* ========================================================================= *
* SENSORFW_BACKEND
* ========================================================================= */
/** Callback function type: parsing initial value reply */
typedef bool (*sfw_value_fn)(sfw_plugin_t *plugin, DBusMessageIter *data);
/** Callback function type: value change reporting */
typedef void (*sfw_sample_fn)(sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
/** Sensor specific data and callbacks */
struct sfw_backend_t
{
/** Name of the sensor as expected by sensord */
const char *be_sensor_name;
/** D-Bus object path for the sensor, or NULL to construct default one */
const char *be_sensor_object;
/** D-Bus interface for the sensor */
const char *be_sensor_interface;
/** Size of sensor data blobs sensord will be sending */
size_t be_sample_size;
/** Callback for handling initial value reply */
sfw_value_fn be_value_cb;
/** Callback for handling sensor data blob */
sfw_sample_fn be_sample_cb;
/** D-Bus method name for querying the initial sensor value */
const char *be_value_method;
};
static bool sfw_backend_parse_data (DBusMessageIter *data, int arg_type, ...);
static bool sfw_backend_als_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_ps_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_orient_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_accelerometer_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_compass_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_gyroscope_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_lid_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_humidity_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_magnetometer_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_pressure_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_rotation_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_stepcounter_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_tap_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static bool sfw_backend_temperature_value_cb (sfw_plugin_t *plugin, DBusMessageIter *data);
static void sfw_backend_als_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_ps_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_orient_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_accelerometer_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_compass_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_gyroscope_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_lid_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_humidity_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_magnetometer_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_pressure_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_rotation_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_stepcounter_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_tap_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
static void sfw_backend_temperature_sample_cb (sfw_plugin_t *plugin, sfw_notify_t type, const void *sample);
/* ========================================================================= *
* SENSORFW_HELPERS
* ========================================================================= */
static bool sfw_socket_set_blocking (int fd, bool blocking);
static int sfw_socket_open (void);
static guint sfw_socket_add_notify (int fd, bool close_on_unref, GIOCondition cnd, GIOFunc io_cb, gpointer aptr);
/* ========================================================================= *
* SENSORFW_REPORTING
* ========================================================================= */
typedef enum
{
/** Initial state used before availability of sensord is known */
REPORTING_INITIAL,
/** Sensord is not available */
REPORTING_IDLE,
/** Choose between start() and stop() */
REPORTING_RETHINK,
/** Waiting a reply to start() */
REPORTING_ENABLING,
/** Sensor started succesfully */
REPORTING_ENABLED,
/** Waiting a reply to stop() */
REPORTING_DISABLING,
/** Sensor stopped succesfully */
REPORTING_DISABLED,
/** Something went wrong */
REPORTING_ERROR,
REPORTING_NUMSTATES
} sfw_reporting_state_t;
/** State machine for handling sensor start/stop */
struct sfw_reporting_t
{
/** Pointer to containing plugin object */
sfw_plugin_t *rep_plugin;
/** Current reporting state */
sfw_reporting_state_t rep_state;
/** Pending start/stop dbus method call */
DBusPendingCall *rep_change_pc;
/** Pending initial value dbus method call */
DBusPendingCall *rep_value_pc;
/** Flag for: MCE wants sensor to be enabled */
bool rep_target;
/** Timer for: Retry after ipc error */
guint rep_retry_id;
};
static const char *sfw_reporting_state_name (sfw_reporting_state_t state);
static sfw_reporting_t *sfw_reporting_create (sfw_plugin_t *plugin);
static void sfw_reporting_delete (sfw_reporting_t *self);
static void sfw_reporting_cancel_change (sfw_reporting_t *self);
static void sfw_reporting_cancel_value (sfw_reporting_t *self);
static void sfw_reporting_cancel_retry (sfw_reporting_t *self);
static void sfw_reporting_trans (sfw_reporting_t *self, sfw_reporting_state_t state);
static void sfw_reporting_change_cb (DBusPendingCall *pc, void *aptr);
static void sfw_reporting_value_cb (DBusPendingCall *pc, void *aptr);
static gboolean sfw_reporting_retry_cb (gpointer aptr);
static void sfw_reporting_do_rethink (sfw_reporting_t *self);
static void sfw_reporting_do_start (sfw_reporting_t *self);
static void sfw_reporting_do_reset (sfw_reporting_t *self);
static void sfw_reporting_set_target (sfw_reporting_t *self, bool enable);
/* ========================================================================= *
* SENSORFW_OVERRIDE
* ========================================================================= */
typedef enum {
/** Initial state used before availability of sensord is known */
OVERRIDE_INITIAL,
/** Sensord is not available */
OVERRIDE_IDLE,
/** Choose between standby override set/unset */
OVERRIDE_RETHINK,
/** Waiting for a reply to set standby override */
OVERRIDE_ENABLING,
/** Standby override succesfully set */
OVERRIDE_ENABLED,
/** Waiting for a reply to unset standby override */
OVERRIDE_DISABLING,
/** Standby override succesfully unset */
OVERRIDE_DISABLED,
/** Something went wrong */
OVERRIDE_ERROR,
/** Not supported */
OVERRIDE_NA,
OVERRIDE_NUMSTATES
} sfw_override_state_t;
/** State machine for handling sensor standby override */
struct sfw_override_t
{
/** Pointer to containing plugin object */
sfw_plugin_t *ovr_plugin;
/** Current override state */
sfw_override_state_t ovr_state;
/** Pending standby override set/unset method call */
DBusPendingCall *ovr_start_pc;
/** Flag for: MCE wants standby override to be set */
bool ovr_target;
/** Timer for: Retry after ipc error */
guint ovr_retry_id;
};
static const char *sfw_override_state_name (sfw_override_state_t state);
static sfw_override_t *sfw_override_create (sfw_plugin_t *plugin);
static void sfw_override_delete (sfw_override_t *self);
static void sfw_override_cancel_start (sfw_override_t *self);
static void sfw_override_cancel_retry (sfw_override_t *self);
static void sfw_override_trans (sfw_override_t *self, sfw_override_state_t state);
static void sfw_override_start_cb (DBusPendingCall *pc, void *aptr);
static gboolean sfw_override_retry_cb (gpointer aptr);
static void sfw_override_do_rethink (sfw_override_t *self);
static void sfw_override_do_start (sfw_override_t *self);
static void sfw_override_do_reset (sfw_override_t *self);
static void sfw_override_set_target (sfw_override_t *self, bool enable);
/* ========================================================================= *
* SENSORFW_CONNECTION
* ========================================================================= */
typedef enum
{
/** Initial state used before availability of sensord is known */
CONNECTION_INITIAL,
/** Sensord is not available */
CONNECTION_IDLE,
/** Waiting for data socket to come writable */
CONNECTION_CONNECTING,
/** Waiting for handshake reply */
CONNECTION_REGISTERING,
/** Waiting for sensor data */
CONNECTION_CONNECTED,
/** Something went wrong */
CONNECTION_ERROR,
CONNECTION_NUMSTATES
} sfw_connection_state_t;
static const char *sfw_connection_state_name (sfw_connection_state_t state);
/** State machine for handling sensor data connection */
struct sfw_connection_t
{
/** Pointer to containing plugin object */
sfw_plugin_t *con_plugin;
/** Current connection state */
sfw_connection_state_t con_state;
/** File descriptor for data socket */
int con_fd;
/** I/O watch id id for: ready to write */
guint con_rx_id;
/** I/O watch id id for: data available */
guint con_tx_id;
/** Timer for: Retry after ipc error */
guint con_retry_id;
};
static sfw_connection_t *sfw_connection_create (sfw_plugin_t *plugin);
static void sfw_connection_delete (sfw_connection_t *self);
static bool sfw_connection_handle_samples (sfw_connection_t *self, char *data, size_t size);
static int sfw_connection_get_session_id (const sfw_connection_t *self);
static bool sfw_connection_tx_req (sfw_connection_t *self);
static bool sfw_connection_rx_ack (sfw_connection_t *self);
static bool sfw_connection_rx_dta (sfw_connection_t *self);
static gboolean sfw_connection_tx_cb (GIOChannel *chn, GIOCondition cnd, gpointer aptr);
static gboolean sfw_connection_rx_cb (GIOChannel *chn, GIOCondition cnd, gpointer aptr);
static void sfw_connection_remove_tx_notify(sfw_connection_t *self);
static void sfw_connection_remove_rx_notify(sfw_connection_t *self);
static void sfw_connection_close_socket (sfw_connection_t *self);
static bool sfw_connection_open_socket (sfw_connection_t *self);
static gboolean sfw_connection_retry_cb (gpointer aptr);
static void sfw_connection_cancel_retry (sfw_connection_t *self);
static void sfw_connection_trans (sfw_connection_t *self, sfw_connection_state_t state);
static void sfw_connection_do_start (sfw_connection_t *self);
static void sfw_connection_do_reset (sfw_connection_t *self);
/* ========================================================================= *
* SENSORFW_SESSION
* ========================================================================= */
typedef enum
{
/** Initial state used before availability of sensord is known */
SESSION_INITIAL,
/** Sensord is not available */
SESSION_IDLE,
/** Waiting for session id reply */
SESSION_REQUESTING,
/** Have a session id */
SESSION_ACTIVE,
/** Something went wrong */
SESSION_ERROR,
/** Sensor is not supported */
SESSION_INVALID,
SESSION_NUMSTATES
} sfw_session_state_t;
/** State machine for handling sensor data session */
struct sfw_session_t
{
/** Pointer to containing plugin object */
sfw_plugin_t *ses_plugin;
/** Current session state */
sfw_session_state_t ses_state;
/** Pending session start dbus method call */
DBusPendingCall *ses_start_pc;
/** Session ID received from sensord */
dbus_int32_t ses_id;
/** Timer for: Retry after ipc error */
guint ses_retry_id;
};
/** Sensor not supported session id from sensorfwd */
#define SESSION_ID_INVALID (-1)
/** Placeholder value for session id not parsed yet */
#define SESSION_ID_UNKNOWN (-2)
static const char *sfw_session_state_name (sfw_session_state_t state);
static sfw_session_t *sfw_session_create (sfw_plugin_t *plugin);
static void sfw_session_delete (sfw_session_t *self);
static int sfw_session_get_id (const sfw_session_t *self);
static void sfw_session_cancel_start (sfw_session_t *self);
static void sfw_session_cancel_retry (sfw_session_t *self);
static void sfw_session_trans (sfw_session_t *self, sfw_session_state_t state);
static void sfw_session_start_cb (DBusPendingCall *pc, void *aptr);
static gboolean sfw_session_retry_cb (gpointer aptr);
static void sfw_session_do_start (sfw_session_t *self);
static void sfw_session_do_reset (sfw_session_t *self);
/* ========================================================================= *
* SENSORFW_PLUGIN
* ========================================================================= */
typedef enum
{
/** Initial state used before availability of sensord is known */
PLUGIN_INITIAL,
/** Sensord is not available */
PLUGIN_IDLE,
/** Waiting for a reply to plugin load method call */
PLUGIN_LOADING,
/** Sensor plugin is loaded */
PLUGIN_LOADED,
/** Something went wrong */
PLUGIN_ERROR,
/** Plugin not available */
PLUGIN_NA,
PLUGIN_NUMSTATES
} sfw_plugin_state_t;
/** State machine for handling sensor plugin loading */
struct sfw_plugin_t
{
/** Sensor specific backend data & callbacks */
const sfw_backend_t *plg_backend;
/** Default sensor specific D-BUs object path
*
* Constructed if backend does not define one explicitly */
char *plg_sensor_object;
/** Current plugin state */
sfw_plugin_state_t plg_state;
/** Pending plugin load dbus method call */
DBusPendingCall *plg_load_pc;
/** Session state machine object */
sfw_session_t *plg_session;
/** Connection state machine object */
sfw_connection_t *plg_connection;
/** Standby override state machine object */
sfw_override_t *plg_override;
/** Sensor reporting state machine object */
sfw_reporting_t *plg_reporting;
/** Timer for: Retry after ipc error */
guint plg_retry_id;
};
static const char *sfw_plugin_state_name (sfw_plugin_state_t state);
static sfw_plugin_t *sfw_plugin_create (const sfw_backend_t *backend);
static void sfw_plugin_delete (sfw_plugin_t *self);
static void sfw_plugin_enable_sensor (sfw_plugin_t *self, bool enable);
static const char *sfw_plugin_get_sensor_name (const sfw_plugin_t *self);
static const char *sfw_plugin_get_sensor_object (const sfw_plugin_t *self);
static const char *sfw_plugin_get_sensor_interface(const sfw_plugin_t *self);
static int sfw_plugin_get_session_id (const sfw_plugin_t *self);
static const char *sfw_plugin_get_value_method (const sfw_plugin_t *self);
static size_t sfw_plugin_get_sample_size (const sfw_plugin_t *self);
static void sfw_plugin_handle_sample (sfw_plugin_t *self, const void *sample);
static bool sfw_plugin_handle_value (sfw_plugin_t *self, DBusMessageIter *data);
static void sfw_plugin_reset_value (sfw_plugin_t *self);
static void sfw_plugin_repeat_value (sfw_plugin_t *self);
static void sfw_plugin_restore_value (sfw_plugin_t *self);
static void sfw_plugin_forget_value (sfw_plugin_t *self);
static void sfw_plugin_cancel_load (sfw_plugin_t *self);
static void sfw_plugin_cancel_retry (sfw_plugin_t *self);
static void sfw_plugin_trans (sfw_plugin_t *self, sfw_plugin_state_t state);
static void sfw_plugin_load_cb (DBusPendingCall *pc, void *aptr);
static gboolean sfw_plugin_retry_cb (gpointer aptr);
static void sfw_plugin_do_load (sfw_plugin_t *self);
static void sfw_plugin_do_reset (sfw_plugin_t *self);
static void sfw_plugin_do_session_start (sfw_plugin_t *self);
static void sfw_plugin_do_session_reset (sfw_plugin_t *self);
static void sfw_plugin_do_connection_start (sfw_plugin_t *self);
static void sfw_plugin_do_connection_reset (sfw_plugin_t *self);
static void sfw_plugin_do_override_start (sfw_plugin_t *self);
static void sfw_plugin_do_override_reset (sfw_plugin_t *self);
static void sfw_plugin_do_reporting_start (sfw_plugin_t *self);
static void sfw_plugin_do_reporting_reset (sfw_plugin_t *self);
/* ========================================================================= *
* SENSORFW_SERVICE
* ========================================================================= */
typedef enum
{
/** Sensord availability is not known */
SERVICE_UNKNOWN,
/** Waiting for a reply to name owner query */
SERVICE_QUERYING,
/** Sensord service is available */
SERVICE_RUNNING,
/** Sensord service is not available */
SERVICE_STOPPED,
SERVICE_NUMSTATES
} sfw_service_state_t;
/** State machine for handling sensord service availability tracking */
struct sfw_service_t
{
/** Sensord service tracking state */
sfw_service_state_t srv_state;
/** Pending name owner dbus method call */
DBusPendingCall *srv_query_pc;
/** State machine objects for sensors */
sfw_plugin_t *srv_plugin[SFW_SENSOR_ID_COUNT];
};
static const char *sfw_service_state_name (sfw_service_state_t state);
static sfw_service_t *sfw_service_create (void);
static void sfw_service_delete (sfw_service_t *self);
static void sfw_service_cancel_query (sfw_service_t *self);
static void sfw_service_query_cb (DBusPendingCall *pc, void *aptr);
static void sfw_service_trans (sfw_service_t *self, sfw_service_state_t state);
static void sfw_service_do_start (sfw_service_t *self);
static void sfw_service_do_stop (sfw_service_t *self);
static void sfw_service_do_query (sfw_service_t *self);
static sfw_plugin_t *sfw_service_plugin (const sfw_service_t *self, sensor_id_t id);
static void sfw_service_set_sensor (const sfw_service_t *self, sensor_id_t id, bool enable);
/* ========================================================================= *
* SENSORFW_EXCEPTION
* ========================================================================= */
/** Durations for enforcing use of exceptional sensor values */
typedef enum {
/** Expected time until sensord availability is known */
SFW_EXCEPTION_LENGTH_MCE_STARTING_UP = 30 * 1000,
/** Expected time until data from sensord is available */
SFW_EXCEPTION_LENGTH_SENSORD_RUNNING = 2 * 1000,
/** Expected time until sensord gets (re)started */
SFW_EXCEPTION_LENGTH_SENSORD_STOPPED = 5 * 1000,
} sfw_exception_delay_t;
static gboolean sfw_exception_timer_cb (gpointer aptr);
static void sfw_exception_cancel (void);
static void sfw_exception_start (sfw_exception_delay_t delay_ms);
static bool sfw_exception_is_active (void);
/* ========================================================================= *
* SENSORFW_MODULE
* ========================================================================= */
/** Sensord availability tracking state machine object */
static sfw_service_t *sfw_service = 0;
/** Proximity change callback used for notifying upper level logic */
static void (*sfw_notify_ps_cb)(bool covered) = 0;
/** Ambient light change callback used for notifying upper level logic */
static void (*sfw_notify_als_cb)(int lux) = 0;
/** Orientation change callback used for notifying upper level logic */
static void (*sfw_notify_orient_cb)(int state) = 0;
// (exported API defined in "mce-sensorfw.h")
static gboolean mce_sensorfw_evdev_cb (GIOChannel *chn, GIOCondition cnd, gpointer aptr);
static void mce_sensorfw_als_detach (void);
static void mce_sensorfw_ps_detach (void);
static bool als_from_evdev(void);
static bool ps_from_evdev(void);
/* ========================================================================= *
* SENSORD_DATA_TYPES
* ========================================================================= */
static const char *
sfw_sample_als_repr(const sfw_sample_als_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" lux=%"PRIu32,
self->als_timestamp,
self->als_value);
return buf;
}
static const char *
sfw_sample_ps_repr(const sfw_sample_ps_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" distance=%"PRIu32" proximity=%s",
self->ps_timestamp,
self->ps_value,
self->ps_withinProximity ? "true" : "false");
return buf;
}
static const char *
sfw_sample_orient_repr(const sfw_sample_orient_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" state=%s",
self->orient_timestamp,
orientation_state_repr(self->orient_state));
return buf;
}
static const char *
sfw_sample_accelerometer_repr(const sfw_sample_accelerometer_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" x=%"PRId32" y=%"PRId32" z=%"PRId32,
self->accelerometer_timestamp,
self->accelerometer_xyz.x,
self->accelerometer_xyz.y,
self->accelerometer_xyz.z);
return buf;
}
static const char *
sfw_sample_compass_repr(const sfw_sample_compass_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" deg=%"PRId32" raw=%"PRId32" cor=%"PRId32" lev=%"PRId32,
self->compass_timestamp,
self->compass_degrees,
self->compass_raw_degrees,
self->compass_corrected_degrees,
self->compass_level);
return buf;
}
static const char *
sfw_sample_gyroscope_repr(const sfw_sample_gyroscope_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" x=%"PRId32" y=%"PRId32" z=%"PRId32,
self->gyroscope_timestamp,
self->gyroscope_xyz.x,
self->gyroscope_xyz.y,
self->gyroscope_xyz.z);
return buf;
}
static const char *
sfw_lid_type_repr(sfw_lid_type_t type)
{
const char *repr = "INVALID";
switch( type ) {
case SFW_LID_TYPE_UNKNOWN: repr = "UNKNOWN"; break;
case SFW_LID_TYPE_FRONT: repr = "FRONT"; break;
case SFW_LID_TYPE_BACK: repr = "BACK"; break;
default: break;
}
return repr;
}
static const char *
sfw_sample_lid_repr(const sfw_sample_lid_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" type=%s value=%"PRIu32,
self->lid_timestamp,
sfw_lid_type_repr(self->lid_type),
self->lid_value);
return buf;
}
static const char *
sfw_sample_humidity_repr(const sfw_sample_humidity_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" humidity=%"PRIu32,
self->humidity_timestamp,
self->humidity_value);
return buf;
}
static const char *
sfw_sample_magnetometer_repr(const sfw_sample_magnetometer_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64
" x=%"PRId32" y=%"PRId32" z=%"PRId32
" rx=%"PRId32" ry=%"PRId32" rz=%"PRId32
" level=%"PRId32,
self->magnetometer_timestamp,
self->magnetometer_x,
self->magnetometer_y,
self->magnetometer_z,
self->magnetometer_rx,
self->magnetometer_ry,
self->magnetometer_rz,
self->magnetometer_level);
return buf;
}
static const char *
sfw_sample_pressure_repr(const sfw_sample_pressure_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" pressure=%"PRIu32,
self->pressure_timestamp,
self->pressure_value);
return buf;
}
static const char *
sfw_sample_rotation_repr(const sfw_sample_rotation_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" x=%"PRId32" y=%"PRId32" z=%"PRId32,
self->rotation_timestamp,
self->rotation_xyz.x,
self->rotation_xyz.y,
self->rotation_xyz.z);
return buf;
}
static const char *
sfw_sample_stepcounter_repr(const sfw_sample_stepcounter_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" stepcount=%"PRIu32,
self->stepcounter_timestamp,
self->stepcounter_value);
return buf;
}
static const char *
sfw_tap_direction_repr(sfw_tap_direction_t direction)
{
const char *repr = "INVALID";
switch( direction ) {
case SFW_TAP_DIRECTION_X: repr = "X"; break;
case SFW_TAP_DIRECTION_Y: repr = "Y"; break;
case SFW_TAP_DIRECTION_Z: repr = "Z"; break;
case SFW_TAP_DIRECTION_LEFT_RIGHT: repr = "LEFT_RIGHT"; break;
case SFW_TAP_DIRECTION_RIGHT_LEFT: repr = "RIGHT_LEFT"; break;
case SFW_TAP_DIRECTION_TOP_BOTTOM: repr = "TOP_BOTTOM"; break;
case SFW_TAP_DIRECTION_BOTTOM_TOP: repr = "BOTTOM_TOP"; break;
case SFW_TAP_DIRECTION_FACE_BACK: repr = "FACE_BACK"; break;
case SFW_TAP_DIRECTION_BACK_FACE: repr = "BACK_FACE"; break;
default: break;
}
return repr;
}
static const char *
sfw_tap_type_repr(sfw_tap_type_t type)
{
const char *repr = "INVALID";
switch( type ) {
case SFW_TAP_TYPE_NONE: repr = "NONE"; break;
case SFW_TAP_TYPE_DOUBLE_TAP: repr = "DOUBLE_TAP"; break;
case SFW_TAP_TYPE_SINGLE_TAP: repr = "SINGLE_TAP"; break;
default: break;
}
return repr;
}
static const char *
sfw_sample_tap_repr(const sfw_sample_tap_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf, "time=%"PRIu64" direction=%s type=%s",
self->tap_timestamp,
sfw_tap_direction_repr(self->tap_direction),
sfw_tap_type_repr(self->tap_type));
return buf;
}
static const char *
sfw_sample_temperature_repr(const sfw_sample_temperature_t *self)
{
static char buf[64];
snprintf(buf, sizeof buf,
"time=%"PRIu64" temperature=%"PRIu32,
self->temperature_timestamp,
self->temperature_value);
return buf;
}
/* ========================================================================= *
* SENSORFW_BACKEND
* ========================================================================= */
/* ------------------------------------------------------------------------- *
* callbacks for interpreting sensor specific current value replies
* ------------------------------------------------------------------------- */
static bool
sfw_backend_parse_data(DBusMessageIter *data, int arg_type, ...)
{
bool ack = false;
va_list va;
va_start(va, arg_type);
while( !mce_dbus_iter_at_end(data) ) {
if( !mce_dbus_iter_get_basic(data, va_arg(va, void *), arg_type) )
goto EXIT;
arg_type = va_arg(va, int);
}
ack = true;
EXIT:
va_end(va);
return ack;
}
static bool
sfw_backend_als_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_uint32_t val = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_UINT32, &val,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_als_t sample = {
.als_timestamp = tck,
.als_value = val,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_ps_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_uint32_t val = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_UINT32, &val,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_ps_t sample = {
.ps_timestamp = tck,
.ps_value = (val < 1) ? 0 : 10,
.ps_withinProximity = (val < 1) ? true : false,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_orient_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_uint32_t val = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_UINT32, &val,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_orient_t sample = {
.orient_timestamp = tck,
.orient_state = val,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_accelerometer_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_int32_t xval = 0;
dbus_int32_t yval = 0;
dbus_int32_t zval = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_INT32, &xval,
DBUS_TYPE_INT32, &yval,
DBUS_TYPE_INT32, &zval,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_accelerometer_t sample = {
.accelerometer_timestamp = tck,
.accelerometer_xyz = {
.x = xval,
.y = yval,
.z = zval,
},
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_compass_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_int32_t deg = 0;
dbus_int32_t raw = 0;
dbus_int32_t cor = 0;
dbus_int32_t lev = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_INT32, &deg,
DBUS_TYPE_INT32, &raw,
DBUS_TYPE_INT32, &cor,
DBUS_TYPE_INT32, &lev,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_compass_t sample = {
.compass_timestamp = tck,
.compass_degrees = deg,
.compass_raw_degrees = raw,
.compass_corrected_degrees = cor,
.compass_level = lev,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_gyroscope_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_int32_t xval = 0;
dbus_int32_t yval = 0;
dbus_int32_t zval = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_INT32, &xval,
DBUS_TYPE_INT32, &yval,
DBUS_TYPE_INT32, &zval,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_gyroscope_t sample = {
.gyroscope_timestamp = tck,
.gyroscope_xyz = {
.x = xval,
.y = yval,
.z = zval,
},
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_lid_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_int32_t type = 0;
dbus_uint32_t val = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_INT32, &type,
DBUS_TYPE_UINT32, &val,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_lid_t sample = {
.lid_timestamp = tck,
.lid_type = type,
.lid_value = val,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_humidity_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_uint32_t val = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_UINT32, &val,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_humidity_t sample = {
.humidity_timestamp = tck,
.humidity_value = val,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_magnetometer_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_int32_t x = 0;
dbus_int32_t y = 0;
dbus_int32_t z = 0;
dbus_int32_t rx = 0;
dbus_int32_t ry = 0;
dbus_int32_t rz = 0;
dbus_int32_t lev = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_INT32, &x,
DBUS_TYPE_INT32, &y,
DBUS_TYPE_INT32, &z,
DBUS_TYPE_INT32, &rx,
DBUS_TYPE_INT32, &ry,
DBUS_TYPE_INT32, &rz,
DBUS_TYPE_INT32, &lev,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_magnetometer_t sample = {
.magnetometer_timestamp = tck,
.magnetometer_x = x,
.magnetometer_y = y,
.magnetometer_z = z,
.magnetometer_rx = rx,
.magnetometer_ry = ry,
.magnetometer_rz = rz,
.magnetometer_level = lev,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_pressure_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_uint32_t val = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_UINT32, &val,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_pressure_t sample = {
.pressure_timestamp = tck,
.pressure_value = val,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_rotation_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_int32_t xval = 0;
dbus_int32_t yval = 0;
dbus_int32_t zval = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_INT32, &xval,
DBUS_TYPE_INT32, &yval,
DBUS_TYPE_INT32, &zval,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_rotation_t sample = {
.rotation_timestamp = tck,
.rotation_xyz = {
.x = xval,
.y = yval,
.z = zval,
},
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_stepcounter_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_uint32_t val = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_UINT32, &val,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_stepcounter_t sample = {
.stepcounter_timestamp = tck,
.stepcounter_value = val,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_tap_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_uint32_t direction = 0;
dbus_uint32_t type = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_UINT32, &direction,
DBUS_TYPE_INT32, &type,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_tap_t sample = {
.tap_timestamp = tck,
.tap_direction = direction,
.tap_type = type,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
static bool
sfw_backend_temperature_value_cb(sfw_plugin_t *plugin, DBusMessageIter *data)
{
bool ack = false;
dbus_uint64_t tck = 0;
dbus_uint32_t val = 0;
if( !sfw_backend_parse_data(data,
DBUS_TYPE_UINT64, &tck,
DBUS_TYPE_UINT32, &val,
DBUS_TYPE_INVALID) )
goto EXIT;
const sfw_sample_temperature_t sample = {
.temperature_timestamp = tck,
.temperature_value = val,
};
sfw_plugin_handle_sample(plugin, &sample);
ack = true;
EXIT:
return ack;
}
/* ------------------------------------------------------------------------- *
* Callbacks for interpreting sensor specific change notifications
* ------------------------------------------------------------------------- */
/** Callback for handling ambient light events from sensord */
static void
sfw_backend_als_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_als_t *sample = sampledata;
static const sfw_sample_als_t default_value = {
.als_value = SFW_NOTIFY_DEFAULT_ALS,
};
static sfw_sample_als_t cached_value = {
.als_value = SFW_NOTIFY_DEFAULT_ALS,
};
static bool tracking_active = false;
if( sample ) {
mce_log(LL_DEBUG, "ALS: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_als_repr(sample));
}
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
cached_value = *sample;
break;
case NOTIFY_SENSORD:
if( als_from_evdev() )
mce_log(LL_DEBUG, "ignoring sensord input: %s",
sfw_sample_als_repr(sample));
else
cached_value = *sample;
break;
}
/* Default value is used unless we are in fully working state */
sample = tracking_active ? &cached_value : &default_value ;
if( sfw_notify_als_cb ) {
mce_log(LL_DEBUG, "ALS: NOTIFY %s %s",
sfw_notify_name(type),
sfw_sample_als_repr(sample));
sfw_notify_als_cb(sample->als_value);
}
return;
}
/** Callback for handling proximity events from sensord */
static void
sfw_backend_ps_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_ps_t *sample = sampledata;
static const sfw_sample_ps_t exception_value = {
.ps_withinProximity = SFW_NOTIFY_EXCEPTION_PS,
};
static const sfw_sample_ps_t default_value = {
.ps_withinProximity = SFW_NOTIFY_DEFAULT_PS,
};
static sfw_sample_ps_t cached_value = {
.ps_value = 10,
.ps_withinProximity = SFW_NOTIFY_DEFAULT_PS,
};
static bool tracking_active = false;
if( sample ) {
mce_log(LL_DEBUG, "PS: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_ps_repr(sample));
}
switch( type ) {
default:
case NOTIFY_FORGET:
case NOTIFY_REPEAT:
break;
case NOTIFY_RESET:
tracking_active = false;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
cached_value = *sample;
break;
case NOTIFY_SENSORD:
if( ps_from_evdev() )
mce_log(LL_DEBUG, "ignoring sensord input: %s",
sfw_sample_ps_repr(sample));
else
cached_value = *sample;
break;
}
if( sfw_exception_is_active() ) {
// ps=covered while waiting for sensorfwd to show up
sample = &exception_value;
}
else if( !tracking_active ) {
// ps=not-covered while sensorfwd is not running
sample = &default_value;
}
else {
// ps=as-reported by sensorfwd or kernel
sample = &cached_value;
}
if( sfw_notify_ps_cb ) {
mce_log(LL_DEBUG, "PS: NOTIFY %s %s",
sfw_notify_name(type),
sfw_sample_ps_repr(sample));
sfw_notify_ps_cb(sample->ps_withinProximity);
}
return;
}
/** Callback for handling orientation events from sensord */
static void
sfw_backend_orient_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
static const sfw_sample_orient_t default_value = {
.orient_state = SFW_NOTIFY_DEFAULT_ORIENT,
};
static sfw_sample_orient_t cached_value = {
.orient_state = SFW_NOTIFY_DEFAULT_ORIENT,
};
static bool tracking_active = false;
(void)plugin;
const sfw_sample_orient_t *sample = sampledata;
if( sample ) {
mce_log(LL_DEBUG, "ORIENT: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_orient_repr(sample));
}
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
/* Default value is used unless we are in fully working state */
sample = tracking_active ? &cached_value : &default_value ;
if( sfw_notify_orient_cb ) {
mce_log(LL_DEBUG, "ORIENT: NOTIFY %s %s",
sfw_notify_name(type),
sfw_sample_orient_repr(sample));
sfw_notify_orient_cb(sample->orient_state);
}
return;
}
/** Callback for handling accelerometer events from sensord */
static void
sfw_backend_accelerometer_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_accelerometer_t *sample = sampledata;
static const sfw_sample_accelerometer_t default_value =
{
.accelerometer_xyz = {
.x = 0,
.y = 0,
.z = 0,
},
};
static sfw_sample_accelerometer_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "ACCELEROMETER: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_accelerometer_repr(sample));
return;
}
static void
sfw_backend_compass_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_compass_t *sample = sampledata;
static const sfw_sample_compass_t default_value = { };
static sfw_sample_compass_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "COMPASS: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_compass_repr(sample));
return;
}
static void
sfw_backend_gyroscope_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_gyroscope_t *sample = sampledata;
static const sfw_sample_gyroscope_t default_value = { };
static sfw_sample_gyroscope_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "GYROSCOPE: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_gyroscope_repr(sample));
return;
}
static void
sfw_backend_lid_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_lid_t *sample = sampledata;
static const sfw_sample_lid_t default_value = { };
static sfw_sample_lid_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "LID: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_lid_repr(sample));
return;
}
static void
sfw_backend_humidity_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_humidity_t *sample = sampledata;
static const sfw_sample_humidity_t default_value = { };
static sfw_sample_humidity_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "HUMIDITY: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_humidity_repr(sample));
return;
}
static void
sfw_backend_magnetometer_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_magnetometer_t *sample = sampledata;
static const sfw_sample_magnetometer_t default_value = { };
static sfw_sample_magnetometer_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "MAGNETOMETER: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_magnetometer_repr(sample));
return;
}
static void
sfw_backend_pressure_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_pressure_t *sample = sampledata;
static const sfw_sample_pressure_t default_value = { };
static sfw_sample_pressure_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "PRESSURE: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_pressure_repr(sample));
return;
}
static void
sfw_backend_rotation_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_rotation_t *sample = sampledata;
static const sfw_sample_rotation_t default_value = { };
static sfw_sample_rotation_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "ROTATION: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_rotation_repr(sample));
return;
}
static void
sfw_backend_stepcounter_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_stepcounter_t *sample = sampledata;
static const sfw_sample_stepcounter_t default_value = { };
static sfw_sample_stepcounter_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "STEPCOUNTER: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_stepcounter_repr(sample));
return;
}
static void
sfw_backend_tap_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_tap_t *sample = sampledata;
static const sfw_sample_tap_t default_value = { };
static sfw_sample_tap_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "TAP: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_tap_repr(sample));
return;
}
static void
sfw_backend_temperature_sample_cb(sfw_plugin_t *plugin, sfw_notify_t type, const void *sampledata)
{
(void)plugin;
const sfw_sample_temperature_t *sample = sampledata;
static const sfw_sample_temperature_t default_value = { };
static sfw_sample_temperature_t cached_value = { };
static bool tracking_active = false;
switch( type ) {
default:
case NOTIFY_REPEAT:
break;
case NOTIFY_FORGET:
case NOTIFY_RESET:
tracking_active = false;
cached_value = default_value;
break;
case NOTIFY_RESTORE:
tracking_active = true;
break;
case NOTIFY_EVDEV:
case NOTIFY_SENSORD:
cached_value = *sample;
break;
}
sample = tracking_active ? &cached_value : &default_value;
mce_log(LL_DEBUG, "TEMPERATURE: UPDATE %s %s",
sfw_notify_name(type),
sfw_sample_temperature_repr(sample));
return;
}
// ----------------------------------------------------------------
/** Data and callback functions for all sensors */
static const sfw_backend_t sfw_backend_lut[SFW_SENSOR_ID_COUNT] =
{
[SFW_SENSOR_ID_PS] = {
.be_sensor_name = SFW_SENSOR_NAME_PS,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_PS,
.be_sample_size = sizeof(sfw_sample_ps_t),
.be_value_cb = sfw_backend_ps_value_cb,
.be_sample_cb = sfw_backend_ps_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_PS,
},
[SFW_SENSOR_ID_ALS] = {
.be_sensor_name = SFW_SENSOR_NAME_ALS,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_ALS,
.be_sample_size = sizeof(sfw_sample_als_t),
.be_value_cb = sfw_backend_als_value_cb,
.be_sample_cb = sfw_backend_als_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_ALS,
},
[SFW_SENSOR_ID_ORIENT] = {
.be_sensor_name = SFW_SENSOR_NAME_ORIENT,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_ORIENT,
.be_sample_size = sizeof(sfw_sample_orient_t),
.be_value_cb = sfw_backend_orient_value_cb,
.be_sample_cb = sfw_backend_orient_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_ORIENT,
},
[SFW_SENSOR_ID_ACCELEROMETER] = {
.be_sensor_name = SFW_SENSOR_NAME_ACCELEROMETER,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_ACCELEROMETER,
.be_sample_size = sizeof(sfw_sample_accelerometer_t),
.be_value_cb = sfw_backend_accelerometer_value_cb,
.be_sample_cb = sfw_backend_accelerometer_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_ACCELEROMETER,
},
[SFW_SENSOR_ID_COMPASS] = {
.be_sensor_name = SFW_SENSOR_NAME_COMPASS,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_COMPASS,
.be_sample_size = sizeof(sfw_sample_compass_t),
.be_value_cb = sfw_backend_compass_value_cb,
.be_sample_cb = sfw_backend_compass_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_COMPASS,
},
[SFW_SENSOR_ID_GYROSCOPE] = {
.be_sensor_name = SFW_SENSOR_NAME_GYROSCOPE,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_GYROSCOPE,
.be_sample_size = sizeof(sfw_sample_gyroscope_t),
.be_value_cb = sfw_backend_gyroscope_value_cb,
.be_sample_cb = sfw_backend_gyroscope_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_GYROSCOPE,
},
[SFW_SENSOR_ID_LID] = {
.be_sensor_name = SFW_SENSOR_NAME_LID,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_LID,
.be_sample_size = sizeof(sfw_sample_lid_t),
.be_value_cb = sfw_backend_lid_value_cb,
.be_sample_cb = sfw_backend_lid_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_LID,
},
[SFW_SENSOR_ID_HUMIDITY] = {
.be_sensor_name = SFW_SENSOR_NAME_HUMIDITY,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_HUMIDITY,
.be_sample_size = sizeof(sfw_sample_humidity_t),
.be_value_cb = sfw_backend_humidity_value_cb,
.be_sample_cb = sfw_backend_humidity_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_HUMIDITY,
},
[SFW_SENSOR_ID_MAGNETOMETER] = {
.be_sensor_name = SFW_SENSOR_NAME_MAGNETOMETER,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_MAGNETOMETER,
.be_sample_size = sizeof(sfw_sample_magnetometer_t),
.be_value_cb = sfw_backend_magnetometer_value_cb,
.be_sample_cb = sfw_backend_magnetometer_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_MAGNETOMETER,
},
[SFW_SENSOR_ID_PRESSURE] = {
.be_sensor_name = SFW_SENSOR_NAME_PRESSURE,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_PRESSURE,
.be_sample_size = sizeof(sfw_sample_pressure_t),
.be_value_cb = sfw_backend_pressure_value_cb,
.be_sample_cb = sfw_backend_pressure_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_PRESSURE,
},
[SFW_SENSOR_ID_ROTATION] = {
.be_sensor_name = SFW_SENSOR_NAME_ROTATION,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_ROTATION,
.be_sample_size = sizeof(sfw_sample_rotation_t),
.be_value_cb = sfw_backend_rotation_value_cb,
.be_sample_cb = sfw_backend_rotation_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_ROTATION,
},
[SFW_SENSOR_ID_STEPCOUNTER] = {
.be_sensor_name = SFW_SENSOR_NAME_STEPCOUNTER,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_STEPCOUNTER,
.be_sample_size = sizeof(sfw_sample_stepcounter_t),
.be_value_cb = sfw_backend_stepcounter_value_cb,
.be_sample_cb = sfw_backend_stepcounter_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_STEPCOUNTER,
},
[SFW_SENSOR_ID_TAP] = {
.be_sensor_name = SFW_SENSOR_NAME_TAP,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_TAP,
.be_sample_size = sizeof(sfw_sample_tap_t),
.be_value_cb = sfw_backend_tap_value_cb,
.be_sample_cb = sfw_backend_tap_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_TAP,
},
[SFW_SENSOR_ID_TEMPERATURE] = {
.be_sensor_name = SFW_SENSOR_NAME_TEMPERATURE,
.be_sensor_object = 0,
.be_sensor_interface = SFW_SENSOR_INTERFACE_TEMPERATURE,
.be_sample_size = sizeof(sfw_sample_temperature_t),
.be_value_cb = sfw_backend_temperature_value_cb,
.be_sample_cb = sfw_backend_temperature_sample_cb,
.be_value_method = SFW_SENSOR_METHOD_READ_TEMPERATURE,
},
};
/* ========================================================================= *
* SENSORFW_HELPERS
* ========================================================================= */
/* Set file descriptor to blocking/unblocking state
*/
static bool
sfw_socket_set_blocking(int fd, bool blocking)
{
bool ok = false;
int flags = 0;
if( (flags = fcntl(fd, F_GETFL, 0)) == -1 ) {
mce_log(LL_ERR, "could not get socket flags");
goto EXIT;
}
if( blocking )
flags &= ~O_NONBLOCK;
else
flags |= O_NONBLOCK;
if( fcntl(fd, F_SETFL, flags) == -1 ){
mce_log(LL_ERR, "could not set socket flags");
goto EXIT;
}
ok = true;
EXIT:
return ok;
}
/** Get a sensord data socket connection file descriptor
*/
static int
sfw_socket_open(void)
{
bool ok = false;
int fd = -1;
struct sockaddr_un sa;
socklen_t sa_len;
/* create socket */
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ) {
mce_log(LL_ERR, "could not open local domain socket");
goto EXIT;
}
/* make it non-blocking -> connect() will return immediately */
if( !sfw_socket_set_blocking(fd, false) )
goto EXIT;
/* connect to daemon */
memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX;
snprintf(sa.sun_path, sizeof sa.sun_path, "%s", SENSORFW_DATA_SOCKET);
sa_len = strchr(sa.sun_path, 0) + 1 - (char *)&sa;
if( connect(fd, (struct sockaddr *)&sa, sa_len) == -1 ) {
mce_log(LL_ERR, "could not connect to %s: %m",
SENSORFW_DATA_SOCKET);
goto EXIT;
}
ok = true;
EXIT:
/* all or nothing */
if( !ok && fd != -1 )
close(fd), fd = -1;
return fd;
}
/** Add a glib I/O notification for a file descriptor
*/
static guint
sfw_socket_add_notify(int fd, bool close_on_unref,
GIOCondition cnd, GIOFunc io_cb, gpointer aptr)
{
guint wid = 0;
GIOChannel *chn = 0;
if( !(chn = g_io_channel_unix_new(fd)) ) {
goto EXIT;
}
g_io_channel_set_close_on_unref(chn, close_on_unref);
cnd |= G_IO_ERR | G_IO_HUP | G_IO_NVAL;
if( !(wid = g_io_add_watch(chn, cnd, io_cb, aptr)) )
goto EXIT;
EXIT:
if( chn != 0 ) g_io_channel_unref(chn);
return wid;
}
/* ========================================================================= *
* SENSORFW_REPORTING
* ========================================================================= */
/** Translate reporting state to human readable form
*/
static const char *
sfw_reporting_state_name(sfw_reporting_state_t state)
{
static const char *const lut[REPORTING_NUMSTATES] =
{
[REPORTING_INITIAL] = "INITIAL",
[REPORTING_IDLE] = "IDLE",
[REPORTING_RETHINK] = "RETHINK",
[REPORTING_ENABLING] = "ENABLING",
[REPORTING_ENABLED] = "ENABLED",
[REPORTING_DISABLING] = "DISABLING",
[REPORTING_DISABLED] = "DISABLED",
[REPORTING_ERROR] = "ERROR",
};
return (state < REPORTING_NUMSTATES) ? lut[state] : 0;
}
/** Create sensor start/stop state machine object
*/
static sfw_reporting_t *
sfw_reporting_create(sfw_plugin_t *plugin)
{
sfw_reporting_t *self = calloc(1, sizeof *self);
self->rep_plugin = plugin;
self->rep_state = REPORTING_INITIAL;
self->rep_change_pc = 0;
self->rep_value_pc = 0;
self->rep_target = false;
self->rep_retry_id = 0;
return self;
}
/** Delete sensor start/stop state machine object
*/
static void
sfw_reporting_delete(sfw_reporting_t *self)
{
// using NULL self pointer explicitly allowed
if( self ) {
sfw_reporting_trans(self, REPORTING_INITIAL);
self->rep_plugin = 0;
free(self);
}
}
/** Set sensor start/stop target state
*/
static void
sfw_reporting_set_target(sfw_reporting_t *self, bool enable)
{
if( self->rep_target != enable ) {
self->rep_target = enable;
sfw_reporting_do_rethink(self);
}
}
/** Cancel pending sensor start/stop method call
*/
static void
sfw_reporting_cancel_change(sfw_reporting_t *self)
{
if( self->rep_change_pc ) {
dbus_pending_call_cancel(self->rep_change_pc);
dbus_pending_call_unref(self->rep_change_pc);
self->rep_change_pc = 0;
}
}
/** Cancel pending sensor initial value method call
*/
static void
sfw_reporting_cancel_value(sfw_reporting_t *self)
{
if( self->rep_value_pc ) {
dbus_pending_call_cancel(self->rep_value_pc);
dbus_pending_call_unref(self->rep_value_pc);
self->rep_value_pc = 0;
}
}
/** Cancel pending ipc retry timer
*/
static void
sfw_reporting_cancel_retry(sfw_reporting_t *self)
{
if( self->rep_retry_id ) {
g_source_remove(self->rep_retry_id);
self->rep_retry_id = 0;
}
}
/** Make a state transition
*/
static void
sfw_reporting_trans(sfw_reporting_t *self, sfw_reporting_state_t state)
{
dbus_int32_t sid = sfw_plugin_get_session_id(self->rep_plugin);
if( self->rep_state == state )
goto EXIT;
sfw_reporting_cancel_change(self);
sfw_reporting_cancel_value(self);
sfw_reporting_cancel_retry(self);
mce_log(LL_DEBUG, "reporting(%s): %s -> %s",
sfw_plugin_get_sensor_name(self->rep_plugin),
sfw_reporting_state_name(self->rep_state),
sfw_reporting_state_name(state));
self->rep_state = state;
switch( self->rep_state ) {
case REPORTING_RETHINK:
if( self->rep_target )
sfw_reporting_trans(self, REPORTING_ENABLING);
else
sfw_reporting_trans(self, REPORTING_DISABLING);
break;
case REPORTING_ENABLING:
// resend last known state
sfw_plugin_restore_value(self->rep_plugin);
dbus_send_ex(SENSORFW_SERVICE,
sfw_plugin_get_sensor_object(self->rep_plugin),
sfw_plugin_get_sensor_interface(self->rep_plugin),
SFW_SENSOR_METHOD_START,
sfw_reporting_change_cb,
self, 0, &self->rep_change_pc,
DBUS_TYPE_INT32, &sid,
DBUS_TYPE_INVALID);
break;
case REPORTING_DISABLING:
// optional: switch to sensor stopped value
sfw_plugin_forget_value(self->rep_plugin);
dbus_send_ex(SENSORFW_SERVICE,
sfw_plugin_get_sensor_object(self->rep_plugin),
sfw_plugin_get_sensor_interface(self->rep_plugin),
SFW_SENSOR_METHOD_STOP,
sfw_reporting_change_cb,
self, 0, &self->rep_change_pc,
DBUS_TYPE_INT32, &sid,
DBUS_TYPE_INVALID);
break;
case REPORTING_ENABLED:
if( !sfw_plugin_get_value_method(self->rep_plugin) ) {
mce_log(LL_DEBUG, "reporting(%s): skip state query",
sfw_plugin_get_sensor_name(self->rep_plugin));
break;
}
dbus_send_ex(SENSORFW_SERVICE,
sfw_plugin_get_sensor_object(self->rep_plugin),
sfw_plugin_get_sensor_interface(self->rep_plugin),
sfw_plugin_get_value_method(self->rep_plugin),
sfw_reporting_value_cb,
self, 0, &self->rep_value_pc,
DBUS_TYPE_INVALID);
break;
case REPORTING_DISABLED:
// NOP
break;
case REPORTING_ERROR:
self->rep_retry_id = g_timeout_add(SENSORFW_RETRY_DELAY_MS,
sfw_reporting_retry_cb,
self);
break;
default:
case REPORTING_IDLE:
case REPORTING_INITIAL:
// reset sensor value to default state
sfw_plugin_reset_value(self->rep_plugin);
break;
}
EXIT:
return;
}
/** Handle reply to initial sensor value query
*/
static void
sfw_reporting_value_cb(DBusPendingCall *pc, void *aptr)
{
sfw_reporting_t *self = aptr;
DBusMessage *rsp = 0;
DBusError err = DBUS_ERROR_INIT;
bool ack = false;
if( pc != self->rep_value_pc )
goto EXIT;
dbus_pending_call_unref(self->rep_value_pc),
self->rep_value_pc = 0;
if( !(rsp = dbus_pending_call_steal_reply(pc)) ) {
mce_log(LL_ERR, "reporting(%s): no reply",
sfw_plugin_get_sensor_name(self->rep_plugin));
goto EXIT;
}
if( dbus_set_error_from_message(&err, rsp) ) {
mce_log(LL_ERR, "reporting(%s): error reply: %s: %s",
sfw_plugin_get_sensor_name(self->rep_plugin),
err.name, err.message);
goto EXIT;
}
mce_log(LL_DEBUG, "reporting(%s): reply received",
sfw_plugin_get_sensor_name(self->rep_plugin));
DBusMessageIter body, data;
if( !dbus_message_iter_init(rsp, &body) )
goto PARSE_FAILED;
if( !mce_dbus_iter_get_struct(&body, &data) )
goto PARSE_FAILED;
if( !(ack = sfw_plugin_handle_value(self->rep_plugin, &data)) )
goto PARSE_FAILED;
ack = true;
goto EXIT;
PARSE_FAILED:
mce_log(LL_ERR, "reporting(%s): parse error",
sfw_plugin_get_sensor_name(self->rep_plugin));
EXIT:
if( rsp ) dbus_message_unref(rsp);
dbus_error_free(&err);
if( !ack && self->rep_state == REPORTING_ENABLED )
sfw_reporting_trans(self, REPORTING_ERROR);
return;
}
/** Handle reply to start/stop sensor request
*/
static void
sfw_reporting_change_cb(DBusPendingCall *pc, void *aptr)
{
sfw_reporting_t *self = aptr;
DBusMessage *rsp = 0;
DBusError err = DBUS_ERROR_INIT;
dbus_bool_t ack = FALSE;
if( pc != self->rep_change_pc )
goto EXIT;
dbus_pending_call_unref(self->rep_change_pc),