OSDN Git Service

iio-sensors: Add support for STEP_COUNTER sensor
authorDaniel Baluta <daniel.baluta@intel.com>
Thu, 29 Jan 2015 10:20:33 +0000 (12:20 +0200)
committerDaniel Baluta <daniel.baluta@intel.com>
Fri, 6 Feb 2015 12:25:43 +0000 (14:25 +0200)
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>
common.h
control.c
description.c
enumeration.c
sens.c
transform.c
transform.h
utils.c
utils.h

index 42cbe76..5718cbc 100644 (file)
--- a/common.h
+++ b/common.h
@@ -5,8 +5,8 @@
 #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 */
 
@@ -18,6 +18,7 @@
 #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"
@@ -202,8 +203,11 @@ typedef struct
        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
@@ -243,6 +247,13 @@ typedef struct
         * 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;
 
index a23518c..3e81095 100644 (file)
--- a/control.c
+++ b/control.c
@@ -129,6 +129,14 @@ static int setup_trigger (int s, const char* trigger_val)
 }
 
 
+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 */
@@ -403,8 +411,9 @@ int adjust_counters (int s, int enabled, int from_virtual)
 }
 
 
-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  */
@@ -424,6 +433,9 @@ static int get_field_count (int s)
                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 */
@@ -478,6 +490,7 @@ static void* acquisition_routine (void* param)
        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");
@@ -496,7 +509,7 @@ static void* acquisition_routine (void* param)
        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
@@ -513,7 +526,10 @@ static void* acquisition_routine (void* param)
 
                /* 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)
@@ -911,6 +927,8 @@ int sensor_activate (int s, int enabled, int from_virtual)
        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);
@@ -943,6 +961,10 @@ int sensor_activate (int s, int enabled, int 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);
+               }
        }
 
        /*
@@ -1004,7 +1026,11 @@ int sensor_activate (int s, int enabled, int from_virtual)
        }
 
        /* 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);
@@ -1194,7 +1220,8 @@ static int propagate_sensor_report (int s, sensors_event_t *data)
 {
        /* 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;
index f44fee3..d6fb3d7 100644 (file)
@@ -455,6 +455,7 @@ flag_t sensor_get_flags (int s)
                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;
 
index be6a0bf..5133c62 100644 (file)
@@ -5,6 +5,7 @@
 #include <ctype.h>
 #include <dirent.h>
 #include <stdlib.h>
+#include <fcntl.h>
 #include <utils/Log.h>
 #include <hardware/sensors.h>
 #include "enumeration.h"
@@ -140,6 +141,15 @@ sensor_catalog_entry_t sensor_catalog[] = {
                        { 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)
@@ -156,6 +166,22 @@ sensor_info_t      sensor[MAX_SENSORS];            /* Internal descriptors      */
 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)
 {
@@ -569,6 +595,8 @@ static void add_sensor (int dev_num, int catalog_index, int mode)
        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++;
 }
 
diff --git a/sens.c b/sens.c
index 9f97068..2d6d523 100644 (file)
--- a/sens.c
+++ b/sens.c
@@ -151,7 +151,7 @@ static void print_event(struct sensors_event_t *e)
                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;
        }
index bc6178d..9f70549 100644 (file)
@@ -347,10 +347,15 @@ static int finalize_sample_default (int s, sensors_event_t* data)
 
                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;
        }
 
@@ -491,7 +496,7 @@ void select_transform (int s)
 }
 
 
-float acquire_immediate_value (int s, int c)
+float acquire_immediate_float_value (int s, int c)
 {
        char sysfs_path[PATH_MAX];
        float val;
@@ -536,3 +541,42 @@ float acquire_immediate_value (int s, int c)
 
        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;
+}
index d11c33c..70c177e 100644 (file)
@@ -8,7 +8,8 @@
 #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
 
diff --git a/utils.c b/utils.c
index 505528d..718b444 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -225,6 +225,41 @@ int sysfs_read_float(const char path[PATH_MAX], float *value)
        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)
 {
diff --git a/utils.h b/utils.h
index d3da472..b8a0a9f 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -16,6 +16,8 @@ int   sysfs_write_str  (const char path[PATH_MAX], const char *buf);
 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);