static GVariant * handle_get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data) { SensorData *data = user_data; g_assert (data->connection); if (g_strcmp0 (property_name, "HasAccelerometer") == 0) return g_variant_new_boolean (driver_type_exists (data, DRIVER_TYPE_ACCEL)); if (g_strcmp0 (property_name, "AccelerometerOrientation") == 0) return g_variant_new_string (orientation_to_string (data->previous_orientation)); if (g_strcmp0 (property_name, "HasAmbientLight") == 0) return g_variant_new_boolean (driver_type_exists (data, DRIVER_TYPE_LIGHT)); if (g_strcmp0 (property_name, "LightLevelUnit") == 0) return g_variant_new_string (data->uses_lux ? "lux" : "vendor"); if (g_strcmp0 (property_name, "LightLevel") == 0) return g_variant_new_double (data->previous_level); return NULL; }
static void free_orientation_data (SensorData *data) { guint i; if (data == NULL) return; if (data->name_id != 0) { g_bus_unown_name (data->name_id); data->name_id = 0; } for (i = 0; i < NUM_SENSOR_TYPES; i++) { if (driver_type_exists (data, i)) driver_close (DRIVER_FOR_TYPE(i)); g_clear_object (&DEVICE_FOR_TYPE(i)); g_clear_pointer (&data->clients[i], g_hash_table_unref); } g_clear_pointer (&data->introspection_data, g_dbus_node_info_unref); g_clear_object (&data->connection); g_clear_pointer (&data->loop, g_main_loop_unref); g_free (data); }
static void handle_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { SensorData *data = user_data; DriverType driver_type; GHashTable *ht; guint watch_id; if (g_strcmp0 (method_name, "ClaimAccelerometer") == 0 || g_strcmp0 (method_name, "ReleaseAccelerometer") == 0) driver_type = DRIVER_TYPE_ACCEL; else if (g_strcmp0 (method_name, "ClaimLight") == 0 || g_strcmp0 (method_name, "ClaimAccelerometer") == 0) driver_type = DRIVER_TYPE_LIGHT; else { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Method '%s' does not exist", method_name); return; } ht = data->clients[driver_type]; if (g_str_has_prefix (method_name, "Claim")) { watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender)); if (watch_id > 0) { g_dbus_method_invocation_return_value (invocation, NULL); return; } /* No other clients for this sensor? Start it */ if (driver_type_exists (data, driver_type) && g_hash_table_size (ht) == 0) driver_set_polling (DRIVER_FOR_TYPE(driver_type), TRUE); watch_id = g_bus_watch_name_on_connection (data->connection, sender, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, client_vanished_cb, data, NULL); g_hash_table_insert (ht, g_strdup (sender), GUINT_TO_POINTER (watch_id)); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_str_has_prefix (method_name, "Release")) { client_release (data, sender, driver_type); g_dbus_method_invocation_return_value (invocation, NULL); } }
int main (int argc, char **argv) { SensorData *data; GUdevClient *client; int ret = 0; const gchar * const subsystems[] = { "iio", "input", "platform", NULL }; guint i; /* g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); */ data = g_new0 (SensorData, 1); data->previous_orientation = ORIENTATION_UNDEFINED; data->uses_lux = TRUE; /* Set up D-Bus */ setup_dbus (data); client = g_udev_client_new (subsystems); if (!find_sensors (client, data)) { g_debug ("Could not find any supported sensors"); return 0; } g_signal_connect (G_OBJECT (client), "uevent", G_CALLBACK (sensor_changes), data); for (i = 0; i < NUM_SENSOR_TYPES; i++) { data->clients[i] = create_clients_hash_table (); if (!driver_type_exists (data, i)) continue; if (!driver_open (DRIVER_FOR_TYPE(i), DEVICE_FOR_TYPE(i), driver_type_to_callback_func (data->drivers[i]->type), data)) { DRIVER_FOR_TYPE(i) = NULL; g_clear_object (&DEVICE_FOR_TYPE(i)); } } if (!any_sensors_left (data)) goto out; data->init_done = TRUE; if (data->connection) { send_dbus_event (data, PROP_ALL); send_dbus_event (data, PROP_ALL_COMPASS); } data->loop = g_main_loop_new (NULL, TRUE); g_main_loop_run (data->loop); out: free_orientation_data (data); return ret; }
static gboolean find_sensors (GUdevClient *client, SensorData *data) { GList *devices, *input, *platform, *l; gboolean found = FALSE; devices = g_udev_client_query_by_subsystem (client, "iio"); input = g_udev_client_query_by_subsystem (client, "input"); platform = g_udev_client_query_by_subsystem (client, "platform"); devices = g_list_concat (devices, input); devices = g_list_concat (devices, platform); /* Find the devices */ for (l = devices; l != NULL; l = l->next) { GUdevDevice *dev = l->data; guint i; for (i = 0; i < G_N_ELEMENTS(drivers); i++) { SensorDriver *driver = (SensorDriver *) drivers[i]; if (!driver_type_exists(data, driver->type) && driver_discover (driver, dev)) { g_debug ("Found device %s of type %s at %s", g_udev_device_get_sysfs_path (dev), driver_type_to_str (driver->type), driver->name); DEVICE_FOR_TYPE(driver->type) = g_object_ref (dev); DRIVER_FOR_TYPE(driver->type) = (SensorDriver *) driver; found = TRUE; } } if (driver_type_exists (data, DRIVER_TYPE_ACCEL) && driver_type_exists (data, DRIVER_TYPE_LIGHT) && driver_type_exists (data, DRIVER_TYPE_COMPASS)) break; } g_list_free_full (devices, g_object_unref); return found; }
static gboolean any_sensors_left (SensorData *data) { guint i; gboolean exists = FALSE; for (i = 0; i < NUM_SENSOR_TYPES; i++) { if (driver_type_exists (data, i)) { exists = TRUE; break; } } return exists; }
static void handle_generic_method_call (SensorData *data, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, DriverType driver_type) { GHashTable *ht; guint watch_id; g_debug ("Handling driver refcounting method '%s' for %s device", method_name, driver_type_to_str (driver_type)); ht = data->clients[driver_type]; if (g_str_has_prefix (method_name, "Claim")) { watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender)); if (watch_id > 0) { g_dbus_method_invocation_return_value (invocation, NULL); return; } /* No other clients for this sensor? Start it */ if (driver_type_exists (data, driver_type) && g_hash_table_size (ht) == 0) driver_set_polling (DRIVER_FOR_TYPE(driver_type), TRUE); watch_id = g_bus_watch_name_on_connection (data->connection, sender, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, client_vanished_cb, data, NULL); g_hash_table_insert (ht, g_strdup (sender), GUINT_TO_POINTER (watch_id)); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_str_has_prefix (method_name, "Release")) { client_release (data, sender, driver_type); g_dbus_method_invocation_return_value (invocation, NULL); } }
static void client_release (SensorData *data, const char *sender, DriverType driver_type) { GHashTable *ht; guint watch_id; ht = data->clients[driver_type]; watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender)); if (watch_id == 0) return; g_hash_table_remove (ht, sender); if (driver_type_exists (data, driver_type) && g_hash_table_size (ht) == 0) driver_set_polling (DRIVER_FOR_TYPE(driver_type), FALSE); }
static void sensor_changes (GUdevClient *client, gchar *action, GUdevDevice *device, SensorData *data) { guint i; if (g_strcmp0 (action, "remove") == 0) { for (i = 0; i < NUM_SENSOR_TYPES; i++) { GUdevDevice *dev = DEVICE_FOR_TYPE(i); if (!dev) continue; if (g_strcmp0 (g_udev_device_get_sysfs_path (device), g_udev_device_get_sysfs_path (dev)) == 0) { g_debug ("Sensor type %s got removed (%s)", driver_type_to_str (i), g_udev_device_get_sysfs_path (dev)); g_clear_object (&DEVICE_FOR_TYPE(i)); DRIVER_FOR_TYPE(i) = NULL; g_clear_pointer (&data->clients[i], g_hash_table_unref); data->clients[i] = create_clients_hash_table (); send_driver_changed_dbus_event (data, i); } } if (!any_sensors_left (data)) g_main_loop_quit (data->loop); } else if (g_strcmp0 (action, "add") == 0) { guint i; for (i = 0; i < G_N_ELEMENTS(drivers); i++) { SensorDriver *driver = (SensorDriver *) drivers[i]; if (!driver_type_exists (data, driver->type) && driver_discover (driver, device)) { g_debug ("Found hotplugged device %s of type %s at %s", g_udev_device_get_sysfs_path (device), driver_type_to_str (driver->type), driver->name); if (driver_open (driver, device, driver_type_to_callback_func (driver->type), data)) { GHashTable *ht; DEVICE_FOR_TYPE(driver->type) = g_object_ref (device); DRIVER_FOR_TYPE(driver->type) = (SensorDriver *) driver; send_driver_changed_dbus_event (data, driver->type); ht = data->clients[driver->type]; if (g_hash_table_size (ht) > 0) driver_set_polling (DRIVER_FOR_TYPE(driver->type), TRUE); } break; } } } }
static void send_dbus_event (SensorData *data, PropertiesMask mask) { GVariantBuilder props_builder; GVariant *props_changed = NULL; g_assert (data->connection); if (mask == 0) return; g_assert ((mask & PROP_ALL) == 0 || (mask & PROP_ALL_COMPASS) == 0); g_variant_builder_init (&props_builder, G_VARIANT_TYPE ("a{sv}")); if (mask & PROP_HAS_ACCELEROMETER) { gboolean has_accel; has_accel = driver_type_exists (data, DRIVER_TYPE_ACCEL); g_variant_builder_add (&props_builder, "{sv}", "HasAccelerometer", g_variant_new_boolean (has_accel)); /* Send the orientation when the device appears */ if (has_accel) mask |= PROP_ACCELEROMETER_ORIENTATION; else data->previous_orientation = ORIENTATION_UNDEFINED; } if (mask & PROP_ACCELEROMETER_ORIENTATION) { g_variant_builder_add (&props_builder, "{sv}", "AccelerometerOrientation", g_variant_new_string (orientation_to_string (data->previous_orientation))); } if (mask & PROP_HAS_AMBIENT_LIGHT) { gboolean has_als; has_als = driver_type_exists (data, DRIVER_TYPE_LIGHT); g_variant_builder_add (&props_builder, "{sv}", "HasAmbientLight", g_variant_new_boolean (has_als)); /* Send the light level when the device appears */ if (has_als) mask |= PROP_LIGHT_LEVEL; } if (mask & PROP_LIGHT_LEVEL) { g_variant_builder_add (&props_builder, "{sv}", "LightLevelUnit", g_variant_new_string (data->uses_lux ? "lux" : "vendor")); g_variant_builder_add (&props_builder, "{sv}", "LightLevel", g_variant_new_double (data->previous_level)); } if (mask & PROP_HAS_COMPASS) { gboolean has_compass; has_compass = driver_type_exists (data, DRIVER_TYPE_COMPASS); g_variant_builder_add (&props_builder, "{sv}", "HasCompass", g_variant_new_boolean (has_compass)); /* Send the heading when the device appears */ if (has_compass) mask |= PROP_COMPASS_HEADING; } if (mask & PROP_COMPASS_HEADING) { g_variant_builder_add (&props_builder, "{sv}", "CompassHeading", g_variant_new_double (data->previous_heading)); } props_changed = g_variant_new ("(s@a{sv}@as)", (mask & PROP_ALL) ? SENSOR_PROXY_IFACE_NAME : SENSOR_PROXY_COMPASS_IFACE_NAME, g_variant_builder_end (&props_builder), g_variant_new_strv (NULL, 0)); g_dbus_connection_emit_signal (data->connection, NULL, (mask & PROP_ALL) ? SENSOR_PROXY_DBUS_PATH : SENSOR_PROXY_COMPASS_DBUS_PATH, "org.freedesktop.DBus.Properties", "PropertiesChanged", props_changed, NULL); }