/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "Sensors"
#define LOG_NDEBUG 1
#include <hardware/sensors.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <math.h>
#include <poll.h>
#include <pthread.h>
#include <sys/select.h>
#include <linux/input.h>
#include <linux/akm8973.h>
#include <linux/capella_cm3602.h>
#include <linux/lightsensor.h>
#include <cutils/atomic.h>
#include <cutils/log.h>
#include <cutils/native_handle.h>
#define __MAX(a,b) ((a)>=(b)?(a):(b))
/*****************************************************************************/
#define MAX_NUM_SENSORS 6
#define SUPPORTED_SENSORS ((1<<MAX_NUM_SENSORS)-1)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define ID_A (0)
#define ID_M (1)
#define ID_O (2)
#define ID_T (3)
#define ID_P (4)
#define ID_L (5)
static int id_to_sensor[MAX_NUM_SENSORS] = {
[ID_A] = SENSOR_TYPE_ACCELEROMETER,
[ID_M] = SENSOR_TYPE_MAGNETIC_FIELD,
[ID_O] = SENSOR_TYPE_ORIENTATION,
[ID_T] = SENSOR_TYPE_TEMPERATURE,
[ID_P] = SENSOR_TYPE_PROXIMITY,
[ID_L] = SENSOR_TYPE_LIGHT,
};
#define SENSORS_AKM_ACCELERATION (1<<ID_A)
#define SENSORS_AKM_MAGNETIC_FIELD (1<<ID_M)
#define SENSORS_AKM_ORIENTATION (1<<ID_O)
#define SENSORS_AKM_TEMPERATURE (1<<ID_T)
#define SENSORS_AKM_GROUP ((1<<ID_A)|(1<<ID_M)|(1<<ID_O)|(1<<ID_T))
#define SENSORS_CM_PROXIMITY (1<<ID_P)
#define SENSORS_CM_GROUP (1<<ID_P)
#define SENSORS_LIGHT (1<<ID_L)
#define SENSORS_LIGHT_GROUP (1<<ID_L)
/*****************************************************************************/
struct sensors_control_context_t {
struct sensors_control_device_t device; // must be first
int akmd_fd;
int cmd_fd;
int lsd_fd;
uint32_t active_sensors;
};
struct sensors_data_context_t {
struct sensors_data_device_t device; // must be first
int events_fd[3];
sensors_data_t sensors[MAX_NUM_SENSORS];
uint32_t pendingSensors;
};
/*
* The SENSORS Module
*/
/* the CM3602 is a binary proximity sensor that triggers around 9 cm on
* this hardware */
#define PROXIMITY_THRESHOLD_CM 9.0f
/*
* the AK8973 has a 8-bit ADC but the firmware seems to average 16 samples,
* or at least makes its calibration on 12-bits values. This increases the
* resolution by 4 bits.
*/
static const struct sensor_t sSensorList[] = {
{ "BMA150 3-axis Accelerometer",
"Bosh",
1, SENSORS_HANDLE_BASE+ID_A,
SENSOR_TYPE_ACCELEROMETER, 4.0f*9.81f, (4.0f*9.81f)/256.0f, 0.2f, { } },
{ "AK8973 3-axis Magnetic field sensor",
"Asahi Kasei",
1, SENSORS_HANDLE_BASE+ID_M,
SENSOR_TYPE_MAGNETIC_FIELD, 2000.0f, 1.0f/16.0f, 6.8f, { } },
{ "AK8973 Orientation sensor",
"Asahi Kasei",
1, SENSORS_HANDLE_BASE+ID_O,
SENSOR_TYPE_ORIENTATION, 360.0f, 1.0f, 7.0f, { } },
{ "CM3602 Proximity sensor",
"Capella Microsystems",
1, SENSORS_HANDLE_BASE+ID_P,
SENSOR_TYPE_PROXIMITY,
PROXIMITY_THRESHOLD_CM, PROXIMITY_THRESHOLD_CM,
0.5f, { } },
{ "CM3602 Light sensor",
"Capella Microsystems",
1, SENSORS_HANDLE_BASE+ID_L,
SENSOR_TYPE_LIGHT, 10240.0f, 1.0f, 0.5f, { } },
};
static const float sLuxValues[8] = {
10.0,
160.0,
225.0,
320.0,
640.0,
1280.0,
2600.0,
10240.0
};
static int open_sensors(const struct hw_module_t* module, const char* name,
struct hw_device_t** device);
static int sensors__get_sensors_list(struct sensors_module_t* module,
struct sensor_t const** list)
{
*list = sSensorList;
return ARRAY_SIZE(sSensorList);
}
static struct hw_module_methods_t sensors_module_methods = {
.open = open_sensors
};
const struct sensors_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = SENSORS_HARDWARE_MODULE_ID,
.name = "AK8973A & CM3602 Sensors Module",
.author = "The Android Open Source Project",
.methods = &sensors_module_methods,
},
.get_sensors_list = sensors__get_sensors_list
};
/*****************************************************************************/
#define AKM_DEVICE_NAME "/dev/akm8973_aot"
#define CM_DEVICE_NAME "/dev/cm3602"
#define LS_DEVICE_NAME "/dev/lightsensor"
// sensor IDs must be a power of two and
// must match values in SensorManager.java
#define EVENT_TYPE_ACCEL_X ABS_X
#define EVENT_TYPE_ACCEL_Y ABS_Z
#define EVENT_TYPE_ACCEL_Z ABS_Y
#define EVENT_TYPE_ACCEL_STATUS ABS_WHEEL
#define EVENT_TYPE_YAW ABS_RX
#define EVENT_TYPE_PITCH ABS_RY
#define EVENT_TYPE_ROLL ABS_RZ
#define EVENT_TYPE_ORIENT_STATUS ABS_RUDDER
#define EVENT_TYPE_MAGV_X ABS_HAT0X
#define EVENT_TYPE_MAGV_Y ABS_HAT0Y
#define EVENT_TYPE_MAGV_Z ABS_BRAKE
#define EVENT_TYPE_TEMPERATURE ABS_THROTTLE
#define EVENT_TYPE_STEP_COUNT ABS_GAS
#define EVENT_TYPE_PROXIMITY ABS_DISTANCE
#define EVENT_TYPE_LIGHT ABS_MISC
// 720 LSG = 1G
#define LSG (720.0f)
// conversion of acceleration data to SI units (m/s^2)
#define CONVERT_A (GRAVITY_EARTH / LSG)
#define CONVERT_A_X (-CONVERT_A)
#define CONVERT_A_Y (CONVERT_A)
#define CONVERT_A_Z (-CONVERT_A)
// conversion of magnetic data to uT units
#define CONVERT_M (1.0f/16.0f)
#define CONVERT_M_X (-CONVERT_M)
#define CONVERT_M_Y (-CONVERT_M)
#define CONVERT_M_Z (CONVERT_M)
#define SENSOR_STATE_MASK (0x7FFF)
/*****************************************************************************/
static int open_inputs(int mode, int *akm_fd, int *p_fd, int *l_fd)
{
/* scan all input drivers and look for "compass" */
int fd = -1;
const char *dirname = "/dev/input";
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
if(dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
*akm_fd = *p_fd = -1;
while((de = readdir(dir))) {
if(de->d_name[0] == '.' &&
(de->d_name[1] == '/0' ||
(de->d_name[1] == '.' && de->d_name[2] == '/0')))
continue;
strcpy(filename, de->d_name);
fd = open(devname, mode);
if (fd>=0) {
char name[80];
if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
name[0] = '/0';
}
if (!strcmp(name, "compass")) {
LOGV("using %s (name=%s)", devname, name);
*akm_fd = fd;
}
else if (!strcmp(name, "proximity")) {
LOGV("using %s (name=%s)", devname, name);
*p_fd = fd;
}
else if (!strcmp(name, "lightsensor-level")) {
LOGV("using %s (name=%s)", devname, name);
*l_fd = fd;
}
else
close(fd);
}
}
closedir(dir);
fd = 0;
if (*akm_fd < 0) {
LOGE("Couldn't find or open 'compass' driver (%s)", strerror(errno));
fd = -1;
}
if (*p_fd < 0) {
LOGE("Couldn't find or open 'proximity' driver (%s)", strerror(errno));
fd = -1;
}
if (*l_fd < 0) {
LOGE("Couldn't find or open 'light' driver (%s)", strerror(errno));
fd = -1;
}
return fd;
}
static int open_akm(struct sensors_control_context_t* dev)
{
if (dev->akmd_fd < 0) {
dev->akmd_fd = open(AKM_DEVICE_NAME, O_RDONLY);
LOGV("%s, fd=%d", __PRETTY_FUNCTION__, dev->akmd_fd);
LOGE_IF(dev->akmd_fd<0, "Couldn't open %s (%s)",
AKM_DEVICE_NAME, strerror(errno));
if (dev->akmd_fd >= 0) {
dev->active_sensors &= ~SENSORS_AKM_GROUP;
}
}
return dev->akmd_fd;
}
static void close_akm(struct sensors_control_context_t* dev)
{
if (dev->akmd_fd >= 0) {
LOGV("%s, fd=%d", __PRETTY_FUNCTION__, dev->akmd_fd);
close(dev->akmd_fd);
dev->akmd_fd = -1;
}
}
static uint32_t read_akm_sensors_state(int fd)
{
short flags;
uint32_t sensors = 0;
// read the actual value of all sensors
if (!ioctl(fd, ECS_IOCTL_APP_GET_MFLAG, &flags)) {
if (flags) sensors |= SENSORS_AKM_ORIENTATION;
else sensors &= ~SENSORS_AKM_ORIENTATION;
}
if (!ioctl(fd, ECS_IOCTL_APP_GET_AFLAG, &flags)) {
if (flags) sensors |= SENSORS_AKM_ACCELERATION;
else sensors &= ~SENSORS_AKM_ACCELERATION;
}
if (!ioctl(fd, ECS_IOCTL_APP_GET_TFLAG, &flags)) {
if (flags) sensors |= SENSORS_AKM_TEMPERATURE;
else sensors &= ~SENSORS_AKM_TEMPERATURE;
}
if (!ioctl(fd, ECS_IOCTL_APP_GET_MVFLAG, &flags)) {
if (flags) sensors |= SENSORS_AKM_MAGNETIC_FIELD;
else sensors &= ~SENSORS_AKM_MAGNETIC_FIELD;
}
return sensors;
}
static uint32_t enable_disable_akm(struct sensors_control_context_t *dev,
uint32_t active, uint32_t sensors,
uint32_t mask)
{
uint32_t now_active_akm_sensors;
int fd = open_akm(dev);
if (fd < 0)
return 0;
LOGV("(before) akm sensors = %08x, real = %08x",
sensors, read_akm_sensors_state(fd));
short flags;
if (mask & SENSORS_AKM_ORIENTATION) {
flags = (sensors & SENSORS_AKM_ORIENTATION) ? 1 : 0;
if (ioctl(fd, ECS_IOCTL_APP_SET_MFLAG, &flags) < 0) {
LOGE("ECS_IOCTL_APP_SET_MFLAG error (%s)", strerror(errno));
}
}
if (mask & SENSORS_AKM_ACCELERATION) {
flags = (sensors & SENSORS_AKM_ACCELERATION) ? 1 : 0;
if (ioctl(fd, ECS_IOCTL_APP_SET_AFLAG, &flags) < 0) {
LOGE("ECS_IOCTL_APP_SET_AFLAG error (%s)", strerror(errno));
}
}
if (mask & SENSORS_AKM_TEMPERATURE) {
flags = (sensors & SENSORS_AKM_TEMPERATURE) ? 1 : 0;
if (ioctl(fd, ECS_IOCTL_APP_SET_TFLAG, &flags) < 0) {
LOGE("ECS_IOCTL_APP_SET_TFLAG error (%s)", strerror(errno));
}
}
if (mask & SENSORS_AKM_MAGNETIC_FIELD) {
flags = (sensors & SENSORS_AKM_MAGNETIC_FIELD) ? 1 : 0;
if (ioctl(fd, ECS_IOCTL_APP_SET_MVFLAG, &flags) < 0) {
LOGE("ECS_IOCTL_APP_SET_MVFLAG error (%s)", strerror(errno));
}
}
now_active_akm_sensors = read_akm_sensors_state(fd);
LOGV("(after) akm sensors = %08x, real = %08x",
sensors, now_active_akm_sensors);
if (!sensors)
close_akm(dev);
return now_active_akm_sensors;
}
static uint32_t read_cm_sensors_state(int fd)
{
int flags;
uint32_t sensors = 0;
// read the actual value of all sensors
if (!ioctl(fd, CAPELLA_CM3602_IOCTL_GET_ENABLED, &flags)) {
if (flags) sensors |= SENSORS_CM_PROXIMITY;
else sensors &= ~SENSORS_CM_PROXIMITY;
}
return sensors;
}
static int open_cm(struct sensors_control_context_t* dev)
{
if (dev->cmd_fd < 0) {
dev->cmd_fd = open(CM_DEVICE_NAME, O_RDONLY);
LOGV("%s, fd=%d", __PRETTY_FUNCTION__, dev->cmd_fd);
LOGE_IF(dev->cmd_fd<0, "Couldn't open %s (%s)",
CM_DEVICE_NAME, strerror(errno));
if (dev->cmd_fd >= 0) {
dev->active_sensors &= ~SENSORS_CM_GROUP;
}
}
return dev->cmd_fd;
}
static void close_cm(struct sensors_control_context_t* dev)
{
if (dev->cmd_fd >= 0) {
LOGV("%s, fd=%d", __PRETTY_FUNCTION__, dev->cmd_fd);
close(dev->cmd_fd);
dev->cmd_fd = -1;
}
}
static int enable_disable_cm(struct sensors_control_context_t *dev,
uint32_t active, uint32_t sensors, uint32_t mask)
{
int rc = 0;
uint32_t now_active_cm_sensors;
int fd = open_cm(dev);
if (fd < 0) {
LOGE("Couldn't open %s (%s)", CM_DEVICE_NAME, strerror(errno));
return 0;
}
LOGV("(before) cm sensors = %08x, real = %08x",
sensors, read_cm_sensors_state(fd));
if (mask & SENSORS_CM_PROXIMITY) {
int flags = (sensors & SENSORS_CM_PROXIMITY) ? 1 : 0;
rc = ioctl(fd, CAPELLA_CM3602_IOCTL_ENABLE, &flags);
if (rc < 0)
LOGE("CAPELLA_CM3602_IOCTL_ENABLE error (%s)", strerror(errno));
}
now_active_cm_sensors = read_cm_sensors_state(fd);
LOGV("(after) cm sensors = %08x, real = %08x",
sensors, now_active_cm_sensors);
return now_active_cm_sensors;
}
static uint32_t read_ls_sensors_state(int fd)
{
int flags;
uint32_t sensors = 0;
// read the actual value of all sensors
if (!ioctl(fd, LIGHTSENSOR_IOCTL_GET_ENABLED, &flags)) {
if (flags) sensors |= SENSORS_LIGHT;
else sensors &= ~SENSORS_LIGHT;
}
return sensors;
}
static int open_ls(struct sensors_control_context_t* dev)
{
if (dev->lsd_fd < 0) {
dev->lsd_fd = open(LS_DEVICE_NAME, O_RDONLY);
LOGV("%s, fd=%d", __PRETTY_FUNCTION__, dev->lsd_fd);
LOGE_IF(dev->lsd_fd<0, "Couldn't open %s (%s)",
LS_DEVICE_NAME, strerror(errno));
if (dev->lsd_fd >= 0) {
dev->active_sensors &= ~SENSORS_LIGHT_GROUP;
}
}
return dev->lsd_fd;
}
static void close_ls(struct sensors_control_context_t* dev)
{
if (dev->lsd_fd >= 0) {
LOGV("%s, fd=%d", __PRETTY_FUNCTION__, dev->lsd_fd);
close(dev->lsd_fd);
dev->lsd_fd = -1;
}
}
static int enable_disable_ls(struct sensors_control_context_t *dev,
uint32_t active, uint32_t sensors, uint32_t mask)
{
int rc = 0;
uint32_t now_active_ls_sensors;
int fd = open_ls(dev);
if (fd < 0) {
LOGE("Couldn't open %s (%s)", LS_DEVICE_NAME, strerror(errno));
return 0;
}
LOGV("(before) ls sensors = %08x, real = %08x",
sensors, read_ls_sensors_state(fd));
if (mask & SENSORS_LIGHT) {
int flags = (sensors & SENSORS_LIGHT) ? 1 : 0;
rc = ioctl(fd, LIGHTSENSOR_IOCTL_ENABLE, &flags);
if (rc < 0)
LOGE("LIGHTSENSOR_IOCTL_ENABLE error (%s)", strerror(errno));
}
now_active_ls_sensors = read_ls_sensors_state(fd);
LOGV("(after) ls sensors = %08x, real = %08x",
sensors, now_active_ls_sensors);
return now_active_ls_sensors;
}
/*****************************************************************************/
static native_handle_t* control__open_data_source(struct sensors_control_context_t *dev)
{
native_handle_t* handle;
int akm_fd, p_fd, l_fd;
if (open_inputs(O_RDONLY, &akm_fd, &p_fd, &l_fd) < 0 ||
akm_fd < 0 || p_fd < 0 || l_fd < 0) {
return NULL;
}
handle = native_handle_create(3, 0);
handle->data[0] = akm_fd;
handle->data[1] = p_fd;
handle->data[2] = l_fd;
return handle;
}
static int control__activate(struct sensors_control_context_t *dev,
int handle, int enabled)
{
if ((handle < SENSORS_HANDLE_BASE) ||
(handle >= SENSORS_HANDLE_BASE+MAX_NUM_SENSORS))
return -1;
uint32_t mask = (1 << handle);
uint32_t sensors = enabled ? mask : 0;
uint32_t active = dev->active_sensors;
uint32_t new_sensors = (active & ~mask) | (sensors & mask);
uint32_t changed = active ^ new_sensors;
if (changed) {
if (!active && new_sensors)
// force all sensors to be updated
changed = SUPPORTED_SENSORS;
dev->active_sensors =
enable_disable_akm(dev,
active & SENSORS_AKM_GROUP,
new_sensors & SENSORS_AKM_GROUP,
changed & SENSORS_AKM_GROUP) |
enable_disable_cm(dev,
active & SENSORS_CM_GROUP,
new_sensors & SENSORS_CM_GROUP,
changed & SENSORS_CM_GROUP) |
enable_disable_ls(dev,
active & SENSORS_LIGHT_GROUP,
new_sensors & SENSORS_LIGHT_GROUP,
changed & SENSORS_LIGHT_GROUP);
}
return 0;
}
static int control__set_delay(struct sensors_control_context_t *dev, int32_t ms)
{
#ifdef ECS_IOCTL_APP_SET_DELAY
if (dev->akmd_fd <= 0) {
return -1;
}
short delay = ms;
if (!ioctl(dev->akmd_fd, ECS_IOCTL_APP_SET_DELAY, &delay)) {
return -errno;
}
return 0;
#else
return -1;
#endif
}
static int control__wake(struct sensors_control_context_t *dev)
{
int err = 0;
int akm_fd, p_fd, l_fd;
if (open_inputs(O_RDWR, &akm_fd, &p_fd, &l_fd) < 0 ||
akm_fd < 0 || p_fd < 0 || l_fd < 0) {
return -1;
}
struct input_event event[1];
event[0].type = EV_SYN;
event[0].code = SYN_CONFIG;
event[0].value = 0;
err = write(akm_fd, event, sizeof(event));
LOGV_IF(err<0, "control__wake(compass), fd=%d (%s)",
akm_fd, strerror(errno));
close(akm_fd);
err = write(p_fd, event, sizeof(event));
LOGV_IF(err<0, "control__wake(proximity), fd=%d (%s)",
p_fd, strerror(errno));
close(p_fd);
err = write(l_fd, event, sizeof(event));
LOGV_IF(err<0, "control__wake(light), fd=%d (%s)",
l_fd, strerror(errno));
close(l_fd);
return err;
}
/*****************************************************************************/
static int data__data_open(struct sensors_data_context_t *dev, native_handle_t* handle)
{
int i;
struct input_absinfo absinfo;
memset(&dev->sensors, 0, sizeof(dev->sensors));
for (i = 0; i < MAX_NUM_SENSORS; i++) {
// by default all sensors have high accuracy
// (we do this because we don't get an update if the value doesn't
// change).
dev->sensors[i].vector.status = SENSOR_STATUS_ACCURACY_HIGH;
}
dev->sensors[ID_A].sensor = SENSOR_TYPE_ACCELEROMETER;
dev->sensors[ID_M].sensor = SENSOR_TYPE_MAGNETIC_FIELD;
dev->sensors[ID_O].sensor = SENSOR_TYPE_ORIENTATION;
dev->sensors[ID_T].sensor = SENSOR_TYPE_TEMPERATURE;
dev->sensors[ID_P].sensor = SENSOR_TYPE_PROXIMITY;
dev->sensors[ID_L].sensor = SENSOR_TYPE_LIGHT;
dev->events_fd[0] = dup(handle->data[0]);
dev->events_fd[1] = dup(handle->data[1]);
dev->events_fd[2] = dup(handle->data[2]);
LOGV("data__data_open: compass fd = %d", handle->data[0]);
LOGV("data__data_open: proximity fd = %d", handle->data[1]);
LOGV("data__data_open: light fd = %d", handle->data[2]);
// Framework will close the handle
native_handle_delete(handle);
dev->pendingSensors = 0;
if (!ioctl(dev->events_fd[1], EVIOCGABS(ABS_DISTANCE), &absinfo)) {
LOGV("proximity sensor initial value %d/n", absinfo.value);
dev->pendingSensors |= SENSORS_CM_PROXIMITY;
// FIXME: we should save here absinfo.{minimum, maximum, etc}
// and use them to scale the return value according to
// the sensor description.
dev->sensors[ID_P].distance = (float)absinfo.value;
}
else LOGE("Cannot get proximity sensor initial value: %s/n",
strerror(errno));
return 0;
}
static int data__data_close(struct sensors_data_context_t *dev)
{
if (dev->events_fd[0] >= 0) {
//LOGV("(data close) about to close compass fd=%d", dev->events_fd[0]);
close(dev->events_fd[0]);
dev->events_fd[0] = -1;
}
if (dev->events_fd[1] >= 0) {
//LOGV("(data close) about to close proximity fd=%d", dev->events_fd[1]);
close(dev->events_fd[1]);
dev->events_fd[1] = -1;
}
if (dev->events_fd[2] >= 0) {
//LOGV("(data close) about to close light fd=%d", dev->events_fd[1]);
close(dev->events_fd[2]);
dev->events_fd[2] = -1;
}
return 0;
}
static int pick_sensor(struct sensors_data_context_t *dev,
sensors_data_t* values)
{
uint32_t mask = SUPPORTED_SENSORS;
while (mask) {
uint32_t i = 31 - __builtin_clz(mask);
mask &= ~(1<<i);
if (dev->pendingSensors & (1<<i)) {
dev->pendingSensors &= ~(1<<i);
*values = dev->sensors[i];
values->sensor = id_to_sensor[i];
LOGV_IF(0, "%d [%f, %f, %f]",
values->sensor,
values->vector.x,
values->vector.y,
values->vector.z);
return i;
}
}
LOGE("no sensor to return: pendingSensors = %08x", dev->pendingSensors);
return -1;
}
static uint32_t data__poll_process_akm_abs(struct sensors_data_context_t *dev,
int fd __attribute__((unused)),
struct input_event *event)
{
uint32_t new_sensors = 0;
if (event->type == EV_ABS) {
LOGV("compass type: %d code: %d value: %-5d time: %ds",
event->type, event->code, event->value,
(int)event->time.tv_sec);
switch (event->code) {
case EVENT_TYPE_ACCEL_X:
new_sensors |= SENSORS_AKM_ACCELERATION;
dev->sensors[ID_A].acceleration.x = event->value * CONVERT_A_X;
break;
case EVENT_TYPE_ACCEL_Y:
new_sensors |= SENSORS_AKM_ACCELERATION;
dev->sensors[ID_A].acceleration.y = event->value * CONVERT_A_Y;
break;
case EVENT_TYPE_ACCEL_Z:
new_sensors |= SENSORS_AKM_ACCELERATION;
dev->sensors[ID_A].acceleration.z = event->value * CONVERT_A_Z;
break;
case EVENT_TYPE_MAGV_X:
new_sensors |= SENSORS_AKM_MAGNETIC_FIELD;
dev->sensors[ID_M].magnetic.x = event->value * CONVERT_M_X;
break;
case EVENT_TYPE_MAGV_Y:
new_sensors |= SENSORS_AKM_MAGNETIC_FIELD;
dev->sensors[ID_M].magnetic.y = event->value * CONVERT_M_Y;
break;
case EVENT_TYPE_MAGV_Z:
new_sensors |= SENSORS_AKM_MAGNETIC_FIELD;
dev->sensors[ID_M].magnetic.z = event->value * CONVERT_M_Z;
break;
case EVENT_TYPE_YAW:
new_sensors |= SENSORS_AKM_ORIENTATION;
dev->sensors[ID_O].orientation.azimuth = event->value;
break;
case EVENT_TYPE_PITCH:
new_sensors |= SENSORS_AKM_ORIENTATION;
dev->sensors[ID_O].orientation.pitch = event->value;
break;
case EVENT_TYPE_ROLL:
new_sensors |= SENSORS_AKM_ORIENTATION;
dev->sensors[ID_O].orientation.roll = -event->value;
break;
case EVENT_TYPE_TEMPERATURE:
new_sensors |= SENSORS_AKM_TEMPERATURE;
dev->sensors[ID_T].temperature = event->value;
break;
case EVENT_TYPE_STEP_COUNT:
// step count (only reported in MODE_FFD)
// we do nothing with it for now.
break;
case EVENT_TYPE_ACCEL_STATUS:
// accuracy of the calibration (never returned!)
//LOGV("G-Sensor status %d", event->value);
break;
case EVENT_TYPE_ORIENT_STATUS: {
// accuracy of the calibration
uint32_t v = (uint32_t)(event->value & SENSOR_STATE_MASK);
LOGV_IF(dev->sensors[ID_O].orientation.status != (uint8_t)v,
"M-Sensor status %d", v);
dev->sensors[ID_O].orientation.status = (uint8_t)v;
}
break;
}
}
return new_sensors;
}
static uint32_t data__poll_process_cm_abs(struct sensors_data_context_t *dev,
int fd __attribute__((unused)),
struct input_event *event)
{
uint32_t new_sensors = 0;
if (event->type == EV_ABS) {
LOGV("proximity type: %d code: %d value: %-5d time: %ds",
event->type, event->code, event->value,
(int)event->time.tv_sec);
if (event->code == EVENT_TYPE_PROXIMITY) {
new_sensors |= SENSORS_CM_PROXIMITY;
/* event->value seems to be 0 or 1, scale it to the threshold */
dev->sensors[ID_P].distance = event->value * PROXIMITY_THRESHOLD_CM;
}
}
return new_sensors;
}
static uint32_t data__poll_process_ls_abs(struct sensors_data_context_t *dev,
int fd __attribute__((unused)),
struct input_event *event)
{
uint32_t new_sensors = 0;
if (event->type == EV_ABS) {
LOGV("light-level type: %d code: %d value: %-5d time: %ds",
event->type, event->code, event->value,
(int)event->time.tv_sec);
if (event->code == EVENT_TYPE_LIGHT) {
struct input_absinfo absinfo;
int index;
if (!ioctl(fd, EVIOCGABS(ABS_DISTANCE), &absinfo)) {
index = event->value;
if (index >= 0) {
new_sensors |= SENSORS_LIGHT;
if (index >= ARRAY_SIZE(sLuxValues)) {
index = ARRAY_SIZE(sLuxValues) - 1;
}
dev->sensors[ID_L].light = sLuxValues[index];
}
}
}
}
return new_sensors;
}
static void data__poll_process_syn(struct sensors_data_context_t *dev,
struct input_event *event,
uint32_t new_sensors)
{
if (new_sensors) {
dev->pendingSensors |= new_sensors;
int64_t t = event->time.tv_sec*1000000000LL +
event->time.tv_usec*1000;
while (new_sensors) {
uint32_t i = 31 - __builtin_clz(new_sensors);
new_sensors &= ~(1<<i);
dev->sensors[i].time = t;
}
}
}
static int data__poll(struct sensors_data_context_t *dev, sensors_data_t* values)
{
int akm_fd = dev->events_fd[0];
int cm_fd = dev->events_fd[1];
int ls_fd = dev->events_fd[2];
if (akm_fd < 0) {
LOGE("invalid compass file descriptor, fd=%d", akm_fd);
return -1;
}
if (cm_fd < 0) {
LOGE("invalid proximity-sensor file descriptor, fd=%d", cm_fd);
return -1;
}
if (ls_fd < 0) {
LOGE("invalid light-sensor file descriptor, fd=%d", ls_fd);
return -1;
}
// there are pending sensors, returns them now...
if (dev->pendingSensors) {
LOGV("pending sensors 0x%08x", dev->pendingSensors);
return pick_sensor(dev, values);
}
// wait until we get a complete event for an enabled sensor
uint32_t new_sensors = 0;
while (1) {
/* read the next event; first, read the compass event, then the
proximity event */
struct input_event event;
int got_syn = 0;
int exit = 0;
int nread;
fd_set rfds;
int n;
FD_ZERO(&rfds);
FD_SET(akm_fd, &rfds);
FD_SET(cm_fd, &rfds);
FD_SET(ls_fd, &rfds);
n = select(__MAX(akm_fd, __MAX(cm_fd, ls_fd)) + 1, &rfds,
NULL, NULL, NULL);
LOGV("return from select: %d/n", n);
if (n < 0) {
LOGE("%s: error from select(%d, %d): %s",
__FUNCTION__,
akm_fd, cm_fd, strerror(errno));
return -1;
}
if (FD_ISSET(akm_fd, &rfds)) {
nread = read(akm_fd, &event, sizeof(event));
if (nread == sizeof(event)) {
new_sensors |= data__poll_process_akm_abs(dev, akm_fd, &event);
LOGV("akm abs %08x", new_sensors);
got_syn = event.type == EV_SYN;
exit = got_syn && event.code == SYN_CONFIG;
if (got_syn) {
LOGV("akm syn %08x", new_sensors);
data__poll_process_syn(dev, &event, new_sensors);
new_sensors = 0;
}
}
else LOGE("akm read too small %d", nread);
}
else LOGV("akm fd is not set");
if (FD_ISSET(cm_fd, &rfds)) {
nread = read(cm_fd, &event, sizeof(event));
if (nread == sizeof(event)) {
new_sensors |= data__poll_process_cm_abs(dev, cm_fd, &event);
LOGV("cm abs %08x", new_sensors);
got_syn |= event.type == EV_SYN;
exit |= got_syn && event.code == SYN_CONFIG;
if (got_syn) {
LOGV("cm syn %08x", new_sensors);
data__poll_process_syn(dev, &event, new_sensors);
new_sensors = 0;
}
}
else LOGE("cm read too small %d", nread);
}
else LOGV("cm fd is not set");
if (FD_ISSET(ls_fd, &rfds)) {
nread = read(ls_fd, &event, sizeof(event));
if (nread == sizeof(event)) {
new_sensors |= data__poll_process_ls_abs(dev, ls_fd, &event);
LOGV("ls abs %08x", new_sensors);
got_syn |= event.type == EV_SYN;
exit |= got_syn && event.code == SYN_CONFIG;
if (got_syn) {
LOGV("ls syn %08x", new_sensors);
data__poll_process_syn(dev, &event, new_sensors);
new_sensors = 0;
}
}
else LOGE("ls read too small %d", nread);
}
else LOGV("ls fd is not set");
if (exit) {
// we use SYN_CONFIG to signal that we need to exit the
// main loop.
//LOGV("got empty message: value=%d", event->value);
LOGV("exit");
return 0x7FFFFFFF;
}
if (got_syn && dev->pendingSensors) {
LOGV("got syn, picking sensor");
return pick_sensor(dev, values);
}
}
}
/*****************************************************************************/
static int control__close(struct hw_device_t *dev)
{
struct sensors_control_context_t* ctx =
(struct sensors_control_context_t*)dev;
if (ctx) {
close_akm(ctx);
close_cm(ctx);
close_ls(ctx);
free(ctx);
}
return 0;
}
static int data__close(struct hw_device_t *dev)
{
struct sensors_data_context_t* ctx = (struct sensors_data_context_t*)dev;
if (ctx) {
data__data_close(ctx);
free(ctx);
}
return 0;
}
/** Open a new instance of a sensor device using name */
static int open_sensors(const struct hw_module_t* module, const char* name,
struct hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, SENSORS_HARDWARE_CONTROL)) {
struct sensors_control_context_t *dev;
dev = malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
dev->akmd_fd = -1;
dev->cmd_fd = -1;
dev->lsd_fd = -1;
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = module;
dev->device.common.close = control__close;
dev->device.open_data_source = control__open_data_source;
dev->device.activate = control__activate;
dev->device.set_delay= control__set_delay;
dev->device.wake = control__wake;
*device = &dev->device.common;
} else if (!strcmp(name, SENSORS_HARDWARE_DATA)) {
struct sensors_data_context_t *dev;
dev = malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
dev->events_fd[0] = -1;
dev->events_fd[1] = -1;
dev->events_fd[2] = -1;
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = module;
dev->device.common.close = data__close;
dev->device.data_open = data__data_open;
dev->device.data_close = data__data_close;
dev->device.poll = data__poll;
*device = &dev->device.common;
}
return status;
}
从源码找到的一个例子,写的很优雅,不知道HAL怎么写的同学可以好好学习一下:
主要结构分析:
传感器模块封装:
/**
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
* and the fields of this data structure must begin with hw_module_t
* followed by module specific information.
*/
struct sensors_module_t {
struct hw_module_t common;
/**
* Enumerate all available sensors. The list is returned in "list".
* @return number of sensors in the list
*/
int (*get_sensors_list)(struct sensors_module_t* module,
struct sensor_t const** list);
};
传感器封装:
struct sensor_t {
/* name of this sensors */
const char* name;
/* vendor of the hardware part */
const char* vendor;
/* version of the hardware part + driver. The value of this field is
* left to the implementation and doesn't have to be monotonically
* increasing.
*/
int version;
/* handle that identifies this sensors. This handle is used to activate
* and deactivate this sensor. The value of the handle must be 8 bits
* in this version of the API.
*/
int handle;
/* this sensor's type. */
int type;
/* maximaum range of this sensor's value in SI units */
float maxRange;
/* smallest difference between two values reported by this sensor */
float resolution;
/* rough estimate of this sensor's power consumption in mA */
float power;
/* minimum delay allowed between events in microseconds. A value of zero
* means that this sensor doesn't report events at a constant rate, but
* rather only when a new data is available */
int32_t minDelay;
/* reserved fields, must be zero */
void* reserved[8];
};
与这两个数据相关的操作,主要是提供对外的接口
static struct hw_module_methods_t sensors_module_methods = {
.open = open_sensors
};
const struct sensors_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = SENSORS_HARDWARE_MODULE_ID,
.name = "AK8973A & CM3602 Sensors Module",
.author = "The Android Open Source Project",
.methods = &sensors_module_methods,
},
.get_sensors_list = sensors__get_sensors_list
};
关键操作有open_sensors
/** Open a new instance of a sensor device using name */
static int open_sensors(const struct hw_module_t* module, const char* name,
struct hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, SENSORS_HARDWARE_CONTROL)) {
struct sensors_control_context_t *dev;
dev = malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
dev->akmd_fd = -1;
dev->cmd_fd = -1;
dev->lsd_fd = -1;
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = module;
dev->device.common.close = control__close;
dev->device.open_data_source = control__open_data_source;
dev->device.activate = control__activate;
dev->device.set_delay= control__set_delay;
dev->device.wake = control__wake;
*device = &dev->device.common;
} else if (!strcmp(name, SENSORS_HARDWARE_DATA)) {
struct sensors_data_context_t *dev;
dev = malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
dev->events_fd[0] = -1;
dev->events_fd[1] = -1;
dev->events_fd[2] = -1;
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = module;
dev->device.common.close = data__close;
dev->device.data_open = data__data_open;
dev->device.data_close = data__data_close;
dev->device.poll = data__poll;
*device = &dev->device.common;
}
return status;
}
设备数据的基类
/**
* Every device data structure must begin with hw_device_t
* followed by module specific public methods and attributes.
*/
typedef struct hw_device_t {
/** tag must be initialized to HARDWARE_DEVICE_TAG */
uint32_t tag;
/** version number for hw_device_t */
uint32_t version;
/** reference to the module this device belongs to */
struct hw_module_t* module;
/** padding reserved for future use */
uint32_t reserved[12];
/** Close this device */
int (*close)(struct hw_device_t* device);
} hw_device_t;
传输的函数中name参数为控制或数据(control,data)。
控制设备的上下文
struct sensors_control_context_t {
struct sensors_control_device_t device; // must be first
int akmd_fd;
int cmd_fd;
int lsd_fd;
uint32_t active_sensors;
};
其中,sensors_control_device_t 为传感器控制设备提供操作的方法
struct sensors_control_device_t {
struct hw_device_t common;
native_handle_t* (*open_data_source)(struct sensors_control_device_t *dev);
int (*close_data_source)(struct sensors_control_device_t *dev);
int (*activate)(struct sensors_control_device_t *dev,
int handle, int enabled);
int (*set_delay)(struct sensors_control_device_t *dev, int32_t ms);
int (*wake)(struct sensors_control_device_t *dev);
};
设备数据上下文
struct sensors_data_context_t {
struct sensors_data_device_t device; // must be first
int events_fd[3];
sensors_data_t sensors[MAX_NUM_SENSORS];
uint32_t pendingSensors;
};
其中,sensors_data_device_t 为传感器的数据操作提供方法
struct sensors_data_device_t {
struct hw_device_t common;
int (*data_open)(struct sensors_data_device_t *dev, native_handle_t* nh);
int (*data_close)(struct sensors_data_device_t *dev);
int (*poll)(struct sensors_data_device_t *dev,
sensors_data_t* data);
};
有了以上的数据和控制设备上下文,就可以将驱动层的函数填充到设备山下文中去,主要的函数有如下
control__wake, control__set_delay,control__activate,control__open_data_source,control__close, data__close,data__data_open,data__data_close,data__poll。
经过上述封装,就将传感器的驱动层的操作封装了,以便给上层的framwork层调用。
control__set_delay
ioctl(dev->akmd_fd, ECS_IOCTL_APP_SET_DELAY, &delay)
control__wake
open_inputs
input_event:EV_SYN,SYN_CONFIG,0
write(akm_fd, event, sizeof(event)
close(akm_fd)
write(p_fd, event, sizeof(event)
close(p_fd)
write(l_fd, event, sizeof(event)
close(l_fd)
data__close
data__data_close
data__data_open
input_absinfo
sensors_data_context_t的填充
将文件描述符封装到事件中去
native_handle_delete(handle)
ioctl(dev->events_fd[1], EVIOCGABS(ABS_DISTANCE), &absinfo)获取proximity sensor
initial value
data__data_close
close(dev->events_fd[0]),也就是关闭compass:proximity:lightsensor-level匹配的fd
data__poll
pick_sensor
data__poll_process_akm_abs:将得到的值乘以一个系数
data__poll_process_syn:同步