--- /dev/null
+#
+# Copyright (C) 2014 Intel Corporation.
+#
+
+# IIO sensors HAL module implementation, compiled as hw/iio-sensors-hal.so
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+src_path := .
+src_files := $(src_path)/entry.c \
+ $(src_path)/enumeration.c \
+ $(src_path)/control.c \
+ $(src_path)/description.c \
+ $(src_path)/utils.c \
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH) vendor/intel/hardware/iio-sensors-hal
+LOCAL_MODULE := iio-sensors-hal
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DLOG_TAG=\"Sensors\" -fvisibility=hidden
+LOCAL_LDFLAGS := -Wl,--gc-sections
+LOCAL_SHARED_LIBRARIES := liblog libcutils libdl
+LOCAL_PRELINK_MODULE := false
+LOCAL_SRC_FILES := $(src_files)
+
+include $(BUILD_SHARED_LIBRARY)
+
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#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_CHANNELS 4 /* We can handle as many channels per sensor */
+
+#define DEV_FILE_PATH "/dev/iio:device%d"
+
+#define BASE_PATH "/sys/bus/iio/devices/iio:device%d/"
+
+#define CHANNEL_PATH BASE_PATH "scan_elements/"
+#define ENABLE_PATH BASE_PATH "buffer/enable"
+#define NAME_PATH BASE_PATH "name"
+#define TRIGGER_PATH BASE_PATH "trigger/current_trigger"
+#define COMMON_OFFSET_PATH BASE_PATH "in_%s_offset"
+#define COMMON_SCALE_PATH BASE_PATH "in_%s_scale"
+
+#define MAX_TYPE_SPEC_LEN 32 /* Channel type spec len; ex: "le:u10/16>>0" */
+#define MAX_SENSOR_REPORT_SIZE 32 /* Sensor report buffer size */
+
+#define MAX_NAME_SIZE 32
+
+#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0])
+
+struct channel_descriptor_t
+{
+ /* sysfs entries located under scan_elements */
+ const char *en_path; /* Enabled sysfs file name ; ex: "in_temp_en" */
+ const char *type_path; /* _type sysfs file name */
+ const char *index_path; /* _index sysfs file name */
+
+ /* sysfs entries located in /sys/bus/iio/devices/iio:deviceX */
+ const char *raw_path; /* _raw sysfs file name */
+ const char *input_path; /* _input sysfs file name */
+};
+
+struct sensor_catalog_entry_t
+{
+ const char *tag; /* Prefix such as "accel", "gyro", "temp"... */
+ const int type; /* Sensor type ; ex: SENSOR_TYPE_ACCELEROMETER */
+ const int num_channels; /* Expected iio channels for this sensor */
+ struct channel_descriptor_t channel[MAX_CHANNELS];
+};
+
+struct datum_info_t
+{
+ char sign;
+ char endianness;
+ short realbits;
+ short storagebits;
+ short shift;
+};
+
+struct channel_info_t
+{
+ int offset; /* Offset in bytes within the iio character device report */
+ int size; /* Field size in bytes */
+ char type_spec[MAX_TYPE_SPEC_LEN]; /* From driver; ex: le:u10/16>>0 */
+ struct datum_info_t type_info; /* Decoded contents of type spec */
+};
+
+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 */
+
+ float max_range;
+ float resolution;
+ float power;
+
+ float offset; /* (cooked = raw + offset) * scale */
+ float scale;
+
+ int dev_num; /* Associated iio dev num, ex: 3 for /dev/iio:device3 */
+ int enable_count;
+
+ int catalog_index;/* Associated entry within the sensor_catalog array */
+
+ int num_channels; /* Actual channel count ; 0 for poll mode sensors */
+
+ /*
+ * The array below indicates where to gather report data for this
+ * sensor inside the reports that we read from the iio character device.
+ * It is updated whenever channels are enabled or disabled on the same
+ * device. Channel size indicates the size in bytes of fields, and
+ * should be zero for disabled channels. The type field indicates how a
+ * specific channel data item is structured.
+ */
+ struct channel_info_t channel[MAX_CHANNELS];
+
+ /*
+ * This flag is set if we acquired data from the sensor but did not
+ * forward it to upper layers (i.e. Android) yet. If so, report_buffer
+ * contains that data.
+ */
+ int report_pending;
+
+ unsigned char report_buffer[MAX_SENSOR_REPORT_SIZE];
+
+ /* Note: we may have to explicitely serialize access to some fields */
+};
+
+/* Reference a few commonly used variables... */
+extern int sensor_count;
+extern struct sensor_info_t sensor_info[MAX_SENSORS];
+extern struct sensor_catalog_entry_t sensor_catalog[];
+extern int sensors_per_device[MAX_DEVICES];
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <math.h>
+#include <utils/Log.h>
+#include <hardware/sensors.h>
+#include "control.h"
+#include "enumeration.h"
+#include "utils.h"
+
+/* Currently active sensors count, per device */
+static int poll_sensors_per_dev[MAX_DEVICES]; /* poll-mode sensors */
+static int trig_sensors_per_dev[MAX_DEVICES]; /* trigger, event based */
+
+static int device_fd[MAX_DEVICES]; /* fd on the /dev/iio:deviceX file */
+
+static int poll_fd; /* epoll instance covering all enabled sensors */
+
+/* Timestamp for the moment when we last exited a poll operation */
+static int64_t last_poll_exit_ts;
+
+/* Cap the time between poll operations to this, to counter runaway polls */
+#define POLL_MIN_INTERVAL 10000 /* uS */
+
+static int active_poll_sensors; /* Number of enabled poll-mode sensors */
+
+
+static int enable_buffer(int dev_num, int enabled)
+{
+ char sysfs_path[PATH_MAX];
+
+ sprintf(sysfs_path, ENABLE_PATH, dev_num);
+
+ /* Low level, non-multiplexed, enable/disable routine */
+ return sysfs_write_int(sysfs_path, enabled);
+}
+
+
+static int setup_trigger(int dev_num, const char* trigger_val)
+{
+ char sysfs_path[PATH_MAX];
+
+ sprintf(sysfs_path, TRIGGER_PATH, dev_num);
+
+ return sysfs_write_str(sysfs_path, trigger_val);
+}
+
+
+static void refresh_sensor_report_maps(int dev_num)
+{
+ /*
+ * Read sysfs files from a iio device's scan_element directory, and
+ * build a couple of tables from that data. These tables will tell, for
+ * each sensor, where to gather relevant data in a device report, i.e.
+ * the structure that we read from the /dev/iio:deviceX file in order to
+ * sensor report, itself being the data that we return to Android when a
+ * sensor poll completes. The mapping should be straightforward in the
+ * case where we have a single sensor active per iio device but, this is
+ * not the general case. In general several sensors can be handled
+ * through a single iio device, and the _en, _index and _type syfs
+ * entries all concur to paint a picture of what the structure of the
+ * device report is.
+ */
+
+ int s;
+ int c;
+ int n;
+ int i;
+ int ch_enabled;
+ int ch_index;
+ char* ch_spec;
+ char spec_buf[MAX_TYPE_SPEC_LEN];
+ struct datum_info_t* ch_info;
+ int size;
+ char sysfs_path[PATH_MAX];
+ int active_channels;
+ int offset;
+ int channel_count;
+ int channel_size_from_index[MAX_SENSORS * MAX_CHANNELS] = { 0 };
+ int sensor_handle_from_index[MAX_SENSORS * MAX_CHANNELS] = { 0 };
+ int channel_number_from_index[MAX_SENSORS * MAX_CHANNELS] = { 0 };
+
+ active_channels = 0;
+
+ /* For each sensor that is linked to this device */
+ for (s=0; s<sensor_count; s++) {
+ if (sensor_info[s].dev_num != dev_num)
+ continue;
+
+ i = sensor_info[s].catalog_index;
+
+ /* Read channel status through syfs attributes */
+ for (c=0; c<sensor_info[s].num_channels; c++) {
+
+ /* Read _en file */
+ sprintf(sysfs_path, CHANNEL_PATH "%s",
+ sensor_info[s].dev_num,
+ sensor_catalog[i].channel[c].en_path);
+
+ n = sysfs_read_int(sysfs_path, &ch_enabled);
+
+ if (n == -1) {
+ ALOGW( "Failed to read _en flag: %s\n",
+ sysfs_path);
+ continue;
+ }
+
+ if (!ch_enabled != 1) {
+ sensor_info[s].channel[c].size = 0;
+ }
+
+ /* Read _type file */
+ sprintf(sysfs_path, CHANNEL_PATH "%s",
+ sensor_info[s].dev_num,
+ sensor_catalog[i].channel[c].type_path);
+
+ n = sysfs_read_str(sysfs_path, spec_buf,
+ sizeof(spec_buf));
+
+ if (n == -1) {
+ ALOGW( "Failed to read type: %s\n",
+ sysfs_path);
+ continue;
+ }
+
+ ch_spec = sensor_info[s].channel[c].type_spec;
+
+ memcpy(ch_spec, spec_buf, sizeof(spec_buf));
+
+ ch_info = &sensor_info[s].channel[c].type_info;
+
+ size = decode_type_spec(ch_spec, ch_info);
+
+ /* Read _index file */
+ sprintf(sysfs_path, CHANNEL_PATH "%s",
+ sensor_info[s].dev_num,
+ sensor_catalog[i].channel[c].index_path);
+
+ n = sysfs_read_int(sysfs_path, &ch_index);
+
+ if (n == -1) {
+ ALOGW( "Failed to read index: %s\n",
+ sysfs_path);
+ continue;
+ }
+
+ /* Record what this index is about */
+
+ sensor_handle_from_index [ch_index] = s;
+ channel_number_from_index[ch_index] = c;
+ channel_size_from_index [ch_index] = size;
+
+ active_channels++;
+ }
+ }
+
+ ALOGI("Found %d enabled channels for iio device %d\n", active_channels,
+ dev_num);
+
+ /*
+ * Now that we know which channels are enabled, their sizes and their
+ * ordering, update channels offsets within device report. Note: there
+ * is a possibility that several sensors share the same index, with
+ * their data fields being isolated by masking and shifting as specified
+ * through the real bits and shift values in type attributes. This case
+ * is not currently supported. Also, the code below assumes no hole in
+ * the sequence of indices, so it is dependent on discovery of all
+ * sensors.
+ */
+ offset = 0;
+ for (i=0; i<MAX_SENSORS * MAX_CHANNELS; i++) {
+ s = sensor_handle_from_index[i];
+ c = channel_number_from_index[i];
+ size = channel_size_from_index[i];
+
+ if (!size)
+ continue;
+
+ ALOGI("S%d C%d : offset %d, size %d, type %s\n",
+ s, c, offset, size, sensor_info[s].channel[c].type_spec);
+
+ sensor_info[s].channel[c].offset = offset;
+ sensor_info[s].channel[c].size = size;
+
+ offset += size;
+ }
+}
+
+
+int adjust_counters (int s, int enabled)
+{
+ /*
+ * Adjust counters based on sensor enable action. Return values are:
+ * -1 if there's an inconsistency: abort action in this case
+ * 0 if the operation was completed and we're all set
+ * 1 if we toggled the state of the sensor and there's work left
+ */
+
+ int dev_num = sensor_info[s].dev_num;
+
+ /* Refcount per sensor, in terms of enable count */
+ if (enabled) {
+ ALOGI("Enabling sensor %d (iio device %d: %s)\n",
+ s, dev_num, sensor_info[s].internal_name);
+
+ sensor_info[s].enable_count++;
+
+ if (sensor_info[s].enable_count != 1)
+ return 0; /* The sensor was, and remains, in use */
+ } else {
+ if (sensor_info[s].enable_count == 0)
+ return -1; /* Spurious disable call */
+
+ ALOGI("Disabling sensor %d (iio device %d)\n", s, dev_num);
+
+ sensor_info[s].enable_count--;
+
+ if (sensor_info[s].enable_count > 0)
+ return 0; /* The sensor was, and remains, in use */
+
+ /* Sensor disabled, clear up pending data */
+
+ sensor_info[s].report_pending = 0;
+ memset(sensor_info[s].report_buffer, 0, MAX_SENSOR_REPORT_SIZE);
+ }
+
+ /* We changed the state of a sensor - adjust per iio device counters */
+
+ /* If this is a regular event-driven sensor */
+ if (sensor_info[s].num_channels) {
+
+ if (enabled)
+ trig_sensors_per_dev[dev_num]++;
+ else
+ trig_sensors_per_dev[dev_num]--;
+
+ return 1;
+ }
+
+ if (enabled) {
+ active_poll_sensors++;
+ poll_sensors_per_dev[dev_num]++;
+ return 1;
+ }
+
+ active_poll_sensors--;
+ poll_sensors_per_dev[dev_num]--;
+ return 1;
+}
+
+
+int sensor_activate(int s, int enabled)
+{
+ char sysfs_path[PATH_MAX];
+ char device_name[PATH_MAX];
+ char trigger_name[MAX_NAME_SIZE + 16];
+ int c;
+ struct epoll_event ev = {0};
+ int dev_fd;
+ int ret;
+ int dev_num = sensor_info[s].dev_num;
+ int i = sensor_info[s].catalog_index;
+ int is_poll_sensor = !sensor_info[s].num_channels;
+
+ ret = adjust_counters(s, enabled);
+
+ /* If the operation was neutral in terms of state, we're done */
+ if (ret <= 0)
+ return ret;
+
+ if (!is_poll_sensor) {
+ /* Changes have to be made while the buffer is turned off */
+ enable_buffer(dev_num, 0);
+
+ /* Configure trigger */
+ switch (trig_sensors_per_dev[dev_num]) {
+ case 0:
+ setup_trigger(dev_num, "none");
+ break;
+
+ case 1:
+ sprintf(trigger_name, "%s-dev%d",
+ sensor_info[s].internal_name, dev_num);
+
+ setup_trigger(dev_num, trigger_name);
+ break;
+
+ default:
+ /* The trigger is already set */
+ break;
+ }
+
+ /*
+ * Turn channels associated to this sensor on or off, and update
+ * the channels maps for all sensors associated to this device.
+ */
+ for (c=0;c<sensor_info[s].num_channels; c++) {
+ sprintf(sysfs_path, CHANNEL_PATH "%s",
+ sensor_info[s].dev_num,
+ sensor_catalog[i].channel[c].en_path);
+
+ sysfs_write_int(sysfs_path, enabled);
+ }
+
+ /* If there's at least one sensor left */
+ if (trig_sensors_per_dev[dev_num]) {
+ refresh_sensor_report_maps(dev_num);
+ enable_buffer(dev_num, 1);
+ }
+ }
+
+ /*
+ * Make sure we have a fd on the character device ; conversely, close
+ * the fd if no one is using associated sensor anymore. The assumption
+ * here is that the underlying driver will power on the relevant
+ * hardware block while someone hold a fd on the device.
+ */
+ dev_fd = device_fd[dev_num];
+
+ switch (poll_sensors_per_dev[dev_num] + trig_sensors_per_dev[dev_num]) {
+
+ case 0:
+ if (dev_fd != -1) {
+ /*
+ * Stop watching this fd. This should be a no-op
+ * in case this fd was not in the poll set.
+ */
+ epoll_ctl(poll_fd, EPOLL_CTL_DEL, dev_fd, NULL);
+
+ close(dev_fd);
+ device_fd[dev_num] = -1;
+ }
+ return 0;
+
+ case 1:
+ /* First enabled sensor on this iio device */
+ sprintf(device_name, DEV_FILE_PATH, dev_num);
+ dev_fd = open(device_name, O_RDONLY | O_NONBLOCK);
+
+ if (dev_fd == -1) {
+ ALOGE("Could not open fd on %s (%s)\n",
+ device_name, strerror(errno));
+ return -1;
+ }
+
+ ALOGV("Opened %s: fd=%d\n", device_name, dev_fd);
+
+ device_fd[dev_num] = dev_fd;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!is_poll_sensor && trig_sensors_per_dev[dev_num] == 1) {
+
+ /* Add this iio device fd to the set of watched fds */
+ ev.events = EPOLLIN;
+ ev.data.u32 = dev_num;
+
+ ret = epoll_ctl(poll_fd, EPOLL_CTL_ADD, dev_fd, &ev);
+
+ if (ret == -1) {
+ ALOGE("Failed adding %d to poll set (%s)\n", dev_fd,
+ strerror(errno));
+ return -1;
+ }
+
+ /* Note: poll-mode fds are not readable */
+ }
+
+ return 0;
+}
+
+
+static int integrate_device_report(int dev_num)
+{
+ int len;
+ int s,c;
+ unsigned char buf[MAX_SENSOR_REPORT_SIZE * MAX_SENSORS] = { 0 };
+ int dr_offset;
+ int sr_offset;
+ unsigned char *target;
+ unsigned char *source;
+ int size;
+ int expected_size = 0;
+
+ if (dev_num < 0 || dev_num >= MAX_DEVICES)
+ return -1;
+
+ /* There's an incoming report on the specified fd */
+
+ for (s=0; s<MAX_SENSORS; s++)
+ if (sensor_info[s].enable_count &&
+ sensor_info[s].dev_num == dev_num)
+ for (c=0; c<sensor_info[s].num_channels; c++)
+ expected_size += sensor_info[s].channel[c].size;
+
+ if (expected_size == 0)
+ return 0;
+
+ len = read(device_fd[dev_num], buf, expected_size);
+
+ if (len == -1) {
+ ALOGE("Could not read report from iio device %d (%s)\n",
+ dev_num, strerror(errno));
+ return -1;
+ }
+
+ ALOGV("Read %d bytes from iio device %d\n", len, dev_num);
+
+ dr_offset = 0;
+
+ for (s=0; s<MAX_SENSORS; s++)
+ if (sensor_info[s].enable_count &&
+ sensor_info[s].dev_num == dev_num) {
+ sr_offset = 0;
+
+ /* Copy data from device to sensor report buffer */
+ for (c=0; c<sensor_info[s].num_channels; c++) {
+
+ target = sensor_info[s].report_buffer +
+ sr_offset;
+
+ source = buf + sensor_info[s].channel[c].offset;
+
+ size = sensor_info[s].channel[c].size;
+
+ memcpy(target, source, size);
+
+ sr_offset += size;
+ }
+
+ ALOGV("Sensor %d report available (%d bytes)\n",
+ s, sr_offset);
+
+ sensor_info[s].report_pending = 1;
+ }
+
+ return 0;
+}
+
+
+static float acquire_immediate_value(int s, int c)
+{
+ char sysfs_path[PATH_MAX];
+ float val;
+ int ret;
+ int dev_num = sensor_info[s].dev_num;
+ int i = sensor_info[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_info[s].scale;
+ float offset = sensor_info[s].offset;
+
+ /* 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_float(sysfs_path, &val);
+
+ if (!ret) {
+ return val;
+ }
+ };
+
+ if (!raw_path[0])
+ return 0;
+
+ sprintf(sysfs_path, BASE_PATH "%s", dev_num, raw_path);
+ ret = sysfs_read_float(sysfs_path, &val);
+
+ if (ret == -1)
+ return 0;
+
+ return val;
+}
+
+
+static void propagate_sensor_report(int s, struct sensors_event_t* data)
+{
+ /* There's a sensor report pending for this sensor ; transmit it */
+
+ int catalog_index = sensor_info[s].catalog_index;
+ int sensor_type = sensor_catalog[catalog_index].type;
+ int num_fields;
+ int c;
+ unsigned char* current_sample;
+ int sample_size;
+ struct datum_info_t* sample_type;
+ int64_t s64;
+ float val;
+
+ memset(data, 0, sizeof(sensors_event_t));
+
+ data->version = sizeof(sensors_event_t);
+ data->sensor = s;
+ data->type = sensor_type;
+ data->timestamp = get_timestamp();
+
+ switch (sensor_type) {
+ case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */
+ case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */
+ case SENSOR_TYPE_ORIENTATION: /* degrees */
+ case SENSOR_TYPE_GYROSCOPE: /* radians/s */
+ num_fields = 3;
+ break;
+
+ case SENSOR_TYPE_LIGHT: /* SI lux units */
+ case SENSOR_TYPE_AMBIENT_TEMPERATURE: /* °C */
+ case SENSOR_TYPE_TEMPERATURE: /* °C */
+ case SENSOR_TYPE_PROXIMITY: /* centimeters */
+ case SENSOR_TYPE_PRESSURE: /* hecto-pascal */
+ case SENSOR_TYPE_RELATIVE_HUMIDITY: /* percent */
+ num_fields = 1;
+ break;
+
+ case SENSOR_TYPE_ROTATION_VECTOR:
+ num_fields = 4;
+ break;
+
+ case SENSOR_TYPE_DEVICE_PRIVATE_BASE: /* hidden for now */
+ num_fields = 0;
+ break;
+
+ default:
+ ALOGE("Unknown sensor type!\n");
+ num_fields = 0;
+ break;
+ }
+
+ ALOGV("Sample on sensor %d (type %d):\n", s, sensor_type);
+
+ /* If we're dealing with a poll-mode sensor */
+ if (!sensor_info[s].num_channels) {
+
+ /* Read values through sysfs rather than from a report buffer */
+ for (c=0; c<num_fields; c++) {
+ val = acquire_immediate_value(s, c);
+
+ data->data[c] = transform_sample(sensor_type, c, val);
+
+ ALOGV("\tfield %d: %f\n", c, data->data[c]);
+ }
+ return;
+ }
+
+ /* Convert the data into the expected Android-level format */
+
+ current_sample = sensor_info[s].report_buffer;
+
+ for (c=0; c<num_fields; c++) {
+ sample_size = sensor_info[s].channel[c].size;
+ sample_type = &sensor_info[s].channel[c].type_info;
+
+ s64 = sample_as_int64(current_sample, sample_type);
+
+ val = (sensor_info[s].offset + s64) * sensor_info[s].scale;
+
+ data->data[c] = transform_sample(sensor_type, c, val);
+
+ ALOGV("\tfield %d: %f\n", c, data->data[c]);
+ current_sample += sample_size;
+ }
+}
+
+
+static int get_poll_time (void)
+{
+ if (!active_poll_sensors)
+ return -1; /* Infinite wait */
+
+ return 100; /* ms ... this needs to be dynamic */
+}
+
+
+int sensor_poll(struct sensors_event_t* data, int count)
+{
+ int s;
+ int i;
+ int nfds;
+ int delta;
+ struct epoll_event ev[MAX_DEVICES];
+
+ /* Get one or more events from our collection of sensors */
+
+return_first_available_sensor_report:
+
+ /* If there's at least one available report */
+ for (s=0; s<sensor_count; s++)
+ if (sensor_info[s].report_pending) {
+
+ /* Return that up */
+ propagate_sensor_report(s, data);
+ sensor_info[s].report_pending = 0;
+ ALOGV("Report on sensor %d\n", s);
+ return 1;
+ }
+
+ /* Keep a minimum time interval between poll operations */
+ delta = (get_timestamp() - last_poll_exit_ts)/1000;
+
+ if (delta > 0 && delta < POLL_MIN_INTERVAL)
+ usleep(POLL_MIN_INTERVAL - delta);
+
+ ALOGV("Awaiting sensor data\n");
+
+ nfds = epoll_wait(poll_fd, ev, MAX_DEVICES, get_poll_time());
+
+ last_poll_exit_ts = get_timestamp();
+
+ ALOGV("%d fds signalled\n", nfds);
+
+ /* For each of the devices for which a report is available */
+ for (i=0; i<nfds; i++)
+ if (ev[i].events == EPOLLIN)
+ /* Read report */
+ integrate_device_report(ev[i].data.u32);
+
+ /* It's a good time to invalidate poll-mode sensor values */
+ for (s=0; s<sensor_count; s++)
+ if (!sensor_info[s].num_channels && sensor_info[s].enable_count)
+ sensor_info[s].report_pending = 1;
+
+ goto return_first_available_sensor_report;
+}
+
+
+int sensor_set_delay(int handle, int64_t ns)
+{
+ /* Set the rate at which a specific sensor should report events */
+ /* Continuous reports: accelerometer, gyroscope */
+ /* On change with minimum delay between events: ALS, proximity */
+ /* See sensors.h for indication on sensor trigger modes */
+ return -1;
+}
+
+
+int allocate_control_data (void)
+{
+ int i;
+
+ for (i=0; i<MAX_DEVICES; i++)
+ device_fd[i] = -1;
+
+ poll_fd = epoll_create(MAX_DEVICES);
+
+ if (poll_fd == -1) {
+ ALOGE("Can't create epoll instance for iio sensors!\n");
+ }
+
+ return poll_fd;
+}
+
+
+void delete_control_data (void)
+{
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#ifndef __CONTROL_H__
+#define __CONTROL_H__
+
+int sensor_activate (int handle, int enabled);
+int sensor_set_delay (int handle, int64_t ns);
+int sensor_poll (sensors_event_t* data, int count);
+
+int allocate_control_data (void);
+void delete_control_data (void);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#include <utils/Log.h>
+#include <hardware/sensors.h>
+#include "enumeration.h"
+
+/*
+ * This information should be provided on a sensor basis through a configuration
+ * file, or we should build a catalog of known sensors.
+ */
+
+#define IIO_SENSOR_HAL_VERSION 1
+
+
+char* sensor_get_name (int s)
+{
+ if (sensor_info[s].friendly_name[0] == '\0') {
+
+ /* If we got a iio device name from sysfs, use it */
+ if (sensor_info[s].internal_name[0])
+ sprintf(sensor_info[s].friendly_name, "S%d-%s", s,
+ sensor_info[s].internal_name);
+ else
+ sprintf(sensor_info[s].friendly_name, "S%d", s);
+ }
+
+ return sensor_info[s].friendly_name;
+}
+
+
+char* sensor_get_vendor (int s)
+{
+ if (sensor_info[s].vendor_name[0])
+ return sensor_info[s].vendor_name;
+
+ return "<unknown>";
+}
+
+
+int sensor_get_version (int handle)
+{
+ return IIO_SENSOR_HAL_VERSION;
+}
+
+
+float sensor_get_max_range (int s)
+{
+ int catalog_index;
+ int sensor_type;
+
+ if (sensor_info[s].max_range != 0.0)
+ return sensor_info[s].max_range;
+
+ /* Try returning a sensible value given the sensor type */
+
+ /* We should cap returned samples accordingly... */
+
+ catalog_index = sensor_info[s].catalog_index;
+ sensor_type = sensor_catalog[catalog_index].type;
+
+ switch (sensor_type) {
+ case SENSOR_TYPE_ACCELEROMETER: /* m/s^2 */
+ return 50;
+
+ case SENSOR_TYPE_MAGNETIC_FIELD: /* micro-tesla */
+ return 500;
+
+ case SENSOR_TYPE_ORIENTATION: /* degrees */
+ return 360;
+
+ case SENSOR_TYPE_GYROSCOPE: /* radians/s */
+ return 10;
+
+ case SENSOR_TYPE_LIGHT: /* SI lux units */
+ return 50000;
+
+ case SENSOR_TYPE_AMBIENT_TEMPERATURE: /* °C */
+ case SENSOR_TYPE_TEMPERATURE: /* °C */
+ case SENSOR_TYPE_PROXIMITY: /* centimeters */
+ case SENSOR_TYPE_PRESSURE: /* hecto-pascal */
+ case SENSOR_TYPE_RELATIVE_HUMIDITY: /* percent */
+ return 100;
+
+ default:
+ return 0.0;
+ }
+}
+
+
+float sensor_get_resolution (int s)
+{
+ return sensor_info[s].resolution;
+}
+
+
+float sensor_get_power (int s)
+{
+ /* mA used while sensor is in use ; not sure about volts :) */
+ return sensor_info[s].power;
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#ifndef __DESCRIPTION_H__
+#define __DESCRIPTION_H__
+
+#include "common.h"
+
+char* sensor_get_name (int handle);
+char* sensor_get_vendor (int handle);
+int sensor_get_version (int handle);
+float sensor_get_max_range (int handle);
+float sensor_get_resolution (int handle);
+float sensor_get_power (int handle);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#include <hardware/sensors.h>
+#include <utils/Log.h>
+#include "enumeration.h"
+#include "control.h"
+
+/* This is the IIO Sensors HAL module entry points file */
+
+static int init_count;
+
+static int activate(struct sensors_poll_device_t* dev, int handle, int enabled)
+{
+ if (init_count == 0 || handle < 0 || handle >= sensor_count)
+ return -EINVAL;
+
+ return sensor_activate(handle, enabled);
+}
+
+
+static int set_delay(struct sensors_poll_device_t* dev, int handle, int64_t ns)
+{
+ if (init_count == 0 || handle < 0 || handle >= sensor_count)
+ return -EINVAL;
+
+ return sensor_set_delay(handle, ns);
+}
+
+
+static int poll(struct sensors_poll_device_t* dev, sensors_event_t* data,
+ int count)
+{
+ if (init_count == 0 || !data || count < 1)
+ return -EINVAL;
+
+ return sensor_poll(data, count);
+}
+
+
+static int close_module(hw_device_t *device)
+{
+ if (init_count == 0)
+ return -EINVAL;
+
+ init_count--;
+
+ if (init_count == 0) {
+ ALOGI("Closing IIO sensors HAL module\n");
+ delete_enumeration_data();
+ delete_control_data();
+ }
+
+ return 0;
+}
+
+
+static int initialize_module(const struct hw_module_t *module, const char *id,
+ struct hw_device_t** device)
+{
+ static struct sensors_poll_device_t poll_device;
+
+ if (strcmp(id, SENSORS_HARDWARE_POLL))
+ return -EINVAL;
+
+ poll_device.common.tag = HARDWARE_DEVICE_TAG;
+ poll_device.common.version = 0;
+ poll_device.common.module = (struct hw_module_t*) module;
+ poll_device.common.close = close_module;
+
+ poll_device.activate = activate;
+ poll_device.setDelay = set_delay;
+ poll_device.poll = poll;
+
+ *device = &poll_device.common;
+
+ if (init_count == 0) {
+ ALOGI("Initializing IIO sensors HAL module\n");
+ allocate_control_data();
+ enumerate_sensors();
+ }
+
+ init_count++;
+ return 0;
+}
+
+
+static struct hw_module_methods_t module_methods = {
+ .open = initialize_module
+};
+
+
+/* Externally visible module descriptor */
+struct sensors_module_t __attribute__ ((visibility ("default")))
+ HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = SENSORS_HARDWARE_MODULE_ID,
+ .name = "IIO sensors HAL",
+ .author = "Intel",
+ .methods = &module_methods,
+ },
+ .get_sensors_list = get_sensors_list
+};
+
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#include <dirent.h>
+#include <utils/Log.h>
+#include <hardware/sensors.h>
+#include "enumeration.h"
+#include "description.h"
+#include "utils.h"
+
+/*
+ * This table maps syfs entries in scan_elements directories to sensor types,
+ * and will also be used to determine other sysfs names as well as the iio
+ * device number associated to a specific sensor.
+ */
+
+struct sensor_catalog_entry_t sensor_catalog[] = {
+ DECLARE_SENSOR3("accel", SENSOR_TYPE_ACCELEROMETER, "x", "y", "z")
+ DECLARE_SENSOR3("anglvel", SENSOR_TYPE_GYROSCOPE, "x", "y", "z")
+ DECLARE_SENSOR3("magn", SENSOR_TYPE_MAGNETIC_FIELD, "x", "y", "z")
+ DECLARE_SENSOR0("illuminance",SENSOR_TYPE_LIGHT )
+ DECLARE_SENSOR3("incli", SENSOR_TYPE_ORIENTATION, "x", "y", "z")
+ DECLARE_SENSOR4("rot", SENSOR_TYPE_ROTATION_VECTOR,
+ "quat_x", "quat_y", "quat_z", "quat_w")
+ DECLARE_SENSOR0("temp", SENSOR_TYPE_TEMPERATURE )
+ DECLARE_SENSOR0("timestamp", SENSOR_TYPE_DEVICE_PRIVATE_BASE )
+};
+
+#define CATALOG_SIZE ARRAY_SIZE(sensor_catalog)
+
+
+/* We equate sensor handles to indices in these tables */
+
+struct sensor_t sensor_desc[MAX_SENSORS]; /* Android-level descriptors */
+struct sensor_info_t sensor_info[MAX_SENSORS]; /* Internal descriptors */
+
+int sensors_per_device[MAX_DEVICES]; /* Sensors can share a iio device */
+int sensor_count; /* Detected sensors */
+
+
+static void add_sensor (int dev_num, int catalog_index, int use_polling)
+{
+ int s;
+ int sensor_type;
+ char sysfs_path[PATH_MAX];
+ const char* prefix;
+ float scale;
+
+ if (sensor_count == MAX_SENSORS) {
+ ALOGE("Too many sensors!\n");
+ return;
+ }
+
+ sensor_type = sensor_catalog[catalog_index].type;
+
+ /*
+ * At this point we could check that the expected sysfs attributes are
+ * present ; that would enable having multiple catalog entries with the
+ * same sensor type, accomodating different sets of sysfs attributes.
+ */
+
+ s = sensor_count;
+
+ sensor_info[s].dev_num = dev_num;
+ sensor_info[s].catalog_index = catalog_index;
+
+ if (use_polling)
+ sensor_info[s].num_channels = 0;
+ else
+ sensor_info[s].num_channels =
+ sensor_catalog[catalog_index].num_channels;
+
+ prefix = sensor_catalog[catalog_index].tag;
+
+ /* Read name attribute, if available */
+ sprintf(sysfs_path, NAME_PATH, dev_num);
+ sysfs_read_str(sysfs_path, sensor_info[s].internal_name, MAX_NAME_SIZE);
+
+ /* See if we have general offsets and scale values for this sensor */
+
+ sprintf(sysfs_path, COMMON_OFFSET_PATH, dev_num, prefix);
+ sysfs_read_float(sysfs_path, &sensor_info[s].offset);
+
+ sprintf(sysfs_path, COMMON_SCALE_PATH, dev_num, prefix);
+ if (!sysfs_read_float(sysfs_path, &scale))
+ sensor_info[s].scale = scale;
+
+ /* Initialize Android-visible descriptor */
+ sensor_desc[s].name = sensor_get_name(s);
+ sensor_desc[s].vendor = sensor_get_vendor(s);
+ sensor_desc[s].version = sensor_get_version(s);
+ sensor_desc[s].handle = s;
+ sensor_desc[s].type = sensor_type;
+ sensor_desc[s].maxRange = sensor_get_max_range(s);
+ sensor_desc[s].resolution = sensor_get_resolution(s);
+ sensor_desc[s].power = sensor_get_power(s);
+
+ if (sensor_info[s].internal_name[0] == '\0') {
+ /*
+ * In case the kernel-mode driver doesn't expose a name for
+ * the iio device, use (null)-dev%d as the trigger name...
+ * This can be considered a kernel-mode iio driver bug.
+ */
+ ALOGW("Using null trigger on sensor %d (dev %d)\n", s, dev_num);
+ strcpy(sensor_info[s].internal_name, "(null)");
+ }
+
+ sensor_count++;
+
+ sensors_per_device[dev_num]++;
+}
+
+
+static void discover_poll_sensors (int dev_num, char map[CATALOG_SIZE])
+{
+ char base_dir[PATH_MAX];
+ DIR *dir;
+ char sysfs_dir[PATH_MAX];
+ struct sensor *sensor;
+ struct dirent *d;
+ unsigned int i;
+ int c;
+
+ memset(map, 0, CATALOG_SIZE);
+
+ snprintf(base_dir, sizeof(base_dir), BASE_PATH, dev_num);
+
+ dir = opendir(base_dir);
+ if (!dir) {
+ return;
+ }
+
+ /* Enumerate entries in this iio device's base folder */
+
+ while ((d = readdir(dir))) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ /* If the name matches a catalog entry, flag it */
+ for (i = 0; i<CATALOG_SIZE; i++)
+ for (c=0; c<sensor_catalog[i].num_channels; c++)
+ if (!strcmp(d->d_name,
+ sensor_catalog[i].channel[c].raw_path) ||
+ !strcmp(d->d_name,
+ sensor_catalog[i].channel[c].input_path)) {
+ map[i] = 1;
+ break;
+ }
+ }
+
+ closedir(dir);
+}
+
+
+static void discover_trig_sensors (int dev_num, char map[CATALOG_SIZE])
+{
+ char scan_elem_dir[PATH_MAX];
+ DIR *dir;
+ char sysfs_dir[PATH_MAX];
+ struct sensor *sensor;
+ struct dirent *d;
+ unsigned int i;
+
+ memset(map, 0, CATALOG_SIZE);
+
+ /* Enumerate entries in this iio device's scan_elements folder */
+
+ snprintf(scan_elem_dir, sizeof(scan_elem_dir), CHANNEL_PATH, dev_num);
+
+ dir = opendir(scan_elem_dir);
+ if (!dir) {
+ return;
+ }
+
+ while ((d = readdir(dir))) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ /* Compare en entry to known ones and create matching sensors */
+
+ for (i = 0; i<CATALOG_SIZE; i++)
+ if (!strcmp(d->d_name,
+ sensor_catalog[i].channel[0].en_path)) {
+ map[i] = 1;
+ break;
+ }
+ }
+
+ closedir(dir);
+}
+
+
+void enumerate_sensors (void)
+{
+ /*
+ * Discover supported sensors and allocate control structures for them.
+ * Multiple sensors can potentially rely on a single iio device (each
+ * using their own channels). We can't have multiple sensors of the same
+ * type on the same device. In case of detection as both a poll-mode
+ * and trigger-based sensor, use the trigger usage mode.
+ */
+ char poll_sensors[CATALOG_SIZE];
+ char trig_sensors[CATALOG_SIZE];
+ int dev_num;
+ unsigned int i;
+
+ for (dev_num=0; dev_num<MAX_DEVICES; dev_num++) {
+ discover_poll_sensors(dev_num, poll_sensors);
+ discover_trig_sensors(dev_num, trig_sensors);
+
+ for (i=0; i<CATALOG_SIZE; i++)
+ if (trig_sensors[i])
+ add_sensor(dev_num, i, 0);
+ else
+ if (poll_sensors[i])
+ add_sensor(dev_num, i, 1);
+ }
+
+ ALOGI("Discovered %d sensors\n", sensor_count);
+}
+
+
+void delete_enumeration_data (void)
+{
+ /* Reset sensor count */
+ sensor_count = 0;
+}
+
+
+int get_sensors_list( struct sensors_module_t* module,
+ struct sensor_t const** list)
+{
+ *list = sensor_desc;
+ return sensor_count;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#ifndef __ENUMERATION_H__
+#define __ENUMERATION_H__
+
+#include "common.h"
+
+/*
+ * Macros associating iio sysfs entries to to sensor types ; see
+ * linux/kernel/drivers/iio/industrialio-core.c and
+ * hardware/libhardware/include/hardware/sensor.h
+ */
+
+#define DECLARE_CHANNEL(tag, spacer, name) \
+ { \
+ "in_"tag spacer name"_en", \
+ "in_"tag spacer name"_type", \
+ "in_"tag spacer name"_index", \
+ "in_"tag spacer name"_raw", \
+ "in_"tag spacer name"_input", \
+ },
+
+#define DECLARE_NAMED_CHANNEL(tag, name) DECLARE_CHANNEL(tag, "_", name)
+
+#define DECLARE_GENERIC_CHANNEL(tag) DECLARE_CHANNEL(tag, "", "")
+
+
+#define DECLARE_SENSOR0(tag, type) \
+{ \
+ tag, type, 1, \
+ { \
+ DECLARE_GENERIC_CHANNEL(tag) \
+ } \
+},
+
+#define DECLARE_SENSOR1(tag, type, ch1) \
+{ \
+ tag, type, 1, \
+ { \
+ DECLARE_NAMED_CHANNEL(tag, ch1) \
+ } \
+},
+
+#define DECLARE_SENSOR2(tag, type, ch1, ch2) \
+{ \
+ tag, type, 2, \
+ { \
+ DECLARE_NAMED_CHANNEL(tag, ch1) \
+ DECLARE_NAMED_CHANNEL(tag, ch2) \
+ } \
+},
+
+#define DECLARE_SENSOR3(tag, type, ch1, ch2, ch3) \
+{ \
+ tag, type, 3, \
+ { \
+ DECLARE_NAMED_CHANNEL(tag, ch1) \
+ DECLARE_NAMED_CHANNEL(tag, ch2) \
+ DECLARE_NAMED_CHANNEL(tag, ch3) \
+ } \
+},
+
+#define DECLARE_SENSOR4(tag, type, ch1, ch2, ch3, ch4) \
+{ \
+ tag, type, 4, \
+ { \
+ DECLARE_NAMED_CHANNEL(tag, ch1) \
+ DECLARE_NAMED_CHANNEL(tag, ch2) \
+ DECLARE_NAMED_CHANNEL(tag, ch3) \
+ DECLARE_NAMED_CHANNEL(tag, ch4) \
+ } \
+},
+
+int get_sensors_list (struct sensors_module_t* module,
+ struct sensor_t const** list);
+
+void enumerate_sensors (void);
+void delete_enumeration_data (void);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+#include <hardware/sensors.h>
+#include "utils.h"
+
+
+/* Note:
+ *
+ * Some of these calls are going to fail, because not all sensors expose all
+ * possible sysfs attributes. As an optimization we may want to cache which
+ * ones are valid and immediately return in error for inexistent entries.
+ */
+
+int sysfs_write_int(const char path[PATH_MAX], int value)
+{
+ int ret;
+ int fd;
+ int len;
+ char buf[20];
+
+ if (!path[0]) {
+ return -1;
+ }
+
+ fd = open(path, O_WRONLY);
+
+ if (fd == -1) {
+ ALOGV("Cannot open %s (%s)\n", path, strerror(errno));
+ return -1;
+ }
+
+ len = sprintf(buf, "%d", value) + 1;
+
+ ret = write(fd, buf, len);
+
+ if (ret != len) {
+ ALOGW("Cannot write %s (%d bytes) to %s (%s)\n", buf, len, path,
+ strerror(errno));
+ }
+
+ close(fd);
+
+ return ret;
+}
+
+
+int sysfs_read_int(const char path[PATH_MAX], int *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 integer from %s (%s)\n", path,
+ strerror(errno));
+ return -1;
+ }
+
+ *value = atoi(buf);
+
+ ALOGV("Read %d from %s\n", *value, path);
+
+ return 0;
+}
+
+
+int sysfs_write_str(const char path[PATH_MAX], const char *str)
+{
+ int ret;
+ int fd;
+ int len;
+
+ if (!path[0] || !str || !str[0]) {
+ return -1;
+ }
+
+ fd = open(path, O_WRONLY);
+
+ if (fd == -1) {
+ ALOGV("Cannot open %s (%s)\n", path, strerror(errno));
+ return -1;
+ }
+
+ len = strlen(str);
+
+ ret = write(fd, str, len);
+
+ if (ret != len) {
+ ALOGW("Cannot write %s (%d bytes) to %s (%s)\n", str, len, path,
+ strerror(errno));
+ }
+ else
+ ALOGV("Wrote %s to %s\n", str, path);
+
+ close(fd);
+
+ return ret;
+}
+
+
+int sysfs_read_str(const char path[PATH_MAX], char *buf, int buf_len)
+{
+ int fd;
+ int len;
+
+ if (!path[0] || !buf || buf_len < 1)
+ 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, buf_len);
+
+ close(fd);
+
+ if (len == -1) {
+ ALOGW("Cannot read string from %s (%s)\n", path,
+ strerror(errno));
+ return -1;
+ }
+
+ buf[len == 0 ? 0 : len-1] = '\0';
+
+ ALOGV("Read %s from %s\n", buf, path);
+
+ return len;
+}
+
+
+int sysfs_read_float(const char path[PATH_MAX], float *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 float from %s (%s)\n", path,
+ strerror(errno));
+ return -1;
+ }
+
+ *value = (float) strtod(buf, NULL);
+
+ ALOGV("Read %f from %s\n", *value, path);
+
+ return 0;
+}
+
+
+int decode_type_spec( const char type_buf[MAX_TYPE_SPEC_LEN],
+ struct datum_info_t *type_info)
+{
+ /* Return size in bytes for this type specification, or -1 in error */
+ char sign;
+ char endianness;
+ unsigned int realbits, storagebits, shift;
+ int tokens;
+
+ /* Valid specs: "le:u10/16>>0", "le:s16/32>>0" or "le:s32/32>>0" */
+
+ tokens = sscanf(type_buf, "%ce:%c%u/%u>>%u",
+ &endianness, &sign, &realbits, &storagebits, &shift);
+
+ if (tokens != 5 ||
+ (endianness != 'b' && endianness != 'l') ||
+ (sign != 'u' && sign != 's') ||
+ realbits > storagebits ||
+ (storagebits != 16 && storagebits != 32 && storagebits != 64)) {
+ ALOGE("Invalid iio channel type spec: %s\n", type_buf);
+ return -1;
+ }
+
+ type_info->endianness = endianness;
+ type_info->sign = sign;
+ type_info->realbits = (short) realbits;
+ type_info->storagebits = (short) storagebits;
+ type_info->shift = (short) shift;
+
+ return storagebits / 8;
+}
+
+
+int64_t sample_as_int64(unsigned char* sample, struct datum_info_t* type)
+{
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
+ int i;
+
+ switch (type->storagebits) {
+ case 64:
+ u64 = 0;
+
+ if (type->endianness == 'b')
+ for (i=0; i<8; i++)
+ u64 = (u64 << 8) | sample[i];
+ else
+ for (i=7; i>=0; i--)
+ u64 = (u64 << 8) | sample[i];
+
+ if (type->sign == 'u')
+ return (int64_t) (u64 >> type->shift);
+
+ return ((int64_t) u64) >> type->shift;
+
+ case 32:
+ if (type->endianness == 'b')
+ u32 = (sample[0] << 24) | (sample[1] << 16) |
+ (sample[2] << 8) | sample[3];
+ else
+ u32 = (sample[3] << 24) | (sample[2] << 16) |
+ (sample[1] << 8) | sample[0];
+
+ if (type->sign == 'u')
+ return u32 >> type->shift;
+
+ return ((int32_t) u32) >> type->shift;
+
+ case 16:
+ if (type->endianness == 'b')
+ u16 = (sample[0] << 8) | sample[1];
+ else
+ u16 = (sample[1] << 8) | sample[0];
+
+ if (type->sign == 'u')
+ return u16 >> type->shift;
+
+ return ((int16_t) u16) >> type->shift;
+ }
+
+ ALOGE("Unhandled sample storage size\n");
+ return 0;
+}
+
+
+float transform_sample (int sensor_type, int channel, float val)
+{
+ /* Last opportunity to alter sample data before it goes to Android */
+ switch (sensor_type) {
+ case SENSOR_TYPE_ACCELEROMETER:
+ /*
+ * Invert x axis orientation from SI units - see
+ * /hardware/libhardware/include/hardware/sensors.h
+ * for a discussion of what Android expects
+ */
+ if (channel == 0)
+ return -val;
+ break;
+
+ case SENSOR_TYPE_GYROSCOPE:
+ /* Limit drift */
+ if (val > -0.05 && val < 0.05)
+ return 0;
+ break;
+ }
+
+ return val;
+}
+
+
+int64_t get_timestamp(void)
+{
+ struct timespec ts = {0};
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ return 1000000000LL * ts.tv_sec + ts.tv_nsec;
+}
+
+
--- /dev/null
+/*
+ * Copyright (C) 2014 Intel Corporation.
+ */
+
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include "common.h"
+
+int sysfs_read_int (const char path[PATH_MAX], int *value);
+int sysfs_write_int (const char path[PATH_MAX], int value);
+
+int sysfs_read_str (const char path[PATH_MAX], char *buf, int buf_len);
+int sysfs_write_str (const char path[PATH_MAX], const char *buf);
+
+int sysfs_read_float(const char path[PATH_MAX], float *value);
+
+int decode_type_spec(const char type_buf[MAX_TYPE_SPEC_LEN],
+ struct datum_info_t *type_info);
+
+int64_t sample_as_int64 (unsigned char* sample, struct datum_info_t* type);
+
+float transform_sample(int sensor_type, int channel, float val);
+
+int64_t get_timestamp (void);
+
+#endif
+
+
+