The step counter is a sensor that will count using a hardware
register the number of steps taken by the user since the last
reboot while activated. More information on the step counter in
Android can be found in Google's documentation:
http://source.android.com/devices/sensors/composite_sensors.html#counter.
The iio interface for the step counter is available with commit
a88bfe785 ("iio: core: Introduce STEPS channel, ENABLE mask and INSTANCE
event") soon to be found in linux kernel 3.20. Also the interface is
documented under Documentation/ABI/testing/sysfs-bus-iio
This is how the interface should be used:
- to enable the step counter, we need to write 1 to in_steps_en
- the current number of steps can be read from in_steps_input
- to disable the step counter, we need to write 0 to in_steps_en
This patch adds support for the step counter in the HAL.
The main difference from the other sensors is that the data
returned by the step counter is uint64_t, while other sensors
return float. This patch adds support for uint64_t return values
and adds the STEP_COUNTER in the supported sensors list.
Change-Id: I21a1288a9bf5ea02ae12176d1853dcd71e714bc9
Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
Signed-off-by: Daniel Baluta <daniel.baluta@intel.com>
#ifndef __COMMON_H__
#define __COMMON_H__
-#define MAX_DEVICES 8 /* Check iio devices 0 to MAX_DEVICES-1 */
-#define MAX_SENSORS 10 /* We can handle as many sensors */
+#define MAX_DEVICES 9 /* Check iio devices 0 to MAX_DEVICES-1 */
+#define MAX_SENSORS 11 /* We can handle as many sensors */
#define MAX_CHANNELS 4 /* We can handle as many channels per sensor */
#define MAX_TRIGGERS 8 /* Check for triggers 0 to MAX_TRIGGERS-1 */
#define ENABLE_PATH BASE_PATH "buffer/enable"
#define NAME_PATH BASE_PATH "name"
#define TRIGGER_PATH BASE_PATH "trigger/current_trigger"
+#define SENSOR_ENABLE_PATH BASE_PATH "in_%s_en"
#define SENSOR_OFFSET_PATH BASE_PATH "in_%s_offset"
#define SENSOR_SCALE_PATH BASE_PATH "in_%s_scale"
#define SENSOR_SAMPLING_PATH BASE_PATH "in_%s_sampling_frequency"
void* filter; /* Filtering data for noisy sensors */
int filter_type;/* FILTER_ specification for this sensor ; default is FILTER_NONE */
- float prev_val; /* Previously reported value, for on-change sensors */
-
+ /* Previously reported value, for on-change sensors */
+ union {
+ float data;
+ uint64_t data64;
+ } prev_val;
/*
* Certain sensors expose their readings through sysfs files that have a long response time (100-200 ms for ALS). Rather than block our
* global control loop for several hundred ms each second, offload those lengthy blocking reads to dedicated threads, which will then report
* events before filtering kicks in. We can also use it for statistics.
*/
uint64_t event_count;
+
+ /* Some polled sensors need to be first enabled so that they start
+ * computing a set of values in hardware (e.g step counter). Enabling
+ * is done through a sysfs attribute in_<tag>_en
+ */
+ int needs_enable;
+
}
sensor_info_t;
}
+static int enable_sensor(int dev_num, const char *tag, int enabled)
+{
+ char sysfs_path[PATH_MAX];
+
+ sprintf(sysfs_path, SENSOR_ENABLE_PATH, dev_num, tag);
+ return sysfs_write_int(sysfs_path, enabled);
+}
+
static void enable_iio_timestamp (int dev_num, int known_channels)
{
/* Check if we have a dedicated iio timestamp channel */
}
-static int get_field_count (int s)
+static int get_field_count (int s, size_t *field_size)
{
+ *field_size = sizeof(float);
switch (sensor[s].type) {
case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */
case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */
case SENSOR_TYPE_ROTATION_VECTOR:
return 4;
+ case SENSOR_TYPE_STEP_COUNTER: /* number of steps */
+ *field_size = sizeof(uint64_t);
+ return 1;
default:
ALOGE("Unknown sensor type!\n");
return 0; /* Drop sample */
int ret;
struct timespec target_time;
int64_t timestamp, period, start, stop;
+ size_t field_size;
if (s < 0 || s >= sensor_count) {
ALOGE("Invalid sensor handle!\n");
data.sensor = s;
data.type = sensor[s].type;
- num_fields = get_field_count(s);
+ num_fields = get_field_count(s, &field_size);
/*
* Each condition variable is associated to a mutex that has to be locked by the thread that's waiting on it. We use these condition
/* Read values through sysfs */
for (c=0; c<num_fields; c++) {
- data.data[c] = acquire_immediate_value(s, c);
+ if (field_size == sizeof(uint64_t))
+ data.u64.data[c] = acquire_immediate_uint64_value(s, c);
+ else
+ data.data[c] = acquire_immediate_float_value(s, c);
/* Check and honor termination requests */
if (sensor[s].thread_data_fd[1] == -1)
int dev_fd;
int ret;
int dev_num = sensor[s].dev_num;
+ size_t field_size;
+ int catalog_index = sensor[s].catalog_index;
if (sensor[s].is_virtual)
return sensor_activate_virtual(s, enabled, from_virtual);
setup_trigger(s, sensor[s].init_trigger_name);
enable_buffer(dev_num, 1);
}
+ } else if (sensor[s].mode == MODE_POLL) {
+ if (sensor[s].needs_enable) {
+ enable_sensor(dev_num, sensor_catalog[catalog_index].tag, enabled);
+ }
}
/*
}
/* Ensure that on-change sensors send at least one event after enable */
- sensor[s].prev_val = -1;
+ get_field_count(s, &field_size);
+ if (field_size == sizeof(uint64_t))
+ sensor[s].prev_val.data64 = -1;
+ else
+ sensor[s].prev_val.data = -1;
if (sensor[s].mode == MODE_POLL)
start_acquisition_thread(s);
{
/* There's a sensor report pending for this sensor ; transmit it */
- int num_fields = get_field_count(s);
+ size_t field_size;
+ int num_fields = get_field_count(s, &field_size);
int c;
unsigned char* current_sample;
int ret;
case SENSOR_TYPE_AMBIENT_TEMPERATURE:
case SENSOR_TYPE_TEMPERATURE:
case SENSOR_TYPE_RELATIVE_HUMIDITY:
+ case SENSOR_TYPE_STEP_COUNTER:
flags |= SENSOR_FLAG_ON_CHANGE_MODE;
break;
#include <ctype.h>
#include <dirent.h>
#include <stdlib.h>
+#include <fcntl.h>
#include <utils/Log.h>
#include <hardware/sensors.h>
#include "enumeration.h"
{ DECLARE_GENERIC_CHANNEL("") },
},
},
+ {
+ .tag = "steps",
+ .type = SENSOR_TYPE_STEP_COUNTER,
+ .num_channels = 1,
+ .is_virtual = 0,
+ .channel = {
+ { DECLARE_GENERIC_CHANNEL("steps") },
+ },
+ },
};
#define CATALOG_SIZE ARRAY_SIZE(sensor_catalog)
int sensor_count; /* Detected sensors */
+/* if the sensor has an _en attribute, we need to enable it */
+int get_needs_enable(int dev_num, const char *tag)
+{
+ char sysfs_path[PATH_MAX];
+ int fd;
+
+ sprintf(sysfs_path, SENSOR_ENABLE_PATH, dev_num, tag);
+
+ fd = open(sysfs_path, O_RDWR);
+ if (fd == -1)
+ return 0;
+
+ close(fd);
+ return 1;
+}
+
static void setup_properties_from_pld (int s, int panel, int rotation,
int num_channels)
{
if (sensor_get_order(s, sensor[s].order))
sensor[s].quirks |= QUIRK_FIELD_ORDERING;
+ sensor[s].needs_enable = get_needs_enable(dev_num, sensor_catalog[catalog_index].tag);
+
sensor_count++;
}
fprintf(f, "event: step_detector=%10.2f\n", e->data[0]);
break;
case SENSOR_TYPE_STEP_COUNTER:
- fprintf(f, "event: step_detector=%llu\n",
+ fprintf(f, "event: step_counter=%llu\n",
(unsigned long long)e->u64.step_counter);
break;
}
case SENSOR_TYPE_PROXIMITY:
/* These are on change sensors ; drop the sample if it has the same value as the previously reported one. */
- if (data->data[0] == sensor[s].prev_val)
+ if (data->data[0] == sensor[s].prev_val.data)
return 0;
- sensor[s].prev_val = data->data[0];
+ sensor[s].prev_val.data = data->data[0];
+ break;
+ case SENSOR_TYPE_STEP_COUNTER:
+ if (data->u64.step_counter == sensor[s].prev_val.data64)
+ return 0;
+ sensor[s].prev_val.data64 = data->u64.data[0];
break;
}
}
-float acquire_immediate_value (int s, int c)
+float acquire_immediate_float_value (int s, int c)
{
char sysfs_path[PATH_MAX];
float val;
return (val + offset) * scale * correction;
}
+
+uint64_t acquire_immediate_uint64_value (int s, int c)
+{
+ char sysfs_path[PATH_MAX];
+ uint64_t val;
+ int ret;
+ int dev_num = sensor[s].dev_num;
+ int i = sensor[s].catalog_index;
+ const char* raw_path = sensor_catalog[i].channel[c].raw_path;
+ const char* input_path = sensor_catalog[i].channel[c].input_path;
+ float scale = sensor[s].scale ? sensor[s].scale : sensor[s].channel[c].scale;
+ float offset = sensor[s].offset;
+ int sensor_type = sensor_catalog[i].type;
+ float correction;
+
+ /* In case correction has been requested using properties, apply it */
+ correction = sensor[s].channel[c].opt_scale;
+
+ /* Acquire a sample value for sensor s / channel c through sysfs */
+
+ if (input_path[0]) {
+ sprintf(sysfs_path, BASE_PATH "%s", dev_num, input_path);
+ ret = sysfs_read_uint64(sysfs_path, &val);
+
+ if (!ret)
+ return val * correction;
+ };
+
+ if (!raw_path[0])
+ return 0;
+
+ sprintf(sysfs_path, BASE_PATH "%s", dev_num, raw_path);
+ ret = sysfs_read_uint64(sysfs_path, &val);
+
+ if (ret == -1)
+ return 0;
+
+ return (val + offset) * scale * correction;
+}
#include "common.h"
void select_transform (int s);
-float acquire_immediate_value (int s, int c);
+float acquire_immediate_float_value (int s, int c);
+uint64_t acquire_immediate_uint64_value (int s, int c);
#endif
return 0;
}
+int sysfs_read_uint64(const char path[PATH_MAX], uint64_t *value)
+{
+ int fd;
+ int len;
+ char buf[20] = {0};
+
+ if (!path[0] || !value) {
+ return -1;
+ }
+
+ fd = open(path, O_RDONLY);
+
+ if (fd == -1) {
+ ALOGV("Cannot open %s (%s)\n", path, strerror(errno));
+ return -1;
+ }
+
+ len = read(fd, buf, sizeof(buf));
+
+ close(fd);
+
+ if (len <= 0) {
+ ALOGW("Cannot read uint64 from %s (%s)\n", path,
+ strerror(errno));
+ return -1;
+ }
+
+ *value = atoll(buf);
+
+ ALOGV("Read %llu from %s\n", *value, path);
+
+ return 0;
+}
+
+
int64_t get_timestamp_realtime (void)
{
int sysfs_read_float (const char path[PATH_MAX], float *value);
int sysfs_write_float(const char path[PATH_MAX], float value);
+int sysfs_read_uint64(const char path[PATH_MAX], uint64_t *value);
+
void set_timestamp (struct timespec *out, int64_t target_ns);
int64_t get_timestamp_boot (void);