struct sensor_info_t
{
- char friendly_name[MAX_NAME_SIZE]; /* ex: Accelerometer */
- char internal_name[MAX_NAME_SIZE]; /* ex: accel_3d */
- char vendor_name[MAX_NAME_SIZE]; /* ex: Intel */
- char trigger_name[MAX_NAME_SIZE]; /* ex: accel-name-dev1 */
+ char friendly_name[MAX_NAME_SIZE]; /* ex: Accelerometer */
+ char internal_name[MAX_NAME_SIZE]; /* ex: accel_3d */
+ char vendor_name[MAX_NAME_SIZE]; /* ex: Intel */
+ char init_trigger_name[MAX_NAME_SIZE]; /* ex: accel-name-dev1 */
+ char motion_trigger_name[MAX_NAME_SIZE];/* ex: accel-any-motion-dev1 */
float max_range;
float resolution;
float power;
+ /*
+ * Currently active trigger - either a pointer to the initial (default)
+ * trigger name buffer, or a pointer to the motion trigger name buffer,
+ * or something else (typically NULL or a pointer to some static "\n".
+ * This is used to determine if the conditions are met to switch from
+ * the default trigger to the motion trigger for a sensor, or rather for
+ * the interrupt-driven sensors associated to a given iio device.
+ */
+ const char* selected_trigger;
+
float offset; /* (cooked = raw + offset) * scale */
float scale; /*default: 1. when set to 0, use channel specific value*/
float illumincalib; /* to set the calibration for the ALS */
}
-static int setup_trigger(int dev_num, const char* trigger_val)
+static void setup_trigger (int s, const char* trigger_val)
{
char sysfs_path[PATH_MAX];
- sprintf(sysfs_path, TRIGGER_PATH, dev_num);
+ sprintf(sysfs_path, TRIGGER_PATH, sensor_info[s].dev_num);
- return sysfs_write_str(sysfs_path, trigger_val);
+ if (trigger_val[0] != '\n')
+ ALOGI("Setting S%d (%s) trigger to %s\n", s,
+ sensor_info[s].friendly_name, trigger_val);
+
+ sysfs_write_str(sysfs_path, trigger_val);
+
+ sensor_info[s].selected_trigger = trigger_val;
}
/* Stop sampling - if we are recovering from hal restart */
enable_buffer(dev_num, 0);
- setup_trigger(dev_num, "\n");
+ setup_trigger(s, "\n");
/* Turn on channels we're aware of */
for (c=0;c<sensor_info[s].num_channels; c++) {
/* Stop sampling */
enable_buffer(dev_num, 0);
- setup_trigger(dev_num, "\n");
+ setup_trigger(s, "\n");
/* If there's at least one sensor enabled on this iio device */
if (trig_sensors_per_dev[dev_num]) {
/* Start sampling */
- setup_trigger(dev_num, sensor_info[s].trigger_name);
+ setup_trigger(s, sensor_info[s].init_trigger_name);
enable_buffer(dev_num, 1);
}
}
sensor_info[s].history = NULL;
sensor_info[s].history_size = 0;
}
+
return 0;
}
}
+static void enable_motion_trigger (int dev_num)
+{
+ /*
+ * In the ideal case, we enumerate two triggers per iio device ; the
+ * default (periodically firing) trigger, and another one (the motion
+ * trigger) that only fires up when motion is detected. This second one
+ * allows for lesser energy consumption, but requires periodic sample
+ * duplication at the HAL level for sensors that Android defines as
+ * continuous. This "duplicate last sample" logic can only be engaged
+ * once we got a first sample for the driver, so we start with the
+ * default trigger when an iio device is first opened, then adjust the
+ * trigger when we got events for all active sensors. Unfortunately in
+ * the general case several sensors can be associated to a given iio
+ * device, they can independently be controlled, and we have to adjust
+ * the trigger in use at the iio device level depending on whether or
+ * not appropriate conditions are met at the sensor level.
+ */
+
+ int s;
+ int i;
+ int active_sensors = trig_sensors_per_dev[dev_num];
+ int candidate[MAX_SENSORS];
+ int candidate_count = 0;
+
+ if (!active_sensors)
+ return;
+
+ /* Check that all active sensors are ready to switch */
+
+ for (s=0; s<MAX_SENSORS; s++)
+ if (sensor_info[s].dev_num == dev_num &&
+ sensor_info[s].enable_count &&
+ sensor_info[s].num_channels &&
+ (!sensor_info[s].motion_trigger_name[0] ||
+ !sensor_info[s].report_initialized)
+ )
+ return; /* Nope */
+
+ /* Record which particular sensors need to switch */
+
+ for (s=0; s<MAX_SENSORS; s++)
+ if (sensor_info[s].dev_num == dev_num &&
+ sensor_info[s].enable_count &&
+ sensor_info[s].num_channels &&
+ sensor_info[s].selected_trigger !=
+ sensor_info[s].motion_trigger_name)
+ candidate[candidate_count++] = s;
+
+ if (!candidate_count)
+ return;
+
+ /* Now engage the motion trigger for sensors which aren't using it */
+
+ enable_buffer(dev_num, 0);
+
+ for (i=0; i<candidate_count; i++) {
+ s = candidate[i];
+ setup_trigger(s, sensor_info[s].motion_trigger_name);
+ }
+
+ enable_buffer(dev_num, 1);
+}
+
+
static int integrate_device_report(int dev_num)
{
int len;
sensor_info[s].report_initialized = 1;
}
+ /* Tentatively switch to an any-motion trigger if conditions are met */
+ enable_motion_trigger(dev_num);
+
return 0;
}
continue;
/* If the sensor can generate duplicates, leave it alone */
- if (!(sensor_info[s].quirks & QUIRK_TERSE_DRIVER))
+ if (!(sensor_info[s].quirks & QUIRK_TERSE_DRIVER) &&
+ sensor_info[s].selected_trigger !=
+ sensor_info[s].motion_trigger_name)
continue;
/* If we haven't seen a sample, there's nothing to duplicate */
*/
for (s=0; s<sensor_count; s++)
if (sensor_info[s].enable_count &&
- (sensor_info[s].quirks & QUIRK_TERSE_DRIVER) &&
- sensor_info[s].sampling_rate) {
+ ((sensor_info[s].quirks & QUIRK_TERSE_DRIVER) ||
+ sensor_info[s].selected_trigger ==
+ sensor_info[s].motion_trigger_name) &&
+ sensor_info[s].sampling_rate) {
period = (int64_t) (1000000000.0 /
sensor_info[s].sampling_rate);
return;
/*
- * Anything else is higher priority. However if we already found an
- * any-motion trigger, don't select anything else.
- */
-
- if (!memcmp(sensor_info[s].trigger_name + sensor_name_len + 1,
- "any-motion-", 11))
- return;
-
- /*
- * If we're switching to an any-motion trigger, force the sensor to
+ * If we found any-motion trigger, record it and force the sensor to
* automatic intermediate event generation mode, at least if it is of a
* continuously firing sensor type.
*/
- if (!memcmp(suffix, "any-motion-", 11) && is_continuous(s))
- sensor_info[s].quirks |= QUIRK_TERSE_DRIVER;
+ if (!memcmp(suffix, "any-motion-", 11) && is_continuous(s)) {
+ /* Update the any-motion trigger name to use for this sensor */
+ strcpy(sensor_info[s].motion_trigger_name, trigger_name);
+ return;
+ }
- /* Update the trigger name to use for this sensor */
- strcpy(sensor_info[s].trigger_name, trigger_name);
+ /* Update the initial trigger name to use for this sensor */
+ strcpy(sensor_info[s].init_trigger_name, trigger_name);
}
/* By default, use the name-dev convention that most drivers use */
for (s=0; s<sensor_count; s++)
- snprintf(sensor_info[s].trigger_name, MAX_NAME_SIZE, "%s-dev%d",
- sensor_info[s].internal_name, sensor_info[s].dev_num);
+ snprintf(sensor_info[s].init_trigger_name,
+ MAX_NAME_SIZE, "%s-dev%d",
+ sensor_info[s].internal_name, sensor_info[s].dev_num);
/* Now have a look to /sys/bus/iio/devices/triggerX entries */
if (ret < 0)
break;
+ /* Record initial and any-motion triggers names */
update_sensor_matching_trigger_name(buf);
}
for (s=0; s<sensor_count; s++)
if (sensor_info[s].num_channels) {
- ALOGI( "Sensor %d (%s) using iio trigger %s\n", s,
+ ALOGI( "Sensor %d (%s) default trigger: %s\n", s,
sensor_info[s].friendly_name,
- sensor_info[s].trigger_name);
+ sensor_info[s].init_trigger_name);
+ if (sensor_info[s].motion_trigger_name[0])
+ ALOGI( "Sensor %d (%s) motion trigger: %s\n",
+ s, sensor_info[s].friendly_name,
+ sensor_info[s].motion_trigger_name);
}
}
}
sensor_info[uncal_idx].pair_idx = cal_idx;
sensor_info[cal_idx].pair_idx = uncal_idx;
+ strncpy(sensor_info[uncal_idx].init_trigger_name,
+ sensor_info[cal_idx].init_trigger_name,
+ MAX_NAME_SIZE);
+ strncpy(sensor_info[uncal_idx].motion_trigger_name,
+ sensor_info[cal_idx].motion_trigger_name,
+ MAX_NAME_SIZE);
break;
}
}